Рендер модели игрока на сервере

Версия Minecraft
1.7.10
173
1
3
Приветствую.

Я хотел задать вопрос к этой теме, но она уже закрыта

Собственно, вопрос. Как кастомно рендерить модель только моего игрока?

На сервере подобное решение вызывает одинаковый рендер всех игроков сразу, а это не есть хорошо, сами понимаете...
 
173
1
3
Как-то странно...

У меня переменная tick, которая меняется и работает на клиенте нормально. Она объявляется в том же классе с эвентами. Отрисовка гуи по этой переменной идет нормальная, у каждого своя, но вот рендер модели кривой. Все игроки разом поднимают ручки...


Код:
@SubscribeEvent
   public void onRenderPlayer(RenderPlayerEvent.Pre event) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        if (tick > 0){
event.renderer.modelBipedMain.aimedBow = true;
}
 
173
1
3
Через ExtendedProp пробовал, там получается так, что для игрока все рендерится нормально (У него руки пучком, а у других нет), а для других игроков этого не видно...
Код:
@SubscribeEvent
public void onRenderPlayer(RenderPlayerEvent.Pre event) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {if (ExtendedPlayer.get(event.entityPlayer).getIsCasting())
           event.renderer.modelBipedMain.aimedBow = true;

IAttribute никогда не юзал... Есть где примеры?
 
2,505
81
397
Ну дак синхронизировать потому что нужно со всеми игроками, а не только с владельцем, как делают во всех "гуидах".


Примеры по IAttribute есть в EntityLivingBase


Если не разберешься, могу показать, как пользоваться.
 
173
1
3
Но как?


Чем больше я пытаюсь понять разделение сервера и клиента в майнкрафте, тем больше я в нем путаюсь.

Пакеты на сервер я отправляю, он вроде их синхронит даже, это в ExtendedPlayer
Код:
public void update(EntityPlayer player) {

       
        if(isCastingLast != isCasting)
        {
            if(player instanceof EntityPlayerMP)
                Main.network.sendTo(new MessageIsCasting(isCasting),(EntityPlayerMP)player);
            isCastingLast = isCasting;
        }


И мессадж: 
Код:
public class MessageIsCasting implements IMessage {
    private boolean isCasting;

    public MessageIsCasting() {
    }

    public MessageIsCasting(boolean isCasting ) {
        this.isCasting = isCasting ;
    }

    @Override
    public void toBytes(ByteBuf buf) {
        buf.writeBoolean(isCasting);
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        isCasting = buf.readBoolean();
    }

    public static class Handler implements IMessageHandler<MessageIsCasting, IMessage> {

        @Override
        public IMessage onMessage(MessageIsCasting packet, MessageContext message) {
            if (FMLCommonHandler.instance().getSide().isClient())
                setCasting(packet.isCasting);
            else
                setCasting(message.getServerHandler().playerEntity, packet.isCasting);
            return null;
        }

        @SideOnly(Side.CLIENT)
        private void setCasting(boolean isCasting) {
            Minecraft mc = Minecraft.getMinecraft();
            ExtendedPlayer extendedPlayer= ExtendedPlayer.get(mc.thePlayer);
            if (extendedPlayer!= null) {
                extendedPlayer.setIsCasting(isCasting);
            }
        }

        private void setCasting(EntityPlayerMP player, boolean isCasting) {
            ExtendedPlayer extendedPlayer = ExtendedPlayer.get(player);
            if (extendedPlayer != null) {
                extendedPlayer.setIsCasting(isCasting);
            }
        }
    }
}


Но... Я не понимаю как отправлять пакет каждому игроку информацию о другом плеере...
 
2,505
81
397
Что непонятного в разделении сервера и клиента? На каждой стороне свои значения переменных, которые нужно синхронизировать.

Где ты вызываешь свой update? В любом случае это лютый костыль.

Вот, что форж говорит от том, когда нужно синхронизировать переменные. Вроде, все должно быть понятно.
There are three different situation in which you may want to send synchronization packets, all of them optional:
  1. When the entity spawns in the world, or the block is placed, you may want to share the initialization-assigned values with the clients.
  2. When the stored data changes, you may want to notify some or all of the watching clients.
  3. When a new client starts viewing the entity or block, you may want to notify it of the existing data.

И синхронизируешь переменную ты только с владельцем, а не со всеми.


лалал.sendToAll(message);


Лучше забей на этот IExtendedEntityProperties и юзай IAttribute. Это намного легче. И очень подходит для единичной переменной.
Если найдется кто-нибудь умный, кто скажет, почему лучше не пользоваться IAttribute будет не плохо.
 
173
1
3
IAttribute же не надо синхронизировать?

Я вроде разобрался, запилил свою переменную, зарегал при входе в мир игрока. Она даже работает, рендер идет в прямой зависимости от этого атрибута, но другие игроки этого всё равно не видят :(

Регистрация: 
Код:
@SubscribeEvent
    public void addEntityConstructing(EntityEvent.EntityConstructing event) {
        if (event.entity != null && event.entity instanceof EntityPlayer) {

            EntityPlayer player = (EntityPlayer) event.entity;

            if(player.getAttributeMap().getAttributeInstance(isCasting) == null) {
                player.getAttributeMap().addAttributeInstance(new ModifiableAttributeInstance(player.getAttributeMap(), isCasting));
                player.getAttributeMap().registerAttribute(isCasting);
                player.getAttributeMap().getAttributeInstance(isCasting).setBaseValue(0.0d); //Разобрался поверхностно, поэтому заюзал систему через числа. 0 - false, 1 - true
            }


Рендер:
Код:
@SubscribeEvent
    public void onRenderPlayer(RenderPlayerEvent.Pre event) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        if (event.entityPlayer.getAttributeMap().getAttributeInstanceByName("isCasting").getAttributeValue() != 0) {
            event.renderer.modelBipedMain.aimedBow = true;
        }
}
 
2,505
81
397
Почти так, но нет.

Код:
// Создаешь, где угодно аттрибут.
// первого параметра (null) в 1.7.10, вроде, не было.
public static final IAttribute CAST_ATTR = new BaseAttribute(null, "is cast", 0)
{
    @Override
    public double clampValue(double value)
    {
        return value;
    }
}.setShouldWatch(true);

// регаешь его
@SubscribeEvent
public void onEntityConstructing(EntityConstructing e)
{
    if (e.getEntity() instanceof EntityPlayer) {
        ((EntityPlayer) e.getEntity()).getAttributeMap().registerAttribute(CAST_ATTR);
    }
}

// юзаешь
public void doWork(EntityPlayer player)
{
    player.getEntityAttribute(CAST_ATTR).getAttributeValue();
    player.getEntityAttribute(CAST_ATTR).setBaseValue(1);
}


"Разобрался поверхностно, поэтому заюзал систему через числа. 0 - false, 1 - true"
По-другому никак.


В 1.10.2, например, добавили еще DataParameter. Для твоей задачи это намного лучше, т.к. у IAttribute еще система модификаторов, которая тебе не нужна. (про нее я совсем забыл)
Код:
// параметр для текущего здоровья
private static final DataParameter<Float> HEALTH = EntityDataManager.<Float>createKey(EntityLivingBase.class, DataSerializers.FLOAT);
 
173
1
3
Все работает, спасибо большое.

Где ты вызываешь свой update? В любом случае это лютый костыль.


Последнее, ты можешь подсказать как лучше синхронизировать переменные в ExtendedProp если не так? А то у меня уже переменных 10 так синхронится и вроде не лагает...
 
2,505
81
397
There are three different situation in which you may want to send synchronization packets, all of them optional:
  1. When the entity spawns in the world, or the block is placed, you may want to share the initialization-assigned values with the clients.
  2. When the stored data changes, you may want to notify some or all of the watching clients.
  3. When a new client starts viewing the entity or block, you may want to notify it of the existing data.


    Если надо, я могу потом нормальный урок запилить по IExtendedEntityProperties для 1.7.10 и ICapability для 1.10.2. Хотя по первому уже миллион уроков.
 

Icosider

Kotliner
Администратор
3,603
99
664
Dahaka написал(а):
There are three different situation in which you may want to send synchronization packets, all of them optional:
  1. When the entity spawns in the world, or the block is placed, you may want to share the initialization-assigned values with the clients.
  2. When the stored data changes, you may want to notify some or all of the watching clients.
  3. When a new client starts viewing the entity or block, you may want to notify it of the existing data.



    [*]
    Если надо, я могу потом нормальный урок запилить по IExtendedEntityProperties для 1.7.10 и ICapability для 1.10.2. Хотя по первому уже миллион уроков.


  1. [*]

    Пили, и не мешало бы сделать туториал про пакеты(более развернутый, т.е. не только как заспавнить моба по нажатию на кнопку, а например как показать частицы от игрока всем по близости. Ну и т.п.).
 
173
1
3
Алярм! Up темы, проблем осталась :D
Не заметил сразу, но руки рендерятся не так...
Вот без брони



Вот с броней: 




А если нажать F1, то руки вообще не поднимаются. Что не так? На сервере игроки видят как друг у друга меняется положение рук, но с броней там такая же лажа
 
173
1
3
Так вроде и делаю...
Код:
@SubscribeEvent
    public void onRenderPlayer(RenderPlayerEvent.Pre event) {

        if (event.entityPlayer.getEntityAttribute(EventForge.isCasting).getBaseValue() == 1) {
            event.renderer.modelBipedMain.aimedBow = true;
    }

Имеет значение то, что я делаю это по зажатию кнопки? Хотя там вроде механизм не такой простой...
 
2,505
81
397
Ну скорее всего, ты просто руки поднимаешь только у основой модели. А у одетой брони, возможно, нужно отдельно поднимать. Точно не знаю. Нужно дебажить.

Совет. 1 == true - плохо. Что, если число будет 1.000001? Лучше сделай < 0 == false, >= 0 true.
 
210
1
19
Эта проблема присутствует в 1.7.10 версии в рендере скелета: руки подняты с луком или мечом, а броня - нет. Позже её исправили. Я хотел исправить у себя, пытался сравнить ресурсы 1.7 и 1.9, но ничего там не понял.

SAVhyiI0aH.png


xxh2atQxZB.png


BoL38Xajh9.png


Можно ли это исправить? Если да, то как?
 
173
1
3
Решил свою проблему вот так: 
Код:
@SubscribeEvent
    public void onRenderPlayer(RenderPlayerEvent.Pre event) {

        if (event.entityPlayer.getEntityAttribute(EventForge.isCasting).getBaseValue() == 1) {
            event.renderer.modelBipedMain.aimedBow = true;
            event.renderer.modelArmorChestplate.aimedBow = true;
        }
    }

Вроде все нормально работает. Не знаю как поступить со скелетами, не работал еще с рендером мобов...
 
Сверху