Pulled out common tile enity bus controller logic (checking for loaded/unloaded chunks to trigger scan).

This commit is contained in:
Florian Nücke
2020-12-25 20:17:00 +01:00
parent a3bd9445ff
commit a072717b28
2 changed files with 108 additions and 14 deletions

View File

@@ -11,6 +11,7 @@ import li.cil.oc2.api.bus.device.vm.VMDevice;
import li.cil.oc2.api.bus.device.vm.VMDeviceLifecycleEventType;
import li.cil.oc2.common.block.ComputerBlock;
import li.cil.oc2.common.bus.AbstractDeviceBusController;
import li.cil.oc2.common.bus.TileEntityDeviceBusController;
import li.cil.oc2.common.bus.TileEntityDeviceBusElement;
import li.cil.oc2.common.bus.device.ItemDeviceInfo;
import li.cil.oc2.common.capabilities.Capabilities;
@@ -113,14 +114,14 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
virtualMachine.vmAdapter.setDefaultAddressProvider(this::getDefaultDeviceAddress);
}
public Terminal getTerminal() {
return terminal;
}
public IItemHandler getItemHandler() {
return itemHandler;
}
public Terminal getTerminal() {
return terminal;
}
public void start() {
if (runState == RunState.RUNNING) {
return;
@@ -157,7 +158,7 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
}
public void handleNeighborChanged(final BlockPos pos) {
busElement.handleNeighborChanged(pos);
busController.scheduleBusScan();
}
@OnlyIn(Dist.CLIENT)
@@ -198,11 +199,6 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
@Override
protected void collectCapabilities(final CapabilityCollector collector, @Nullable final Direction direction) {
if (direction != getBlockState().get(ComputerBlock.HORIZONTAL_FACING)) {
collector.offer(Capabilities.DEVICE_BUS_ELEMENT_CAPABILITY, busElement);
collector.offer(Capabilities.DEVICE_BUS_CONTROLLER_CAPABILITY, busController);
}
collector.offer(Capabilities.ITEM_HANDLER_CAPABILITY, itemHandler);
}
@@ -241,7 +237,15 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
// bus setup and devices to load. So we can keep using it.
if (runner == null) {
virtualMachine.board.reset();
virtualMachine.board.initialize();
try {
virtualMachine.board.initialize();
} catch (final Throwable e) {
LOGGER.error(e);
setRunState(RunState.STOPPED);
return;
}
virtualMachine.board.setRunning(true);
runner = new ComputerVirtualMachineRunner(virtualMachine);
@@ -451,9 +455,9 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
///////////////////////////////////////////////////////////////////
private final class BusController extends AbstractDeviceBusController {
private BusController() {
super(busElement);
private final class BusController extends TileEntityDeviceBusController {
private BusController(final DeviceBusElement root) {
super(root, ComputerTileEntity.this);
}
@Override

View File

@@ -0,0 +1,90 @@
package li.cil.oc2.common.bus;
import li.cil.oc2.api.bus.BlockDeviceBusElement;
import li.cil.oc2.api.bus.DeviceBusElement;
import li.cil.oc2.common.util.ServerScheduler;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import java.util.Collection;
import java.util.HashSet;
public class TileEntityDeviceBusController extends AbstractDeviceBusController {
private final Runnable onBusChunkLoadedStateChanged = this::scheduleBusScan;
private final HashSet<ChunkPos> trackedChunks = new HashSet<>();
private final TileEntity tileEntity;
///////////////////////////////////////////////////////////////////
public TileEntityDeviceBusController(final DeviceBusElement root, final TileEntity tileEntity) {
super(root);
this.tileEntity = tileEntity;
}
///////////////////////////////////////////////////////////////////
@Override
public void dispose() {
super.dispose();
removeListeners(trackedChunks);
trackedChunks.clear();
}
///////////////////////////////////////////////////////////////////
@Override
protected void onAfterBusScan() {
final World world = tileEntity.getWorld();
if (world == null) {
return;
}
final HashSet<ChunkPos> newTrackedChunks = new HashSet<>();
for (final DeviceBusElement element : getElements()) {
if (element instanceof BlockDeviceBusElement) {
final BlockPos position = ((BlockDeviceBusElement) element).getPosition();
newTrackedChunks.add(new ChunkPos(position));
newTrackedChunks.add(new ChunkPos(position.offset(Direction.NORTH)));
newTrackedChunks.add(new ChunkPos(position.offset(Direction.EAST)));
newTrackedChunks.add(new ChunkPos(position.offset(Direction.SOUTH)));
newTrackedChunks.add(new ChunkPos(position.offset(Direction.WEST)));
}
}
// Do not track the chunk the controller itself is in -- this is unneeded because
// we expect the controller to be disposed if its chunk is unloaded.
newTrackedChunks.remove(new ChunkPos(tileEntity.getPos()));
final HashSet<ChunkPos> removedChunks = new HashSet<>(trackedChunks);
removedChunks.removeAll(newTrackedChunks);
removeListeners(removedChunks);
final HashSet<ChunkPos> addedChunks = new HashSet<>(newTrackedChunks);
newTrackedChunks.removeAll(trackedChunks);
addListeners(world, addedChunks);
trackedChunks.removeAll(removedChunks);
trackedChunks.addAll(newTrackedChunks);
}
///////////////////////////////////////////////////////////////////
private void addListeners(final World world, final Collection<ChunkPos> chunks) {
for (final ChunkPos chunkPos : chunks) {
ServerScheduler.scheduleOnLoad(world, chunkPos, onBusChunkLoadedStateChanged);
ServerScheduler.scheduleOnUnload(world, chunkPos, onBusChunkLoadedStateChanged);
}
}
private void removeListeners(final Collection<ChunkPos> chunks) {
final World world = tileEntity.getWorld();
for (final ChunkPos chunkPos : chunks) {
ServerScheduler.cancelOnLoad(world, chunkPos, onBusChunkLoadedStateChanged);
ServerScheduler.cancelOnUnload(world, chunkPos, onBusChunkLoadedStateChanged);
}
}
}