STE tick optimization.

- SmartTileEntity#tick down to 3.32% from 11.64% cpu time.
 - Measured by JFR over 2 sessions each >8min.
 - Test world was the deployer fields.
 - Iterating over HashMap values is slow.
 - Collect TileEntityBehaviours into a list when the contents of SmartTileEntity#behaviours changes.
This commit is contained in:
JozsefA 2021-03-26 22:02:19 -07:00
parent cf5eea5a10
commit d3d338e64b

View File

@ -17,7 +17,9 @@ import net.minecraftforge.items.CapabilityItemHandler;
public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity {
private Map<BehaviourType<?>, TileEntityBehaviour> behaviours;
private final Map<BehaviourType<?>, TileEntityBehaviour> behaviours;
// Internally maintained to be identical to behaviorMap.values() in order to improve iteration performance.
private final List<TileEntityBehaviour> behaviourList;
private boolean initialized;
private boolean firstNbtRead;
private int lazyTickRate;
@ -36,6 +38,9 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
ArrayList<TileEntityBehaviour> list = new ArrayList<>();
addBehaviours(list);
list.forEach(b -> behaviours.put(b.getType(), b));
behaviourList = new ArrayList<>(list.size());
updateBehaviorList();
}
public abstract void addBehaviours(List<TileEntityBehaviour> behaviours);
@ -58,13 +63,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
lazyTick();
}
behaviours.values()
.forEach(TileEntityBehaviour::tick);
behaviourList.forEach(TileEntityBehaviour::tick);
}
public void initialize() {
behaviours.values()
.forEach(TileEntityBehaviour::initialize);
behaviourList.forEach(TileEntityBehaviour::initialize);
lazyTick();
}
@ -99,10 +102,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
ArrayList<TileEntityBehaviour> list = new ArrayList<>();
addBehavioursDeferred(list);
list.forEach(b -> behaviours.put(b.getType(), b));
updateBehaviorList();
}
super.read(compound);
behaviours.values()
.forEach(tb -> tb.read(compound, clientPacket));
behaviourList.forEach(tb -> tb.read(compound, clientPacket));
}
/**
@ -110,8 +114,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
*/
protected void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound);
behaviours.values()
.forEach(tb -> tb.write(compound, clientPacket));
behaviourList.forEach(tb -> tb.write(compound, clientPacket));
}
@Override
@ -130,19 +133,31 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
}
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
behaviours.values()
.forEach(action);
behaviourList.forEach(action);
}
protected void attachBehaviourLate(TileEntityBehaviour behaviour) {
behaviours.put(behaviour.getType(), behaviour);
behaviour.initialize();
updateBehaviorList();
}
protected void removeBehaviour(BehaviourType<?> type) {
TileEntityBehaviour remove = behaviours.remove(type);
if (remove != null)
if (remove != null) {
remove.remove();
updateBehaviorList();
}
}
// We don't trust the input to the API will be sane, so we
// update all the contents whenever something changes. It's
// simpler than trying to manipulate the list one element at
// a time.
private void updateBehaviorList() {
behaviourList.clear();
behaviourList.addAll(behaviours.values());
}
@SuppressWarnings("unchecked")