diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index 4db08fb1d..0cd89a339 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -87,6 +87,7 @@ public class Registry { public static final ResourceLocation MATTER_PANEL = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_panel"); public static final ResourceLocation MATTER_REPLICATOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_replicator"); public static final ResourceLocation MATTER_BOTTLER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_bottler"); + public static final ResourceLocation DRIVE_VIEWER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "drive_viewer"); // capabilities public static final ResourceLocation ANDROID_CAPABILITY = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_capability"); @@ -174,6 +175,7 @@ public class Registry { public static final Block MATTER_PANEL = new BlockMatterPanel(); public static final Block MATTER_REPLICATOR = new BlockMatterReplicator(); public static final Block MATTER_BOTTLER = new BlockMatterBottler(); + public static final Block DRIVE_VIEWER = new BlockDriveViewer(); static { ANDROID_STATION.setRegistryName(Names.ANDROID_STATION); @@ -186,6 +188,7 @@ public class Registry { MATTER_PANEL.setRegistryName(Names.MATTER_PANEL); MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR); MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER); + DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER); } @SubscribeEvent @@ -200,6 +203,7 @@ public class Registry { event.getRegistry().register(MATTER_PANEL); event.getRegistry().register(MATTER_REPLICATOR); event.getRegistry().register(MATTER_BOTTLER); + event.getRegistry().register(DRIVE_VIEWER); // OverdriveThatMatters.LOGGER.info("Registered blocks"); } @@ -216,6 +220,7 @@ public class Registry { public static final Item MATTER_PANEL = new BlockItem(Blocks.MATTER_PANEL, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final Item MATTER_REPLICATOR = new BlockItem(Blocks.MATTER_REPLICATOR, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final Item MATTER_BOTTLER = new BlockItem(Blocks.MATTER_BOTTLER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); + public static final Item DRIVE_VIEWER = new BlockItem(Blocks.DRIVE_VIEWER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB)); public static final ItemPill PILL_ANDROID = new ItemPill(ItemPill.PillType.BECOME_ANDROID); public static final ItemPill PILL_HUMANE = new ItemPill(ItemPill.PillType.BECOME_HUMANE); @@ -248,6 +253,7 @@ public class Registry { MATTER_PANEL.setRegistryName(Names.MATTER_PANEL); MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR); MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER); + DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER); PILL_ANDROID.setRegistryName(Names.PILL_ANDROID); PILL_HUMANE.setRegistryName(Names.PILL_HUMANE); @@ -280,6 +286,7 @@ public class Registry { event.getRegistry().register(MATTER_PANEL); event.getRegistry().register(MATTER_REPLICATOR); event.getRegistry().register(MATTER_BOTTLER); + event.getRegistry().register(DRIVE_VIEWER); event.getRegistry().register(PILL_ANDROID); event.getRegistry().register(PILL_HUMANE); @@ -314,6 +321,7 @@ public class Registry { public static final BlockEntityType MATTER_PANEL = BlockEntityType.Builder.of(BlockEntityMatterPanel::new, Blocks.MATTER_PANEL).build(null); public static final BlockEntityType MATTER_REPLICATOR = BlockEntityType.Builder.of(BlockEntityMatterReplicator::new, Blocks.MATTER_REPLICATOR).build(null); public static final BlockEntityType MATTER_BOTTLER = BlockEntityType.Builder.of(BlockEntityMatterBottler::new, Blocks.MATTER_BOTTLER).build(null); + public static final BlockEntityType DRIVE_VIEWER = BlockEntityType.Builder.of(BlockEntityDriveViewer::new, Blocks.DRIVE_VIEWER).build(null); static { ANDROID_STATION.setRegistryName(Names.ANDROID_STATION); @@ -326,6 +334,7 @@ public class Registry { MATTER_PANEL.setRegistryName(Names.MATTER_PANEL); MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR); MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER); + DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER); } @SubscribeEvent @@ -340,6 +349,7 @@ public class Registry { event.getRegistry().register(MATTER_PANEL); event.getRegistry().register(MATTER_REPLICATOR); event.getRegistry().register(MATTER_BOTTLER); + event.getRegistry().register(DRIVE_VIEWER); // OverdriveThatMatters.LOGGER.info("Registered block entities"); } @@ -575,6 +585,7 @@ public class Registry { public static final MenuType MATTER_PANEL = new MenuType<>(MatterPanelMenu::new); public static final MenuType MATTER_REPLICATOR = new MenuType<>(MatterReplicatorMenu::new); public static final MenuType MATTER_BOTTLER = new MenuType<>(MatterBottlerMenu::new); + public static final MenuType DRIVE_VIEWER = new MenuType<>(DriveViewerMenu::new); static { ANDROID_STATION.setRegistryName(Names.ANDROID_STATION); @@ -586,6 +597,7 @@ public class Registry { MATTER_PANEL.setRegistryName(Names.MATTER_PANEL); MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR); MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER); + DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER); } @SubscribeEvent @@ -599,6 +611,7 @@ public class Registry { event.getRegistry().register(MATTER_PANEL); event.getRegistry().register(MATTER_REPLICATOR); event.getRegistry().register(MATTER_BOTTLER); + event.getRegistry().register(DRIVE_VIEWER); // OverdriveThatMatters.LOGGER.info("Registered menus"); } @@ -614,6 +627,7 @@ public class Registry { MenuScreens.register(MATTER_PANEL, MatterPanelScreen::new); MenuScreens.register(MATTER_REPLICATOR, MatterReplicatorScreen::new); MenuScreens.register(MATTER_BOTTLER, MatterBottlerScreen::new); + MenuScreens.register(DRIVE_VIEWER, DriveViewerScreen::new); // OverdriveThatMatters.LOGGER.info("Registered screens"); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/BlockDriveViewer.java b/src/main/java/ru/dbotthepony/mc/otm/block/BlockDriveViewer.java new file mode 100644 index 000000000..81f0ecb9d --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/block/BlockDriveViewer.java @@ -0,0 +1,17 @@ +package ru.dbotthepony.mc.otm.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveViewer; + +import javax.annotation.Nullable; + +public class BlockDriveViewer extends BlockMatteryRotatable implements EntityBlock { + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return new BlockEntityDriveViewer(blockPos, blockState); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityDriveViewer.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityDriveViewer.java new file mode 100644 index 000000000..c5dd66709 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityDriveViewer.java @@ -0,0 +1,52 @@ +package ru.dbotthepony.mc.otm.block.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import ru.dbotthepony.mc.otm.Registry; +import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage; +import ru.dbotthepony.mc.otm.container.MatteryContainer; +import ru.dbotthepony.mc.otm.menu.DriveViewerMenu; + +import javax.annotation.Nullable; +import java.math.BigDecimal; + +public class BlockEntityDriveViewer extends BlockEntityMatteryPowered { + public BlockEntityDriveViewer(BlockPos p_155229_, BlockState p_155230_) { + super(Registry.BlockEntities.DRIVE_VIEWER, p_155229_, p_155230_); + energy = new MatteryMachineEnergyStorage(this, MatteryMachineEnergyStorage.MachineType.WORKER, new BigDecimal(30_000)); + } + + private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.drive_viewer"); + + public final MatteryContainer drive_slot = new MatteryContainer(this::setChanged, 1); + + @Override + protected Component getDefaultDisplayName() { + return NAME; + } + + @Nullable + @Override + public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) { + return new DriveViewerMenu(containerID, inventory, this); + } + + @Override + public CompoundTag save(CompoundTag nbt) { + nbt.put("drive_slot", drive_slot.serializeNBT()); + return super.save(nbt); + } + + @Override + public void load(CompoundTag nbt) { + super.load(nbt); + drive_slot.deserializeNBT(nbt.get("drive_slot")); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/IMatteryDrive.java b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/IMatteryDrive.java index 2c1dd20b3..24f7a6455 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/IMatteryDrive.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/IMatteryDrive.java @@ -33,7 +33,7 @@ public interface IMatteryDrive { List findItems(@Nonnull ItemStack stack); @Nullable - StoredStack getItem(@Nonnull UUID id); + StoredStack getItem(int id); int getStoredCount(); int getCapacity(); @@ -42,12 +42,12 @@ public interface IMatteryDrive { ItemStack insertItem(@Nonnull ItemStack item, boolean simulate); @Nonnull - default ItemStack extractItem(@Nonnull UUID id, int amount, boolean simulate) { + default ItemStack extractItem(int id, int amount, boolean simulate) { return extractItem(id, amount, true, simulate); } @Nonnull - ItemStack extractItem(@Nonnull UUID id, int amount, boolean obey_stack_size, boolean simulate); + ItemStack extractItem(int id, int amount, boolean obey_stack_size, boolean simulate); // not extending INBTSerializable to avoid serializing it as forgecaps CompoundTag serializeNBT(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/MatteryDrive.java b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/MatteryDrive.java index ebb2f8d58..c56923b10 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/MatteryDrive.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/MatteryDrive.java @@ -8,6 +8,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraftforge.registries.RegistryManager; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -15,13 +16,18 @@ import java.util.*; public class MatteryDrive implements IMatteryDrive { protected final HashMap> items = new HashMap<>(); - protected final HashMap items_uuid = new HashMap<>(); + protected final HashMap items_by_id = new HashMap<>(); protected boolean dirty = false; protected int different_stacks = 0; protected int stored = 0; protected int max_different_stacks; protected int capacity; + protected int next_item_id = 0; + + protected int getNextID() { + return next_item_id++; + } public MatteryDrive(int capacity, int max_different_stacks) { this.capacity = capacity; @@ -41,13 +47,9 @@ public class MatteryDrive implements IMatteryDrive { } var output = new ArrayList(amount); - int i = 0; for (var list : items.values()) { - for (var stack : list) { - output.set(i, stack); - i++; - } + output.addAll(list); } return output; @@ -120,8 +122,8 @@ public class MatteryDrive implements IMatteryDrive { @Nullable @Override - public StoredStack getItem(@Nonnull UUID id) { - return items_uuid.get(id); + public StoredStack getItem(int id) { + return items_by_id.get(id); } @Nonnull @@ -156,9 +158,9 @@ public class MatteryDrive implements IMatteryDrive { different_stacks++; var copy = item.copy(); copy.setCount(max_insert); - var state = new StoredStack(copy, UUID.randomUUID()); + var state = new StoredStack(copy, getNextID()); listing.add(state); - items_uuid.put(state.id(), state); + items_by_id.put(state.id(), state); markDirty(); } @@ -169,8 +171,8 @@ public class MatteryDrive implements IMatteryDrive { @Nonnull @Override - public ItemStack extractItem(@Nonnull UUID id, int amount, boolean obey_stack_size, boolean simulate) { - var get = items_uuid.get(id); + public ItemStack extractItem(int id, int amount, boolean obey_stack_size, boolean simulate) { + var get = items_by_id.get(id); if (get == null) return ItemStack.EMPTY; @@ -202,6 +204,7 @@ public class MatteryDrive implements IMatteryDrive { public CompoundTag serializeNBT() { final var compound = new CompoundTag(); + compound.putInt("next_item_id", next_item_id); compound.putInt("capacity", capacity); compound.putInt("max_different_stacks", max_different_stacks); @@ -221,7 +224,7 @@ public class MatteryDrive implements IMatteryDrive { stack_list.add(stack_nbt); stack_nbt.putInt("count", stack.stack().getCount()); - stack_nbt.putLongArray("uuid", new long[] { stack.id().getMostSignificantBits(), stack.id().getLeastSignificantBits() }); + stack_nbt.putInt("id", stack.id()); if (stack.stack().getTag() != null) { stack_nbt.put("data", stack.stack().getTag()); @@ -237,10 +240,11 @@ public class MatteryDrive implements IMatteryDrive { @Override public void deserializeNBT(CompoundTag nbt) { items.clear(); - items_uuid.clear(); + items_by_id.clear(); stored = 0; different_stacks = 0; + next_item_id = nbt.getInt("next_item_id"); capacity = nbt.getInt("capacity"); max_different_stacks = nbt.getInt("max_different_stacks"); @@ -259,7 +263,7 @@ public class MatteryDrive implements IMatteryDrive { for (var _stack : stack_list) { if (_stack instanceof CompoundTag stack) { var count = stack.getInt("count"); - var _uuid = stack.getLongArray("uuid"); + var id = stack.getInt("id"); var data = stack.get("data"); var itemstack = new ItemStack(item, count); @@ -270,9 +274,9 @@ public class MatteryDrive implements IMatteryDrive { stored += count; different_stacks += 1; - var state = new StoredStack(itemstack, new UUID(_uuid[0], _uuid[1])); + var state = new StoredStack(itemstack, id); map_list.add(state); - items_uuid.put(state.id(), state); + items_by_id.put(state.id(), state); } } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/NetworkedItemView.java b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/NetworkedItemView.java new file mode 100644 index 000000000..2a5057cc8 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/NetworkedItemView.java @@ -0,0 +1,330 @@ +package ru.dbotthepony.mc.otm.capability.drive; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fmllegacy.network.NetworkEvent; +import net.minecraftforge.fmllegacy.network.PacketDistributor; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.network.MatteryNetworking; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.function.Supplier; + +public class NetworkedItemView { + record TrackedState(int id, int id_upstream, ItemStack stack) { + TrackedState(int id, ItemStack stack) { + this(id, 0, stack); + } + } + + public record ClearPacket(UUID id, boolean remove) { + public void write(FriendlyByteBuf buffer) { + buffer.writeLong(id.getMostSignificantBits()); + buffer.writeLong(id.getLeastSignificantBits()); + buffer.writeBoolean(remove); + } + + public static ClearPacket read(FriendlyByteBuf buffer) { + return new ClearPacket(new UUID(buffer.readLong(), buffer.readLong()), buffer.readBoolean()); + } + + public void play(Supplier context) { + context.get().setPacketHandled(true); + context.get().enqueueWork(() -> { + var get = TRACKERS_REMOTE.get(id); + + if (get == null) { + throw new IllegalStateException("No such item tracker with id " + id); + } + + if (remove) { + get.remove(); + } else { + get.clear(); + } + }); + } + } + + public record CreatedPacket(UUID id) { + public void write(FriendlyByteBuf buffer) { + buffer.writeLong(id.getMostSignificantBits()); + buffer.writeLong(id.getLeastSignificantBits()); + } + + public static CreatedPacket read(FriendlyByteBuf buffer) { + return new CreatedPacket(new UUID(buffer.readLong(), buffer.readLong())); + } + + public void play(Supplier context) { + context.get().setPacketHandled(true); + context.get().enqueueWork(() -> { + new NetworkedItemView(Minecraft.getInstance().player, id, true); + }); + } + } + + public record StackAddPacket(UUID id, int stack_id, ItemStack stack) { + public void write(FriendlyByteBuf buffer) { + buffer.writeLong(id.getMostSignificantBits()); + buffer.writeLong(id.getLeastSignificantBits()); + buffer.writeInt(stack_id); + buffer.writeRegistryId(stack.getItem()); + buffer.writeInt(stack.getCount()); + buffer.writeBoolean(stack.getTag() != null); + + if (stack.getTag() != null) + buffer.writeNbt(stack.getShareTag()); + } + + public static StackAddPacket read(FriendlyByteBuf buffer) { + var id = new UUID(buffer.readLong(), buffer.readLong()); + var stack = buffer.readInt(); + var item = buffer.readRegistryIdSafe(Item.class); + var count = buffer.readInt(); + + var state = new ItemStack(item, count); + + if (buffer.readBoolean()) + state.readShareTag(buffer.readNbt()); + + return new StackAddPacket(id, stack, state); + } + + public void play(Supplier context) { + context.get().setPacketHandled(true); + context.get().enqueueWork(() -> { + var get = TRACKERS_REMOTE.get(id); + + if (get == null) { + throw new IllegalStateException("No such item tracker with id " + id); + } + + if (get.state.containsKey(stack_id)) { + throw new IllegalStateException("Item tracker " + id + " already has stack with id of " + stack_id); + } + + get.state.put(stack_id, new TrackedState(stack_id, stack)); + get.clearCache(); + }); + } + } + + public record StackChangePacket(UUID id, int stack_id, int new_count) { + public void write(FriendlyByteBuf buffer) { + buffer.writeLong(id.getMostSignificantBits()); + buffer.writeLong(id.getLeastSignificantBits()); + buffer.writeInt(stack_id); + buffer.writeInt(new_count); + } + + public static StackChangePacket read(FriendlyByteBuf buffer) { + var id = new UUID(buffer.readLong(), buffer.readLong()); + var stack_id = buffer.readInt(); + var new_count = buffer.readInt(); + + return new StackChangePacket(id, stack_id, new_count); + } + + public void play(Supplier context) { + context.get().setPacketHandled(true); + context.get().enqueueWork(() -> { + var get = TRACKERS_REMOTE.get(id); + + if (get == null) { + throw new IllegalStateException("No such item tracker with id " + id); + } + + var get_state = get.state.get(stack_id); + + if (get_state == null) { + throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id); + } + + get_state.stack.setCount(new_count); + get.clearCache(); + }); + } + } + + public record StackRemovePacket(UUID id, int stack_id) { + public void write(FriendlyByteBuf buffer) { + buffer.writeLong(id.getMostSignificantBits()); + buffer.writeLong(id.getLeastSignificantBits()); + buffer.writeInt(stack_id); + } + + public static StackRemovePacket read(FriendlyByteBuf buffer) { + var id = new UUID(buffer.readLong(), buffer.readLong()); + var stack_id = buffer.readInt(); + + return new StackRemovePacket(id, stack_id); + } + + public void play(Supplier context) { + context.get().setPacketHandled(true); + context.get().enqueueWork(() -> { + var get = TRACKERS_REMOTE.get(id); + + if (get == null) { + throw new IllegalStateException("No such item tracker with id " + id); + } + + var get_state = get.state.remove(stack_id); + + if (get_state == null) { + throw new IllegalStateException("Item tracker " + id + " has no stack with id of " + stack_id); + } + + get.clearCache(); + }); + } + } + + public final Player ply; + public final UUID id; + public final boolean remote; + protected int next_stack_id = 0; + + protected final HashMap state = new HashMap<>(); + protected final HashMap upstream_state = new HashMap<>(); + protected final ArrayList backlog = new ArrayList<>(); + + private static final HashMap TRACKERS_LOCAL = new HashMap<>(); + private static final HashMap TRACKERS_REMOTE = new HashMap<>(); + + public static NetworkedItemView getLocal(UUID id) { + return TRACKERS_LOCAL.get(id); + } + + public static NetworkedItemView getRemote(UUID id) { + return TRACKERS_REMOTE.get(id); + } + + public NetworkedItemView(Player ply) { + this(ply, UUID.randomUUID()); + } + + public NetworkedItemView(Player ply, UUID id) { + this(ply, id, false); + } + + public NetworkedItemView(Player ply, UUID id, boolean remote) { + this.remote = remote; + this.ply = ply; + this.id = id; + + if (remote) { + TRACKERS_REMOTE.put(this.id, this); + } else { + TRACKERS_LOCAL.put(this.id, this); + MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) ply), new CreatedPacket(this.id)); + } + } + + private List view_cache; + + public void clearCache() { + view_cache = null; + } + + public List getItems() { + if (view_cache != null) + return view_cache; + + var list = new ArrayList(state.size()); + + for (var state : this.state.values()) + list.add(state.stack); + + return view_cache = list; + } + + public void addItem(ItemStack stack, int id_upstream) { + if (upstream_state.containsKey(id_upstream)) + throw new IllegalStateException("Already tracking ItemStack with upstream id " + id_upstream + "!"); + + var state = new TrackedState(next_stack_id++, id_upstream, stack); + this.state.put(state.id, state); + this.upstream_state.put(id_upstream, state); + + if (!remote) { + backlog.add(new StackAddPacket(id, state.id, stack)); + } + + clearCache(); + } + + public void changeItem(int id_upstream, int new_count) { + var get = upstream_state.get(id_upstream); + + if (get == null) + throw new IllegalStateException("Unknown ItemStack with upstream id " + id_upstream + "!"); + + get.stack.setCount(new_count); + + if (!remote) { + backlog.add(new StackChangePacket(id, get.id, new_count)); + } + + clearCache(); + } + + public void removeItem(int id_upstream) { + var get = upstream_state.get(id_upstream); + + if (get == null) + throw new IllegalStateException("Unknown ItemStack with upstream id " + id_upstream + "!"); + + upstream_state.remove(id_upstream); + state.remove(get.id); + + if (!remote) { + backlog.add(new StackRemovePacket(id, get.id)); + } + + clearCache(); + } + + public void clear() { + OverdriveThatMatters.LOGGER.info("Clear called"); + clearCache(); + upstream_state.clear(); + state.clear(); + + if (!remote) { + backlog.clear(); + backlog.add(new ClearPacket(id, false)); + } + } + + public void remove() { + if (!remote) { + TRACKERS_LOCAL.remove(id); + backlog.clear(); + backlog.add(new ClearPacket(id, true)); + } + } + + public void network() { + if (remote) + throw new IllegalStateException("Not a server"); + + var consumer = PacketDistributor.PLAYER.with(() -> (ServerPlayer) ply); + + for (var packet : backlog) { + MatteryNetworking.CHANNEL.send(consumer, packet); + OverdriveThatMatters.LOGGER.info("Send packet {}", packet); + } + + backlog.clear(); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/StoredStack.java b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/StoredStack.java index 901c68237..036a509b4 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/drive/StoredStack.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/drive/StoredStack.java @@ -4,5 +4,5 @@ import net.minecraft.world.item.ItemStack; import java.util.UUID; -public record StoredStack(ItemStack stack, UUID id) { +public record StoredStack(ItemStack stack, int id) { } diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.java new file mode 100644 index 000000000..483b9c278 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/DriveViewerMenu.java @@ -0,0 +1,120 @@ +package ru.dbotthepony.mc.otm.menu; + +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import ru.dbotthepony.mc.otm.Registry; +import ru.dbotthepony.mc.otm.block.entity.BlockEntityDriveViewer; +import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatteryPowered; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; +import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive; +import ru.dbotthepony.mc.otm.capability.drive.NetworkedItemView; +import ru.dbotthepony.mc.otm.menu.data.UUIDDataContainer; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; + +import javax.annotation.Nullable; +import java.util.UUID; + +public class DriveViewerMenu extends PoweredMatteryMenu { + public UUIDDataContainer view_uuid; + public NetworkedItemView view; + public MatterySlot drive_slot; + protected IMatteryDrive last_drive; + + public NetworkedItemView getView() { + return view != null ? view : NetworkedItemView.getRemote(view_uuid.getValue()); + } + + public DriveViewerMenu(int containerID, Inventory inventory) { + this(containerID, inventory, null); + } + + public DriveViewerMenu(int containerID, Inventory inventory, @Nullable BlockEntityDriveViewer tile) { + super(Registry.Menus.DRIVE_VIEWER, containerID, inventory, tile); + + view_uuid = new UUIDDataContainer(); + var container = tile != null ? tile.drive_slot : new SimpleContainer(1); + + drive_slot = new MatterySlot(container, 0) { + @Override + public boolean mayPlace(ItemStack stack) { + return stack.getCapability(MatteryCapability.DRIVE).isPresent(); + } + }; + + addSlot(drive_slot); + + if (tile != null) { + view = new NetworkedItemView(inventory.player); + view_uuid.setValue(view.id); + } + + addDataSlots(view_uuid); + + addBatterySlot(); + addInventorySlots(); + } + + @Override + public void broadcastChanges() { + super.broadcastChanges(); + + if (tile != null) { + var get = ((BlockEntityDriveViewer) tile).drive_slot.getItem(0); + + if (get.isEmpty()) { + if (last_drive != null) { + view.clear(); + } + + last_drive = null; + } else { + var get_cap = get.getCapability(MatteryCapability.DRIVE).resolve(); + + if (get_cap.isEmpty()) { + if (last_drive != null) { + view.clear(); + } + + last_drive = null; + } else { + if (last_drive != get_cap.get()) { + view.clear(); + + for (var stack : get_cap.get().getItems()) { + view.addItem(stack.stack(), stack.id()); + } + } + + last_drive = get_cap.get(); + } + } + + view.network(); + } + } + + @Override + public void removed(Player p_38940_) { + super.removed(p_38940_); + + if (!p_38940_.level.isClientSide) { + var view = getView(); + + if (view != null) + view.remove(); + } + } + + @Override + protected int getWorkingSlotStart() { + return 0; + } + + @Override + protected int getWorkingSlotEnd() { + return 2; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/data/UUIDDataContainer.java b/src/main/java/ru/dbotthepony/mc/otm/menu/data/UUIDDataContainer.java new file mode 100644 index 000000000..09117c5a4 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/data/UUIDDataContainer.java @@ -0,0 +1,81 @@ +package ru.dbotthepony.mc.otm.menu.data; + +import net.minecraft.world.inventory.ContainerData; + +import java.util.UUID; + +public class UUIDDataContainer implements ContainerData { + public static final int NETWORK_PAYLOAD_SIZE = 8; + + private UUID value; + private final int[] buffer = new int[NETWORK_PAYLOAD_SIZE]; + + public UUID getValue() { + if (value != null) { + return value; + } + + long a = buffer[0]; + long b = buffer[1]; + long c = buffer[2]; + long d = buffer[3]; + + long upper = a | b << 16 | c << 32 | d << 48; + + a = buffer[4]; + b = buffer[5]; + c = buffer[6]; + d = buffer[7]; + + long lower = a | b << 16 | c << 32 | d << 48; + + return value = new UUID(upper, lower); + } + + public void setValue(UUID value) { + if (value.equals(this.value)) { + return; + } + + this.value = value; + + long long_value = value.getMostSignificantBits(); + + buffer[0] = (int) ((long_value) & 0xFFFF); + buffer[1] = (int) ((long_value >>> 16) & 0xFFFF); + buffer[2] = (int) ((long_value >>> 32) & 0xFFFF); + buffer[3] = (int) ((long_value >>> 48) & 0xFFFF); + + long_value = value.getLeastSignificantBits(); + + buffer[4] = (int) ((long_value) & 0xFFFF); + buffer[5] = (int) ((long_value >>> 16) & 0xFFFF); + buffer[6] = (int) ((long_value >>> 32) & 0xFFFF); + buffer[7] = (int) ((long_value >>> 48) & 0xFFFF); + } + + // override + protected void updateValue() { + + } + + @Override + public int get(int index) { + updateValue(); + return buffer[index]; + } + + @Override + public void set(int index, int _value) { + if (buffer[index] == _value) + return; + + value = null; + buffer[index] = _value; + } + + @Override + public int getCount() { + return NETWORK_PAYLOAD_SIZE; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java index f87eee883..e237282be 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java @@ -5,6 +5,7 @@ import net.minecraftforge.fmllegacy.network.NetworkDirection; import net.minecraftforge.fmllegacy.network.NetworkRegistry; import net.minecraftforge.fmllegacy.network.simple.SimpleChannel; import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.capability.drive.NetworkedItemView; import ru.dbotthepony.mc.otm.network.android.*; import java.util.Optional; @@ -129,5 +130,50 @@ public class MatteryNetworking { MatterBottlerSwitchPacket::play, Optional.of(NetworkDirection.PLAY_TO_SERVER) ); + + CHANNEL.registerMessage( + next_network_id++, + NetworkedItemView.ClearPacket.class, + NetworkedItemView.ClearPacket::write, + NetworkedItemView.ClearPacket::read, + NetworkedItemView.ClearPacket::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + NetworkedItemView.CreatedPacket.class, + NetworkedItemView.CreatedPacket::write, + NetworkedItemView.CreatedPacket::read, + NetworkedItemView.CreatedPacket::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + NetworkedItemView.StackAddPacket.class, + NetworkedItemView.StackAddPacket::write, + NetworkedItemView.StackAddPacket::read, + NetworkedItemView.StackAddPacket::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + NetworkedItemView.StackChangePacket.class, + NetworkedItemView.StackChangePacket::write, + NetworkedItemView.StackChangePacket::read, + NetworkedItemView.StackChangePacket::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); + + CHANNEL.registerMessage( + next_network_id++, + NetworkedItemView.StackRemovePacket.class, + NetworkedItemView.StackRemovePacket::write, + NetworkedItemView.StackRemovePacket::read, + NetworkedItemView.StackRemovePacket::play, + Optional.of(NetworkDirection.PLAY_TO_CLIENT) + ); } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java index 2cb3c49fe..b5e2fbd0c 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java @@ -14,6 +14,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer; import ru.dbotthepony.mc.otm.menu.AndroidStationMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget; import ru.dbotthepony.mc.otm.screen.panels.*; @@ -104,7 +105,7 @@ public class AndroidStationScreen extends MatteryScreen impl } @Override - public List getBatterySlots() { + public List getBatterySlots() { return List.of(menu.battery_slot); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/DriveViewerScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/DriveViewerScreen.java new file mode 100644 index 000000000..7717c1827 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/DriveViewerScreen.java @@ -0,0 +1,72 @@ +package ru.dbotthepony.mc.otm.screen; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import ru.dbotthepony.mc.otm.menu.DriveViewerMenu; +import ru.dbotthepony.mc.otm.menu.MatteryMenu; +import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; +import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget; +import ru.dbotthepony.mc.otm.screen.panels.*; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class DriveViewerScreen extends MatteryScreen implements MatteryScreen.IMatteryScreenGaugeGetter, MatteryScreen.IMatteryScreenBatteryGetter { + public static final int FRAME_WIDTH = 210; + public static final int FRAME_HEIGHT = 100; + + public DriveViewerScreen(DriveViewerMenu menu, Inventory inventory, Component title) { + super(menu, inventory, title); + } + + @Override + public List getGauges() { + return List.of(menu.battery_widget); + } + + @Override + public List getBatterySlots() { + return List.of(menu.battery_slot, menu.drive_slot); + } + + @Nullable + @Override + protected FramePanel makeMainFrame() { + var frame = new FramePanel(this, null, 0, 0, FRAME_WIDTH, FRAME_HEIGHT, getTitle()); + + autoAttachToFrame(frame); + + var grid = new GridPanel(this, frame, 0, 0, 0, 0, 3, 3); + grid.setDock(Dock.FILL); + + for (int i = 0; i < 9; i++) { + final int index = i; + + new AbstractSlotPanel(this, grid, 0, 0) { + @Nonnull + @Override + protected ItemStack getItemStack() { + var view = menu.getView(); + + if (view != null) { + var list = view.getItems(); + + if (index >= list.size()) { + return ItemStack.EMPTY; + } + + return list.get(index); + } + + return ItemStack.EMPTY; + } + }; + } + + return frame; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterBottlerScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterBottlerScreen.java index c54dda322..7a6926c6e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterBottlerScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterBottlerScreen.java @@ -5,6 +5,7 @@ import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget; import ru.dbotthepony.mc.otm.screen.panels.*; @@ -22,7 +23,7 @@ public class MatterBottlerScreen extends MatteryScreen implem } @Override - public List getBatterySlots() { + public List getBatterySlots() { return List.of(menu.battery_slot); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterDecomposerScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterDecomposerScreen.java index 93804fc00..88106b6d8 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterDecomposerScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterDecomposerScreen.java @@ -5,6 +5,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.menu.MatterDecomposerMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget; import ru.dbotthepony.mc.otm.screen.panels.*; @@ -22,7 +23,7 @@ public class MatterDecomposerScreen extends MatteryScreen } @Override - public List getBatterySlots() { + public List getBatterySlots() { return List.of(menu.battery_slot); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java index ca81436ca..1c215764e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterReplicatorScreen.java @@ -4,6 +4,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget; import ru.dbotthepony.mc.otm.screen.panels.*; @@ -21,7 +22,7 @@ public class MatterReplicatorScreen extends MatteryScreen } @Override - public List getBatterySlots() { + public List getBatterySlots() { return List.of(menu.battery_slot); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterScannerScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterScannerScreen.java index 22712e5e7..0e9af37e8 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterScannerScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterScannerScreen.java @@ -4,6 +4,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.menu.MatterScannerMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; import ru.dbotthepony.mc.otm.menu.widget.GaugeWidget; import ru.dbotthepony.mc.otm.screen.panels.*; @@ -21,7 +22,7 @@ public class MatterScannerScreen extends MatteryScreen implem } @Override - public List getBatterySlots() { + public List getBatterySlots() { return List.of(menu.battery_slot); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java index 0fa4529a8..3e9d6a0f3 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java @@ -57,7 +57,7 @@ public abstract class MatteryScreen extends AbstractConta } public interface IMatteryScreenBatteryGetter extends IMatteryScreenLeftPanel { - List getBatterySlots(); + List getBatterySlots(); } public interface IMatteryScreenGridBased {