Split up providers by context/query type after all.

Added logic to allow item devices to store data to their stack and load it back when first initialized.
This commit is contained in:
Florian Nücke
2020-12-20 04:51:38 +01:00
parent 556ae0cf6e
commit f641b7b60c
65 changed files with 726 additions and 389 deletions

View File

@@ -0,0 +1,9 @@
package li.cil.oc2.api.bus.device;
import net.minecraft.nbt.CompoundNBT;
public interface ItemDevice extends Device {
void exportToItemStack(CompoundNBT nbt);
void importFromItemStack(CompoundNBT nbt);
}

View File

@@ -0,0 +1,51 @@
package li.cil.oc2.api.bus.device.provider;
import li.cil.oc2.api.bus.device.Device;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.registries.IForgeRegistryEntry;
/**
* This is used to query for devices given a block face.
* <p>
* Implementations <em>may</em> return various device types depending on the query.
* <p>
* For identical queries and world state, implementations <em>should</em> return the same device.
* Failing that, implementations <em>should</em> return instances that are equal to each other
* when compared using {@link Object#equals(Object)} and have equal {@link Object#hashCode()}s.
* <p>
* This allows avoiding unnecessary re-initialization of devices that have not changed since a
* previous scan.
* <p>
* This is also required to avoid device duplication when a device is connected to a
* {@link li.cil.oc2.api.bus.DeviceBus} more than once. An example where this can occur are
* blocks that expose the same device on all sides having connected cabling adjacent to more
* than one face.
* <p>
* Providers can be registered via the provider registries, much like blocks and items
* are registered. For example:
* <pre>
* class YourModInitialization {
* static DeferredRegister&lt;BlockDeviceProvider&gt; BLOCK_DEVICE_PROVIDERS = DeferredRegister.create(BlockDeviceProvider.class, "your_mod_id");
*
* static void initialize() {
* BLOCK_DEVICE_PROVIDERS.register("your_block_device_name", YourBlockDeviceProvider::new);
*
* BLOCK_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus());
* }
* }
* </pre>
*
* @see li.cil.oc2.api.bus.device.rpc.RPCDevice
* @see li.cil.oc2.api.bus.device.object.ObjectDevice
* @see li.cil.oc2.api.bus.device.vm.VMDevice
* @see BlockDeviceQuery
*/
public interface BlockDeviceProvider extends IForgeRegistryEntry<BlockDeviceProvider> {
/**
* Get a device for the specified query.
*
* @param query the query describing the object to get a {@link Device} for.
* @return a device for the specified query, if available.
*/
LazyOptional<Device> getDevice(BlockDeviceQuery query);
}

View File

@@ -8,8 +8,10 @@ import javax.annotation.Nullable;
/**
* Device query for a block in the world.
*
* @see BlockDeviceProvider
*/
public interface BlockDeviceQuery extends DeviceQuery {
public interface BlockDeviceQuery {
/**
* The world containing the block this query is performed for.
*

View File

@@ -1,55 +0,0 @@
package li.cil.oc2.api.bus.device.provider;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.rpc.RPCDevice;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.registries.IForgeRegistryEntry;
/**
* Allows querying for devices given some context.
* <p>
* See the specializations of {@link DeviceQuery} for possible queries.
* <ul>
* <li>Implementations <em>may</em> handle multiple query types and return various device
* types depending on the query.</li>
* <li>
* Implementations <em>should</em> return the same device for the same query.
* <p>
* Failing that, implementations <em>should</em> return instances that are equal to each
* other when compared using {@link Object#equals(Object)} and have equal {@link Object#hashCode()}s.
* <p>
* This is required to avoid device duplication when a device is connected to a bus more
* than once (e.g. for blocks when connected cables are adjacent to multiple faces of the
* block).
* </li>
* </ul>
* <p>
* Providers can be registered via the device provider registry, much like blocks and items
* are registered. For example:
* <pre>
* class YourModInitialization {
* static DeferredRegister&lt;DeviceProvider&gt; PROVIDERS = DeferredRegister.create(DeviceProvider.class, "your_mod_id");
*
* static void initialize() {
* PROVIDERS.register("your_device_name", YourDeviceProvider::new);
*
* PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus());
* }
* }
* </pre>
*
* @see RPCDevice
* @see ObjectDevice
* @see DeviceQuery
* @see BlockDeviceQuery
*/
public interface DeviceProvider extends IForgeRegistryEntry<DeviceProvider> {
/**
* Get a device for the specified query.
*
* @param query the query describing the object to get a {@link Device} for.
* @return a device for the specified query, if available.
*/
LazyOptional<Device> getDevice(DeviceQuery query);
}

View File

@@ -1,10 +0,0 @@
package li.cil.oc2.api.bus.device.provider;
/**
* Base interface for all queries to {@link DeviceProvider}s.
*
* @see DeviceProvider
* @see BlockDeviceQuery
*/
public interface DeviceQuery {
}

View File

@@ -0,0 +1,48 @@
package li.cil.oc2.api.bus.device.provider;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.ItemDevice;
import net.minecraftforge.registries.IForgeRegistryEntry;
import java.util.Optional;
/**
* This is used to query for devices given an item stack.
* <p>
* Implementations <em>may</em> return various device types depending on the query.
* <p>
* For identical queries, implementations <em>should</em> return the same device. Failing that,
* implementations <em>should</em> return instances that are equal to each other when compared
* using {@link Object#equals(Object)} and have equal {@link Object#hashCode()}s.
* <p>
* This allows avoiding unnecessary re-initialization of devices that have not changed since a
* previous scan.
* <p>
* Providers can be registered via the provider registries, much like blocks and items
* are registered. For example:
* <pre>
* class YourModInitialization {
* static DeferredRegister&lt;ItemDeviceProvider&gt; ITEM_DEVICE_PROVIDERS = DeferredRegister.create(ItemDeviceProvider.class, "your_mod_id");
*
* static void initialize() {
* ITEM_DEVICE_PROVIDERS.register("your_item_device_name", YourItemDeviceProvider::new);
*
* ITEM_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus());
* }
* }
* </pre>
*
* @see li.cil.oc2.api.bus.device.rpc.RPCDevice
* @see li.cil.oc2.api.bus.device.object.ObjectDevice
* @see li.cil.oc2.api.bus.device.vm.VMDevice
* @see ItemDeviceQuery
*/
public interface ItemDeviceProvider extends IForgeRegistryEntry<ItemDeviceProvider> {
/**
* Get a device for the specified query.
*
* @param query the query describing the object to get a {@link Device} for.
* @return a device for the specified query, if available.
*/
Optional<ItemDevice> getDevice(ItemDeviceQuery query);
}

View File

@@ -2,6 +2,16 @@ package li.cil.oc2.api.bus.device.provider;
import net.minecraft.item.ItemStack;
public interface ItemDeviceQuery extends DeviceQuery {
/**
* Device query for an item stack.
*
* @see ItemDeviceProvider
*/
public interface ItemDeviceQuery {
/**
* The item stack this query is performed for.
*
* @return the item stack to get a device for.
*/
ItemStack getItemStack();
}

View File

@@ -2,7 +2,6 @@ package li.cil.oc2.api.bus.device.rpc;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.provider.DeviceProvider;
import java.util.List;
@@ -20,7 +19,8 @@ import java.util.List;
* the {@link ObjectDevice} class.
*
* @see ObjectDevice
* @see DeviceProvider
* @see li.cil.oc2.api.bus.device.provider.BlockDeviceProvider
* @see li.cil.oc2.api.bus.device.provider.ItemDeviceProvider
*/
public interface RPCDevice extends Device {
/**

View File

@@ -17,6 +17,8 @@ import li.cil.sedna.api.device.MemoryMappedDevice;
* for releasing unmanaged resources acquired in {@link #load(VMContext)}.
*
* @see VMDeviceLifecycleListener
* @see li.cil.oc2.api.bus.device.provider.BlockDeviceProvider
* @see li.cil.oc2.api.bus.device.provider.ItemDeviceProvider
*/
public interface VMDevice extends Device {
/**

View File

@@ -20,6 +20,8 @@ public abstract class AbstractTileEntity extends TileEntity {
super(tileEntityType);
}
///////////////////////////////////////////////////////////////////
@NotNull
@Override
public <T> LazyOptional<T> getCapability(@NotNull final Capability<T> capability, @Nullable final Direction side) {

View File

@@ -27,6 +27,8 @@ public class BusCableTileEntity extends AbstractTileEntity {
setCapabilityIfAbsent(Capabilities.DEVICE_BUS_ELEMENT_CAPABILITY, busElement);
}
///////////////////////////////////////////////////////////////////
public void handleNeighborChanged(final BlockPos pos) {
busElement.handleNeighborChanged(pos);
}

View File

@@ -3,7 +3,6 @@ package li.cil.oc2.common.block.entity;
import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue;
import li.cil.ceres.api.Serialized;
import li.cil.oc2.Constants;
import li.cil.oc2.api.API;
import li.cil.oc2.api.bus.DeviceBusElement;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.vm.VMContext;
@@ -20,10 +19,7 @@ import li.cil.oc2.common.network.message.ComputerBusStateMessage;
import li.cil.oc2.common.network.message.ComputerRunStateMessage;
import li.cil.oc2.common.network.message.TerminalBlockOutputMessage;
import li.cil.oc2.common.serialization.NBTSerialization;
import li.cil.oc2.common.util.HorizontalBlockUtils;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.oc2.common.util.NBTUtils;
import li.cil.oc2.common.util.ServerScheduler;
import li.cil.oc2.common.util.*;
import li.cil.oc2.common.vm.Terminal;
import li.cil.oc2.common.vm.VirtualMachine;
import li.cil.oc2.common.vm.VirtualMachineRunner;
@@ -128,9 +124,7 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic
itemHandler.setStackInSlot(2, new ItemStack(Items.RAM_8M_ITEM.get()));
final ItemStack hdd = new ItemStack(Items.HDD_ITEM.get());
final CompoundNBT hddInfo = new CompoundNBT();
hddInfo.putString(Constants.HDD_BASE_NBT_TAG_NAME, "linux");
hdd.setTagInfo(API.MOD_ID, hddInfo);
ItemStackUtils.getOrCreateModDataTag(hdd).putString(Constants.HDD_BASE_NBT_TAG_NAME, "linux");
itemHandler.setStackInSlot(4, hdd);
}

View File

@@ -39,6 +39,8 @@ public class RedstoneInterfaceTileEntity extends TileEntity implements NamedDevi
super(TileEntities.REDSTONE_INTERFACE_TILE_ENTITY.get());
}
///////////////////////////////////////////////////////////////////
@Override
public CompoundNBT write(CompoundNBT compound) {
compound = super.write(compound);

View File

@@ -42,6 +42,8 @@ public abstract class AbstractDeviceBusController implements DeviceBusController
this.root = root;
}
///////////////////////////////////////////////////////////////////
public void dispose() {
for (final DeviceBusElement element : elements) {
element.removeController(this);

View File

@@ -0,0 +1,10 @@
package li.cil.oc2.common.bus;
import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider;
import li.cil.oc2.common.bus.device.BlockDeviceInfo;
public abstract class AbstractGroupingBlockDeviceBusElement extends AbstractGroupingDeviceBusElement<BlockDeviceProvider, BlockDeviceInfo> {
public AbstractGroupingBlockDeviceBusElement(final int groupCount) {
super(groupCount);
}
}

View File

@@ -1,55 +1,58 @@
package li.cil.oc2.common.bus;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.common.bus.device.DeviceInfo;
import li.cil.oc2.common.bus.device.AbstractDeviceInfo;
import li.cil.oc2.common.util.ItemDeviceUtils;
import li.cil.oc2.common.util.NBTTagIds;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.registries.IForgeRegistryEntry;
import java.util.*;
import java.util.stream.Collectors;
public abstract class AbstractGroupingDeviceBusElement extends AbstractDeviceBusElement implements INBTSerializable<ListNBT> {
private static final String DEVICE_ID_NBT_TAG_NAME = "deviceId";
private static final String DEVICE_DATA_NBT_TAG_NAME = "deviceData";
public abstract class AbstractGroupingDeviceBusElement<TProvider extends IForgeRegistryEntry<TProvider>, TDeviceInfo extends AbstractDeviceInfo<TProvider, ?>> extends AbstractDeviceBusElement implements INBTSerializable<ListNBT> {
private static final String GROUP_ID_NBT_TAG_NAME = "groupId";
private static final String GROUP_DATA_NBT_TAG_NAME = "groupData";
///////////////////////////////////////////////////////////////////
protected final int groupCount;
protected final ArrayList<HashSet<DeviceInfo>> devicesByGroup;
protected final ArrayList<HashSet<TDeviceInfo>> groups;
///////////////////////////////////////////////////////////////////
protected final UUID[] deviceIds;
protected final CompoundNBT[] deviceData;
protected final UUID[] groupIds;
protected final CompoundNBT[] groupData;
///////////////////////////////////////////////////////////////////
protected AbstractGroupingDeviceBusElement(final int groupCount) {
this.groupCount = groupCount;
this.devicesByGroup = new ArrayList<>(groupCount);
this.deviceIds = new UUID[groupCount];
this.deviceData = new CompoundNBT[groupCount];
this.groups = new ArrayList<>(groupCount);
this.groupIds = new UUID[groupCount];
this.groupData = new CompoundNBT[groupCount];
for (int i = 0; i < groupCount; i++) {
devicesByGroup.add(new HashSet<>());
deviceIds[i] = UUID.randomUUID();
deviceData[i] = new CompoundNBT();
groups.add(new HashSet<>());
groupIds[i] = UUID.randomUUID();
groupData[i] = new CompoundNBT();
}
}
///////////////////////////////////////////////////////////////////
@Override
public ListNBT serializeNBT() {
serializeDevices();
final ListNBT nbt = new ListNBT();
for (int i = 0; i < groupCount; i++) {
serializeDevices(i);
final CompoundNBT sideNbt = new CompoundNBT();
sideNbt.putUniqueId(DEVICE_ID_NBT_TAG_NAME, deviceIds[i]);
sideNbt.put(DEVICE_DATA_NBT_TAG_NAME, deviceData[i]);
sideNbt.putUniqueId(GROUP_ID_NBT_TAG_NAME, groupIds[i]);
sideNbt.put(GROUP_DATA_NBT_TAG_NAME, groupData[i]);
nbt.add(sideNbt);
}
@@ -62,11 +65,11 @@ public abstract class AbstractGroupingDeviceBusElement extends AbstractDeviceBus
for (int i = 0; i < count; i++) {
final CompoundNBT sideNbt = nbt.getCompound(i);
if (sideNbt.hasUniqueId(DEVICE_ID_NBT_TAG_NAME)) {
deviceIds[i] = sideNbt.getUniqueId(DEVICE_ID_NBT_TAG_NAME);
if (sideNbt.hasUniqueId(GROUP_ID_NBT_TAG_NAME)) {
groupIds[i] = sideNbt.getUniqueId(GROUP_ID_NBT_TAG_NAME);
}
if (sideNbt.contains(DEVICE_DATA_NBT_TAG_NAME, NBTTagIds.TAG_COMPOUND)) {
deviceData[i] = sideNbt.getCompound(DEVICE_DATA_NBT_TAG_NAME);
if (sideNbt.contains(GROUP_DATA_NBT_TAG_NAME, NBTTagIds.TAG_COMPOUND)) {
groupData[i] = sideNbt.getCompound(GROUP_DATA_NBT_TAG_NAME);
}
}
}
@@ -74,10 +77,10 @@ public abstract class AbstractGroupingDeviceBusElement extends AbstractDeviceBus
@Override
public Optional<UUID> getDeviceIdentifier(final Device device) {
for (int i = 0; i < groupCount; i++) {
final HashSet<DeviceInfo> group = devicesByGroup.get(i);
for (final DeviceInfo deviceInfo : group) {
final HashSet<TDeviceInfo> group = groups.get(i);
for (final TDeviceInfo deviceInfo : group) {
if (Objects.equals(device, deviceInfo.device)) {
return Optional.of(deviceIds[i]);
return Optional.of(groupIds[i]);
}
}
}
@@ -86,29 +89,29 @@ public abstract class AbstractGroupingDeviceBusElement extends AbstractDeviceBus
///////////////////////////////////////////////////////////////////
protected void setDevicesForGroup(final int index, final HashSet<DeviceInfo> newDevices) {
final HashSet<DeviceInfo> oldDevices = devicesByGroup.get(index);
protected final void setDevicesForGroup(final int index, final Set<TDeviceInfo> newDevices) {
final HashSet<TDeviceInfo> oldDevices = groups.get(index);
if (Objects.equals(newDevices, oldDevices)) {
return;
}
final HashSet<DeviceInfo> removedDevices = new HashSet<>(oldDevices);
final HashSet<TDeviceInfo> removedDevices = new HashSet<>(oldDevices);
removedDevices.removeAll(newDevices);
devices.removeAll(removedDevices.stream().map(info -> info.device).collect(Collectors.toList()));
final HashSet<DeviceInfo> addedDevices = new HashSet<>(newDevices);
final HashSet<TDeviceInfo> addedDevices = new HashSet<>(newDevices);
addedDevices.removeAll(oldDevices);
devices.addAll(addedDevices.stream().map(info -> info.device).collect(Collectors.toList()));
oldDevices.removeAll(removedDevices);
oldDevices.addAll(newDevices);
final CompoundNBT devicesNbt = deviceData[index];
for (final DeviceInfo deviceInfo : removedDevices) {
getSerializationKey(deviceInfo).ifPresent(devicesNbt::remove);
final CompoundNBT devicesNbt = groupData[index];
for (final TDeviceInfo deviceInfo : removedDevices) {
ItemDeviceUtils.getItemDeviceDataKey(deviceInfo.provider).ifPresent(devicesNbt::remove);
}
for (final DeviceInfo deviceInfo : addedDevices) {
getSerializationKey(deviceInfo).ifPresent(key -> {
for (final TDeviceInfo deviceInfo : addedDevices) {
ItemDeviceUtils.getItemDeviceDataKey(deviceInfo.provider).ifPresent(key -> {
if (devicesNbt.contains(key, NBTTagIds.TAG_COMPOUND)) {
deviceInfo.device.deserializeNBT(devicesNbt.getCompound(key));
}
@@ -120,27 +123,17 @@ public abstract class AbstractGroupingDeviceBusElement extends AbstractDeviceBus
///////////////////////////////////////////////////////////////////
private void serializeDevices() {
for (int i = 0; i < groupCount; i++) {
final CompoundNBT devicesNbt = new CompoundNBT();
for (final DeviceInfo deviceInfo : devicesByGroup.get(i)) {
getSerializationKey(deviceInfo).ifPresent(key -> {
final CompoundNBT deviceNbt = deviceInfo.device.serializeNBT();
if (!deviceNbt.isEmpty()) {
devicesNbt.put(key, deviceNbt);
}
});
}
deviceData[i] = devicesNbt;
}
}
private static Optional<String> getSerializationKey(final DeviceInfo info) {
final ResourceLocation providerName = info.provider.getRegistryName();
if (providerName == null) {
return Optional.empty();
private void serializeDevices(final int index) {
final CompoundNBT devicesNbt = new CompoundNBT();
for (final TDeviceInfo deviceInfo : groups.get(index)) {
ItemDeviceUtils.getItemDeviceDataKey(deviceInfo.provider).ifPresent(key -> {
final CompoundNBT deviceNbt = deviceInfo.device.serializeNBT();
if (!deviceNbt.isEmpty()) {
devicesNbt.put(key, deviceNbt);
}
});
}
return Optional.of(providerName.toString());
groupData[index] = devicesNbt;
}
}

View File

@@ -0,0 +1,10 @@
package li.cil.oc2.common.bus;
import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider;
import li.cil.oc2.common.bus.device.ItemDeviceInfo;
public abstract class AbstractGroupingItemDeviceBusElement extends AbstractGroupingDeviceBusElement<ItemDeviceProvider, ItemDeviceInfo> {
public AbstractGroupingItemDeviceBusElement(final int groupCount) {
super(groupCount);
}
}

View File

@@ -1,33 +1,64 @@
package li.cil.oc2.common.bus;
import li.cil.oc2.common.bus.device.DeviceInfo;
import li.cil.oc2.common.bus.device.Devices;
import li.cil.oc2.common.bus.device.ItemDeviceInfo;
import li.cil.oc2.common.util.ItemDeviceUtils;
import li.cil.oc2.common.util.NBTTagIds;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraft.nbt.CompoundNBT;
import java.util.Collections;
import java.util.HashSet;
public class ItemHandlerDeviceBusElement extends AbstractGroupingDeviceBusElement {
private final ItemStackHandler handler;
public class ItemHandlerDeviceBusElement extends AbstractGroupingItemDeviceBusElement {
public ItemHandlerDeviceBusElement(final int slotCount) {
super(slotCount);
}
///////////////////////////////////////////////////////////////////
public ItemHandlerDeviceBusElement(final ItemStackHandler handler) {
super(handler.getSlots());
this.handler = handler;
public void updateDevices(final int slot, final ItemStack stack) {
if (!stack.isEmpty()) {
final HashSet<ItemDeviceInfo> newDevices = new HashSet<>(Devices.getDevices(stack));
importDeviceDataFromItemStack(stack, newDevices);
setDevicesForGroup(slot, newDevices);
} else {
setDevicesForGroup(slot, Collections.emptySet());
}
}
public void handleSlotChanged(final int slot) {
final HashSet<DeviceInfo> newDevices = new HashSet<>();
final ItemStack stack = handler.getStackInSlot(slot);
public void handleBeforeItemRemoved(final int slot, final ItemStack stack) {
if (!stack.isEmpty()) {
for (final LazyOptional<DeviceInfo> info : Devices.getDevices(stack)) {
info.ifPresent(newDevices::add);
info.addListener(unused -> handleSlotChanged(slot));
}
exportDeviceDataToItemStack(slot, stack);
}
}
///////////////////////////////////////////////////////////////////
private void exportDeviceDataToItemStack(final int slot, final ItemStack stack) {
final CompoundNBT exportedNbt = new CompoundNBT();
for (final ItemDeviceInfo info : groups.get(slot)) {
ItemDeviceUtils.getItemDeviceDataKey(info.provider).ifPresent(key -> {
final CompoundNBT deviceNbt = new CompoundNBT();
info.device.exportToItemStack(deviceNbt);
if (!deviceNbt.isEmpty()) {
exportedNbt.put(key, deviceNbt);
}
});
}
setDevicesForGroup(slot, newDevices);
ItemDeviceUtils.setItemDeviceData(stack, exportedNbt);
}
private void importDeviceDataFromItemStack(final ItemStack stack, final HashSet<ItemDeviceInfo> devices) {
ItemDeviceUtils.getItemDeviceData(stack).ifPresent(exportedNbt -> {
for (final ItemDeviceInfo info : devices) {
ItemDeviceUtils.getItemDeviceDataKey(info.provider).ifPresent(key -> {
if (exportedNbt.contains(key, NBTTagIds.TAG_COMPOUND)) {
info.device.importFromItemStack(exportedNbt.getCompound(key));
}
});
}
});
}
}

View File

@@ -71,6 +71,8 @@ public final class RPCAdapter implements Steppable {
.create();
}
///////////////////////////////////////////////////////////////////
public void reset() {
transmitBuffer.clear();
receiveBuffer = null;

View File

@@ -2,7 +2,7 @@ package li.cil.oc2.common.bus;
import li.cil.oc2.api.bus.DeviceBus;
import li.cil.oc2.api.bus.DeviceBusElement;
import li.cil.oc2.common.bus.device.DeviceInfo;
import li.cil.oc2.common.bus.device.BlockDeviceInfo;
import li.cil.oc2.common.bus.device.Devices;
import li.cil.oc2.common.capabilities.Capabilities;
import li.cil.oc2.common.util.ServerScheduler;
@@ -21,7 +21,7 @@ import java.util.Optional;
import static java.util.Objects.requireNonNull;
public class TileEntityDeviceBusElement extends AbstractGroupingDeviceBusElement {
public class TileEntityDeviceBusElement extends AbstractGroupingBlockDeviceBusElement {
private static final int NEIGHBOR_COUNT = 6;
final Direction[] NEIGHBOR_DIRECTIONS = Direction.values();
@@ -36,6 +36,8 @@ public class TileEntityDeviceBusElement extends AbstractGroupingDeviceBusElement
this.tileEntity = tileEntity;
}
///////////////////////////////////////////////////////////////////
@Override
public Optional<Collection<LazyOptional<DeviceBusElement>>> getNeighbors() {
final World world = tileEntity.getWorld();
@@ -80,9 +82,9 @@ public class TileEntityDeviceBusElement extends AbstractGroupingDeviceBusElement
final int index = direction.getIndex();
final HashSet<DeviceInfo> newDevices = new HashSet<>();
final HashSet<BlockDeviceInfo> newDevices = new HashSet<>();
if (canConnectToSide(direction)) {
for (final LazyOptional<DeviceInfo> deviceInfo : Devices.getDevices(world, pos, direction)) {
for (final LazyOptional<BlockDeviceInfo> deviceInfo : Devices.getDevices(world, pos, direction)) {
deviceInfo.ifPresent(newDevices::add);
deviceInfo.addListener(unused -> handleNeighborChanged(pos));
}

View File

@@ -0,0 +1,33 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.Device;
import net.minecraftforge.registries.IForgeRegistryEntry;
import java.util.Objects;
public abstract class AbstractDeviceInfo<TProvider extends IForgeRegistryEntry<TProvider>, TDevice extends Device> {
public final TProvider provider;
public final TDevice device;
///////////////////////////////////////////////////////////////////
protected AbstractDeviceInfo(final TProvider provider, final TDevice device) {
this.provider = provider;
this.device = device;
}
///////////////////////////////////////////////////////////////////
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final AbstractDeviceInfo<?, ?> that = (AbstractDeviceInfo<?, ?>) o;
return provider.equals(that.provider) && device.equals(that.device);
}
@Override
public int hashCode() {
return Objects.hash(provider, device);
}
}

View File

@@ -1,7 +1,6 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.vm.*;
import li.cil.oc2.common.bus.device.provider.util.AbstractObjectProxy;
import li.cil.oc2.common.serialization.BlobStorage;
import li.cil.oc2.common.serialization.NBTSerialization;
import li.cil.oc2.common.util.NBTTagIds;
@@ -17,7 +16,7 @@ import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.UUID;
public abstract class AbstractHardDiskDriveDevice<T extends BlockDevice> extends AbstractObjectProxy<ItemStack> implements VMDevice, VMDeviceLifecycleListener {
public abstract class AbstractHardDiskDriveDevice<T extends BlockDevice> extends AbstractItemDevice implements VMDevice, VMDeviceLifecycleListener {
private static final String DEVICE_NBT_TAG_NAME = "device";
private static final String ADDRESS_NBT_TAG_NAME = "address";
private static final String INTERRUPT_NBT_TAG_NAME = "interrupt";
@@ -45,6 +44,8 @@ public abstract class AbstractHardDiskDriveDevice<T extends BlockDevice> extends
super(stack);
}
///////////////////////////////////////////////////////////////////
@Override
public VMDeviceLoadResult load(final VMContext context) {
if (!allocateDevice(context)) {
@@ -76,6 +77,20 @@ public abstract class AbstractHardDiskDriveDevice<T extends BlockDevice> extends
}
}
@Override
public void exportToItemStack(final CompoundNBT nbt) {
if (blobHandle != null) {
nbt.putUniqueId(BLOB_HANDLE_NBT_TAG_NAME, blobHandle);
}
}
@Override
public void importFromItemStack(final CompoundNBT nbt) {
if (nbt.hasUniqueId(BLOB_HANDLE_NBT_TAG_NAME)) {
blobHandle = nbt.getUniqueId(BLOB_HANDLE_NBT_TAG_NAME);
}
}
@Override
public CompoundNBT serializeNBT() {
final CompoundNBT nbt = new CompoundNBT();

View File

@@ -0,0 +1,21 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.ItemDevice;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
public abstract class AbstractItemDevice extends AbstractObjectDevice<ItemStack> implements ItemDevice {
public AbstractItemDevice(final ItemStack value) {
super(value);
}
///////////////////////////////////////////////////////////////////
@Override
public void exportToItemStack(final CompoundNBT nbt) {
}
@Override
public void importFromItemStack(final CompoundNBT nbt) {
}
}

View File

@@ -1,22 +1,24 @@
package li.cil.oc2.common.bus.device.provider.util;
package li.cil.oc2.common.bus.device;
import javax.annotation.Nullable;
import java.util.Objects;
public abstract class AbstractObjectProxy<T> {
public abstract class AbstractObjectDevice<T> {
protected final T value;
///////////////////////////////////////////////////////////////////
public AbstractObjectProxy(final T value) {
public AbstractObjectDevice(final T value) {
this.value = value;
}
///////////////////////////////////////////////////////////////////
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final AbstractObjectProxy<?> that = (AbstractObjectProxy<?>) o;
final AbstractObjectDevice<?> that = (AbstractObjectDevice<?>) o;
return value.equals(that.value);
}

View File

@@ -0,0 +1,10 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider;
public final class BlockDeviceInfo extends AbstractDeviceInfo<BlockDeviceProvider, Device> {
public BlockDeviceInfo(final BlockDeviceProvider blockDeviceProvider, final Device device) {
super(blockDeviceProvider, device);
}
}

View File

@@ -1,29 +0,0 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.provider.DeviceProvider;
import java.util.Objects;
public final class DeviceInfo {
public final Device device;
public final DeviceProvider provider;
public DeviceInfo(final Device device, final DeviceProvider provider) {
this.device = device;
this.provider = provider;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DeviceInfo that = (DeviceInfo) o;
return device.equals(that.device) && provider.equals(that.provider);
}
@Override
public int hashCode() {
return Objects.hash(device, provider);
}
}

View File

@@ -1,9 +1,10 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.api.bus.device.provider.DeviceProvider;
import li.cil.oc2.api.bus.device.provider.DeviceQuery;
import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider;
import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery;
import li.cil.oc2.common.init.Providers;
import net.minecraft.item.ItemStack;
@@ -17,9 +18,10 @@ import net.minecraftforge.registries.IForgeRegistry;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public final class Devices {
public static List<LazyOptional<DeviceInfo>> getDevices(final TileEntity tileEntity, final Direction side) {
public static List<LazyOptional<BlockDeviceInfo>> getDevices(final TileEntity tileEntity, final Direction side) {
final World world = tileEntity.getWorld();
final BlockPos pos = tileEntity.getPos();
@@ -28,21 +30,23 @@ public final class Devices {
return getDevices(world, pos, side);
}
public static List<LazyOptional<DeviceInfo>> getDevices(final World world, final BlockPos pos, final Direction side) {
public static List<LazyOptional<BlockDeviceInfo>> getDevices(final World world, final BlockPos pos, final Direction side) {
return getDevices(new BlockQuery(world, pos, side));
}
public static List<LazyOptional<DeviceInfo>> getDevices(final ItemStack stack) {
public static List<ItemDeviceInfo> getDevices(final ItemStack stack) {
return getDevices(new ItemQuery(stack));
}
public static List<LazyOptional<DeviceInfo>> getDevices(final DeviceQuery query) {
final IForgeRegistry<DeviceProvider> providers = Providers.PROVIDERS_REGISTRY.get();
final ArrayList<LazyOptional<DeviceInfo>> devices = new ArrayList<>();
for (final DeviceProvider provider : providers.getValues()) {
///////////////////////////////////////////////////////////////////
private static List<LazyOptional<BlockDeviceInfo>> getDevices(final BlockQuery query) {
final IForgeRegistry<BlockDeviceProvider> registry = Providers.BLOCK_DEVICE_PROVIDER_REGISTRY.get();
final ArrayList<LazyOptional<BlockDeviceInfo>> devices = new ArrayList<>();
for (final BlockDeviceProvider provider : registry.getValues()) {
final LazyOptional<Device> device = provider.getDevice(query);
if (device.isPresent()) {
final LazyOptional<DeviceInfo> info = device.lazyMap(d -> new DeviceInfo(d, provider));
final LazyOptional<BlockDeviceInfo> info = device.lazyMap(d -> new BlockDeviceInfo(provider, d));
device.addListener(unused -> info.invalidate());
devices.add(info);
}
@@ -50,6 +54,16 @@ public final class Devices {
return devices;
}
private static List<ItemDeviceInfo> getDevices(final ItemQuery query) {
final IForgeRegistry<ItemDeviceProvider> registry = Providers.ITEM_DEVICE_PROVIDER_REGISTRY.get();
final ArrayList<ItemDeviceInfo> devices = new ArrayList<>();
for (final ItemDeviceProvider provider : registry.getValues()) {
final Optional<ItemDevice> device = provider.getDevice(query);
device.ifPresent(d -> devices.add(new ItemDeviceInfo(provider, d)));
}
return devices;
}
///////////////////////////////////////////////////////////////////
private static class BlockQuery implements BlockDeviceQuery {

View File

@@ -11,12 +11,16 @@ public final class HardDiskDriveDevice extends AbstractHardDiskDriveDevice<ByteB
private final int size;
private final boolean readonly;
///////////////////////////////////////////////////////////////////
public HardDiskDriveDevice(final ItemStack stack, final int size, final boolean readonly) {
super(stack);
this.size = size;
this.readonly = readonly;
}
///////////////////////////////////////////////////////////////////
@Override
protected int getSize() {
return size;

View File

@@ -0,0 +1,10 @@
package li.cil.oc2.common.bus.device;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider;
public class ItemDeviceInfo extends AbstractDeviceInfo<ItemDeviceProvider, ItemDevice> {
public ItemDeviceInfo(final ItemDeviceProvider itemDeviceProvider, final ItemDevice device) {
super(itemDeviceProvider, device);
}
}

View File

@@ -2,7 +2,6 @@ package li.cil.oc2.common.bus.device;
import li.cil.oc2.Constants;
import li.cil.oc2.api.bus.device.vm.*;
import li.cil.oc2.common.bus.device.provider.util.AbstractObjectProxy;
import li.cil.oc2.common.serialization.BlobStorage;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.sedna.api.device.PhysicalMemory;
@@ -15,7 +14,7 @@ import net.minecraft.nbt.CompoundNBT;
import java.util.OptionalLong;
import java.util.UUID;
public final class MemoryDevice extends AbstractObjectProxy<ItemStack> implements VMDevice, VMDeviceLifecycleListener {
public final class MemoryDevice extends AbstractItemDevice implements VMDevice, VMDeviceLifecycleListener {
private static final String BLOB_HANDLE_NBT_TAG_NAME = "blob";
private static final String ADDRESS_NBT_TAG_NAME = "address";
@@ -37,6 +36,8 @@ public final class MemoryDevice extends AbstractObjectProxy<ItemStack> implement
super(value);
}
///////////////////////////////////////////////////////////////////
@Override
public VMDeviceLoadResult load(final VMContext context) {
if (!allocateDevice(context)) {

View File

@@ -1,35 +0,0 @@
package li.cil.oc2.common.bus.device.provider;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.Callbacks;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.api.bus.device.provider.DeviceQuery;
import li.cil.oc2.common.bus.device.provider.util.AbstractDeviceProvider;
import li.cil.oc2.common.util.WorldUtils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraftforge.common.util.LazyOptional;
public final class BlockDeviceProvider extends AbstractDeviceProvider {
@Override
public LazyOptional<Device> getDevice(final DeviceQuery query) {
if (!(query instanceof BlockDeviceQuery)) {
return LazyOptional.empty();
}
final BlockDeviceQuery blockQuery = (BlockDeviceQuery) query;
final BlockState blockState = blockQuery.getWorld().getBlockState(blockQuery.getQueryPosition());
if (blockState.getBlock().isAir(blockState, blockQuery.getWorld(), blockQuery.getQueryPosition())) {
return LazyOptional.empty();
}
final Block block = blockState.getBlock();
if (!Callbacks.hasMethods(block)) {
return LazyOptional.empty();
}
final String typeName = WorldUtils.getBlockName(blockQuery.getWorld(), blockQuery.getQueryPosition());
return LazyOptional.of(() -> new ObjectDevice(block, typeName));
}
}

View File

@@ -0,0 +1,35 @@
package li.cil.oc2.common.bus.device.provider;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.Callbacks;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.common.bus.device.provider.util.AbstractBlockDeviceProvider;
import li.cil.oc2.common.util.WorldUtils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
public final class BlockStateDeviceProvider extends AbstractBlockDeviceProvider {
@Override
public LazyOptional<Device> getDevice(final BlockDeviceQuery query) {
final World world = query.getWorld();
final BlockPos position = query.getQueryPosition();
final BlockState blockState = world.getBlockState(position);
final Block block = blockState.getBlock();
if (block.isAir(blockState, world, position)) {
return LazyOptional.empty();
}
if (!Callbacks.hasMethods(block)) {
return LazyOptional.empty();
}
final String typeName = WorldUtils.getBlockName(world, position);
return LazyOptional.of(() -> new ObjectDevice(block, typeName));
}
}

View File

@@ -4,31 +4,32 @@ import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.Callback;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.common.bus.device.provider.util.AbstractCapabilityAnyTileEntityDeviceProvider;
import li.cil.oc2.common.bus.device.provider.util.AbstractObjectProxy;
import li.cil.oc2.common.bus.device.provider.util.AbstractTileEntityCapabilityDeviceProvider;
import li.cil.oc2.common.bus.device.AbstractObjectDevice;
import li.cil.oc2.common.capabilities.Capabilities;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
public final class EnergyStorageDeviceProvider extends AbstractCapabilityAnyTileEntityDeviceProvider<IEnergyStorage> {
public final class EnergyStorageBlockDeviceProvider extends AbstractTileEntityCapabilityDeviceProvider<IEnergyStorage, TileEntity> {
private static final String ENERGY_STORAGE_TYPE_NAME = "energyStorage";
///////////////////////////////////////////////////////////////////
public EnergyStorageDeviceProvider() {
public EnergyStorageBlockDeviceProvider() {
super(() -> Capabilities.ENERGY_STORAGE_CAPABILITY);
}
///////////////////////////////////////////////////////////////////
@Override
protected LazyOptional<Device> getDevice(final BlockDeviceQuery query, final IEnergyStorage value) {
protected LazyOptional<Device> getBlockDevice(final BlockDeviceQuery query, final IEnergyStorage value) {
return LazyOptional.of(() -> new ObjectDevice(new EnergyStorageDevice(value), ENERGY_STORAGE_TYPE_NAME));
}
///////////////////////////////////////////////////////////////////
public static final class EnergyStorageDevice extends AbstractObjectProxy<IEnergyStorage> {
public static final class EnergyStorageDevice extends AbstractObjectDevice<IEnergyStorage> {
public EnergyStorageDevice(final IEnergyStorage energyStorage) {
super(energyStorage);
}

View File

@@ -4,32 +4,33 @@ import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.Callback;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.common.bus.device.provider.util.AbstractCapabilityAnyTileEntityDeviceProvider;
import li.cil.oc2.common.bus.device.provider.util.AbstractObjectProxy;
import li.cil.oc2.common.bus.device.provider.util.AbstractTileEntityCapabilityDeviceProvider;
import li.cil.oc2.common.bus.device.AbstractObjectDevice;
import li.cil.oc2.common.capabilities.Capabilities;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
public final class FluidHandlerDeviceProvider extends AbstractCapabilityAnyTileEntityDeviceProvider<IFluidHandler> {
public final class FluidHandlerBlockDeviceProvider extends AbstractTileEntityCapabilityDeviceProvider<IFluidHandler, TileEntity> {
private static final String FLUID_HANDLER_TYPE_NAME = "fluidHandler";
///////////////////////////////////////////////////////////////////
public FluidHandlerDeviceProvider() {
public FluidHandlerBlockDeviceProvider() {
super(() -> Capabilities.FLUID_HANDLER_CAPABILITY);
}
///////////////////////////////////////////////////////////////////
@Override
protected LazyOptional<Device> getDevice(final BlockDeviceQuery query, final IFluidHandler value) {
protected LazyOptional<Device> getBlockDevice(final BlockDeviceQuery query, final IFluidHandler value) {
return LazyOptional.of(() -> new ObjectDevice(new FluidHandlerDevice(value), FLUID_HANDLER_TYPE_NAME));
}
///////////////////////////////////////////////////////////////////
public static final class FluidHandlerDevice extends AbstractObjectProxy<IFluidHandler> {
public static final class FluidHandlerDevice extends AbstractObjectDevice<IFluidHandler> {
public FluidHandlerDevice(final IFluidHandler fluidHandler) {
super(fluidHandler);
}

View File

@@ -2,70 +2,88 @@ package li.cil.oc2.common.bus.device.provider;
import li.cil.oc2.Config;
import li.cil.oc2.Constants;
import li.cil.oc2.api.API;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery;
import li.cil.oc2.common.bus.device.HardDiskDriveDevice;
import li.cil.oc2.common.bus.device.SparseHardDiskDriveDevice;
import li.cil.oc2.common.bus.device.provider.util.AbstractItemDeviceProvider;
import li.cil.oc2.common.init.Items;
import li.cil.oc2.common.util.ItemStackUtils;
import li.cil.oc2.common.util.NBTTagIds;
import li.cil.sedna.api.device.BlockDevice;
import li.cil.sedna.buildroot.Buildroot;
import li.cil.sedna.device.block.ByteBufferBlockDevice;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.common.util.LazyOptional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
public final class HardDriveItemDeviceProvider extends AbstractItemDeviceProvider {
private static final Logger LOGGER = LogManager.getLogger();
///////////////////////////////////////////////////////////////////
private static final ByteBufferBlockDevice ROOT_FS;
static {
ByteBufferBlockDevice rootfs;
try {
rootfs = ByteBufferBlockDevice.createFromStream(Buildroot.getRootFilesystem(), true);
} catch (final IOException e) {
LOGGER.error(e);
rootfs = ByteBufferBlockDevice.create(0, true);
}
ROOT_FS = rootfs;
}
///////////////////////////////////////////////////////////////////
public HardDriveItemDeviceProvider() {
super(Items.HDD_ITEM.get());
super(Items.HDD_ITEM);
}
///////////////////////////////////////////////////////////////////
@Override
protected LazyOptional<Device> getItemDevice(final ItemDeviceQuery query) {
protected Optional<ItemDevice> getItemDevice(final ItemDeviceQuery query) {
final ItemStack stack = query.getItemStack();
final CompoundNBT info = stack.getChildTag(API.MOD_ID);
final CompoundNBT info = ItemStackUtils.getModDataTag(stack);
if (info == null) {
return LazyOptional.empty();
return Optional.empty();
}
final boolean readonly = info.getBoolean(Constants.HDD_READONLY_NBT_TAG_NAME);
if (info.contains(Constants.HDD_BASE_NBT_TAG_NAME, NBTTagIds.TAG_STRING)) {
final String baseName = info.getString(Constants.HDD_BASE_NBT_TAG_NAME);
BlockDevice base = null;
// TODO Allow registering additional base file systems?
if (Objects.equals(baseName, "linux")) {
try {
base = ByteBufferBlockDevice.createFromStream(Buildroot.getRootFilesystem(), true);
} catch (final IOException e) {
LOGGER.error(e);
}
}
final BlockDevice base = getBaseBlockDevice(baseName);
if (base != null) {
final BlockDevice baseForClosure = base;
return LazyOptional.of(() -> new SparseHardDiskDriveDevice(stack, baseForClosure, readonly));
return Optional.of(new SparseHardDiskDriveDevice(stack, base, readonly));
}
} else if (info.contains(Constants.HDD_SIZE_NBT_TAG_NAME, NBTTagIds.TAG_INT)) {
final int size = Math.max(0, Math.min(Config.maxHddSize, info.getInt(Constants.HDD_SIZE_NBT_TAG_NAME)));
return LazyOptional.of(() -> new HardDiskDriveDevice(stack, size, readonly));
return Optional.of(new HardDiskDriveDevice(stack, size, readonly));
}
return LazyOptional.empty();
return Optional.empty();
}
///////////////////////////////////////////////////////////////////
@Nullable
private static BlockDevice getBaseBlockDevice(final String name) {
// TODO Allow registering additional base file systems.
if (Objects.equals(name, "linux")) {
return ROOT_FS;
}
return null;
}
}

View File

@@ -4,32 +4,33 @@ import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.object.Callback;
import li.cil.oc2.api.bus.device.object.ObjectDevice;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.common.bus.device.provider.util.AbstractCapabilityAnyTileEntityDeviceProvider;
import li.cil.oc2.common.bus.device.provider.util.AbstractObjectProxy;
import li.cil.oc2.common.bus.device.AbstractObjectDevice;
import li.cil.oc2.common.bus.device.provider.util.AbstractTileEntityCapabilityDeviceProvider;
import li.cil.oc2.common.capabilities.Capabilities;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
public final class ItemHandlerDeviceProvider extends AbstractCapabilityAnyTileEntityDeviceProvider<IItemHandler> {
public final class ItemHandlerBlockDeviceProvider extends AbstractTileEntityCapabilityDeviceProvider<IItemHandler, TileEntity> {
private static final String ITEM_HANDLER_TYPE_NAME = "itemHandler";
///////////////////////////////////////////////////////////////////
public ItemHandlerDeviceProvider() {
public ItemHandlerBlockDeviceProvider() {
super(() -> Capabilities.ITEM_HANDLER_CAPABILITY);
}
///////////////////////////////////////////////////////////////////
@Override
protected LazyOptional<Device> getDevice(final BlockDeviceQuery query, final IItemHandler value) {
protected LazyOptional<Device> getBlockDevice(final BlockDeviceQuery query, final IItemHandler value) {
return LazyOptional.of(() -> new ObjectDevice(new ItemHandlerDevice(value), ITEM_HANDLER_TYPE_NAME));
}
///////////////////////////////////////////////////////////////////
public static final class ItemHandlerDevice extends AbstractObjectProxy<IItemHandler> {
public static final class ItemHandlerDevice extends AbstractObjectDevice<IItemHandler> {
public ItemHandlerDevice(final IItemHandler itemHandler) {
super(itemHandler);
}

View File

@@ -1,21 +1,22 @@
package li.cil.oc2.common.bus.device.provider;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery;
import li.cil.oc2.common.bus.device.MemoryDevice;
import li.cil.oc2.common.bus.device.provider.util.AbstractItemDeviceProvider;
import li.cil.oc2.common.init.Items;
import net.minecraftforge.common.util.LazyOptional;
import java.util.Optional;
public final class MemoryItemDeviceProvider extends AbstractItemDeviceProvider {
public MemoryItemDeviceProvider() {
super(Items.RAM_8M_ITEM.get());
super(Items.RAM_8M_ITEM);
}
///////////////////////////////////////////////////////////////////
@Override
protected LazyOptional<Device> getItemDevice(final ItemDeviceQuery query) {
return LazyOptional.of(() -> new MemoryDevice(query.getItemStack()));
protected Optional<ItemDevice> getItemDevice(final ItemDeviceQuery query) {
return Optional.of(new MemoryDevice(query.getItemStack()));
}
}

View File

@@ -7,15 +7,12 @@ import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.common.bus.device.provider.util.AbstractTileEntityDeviceProvider;
import li.cil.oc2.common.util.WorldUtils;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.common.util.LazyOptional;
public final class TileEntityDeviceProvider extends AbstractTileEntityDeviceProvider<TileEntity> {
public TileEntityDeviceProvider() {
super(TileEntity.class);
}
@Override
public LazyOptional<Device> getDevice(final BlockDeviceQuery query, final TileEntity tileEntity) {
public LazyOptional<Device> getBlockDevice(final BlockDeviceQuery query, final TileEntity tileEntity) {
if (Callbacks.hasMethods(tileEntity)) {
return LazyOptional.of(() -> {
final String typeName = WorldUtils.getBlockName(query.getWorld(), query.getQueryPosition());

View File

@@ -0,0 +1,7 @@
package li.cil.oc2.common.bus.device.provider.util;
import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider;
import net.minecraftforge.registries.ForgeRegistryEntry;
public abstract class AbstractBlockDeviceProvider extends ForgeRegistryEntry<BlockDeviceProvider> implements BlockDeviceProvider {
}

View File

@@ -1,12 +0,0 @@
package li.cil.oc2.common.bus.device.provider.util;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.capabilities.Capability;
import java.util.function.Supplier;
public abstract class AbstractCapabilityAnyTileEntityDeviceProvider<TCapability> extends AbstractCapabilityTileEntityDeviceProvider<TCapability, TileEntity> {
public AbstractCapabilityAnyTileEntityDeviceProvider(final Supplier<Capability<TCapability>> capabilitySupplier) {
super(TileEntity.class, capabilitySupplier);
}
}

View File

@@ -1,7 +0,0 @@
package li.cil.oc2.common.bus.device.provider.util;
import li.cil.oc2.api.bus.device.provider.DeviceProvider;
import net.minecraftforge.registries.ForgeRegistryEntry;
public abstract class AbstractDeviceProvider extends ForgeRegistryEntry<DeviceProvider> implements DeviceProvider {
}

View File

@@ -1,37 +1,45 @@
package li.cil.oc2.common.bus.device.provider.util;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.provider.DeviceQuery;
import li.cil.oc2.api.bus.device.ItemDevice;
import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider;
import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.ForgeRegistryEntry;
public abstract class AbstractItemDeviceProvider extends AbstractDeviceProvider {
private final Item item;
import java.util.Optional;
protected AbstractItemDeviceProvider(final Item item) {
public abstract class AbstractItemDeviceProvider extends ForgeRegistryEntry<ItemDeviceProvider> implements ItemDeviceProvider {
private final RegistryObject<Item> item;
///////////////////////////////////////////////////////////////////
protected AbstractItemDeviceProvider(final RegistryObject<Item> item) {
this.item = item;
}
@Override
public LazyOptional<Device> getDevice(final DeviceQuery query) {
if (!(query instanceof ItemDeviceQuery)) {
return LazyOptional.empty();
}
final ItemDeviceQuery itemDeviceQuery = (ItemDeviceQuery) query;
final ItemStack stack = itemDeviceQuery.getItemStack();
if (stack.isEmpty()) {
return LazyOptional.empty();
}
if (stack.getItem() != item) {
return LazyOptional.empty();
}
return getItemDevice(itemDeviceQuery);
protected AbstractItemDeviceProvider() {
this.item = null;
}
protected abstract LazyOptional<Device> getItemDevice(final ItemDeviceQuery query);
///////////////////////////////////////////////////////////////////
@Override
public final Optional<ItemDevice> getDevice(final ItemDeviceQuery query) {
final ItemStack stack = query.getItemStack();
if (stack.isEmpty()) {
return Optional.empty();
}
if (item != null && stack.getItem() != item.get()) {
return Optional.empty();
}
return getItemDevice(query);
}
///////////////////////////////////////////////////////////////////
protected abstract Optional<ItemDevice> getItemDevice(final ItemDeviceQuery query);
}

View File

@@ -3,23 +3,30 @@ package li.cil.oc2.common.bus.device.provider.util;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import java.util.function.Supplier;
public abstract class AbstractCapabilityTileEntityDeviceProvider<TCapability, TTileEntity extends TileEntity> extends AbstractTileEntityDeviceProvider<TTileEntity> {
public abstract class AbstractTileEntityCapabilityDeviceProvider<TCapability, TTileEntity extends TileEntity> extends AbstractTileEntityDeviceProvider<TTileEntity> {
private final Supplier<Capability<TCapability>> capabilitySupplier;
///////////////////////////////////////////////////////////////////
protected AbstractCapabilityTileEntityDeviceProvider(final Class<TTileEntity> tileEntityType, final Supplier<Capability<TCapability>> capabilitySupplier) {
protected AbstractTileEntityCapabilityDeviceProvider(final TileEntityType<TTileEntity> tileEntityType, final Supplier<Capability<TCapability>> capabilitySupplier) {
super(tileEntityType);
this.capabilitySupplier = capabilitySupplier;
}
protected AbstractTileEntityCapabilityDeviceProvider(final Supplier<Capability<TCapability>> capabilitySupplier) {
this.capabilitySupplier = capabilitySupplier;
}
///////////////////////////////////////////////////////////////////
@Override
protected final LazyOptional<Device> getDevice(final BlockDeviceQuery blockQuery, final TileEntity tileEntity) {
protected final LazyOptional<Device> getBlockDevice(final BlockDeviceQuery blockQuery, final TileEntity tileEntity) {
final Capability<TCapability> capability = capabilitySupplier.get();
if (capability == null) throw new IllegalStateException();
final LazyOptional<TCapability> optional = tileEntity.getCapability(capability, blockQuery.getQuerySide());
@@ -28,10 +35,10 @@ public abstract class AbstractCapabilityTileEntityDeviceProvider<TCapability, TT
}
final TCapability value = optional.orElseThrow(AssertionError::new);
final LazyOptional<Device> device = getDevice(blockQuery, value);
final LazyOptional<Device> device = getBlockDevice(blockQuery, value);
optional.addListener(ignored -> device.invalidate());
return device;
}
protected abstract LazyOptional<Device> getDevice(final BlockDeviceQuery query, final TCapability value);
protected abstract LazyOptional<Device> getBlockDevice(final BlockDeviceQuery query, final TCapability value);
}

View File

@@ -2,37 +2,42 @@ package li.cil.oc2.common.bus.device.provider.util;
import li.cil.oc2.api.bus.device.Device;
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
import li.cil.oc2.api.bus.device.provider.DeviceQuery;
import li.cil.oc2.common.util.WorldUtils;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.common.util.LazyOptional;
public abstract class AbstractTileEntityDeviceProvider<T extends TileEntity> extends AbstractDeviceProvider {
private final Class<T> tileEntityType;
public abstract class AbstractTileEntityDeviceProvider<T extends TileEntity> extends AbstractBlockDeviceProvider {
private final TileEntityType<T> tileEntityType;
///////////////////////////////////////////////////////////////////
protected AbstractTileEntityDeviceProvider(final Class<T> tileEntityType) {
protected AbstractTileEntityDeviceProvider(final TileEntityType<T> tileEntityType) {
this.tileEntityType = tileEntityType;
}
@SuppressWarnings("unchecked")
@Override
public LazyOptional<Device> getDevice(final DeviceQuery query) {
if (!(query instanceof BlockDeviceQuery)) {
return LazyOptional.empty();
}
final BlockDeviceQuery blockQuery = (BlockDeviceQuery) query;
final TileEntity tileEntity = WorldUtils.getTileEntityIfChunkExists(blockQuery.getWorld(), blockQuery.getQueryPosition());
if (!tileEntityType.isInstance(tileEntity)) {
return LazyOptional.empty();
}
return getDevice(blockQuery, (T) tileEntity);
protected AbstractTileEntityDeviceProvider() {
this.tileEntityType = null;
}
///////////////////////////////////////////////////////////////////
protected abstract LazyOptional<Device> getDevice(final BlockDeviceQuery query, final T tileEntity);
@SuppressWarnings("unchecked")
@Override
public final LazyOptional<Device> getDevice(final BlockDeviceQuery query) {
final TileEntity tileEntity = WorldUtils.getTileEntityIfChunkExists(query.getWorld(), query.getQueryPosition());
if (tileEntity == null) {
return LazyOptional.empty();
}
if (tileEntityType != null && tileEntity.getType() != tileEntityType) {
return LazyOptional.empty();
}
return getBlockDevice(query, (T) tileEntity);
}
///////////////////////////////////////////////////////////////////
protected abstract LazyOptional<Device> getBlockDevice(final BlockDeviceQuery query, final T tileEntity);
}

View File

@@ -24,9 +24,11 @@ public class DeviceItemStackHandler extends ItemStackHandler {
public DeviceItemStackHandler(final NonNullList<ItemStack> stacks) {
super(stacks);
this.busElement = new ItemHandlerDeviceBusElement(this);
this.busElement = new ItemHandlerDeviceBusElement(getSlots());
}
///////////////////////////////////////////////////////////////////
public DeviceBusElement getBusElement() {
return busElement;
}
@@ -42,14 +44,19 @@ public class DeviceItemStackHandler extends ItemStackHandler {
public void deserializeNBT(final CompoundNBT nbt) {
super.deserializeNBT(nbt);
busElement.deserializeNBT(nbt.getList(BUS_ELEMENT_NBT_TAG_NAME, NBTTagIds.TAG_COMPOUND));
for (int i = 0; i < getSlots(); i++) {
busElement.handleSlotChanged(i);
for (int slot = 0; slot < getSlots(); slot++) {
busElement.updateDevices(slot, getStackInSlot(slot));
}
}
@NotNull
@Override
public boolean isItemValid(final int slot, @NotNull final ItemStack stack) {
return super.isItemValid(slot, stack);
public ItemStack extractItem(final int slot, final int amount, final boolean simulate) {
if (!simulate && amount > 0) {
busElement.handleBeforeItemRemoved(slot, getStackInSlot(slot));
}
return super.extractItem(slot, amount, simulate);
}
@Override
@@ -57,11 +64,16 @@ public class DeviceItemStackHandler extends ItemStackHandler {
return 1;
}
@Override
public boolean isItemValid(final int slot, @NotNull final ItemStack stack) {
return super.isItemValid(slot, stack);
}
///////////////////////////////////////////////////////////////////
@Override
protected void onContentsChanged(final int slot) {
super.onContentsChanged(slot);
busElement.handleSlotChanged(slot);
busElement.updateDevices(slot, getStackInSlot(slot));
}
}

View File

@@ -1,7 +1,8 @@
package li.cil.oc2.common.init;
import li.cil.oc2.api.API;
import li.cil.oc2.api.bus.device.provider.DeviceProvider;
import li.cil.oc2.api.bus.device.provider.BlockDeviceProvider;
import li.cil.oc2.api.bus.device.provider.ItemDeviceProvider;
import li.cil.oc2.common.bus.device.provider.*;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
@@ -11,25 +12,28 @@ import net.minecraftforge.registries.RegistryBuilder;
import java.util.function.Supplier;
public final class Providers {
private static final DeferredRegister<DeviceProvider> PROVIDERS = DeferredRegister.create(DeviceProvider.class, API.MOD_ID);
private static final DeferredRegister<BlockDeviceProvider> BLOCK_DEVICE_PROVIDERS = DeferredRegister.create(BlockDeviceProvider.class, API.MOD_ID);
private static final DeferredRegister<ItemDeviceProvider> ITEM_DEVICE_PROVIDERS = DeferredRegister.create(ItemDeviceProvider.class, API.MOD_ID);
///////////////////////////////////////////////////////////////////
public static final Supplier<IForgeRegistry<DeviceProvider>> PROVIDERS_REGISTRY = PROVIDERS.makeRegistry("device_providers", RegistryBuilder::new);
public static final Supplier<IForgeRegistry<BlockDeviceProvider>> BLOCK_DEVICE_PROVIDER_REGISTRY = BLOCK_DEVICE_PROVIDERS.makeRegistry("block_device_providers", RegistryBuilder::new);
public static final Supplier<IForgeRegistry<ItemDeviceProvider>> ITEM_DEVICE_PROVIDER_REGISTRY = ITEM_DEVICE_PROVIDERS.makeRegistry("item_device_providers", RegistryBuilder::new);
///////////////////////////////////////////////////////////////////
public static void initialize() {
PROVIDERS.register("block", BlockDeviceProvider::new);
PROVIDERS.register("tile_entity", TileEntityDeviceProvider::new);
BLOCK_DEVICE_PROVIDERS.register("block", BlockStateDeviceProvider::new);
BLOCK_DEVICE_PROVIDERS.register("tile_entity", TileEntityDeviceProvider::new);
PROVIDERS.register("energy_storage", EnergyStorageDeviceProvider::new);
PROVIDERS.register("fluid_handler", FluidHandlerDeviceProvider::new);
PROVIDERS.register("item_handler", ItemHandlerDeviceProvider::new);
BLOCK_DEVICE_PROVIDERS.register("energy_storage", EnergyStorageBlockDeviceProvider::new);
BLOCK_DEVICE_PROVIDERS.register("fluid_handler", FluidHandlerBlockDeviceProvider::new);
BLOCK_DEVICE_PROVIDERS.register("item_handler", ItemHandlerBlockDeviceProvider::new);
PROVIDERS.register("item_memory", MemoryItemDeviceProvider::new);
PROVIDERS.register("item_hard_drive", HardDriveItemDeviceProvider::new);
ITEM_DEVICE_PROVIDERS.register("item_memory", MemoryItemDeviceProvider::new);
ITEM_DEVICE_PROVIDERS.register("item_hard_drive", HardDriveItemDeviceProvider::new);
PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus());
BLOCK_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus());
ITEM_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus());
}
}

View File

@@ -22,6 +22,8 @@ public final class Network {
PROTOCOL_VERSION::equals
);
///////////////////////////////////////////////////////////////////
private static int nextPacketId = 1;
///////////////////////////////////////////////////////////////////

View File

@@ -21,6 +21,8 @@ public abstract class AbstractTerminalBlockMessage {
fromBytes(buffer);
}
///////////////////////////////////////////////////////////////////
public void fromBytes(final PacketBuffer buffer) {
pos = buffer.readBlockPos();
data = buffer.readByteArray();

View File

@@ -24,6 +24,8 @@ public class ComputerBusStateMessage {
fromBytes(buffer);
}
///////////////////////////////////////////////////////////////////
public static boolean handleMessage(final ComputerBusStateMessage message, final Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> MessageUtils.withClientTileEntityAt(message.pos, ComputerTileEntity.class,
(tileEntity) -> tileEntity.setBusStateClient(message.busState)));

View File

@@ -23,6 +23,8 @@ public class ComputerRunStateMessage {
fromBytes(buffer);
}
///////////////////////////////////////////////////////////////////
public static boolean handleMessage(final ComputerRunStateMessage message, final Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> MessageUtils.withClientTileEntityAt(message.pos, ComputerTileEntity.class,
(tileEntity) -> tileEntity.setRunStateClient(message.runState)));

View File

@@ -17,6 +17,8 @@ public final class TerminalBlockInputMessage extends AbstractTerminalBlockMessag
super(buffer);
}
///////////////////////////////////////////////////////////////////
public static boolean handleMessage(final AbstractTerminalBlockMessage message, final Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> MessageUtils.withServerTileEntityAt(context, message.pos, ComputerTileEntity.class,
(tileEntity) -> tileEntity.getTerminal().putInput(ByteBuffer.wrap(message.data))));

View File

@@ -17,6 +17,8 @@ public final class TerminalBlockOutputMessage extends AbstractTerminalBlockMessa
super(buffer);
}
///////////////////////////////////////////////////////////////////
public static boolean handleMessage(final AbstractTerminalBlockMessage message, final Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> MessageUtils.withClientTileEntityAt(message.pos, ComputerTileEntity.class,
tileEntity -> tileEntity.getTerminal().putOutput(ByteBuffer.wrap(message.data))));

View File

@@ -9,6 +9,8 @@ import javax.annotation.Nullable;
public final class HorizontalBlockUtils {
public static final int HORIZONTAL_DIRECTION_COUNT = 4;
///////////////////////////////////////////////////////////////////
@Nullable
public static Direction toLocal(final BlockState blockState, @Nullable final Direction direction) {
if (direction == null) {

View File

@@ -0,0 +1,49 @@
package li.cil.oc2.common.util;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.registries.IForgeRegistryEntry;
import javax.annotation.Nullable;
import java.util.Optional;
public final class ItemDeviceUtils {
private static final String ITEM_DEVICE_DATA_NBT_TAG_NAME = "item_device";
///////////////////////////////////////////////////////////////////
public static Optional<CompoundNBT> getItemDeviceData(final ItemStack stack) {
if (stack.isEmpty()) {
return Optional.empty();
}
final CompoundNBT nbt = ItemStackUtils.getModDataTag(stack);
if (nbt == null) {
return Optional.empty();
}
return Optional.of(nbt.getCompound(ITEM_DEVICE_DATA_NBT_TAG_NAME));
}
public static void setItemDeviceData(final ItemStack stack, final CompoundNBT data) {
if (data.isEmpty()) {
return;
}
ItemStackUtils.getOrCreateModDataTag(stack).put(ITEM_DEVICE_DATA_NBT_TAG_NAME, data);
}
public static Optional<String> getItemDeviceDataKey(@Nullable final IForgeRegistryEntry<?> provider) {
if (provider == null) {
return Optional.empty();
}
final ResourceLocation providerName = provider.getRegistryName();
if (providerName == null) {
return Optional.empty();
}
return Optional.of(providerName.toString());
}
}

View File

@@ -0,0 +1,26 @@
package li.cil.oc2.common.util;
import li.cil.oc2.api.API;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import javax.annotation.Nullable;
public final class ItemStackUtils {
@Nullable
public static CompoundNBT getModDataTag(final ItemStack stack) {
if (stack.isEmpty()) {
return null;
}
return stack.getChildTag(API.MOD_ID);
}
public static CompoundNBT getOrCreateModDataTag(final ItemStack stack) {
if (stack.isEmpty()) {
throw new IllegalArgumentException();
}
return stack.getOrCreateChildTag(API.MOD_ID);
}
}

View File

@@ -23,6 +23,8 @@ public final class ManagedInterruptAllocator implements InterruptAllocator {
this.interruptCount = interruptCount;
}
///////////////////////////////////////////////////////////////////
public void freeze() {
isFrozen = true;
}

View File

@@ -15,6 +15,8 @@ public final class ManagedInterruptController implements InterruptController {
this.allocator = allocator;
}
///////////////////////////////////////////////////////////////////
public void invalidate() {
isValid = false;
interruptController.lowerInterrupts(raisedInterrupts);

View File

@@ -9,6 +9,8 @@ public final class ManagedMemoryAllocator implements MemoryAllocator {
private final ArrayList<UUID> claimedMemory = new ArrayList<>();
private boolean isFrozen;
///////////////////////////////////////////////////////////////////
public void freeze() {
isFrozen = true;
}

View File

@@ -18,6 +18,8 @@ final class ManagedMemoryMap implements MemoryMap {
this.memoryMap = memoryMap;
}
///////////////////////////////////////////////////////////////////
@Override
public OptionalLong findFreeRange(final long start, final long end, final int size) {
return memoryMap.findFreeRange(start, end, size);

View File

@@ -14,10 +14,14 @@ public final class ManagedMemoryRangeAllocator implements MemoryRangeAllocator {
private final ArrayList<MemoryMappedDevice> managedDevices = new ArrayList<>();
private boolean isFrozen;
///////////////////////////////////////////////////////////////////
public ManagedMemoryRangeAllocator(final Board board) {
this.board = board;
}
///////////////////////////////////////////////////////////////////
public void freeze() {
isFrozen = true;
}

View File

@@ -27,6 +27,8 @@ public final class ManagedVMContext implements VMContext {
this.memoryAllocator = new ManagedMemoryAllocator();
}
///////////////////////////////////////////////////////////////////
public void freeze() {
memoryRangeAllocator.freeze();
interruptAllocator.freeze();

View File

@@ -57,12 +57,16 @@ public final class Terminal {
private static final byte DEFAULT_COLORS = COLOR_WHITE << COLOR_FOREGROUND_SHIFT;
private static final byte DEFAULT_STYLE = 0;
///////////////////////////////////////////////////////////////////
public enum State { // Must be public for serialization.
NORMAL, // Currently reading characters normally.
ESCAPE, // Last character was ESC, figure out what kind next.
SEQUENCE, // Know what sequence we have, now parsing it.
}
///////////////////////////////////////////////////////////////////
private final ByteArrayFIFOQueue input = new ByteArrayFIFOQueue(32);
private final byte[] buffer = new byte[WIDTH * HEIGHT];
private final byte[] colors = new byte[WIDTH * HEIGHT];
@@ -85,10 +89,14 @@ public final class Terminal {
private transient Object renderer;
private transient boolean displayOnly; // Set on client to not send responses to status requests.
///////////////////////////////////////////////////////////////////
public Terminal() {
clear();
}
///////////////////////////////////////////////////////////////////
public void setDisplayOnly(final boolean value) {
displayOnly = value;
}
@@ -331,6 +339,8 @@ public final class Terminal {
}
}
///////////////////////////////////////////////////////////////////
private void selectStyle(final int sgr) {
switch (sgr) {
case 0: { // Reset / Normal
@@ -476,6 +486,8 @@ public final class Terminal {
dirty.set(-1);
}
///////////////////////////////////////////////////////////////////
@OnlyIn(Dist.CLIENT)
private static final class Renderer {
private static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/terminus.png");
@@ -506,15 +518,21 @@ public final class Terminal {
0x777777, // White
};
///////////////////////////////////////////////////////////////
private final Terminal terminal;
private final Object[] lines = new Object[HEIGHT]; // Cached vertex buffers for rendering, untyped for server.
private Object lastMatrix; // Untyped for server.
///////////////////////////////////////////////////////////////
public Renderer(final Terminal terminal) {
this.terminal = terminal;
}
///////////////////////////////////////////////////////////////
public void render(final AtomicInteger dirty, final MatrixStack stack) {
validateLineCache(dirty, stack);
renderBuffer();
@@ -524,6 +542,8 @@ public final class Terminal {
}
}
///////////////////////////////////////////////////////////////
private void renderBuffer() {
GlStateManager.depthMask(false);
Minecraft.getInstance().getTextureManager().bindTexture(LOCATION_FONT_TEXTURE);

View File

@@ -7,22 +7,12 @@ import li.cil.oc2.api.bus.device.vm.MemoryRangeAllocator;
import li.cil.oc2.api.bus.device.vm.VMContext;
import li.cil.oc2.common.bus.RPCAdapter;
import li.cil.sedna.api.device.InterruptController;
import li.cil.sedna.buildroot.Buildroot;
import li.cil.sedna.device.block.ByteBufferBlockDevice;
import li.cil.sedna.device.rtc.GoldfishRTC;
import li.cil.sedna.device.serial.UART16550A;
import li.cil.sedna.device.virtio.VirtIOConsoleDevice;
import li.cil.sedna.riscv.R5Board;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
public final class VirtualMachine {
private static final Logger LOGGER = LogManager.getLogger();
///////////////////////////////////////////////////////////////////
// We report a clock rate to the VM such that for the VM it looks as though
// passes as much faster as MC time passes faster than real time.
public static final int REPORTED_CPU_FREQUENCY = 700_000;
@@ -32,19 +22,6 @@ public final class VirtualMachine {
private static final int RTC_INTERRUPT = 0x2;
private static final int RPC_INTERRUPT = 0x3;
private static final ByteBufferBlockDevice ROOT_FS;
static {
ByteBufferBlockDevice rootfs;
try {
rootfs = ByteBufferBlockDevice.createFromStream(Buildroot.getRootFilesystem(), true);
} catch (final IOException e) {
LOGGER.error(e);
rootfs = ByteBufferBlockDevice.create(0, true);
}
ROOT_FS = rootfs;
}
///////////////////////////////////////////////////////////////////
public final MinecraftRealTimeCounter rtc = new MinecraftRealTimeCounter();
@@ -92,6 +69,8 @@ public final class VirtualMachine {
board.setStandardOutputDevice(uart);
}
///////////////////////////////////////////////////////////////////
public void reset() {
board.reset();
rpcAdapter.reset();

View File

@@ -33,6 +33,8 @@ public final class VirtualMachineDeviceBusAdapter {
this.claimedInterrupts.set(0);
}
///////////////////////////////////////////////////////////////////
public VMContext getGlobalContext() {
return globalContext;
}

View File

@@ -36,6 +36,8 @@ public class VirtualMachineRunner implements Runnable {
this.board = board;
}
///////////////////////////////////////////////////////////////////
public void tick() {
cycleLimit += getCyclesPerTick();
if (timeQuotaInMillis.addAndGet(TIMESLICE_IN_MS) > 0 && lastSchedule == null || lastSchedule.isDone() || lastSchedule.isCancelled()) {