From 335500e07093d3093a679f5b9a660771f74d9d13 Mon Sep 17 00:00:00 2001 From: 17146 <1714673995@qq.com> Date: Sun, 8 Dec 2024 02:08:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E6=9C=80=E9=AB=98?= =?UTF-8?q?=E4=B8=BA32767=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/atsuishio/superbwarfare/ModUtils.java | 1 + .../entity/ChargingStationBlockEntity.java | 32 ++++--- .../block/menu/ChargingStationMenu.java | 86 ++++++++++++++++--- .../client/screens/ChargingStationScreen.java | 6 +- .../network/ClientPacketHandler.java | 21 ++++- .../network/dataslot/ContainerEnergyData.java | 10 +++ .../dataslot/ContainerEnergyDataSlot.java | 35 ++++++++ .../network/dataslot/SimpleEnergyData.java | 28 ++++++ .../network/message/ContainerDataMessage.java | 56 ++++++++++++ 9 files changed, 247 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyData.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyDataSlot.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/network/dataslot/SimpleEnergyData.java create mode 100644 src/main/java/com/atsuishio/superbwarfare/network/message/ContainerDataMessage.java diff --git a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java index 002551a07..5098a2516 100644 --- a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java +++ b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java @@ -154,6 +154,7 @@ public class ModUtils { addNetworkMessage(EditMessage.class, EditMessage::encode, EditMessage::decode, EditMessage::handler); addNetworkMessage(SwitchScopeMessage.class, SwitchScopeMessage::encode, SwitchScopeMessage::decode, SwitchScopeMessage::handler); addNetworkMessage(SetFiringParametersMessage.class, SetFiringParametersMessage::encode, SetFiringParametersMessage::decode, SetFiringParametersMessage::handler); + addNetworkMessage(ContainerDataMessage.class, ContainerDataMessage::encode, ContainerDataMessage::decode, ContainerDataMessage::handler, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); event.enqueueWork(() -> BrewingRecipeRegistry.addRecipe(Ingredient.of(PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER)), Ingredient.of(Items.LIGHTNING_ROD), PotionUtils.setPotion(new ItemStack(Items.POTION), ModPotion.SHOCK.get()))); diff --git a/src/main/java/com/atsuishio/superbwarfare/block/entity/ChargingStationBlockEntity.java b/src/main/java/com/atsuishio/superbwarfare/block/entity/ChargingStationBlockEntity.java index c5fb9de43..61610a939 100644 --- a/src/main/java/com/atsuishio/superbwarfare/block/entity/ChargingStationBlockEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/block/entity/ChargingStationBlockEntity.java @@ -3,6 +3,7 @@ package com.atsuishio.superbwarfare.block.entity; import com.atsuishio.superbwarfare.block.menu.ChargingStationMenu; import com.atsuishio.superbwarfare.entity.IChargeEntity; import com.atsuishio.superbwarfare.init.ModBlockEntities; +import com.atsuishio.superbwarfare.network.dataslot.ContainerEnergyData; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; @@ -17,7 +18,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.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; @@ -34,7 +34,11 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +/** + * Energy Data Slot Code based on @GoryMoon's Chargers + */ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyContainer, MenuProvider { protected static final int SLOT_FUEL = 0; @@ -58,28 +62,31 @@ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyCo public int fuelTick = 0; public int maxFuelTick = DEFAULT_FUEL_TIME; - public int energy; - protected final ContainerData dataAccess = new ContainerData() { - public int get(int pIndex) { + protected final ContainerEnergyData dataAccess = new ContainerEnergyData() { + public long get(int pIndex) { return switch (pIndex) { case 0 -> ChargingStationBlockEntity.this.fuelTick; case 1 -> ChargingStationBlockEntity.this.maxFuelTick; - case 2 -> ChargingStationBlockEntity.this.energy; + case 2 -> { + AtomicInteger energy = new AtomicInteger(); + ChargingStationBlockEntity.this.getCapability(ForgeCapabilities.ENERGY).ifPresent(consumer -> energy.set(consumer.getEnergyStored())); + yield energy.get(); + } default -> 0; }; } - public void set(int pIndex, int pValue) { + public void set(int pIndex, long pValue) { switch (pIndex) { case 0: - ChargingStationBlockEntity.this.fuelTick = pValue; + ChargingStationBlockEntity.this.fuelTick = (int) pValue; break; case 1: - ChargingStationBlockEntity.this.maxFuelTick = pValue; + ChargingStationBlockEntity.this.maxFuelTick = (int) pValue; break; case 2: - ChargingStationBlockEntity.this.energy = pValue; + ChargingStationBlockEntity.this.getCapability(ForgeCapabilities.ENERGY).ifPresent(consumer -> consumer.receiveEnergy((int) pValue, false)); break; } } @@ -98,7 +105,6 @@ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyCo public static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, ChargingStationBlockEntity blockEntity) { blockEntity.energyHandler.ifPresent(handler -> { int energy = handler.getEnergyStored(); - blockEntity.energy = energy; if (energy > 0) { blockEntity.chargeEntity(handler); } @@ -253,10 +259,16 @@ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyCo @Override public void setItem(int pSlot, ItemStack pStack) { + ItemStack itemstack = this.items.get(pSlot); + boolean flag = !pStack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, pStack); this.items.set(pSlot, pStack); if (pStack.getCount() > this.getMaxStackSize()) { pStack.setCount(this.getMaxStackSize()); } + + if (pSlot == 0 && !flag) { + this.setChanged(); + } } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/block/menu/ChargingStationMenu.java b/src/main/java/com/atsuishio/superbwarfare/block/menu/ChargingStationMenu.java index 97e145b39..2aadaa7c6 100644 --- a/src/main/java/com/atsuishio/superbwarfare/block/menu/ChargingStationMenu.java +++ b/src/main/java/com/atsuishio/superbwarfare/block/menu/ChargingStationMenu.java @@ -1,46 +1,61 @@ package com.atsuishio.superbwarfare.block.menu; +import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.block.entity.ChargingStationBlockEntity; import com.atsuishio.superbwarfare.init.ModMenuTypes; +import com.atsuishio.superbwarfare.network.dataslot.ContainerEnergyData; +import com.atsuishio.superbwarfare.network.dataslot.ContainerEnergyDataSlot; +import com.atsuishio.superbwarfare.network.dataslot.SimpleEnergyData; +import com.atsuishio.superbwarfare.network.message.ContainerDataMessage; +import com.google.common.collect.Lists; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; 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.inventory.SimpleContainerData; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.Level; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.event.entity.player.PlayerContainerEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.network.PacketDistributor; +import java.util.ArrayList; +import java.util.List; + +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE) public class ChargingStationMenu extends AbstractContainerMenu { private final Container container; - private final ContainerData containerData; + private final ContainerEnergyData containerData; + protected final Level level; + private final List containerEnergyDataSlots = Lists.newArrayList(); + private final List usingPlayers = new ArrayList<>(); public static final int X_OFFSET = 0; public static final int Y_OFFSET = 0; public ChargingStationMenu(int id, Inventory inventory) { - this(id, inventory, new SimpleContainer(2), new SimpleContainerData(ChargingStationBlockEntity.MAX_DATA_COUNT)); + this(id, inventory, new SimpleContainer(2), new SimpleEnergyData(ChargingStationBlockEntity.MAX_DATA_COUNT)); } - public ChargingStationMenu(int id, Inventory inventory, Container container, ContainerData containerData) { + public ChargingStationMenu(int id, Inventory inventory, Container container, ContainerEnergyData containerData) { super(ModMenuTypes.CHARGING_STATION_MENU.get(), id); checkContainerSize(container, 2); - checkContainerDataCount(containerData, ChargingStationBlockEntity.MAX_DATA_COUNT); this.container = container; this.containerData = containerData; + this.level = inventory.player.level(); this.addSlot(new Slot(container, 0, 44, 54)); this.addSlot(new ChargingSlot(container, 1, 116, 54)); - this.addDataSlots(containerData); - for (int i = 0; i < 3; ++i) { for (int j = 0; j < 9; ++j) { this.addSlot(new Slot(inventory, j + i * 9 + 9, 8 + j * 18 + X_OFFSET, 84 + i * 18 + Y_OFFSET)); @@ -50,6 +65,35 @@ public class ChargingStationMenu extends AbstractContainerMenu { for (int k = 0; k < 9; ++k) { this.addSlot(new Slot(inventory, k, 8 + k * 18 + X_OFFSET, 142 + Y_OFFSET)); } + + for (int i = 0; i < containerData.getCount(); ++i) { + this.containerEnergyDataSlots.add(ContainerEnergyDataSlot.forContainer(containerData, i)); + } + } + + @Override + public void broadcastChanges() { + List pairs = new ArrayList<>(); + for (int i = 0; i < containerEnergyDataSlots.size(); ++i) { + ContainerEnergyDataSlot dataSlot = containerEnergyDataSlots.get(i); + if (dataSlot.checkAndClearUpdateFlag()) + pairs.add(new ContainerDataMessage.Pair(i, dataSlot.get())); + } + + if (!pairs.isEmpty()) { + PacketDistributor.PacketTarget target = PacketDistributor.NMLIST.with(usingPlayers.stream().map(serverPlayer -> serverPlayer.connection.connection)::toList); + ModUtils.PACKET_HANDLER.send(target, new ContainerDataMessage(this.containerId, pairs)); + } + + super.broadcastChanges(); + } + + public void setData(int id, int data) { + containerEnergyDataSlots.get(id).set(data); + } + + public void setData(int id, long data) { + containerEnergyDataSlots.get(id).set(data); } @Override @@ -104,15 +148,15 @@ public class ChargingStationMenu extends AbstractContainerMenu { return this.container.stillValid(pPlayer); } - public int getFuelTick() { + public long getFuelTick() { return this.containerData.get(0); } - public int getMaxFuelTick() { + public long getMaxFuelTick() { return this.containerData.get(1); } - public int getEnergy() { + public long getEnergy() { return this.containerData.get(2); } @@ -128,4 +172,24 @@ public class ChargingStationMenu extends AbstractContainerMenu { } } + @SubscribeEvent + public static void onContainerOpened(PlayerContainerEvent.Open event) { + if (event.getContainer() instanceof ChargingStationMenu menu && event.getEntity() instanceof ServerPlayer serverPlayer) { + menu.usingPlayers.add(serverPlayer); + + List toSync = new ArrayList<>(); + for (int i = 0; i < menu.containerEnergyDataSlots.size(); ++i) { + toSync.add(new ContainerDataMessage.Pair(i, menu.containerEnergyDataSlots.get(i).get())); + } + + ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new ContainerDataMessage(menu.containerId, toSync)); + } + } + + @SubscribeEvent + public static void onContainerClosed(PlayerContainerEvent.Close event) { + if (event.getContainer() instanceof ChargingStationMenu menu && event.getEntity() instanceof ServerPlayer serverPlayer) { + menu.usingPlayers.remove(serverPlayer); + } + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/client/screens/ChargingStationScreen.java b/src/main/java/com/atsuishio/superbwarfare/client/screens/ChargingStationScreen.java index ed6f44be7..3173b219c 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/screens/ChargingStationScreen.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/screens/ChargingStationScreen.java @@ -32,9 +32,9 @@ public class ChargingStationScreen extends AbstractContainerScreen data, Supplier ctx) { + if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) { + Minecraft mc = Minecraft.getInstance(); + if (mc.player != null && mc.player.containerMenu.containerId == containerId) { + data.forEach(p -> ((ChargingStationMenu) mc.player.containerMenu).setData(p.id, p.data)); + } + } + } } diff --git a/src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyData.java b/src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyData.java new file mode 100644 index 000000000..53abc739d --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyData.java @@ -0,0 +1,10 @@ +package com.atsuishio.superbwarfare.network.dataslot; + +public interface ContainerEnergyData { + + long get(int pIndex); + + void set(int pIndex, long pValue); + + int getCount(); +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyDataSlot.java b/src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyDataSlot.java new file mode 100644 index 000000000..6c92fe746 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/dataslot/ContainerEnergyDataSlot.java @@ -0,0 +1,35 @@ +package com.atsuishio.superbwarfare.network.dataslot; + +/** + * Code based on @GoryMoon's Chargers + */ +public abstract class ContainerEnergyDataSlot { + + private long prevValue; + + public ContainerEnergyDataSlot() { + } + + public static ContainerEnergyDataSlot forContainer(final ContainerEnergyData data, final int index) { + return new ContainerEnergyDataSlot() { + public long get() { + return data.get(index); + } + + public void set(long value) { + data.set(index, value); + } + }; + } + + public abstract long get(); + + public abstract void set(long value); + + public boolean checkAndClearUpdateFlag() { + long tmp = this.get(); + boolean changed = tmp != this.prevValue; + this.prevValue = tmp; + return changed; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/dataslot/SimpleEnergyData.java b/src/main/java/com/atsuishio/superbwarfare/network/dataslot/SimpleEnergyData.java new file mode 100644 index 000000000..b48faf85a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/dataslot/SimpleEnergyData.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.network.dataslot; + +/** + * Code based on @GoryMoon's Chargers + */ +public class SimpleEnergyData implements ContainerEnergyData { + + private final long[] data; + + public SimpleEnergyData(int size) { + this.data = new long[size]; + } + + @Override + public long get(int index) { + return this.data[index]; + } + + @Override + public void set(int index, long value) { + this.data[index] = value; + } + + @Override + public int getCount() { + return this.data.length; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/ContainerDataMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/ContainerDataMessage.java new file mode 100644 index 000000000..1d4532a18 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/ContainerDataMessage.java @@ -0,0 +1,56 @@ +package com.atsuishio.superbwarfare.network.message; + +import com.atsuishio.superbwarfare.network.ClientPacketHandler; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent; + +import java.util.List; +import java.util.function.Supplier; + +/** + * Code based on @GoryMoon's Chargers + */ +public class ContainerDataMessage { + + private final int containerId; + private final List data; + + public ContainerDataMessage(int containerId, List data) { + this.containerId = containerId; + this.data = data; + } + + public static ContainerDataMessage decode(FriendlyByteBuf buf) { + return new ContainerDataMessage(buf.readUnsignedByte(), buf.readList(byteBuf -> new Pair(byteBuf.readShort(), byteBuf.readLong()))); + } + + public static void encode(ContainerDataMessage message, FriendlyByteBuf buf) { + buf.writeByte(message.containerId); + buf.writeCollection(message.data, (byteBuf, p) -> p.write(byteBuf)); + } + + public static void handler(ContainerDataMessage message, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> ClientPacketHandler.handleContainerDataMessage(message.containerId, message.data, ctx))); + ctx.get().setPacketHandled(true); + } + + public static class Pair { + + public int id; + public long data; + + public Pair(int id, long data) { + this.id = id; + this.data = data; + } + + public void write(FriendlyByteBuf buf) { + buf.writeShort(id); + buf.writeLong(data); + } + } + +}