Синхронизировать компаунд getEntityData() между клиентским и серверным EntityPlayer.

Версия Minecraft
1.7.10
210
1
19
На сервере я вписываю свои данные в игрока так: entityplayermp.getEntityData().setInteger("someparameter", 100500);
В клиентском коде я вызываю mc.thePlayer.getEntityData() с целью получить данные и вывести на экран в игре, но он выводит "{}".
Методом проб и ошибок я уже понял, что они не взаимосвязаны - каждый из них может быть пустым или с данными, не отображаясь на второго. И у меня простой вопрос - как мне в клиенте получить данные из entityplayermp.getEntityData()?
 
Решение
Подключил CodeChicken, посмотрел представленные выше листинги, не понял, как их применить к моей задаче.
Вот всё, что я сделал за последние полчаса:
В целом нужно сделать следующие вещи:
Два класса, реализующих обработчики пакетов(IServerPacketHandler, IClientPacketHandler)
Зарегать их экземпляры на modid (PacketCustom.assignHandler), в клиентском и общем прокси
Там где нужно отправлять пакет с сервера на клиент написать че-то вроде
new PacketCustom("<modid>", <packet id, 1 and above>).writeItemStack(<stack>).sendToPlayer(<player>)
В реализации IClientPacketHandler добавить кейс для отправляемого <packet id>, прочитать стак readItemStack() и сделать какой-то эффект с этим стаком

В общем-то это все подробно описано в...
7,099
324
1,509
Подключил CodeChicken, посмотрел представленные выше листинги, не понял, как их применить к моей задаче.
Вот всё, что я сделал за последние полчаса:
В целом нужно сделать следующие вещи:
Два класса, реализующих обработчики пакетов(IServerPacketHandler, IClientPacketHandler)
Зарегать их экземпляры на modid (PacketCustom.assignHandler), в клиентском и общем прокси
Там где нужно отправлять пакет с сервера на клиент написать че-то вроде
new PacketCustom("<modid>", <packet id, 1 and above>).writeItemStack(<stack>).sendToPlayer(<player>)
В реализации IClientPacketHandler добавить кейс для отправляемого <packet id>, прочитать стак readItemStack() и сделать какой-то эффект с этим стаком

В общем-то это все подробно описано в туторе, просто нужно внимательно прочитать
 

Eifel

Модератор
1,623
78
608
Сорямба, не заметил, что там сделано не так ибо бегло прочел. Если для тебя пакеты это новая тема, то попробуй остынуть и внимательно прочесть тутор/разобраться, как уже посоветовал @hohserg1 . Это наилучшее решение
 
210
1
19
@hohserg1

Java:
            delta = current - testSectionTime;
            if(delta <= testInterval * 1000){testTicks++;} else {
             
                List <EntityPlayerMP> players = MinecraftServer.getServer().getConfigurationManager().playerEntityList;
                if(Cons.existBackpacksMod){
                    for(EntityPlayerMP player:players){                 
                        Object obj = null;
                        try {
                            Class clas = Class.forName("de.eydamos.backpack.saves.PlayerSave");
                            if(clas != null) {
                               Constructor constructor = clas.getConstructor(new Class[]{EntityPlayer.class});
                               Object playerSave = constructor.newInstance(new Object[]{player});
                               Method getPersonalBackpackMethod = playerSave.getClass().getDeclaredMethod("getPersonalBackpack", new Class[0]);
                               Method setPersonalBackpackMethod = playerSave.getClass().getDeclaredMethod("setPersonalBackpack", new Class[]{ItemStack.class});
                               if(getPersonalBackpackMethod != null && setPersonalBackpackMethod != null) {
                                  obj = getPersonalBackpackMethod.invoke(playerSave, new Object[0]);
                               }
                            }
                         } catch (Exception var8) { var8.printStackTrace(); }
                     
                        ItemStack item = null;
                        if(obj != null && obj instanceof ItemStack) { item = (ItemStack)obj; }
                     
                        PacketCustom packet = new PacketCustom(Main.MODID, 1).writeItemStack(item);
                        packet.sendToPlayer(player);
                    } 
                }
                testSectionTime = System.currentTimeMillis();
                testTicks = 0L;
            }

Ошибки все исчезли.
Правильно строчка (две - 24 и 25) составлена теперь?
Если предмет равен null, мне тоже нужно отсылать его, чтобы знать, что предмет отсутствует, данный метод же прокатит?

В common.preinit() я добавил строчку:
Java:
PacketCustom.assignHandler(Main.MODID, new ServerPacketHandler());
Update: И зря добавил, потому что для моей задачи это не имеет значения.

В client.preinit() я добавил строчку:
Java:
PacketCustom.assignHandler(Main.MODID, new ClientPacketHandler());


Всё верно?
 
Последнее редактирование:
210
1
19
В клиенте заработало. А вот сервер теперь не запускается.
IwtyTfSGcV.png


Update: Действительно, надо было дать серверу либу. :)

Хочу подытожить, что мне понадобилось:
1. Либа CodeChicken - подключить к проекту и добавить в папку модов на сервере. С её помощью послать пакет из нужного места.
2. Класс ClientPacketHandler - зарегистрировать его в client.preInit, в нём обработать пакет, как мне нужно (засетить итемстак).
3. (этот пункт уже лишний)

Итого - два файла и шесть строчек кода. Вот стоило оно целого вечера самостоятельных "героических" ковыряний?

В любом случае, большое спасибо тем, кто действительно пытался помочь.
 
Последнее редактирование:

will0376

Токсичная личность
2,059
55
573
Эм. если тебе надо передать стак - почему-бы не воспользоваться SimpleNetworkWrapper?(вроде бы он имеется на 1.7)
при помощи ByteBufUtils можно записать стак(опять таки, я не знаю, есть ли он на 1.7)
IMessage бы тебе помог и без CCL
 
210
1
19
почему-бы не воспользоваться SimpleNetworkWrapper?
У меня он есть - в каком-то моде откопал - но я не понял, как им пользоваться. Исходя из задачи, можешь написать мне готовые строчки?
 

will0376

Токсичная личность
2,059
55
573
готовые строчки?
._.
регистрация сети src/main/java/ru/will0376/OpenBlocker/Main.java · master · Will0376 / OpenBlocker
72 строчка - регистрация пакета. CLIENT,SERVER - то, где пакет обрабатываться будет.
сам пакет. src/main/java/ru/will0376/OpenBlocker/common/Blocker.java · master · Will0376 / OpenBlocker
отпарвка пакета - <main class>.network.send<куда>(new <пакет>(<данные для пакета>),<игрок.(если используется sendTo и etc)>);
как пример:
Java:
public static void sendToPlayer(EntityPlayerMP p) {
        Main.network.sendTo(new Blocker(server.toString()), p);
    }
 
210
1
19
В общем, ничего ты не разжевал, но к счастью, я сам уже разжевал всё фактически до мякотки и теперь могу тут в качестве финального поста разжевать для других :

Итак, первое, что нам нужно - создать класс PacketHandler, который должен вызываться из CommonProxy. Лично у меня он выглядит так:
Java:
public class PacketHandler {
    public final SimpleNetworkWrapper networkWrapper = NetworkRegistry.INSTANCE.newSimpleChannel(Main.MODID);

    public void initialise() {
        // эти пакеты посылаются от клиента к серверу
        networkWrapper.registerMessage(MessageGPS.class, MessageGPS.class, 0, Side.SERVER); // передает серверу команду игрока из гуи GPS

        // эти пакеты посылаются от сервера к клиенту
        networkWrapper.registerMessage(MessageBackPack.class, MessageBackPack.class, 10, Side.CLIENT); // передаёт клиенту итемстак рюкзака
        networkWrapper.registerMessage(MessageLinks.class, MessageLinks.class, 11, Side.CLIENT); // передаёт клиенту ссылки для меню ссылок
        networkWrapper.registerMessage(MessageFishTournament.class, MessageFishTournament.class, 12, Side.CLIENT); // передаёт клиенту строку в виде "<FISHTIME>:::<LEADER>:::<COUNT>"
    }
}

Теперь в голове класса Main пишем так:
Java:
public static PacketHandler packetHandler = new PacketHandler();

Соответственно, вызов из CommonProxy (где-нибудь в preInit(FMLPreInitializationEvent e), неважно) будет выглядеть так:
Java:
Main.packetHandler.initialise();

В PacketHandler у меня упомянуто четыре разных класса - это классы пакетов. Можно сделать унифицированные по типу (что пересылаем), но чтобы не запутаться, лучше сделать отдельный класс на каждый случай.

Допустим, нам нужно переслать строку с сервера на клиент. В таком случае класс пакета будет выглядеть так:
Java:
public class MessageLinks implements IMessage, IMessageHandler<MessageLinks, IMessage> {
    protected String packet;
   
    public MessageLinks() {}
   
    public MessageLinks(String packet) {
        this.packet = packet;
    }

    @Override
    public void fromBytes(ByteBuf buffer) {
        packet = ByteBufUtils.readUTF8String(buffer);
    }

    @Override
    public void toBytes(ByteBuf buffer) {
        ByteBufUtils.writeUTF8String(buffer, packet);
    }

    @Override
    public IMessage onMessage(MessageLinks message, MessageContext ctx) {
        if(ctx.side == Side.CLIENT) { // на стороне клиента
         // здесь я обработал присланное сообщение, присвоив его значение переменной в классе на стороне клиента
        // вообще очень важное место, нельзя писать тут просто packet (будет null), но именно message.packet
            Hud.RHLinks = message.packet;
        }
// дальше можно вместо null сформировать обратный пакет и послать
// в ответ, но тогда нужно описать его отдельно в PacketHandler.initialize();
// тогда здесь будет примерно так:
// return new MessageLinks("строковая_фигня"));
        return null;
    }


Теперь остаётся послать со стороны сервера пакет вот так, например:
Main.packetHandler.networkWrapper.sendTo(new MessageLinks(currentRHLinks), player);


Вроде всё.
P.S. И - да - расковыряв эту тему, я отказался от CodeChicken, потому что так мне показалось удобнее.
 
Сверху