PlayerCapability

Версия Minecraft
1.16.5
API
Forge
30
3
2
Написал PlayerCapability

Java:
public class PlayerCapabilities implements ICapabilitySerializable<CompoundNBT> {
    private int breath;
    private int selectKata;
    private int[] learnedKata;
    public static final Capability<PlayerCapabilities> CAPABILITY = null;
    private final LazyOptional<PlayerCapabilities> holder = LazyOptional.of(() -> this);

    public PlayerCapabilities() {
        this.breath = 0;
        this.breath = 0;
        this.learnedKata = new int[15];
    }

    public int getBreath() {
        return this.breath;
    }

    public void setBreath(int breath) {
        this.breath = breath;
    }

    public int getSelected() {
        return this.selectKata;
    }

    public void setSelectKata(int selectKata) {
        this.selectKata = selectKata;
    }

    public int[] getLearnedKata() {
        return this.learnedKata;
    }

    public void setLearnedKata(int[] field3) {
        this.learnedKata = learnedKata;
    }

    @Override
    public CompoundNBT serializeNBT() {
        CompoundNBT nbt = new CompoundNBT();
        nbt.putInt("breath", breath);
        nbt.putInt("selectedKata", selectKata);
        ListNBT listNBT = new ListNBT();
        for (int i : learnedKata) {
            listNBT.add(IntNBT.valueOf(i));
        }
        nbt.put("field3", listNBT);
        return nbt;
    }

    @Override
    public void deserializeNBT(CompoundNBT nbt) {
        breath = nbt.getInt("breath");
        selectKata = nbt.getInt("selectKata");
        ListNBT listNBT = nbt.getList("learnedKata", Constants.NBT.TAG_INT);
        learnedKata = new int[listNBT.size()];
        for (int i = 0; i < listNBT.size(); i++) {
            learnedKata[i] = listNBT.getInt(i);
        }
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        return cap == PlayerCapabilities.CAPABILITY ? holder.cast() : LazyOptional.empty();
    }
}
Написал комманду для уст playercapability
Java:
package net.light.demonslayer.commands;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.tree.LiteralCommandNode;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.light.demonslayer.capabilities.PlayerCapabilities;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.text.*;
import org.apache.logging.log4j.core.tools.picocli.CommandLine;

import java.util.List;


public class SetBreathCommand {
    public static void register(CommandDispatcher<CommandSource> dispatcher) {
        LiteralCommandNode<CommandSource> setBreathCommand = dispatcher.register(
                Commands.literal("setbreath")
                        .then(Commands.argument("value", IntegerArgumentType.integer())
                                .executes(context -> setBreath(context.getSource(), IntegerArgumentType.getInteger(context, "value")))
                        )
        );
    }
    private static int setBreath(CommandSource source, int value) {
        if (!(source.getEntity() instanceof PlayerEntity)) {
            source.sendFailure(new TranslationTextComponent("commands.setbreath.error"));
            return 0;
        }
        PlayerEntity player = (PlayerEntity) source.getEntity();
        PlayerCapabilities cap = player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities());
        cap.setBreath(value);
        source.sendSuccess(new TranslationTextComponent("commands.setbreath.success", value), true);
        return 1;
    }
}
Зарегал
Java:
public class RegisterCommandsEvent {
    @SubscribeEvent
    public static void registerCommands(net.minecraftforge.event.RegisterCommandsEvent event)
    {
        SetBreathCommand.register(event.getDispatcher());
        ConfigCommand.register(event.getDispatcher());
    }
    @SubscribeEvent
    public static void onPlayerClone(PlayerEvent.Clone event) {
        PlayerEntity original = event.getOriginal();
        PlayerEntity player = event.getPlayer();
        PlayerCapabilities originalCap = original.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities());
        PlayerCapabilities newCap = player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities());
        newCap.setBreath(originalCap.getBreath());
        newCap.setSelectKata(originalCap.getSelected());
        newCap.setLearnedKata(originalCap.getLearnedKata().clone());
    }

    @SubscribeEvent
    public static void onWorldUnload(WorldEvent.Unload event) {
        if (event.getWorld() instanceof ServerWorld) {
            ServerWorld world = (ServerWorld) event.getWorld();
            for (ServerPlayerEntity player : world.getPlayers(ServerPlayerEntity::isAlive)) {
                PlayerCapabilities cap = player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities());
                File file = new File("saves/" + world.dimension().getRegistryName() + "/capabilities/" + player.getUUID() + ".nbt");
                CompoundNBT nbt = new CompoundNBT();
                nbt = cap.serializeNBT();
                try (FileOutputStream stream = new FileOutputStream(file)) {
                    CompressedStreamTools.writeCompressed(nbt, stream);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
И зарегал капу
Java:
public static void registerCapabilities() {
        CapabilityManager.INSTANCE.register(PlayerCapabilities.class, new PlayerCapabilitiesStorage(), PlayerCapabilities::new);
    }

    public static void attachCapabilityToPlayer(PlayerEntity player) {
        player.getCapability(PlayerCapabilities.CAPABILITY, null).ifPresent(cap -> cap.setBreath(0));
    }
И сделал кейбинд чтоб дебажить
Java:
@SubscribeEvent
    public static void onKeyPress(InputEvent.KeyInputEvent event) {
        Minecraft mc = Minecraft.getInstance();
        PlayerEntity player = Minecraft.getInstance().player;
        PlayerCapabilities cap = player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities());

        if (mc.screen == null) {
            if (RadialMenuKeybind.isDown()) {
                System.out.println(breath);
            }
        }
}
И при нажатии пишет 0 хоть я написал комманду setbreath 1
В чём ошибка
 
30
3
2
Пакет:
package net.light.demonslayer.network.packages;

import hohserg.elegant.networking.api.ElegantPacket;
import hohserg.elegant.networking.api.ServerToClientPacket;
import net.light.demonslayer.capabilities.PlayerCapabilities;
import net.minecraft.client.Minecraft;

@ElegantPacket

public class Cappacket implements ServerToClientPacket {
    final PlayerCapabilities cap;

    public Cappacket(PlayerCapabilities cap) {
        this.cap = cap;
    }

    @Override
    public void onReceive(Minecraft mc) {
        PlayerCapabilities capP = mc.player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities());
        capP.setBreath(this.cap.getBreath());
        capP.setSelectKata(this.cap.getSelected());
        capP.setLearnedKata(this.cap.getLearnedKata());
    }

}
Отправка в setBreatCommand:
new Cappacket(cap).sendToPlayer((ServerPlayerEntity)player);
Так?
 
30
3
2
Переписал пакет
Java:
public class PlayerCapabilitiesPacket {
    private final PlayerCapabilities playerCapabilities;

    public PlayerCapabilitiesPacket(PlayerCapabilities playerCapabilities) {
        this.playerCapabilities = playerCapabilities;
    }

    public static void encode(PlayerCapabilitiesPacket packet, PacketBuffer buffer) {
        buffer.writeInt(packet.playerCapabilities.getBreath());
        buffer.writeInt(packet.playerCapabilities.getSelected());
        buffer.writeVarInt(packet.playerCapabilities.getLearnedKata().length);
        for (int i : packet.playerCapabilities.getLearnedKata()) {
            buffer.writeVarInt(i);
        }
    }

    public static PlayerCapabilitiesPacket decode(PacketBuffer buffer) {
        int breath = buffer.readInt();
        int selectKata = buffer.readInt();
        int[] learnedKata = new int[buffer.readVarInt()];
        for (int i = 0; i < learnedKata.length; i++) {
            learnedKata[i] = buffer.readVarInt();
        }
        return new PlayerCapabilitiesPacket(new PlayerCapabilities(breath, selectKata, learnedKata));
    }

    public static void handle(PlayerCapabilitiesPacket packet, Supplier<NetworkEvent.Context> context) {
        context.get().enqueueWork(() -> {
            PlayerEntity player = context.get().getSender();
            PlayerCapabilities playerCapabilities = player.getCapability(PlayerCapabilities.CAPABILITY).orElse(new PlayerCapabilities(0,0,new int[0]));
            playerCapabilities.setBreath(packet.playerCapabilities.getBreath());
            playerCapabilities.setSelectKata(packet.playerCapabilities.getSelected());
            playerCapabilities.setLearnedKata(packet.playerCapabilities.getLearnedKata());
        });
        context.get().setPacketHandled(true);
    }

}
И PacketHandler
Java:
public class PacketHandler {
    public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
            new ResourceLocation(MOD_ID, "main"),
            () -> PROTOCOL_VERSION,
            PROTOCOL_VERSION::equals,
            PROTOCOL_VERSION::equals
    );

    public static <MSG> void register(int id, Class<MSG> type, BiConsumer<MSG, PacketBuffer> encoder, Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> handler) {
        INSTANCE.registerMessage(id, type, encoder, decoder, handler);
    }
    public static void sendTo(Object message, ServerPlayerEntity player) {
        INSTANCE.send(PacketDistributor.PLAYER.with(()->player), message);
    }


}
Не пойму насчет строчки
INSTANCE.send(PacketDistributor.PLAYER.with(()->player), message);
А и зарегал пакет капы

Java:
 private void setupCommon(final FMLCommonSetupEvent event){
     PacketHandler.register(0, PlayerCapabilitiesPacket.class, PlayerCapabilitiesPacket::encode, PlayerCapabilitiesPacket::decode, PlayerCapabilitiesPacket::handle);
    }
Просто я хз как отправить пакет на плеера
Если это правильная строчка то капа не работает
А если нет то как сендить на плеера?
 
30
3
2
а у тебя этот PlayerCapabilities сериализуется? в идеале отправь в пакете cap#serializeNBT и на клиенте с этим CompoundNBT вызови у клиентской капы deserializeNBT
Вроде этого?
Java:
public class NBTPacket {
private final CompoundNBT nbt;

    public NBTPacket(CompoundNBT nbt) {
this.nbt = nbt;
    }

public static void encode(NBTPacket packet, PacketBuffer buffer) {
buffer.writeInt(packet.nbt.getInt("breath"));
        buffer.writeInt(packet.nbt.getInt("selectKata"));
        buffer.writeVarInt(packet.nbt.getIntArray("learnedKata").length);
        for (int i : packet.nbt.getIntArray("learnedKata")) {
buffer.writeVarInt(i);
        }
    }

public static NBTPacket decode(PacketBuffer buffer) {
int breath = buffer.readInt();
        int selectKata = buffer.readInt();
        int[] learnedKata = new int[buffer.readVarInt()];
        for (int i = 0; i < learnedKata.length; i++) {
learnedKata[i] = buffer.readVarInt();
        }
CompoundNBT NBT = new CompoundNBT();
        NBT.putInt("breath",breath);
        NBT.putInt("selectKata", selectKata);
        ListNBT listNBT = new ListNBT();
        for (int i : learnedKata) {
listNBT.add(IntNBT.valueOf(i));
        }
NBT.put("learnedKata", listNBT);
        return new NBTPacket(NBT);
    }

public static void handle(NBTPacket packet, Supplier<NetworkEvent.Context> context) {
        context.get().enqueueWork(() -> {
PlayerEntity player = Minecraft.getInstance().player;
            PlayerCapabilities cap = player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities(0,0,new int[0]));
            cap.deserializeNBT(packet.nbt);
        });
        context.get().setPacketHandled(true);
    }

}
И код с отправкой на клиент

Java:
private static int setBreath(CommandSource source, int value) {
        if (!(source.getEntity() instanceof PlayerEntity)) {
            source.sendFailure(new TranslationTextComponent("commands.setbreath.error"));
            return 0;
        }
        ServerPlayerEntity player = (ServerPlayerEntity)source.getEntity();
        PlayerCapabilities cap = player.getCapability(PlayerCapabilities.CAPABILITY, null).orElse(new PlayerCapabilities(0,0,new int[0]));
        cap.setBreath(value);
        CompoundNBT nbt =  cap.serializeNBT();
        NBTPacket packet = new NBTPacket(nbt);

        PacketHandler.sendTo(packet,player);
        source.sendSuccess(new TranslationTextComponent("commands.setbreath.success", value), true);
        return 1;
    }
 
Последнее редактирование:
627
72
178
есть же метод player.getCapability, вызываешь его с параметром Capability<?> (твоя капа с аннотацией @CapabilityInject), и дальше действия делаешь либо через .ifPresent, либо сохраняешь капу в объект через .orElseThrow/.resolve().get() и перед действиями проверяешь её на не-null
 
Сверху