diff --git a/src/main/java/li/cil/oc2/common/bus/TileEntityDeviceBusController.java b/src/main/java/li/cil/oc2/common/bus/TileEntityDeviceBusController.java index 2ae51cad..e6dfd8f2 100644 --- a/src/main/java/li/cil/oc2/common/bus/TileEntityDeviceBusController.java +++ b/src/main/java/li/cil/oc2/common/bus/TileEntityDeviceBusController.java @@ -18,12 +18,16 @@ import static java.util.Collections.emptySet; public abstract class TileEntityDeviceBusController implements DeviceBusController { public enum State { SCAN_PENDING, + INCOMPLETE, TOO_COMPLEX, MULTIPLE_CONTROLLERS, READY, } private static final int MAX_BUS_ELEMENT_COUNT = 128; + private static final int TICKS_PER_SECOND = 20; + private static final int INCOMPLETE_RETRY_INTERVAL = 10; + private static final int TOO_COMPLEX_RETRY_INTERVAL = 5; private final TileEntity tileEntity; @@ -31,6 +35,7 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll private final HashSet devices = new HashSet<>(); private final HashMap> deviceIds = new HashMap<>(); + private State state = State.SCAN_PENDING; private int scanDelay; protected TileEntityDeviceBusController(final TileEntity tileEntity) { @@ -43,6 +48,10 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll protected void onDevicesValid() { } + public State getState() { + return state; + } + @Override public void scheduleBusScan() { onDevicesInvalid(); @@ -56,6 +65,7 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll deviceIds.clear(); scanDelay = 0; // scan as soon as possible + state = State.SCAN_PENDING; } @Override @@ -86,20 +96,21 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll return deviceIds.getOrDefault(device, emptySet()); } - public State scan() { + public void scan() { if (scanDelay < 0) { - return State.READY; + return; } if (scanDelay-- > 0) { - return State.SCAN_PENDING; + return; } assert scanDelay == -1; final World world = tileEntity.getWorld(); if (world == null || world.isRemote()) { - return State.SCAN_PENDING; + scanDelay = 0; + return; } final Stack queue = new Stack<>(); @@ -125,9 +136,10 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll if (!world.chunkExists(chunkPos.x, chunkPos.z)) { // If we have an unloaded chunk neighbor we cannot know whether our neighbor in that // chunk would cause a scan once it is loaded, so we'll just retry every so often. - scanDelay = 20; + scanDelay = INCOMPLETE_RETRY_INTERVAL * TICKS_PER_SECOND; + state = State.INCOMPLETE; elements.clear(); - return State.SCAN_PENDING; + return; } final TileEntity tileEntity = world.getTileEntity(edge.position); @@ -148,7 +160,9 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll if (capability.isPresent()) { if (busPositions.add(edge.position) && busPositions.size() > MAX_BUS_ELEMENT_COUNT) { elements.clear(); - return State.TOO_COMPLEX; // This return is the reason this is not in the ifPresent below. + scanDelay = TOO_COMPLEX_RETRY_INTERVAL * TICKS_PER_SECOND; + state = State.TOO_COMPLEX; + return; // This return is the reason this is not in the ifPresent below. } } @@ -180,12 +194,13 @@ public abstract class TileEntityDeviceBusController implements DeviceBusControll } if (hasMultipleControllers) { - return State.MULTIPLE_CONTROLLERS; + state = State.MULTIPLE_CONTROLLERS; + return; } scanDevices(); - return State.READY; + state = State.READY; } private static final class ScanEdge { diff --git a/src/main/java/li/cil/oc2/common/tile/ComputerTileEntity.java b/src/main/java/li/cil/oc2/common/tile/ComputerTileEntity.java index 9cac2db0..e1c3529c 100644 --- a/src/main/java/li/cil/oc2/common/tile/ComputerTileEntity.java +++ b/src/main/java/li/cil/oc2/common/tile/ComputerTileEntity.java @@ -138,7 +138,8 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic return; } - busState = busController.scan(); + busController.scan(); + setBusState(busController.getState()); if (busState != TileEntityDeviceBusController.State.READY) { return; } diff --git a/src/test/java/li/cil/oc2/bus/DeviceBusTests.java b/src/test/java/li/cil/oc2/bus/DeviceBusTests.java index aa5d67d8..3f748ca1 100644 --- a/src/test/java/li/cil/oc2/bus/DeviceBusTests.java +++ b/src/test/java/li/cil/oc2/bus/DeviceBusTests.java @@ -64,13 +64,15 @@ public class DeviceBusTests { @Test public void scanPendingWhenTileEntityNotLoaded() { - assertEquals(TileEntityDeviceBusController.State.SCAN_PENDING, busController.scan()); + busController.scan(); + assertEquals(TileEntityDeviceBusController.State.INCOMPLETE, busController.getState()); } @Test public void scanCompletesWhenNoNeighbors() { when(world.chunkExists(anyInt(), anyInt())).thenReturn(true); - assertEquals(TileEntityDeviceBusController.State.READY, busController.scan()); + busController.scan(); + assertEquals(TileEntityDeviceBusController.State.READY, busController.getState()); } @Test @@ -80,7 +82,8 @@ public class DeviceBusTests { final RPCDevice device = mock(RPCDevice.class); when(busControllerBusElement.getLocalDevices()).thenReturn(singletonList(device)); - assertEquals(TileEntityDeviceBusController.State.READY, busController.scan()); + busController.scan(); + assertEquals(TileEntityDeviceBusController.State.READY, busController.getState()); verify(busControllerBusElement).addController(busController); assertTrue(busController.getDevices().contains(device)); @@ -93,7 +96,8 @@ public class DeviceBusTests { final DeviceBusElement busElement1 = mockBusElement(CONTROLLER_POS.west()); final DeviceBusElement busElement2 = mockBusElement(CONTROLLER_POS.west().west()); - assertEquals(TileEntityDeviceBusController.State.READY, busController.scan()); + busController.scan(); + assertEquals(TileEntityDeviceBusController.State.READY, busController.getState()); verify(busElement1).addController(busController); verify(busElement2).addController(busController);