修复了服务器数据同步最高为32767的问题

This commit is contained in:
17146 2024-12-08 02:08:30 +08:00
parent 4f1de3b41c
commit 335500e070
9 changed files with 247 additions and 28 deletions

View file

@ -154,6 +154,7 @@ public class ModUtils {
addNetworkMessage(EditMessage.class, EditMessage::encode, EditMessage::decode, EditMessage::handler); addNetworkMessage(EditMessage.class, EditMessage::encode, EditMessage::decode, EditMessage::handler);
addNetworkMessage(SwitchScopeMessage.class, SwitchScopeMessage::encode, SwitchScopeMessage::decode, SwitchScopeMessage::handler); addNetworkMessage(SwitchScopeMessage.class, SwitchScopeMessage::encode, SwitchScopeMessage::decode, SwitchScopeMessage::handler);
addNetworkMessage(SetFiringParametersMessage.class, SetFiringParametersMessage::encode, SetFiringParametersMessage::decode, SetFiringParametersMessage::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)), 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()))); Ingredient.of(Items.LIGHTNING_ROD), PotionUtils.setPotion(new ItemStack(Items.POTION), ModPotion.SHOCK.get())));

View file

@ -3,6 +3,7 @@ package com.atsuishio.superbwarfare.block.entity;
import com.atsuishio.superbwarfare.block.menu.ChargingStationMenu; import com.atsuishio.superbwarfare.block.menu.ChargingStationMenu;
import com.atsuishio.superbwarfare.entity.IChargeEntity; import com.atsuishio.superbwarfare.entity.IChargeEntity;
import com.atsuishio.superbwarfare.init.ModBlockEntities; import com.atsuishio.superbwarfare.init.ModBlockEntities;
import com.atsuishio.superbwarfare.network.dataslot.ContainerEnergyData;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList; 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.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -34,7 +34,11 @@ import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; 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 { public class ChargingStationBlockEntity extends BlockEntity implements WorldlyContainer, MenuProvider {
protected static final int SLOT_FUEL = 0; protected static final int SLOT_FUEL = 0;
@ -58,28 +62,31 @@ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyCo
public int fuelTick = 0; public int fuelTick = 0;
public int maxFuelTick = DEFAULT_FUEL_TIME; public int maxFuelTick = DEFAULT_FUEL_TIME;
public int energy;
protected final ContainerData dataAccess = new ContainerData() { protected final ContainerEnergyData dataAccess = new ContainerEnergyData() {
public int get(int pIndex) { public long get(int pIndex) {
return switch (pIndex) { return switch (pIndex) {
case 0 -> ChargingStationBlockEntity.this.fuelTick; case 0 -> ChargingStationBlockEntity.this.fuelTick;
case 1 -> ChargingStationBlockEntity.this.maxFuelTick; 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; default -> 0;
}; };
} }
public void set(int pIndex, int pValue) { public void set(int pIndex, long pValue) {
switch (pIndex) { switch (pIndex) {
case 0: case 0:
ChargingStationBlockEntity.this.fuelTick = pValue; ChargingStationBlockEntity.this.fuelTick = (int) pValue;
break; break;
case 1: case 1:
ChargingStationBlockEntity.this.maxFuelTick = pValue; ChargingStationBlockEntity.this.maxFuelTick = (int) pValue;
break; break;
case 2: case 2:
ChargingStationBlockEntity.this.energy = pValue; ChargingStationBlockEntity.this.getCapability(ForgeCapabilities.ENERGY).ifPresent(consumer -> consumer.receiveEnergy((int) pValue, false));
break; break;
} }
} }
@ -98,7 +105,6 @@ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyCo
public static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, ChargingStationBlockEntity blockEntity) { public static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, ChargingStationBlockEntity blockEntity) {
blockEntity.energyHandler.ifPresent(handler -> { blockEntity.energyHandler.ifPresent(handler -> {
int energy = handler.getEnergyStored(); int energy = handler.getEnergyStored();
blockEntity.energy = energy;
if (energy > 0) { if (energy > 0) {
blockEntity.chargeEntity(handler); blockEntity.chargeEntity(handler);
} }
@ -253,10 +259,16 @@ public class ChargingStationBlockEntity extends BlockEntity implements WorldlyCo
@Override @Override
public void setItem(int pSlot, ItemStack pStack) { 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); this.items.set(pSlot, pStack);
if (pStack.getCount() > this.getMaxStackSize()) { if (pStack.getCount() > this.getMaxStackSize()) {
pStack.setCount(this.getMaxStackSize()); pStack.setCount(this.getMaxStackSize());
} }
if (pSlot == 0 && !flag) {
this.setChanged();
}
} }
@Override @Override

View file

@ -1,46 +1,61 @@
package com.atsuishio.superbwarfare.block.menu; package com.atsuishio.superbwarfare.block.menu;
import com.atsuishio.superbwarfare.ModUtils;
import com.atsuishio.superbwarfare.block.entity.ChargingStationBlockEntity; import com.atsuishio.superbwarfare.block.entity.ChargingStationBlockEntity;
import com.atsuishio.superbwarfare.init.ModMenuTypes; 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.Container;
import net.minecraft.world.SimpleContainer; import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; 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.inventory.Slot;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.capabilities.ForgeCapabilities; 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 { public class ChargingStationMenu extends AbstractContainerMenu {
private final Container container; private final Container container;
private final ContainerData containerData; private final ContainerEnergyData containerData;
protected final Level level;
private final List<ContainerEnergyDataSlot> containerEnergyDataSlots = Lists.newArrayList();
private final List<ServerPlayer> usingPlayers = new ArrayList<>();
public static final int X_OFFSET = 0; public static final int X_OFFSET = 0;
public static final int Y_OFFSET = 0; public static final int Y_OFFSET = 0;
public ChargingStationMenu(int id, Inventory inventory) { 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); super(ModMenuTypes.CHARGING_STATION_MENU.get(), id);
checkContainerSize(container, 2); checkContainerSize(container, 2);
checkContainerDataCount(containerData, ChargingStationBlockEntity.MAX_DATA_COUNT);
this.container = container; this.container = container;
this.containerData = containerData; this.containerData = containerData;
this.level = inventory.player.level();
this.addSlot(new Slot(container, 0, 44, 54)); this.addSlot(new Slot(container, 0, 44, 54));
this.addSlot(new ChargingSlot(container, 1, 116, 54)); this.addSlot(new ChargingSlot(container, 1, 116, 54));
this.addDataSlots(containerData);
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 9; ++j) { 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)); 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) { for (int k = 0; k < 9; ++k) {
this.addSlot(new Slot(inventory, k, 8 + k * 18 + X_OFFSET, 142 + Y_OFFSET)); 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<ContainerDataMessage.Pair> 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 @Override
@ -104,15 +148,15 @@ public class ChargingStationMenu extends AbstractContainerMenu {
return this.container.stillValid(pPlayer); return this.container.stillValid(pPlayer);
} }
public int getFuelTick() { public long getFuelTick() {
return this.containerData.get(0); return this.containerData.get(0);
} }
public int getMaxFuelTick() { public long getMaxFuelTick() {
return this.containerData.get(1); return this.containerData.get(1);
} }
public int getEnergy() { public long getEnergy() {
return this.containerData.get(2); 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<ContainerDataMessage.Pair> 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);
}
}
} }

View file

@ -32,9 +32,9 @@ public class ChargingStationScreen extends AbstractContainerScreen<ChargingStati
int j = (this.height - this.imageHeight) / 2; int j = (this.height - this.imageHeight) / 2;
pGuiGraphics.blit(TEXTURE, i, j, 0, 0, this.imageWidth, this.imageHeight); pGuiGraphics.blit(TEXTURE, i, j, 0, 0, this.imageWidth, this.imageHeight);
int fuelTick = ChargingStationScreen.this.menu.getFuelTick(); long fuelTick = ChargingStationScreen.this.menu.getFuelTick();
int maxFuelTick = ChargingStationScreen.this.menu.getMaxFuelTick(); long maxFuelTick = ChargingStationScreen.this.menu.getMaxFuelTick();
int energy = ChargingStationScreen.this.menu.getEnergy(); long energy = ChargingStationScreen.this.menu.getEnergy();
if (maxFuelTick == 0) { if (maxFuelTick == 0) {
maxFuelTick = ChargingStationBlockEntity.DEFAULT_FUEL_TIME; maxFuelTick = ChargingStationBlockEntity.DEFAULT_FUEL_TIME;

View file

@ -1,13 +1,16 @@
package com.atsuishio.superbwarfare.network; package com.atsuishio.superbwarfare.network;
import com.atsuishio.superbwarfare.config.client.KillMessageConfig; import com.atsuishio.superbwarfare.block.menu.ChargingStationMenu;
import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage;
import com.atsuishio.superbwarfare.network.message.GunsDataMessage;
import com.atsuishio.superbwarfare.tools.GunsTool;
import com.atsuishio.superbwarfare.client.screens.CrossHairOverlay; import com.atsuishio.superbwarfare.client.screens.CrossHairOverlay;
import com.atsuishio.superbwarfare.client.screens.DroneUIOverlay; import com.atsuishio.superbwarfare.client.screens.DroneUIOverlay;
import com.atsuishio.superbwarfare.config.client.KillMessageConfig;
import com.atsuishio.superbwarfare.event.KillMessageHandler; import com.atsuishio.superbwarfare.event.KillMessageHandler;
import com.atsuishio.superbwarfare.network.message.ClientIndicatorMessage;
import com.atsuishio.superbwarfare.network.message.ContainerDataMessage;
import com.atsuishio.superbwarfare.network.message.GunsDataMessage;
import com.atsuishio.superbwarfare.tools.GunsTool;
import com.atsuishio.superbwarfare.tools.PlayerKillRecord; import com.atsuishio.superbwarfare.tools.PlayerKillRecord;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.world.damagesource.DamageType; import net.minecraft.world.damagesource.DamageType;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -15,6 +18,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ClientPacketHandler { public class ClientPacketHandler {
@ -49,4 +53,13 @@ public class ClientPacketHandler {
DroneUIOverlay.MAX_DISTANCE = distance * 16; DroneUIOverlay.MAX_DISTANCE = distance * 16;
} }
} }
public static void handleContainerDataMessage(int containerId, List<ContainerDataMessage.Pair> data, Supplier<NetworkEvent.Context> 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));
}
}
}
} }

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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<Pair> data;
public ContainerDataMessage(int containerId, List<Pair> 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<NetworkEvent.Context> 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);
}
}
}