From 4a5b02f5e31c6ee4e7726ea197f90836ab3bffe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 1 Jan 2022 05:07:57 +0100 Subject: [PATCH] Fix loss of precision in energy values for robot/computer UI. --- .../container/AbstractComputerContainer.java | 31 +++++--------- .../container/AbstractMachineContainer.java | 16 ++++---- .../AbstractMachineTerminalContainer.java | 2 +- .../container/AbstractRobotContainer.java | 15 +++---- .../container/ComputerInventoryContainer.java | 3 +- .../container/ComputerTerminalContainer.java | 3 +- .../container/IntPrecisionContainerData.java | 41 +++++++++++++++++++ .../container/RobotInventoryContainer.java | 3 +- .../container/RobotTerminalContainer.java | 3 +- .../SimpleIntPrecisionContainerData.java | 26 ++++++++++++ .../serialization/NBTToJsonConverter.java | 26 ++++++------ .../serializers/MessageJsonDeserializer.java | 24 +++-------- 12 files changed, 114 insertions(+), 79 deletions(-) create mode 100644 src/main/java/li/cil/oc2/common/container/IntPrecisionContainerData.java create mode 100644 src/main/java/li/cil/oc2/common/container/SimpleIntPrecisionContainerData.java diff --git a/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java index 7d4968ff..f4caa0b7 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java @@ -11,7 +11,6 @@ import li.cil.oc2.common.network.message.OpenComputerTerminalMessage; import li.cil.oc2.common.vm.Terminal; import li.cil.oc2.common.vm.VirtualMachine; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.inventory.MenuType; import net.minecraftforge.energy.IEnergyStorage; @@ -23,7 +22,7 @@ public abstract class AbstractComputerContainer extends AbstractMachineTerminalC /////////////////////////////////////////////////////////////////// - protected AbstractComputerContainer(final MenuType type, final int id, final Player player, final ComputerBlockEntity computer, final ContainerData energyInfo) { + protected AbstractComputerContainer(final MenuType type, final int id, final Player player, final ComputerBlockEntity computer, final IntPrecisionContainerData energyInfo) { super(type, id, energyInfo); this.computer = computer; @@ -76,28 +75,20 @@ public abstract class AbstractComputerContainer extends AbstractMachineTerminalC /////////////////////////////////////////////////////////////////// - protected static ContainerData createEnergyInfo(final IEnergyStorage energy, final CommonDeviceBusController busController) { - return new ContainerData() { + protected static IntPrecisionContainerData createEnergyInfo(final IEnergyStorage energy, final CommonDeviceBusController busController) { + return new IntPrecisionContainerData() { @Override - public int get(final int index) { - switch (index) { - case AbstractMachineContainer.ENERGY_STORED_INDEX: - return energy.getEnergyStored(); - case AbstractMachineContainer.ENERGY_CAPACITY_INDEX: - return energy.getMaxEnergyStored(); - case AbstractMachineContainer.ENERGY_CONSUMPTION_INDEX: - return busController.getEnergyConsumption(); - default: - return 0; - } + public int getInt(final int index) { + return switch (index) { + case AbstractMachineContainer.ENERGY_STORED_INDEX -> energy.getEnergyStored(); + case AbstractMachineContainer.ENERGY_CAPACITY_INDEX -> energy.getMaxEnergyStored(); + case AbstractMachineContainer.ENERGY_CONSUMPTION_INDEX -> busController.getEnergyConsumption(); + default -> 0; + }; } @Override - public void set(final int index, final int value) { - } - - @Override - public int getCount() { + public int getIntCount() { return ENERGY_INFO_SIZE; } }; diff --git a/src/main/java/li/cil/oc2/common/container/AbstractMachineContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractMachineContainer.java index 37530125..57d3b6ca 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractMachineContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractMachineContainer.java @@ -1,9 +1,7 @@ package li.cil.oc2.common.container; import li.cil.oc2.common.vm.VirtualMachine; -import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.SimpleContainerData; public abstract class AbstractMachineContainer extends AbstractContainer { protected static final int ENERGY_INFO_SIZE = 3; @@ -14,11 +12,11 @@ public abstract class AbstractMachineContainer extends AbstractContainer { /////////////////////////////////////////////////////////////////// - private final ContainerData energyInfo; + private final IntPrecisionContainerData energyInfo; /////////////////////////////////////////////////////////////////// - protected AbstractMachineContainer(final MenuType type, final int id, final ContainerData energyInfo) { + protected AbstractMachineContainer(final MenuType type, final int id, final IntPrecisionContainerData energyInfo) { super(type, id); this.energyInfo = energyInfo; @@ -35,20 +33,20 @@ public abstract class AbstractMachineContainer extends AbstractContainer { public abstract void sendPowerStateToServer(final boolean value); public int getEnergy() { - return energyInfo.get(ENERGY_STORED_INDEX); + return energyInfo.getInt(ENERGY_STORED_INDEX); } public int getEnergyCapacity() { - return energyInfo.get(ENERGY_CAPACITY_INDEX); + return energyInfo.getInt(ENERGY_CAPACITY_INDEX); } public int getEnergyConsumption() { - return energyInfo.get(ENERGY_CONSUMPTION_INDEX); + return energyInfo.getInt(ENERGY_CONSUMPTION_INDEX); } /////////////////////////////////////////////////////////////////// - protected static ContainerData createEnergyInfo() { - return new SimpleContainerData(ENERGY_INFO_SIZE); + protected static IntPrecisionContainerData createEnergyInfo() { + return new SimpleIntPrecisionContainerData(ENERGY_INFO_SIZE); } } diff --git a/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java index bb1e479c..3fc80f50 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java @@ -7,7 +7,7 @@ import net.minecraft.world.inventory.MenuType; import java.nio.ByteBuffer; public abstract class AbstractMachineTerminalContainer extends AbstractMachineContainer { - protected AbstractMachineTerminalContainer(final MenuType type, final int id, final ContainerData energyInfo) { + protected AbstractMachineTerminalContainer(final MenuType type, final int id, final IntPrecisionContainerData energyInfo) { super(type, id, energyInfo); } diff --git a/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java index eef360b5..e893f312 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java @@ -11,7 +11,6 @@ import li.cil.oc2.common.network.message.RobotTerminalInputMessage; import li.cil.oc2.common.vm.Terminal; import li.cil.oc2.common.vm.VirtualMachine; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.inventory.MenuType; import java.nio.ByteBuffer; @@ -21,7 +20,7 @@ public abstract class AbstractRobotContainer extends AbstractMachineTerminalCont /////////////////////////////////////////////////////////////////// - public AbstractRobotContainer(final MenuType type, final int id, final RobotEntity robot, final ContainerData energyInfo) { + public AbstractRobotContainer(final MenuType type, final int id, final RobotEntity robot, final IntPrecisionContainerData energyInfo) { super(type, id, energyInfo); this.robot = robot; } @@ -69,10 +68,10 @@ public abstract class AbstractRobotContainer extends AbstractMachineTerminalCont /////////////////////////////////////////////////////////////////// - protected static ContainerData createEnergyInfo(final FixedEnergyStorage energy, final CommonDeviceBusController busController) { - return new ContainerData() { + protected static IntPrecisionContainerData createEnergyInfo(final FixedEnergyStorage energy, final CommonDeviceBusController busController) { + return new IntPrecisionContainerData() { @Override - public int get(final int index) { + public int getInt(final int index) { return switch (index) { case AbstractMachineContainer.ENERGY_STORED_INDEX -> energy.getEnergyStored(); case AbstractMachineContainer.ENERGY_CAPACITY_INDEX -> energy.getMaxEnergyStored(); @@ -82,11 +81,7 @@ public abstract class AbstractRobotContainer extends AbstractMachineTerminalCont } @Override - public void set(final int index, final int value) { - } - - @Override - public int getCount() { + public int getIntCount() { return ENERGY_INFO_SIZE; } }; diff --git a/src/main/java/li/cil/oc2/common/container/ComputerInventoryContainer.java b/src/main/java/li/cil/oc2/common/container/ComputerInventoryContainer.java index 7ff8669d..1f9b5031 100644 --- a/src/main/java/li/cil/oc2/common/container/ComputerInventoryContainer.java +++ b/src/main/java/li/cil/oc2/common/container/ComputerInventoryContainer.java @@ -13,7 +13,6 @@ import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.network.NetworkHooks; @@ -45,7 +44,7 @@ public final class ComputerInventoryContainer extends AbstractComputerContainer /////////////////////////////////////////////////////////////////// - private ComputerInventoryContainer(final int id, final ComputerBlockEntity computer, final Player player, final ContainerData energyInfo) { + private ComputerInventoryContainer(final int id, final ComputerBlockEntity computer, final Player player, final IntPrecisionContainerData energyInfo) { super(Containers.COMPUTER.get(), id, player, computer, energyInfo); final VMItemStackHandlers handlers = computer.getItemStackHandlers(); diff --git a/src/main/java/li/cil/oc2/common/container/ComputerTerminalContainer.java b/src/main/java/li/cil/oc2/common/container/ComputerTerminalContainer.java index 84922de7..07666172 100644 --- a/src/main/java/li/cil/oc2/common/container/ComputerTerminalContainer.java +++ b/src/main/java/li/cil/oc2/common/container/ComputerTerminalContainer.java @@ -11,7 +11,6 @@ import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.ContainerData; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.network.NetworkHooks; @@ -43,7 +42,7 @@ public final class ComputerTerminalContainer extends AbstractComputerContainer { /////////////////////////////////////////////////////////////////// - private ComputerTerminalContainer(final int id, final Player player, final ComputerBlockEntity computer, final ContainerData energyInfo) { + private ComputerTerminalContainer(final int id, final Player player, final ComputerBlockEntity computer, final IntPrecisionContainerData energyInfo) { super(Containers.COMPUTER_TERMINAL.get(), id, player, computer, energyInfo); } } diff --git a/src/main/java/li/cil/oc2/common/container/IntPrecisionContainerData.java b/src/main/java/li/cil/oc2/common/container/IntPrecisionContainerData.java new file mode 100644 index 00000000..83f8d219 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/container/IntPrecisionContainerData.java @@ -0,0 +1,41 @@ +package li.cil.oc2.common.container; + +import net.minecraft.world.inventory.ContainerData; + +/** + * Utility class for synchronizing full-precision ints using {@link ContainerData}. + *

+ * Expects either {@link #getInt(int)} and {@link #getIntCount()} or {@link #get(int)} and {@link #getCount()} to be + * overridden. + */ +public abstract class IntPrecisionContainerData implements ContainerData { + public int getInt(final int index) { + return (get(index * 2 + 1) << 16) | get(index * 2); + } + + public void setInt(final int index, final int value) { + } + + public int getIntCount() { + return getCount() / 2; + } + + @Override + public int get(final int index) { + final int intValue = getInt(index / 2); + if ((index & 1) == 0) { + return intValue & 0xFFFF; // Low half. + } else { + return (intValue >>> 16) & 0xFFFF; // High half. + } + } + + @Override + public void set(final int index, final int value) { + } + + @Override + public int getCount() { + return getIntCount() * 2; + } +} diff --git a/src/main/java/li/cil/oc2/common/container/RobotInventoryContainer.java b/src/main/java/li/cil/oc2/common/container/RobotInventoryContainer.java index 6262d2af..0f2e9bea 100644 --- a/src/main/java/li/cil/oc2/common/container/RobotInventoryContainer.java +++ b/src/main/java/li/cil/oc2/common/container/RobotInventoryContainer.java @@ -13,7 +13,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.ContainerData; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.SlotItemHandler; import net.minecraftforge.network.NetworkHooks; @@ -45,7 +44,7 @@ public final class RobotInventoryContainer extends AbstractRobotContainer { /////////////////////////////////////////////////////////////////// - private RobotInventoryContainer(final int id, final RobotEntity robot, final Player player, final ContainerData energyInfo) { + private RobotInventoryContainer(final int id, final RobotEntity robot, final Player player, final IntPrecisionContainerData energyInfo) { super(Containers.ROBOT.get(), id, robot, energyInfo); final VMItemStackHandlers handlers = robot.getItemStackHandlers(); diff --git a/src/main/java/li/cil/oc2/common/container/RobotTerminalContainer.java b/src/main/java/li/cil/oc2/common/container/RobotTerminalContainer.java index 22cc7cda..d1461cb9 100644 --- a/src/main/java/li/cil/oc2/common/container/RobotTerminalContainer.java +++ b/src/main/java/li/cil/oc2/common/container/RobotTerminalContainer.java @@ -12,7 +12,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.ContainerData; import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.SlotItemHandler; import net.minecraftforge.network.NetworkHooks; @@ -44,7 +43,7 @@ public final class RobotTerminalContainer extends AbstractRobotContainer { /////////////////////////////////////////////////////////////////// - private RobotTerminalContainer(final int id, final RobotEntity robot, final ContainerData energyInfo) { + private RobotTerminalContainer(final int id, final RobotEntity robot, final IntPrecisionContainerData energyInfo) { super(Containers.ROBOT_TERMINAL.get(), id, robot, energyInfo); // It's kinda dumb we need to access technically-client-side stuff here, but that's the nature of containers diff --git a/src/main/java/li/cil/oc2/common/container/SimpleIntPrecisionContainerData.java b/src/main/java/li/cil/oc2/common/container/SimpleIntPrecisionContainerData.java new file mode 100644 index 00000000..68722965 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/container/SimpleIntPrecisionContainerData.java @@ -0,0 +1,26 @@ +package li.cil.oc2.common.container; + +import net.minecraft.world.inventory.SimpleContainerData; + +public final class SimpleIntPrecisionContainerData extends IntPrecisionContainerData { + private final SimpleContainerData data; + + public SimpleIntPrecisionContainerData(final int size) { + data = new SimpleContainerData(size * 2); + } + + @Override + public int get(final int index) { + return data.get(index); + } + + @Override + public void set(final int index, final int value) { + data.set(index, value & 0xFFFF); + } + + @Override + public int getCount() { + return data.getCount(); + } +} diff --git a/src/main/java/li/cil/oc2/common/serialization/NBTToJsonConverter.java b/src/main/java/li/cil/oc2/common/serialization/NBTToJsonConverter.java index baefce52..f92b67a5 100644 --- a/src/main/java/li/cil/oc2/common/serialization/NBTToJsonConverter.java +++ b/src/main/java/li/cil/oc2/common/serialization/NBTToJsonConverter.java @@ -13,25 +13,25 @@ public final class NBTToJsonConverter { } switch (tag.getId()) { - case NBTTagIds.TAG_BYTE: { + case NBTTagIds.TAG_BYTE -> { return new JsonPrimitive(((ByteTag) tag).getAsByte()); } - case NBTTagIds.TAG_SHORT: { + case NBTTagIds.TAG_SHORT -> { return new JsonPrimitive(((ShortTag) tag).getAsShort()); } - case NBTTagIds.TAG_INT: { + case NBTTagIds.TAG_INT -> { return new JsonPrimitive(((IntTag) tag).getAsInt()); } - case NBTTagIds.TAG_LONG: { + case NBTTagIds.TAG_LONG -> { return new JsonPrimitive(((LongTag) tag).getAsLong()); } - case NBTTagIds.TAG_FLOAT: { + case NBTTagIds.TAG_FLOAT -> { return new JsonPrimitive(((FloatTag) tag).getAsFloat()); } - case NBTTagIds.TAG_DOUBLE: { + case NBTTagIds.TAG_DOUBLE -> { return new JsonPrimitive(((DoubleTag) tag).getAsDouble()); } - case NBTTagIds.TAG_BYTE_ARRAY: { + case NBTTagIds.TAG_BYTE_ARRAY -> { final JsonArray json = new JsonArray(); final byte[] array = ((ByteArrayTag) tag).getAsByteArray(); for (int i = 0; i < array.length; i++) { @@ -39,10 +39,10 @@ public final class NBTToJsonConverter { } return json; } - case NBTTagIds.TAG_STRING: { + case NBTTagIds.TAG_STRING -> { return new JsonPrimitive(tag.getAsString()); } - case NBTTagIds.TAG_LIST: { + case NBTTagIds.TAG_LIST -> { final JsonArray json = new JsonArray(); final ListTag listTag = (ListTag) tag; for (final Tag item : listTag) { @@ -50,7 +50,7 @@ public final class NBTToJsonConverter { } return json; } - case NBTTagIds.TAG_COMPOUND: { + case NBTTagIds.TAG_COMPOUND -> { final JsonObject json = new JsonObject(); final CompoundTag compoundTag = (CompoundTag) tag; for (final String key : compoundTag.getAllKeys()) { @@ -58,7 +58,7 @@ public final class NBTToJsonConverter { } return json; } - case NBTTagIds.TAG_INT_ARRAY: { + case NBTTagIds.TAG_INT_ARRAY -> { final JsonArray json = new JsonArray(); final int[] array = ((IntArrayTag) tag).getAsIntArray(); for (int i = 0; i < array.length; i++) { @@ -66,7 +66,7 @@ public final class NBTToJsonConverter { } return json; } - case NBTTagIds.TAG_LONG_ARRAY: { + case NBTTagIds.TAG_LONG_ARRAY -> { final JsonArray json = new JsonArray(); final long[] array = ((LongArrayTag) tag).getAsLongArray(); for (int i = 0; i < array.length; i++) { @@ -74,7 +74,7 @@ public final class NBTToJsonConverter { } return json; } - default: { + default -> { return JsonNull.INSTANCE; } } diff --git a/src/main/java/li/cil/oc2/common/serialization/serializers/MessageJsonDeserializer.java b/src/main/java/li/cil/oc2/common/serialization/serializers/MessageJsonDeserializer.java index f90efdb5..f91bdf36 100644 --- a/src/main/java/li/cil/oc2/common/serialization/serializers/MessageJsonDeserializer.java +++ b/src/main/java/li/cil/oc2/common/serialization/serializers/MessageJsonDeserializer.java @@ -11,24 +11,12 @@ public final class MessageJsonDeserializer implements JsonDeserializer null; + case RPCDeviceBusAdapter.Message.MESSAGE_TYPE_METHODS -> UUID.fromString(jsonObject.getAsJsonPrimitive("data").getAsString()); + case RPCDeviceBusAdapter.Message.MESSAGE_TYPE_INVOKE_METHOD -> context.deserialize(jsonObject.getAsJsonObject("data"), RPCDeviceBusAdapter.MethodInvocation.class); + default -> throw new JsonParseException(RPCDeviceBusAdapter.ERROR_UNKNOWN_MESSAGE_TYPE); + }; return new RPCDeviceBusAdapter.Message(messageType, messageData); }