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 { 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 initialized;
private boolean firstNbtRead; private boolean firstNbtRead;
private int lazyTickRate; private int lazyTickRate;
@ -36,6 +38,9 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
ArrayList<TileEntityBehaviour> list = new ArrayList<>(); ArrayList<TileEntityBehaviour> list = new ArrayList<>();
addBehaviours(list); addBehaviours(list);
list.forEach(b -> behaviours.put(b.getType(), b)); list.forEach(b -> behaviours.put(b.getType(), b));
behaviourList = new ArrayList<>(list.size());
updateBehaviorList();
} }
public abstract void addBehaviours(List<TileEntityBehaviour> behaviours); public abstract void addBehaviours(List<TileEntityBehaviour> behaviours);
@ -58,13 +63,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
lazyTick(); lazyTick();
} }
behaviours.values() behaviourList.forEach(TileEntityBehaviour::tick);
.forEach(TileEntityBehaviour::tick);
} }
public void initialize() { public void initialize() {
behaviours.values() behaviourList.forEach(TileEntityBehaviour::initialize);
.forEach(TileEntityBehaviour::initialize);
lazyTick(); lazyTick();
} }
@ -99,10 +102,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
ArrayList<TileEntityBehaviour> list = new ArrayList<>(); ArrayList<TileEntityBehaviour> list = new ArrayList<>();
addBehavioursDeferred(list); addBehavioursDeferred(list);
list.forEach(b -> behaviours.put(b.getType(), b)); list.forEach(b -> behaviours.put(b.getType(), b));
updateBehaviorList();
} }
super.read(compound); super.read(compound);
behaviours.values() behaviourList.forEach(tb -> tb.read(compound, clientPacket));
.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) { protected void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound); super.write(compound);
behaviours.values() behaviourList.forEach(tb -> tb.write(compound, clientPacket));
.forEach(tb -> tb.write(compound, clientPacket));
} }
@Override @Override
@ -130,19 +133,31 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
} }
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) { protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
behaviours.values() behaviourList.forEach(action);
.forEach(action);
} }
protected void attachBehaviourLate(TileEntityBehaviour behaviour) { protected void attachBehaviourLate(TileEntityBehaviour behaviour) {
behaviours.put(behaviour.getType(), behaviour); behaviours.put(behaviour.getType(), behaviour);
behaviour.initialize(); behaviour.initialize();
updateBehaviorList();
} }
protected void removeBehaviour(BehaviourType<?> type) { protected void removeBehaviour(BehaviourType<?> type) {
TileEntityBehaviour remove = behaviours.remove(type); TileEntityBehaviour remove = behaviours.remove(type);
if (remove != null) if (remove != null) {
remove.remove(); 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") @SuppressWarnings("unchecked")