Создание моба и инвентаря

Версия Minecraft
1.7.10
317
10
Создал свое entity c inventory. Создал gui, container.
В самом entity буду хранить itemstack + player. (в коде пока что храню только player'а).
В Gui пытаюсь получить ник. Он всегда пустой почему то. Походу на клиенте + сервере разные EntityId;
NBT в Entity так-же почему то слетает.
Получаю на клиенте String ника player'а при помощи пакетов(код тоже ниже, реализовал с помощью EntityID + nickName). (в эвенте RenderWorldLastEvent работает т.е рендерит ник, а в GUI не работает)
Как реализовать?
Буду благодарен за помощь...
Вотс ниже все коды.

В XModDayZ.java:
public static HashMap<EntityPlayerKilled, String> map = new HashMap();


Spawn: 
Код:
EntityPlayerKilled player = new EntityPlayerKilled(event.player.worldObj);
if(!event.player.worldObj.isRemote) {
 player.setPlayer(event.player.getDisplayName());
 player.setLocationAndAngles(event.player.posX, event.player.posY+0.3f, event.player.posZ, 0, 10);
 event.player.worldObj.spawnEntityInWorld(player);
 XModDayZ.pipeline.sendToAll(new PacketUpdateInvKilled(event.player.getDisplayName(), player.getEntityId()));
 XModDayZ.getPlayerData(event.player).setBoolean("kill", true);
}



EntityPlayerKilled:
Код:
public class EntityPlayerKilled extends EntityMob implements IInvBasic {
public String player = "";
public EntityPlayerKilled(World w) {
    super(w);
    } 
    public void setPlayer(String player1) {
    this.player = player1;
    System.out.println("setPlayer: "+ player);
    if(!this.worldObj.isRemote) {
     XModDayZ.map.clear();
     XModDayZ.pipeline.sendToAll(new PacketUpdateInvKilled(getPlayer(), this.getEntityId()));
     if(!XModDayZ.map.containsKey(this)) {
 XModDayZ.map.put(this, this.player);
 System.out.println(this.getEntityId()+": "+XModDayZ.map.get(this));
}
    }
    }
    public String getPlayer() {
    return player;
    }
    
    public boolean interact(EntityPlayer player) { 
    if(!worldObj.isRemote) {
     XModDayZ.pipeline.sendToAll(new PacketUpdateInvKilled(getPlayer(), this.getEntityId()));
     if(!XModDayZ.map.containsKey(this)) {
 XModDayZ.map.put(this, this.player);
}
     player.openGui(XModDayZ.instance, 0, worldObj, 0, 0, 0);
    }
return true;
    }

    protected void updateEntityActionState() { }
    protected void updateLeashedState() {}
    
    public void writeEntityToNBT(NBTTagCompound nbt) {
    XModDayZ.pipeline.sendToAll(new PacketUpdateInvKilled(getPlayer(), this.getEntityId()));
if(!XModDayZ.map.containsKey(this)) {
XModDayZ.map.put(this, this.player);
System.out.println(this.getEntityId()+": "+XModDayZ.map.get(this));
}
nbt.setString("player", getPlayer());
    super.writeEntityToNBT(nbt);
    }
    public void readEntityFromNBT(NBTTagCompound nbt) {
    this.setPlayer(nbt.getString("player"));
    XModDayZ.pipeline.sendToAll(new PacketUpdateInvKilled(getPlayer(), this.getEntityId()));
    if(!XModDayZ.map.containsKey(this)) {
XModDayZ.map.put(this, this.player);
}
    super.readEntityFromNBT(nbt);
    }
@Override
public void onInventoryChanged(InventoryBasic inv) {}
}



GuiInventoryPlayerKill:
Код:
public class GuiInventoryPlayerKill extends GuiContainer {
EntityPlayerKilled entity;
public GuiInventoryPlayerKill(InventoryPlayer inventory, EntityPlayerKilled entity, Container c) {
super(c);
this.entity = entity;
}
@Override
protected void drawGuiContainerBackgroundLayer(float x,int y, int p_146976_3_) {
this.fontRendererObj.drawString("§f"+entity.getPlayer(), 10, 10, 0);
}
}



ContainerPlayerKill:
Код:
public class ContainerPlayerKill extends Container {
EntityPlayerKilled entity;
public ContainerPlayerKill(InventoryPlayer inventory, EntityPlayerKilled entity) {
this.entity = entity;
}
@Override
public boolean canInteractWith(EntityPlayer p_75145_1_) {
return true;
}
}


Handler:
Код:
public class Handler implements IGuiHandler {
@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
switch(ID) {
case 0: 
return new ContainerPlayerKill(player.inventory, new EntityPlayerKilled(world));
}
return null;
}
@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
switch(ID) {
case 0: 
return new GuiInventoryPlayerKill(player.inventory, new EntityPlayerKilled(world), new ContainerPlayerKill(player.inventory, new EntityPlayerKilled(world)));
}
return null;
}
}


Packet:
Код:
public class PacketUpdateInvKilled extends AbstractPacket {
String player;
int entityId;
public PacketUpdateInvKilled() {}
public PacketUpdateInvKilled(String player, int entityId) {this.player = player; this.entityId = entityId;}
@Override
public void encodeInto(ChannelHandlerContext var1, ByteBuf var2) {
ByteBufUtils.writeUTF8String(var2, player);
var2.writeInt(entityId);
}
@Override
public void decodeInto(ChannelHandlerContext var1, ByteBuf var2) {
player = ByteBufUtils.readUTF8String(var2);
entityId = var2.readInt();
}
@Override
public void handleClientSide(EntityPlayer var1) {
if(Minecraft.getMinecraft().theWorld.getEntityByID(entityId) instanceof EntityPlayerKilled) {
EntityPlayerKilled entity = (EntityPlayerKilled) Minecraft.getMinecraft().theWorld.getEntityByID(entityId);
entity.setPlayer(this.player);
if(!XModDayZ.map.containsKey(entity)) {
 XModDayZ.map.put(entity, this.player);
}
}
}
@Override
public void handleServerSide(EntityPlayer player) {}
}



Эвент PlayerEvent.PlayerLoggedInEvent:
Код:
if(!event.player.worldObj.isRemote) {
//XModDayZ.map.clear();
List playerList = event.player.worldObj.loadedEntityList;
if (playerList == null) {
 return;
}
for(int i = 0; i < playerList.size(); ++i) {
 if(playerList.get(i) instanceof EntityPlayerKilled) {
 EntityPlayerKilled entity = (EntityPlayerKilled)playerList.get(i);
 XModDayZ.pipeline.sendToAll(new PacketUpdateInvKilled(entity.player, entity.getEntityId()));
 if(!XModDayZ.map.containsKey(entity)) {
  XModDayZ.map.put(entity, entity.player);
 }
 //System.out.println(entity.getEntityId()+": "+XModDayZ.map.get(entity));
 }
}
}
 
2,505
81
397
Во-первых, ты, когда открываешь гуи, создаешь вообще новую сущность. Даже 2. По одной с каждой стороны.


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


В каком смысле сбивается nbt? Оно используется только для сохранения и если что не синхронизируется с клиентом


Как в гуи получить нужную сущность? Даже не знаю на самом деле. Можно попробовать как-нибудь по координатам найти, благо они есть, если бы ты не передавал 0, 0, 0. Можно попробовать по id сущности. Но его тоже нужно как-то передать в гуи.
 
2,505
81
397
Начну по порядку.
1. Когда спавнишь труп нет смысла отправлять все синхронизирующий пакет. Ты отправляешь его только тем, кто на сервере присутствует. Те, кто подключатся позже инфу не получат. Я сейчас сам разбираюсь с подобным механизмом и по мим догадкам это нужно делать в EntityJoinWorldEvent.
2. Теоретически трупиков одного игрока может быть много. Поэтому нужна во флаге "kill" отпадает.
3. writeEntityToNBT используется для сохранения данных. Отправлять что-то клиентам уж точно не нужно. (интересно, что будет, если это клиентская сторона)
4. readEntityFromNBT для загрузки. И прикол в том, когда происходит эта загрузка, на сервере еще никого нет.
5. В GuiHendler ты попрежнему создаешь какие-то 2 непонятные сущности.


Совет. Если ты на серверной стороне как-нибудь пропихнешь НУЖНУЮ сущность в контейнер, то можно использовать механизм синхронизации, который используется в контейнере.
 
1,137
5
3
Dahaka написал(а):
Начну по порядку.
1. Когда спавнишь труп нет смысла отправлять все синхронизирующий пакет. Ты отправляешь его только тем, кто на сервере присутствует. Те, кто подключатся позже инфу не получат. Я сейчас сам разбираюсь с подобным механизмом и по мим догадкам это нужно делать в EntityJoinWorldEvent.
2. Теоретически трупиков одного игрока может быть много. Поэтому нужна во флаге "kill" отпадает.
3. writeEntityToNBT используется для сохранения данных. Отправлять что-то клиентам уж точно не нужно. (интересно, что будет, если это клиентская сторона)
4. readEntityFromNBT для загрузки. И прикол в том, когда происходит эта загрузка, на сервере еще никого нет.
5. В GuiHendler ты попрежнему создаешь какие-то 2 непонятные сущности.


Совет. Если ты на серверной стороне как-нибудь пропихнешь НУЖНУЮ сущность в контейнер, то можно использовать механизм синхронизации, который используется в контейнере.



1. Смысл-то, как раз, есть. Я сам не могу придумать, но по-хорошему надо отправлять пакет только тогда, когда содержимое поменялось. А новоприбывшим отсылать только данные тех трупов, которые видит игрок.
 
317
10
Я в JoinEvent отправляю ново зашедшим игрокам инфу. Только я еще не тестил ли будет корректно добавлятся инфа о новых трупах уже играющим игрокам.
И вообще еще надо по хорошему тестить все это дело на сервере.
И насчет синхронизации в GUI тоже уже разобрался.
Создал новую мапу. Когда открываю в самом энтити GUI, перед открытием записываю на клиенте + сервере игрока открывшего + entity. А в Handler'е получаю благодаря player.

Это вообще сильно костыльно?)
Или других вариантов нет?
P.s с клиента никогда ничего почти не отправляю, ибо могут написать эксплоит и слать каждый тик пакет. И серверу будет пипец.


Теперь есть еще маленькая трабла. Как изменить "сеточку" моба/трупа? Ибо в рендере я его "положил на пол", но он на стороне сервера все еще стоит как обычный игрок/зомби.
 

timaxa007

Модератор
5,831
409
672
Yarik написал(а):
А как изменить AABB(если не ошибаюсь) или "размер" моба?

В конструктор:
Код:
setSize(1F, 1F);
Первый аргумент - это ширина, второй аргумент - это высота.
 

timaxa007

Модератор
5,831
409
672
Yarik написал(а):
Есть эвент, что бы отменить выпадение вещей при смерти из инвентаря?
LivingDropsEvent - event.setCanceled(true);
Этот эвент работает со всеми мобаи и игроками.


Yarik написал(а):
Или как это работает в gamerule?
Код:
/gamerule keepInventory true
Это правило работает на игрока.
 
608
5
15
wilah написал(а):
С клиентской стороны желательно слать как можно меньше пакетов. Иначе задосят твой сервак

А в чём проблема сделать задержку реагирования на запросы?
 
317
10
timaxa007 написал(а):
Yarik написал(а):
Есть эвент, что бы отменить выпадение вещей при смерти из инвентаря?
LivingDropsEvent - event.setCanceled(true);
Этот эвент работает со всеми мобаи и игроками.


Yarik написал(а):
Или как это работает в gamerule?
Код:
/gamerule keepInventory true
Это правило работает на игрока.



LivingDropsEvent не корректно работает. Мне именно надо что бы был эффект такой же как от команды [font=Monaco, Consolas, Courier, monospace]/gamerule keepInventory true[/font]
 

timaxa007

Модератор
5,831
409
672
Yarik написал(а):
LivingDropsEvent не корректно работает.
И как именно LivingDropsEvent "не корректно работает"?

Yarik написал(а):
Мне именно надо что бы был эффект такой же как от команды [font=Monaco, Consolas, Courier, monospace]/gamerule keepInventory true[/font]

И какой-же эффект, я не очень понимаю тебя? Ты про то что из инвентаря не выпадает и вещи остаются в каждом в своём слоте?
 
317
10
timaxa007 написал(а):
Yarik написал(а):
LivingDropsEvent не корректно работает.
И как именно LivingDropsEvent "не корректно работает"?

Yarik написал(а):
Мне именно надо что бы был эффект такой же как от команды [font=Monaco, Consolas, Courier, monospace]/gamerule keepInventory true[/font]

И какой-же эффект, я не очень понимаю тебя? Ты про то что из инвентаря не выпадает и вещи остаются в каждом в своём слоте?

Я проверял PlayerDropsEvent / Living. Но мне надо что бы вещи были в своих слотах. Ибо я их должен получить во время смерти и записать кое куда. А если они выпадают/удаляются - мне нечего записывать. Инвентарь пустой. А после записи я их удаляю из инвентаря. (так и должно все быть). Пока что все работает как надо с геймрул кипИнвентори. Но мне нужен кодовый вариант этого)
 

timaxa007

Модератор
5,831
409
672
Yarik, у меня как вариант.
Создать место хранения, типа дополнительный инвентарь, с помощью IExtendedEntityProperties. Использовать эвент смерти LivingDeathEvent, проверить что entity является EntityPlayer. Циклом пройтись по слотам или по массивам ItemStack инвентаря и брони (т.е. два цикла) и скопировать в место хранения (типа дополнительный инвентарь). Очистить инвентарь игрока, дабы не было раздвоения вещей.
Т.е. мы скопировали вещи в место хранения (типа дополнительный инвентарь) и останутся в инвентаре. И будут в месте хранения (типа дополнительный инвентарь) и выпадут из инвентаря. По-этому будет раздвоение.

Когда игрок возродится,
Можно с помощью эвента cpw.mods.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent
скопировать из места хранения (типа дополнительный инвентарь) в инвентарь игрока.
 
Сверху