Работа с пакетами

Версия Minecraft
1.12.2
170
2
53
Делаю мод на костюмы и столкнулся с такой проблемой, в мультиплеере игроки не видят костюмы других игроков. Костюм храниться в отдельном инвентаре, в собственной ячейке. Как я понял, нужно запросить у сервера предмет с этой ячейки у игрока, но я совершенно не понимаю как это сделать. Подскажите, как реализовать?

Код:
public class MainHandRenderHandler
{

    private static class CachedInventory
    {

        NonNullList<ItemStack> stacks;
        int state;

        CachedInventory(int size)
        {
            stacks = NonNullList.withSize(size, ItemStack.EMPTY);
            state = 0;
        }

    }

    public static boolean HideCosArmor = false;

    private static final boolean isBaublesLoaded = Loader.isModLoaded("baubles");

    private final LoadingCache<EntityPlayer, CachedInventory> cache = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build(new CacheLoader<EntityPlayer, CachedInventory>()
    {

        @Override
        public CachedInventory load(EntityPlayer owner) throws Exception
        {
            return new CachedInventory(owner.inventory.mainInventory.size());
        }

    });

    @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true)
    public void handleCanceledEvent(RenderPlayerEvent.Pre event)
    {
        if (!event.isCanceled())
            return;

        CachedInventory cachedInv = cache.getUnchecked(event.getEntityPlayer());
        NonNullList<ItemStack> cachedArmor = cachedInv.stacks;
        NonNullList<ItemStack> armor = event.getEntityPlayer().inventory.mainInventory;

        if (armor.size() > cachedArmor.size())
        {
            cache.invalidate(event.getEntityPlayer());
            return;
        }

        if (cachedInv.state != 0)
        {
            for (int i = 0; i < armor.size(); i++)
                armor.set(i, cachedArmor.get(i));

            if (isBaublesLoaded)
            {
                try
                {
                    IBaublesItemHandler bh = BaublesApi.getBaublesHandler(event.getEntityPlayer());
                    boolean block = bh.isEventBlocked();
                    bh.setEventBlock(true);
                    for (int i = 0; i < bh.getSlots(); i++)
                        bh.setStackInSlot(i, cachedArmor.get(9 + i));
                    bh.setEventBlock(block);
                }
                catch (Throwable ignored)
                {
                }
            }

            cachedInv.state = 0;
        }
    }

    @SubscribeEvent(priority = EventPriority.HIGH)
    public void handleEvent(RenderPlayerEvent.Post event)
    {
        CachedInventory cachedInv = cache.getUnchecked(event.getEntityPlayer());
        NonNullList<ItemStack> cachedArmor = cachedInv.stacks;
        NonNullList<ItemStack> armor = event.getEntityPlayer().inventory.mainInventory;

        if (armor.size() > cachedArmor.size())
        {
            cache.invalidate(event.getEntityPlayer());
            return;
        }

        if (cachedInv.state != 0)
        {
            for (int i = 0; i < armor.size(); i++)
                armor.set(i, cachedArmor.get(i));

            if (isBaublesLoaded)
            {
                try
                {
                    IBaublesItemHandler bh = BaublesApi.getBaublesHandler(event.getEntityPlayer());
                    boolean block = bh.isEventBlocked();
                    bh.setEventBlock(true);
                    for (int i = 0; i < bh.getSlots(); i++)
                        bh.setStackInSlot(i, cachedArmor.get(9 + i));
                    bh.setEventBlock(block);
                }
                catch (Throwable ignored)
                {
                }
            }

            cachedInv.state = 0;
        }
    }

    @SubscribeEvent(priority = EventPriority.HIGH, receiveCanceled = true)
    public void handleEvent(RenderPlayerEvent.Pre event)
    {
        CachedInventory cachedInv = cache.getUnchecked(event.getEntityPlayer());
        NonNullList<ItemStack> cachedArmor = cachedInv.stacks;
        EntityPlayer player = event.getEntityPlayer(); // ВОТ ТУТ ВОТ Я БЕРУ ИГРОКА И ПОЛУЧАЮ ЕГО ИНВЕНТАРЬ
        ICAPCustomInventory cap = player.getCapability(CAPCustomInventoryProvider.INVENTORY_CAP, null);
        CustomInventory cosArmor = cap.getInventory();
        NonNullList<ItemStack> armor = event.getEntityPlayer().inventory.mainInventory;

        if (armor.size() > cachedArmor.size())
        {
            cache.invalidate(event.getEntityPlayer());
            return;
        }

        if (cachedInv.state != 0)
        {
            for (int i = 0; i < armor.size(); i++)
                armor.set(i, cachedArmor.get(i));

            if (isBaublesLoaded)
            {
                try
                {
                    IBaublesItemHandler bh = BaublesApi.getBaublesHandler(event.getEntityPlayer());
                    boolean block = bh.isEventBlocked();
                    bh.setEventBlock(true);
                    for (int i = 0; i < bh.getSlots(); i++)
                        bh.setStackInSlot(i, cachedArmor.get(9 + i));
                    bh.setEventBlock(block);
                }
                catch (Throwable ignored)
                {
                }
            }

            cachedInv.state = 0;
        }

        for (int i = 0; i < armor.size(); i++)
            cachedArmor.set(i, armor.get(i));

        cachedInv.state = 1;

        if (HideCosArmor)
            return;

        for (int i = 0; i < armor.size(); i++)
        {
            if (i < 9)
            {
                if (!cosArmor.getStackInSlot(7).isEmpty()) {
                    armor.set(player.inventory.currentItem, cosArmor.getStackInSlot(7)); //тут указываю предмет который нужно рендерить.
                }
            }
        }

        if (isBaublesLoaded)
        {
            try
            {
                IBaublesItemHandler bh = BaublesApi.getBaublesHandler(event.getEntityPlayer());
                boolean block = bh.isEventBlocked();
                bh.setEventBlock(true);
                for (int i = 0; i < bh.getSlots(); i++)
                {
                    if (!cosArmor.getStackInSlot(7).isEmpty()) {
                        bh.setStackInSlot(player.inventory.currentItem, cosArmor.getStackInSlot(i));
                    }
                    else
                        bh.setStackInSlot(player.inventory.currentItem, ItemStack.EMPTY);
                }
                bh.setEventBlock(block);
            }
            catch (Throwable ignored)
            {
            }
        }
    }

}
 
Решение
Тебе нужно сихронизовать свой инвентарь с инвентарём на клиенте, и затем уже через капу получить свой предмет для рендера. А судя по коду, ты пытаешься достать из клиентской капы(которая пустая обычно) предметы, вот никто и не видит кроме тебя самого(и то вряд ли). Что касается пакета, то тем было много(как регистрировать пакеты учить не буду). Тебе нужно передать в свой пакет класс(к примеру MyCustomInventory), затем в toBytes
Java:
buf.writeInt(myInv.slots.size());
for (ItemStack stack : myInv.slots) {
    ByteBufUtils.writeItemStack(buf, stack);
}
далее в fromBytes:
Java:
final int size = buf.readInt();
stacks = new ArrayList<>(size);

for (int i = 0; i < size; i++) {
    stacks.add(ByteBufUtils.readItemStack(buf));
}
И уже в методе...

Icosider

Kotliner
Администратор
3,603
99
664
Тебе нужно сихронизовать свой инвентарь с инвентарём на клиенте, и затем уже через капу получить свой предмет для рендера. А судя по коду, ты пытаешься достать из клиентской капы(которая пустая обычно) предметы, вот никто и не видит кроме тебя самого(и то вряд ли). Что касается пакета, то тем было много(как регистрировать пакеты учить не буду). Тебе нужно передать в свой пакет класс(к примеру MyCustomInventory), затем в toBytes
Java:
buf.writeInt(myInv.slots.size());
for (ItemStack stack : myInv.slots) {
    ByteBufUtils.writeItemStack(buf, stack);
}
далее в fromBytes:
Java:
final int size = buf.readInt();
stacks = new ArrayList<>(size);

for (int i = 0; i < size; i++) {
    stacks.add(ByteBufUtils.readItemStack(buf));
}
И уже в методе onMessage получить через аргумент message список stacks, получить через ctx.getServerHandler().playerEntity капу и положить все стаки(из листа stacks который ранее получили через аргумент message) в твою капу.
P.s. код чисто для примера, не стоит его себе брать и использовать как есть ибо помимо стаков, в некоторых инвентарях приходится указывать конкретные слоты(в baubles id слотов в инвентаре вроде в enum вынесены)
 
Последнее редактирование:
170
2
53
Тебе нужно сихронизовать свой инвентарь с инвентарём на клиенте, и затем уже через капу получить свой предмет для рендера. А судя по коду, ты пытаешься достать из клиентской капы(которая пустая обычно) предметы, вот никто и не видит кроме тебя самого(и то вряд ли). Что касается пакета, то тем было много(как регистрировать пакеты учить не буду). Тебе нужно передать в свой пакет класс(к примеру MyCustomInventory), затем в toBytes
Java:
buf.writeInt(myInv.slots.size());
for (ItemStack stack : myInv.slots) {
    ByteBufUtils.writeItemStack(buf, stack);
}
далее в fromBytes:
Java:
final int size = buf.readInt();
stacks = new ArrayList<>(size);

for (int i = 0; i < size; i++) {
    stacks.add(ByteBufUtils.readItemStack(buf));
}
И уже в методе onMessage получить через аргумент message список stacks, получить через ctx.getServerHandler().playerEntity капу и положить все стаки(из листа stacks который ранее получили через аргумент message) в твою капу.
P.s. код чисто для примера, не стоит его себе брать и использовать как есть ибо помимо стаков, в некоторых инвентарях приходится указывать конкретные слоты(в baubles id слотов в инвентаре вроде в enum вынесены)
как мне отправить пакет с сервера на клиент, в тот момент, когда клиент его запросит?
 
170
2
53
Сделал пакет
Код:
public class PacketPlayerCap implements IMessage {

    public int slot;
    public ItemStack item;
    
    public PacketPlayerCap() {}

    public PacketPlayerCap(ItemStack item, Integer slot) {
        this.slot = slot;
        this.item = item;
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        this.slot = buf.readInt();
        this.item = ByteBufUtils.readItemStack(buf);
        System.out.println("Достаю "+this.item+" в слот " + this.slot);
    }

    @Override
    public void toBytes(ByteBuf buf) {
        buf.writeInt(this.slot);
        ByteBufUtils.writeItemStack(buf, this.item);
        System.out.println("Пакую "+this.item+" в слот " + this.slot);
    }

    public static class Handler implements IMessageHandler<PacketPlayerCap, IMessage> {
        @Override
        public IMessage onMessage(PacketPlayerCap message, MessageContext ctx) {
            /*EntityPlayer player = ctx.getServerHandler().player;
            ICAPCustomInventory cap = player.getCapability(CAPCustomInventoryProvider.INVENTORY_CAP, null);
            CustomInventory inv = cap.getInventory();
            inv.setInventorySlotContents(message.slot, message.item);*/
            System.out.println("ПОЧЕМУ СЮДА НЕ ЗАХОДИТ?");
            return null;
        }
    }

}
При send to all со стороны сервера, клиент не получает public static class Handler implements IMessageHandler<PacketPlayerCap, IMessage>, почему?
 
3,005
192
592
@CKATEPTb Тебе же нужно доставлять клиенту информацию, значит пакет должен быть клиентским.
И ctx.getServerHandler().player; нужно брать из Minecraft.getMinecraft().player. (вроде)
 
3,005
192
592
170
2
53
Код:
public class PacketPlayerCap implements IMessage {

    public int slot;
    public ItemStack item;
    public UUID id;
    
    public PacketPlayerCap() {}

    public PacketPlayerCap(ItemStack item, Integer slot, UUID uuid) {
        this.slot = slot;
        this.item = item;
        this.id = uuid;
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        this.slot = buf.readInt();
        this.item = ByteBufUtils.readItemStack(buf);
        this.id = UUID.fromString(ByteBufUtils.readUTF8String(buf));
        System.out.println("Достаю "+this.item+" в слот " + this.slot);
    }

    @Override
    public void toBytes(ByteBuf buf) {
        buf.writeInt(this.slot);
        ByteBufUtils.writeItemStack(buf, this.item);
        ByteBufUtils.writeUTF8String(buf, this.id.toString());
        System.out.println("Пакую "+this.item+" в слот " + this.slot);
    }

    public static class Handler implements IMessageHandler<PacketPlayerCap, IMessage> {
        @Override
        public IMessage onMessage(PacketPlayerCap message, MessageContext ctx) {
            EntityPlayer player = null; // КАК ЗАСУНУТЬ СЮДА ИГРОКА? Можно ли не используя World?
            ICAPCustomInventory cap = player.getCapability(CAPCustomInventoryProvider.INVENTORY_CAP, null);
            CustomInventory inv = cap.getInventory();
            inv.setInventorySlotContents(message.slot, message.item);
            System.out.println("Ложу в капу "+message.item+" в слот "+message.slot);
            return null;
        }
    }

}
 
Сверху