Рендер рюкзака в моде Backpack

Версия Minecraft
1.7.10
210
1
19
Давно пользуюсь этим модом, где-то когда-то нашёл на него исходники и наконец добрался до него. В принципе, всё, что можно было сделать-доделать-облизать-доработать - всё сделано и мне очень нравится результат, однако осталась одна неприятная деталь. Дело в том, что у меня рюкзак на спине видит только его хозяин, другие игроки не видят. И ощущение (но это не точно), что когда-то было иначе - то есть видели. Грешил на другие моды - пробовал их удалять, играл с настройками графики, в общем, ничего не помогает.
Я вообще с рендерами существ не дружу - максимум могу подменить текстуры в готовом. Но я уверен, что автор мода всё делал по уму и, значит, где-то затесался какой-то мелкий косяк.


Напоследок уже начал грешить на свой косой мод, и его удалил. На этом фото в клиенте (и на сервере) установлен ТОЛЬКО мод Backpack. Настройка renderBackpackModel внутри мода принудительно установлена мною на TRUE.

iffK87BRY9.png




Java:
        if(ConfigurationBackpack.RENDER_BACKPACK_MODEL) {
            EventHandlerClientOnly eventHandlerClient = new EventHandlerClientOnly();
            MinecraftForge.EVENT_BUS.register(eventHandlerClient);
            FMLCommonHandler.instance().bus().register(eventHandlerClient);
        }

Отрисовка идет в Pre эвенте (переделано - добавлены текстуры для всех цветов рюкзака).
Java:
    @SubscribeEvent
    public void render(Pre event) {
        EntityPlayer entityPlayer = event.entityPlayer;
        String UUID = entityPlayer.getUniqueID().toString();
        Backpack.packetHandler.networkWrapper.sendToServer(new MessagePersonalBackpack(UUID));
        if(backpackDamage.containsKey(UUID) && backpackDamage.get(UUID) != -1) {
            GL11.glPushMatrix();
            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
            bind(Constants.modelBackpackPure);
            int type = backpackDamage.get(UUID)%100;
            switch(type){
                case 0:{/*bind(Constants.modelBackpackPure); */break;}
                case 1:{bind(Constants.modelBackpackBlack); break;}
                case 2:{bind(Constants.modelBackpackRed); break;}
                case 3:{bind(Constants.modelBackpackGreen); break;}
                case 4:{bind(Constants.modelBackpackBrown); break;}
                case 5:{bind(Constants.modelBackpackBlue); break;}
                case 6:{bind(Constants.modelBackpackPurple); break;}
                case 7:{bind(Constants.modelBackpackCyan); break;}
                case 8:{bind(Constants.modelBackpackLightGray); break;}
                case 9:{bind(Constants.modelBackpackGray); break;}
                case 10:{bind(Constants.modelBackpackPink); break;}
                case 11:{bind(Constants.modelBackpackLime); break;}
                case 12:{bind(Constants.modelBackpackYellow); break;}
                case 13:{bind(Constants.modelBackpackLightBlue); break;}
                case 14:{bind(Constants.modelBackpackMagenta); break;}
                case 15:{bind(Constants.modelBackpackOrange); break;}
                case 16:{bind(Constants.modelBackpackWhite); break;}
                case 99:{bind(Constants.modelBackpackEnder); break;}
                case 17:{bind(Constants.modelBackpackWorkbench); break;}
                //default:{bind(Constants.modelBackpackPure);}
            }
           
            Constants.model.render(entityPlayer, 0F, 0F, 0F, 0F, 0F, 0.0625F);

            GL11.glPopMatrix();
        }
    }



Куда копать? Какой кусок кода привести здесь для рассмотрения?
 
210
1
19
Последнее редактирование:
167
10
69
Смотри PlayerUpdateEquipShoulders это на примере наплечников, у тимахи вродебы тоже такое есть в его кастомном инвентаре.
 
33
3
6
PlayerUpdateEquipShoulders
Обновляется каждую секунду.
Как пример, стоит брать код тимахи.
Java:
@SubscribeEvent
    public void updatePlayer(LivingUpdateEvent event) {
        if (event.entityLiving instanceof EntityPlayer) {
            EntityPlayer player = (EntityPlayer)event.entityLiving;
            //if (player.worldObj.isRemote) return;
            int i = 0;
            ItemStack slot;

            RpgEntityIEEP ieep = RpgEntityIEEP.get(player);
            if (ieep != null) {
                for (i = 0; i < ieep.getInventory().getSizeInventory(); ++i) {
                    slot = ieep.getInventory().getStackInSlot(i);
                    
                    if (slot != null && slot.getItem() instanceof IItemEquipment)
                        ((IItemEquipment)slot.getItem()).onUpdateItemEquipment(player, slot);

                    if (ieep.oldItemEquipment[i] != slot) {

                        checkItemEquipment(player, ieep.oldItemEquipment[i], slot, i);
                        ieep.oldItemEquipment[i] = slot;
                    }
                }
            }

            for (i = 0; i < player.inventory.armorInventory.length; ++i) {
                slot = player.inventory.armorInventory[i];
                if (ieep.oldItemArmor[i] != slot) {
                    checkItemArmor(player, ieep.oldItemArmor[i], slot, i);
                    ieep.oldItemArmor[i] = slot;
                }
            }

        }
    }

    private static void checkItemEquipment(EntityPlayer player, ItemStack old, ItemStack current, int slotID) {
        if (player.worldObj.isRemote) return;

        /*if (old == null && current != null) System.out.println("put on " + current.getDisplayName());
        if (old != null && current == null) System.out.println("took off " + old.getDisplayName());
        if (old != null && current != null && old != current)
            System.out.println("changed " + old.getDisplayName() + " on " + current.getDisplayName());*/

        SyncItemEquipmentMessage message = new SyncItemEquipmentMessage();
        message.entityID = player.getEntityId();
        message.slotID = (byte)slotID;
        message.item = current;
        //RpgInventoryMod.network.sendToDimension(message, player.dimension);
        RpgInventoryMod.network.sendToAllAround(message, new NetworkRegistry.TargetPoint(
                player.dimension, player.posX, player.posY, player.posZ, 256));
        //EntityTracker.trackedEntityIDs.get(player.getEntityId()).@[email protected] / 2
    }
 
210
1
19
Короче, я полностью переделал систему. Теперь сервер каждые пять секунд проверяет, у кого из онлайн-игроков есть рюкзаки. И потом всё это складывает в пакет и рассылает его всем игрокам. Если в следующую проверку ничего не поменялось - пакет не отсылает. В итоге пакеты уходят только когда игроки приходят, когда уходят и когда снимают/одевают рюкзаки. По мне так суперэкономно получилось.

Одно фигово. Результата я так и не достиг. Каждый игрок видит свой рюкзак (когда F5), но не видит чужих. Хотя в логе я вижу, как выглядит пакет и вижу, что он отсылается игрокам. На стороне клиента я пакет разбираю на составляющие и помещаю в мап. В общем, уже систему отработал, с пакетами разобрался, в другом алгоритме (не касающемся рендеров) эта же система работает чётко.

Возникает ощущение, что мод обрабатывает только рендер игрока-себя, но не обрабатывает рендер игроков-других. Может так быть?

Вот мои классы:

Java:
    public static Map<String, Integer> playersBackpacks;

    @SubscribeEvent
    public void render(Pre event) {
        String nick = event.entityPlayer.getDisplayName();
  
        if(playersBackpacks.containsKey(nick) && playersBackpacks.get(nick) > -1) {
            GL11.glPushMatrix();
            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
            bind(Constants.modelBackpackPure);
            int type = playersBackpacks.get(nick)%100;
            switch(type){
                case 0:{break;}
                case 1:{bind(Constants.modelBackpackBlack); break;}
                case 2:{bind(Constants.modelBackpackRed); break;}
                case 3:{bind(Constants.modelBackpackGreen); break;}
                case 4:{bind(Constants.modelBackpackBrown); break;}
                case 5:{bind(Constants.modelBackpackBlue); break;}
                case 6:{bind(Constants.modelBackpackPurple); break;}
                case 7:{bind(Constants.modelBackpackCyan); break;}
                case 8:{bind(Constants.modelBackpackLightGray); break;}
                case 9:{bind(Constants.modelBackpackGray); break;}
                case 10:{bind(Constants.modelBackpackPink); break;}
                case 11:{bind(Constants.modelBackpackLime); break;}
                case 12:{bind(Constants.modelBackpackYellow); break;}
                case 13:{bind(Constants.modelBackpackLightBlue); break;}
                case 14:{bind(Constants.modelBackpackMagenta); break;}
                case 15:{bind(Constants.modelBackpackOrange); break;}
                case 16:{bind(Constants.modelBackpackWhite); break;}
                case 99:{bind(Constants.modelBackpackEnder); break;}
                case 17:{bind(Constants.modelBackpackWorkbench); break;}
                default:{break;}
            }      
            Constants.model.render(event.entityPlayer, 0F, 0F, 0F, 0F, 0F, 0.0625F);
            GL11.glPopMatrix();
        }
    }

Java:
public class EventHandlerBackpack {
    public static long bpTicks, bpUpdateTime;
    public static int bpUpdateInterval = 5;
    public static String backpackslast;

    @SubscribeEvent
    public void onServerTick(ServerTickEvent e) {
        if(e.phase.equals(Phase.END) && e.side == Side.SERVER){
            long current = System.currentTimeMillis();
            long delta;
            delta = current - bpUpdateTime;
            if(delta <= bpUpdateInterval * 1000){bpTicks++;} else {
                List<EntityPlayerMP> players = MinecraftServer.getServer().getConfigurationManager().playerEntityList;
                if(players.size() > 0){
                    String message = "";
                    for(EntityPlayerMP p:players){
                        ItemStack backpack = new PlayerSave(p.getUniqueID().toString()).getPersonalBackpack();
                        int backpackid = -1;
                        if(backpack != null){backpackid = backpack.getItemDamage();}
                        String playerline = p.getDisplayName() +  "::" + backpackid + ":::";
                        message += playerline;
                    }
                    message = message.substring(0, message.length() - 3);
                    if(!message.equalsIgnoreCase(backpackslast)){
                        MessageBackpacksList backpacks = new MessageBackpacksList(message);
                        for(EntityPlayerMP p:players){
                            Backpack.packetHandler.networkWrapper.sendTo(backpacks, p);
                        }
                        backpackslast = message;
                    }
                }
                bpUpdateTime = System.currentTimeMillis();
                bpTicks = 0L;
            }
        }
    }

Java:
public class MessageBackpacksList implements IMessage, IMessageHandler<MessageBackpacksList, IMessage> {
    protected String packet;

    public MessageBackpacksList() {}

    public MessageBackpacksList(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(MessageBackpacksList message, MessageContext ctx) {
        if(ctx.side == Side.CLIENT) {
            String[] backpacks = message.packet.split(":::");
            EventHandlerClientOnly.playersBackpacks = new HashMap<String, Integer>(); // обнуляем старый список рюкзаков
            for(String backpack:backpacks){
                String[] split = backpack.split("::");
                EventHandlerClientOnly.playersBackpacks.put(split[0], Integer.valueOf(split[1]));
            }
        }
        return null;
    }
}


Да, и ещё - может, это имеет значение: Я нашёл очень старые скриншоты свои, где-то 2015 года, на версии 1.7.2, там рюкзаки были видны у "соседей". Я нашёл мод для версии 1.7.2, декомпилировал его - не увидел разницы (хотя построчно не сверял). Может, то, что работало под 1.7.2, не работает под 1.7.10?
 
Последнее редактирование:
210
1
19
В дебаге метод render вызывается для других игроков?

А это где? (я не очень умный, да)

Update: Ну если сами игроки отрисовываются, разве render не вызывается? Я просто не разбираюсь в этом.
 
Последнее редактирование:
7,099
324
1,510
Нужно в режиме отладки проверить доходит ли выполнение до Constants.model.render
 
210
1
19
Нужно в режиме отладки проверить
Дело в том, что этот мод дурацкий не запускается без компиляции - там какая-то ссылка на мод NEI - это затрудняет его отладку. Думаю вот, почистить нафиг... или вообще объединить мод со своим собственным.:LOL:
Как отладить с компиляцией?
 
129
6
18
Ваш вопрос решается через IExtendedEntityProperties. Судя по коду скорее всего это класс PlayerSave.
Далее через событие RenderPlayerEvent.Specials.Post можно получать PlayerSave и рендерить ваш backpack на клиенте. Без использования пакетов и события ServerTickEvent. По крайней мере так я раньше рендерил рюкзаки.

Вот небольшой кусок кода из мода:
Java:
@SubscribeEvent
    public void onPlayerRenderTick(RenderPlayerEvent.Specials.Post event) {

        if (event.entityPlayer != null) {
            EntityPlayer player = event.entityPlayer;

           
            if (ExtendedPlayer.get(player).inventory.getStackInSlot(0) != null) {//проверяем наличие брони в слоте
                (new RenderBackpack()).render(player, event.renderer);//метод рендера вашей брони
            }
        }
    }
В вашем случае надо проверять вывод из этой функции: new PlayerSave(p.getUniqueID().toString()).getPersonalBackpack()

Вы правильно подключили библиотеку? У меня в idea библиотека должна лежать в папке mods и также отдельно лежать копия в папке libs, ктр в свою очередь надо подключить к самой idea. А также библиотека должна быть пропущена через BON в обоих случаях.

Надеюсь помог:)
 
210
1
19
Вопрос решён. После нескольких часов ковыряний всё оказалось одновременно и просто, и мудрёно. Поделюсь для тех, кто (мало ли) столкнётся.

У меня стоит плагин ColorMe. Да, я удалял все моды подчистую, но совершенно забыл о плагинах. Так вот... Нет, я не додумался и не удалил все плагины, чтобы выяснить это. Я выявлял причину с конца, как если бы гинеколог ставил через своё рабочее место пломбу в зуб мудрости (во рту, конечно). И код упорно твердил мне, что ник игрока, скажем "Petya" не равен "Petya" никакими судьбами. Чуть голову не сломал. Этот самый плагин в начале ника игрока подставляет два символа - "§" и код цвета. И их нигде не видно при "отладке", я увидел их, только когда додумался измерить длину ника, которая внезапно для меня оказалась на два символа длиннее. Сие явление работает только в мультиплере (ведь только там есть плагин), и только тогда, когда идёт отрисовка других игроков, но не самого себя - тут с ником всё в порядке. В итоге свой рюкзак мы видим, а чужие - нет.
Возможные решения:
1) Удалить этот плагин - это проще и надёжнее всего.
2)
bla-bla:
if(event.entityPlayer instanceof EntityOtherPlayerMP)nick= nick.substring(2, nick.length());
- этот метод выбрал я, потому что плагин мне нравится. И - да - в таком случае по той же причине проблема появляется, если зайти к игроку после нажатия кнопки "Открыть по сети" - ведь там плагина нет. Но это уже неважно.

Спасибо всем, кто пытался помочь.

P.S. Держите прикол напоследок:
unknown.png
P.P.S. Зато теперь я знаю о существовании EntityOtherPlayerMP.
 
Последнее редактирование:
Сверху