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

Версия Minecraft
1.7.10
318
12
Создал свое 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. По одной с каждой стороны.


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


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


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


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


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



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

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


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

В конструктор:
Код:
setSize(1F, 1F);
Первый аргумент - это ширина, второй аргумент - это высота.
 
Yarik написал(а):
Есть эвент, что бы отменить выпадение вещей при смерти из инвентаря?
LivingDropsEvent - event.setCanceled(true);
Этот эвент работает со всеми мобаи и игроками.


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

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


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



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

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

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

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

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

Я проверял PlayerDropsEvent / Living. Но мне надо что бы вещи были в своих слотах. Ибо я их должен получить во время смерти и записать кое куда. А если они выпадают/удаляются - мне нечего записывать. Инвентарь пустой. А после записи я их удаляю из инвентаря. (так и должно все быть). Пока что все работает как надо с геймрул кипИнвентори. Но мне нужен кодовый вариант этого)
 
Yarik, у меня как вариант.
Создать место хранения, типа дополнительный инвентарь, с помощью IExtendedEntityProperties. Использовать эвент смерти LivingDeathEvent, проверить что entity является EntityPlayer. Циклом пройтись по слотам или по массивам ItemStack инвентаря и брони (т.е. два цикла) и скопировать в место хранения (типа дополнительный инвентарь). Очистить инвентарь игрока, дабы не было раздвоения вещей.
Т.е. мы скопировали вещи в место хранения (типа дополнительный инвентарь) и останутся в инвентаре. И будут в месте хранения (типа дополнительный инвентарь) и выпадут из инвентаря. По-этому будет раздвоение.

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