Не могу отправить пакет с сервера на клиент

Версия Minecraft
1.7.10
1,159
38
544
Здравствуйте, у меня есть инвентарь с полем ArrayList<ItemStack> и мне нужно чтобы это поле синхронизировалось на клиенте и на сервере. Для этого я создал пакет, который хочу отослать пользователю, с которым нужно синхронизироваться.

Мой пакет:
Java:
package rsstats.common.network;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import rsstats.client.ClientProxy;

import java.util.ArrayList;

public class PacketUpdateParams implements IMessage {
    private ArrayList<ItemStack> skills;

    public PacketUpdateParams(ArrayList<ItemStack> skills) {
        this.skills = skills;
    }

    /**
     * Convert from the supplied buffer into your specific message type
     *
     * @param buf
     */
    @Override
    public void fromBytes(ByteBuf buf) {
        // Читаем размер списка
        int skillsSize = ByteBufUtils.readVarShort(buf);
        
        // Восстанавливаем список из ByteBuf
        skills = new ArrayList<ItemStack>(skillsSize);
        for (int i = 0; i < skills.size(); i++) {
            ItemStack itemStack = ItemStack.loadItemStackFromNBT(ByteBufUtils.readTag(buf));
            skills.set(i, itemStack);
        }

    }

    /**
     * Deconstruct your message into the supplied byte buffer
     *
     * @param buf
     */
    @Override
    public void toBytes(ByteBuf buf) {
        ByteBufUtils.writeVarShort(buf, skills.size()); // Записываем размер списка
        for (ItemStack skill : skills) { // и сам список
            NBTTagCompound NBTSkillItem = new NBTTagCompound();
            skill.writeToNBT(NBTSkillItem);
            ByteBufUtils.writeTag(buf, NBTSkillItem);
        }

    }

    /**
     * Обработчик сообщения {@link PacketOpenRSStatsInventory}
     */
    public static class MessageHandler implements IMessageHandler<PacketUpdateParams, IMessage> {
        @Override
        public IMessage onMessage(PacketUpdateParams message, MessageContext ctx) {
            ClientProxy.extendedPlayer.skillsInventory.setNewSkills(message.skills); // Устанавливаем пришедшие данные
            ClientProxy.extendedPlayer.updateParams(); // И делаем update - это чисто мое и не важно
            
            return null;
        }
    }
}

Регистрируем пакет в CommonProxy:
Java:
/**
 * Проки, содержащий код как для клиента, так и сервера
 * @author RareScrap
 */
public class CommonProxy implements IGuiHandler {
    
    // some code

    public void preInit(FMLPreInitializationEvent event) {
        // some code
        
        INSTANCE.registerMessage(PacketUpdateParams.MessageHandler.class, PacketUpdateParams.class, 4, Side.CLIENT);
        
        // some code
    }

    // some code
}

Вот так я отправляю пакет на клиент из инвентаря:
Java:
// StatsInventory - реализует IInventory
public class SkillsInventory extends StatsInventory {
    
    // some code
    
    /** Структура, хранящая все предметы инвентаря в стаках */
    private ArrayList<ItemStack> skills = new ArrayList<ItemStack>();
    /** Игрок, к которому привязан инвентарь */
    private EntityPlayer entityPlayer;
 
    /**
     * Необходимый публичный контсруктор
     */
    public SkillsInventory(EntityPlayer entityPlayer) {
        super(entityPlayer);
        this.entityPlayer = entityPlayer;
    }
    
    // SomeCode
    
    @Override
    public void setInventorySlotContents(int slotIndex, ItemStack itemStack) {
        
        // some code

        CommonProxy.INSTANCE.sendTo(new PacketUpdateParams(skills), (EntityPlayerMP) entityPlayer);

        // some code
    }
    
     // some code
}


Когда код выполяем - я получаю краш:
java.lang.ClassCastException: net.minecraft.client.entity.EntityClientPlayerMP cannot be cast to net.minecraft.entity.player.EntityPlayerMP
at rsstats.inventory.SkillsInventory.setInventorySlotContents(SkillsInventory.java:85)
at net.minecraft.inventory.Slot.putStack(Slot.java:104)
at net.minecraft.inventory.Container.putStacksInSlots(Container.java:558)
at net.minecraft.client.network.NetHandlerPlayClient.handleWindowItems(NetHandlerPlayClient.java:1202)
at net.minecraft.network.play.server.S30PacketWindowItems.processPacket(S30PacketWindowItems.java:70)
at net.minecraft.network.play.server.S30PacketWindowItems.processPacket(S30PacketWindowItems.java:78)
at net.minecraft.network.NetworkManager.processReceivedPackets(NetworkManager.java:241)
at net.minecraft.client.multiplayer.PlayerControllerMP.updateController(PlayerControllerMP.java:317)
at net.minecraft.client.Minecraft.runTick(Minecraft.java:1693)
at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1039)
at net.minecraft.client.Minecraft.run(Minecraft.java:962)
at net.minecraft.client.main.Main.main(Main.java:164)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
at net.minecraftforge.gradle.GradleStartCommon.launch(Unknown Source)
at GradleStart.main(Unknown Source)

Я не до конца понимаю почему каст не может соверщиться. Может быть отсюда нельзя отправлять пакеты или я пытаюсь отправить их с клиента на клиент? Подскажите пожалуйста, что я делаю не так и чего не понимаю.

Однако я решил пойти другим путем и отправлять пакет через небольшой костыль, дабы избежать приведения типов:

Java:
// StatsInventory - реализует IInventory
public class SkillsInventory extends StatsInventory {
    
    // some code
    
    /** Структура, хранящая все предметы инвентаря в стаках */
    private ArrayList<ItemStack> skills = new ArrayList<ItemStack>();
    /** Игрок, к которому привязан инвентарь */
    private EntityPlayer entityPlayer;
 
    /**
     * Необходимый публичный контсруктор
     */
    public SkillsInventory(EntityPlayer entityPlayer) {
        super(entityPlayer);
        this.entityPlayer = entityPlayer;
    }
    
    // SomeCode
    
    @Override
    public void setInventorySlotContents(int slotIndex, ItemStack itemStack) {
        
        // some code

        // ТЕПЕРЬ ПОПРОБУЕМ ВОТ ТАК
        CommonProxy.INSTANCE.sendToAllAround(new PacketUpdateParams(skills), new NetworkRegistry.TargetPoint(entityPlayer.dimension, entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ, 10));

        // some code
    }
    
     // some code
}

Это привел к крашу, но теперь Stacktrace становится вообще нечитабельным и не информативным (в нем нет ни единой ссылки на мой код. Исключение выбрасывается где-то внутри игры). Он настолько огромен, что я не могу его запостить на форум:
stacktrace - Pastebin.com

Уважаемые форумчане, что я делаю не так?
 

Icosider

Kotliner
Администратор
3,603
99
664
Начнём с того, что в ресурсы я выгрузил обновлённый урок по пакетам. В твоём случаи нужно сделать sendToServer и затем с серверной части отправить на клиент sendToAllAround, только мне не совсем ясно, чего ты собственно хочешь добиться.
 

Icosider

Kotliner
Администратор
3,603
99
664
На самом деле, я не совсем уверен, нужен ли тут вообще пакет. Эту синхронизацию может сделать контейнер.
Не нужен, он непонятно зачем отправляет всем вокруг пакеты.

Ванильные методы тайла юзай
getDescriptionPacket() и onDataPacket() (но это не точно)
У него может быть не тайл.

@talosdx, у тебя не проходит каст, потому что ты на клиенте отправляешь пакеты, оберни в !world.isRemote отправку пакета и каст будет проходить.
 
1,159
38
544
На самом деле, я не совсем уверен, нужен ли тут вообще пакет. Эту синхронизацию может сделать контейнер.
Да, я сам уже понял что пакет тут не нужен. Всем спасибо за помощь, тему пока заморожу до тех пор, пока не найду испточник проблемы
 
1,159
38
544
Окей, кажется я теперь более точно могу сформировать вопрос

Не нужен, он непонятно зачем отправляет всем вокруг пакеты.

Зачем я хочу отправлять пакет. Потому что player на клиенте не имеет актуальный ArrayList<ItemStack>. В SkillInventory у меня есть 2 хранилища ItemStack - ItemStack[] и ArrayList<ItemStack>. в первом хранятся только те стаки, которые будут отрисованы в слотах, а во втором - все стаки инвентаря. Таким макаром я хочу сделать вохможность отобразить сколь угодно стаков в ограниченном инвентаре.

loadNBT в моем IEEP вызывается только для player'а на сервере. Именно поэтому с момент захода пользователя в игру у него пустой Arraylist<ItemStack>. При помощи пакета, я хочу решить эту проблему: в момент открытия контейнера отсылать player'у на клиенте актуальный ArrayList<itemStack>.

Возможно, что я объяснил все совсем не понятно. Очень прошу вас связаться со мной в войсчате (контакты для связи в моем профиле). Мне будет проще объяснить что у меня там как устроено.
 

Icosider

Kotliner
Администратор
3,603
99
664
Окей, кажется я теперь более точно могу сформировать вопрос



Зачем я хочу отправлять пакет. Потому что player на клиенте не имеет актуальный ArrayList<ItemStack>. В SkillInventory у меня есть 2 хранилища ItemStack - ItemStack[] и ArrayList<ItemStack>. в первом хранятся только те стаки, которые будут отрисованы в слотах, а во втором - все стаки инвентаря. Таким макаром я хочу сделать вохможность отобразить сколь угодно стаков в ограниченном инвентаре.

loadNBT в моем IEEP вызывается только для player'а на сервере. Именно поэтому с момент захода пользователя в игру у него пустой Arraylist<ItemStack>. При помощи пакета, я хочу решить эту проблему: в момент открытия контейнера отсылать player'у на клиенте актуальный ArrayList<itemStack>.

Возможно, что я объяснил все совсем не понятно. Очень прошу вас связаться со мной в войсчате (контакты для связи в моем профиле). Мне будет проще объяснить что у меня там как устроено.
1. В войсе не общаюсь, так как говорить не умею.
2. Чёт у тебя стрёмная запись в пакете. Вот как это сделано у меня:
Java:
public final class CPacketSyncShopItems extends AbstractPacket
{
    public CPacketSyncShopItems(){}
    public CPacketSyncShopItems(List<ItemStack> stacks)
    {
        buf().writeInt(stacks.size());
        stacks.forEach(stack -> ByteBufUtils.writeItemStack(buf(), stack));
    }

    @Override
    public void client(EntityPlayer player)
    {
        int count = buf().readInt();
        List<ItemStack> stacks = new ArrayList<>(count);

        for (int i = 0; i < count; i++)
        {
            stacks.add(ByteBufUtils.readItemStack(buf()));
        }

        PlayerProvider.get(player).stacks = stacks;
    }
}
Как видно из кода у меня используется ByteBufUtils для записи и чтения стака, а у тебя какой то бред.

И ещё, стаки передадутся вместе с нбт, так что нет необходимости передавать НБТ.
 
Последнее редактирование:

CumingSoon

Местный стендапер
1,634
12
269
1. В войсе не общаюсь, так как говорить не умею.
2. Чёт у тебя стрёмная запись в пакете. Вот как это сделано у меня:
Java:
public final class CPacketSyncShopItems extends AbstractPacket
{
    public CPacketSyncShopItems(){}
    public CPacketSyncShopItems(List<ItemStack> stacks)
    {
        buf().writeInt(stacks.size());
        stacks.forEach(stack -> ByteBufUtils.writeItemStack(buf(), stack));
    }

    @Override
    public void client(EntityPlayer player)
    {
        List<ItemStack> stacks = new ArrayList<>();
        IntStream.range(0, buf().readInt()).forEach(i -> stacks.add(ByteBufUtils.readItemStack(buf())));

        PlayerProvider.get(player).stacks = stacks;
    }
}
Как видно из кода у меня используется ByteBufUtils для записи и чтения стака, а у тебя какой то бред.

И ещё, стаки передадутся вместе с нбт, так что нет необходимости передавать НБТ.
Тебе не кажется, что вставлять ФП куда попало может быть затратно? По-моему, обычный цикл лучше справится, чем итерация по stream'у из чисел (тут тебе и создание объектов, и боксинг-анбоксинг, и лямбда, которая по-особому выполняется) . Тем более, список сделал с дефолтным размером, хотя уже известен заранее конечный.
 

Icosider

Kotliner
Администратор
3,603
99
664
Тебе не кажется, что вставлять ФП куда попало может быть затратно? По-моему, обычный цикл лучше справится, чем итерация по stream'у из чисел (тут тебе и создание объектов, и боксинг-анбоксинг, и лямбда, которая по-особому выполняется) . Тем более, список сделал с дефолтным размером, хотя уже известен заранее конечный.
По поводу размера листа, учту. По поводу лябды: возможно обычный и справиться лучше, но тогда смысл использовать лябду? Для более жёстких задач чем простой проход по листу?

А и ещё, я никого не принуждаю использовать данный пакет ;)
 

CumingSoon

Местный стендапер
1,634
12
269
По поводу размера листа, учту. По поводу лябды: возможно обычный и справиться лучше, но тогда смысл использовать лябду? Для более жёстких задач чем простой проход по листу?
Для фильтрации данных, их конвертации и при переборе списков - ладно. Но IntStream.range(0, buf().readInt()).forEach будет медленнее, чем обычный цикл. И занимает больше. И зачем тогда? Обычный цикл не столь уж и много места в коде занимает
 

Icosider

Kotliner
Администратор
3,603
99
664
Для фильтрации данных, их конвертации и при переборе списков - ладно. Но IntStream.range(0, buf().readInt()).forEach будет медленнее, чем обычный цикл. И занимает больше. И зачем тогда? Обычный цикл не столь уж и много места в коде занимает
Пара тестов, вывод: да действительно, медленно работает, и причём даже заметно.
 
Сверху