Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

How do I save player capability across deaths?


GrigLog
 Share

Recommended Posts

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 by GrigLog
Link to comment
Share on other sites

5 minutes ago, GrigLog said:
soulNew = soul;

This accomplishes nothing. You need to actually copy the data, not just set some local variable which you do nothing with afterwards.

6 minutes ago, GrigLog said:
SF.sendToClient((ServerPlayerEntity)event.getPlayer(), soulNew);

Do not send packets in PlayerEvent.Clone. The event exists solely to copy data over. Don't do anything else there.

7 minutes ago, GrigLog said:

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

This is highly problematic. This allows the client to just set arbitrary data into the capability, which will enable cheating and, depending how setNbt is implemented, may even allow clients to just crash the server.

Please also show your capability classes, the capability as well as the provider.

Link to comment
Share on other sites

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

 

 

Link to comment
Share on other sites

13 minutes ago, GrigLog said:

Well, thats exactly what Im struggling with. Ive also tried soulNew.setNbt(soul.getNbt()), but with no result

Define "no results".

13 minutes ago, GrigLog said:

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

That's fine, but then allow sending only that. Don't just blindly take the NBT data the client sends you and use it.

Link to comment
Share on other sites

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 by GrigLog
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • Hi guys! I currently have a project that I've been developing in a 'vanilla' environment that I'm actually looking to transfer over to Forge, simply because of how much better the experience would be using Forge. Before starting on this Forge mod, I was planning ahead and was looking at options for proxies, of which I would greatly like to use Velocity. In their docs and by asking around their Discord, they don't support support versions of Forge of 1.13 or later because of changes in the "handshake protocol". But I also really don't want to use an unsupported version of Forge, such as 1.12.2, to be able to use a proxy. I was pointed in the direction of potentially making my own client-side mod to allow Forge to be compatible with an updated proxy, such as Velocity. When asking for a direction for achieving this, I was told to have a look at how the Forge server implements logins and that the discrepancy might be with how modified the handshake protocol is. This sounds like quite the challenge to me and I'm completely up for trying to accomplish it. So for the sake of planning ahead and having a rough idea of how I could accomplish that when the time comes to work on it, has anyone else had experience with trying to achieve this? I appreciate any help or direction offered! Thanks! 
    • Been trying to set up a server for myself and a few friends through BisectHosting. I ended up replicating the server on my own computer to see if the issue persisted (if it was on bisect's end) and it was still there. Every time a player tries to connect to the server they start connecting but after only around 2 seconds the player is disconnected with the error message Payload size exceeds 1048576 bytes.  Upon inspection of the server debug file, the player always disconnects while fmlhandshake ticking packet info is being sent, and I have repeatedly made sure the mods and their configs are identical. I tried to get RandomPatches to increase the max allowed byte size, as the default seems to be 32767, but either something is wrong with it or some other mod is limiting the packet size limit.     Server Debug: https://pastebin.com/xZLbtdQB (only includes portions from after the server launched as I couldn't upload the whole file) Server Log: https://pastebin.com/yrJ3tNaW (similarly only after server launched (hence the weird say commands) Client Log: https://pastebin.com/inSzZV96 (whole thing for once) Modlist: https://pastebin.com/Qvurg45j (All but Optifine and BetterFoliage are present on the server as they have caused issues during startup)   Honestly stumped on how to fix this, been working on it for 10 hours across two days to no avail.
    • quiero dormir uwu
    • Hi, mod called "charging gadgets" is crushing forge minecraft 1.18.1 when i place block from this mod, im temporary playing On 1.18 cuz its not happening on 1.18 but c'mon, pls fix it, 1.18.1 is better and I Wonder i could use this version
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.