Fixed state in controller, added state for incomplete scans and re-scanning for too complex ones automatically (because we won't be notified of changes in that case anymore).

This commit is contained in:
Florian Nücke
2020-12-09 13:11:16 +01:00
parent fb52a2e8d7
commit b7fc45f958
3 changed files with 34 additions and 14 deletions

View File

@@ -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<Device> devices = new HashSet<>();
private final HashMap<Device, Set<UUID>> 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<ScanEdge> 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 {

View File

@@ -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;
}

View File

@@ -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);