diff --git a/src/main/java/li/cil/oc2/api/bus/DeviceBus.java b/src/main/java/li/cil/oc2/api/bus/DeviceBus.java index 68e3788f..f99da661 100644 --- a/src/main/java/li/cil/oc2/api/bus/DeviceBus.java +++ b/src/main/java/li/cil/oc2/api/bus/DeviceBus.java @@ -1,13 +1,13 @@ package li.cil.oc2.api.bus; import li.cil.oc2.api.device.Device; +import li.cil.oc2.api.device.IdentifiableDevice; import java.util.Collection; /** * A device bus provides the interface by which {@link Device} can be made available * to a {@link DeviceBusController}, which is usually used by VMs to access devices. - *

*/ public interface DeviceBus { /** @@ -22,24 +22,24 @@ public interface DeviceBus { * * @param device the device to add to the bus. */ - void addDevice(Device device); + void addDevice(IdentifiableDevice device); /** * Removes a device from this device bus. *

- * If the device has not been added with {@link #addDevice(Device)} before calling + * If the device has not been added with {@link #addDevice(IdentifiableDevice)} before calling * this method, this method is a no-op. * * @param device the device to remove from the bus. */ - void removeDevice(Device device); + void removeDevice(IdentifiableDevice device); /** * The list of all devices currently registered with this device bus. * * @return the list of all devices that are currently on this bus. */ - Collection getDevices(); + Collection getDevices(); /** * Schedules a rescan of the device bus. diff --git a/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java b/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java index 247ade15..6714d377 100644 --- a/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java +++ b/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java @@ -1,6 +1,7 @@ package li.cil.oc2.api.bus; import li.cil.oc2.api.device.Device; +import li.cil.oc2.api.device.IdentifiableDevice; import java.util.Collection; @@ -11,7 +12,7 @@ import java.util.Collection; *

* This interface is usually provided by VM containers and used to collect connected * {@link Device}s by aggregating the devices that were added to the device bus elements - * via {@link DeviceBusElement#addDevice(Device)}. + * via {@link DeviceBus#addDevice(IdentifiableDevice)}. *

* The only way for {@link DeviceBusElement}s to be added to a bus is for a * {@link DeviceBusController} to detect them during a scan. @@ -54,5 +55,5 @@ public interface DeviceBusController { * * @return the list of all devices on the bus managed by this controller. */ - Collection getDevices(); + Collection getDevices(); } diff --git a/src/main/java/li/cil/oc2/api/bus/DeviceBusElement.java b/src/main/java/li/cil/oc2/api/bus/DeviceBusElement.java index c496372e..d8d90668 100644 --- a/src/main/java/li/cil/oc2/api/bus/DeviceBusElement.java +++ b/src/main/java/li/cil/oc2/api/bus/DeviceBusElement.java @@ -1,6 +1,6 @@ package li.cil.oc2.api.bus; -import li.cil.oc2.api.device.Device; +import li.cil.oc2.api.device.IdentifiableDevice; import javax.annotation.Nullable; import java.util.Collection; @@ -48,5 +48,5 @@ public interface DeviceBusElement extends DeviceBus { * * @return the devices that have been added to this element. */ - Collection getLocalDevices(); + Collection getLocalDevices(); } diff --git a/src/main/java/li/cil/oc2/api/device/Device.java b/src/main/java/li/cil/oc2/api/device/Device.java index 1e3d4d30..3ffcf1bf 100644 --- a/src/main/java/li/cil/oc2/api/device/Device.java +++ b/src/main/java/li/cil/oc2/api/device/Device.java @@ -4,7 +4,6 @@ import li.cil.oc2.api.bus.DeviceBus; import li.cil.oc2.api.device.object.ObjectDevice; import java.util.List; -import java.util.UUID; /** * Defines a device that may be added to a {@link DeviceBus}. @@ -15,21 +14,12 @@ import java.util.UUID; * @see ObjectDevice */ public interface Device { - /** - * An id unique to this device. - *

- * This id must persist over save/load to prevent code in a running VM losing - * track of the device. - */ - UUID getUniqueId(); - /** * A list of device type names for this device. *

* Devices may be identified by multiple type names. Although every atomic * implementation will usually only have one, when compounding such modular - * devices into a {@link CompoundDevice} all the underlying type names can - * thus be retained. + * devices all the underlying type names can thus be retained. *

* In a more general sense, these can be considered tags the device can be * referenced by inside a VM. diff --git a/src/main/java/li/cil/oc2/api/device/IdentifiableDevice.java b/src/main/java/li/cil/oc2/api/device/IdentifiableDevice.java new file mode 100644 index 00000000..043911c4 --- /dev/null +++ b/src/main/java/li/cil/oc2/api/device/IdentifiableDevice.java @@ -0,0 +1,23 @@ +package li.cil.oc2.api.device; + +import java.util.UUID; + +/** + * Specialization of devices that allows referencing the device by a {@link UUID}. + *

+ * This type is required when adding devices to a {@link li.cil.oc2.api.bus.DeviceBus} + * or referencing devices on a bus. Some {@link li.cil.oc2.api.bus.DeviceBusElement}s + * may take care of wrapping connected devices automatically. + *

+ * Note that {@link li.cil.oc2.api.device.provider.DeviceProvider}s are not + * required to return identifiable devices. + */ +public interface IdentifiableDevice extends Device { + /** + * An id unique to this device. + *

+ * This id must persist over save/load to prevent code in a running VM losing + * track of the device. + */ + UUID getUniqueId(); +} diff --git a/src/main/java/li/cil/oc2/common/vm/DeviceBusControllerImpl.java b/src/main/java/li/cil/oc2/common/bus/DeviceBusControllerImpl.java similarity index 96% rename from src/main/java/li/cil/oc2/common/vm/DeviceBusControllerImpl.java rename to src/main/java/li/cil/oc2/common/bus/DeviceBusControllerImpl.java index 60c29504..f87ed478 100644 --- a/src/main/java/li/cil/oc2/common/vm/DeviceBusControllerImpl.java +++ b/src/main/java/li/cil/oc2/common/bus/DeviceBusControllerImpl.java @@ -1,4 +1,4 @@ -package li.cil.oc2.common.vm; +package li.cil.oc2.common.bus; import com.google.gson.*; import li.cil.ceres.api.Serialized; @@ -7,7 +7,8 @@ import li.cil.oc2.api.bus.DeviceBusElement; import li.cil.oc2.api.device.Device; import li.cil.oc2.api.device.DeviceMethod; import li.cil.oc2.api.device.DeviceMethodParameter; -import li.cil.oc2.common.util.TileEntities; +import li.cil.oc2.api.device.IdentifiableDevice; +import li.cil.oc2.common.util.TileEntityUtils; import li.cil.sedna.api.device.Steppable; import li.cil.sedna.api.device.serial.SerialDevice; import net.minecraft.tileentity.TileEntity; @@ -50,7 +51,7 @@ public class DeviceBusControllerImpl implements DeviceBusController, Steppable { private static final String MESSAGE_TYPE_INVOKE_METHOD = "invoke"; private final Set elements = new HashSet<>(); - private final ConcurrentHashMap devices = new ConcurrentHashMap<>(); + private final ConcurrentHashMap devices = new ConcurrentHashMap<>(); private final SerialDevice serialDevice; private final Gson gson; @@ -92,7 +93,7 @@ public class DeviceBusControllerImpl implements DeviceBusController, Steppable { public void scanDevices() { devices.clear(); for (final DeviceBusElement element : elements) { - for (final Device device : element.getLocalDevices()) { + for (final IdentifiableDevice device : element.getLocalDevices()) { final UUID uuid = device.getUniqueId(); devices.putIfAbsent(uuid, device); } @@ -100,7 +101,7 @@ public class DeviceBusControllerImpl implements DeviceBusController, Steppable { } @Override - public Collection getDevices() { + public Collection getDevices() { return devices.values(); } @@ -148,7 +149,7 @@ public class DeviceBusControllerImpl implements DeviceBusController, Steppable { continue; } - final Optional capability = TileEntities.getInterfaceForSide(tileEntity, DeviceBusElement.class, edge.face); + final Optional capability = TileEntityUtils.getInterfaceForSide(tileEntity, DeviceBusElement.class, edge.face); if (capability.isPresent()) { if (busPositions.add(edge.position) && busPositions.size() > MAX_BUS_ELEMENT_COUNT) { elements.clear(); @@ -159,7 +160,7 @@ public class DeviceBusControllerImpl implements DeviceBusController, Steppable { elements.add(element); for (final Direction face : faces) { - final Optional otherCapability = TileEntities.getInterfaceForSide(tileEntity, DeviceBusElement.class, face); + final Optional otherCapability = TileEntityUtils.getInterfaceForSide(tileEntity, DeviceBusElement.class, face); otherCapability.ifPresent(otherElement -> { final boolean isConnectedToIncomingEdge = otherElement == element; if (!isConnectedToIncomingEdge) { @@ -423,9 +424,9 @@ public class DeviceBusControllerImpl implements DeviceBusController, Steppable { } } - private static final class DeviceSerializer implements JsonSerializer { + private static final class DeviceSerializer implements JsonSerializer { @Override - public JsonElement serialize(final Device src, final Type typeOfSrc, final JsonSerializationContext context) { + public JsonElement serialize(final IdentifiableDevice src, final Type typeOfSrc, final JsonSerializationContext context) { if (src == null) { return JsonNull.INSTANCE; } diff --git a/src/main/java/li/cil/oc2/common/vm/DeviceBusElementImpl.java b/src/main/java/li/cil/oc2/common/bus/DeviceBusElementImpl.java similarity index 75% rename from src/main/java/li/cil/oc2/common/vm/DeviceBusElementImpl.java rename to src/main/java/li/cil/oc2/common/bus/DeviceBusElementImpl.java index d2d305b4..2672553f 100644 --- a/src/main/java/li/cil/oc2/common/vm/DeviceBusElementImpl.java +++ b/src/main/java/li/cil/oc2/common/bus/DeviceBusElementImpl.java @@ -1,8 +1,8 @@ -package li.cil.oc2.common.vm; +package li.cil.oc2.common.bus; import li.cil.oc2.api.bus.DeviceBusController; import li.cil.oc2.api.bus.DeviceBusElement; -import li.cil.oc2.api.device.Device; +import li.cil.oc2.api.device.IdentifiableDevice; import javax.annotation.Nullable; import java.util.ArrayList; @@ -11,7 +11,7 @@ import java.util.List; import java.util.Optional; public class DeviceBusElementImpl implements DeviceBusElement { - private final List devices = new ArrayList<>(); + private final List devices = new ArrayList<>(); @Nullable private DeviceBusController controller; @Override @@ -24,12 +24,12 @@ public class DeviceBusElementImpl implements DeviceBusElement { } @Override - public Collection getLocalDevices() { + public Collection getLocalDevices() { return devices; } @Override - public void addDevice(final Device device) { + public void addDevice(final IdentifiableDevice device) { devices.add(device); if (controller != null) { controller.scanDevices(); @@ -37,7 +37,7 @@ public class DeviceBusElementImpl implements DeviceBusElement { } @Override - public void removeDevice(final Device device) { + public void removeDevice(final IdentifiableDevice device) { devices.remove(device); if (controller != null) { controller.scanDevices(); @@ -45,7 +45,7 @@ public class DeviceBusElementImpl implements DeviceBusElement { } @Override - public Collection getDevices() { + public Collection getDevices() { if (controller != null) { return controller.getDevices(); } else { diff --git a/src/main/java/li/cil/oc2/common/bus/package-info.java b/src/main/java/li/cil/oc2/common/bus/package-info.java new file mode 100644 index 00000000..851d41ee --- /dev/null +++ b/src/main/java/li/cil/oc2/common/bus/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package li.cil.oc2.common.bus; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/li/cil/oc2/common/device/IdentifiableDeviceImpl.java b/src/main/java/li/cil/oc2/common/device/IdentifiableDeviceImpl.java new file mode 100644 index 00000000..af0fb74b --- /dev/null +++ b/src/main/java/li/cil/oc2/common/device/IdentifiableDeviceImpl.java @@ -0,0 +1,48 @@ +package li.cil.oc2.common.device; + +import li.cil.oc2.api.device.Device; +import li.cil.oc2.api.device.DeviceMethod; +import li.cil.oc2.api.device.IdentifiableDevice; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +public final class IdentifiableDeviceImpl implements IdentifiableDevice { + private final Device device; + private final UUID uuid; + + public IdentifiableDeviceImpl(final Device device, final UUID uuid) { + this.device = device; + this.uuid = uuid; + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public List getTypeNames() { + return device.getTypeNames(); + } + + @Override + public List getMethods() { + return device.getMethods(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final IdentifiableDeviceImpl that = (IdentifiableDeviceImpl) o; + return uuid.equals(that.uuid) && + device.equals(that.device); + } + + @Override + public int hashCode() { + return Objects.hash(uuid, device); + } +} diff --git a/src/main/java/li/cil/oc2/common/device/package-info.java b/src/main/java/li/cil/oc2/common/device/package-info.java new file mode 100644 index 00000000..4f55c409 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/device/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package li.cil.oc2.common.device; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/test/java/li/cil/oc2/bus/DeviceBusTests.java b/src/test/java/li/cil/oc2/bus/DeviceBusTests.java index 674f1b01..e1644b03 100644 --- a/src/test/java/li/cil/oc2/bus/DeviceBusTests.java +++ b/src/test/java/li/cil/oc2/bus/DeviceBusTests.java @@ -1,9 +1,9 @@ package li.cil.oc2.bus; import li.cil.oc2.api.bus.DeviceBusElement; -import li.cil.oc2.api.device.Device; +import li.cil.oc2.api.device.IdentifiableDevice; +import li.cil.oc2.common.bus.DeviceBusControllerImpl; import li.cil.oc2.common.capabilities.Capabilities; -import li.cil.oc2.common.vm.DeviceBusControllerImpl; import li.cil.sedna.api.device.serial.SerialDevice; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -62,7 +62,7 @@ public class DeviceBusTests { final DeviceBusElement busElement = mock(DeviceBusElement.class); when(tileEntity.getCapability(eq(busElementCapability), any())).thenReturn(LazyOptional.of(() -> busElement)); - final Device device = mock(Device.class); + final IdentifiableDevice device = mock(IdentifiableDevice.class); when(busElement.getLocalDevices()).thenReturn(Collections.singletonList(device)); when(device.getUniqueId()).thenReturn(UUID.randomUUID()); diff --git a/src/test/java/li/cil/oc2/vm/ObjectDeviceProtocolTests.java b/src/test/java/li/cil/oc2/vm/ObjectDeviceProtocolTests.java index 75df9146..9733574e 100644 --- a/src/test/java/li/cil/oc2/vm/ObjectDeviceProtocolTests.java +++ b/src/test/java/li/cil/oc2/vm/ObjectDeviceProtocolTests.java @@ -3,15 +3,15 @@ package li.cil.oc2.vm; import com.google.gson.*; import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue; import li.cil.oc2.api.bus.DeviceBusElement; -import li.cil.oc2.api.device.AbstractDevice; -import li.cil.oc2.api.device.Device; import li.cil.oc2.api.device.DeviceMethod; +import li.cil.oc2.api.device.IdentifiableDevice; import li.cil.oc2.api.device.object.Callback; import li.cil.oc2.api.device.object.ObjectDevice; import li.cil.oc2.api.device.object.Parameter; +import li.cil.oc2.common.bus.DeviceBusControllerImpl; +import li.cil.oc2.common.bus.DeviceBusElementImpl; import li.cil.oc2.common.capabilities.Capabilities; -import li.cil.oc2.common.vm.DeviceBusControllerImpl; -import li.cil.oc2.common.vm.DeviceBusElementImpl; +import li.cil.oc2.common.device.IdentifiableDeviceImpl; import li.cil.sedna.api.device.serial.SerialDevice; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -28,6 +28,7 @@ import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.util.Collections; import java.util.List; +import java.util.UUID; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.mock; @@ -117,14 +118,15 @@ public class ObjectDeviceProtocolTests { public void annotatedObject() { final SimpleObject object = new SimpleObject(); final ObjectDevice device = new ObjectDevice(object); + final IdentifiableDeviceImpl identifiableDevice = new IdentifiableDeviceImpl(device, UUID.randomUUID()); - busElement.addDevice(device); + busElement.addDevice(identifiableDevice); controller.scan(world, CONTROLLER_POS); - Assertions.assertEquals(42 + 23, invokeMethod(device, "add", 42, 23).getAsInt()); + Assertions.assertEquals(42 + 23, invokeMethod(identifiableDevice, "add", 42, 23).getAsInt()); } - private JsonElement invokeMethod(final Device device, final String name, final Object... parameters) { + private JsonElement invokeMethod(final IdentifiableDevice device, final String name, final Object... parameters) { final JsonObject request = new JsonObject(); request.addProperty("type", "invoke"); final JsonObject methodInvocation = new JsonObject(); @@ -241,16 +243,28 @@ public class ObjectDeviceProtocolTests { } } - private static final class TestDevice extends AbstractDevice { + private static final class TestDevice implements IdentifiableDevice { + private static final UUID UUID = java.util.UUID.randomUUID(); + private final DeviceMethod method; public TestDevice(final DeviceMethod method) { this.method = method; } + @Override + public List getTypeNames() { + return Collections.singletonList(getClass().getSimpleName()); + } + @Override public List getMethods() { return Collections.singletonList(method); } + + @Override + public UUID getUniqueId() { + return UUID; + } } }