Posted January 14, 20223 yr Forge 1.16.5-36.1.30. Docs say that PlayerEvent.Copy event is helpful for this, but I cant figure out what to do exactly. This is what I wrote and it doesnt work: EventHandler: @SubscribeEvent static void copyPlayerDataOnRespawn(PlayerEvent.Clone event){ SoulCap soul = SF.getSoul(event.getOriginal()); SoulCap soulNew = SF.getSoul(event.getPlayer()); soulNew = soul; SF.sendToClient((ServerPlayerEntity)event.getPlayer(), soulNew); } SF: public static SoulCap getSoul(PlayerEntity player){ return player.getCapability(SoulCap.SoulProvider.SOUL_CAP, null).resolve().orElse(null); } public static void sendToClient(ServerPlayerEntity player, SoulCap cap){ PacketSender.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new SoulPacket(cap)); } SoulPacket: static void handle(SoulPacket p, Supplier<NetworkEvent.Context> ctx){ ctx.get().enqueueWork(() -> { if (ctx.get().getDirection() == NetworkDirection.PLAY_TO_CLIENT) { ClientPlayerEntity player = Minecraft.getInstance().player; SoulCap cap = SF.getSoul(player); cap.setNbt(p.cap.getNbt()); if (cap.justParried) { player.stopActiveHand(); cap.justParried = false; } } else if (ctx.get().getDirection() == NetworkDirection.PLAY_TO_SERVER){ ServerPlayerEntity player = ctx.get().getSender(); SoulCap cap = SF.getSoul(player); cap.setNbt(p.cap.getNbt()); if (cap.justParried) { cap.justParried = false; } } }); ctx.get().setPacketHandled(true); } First of all, the sentToClient side can be easlily removed because at this point in code Minecraft.getInstance().player is still null. But I still have to sync sides somehow... And secondly, the capability is not actually getting copied. I guess its because in this case player.getCapability() only provides a copy of the asked capability, not an assignable reference. But there is no player.setCapability method... So what do I do? Edited January 14, 20223 yr by GrigLog
January 14, 20223 yr Author Quote You need to actually copy the data Well, thats exactly what Im struggling with. Ive also tried soulNew.setNbt(soul.getNbt()), but with no result Quote This allows the client to just set arbitrary data into the capability, which will enable cheating The thing is, I actively use input events and I have to send player inputs to server somehow. I should probably make 2 separate capabilities (for mana and for inputs) later SoulCap class: public class SoulCap { public static int CATimerMax = 20; public static int dashWindowMax = 3; public static int dashCDMax = 20; public int parryTimer = 0; public int CATimer = 0; public int dashWindow = 0; public int dashCD = 0; public boolean justParried = false; public boolean rightClicked = false; public boolean leftClicked = false; public double mana = 0; public double maxMana = 10; public HashMap<String, Integer> usedKeyItems = new HashMap<>(); public boolean trySpendMana(double a) { if (mana >= a){ mana -= a; return true; } return false; } public void addMana(double a){ mana += a; if (mana > maxMana) mana = maxMana; } public CompoundNBT getNbt(){ CompoundNBT tag = new CompoundNBT(); tag.putInt("parryTimer", parryTimer); tag.putInt("CATimer", CATimer); tag.putBoolean("justParried", justParried); tag.putBoolean("rightClicked", rightClicked); tag.putBoolean("leftClicked", leftClicked); tag.putDouble("mana", mana); tag.putDouble("maxMana", maxMana); CompoundNBT keyItems = new CompoundNBT(); for (String s : usedKeyItems.keySet()){ keyItems.putInt(s, usedKeyItems.get(s)); } tag.put("usedKeyItems", keyItems); return tag; } public SoulCap setNbt(CompoundNBT nbt){ parryTimer = nbt.getInt("parryTimer"); CATimer= nbt.getInt("CATimer"); justParried = nbt.getBoolean("justParried"); rightClicked = nbt.getBoolean("rightClicked"); leftClicked = nbt.getBoolean("leftClicked"); mana = nbt.getDouble("mana"); maxMana = nbt.getDouble("maxMana"); CompoundNBT keyItems = nbt.getCompound("usedKeyItems"); for (String s : keyItems.keySet()){ usedKeyItems.put(s, keyItems.getInt(s)); } return this; } public static class SoulProvider implements ICapabilitySerializable<INBT> { @CapabilityInject(SoulCap.class) public static Capability<SoulCap> SOUL_CAP; private final LazyOptional<SoulCap> instance = LazyOptional.of(() -> new SoulCap()); @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return cap == SOUL_CAP ? instance.cast() : LazyOptional.empty(); } @Nonnull @Override public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap) { return cap == SOUL_CAP ? instance.cast() : LazyOptional.empty(); } @Override public INBT serializeNBT() { return SOUL_CAP.getStorage().writeNBT(SOUL_CAP, this.instance.resolve().get(), null); } @Override public void deserializeNBT(INBT nbt) { SOUL_CAP.getStorage().readNBT(SOUL_CAP, this.instance.resolve().get(), null, nbt); } } public static class SoulStorage implements Capability.IStorage<SoulCap> { @Override public INBT writeNBT(Capability<SoulCap> capability, SoulCap soulCap, Direction side) { return soulCap.getNbt(); } @Override public void readNBT(Capability<SoulCap> capability, SoulCap soulCap, Direction side, INBT nbt) { soulCap.setNbt((CompoundNBT)nbt); } } }
January 14, 20223 yr Author Im sorry, there was a result actually - on server side capability got copied correctly, I just didn't see it from the game because its not synced. Now, how can I send that data to client? In which event? Edited January 14, 20223 yr by GrigLog
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.