Разделение сервер-клиент

Версия Minecraft
1.12.2

ReyMagos

Тег-бомбастер
412
7
121
У меня есть хэш мапа, которую я записываю в nbt:
Java:
    @Override
    public void writeEntityToNBT(NBTTagCompound compound) {
        super.writeEntityToNBT(compound);
        LogManager.getLogger().info("\u001B[32m Writting to NBT selected recipes: " + this.selectedRecipes.toString() + "\u001B[0m");
        NBTTagList selectedRecipesList = new NBTTagList();
        for (Map.Entry<String, Integer> entry: this.selectedRecipes.entrySet()) {
            NBTTagCompound tag = new NBTTagCompound();
            Integer recipe = entry.getValue();
            String name = entry.getKey();
            tag.setInteger(name, recipe);
            selectedRecipesList.appendTag(tag);
            LogManager.getLogger().info("\u001B[32m Wrote to NBT selected recipe (one) for player: " + name + ". Recipe: " + recipe.toString() + "\u001B[0m");
        }
        compound.setTag("selectedRecipes", selectedRecipesList);
    }
И соответственно читаю:
Java:
    @Override
    public void readEntityFromNBT(NBTTagCompound compound) {
        super.readEntityFromNBT(compound);
        LogManager.getLogger().info("\u001B[32m Reading from NBT selected recipes. Now the map is: " + this.selectedRecipes.toString() + "\u001B[0m");
        list = compound.getTagList("selectedRecipes", 10);
        for (int i = 0; i < list.tagCount(); i++) {
            NBTTagCompound tag = list.getCompoundTagAt(i);
            String name = Lists.newArrayList(tag.getKeySet()).get(0);
            Integer recipe = tag.getInteger(name);
            this.setSelectedRecipe(name, recipe);
            LogManager.getLogger().info("\u001B[32m Read from NBT selected recipe. Player is: " + name + ". Recipe is: " + recipe + "\u001B[0m");
        }
    }
В консоли выводится что-то такое:
[22:57:34] [Server thread/INFO] [redmod.entities.dwarf.EntityDwarf]: Reading from NBT selected recipes. Now the map is: {}
[22:57:34] [Server thread/INFO] [redmod.entities.dwarf.EntityDwarf]: Setting new selected recipe (entity): 0 for player: Player620 to map: {}
[22:57:34] [Server thread/INFO] [redmod.entities.dwarf.EntityDwarf]: After the setting (entity) map is: {Player620=0}
[22:57:34] [Server thread/INFO] [redmod.entities.dwarf.EntityDwarf]: Read from NBT selected recipe. Player is: Player620. Recipe is: 0
То есть инфа в мапу записана.
Но что-то не работает. При чтение nbt все данные записывает сервер. Но потом когда я её беру с клиента и изменяю:
Java:
public void setSelectedRecipe(String name, int recipe) {
        LogManager.getLogger().info("\u001B[32m Setting new selected recipe (entity): " + recipe + " for player: " + name + " to map: " + this.selectedRecipes.toString() + "\u001B[0m");
        this.selectedRecipes.put(name, recipe);
        LogManager.getLogger().info("\u001B[32m After the setting (entity) map is: " + this.selectedRecipes.toString() + "\u001B[0m");
}
Он мне выводит,
[22:57:40] [main/INFO] [redmod.entities.dwarf.EntityDwarf]: Setting new selected recipe (entity): 0 for player: Player347 to map: {}
[22:57:40] [main/INFO] [redmod.entities.dwarf.EntityDwarf]: After the setting (entity) map is: {Player347=0}
И куда девалась прошлая мапа я не знаю. Попробовал аннотацию SideOnly в setSelectedRecipe() - вылетает. Пробовал world.isRemote - Просто ничего не происходит. В общем нужна помощь.
 

tox1cozZ

aka Agravaine
8,456
598
2,893
Дак сохраняется энтити на серверной стороне всегда.
Если тебе нужно какие-то данные юзать на клиенте потом, то нужно синхронить.
У форджа для этого есть удобный IAdditionalSpawnData, расширяешь в своем мобе и синхронишь.
 

ReyMagos

Тег-бомбастер
412
7
121
То есть IAdditionalSpawnData - это замена nbt? Или как? Мне надо из gui достать мапу, которая находится в энтити. Я прописал в ентити вот это:
Java:
@Override
    public void writeSpawnData(ByteBuf buffer) {
        PacketBuffer packet = new PacketBuffer(buffer);
    }

    @Override
    public void readSpawnData(ByteBuf additionalData) {
        PacketBuffer packet = new PacketBuffer(additionalData);
    }
И то есть чтобы синхронить мне надо в write записать packet.writeInt(test), а в read test = packet.readInt() (допустим мне надо записать не мапу а какое-то число test)?
 
3,005
192
592
Не знаю, будет ли это костыльно и тд..
Но, если ты юзал пакеты, ты знаешь (по крайней мере должен знать), что в ByteBuf можно записать NBTTagCompound.
Как вариант, можно в ByteBuf из IASD запихивать твой nbt.
(На случай "дайте код")
Код:
    private NBTTagCompound tag;

    @Override
    public void readSpawnData(ByteBuf buf) {
        tag = ByteBufUtils.readTag(buf);
    }

    @Override
    public void writeSpawnData(ByteBuf buf) {
        ByteBufUtils.writeTag(buf, tag);
    }

Если будет ошибка с лимитом на 32к, то можешь сделать компрессию tag'а.
 
3,005
192
592
@will0376 Ну, тип это скорее всего будет ASM, а тут без него.
@Agravaine Не знаю, слал лишь только с клиента на сервер.
 

ReyMagos

Тег-бомбастер
412
7
121
Но из-за того что у меня много nbt compound'ов. я их записываю как-то так:
Java:
for (NBTTagCompound compound: this.selectedRecipesList) {
    ByteBufUtils.writeTag(buffer, compound);
}
А чтобы их забрать мне нужны индексы может быть, как в nbt (ключ - значение).
this.selectedRecipesList - это если что arraylist компоундов, в каждом из которых записана пара имя игрока -> номер рецепта.

если ты юзал пакеты
Пакеты не юзал.
 

ReyMagos

Тег-бомбастер
412
7
121
Я только что для проверки сделал простое gui которое отображает число, которое увеличивается на 1 с каждым нажатием на моба. Работает прекрасно и с IASD и без, за исключение того, что число увеличивается не на 1, а на 2, даже несмотря на !world.isRemote. Честно говоря этот тест меня запутал окончательно. Почему число берётся из гуи без всяких проблем, а hashMap нет. Почему?
P.S. И вопрос про индексы также не решился.
 

ReyMagos

Тег-бомбастер
412
7
121
Короче, я порылся в коде маяка и ком блока (это два блока у которых gui связано с их текстурой) и нашёл там отправку пакетов на клиент через mc.getConnection().sendPacket(*пакет*). Попытаюсь сделать так же. Если у кого-то есть мысли, советы - всегда рад!
 

ReyMagos

Тег-бомбастер
412
7
121
Я сейчас делаю простой пакет, в котором можно что-нибудь отправить. Я все данные конвертирую в байты и засовываю в ByteBuf. И мне нужен совет от знающих людей надо ли мне всё конвертировать или лучше пользоваться встроенными методами, такими как writeInt и т.д.?
P.S. возможно нужно было создать отдельный вопрос, но это всё ещё в этот огород камушек, так что не осуждайте.
 
3,005
192
592
А чтобы их забрать мне нужны индексы
Зачем тебе индексы?

Вроде вот так можно сделать:
Код:
ByteBuf buf = ...;
List<NBTTagCompound> someList = ...;

//Запись...
buf.writeInt(someList.size());
for (NBTTagCompound tag : someList) {
    ByteBufUtils.writeTag(buf, tag);
}

//Чтение

int size = buf.readInt();
for (int i = 0; i < size; i++) {
    someList.add(ByteBufUtils.readTag(buf));
}
 
3,005
192
592
@Rey838 Первым записал, первым прочитаешь, вроде так.
Либо первым записал, последним прочитаешь.

Так сложно потратить пару минут на проверку?
 
3,005
192
592
Челик хочет, что бы ему помогали, но он не хочет уделить свои пару минут на проверку, как будет работать.
Ему проще подождать, когда другие сделают..
 

ReyMagos

Тег-бомбастер
412
7
121
Ага... Не бумбум. Честно говоря занимаюсь фигнёй какой-то. Я посмотрел когда вызывается IASD и понял, что это не мой вариант (мне надо чтобы синхронизация вызывалась при взаимодействии). Позырил на маяк и ком блок, как я уже говорил. Увидел так отправку пакетов. Поискал туторы и теперь делаю вот этот симпл пакет:

Java:
public class SimplePacket implements IMessage {

    private Object toSend;

    public SimplePacket(Object object) {
        this.toSend = object;
    }

    @Override
    public void fromBytes(ByteBuf buffer) {
        String type = buffer.readBytes();
        if (type.equals("map")) toSend = readHashMap();
        else if (type.equals("lst")) toSend = readArrayList();
        else toSend = readBytes();
    }

    @Override
    public void toBytes(ByteBuf buffer) {
        if (toSend instanceof HashMap) writeHashMap((HashMap)toSend, buffer);
        if (toSend instanceof ArrayList) writeArrayList((ArrayList<Object>)toSend, buffer);
        if (toSend instanceof NBTTagCompound) writeNBT((NBTTagCompound)toSend, buffer);
        else writePrimitiveType(toSend, buffer);

    }

    private void writePrimitiveType(Object object, ByteBuf buffer) {
        String type = getType(object);
        buffer.writeBytes(type.getBytes());
        ArrayList<Byte> bytesList = convertToBytes(object, type);
        buffer.writeBytes(toByteArray(bytesList));
    }

    private void writeNBT(NBTTagCompound compound, ByteBuf buffer) {
        ByteBufUtils.writeTag(buffer, compound);
    }

    private void writeHashMap(HashMap map, ByteBuf buffer) {
        buffer.writeBytes("map".getBytes());
        Integer size = map.size();
        buffer.writeByte(size.byteValue());
        for (Map.Entry<Object, Object> entry: map.entrySet()) {
            Object key = entry.getKey();
            Object value = entry.getValue();
            buffer.writeBytes(toByteArray(convertToBytes(key, getType(key))));
            buffer.writeBytes(toByteArray(convertToBytes(value, getType(value))));
        }
    }

    private void writeArrayList(ArrayList<Object> list, ByteBuf buffer) {
        buffer.writeBytes("lst".getBytes());
        Integer size = list.size();
        buffer.writeByte(size.byteValue());
        if (list.get(0) instanceof NBTTagCompound) {

        }
        else {
            for (Object object: list) {
                buffer.writeBytes(toByteArray(convertToBytes(object, getType(object))));
            }
        }
    }

    private Object readBytes() {
        return null;
    }

    private HashMap<Object, Object> readHashMap() {
        return null;
    }

    private ArrayList<Object> readArrayList() {
        return null;
    }

    private ArrayList<Byte> convertToBytes(Object object, String type) {
        ArrayList<Byte> bytes = new ArrayList<>();
        switch (type) {
            case "int":  bytes.add(((Integer)object).byteValue());
            case "dbl": bytes.add(((Double)object).byteValue());
            case "flt": bytes.add(((Float)object).byteValue());
            case "str": {
                byte[] string = ((String)object).getBytes();
                for (byte i: string) {
                    bytes.add(i);
                }
            }
            case "bln": {
                byte i = (byte)((Boolean)object ? 1 : 0);
                bytes.add(i);
            }
        }
        return bytes;
    }

    private byte[] toByteArray(ArrayList<Byte> list) {
        byte[] bytes = new byte[list.size()];
        for (int i = 0; i < list.size(); i++) {
            bytes[i] = list.get(i);
        }
        return bytes;
    }

    private String getType(Object object) {
        if (object instanceof Integer) return "int";
        if (object instanceof Double) return "dbl";
        if (object instanceof Float) return "flt";
        if (object instanceof String) return "str";
        if (object instanceof Boolean) return "bln";
        if (object instanceof HashMap) return "map";
        if (object instanceof ArrayList) return "lst";
        if (object instanceof NBTTagCompound) return "nbt";
        return null;
    }
}
 
3,005
192
592
Если ты юзаешь нбт, то записывай сразу его, зачем его разбирать и собирать каждый раз ручками, Когда есть все за тебя?
 
7,099
324
1,510
Юзай CCL - кода получается мало, апи простой и понятный
[1.7-1.12]Пакетная система CodeChickenLib
Главное при работе с пакетами: в каком порядке записываешь значения - в том же и нужно читать
 
Сверху