Posted February 17, 20178 yr I'm trying to add Tough as Nails support for my mod. Basically I want players to keep their thirst level when they die. How should I do this, for hunger I used getOriginal but how should I get Original's thirst level? I already have the deobfuscated jar file in libs folder and I can access the classes but my problem is how do I get thirst level before death. Edited February 17, 20178 yr by Terrails
February 18, 20178 yr Author I need to make my own getOriginal method somehow but I'm not sure how to do it.
February 19, 20178 yr Try to look at the mod how they implemented the functionality and how they handle the thirst. Then look at the getOriginal method and make your own how it is realised. Put both together in the end.
February 19, 20178 yr Author I just made an PlayerEvent class and did this in it: Spoiler public class KHPlayerEvent extends LivingEvent { private final KHEntityPlayer entity; public KHPlayerEvent(KHEntityPlayer player) { super(player); entity = player; } public KHEntityPlayer getKHEntityPlayer() { return this.entity; } public static class KHClone extends KHPlayerEvent { private final KHEntityPlayer original; private final boolean wasDeath; public KHClone(KHEntityPlayer _new, KHEntityPlayer oldPlayer, boolean wasDeath) { super(_new); this.original = oldPlayer; this.wasDeath = wasDeath; } public KHEntityPlayer getKHOriginal() { return original; } public boolean isKHWasDeath() { return wasDeath; } } } This is my EntityPlayer Spoiler public abstract class KHEntityPlayer extends EntityPlayer { protected ThirstHandler thirstHandler = new ThirstHandler(); public KHEntityPlayer(World worldIn, GameProfile gameProfileIn, ThirstHandler thirstHandler) { super(worldIn, gameProfileIn); this.thirstHandler = thirstHandler; } public void cloneKHPlayer(KHEntityPlayer oldPlayer, boolean respawnFromEnd) { if (respawnFromEnd) { this.thirstHandler = oldPlayer.thirstHandler; } this.getDataManager().set(PLAYER_MODEL_FLAG, oldPlayer.getDataManager().get(PLAYER_MODEL_FLAG)); NBTTagCompound old = oldPlayer.getEntityData(); if (old.hasKey(PERSISTED_NBT_TAG)) { getEntityData().setTag(PERSISTED_NBT_TAG, old.getCompoundTag(PERSISTED_NBT_TAG)); } ForgeEventFactory.onPlayerClone(this, oldPlayer, !respawnFromEnd); } public ThirstHandler getThirstStats() { return this.thirstHandler; } } and my event (I registered it in CommonProxy) Spoiler @SubscribeEvent public void keepThirst(KHPlayerEvent.KHClone player) { ThirstHandler thirstHandler = new ThirstHandler(); if (ConfigHandler.thirst && Loader.isModLoaded(ToughAsNails.MOD_ID) && player.isKHWasDeath()) { if (player.getKHEntityPlayer().getThirstStats().getThirst() <= ConfigHandler.thirstAmount && ConfigHandler.amountThirst) { player.getKHEntityPlayer().getThirstStats().setThirst(ConfigHandler.thirstAmount); player.getKHEntityPlayer().getThirstStats().setHydration(player.getKHOriginal().getThirstStats().getHydration()); } else if (ConfigHandler.thirst && Loader.isModLoaded(ToughAsNails.MOD_ID)) { player.getKHEntityPlayer().getThirstStats().setThirst(player.getKHOriginal().getThirstStats().getThirst()); player.getKHEntityPlayer().getThirstStats().setHydration(player.getKHOriginal().getThirstStats().getHydration()); } } } } But it doesn't want to work, I think its something in my EntityPlayer but I'm not sure Edited February 19, 20178 yr by Terrails
February 20, 20178 yr Author I don't crash. the problem is to it doesn't want to work... I think its something in my EntityPlayer but I'm not sure.
February 20, 20178 yr Author If I have Tough as Nails installed it should when a player die's set players thirst like the one before his death. And yes it doesn't do anything it just resets the thirst to max when I die. Edited February 20, 20178 yr by Terrails
February 21, 20178 yr Author I was such an idiot.... it was so simple... this is all I needed to do: @SubscribeEvent public void onClonePlayer(PlayerEvent.Clone player){ final IThirst oldThirst = getThirst(player.getOriginal()); final IThirst newThirst = getThirst(player.getEntityPlayer()); if(oldThirst.getThirst() <= ConfigHandler.thirstAmount && ConfigHandler.amountThirst && Loader.isModLoaded("toughasnails")){ newThirst.setThirst(ConfigHandler.thirstAmount); newThirst.setHydration(oldThirst.getHydration()); } else if(ConfigHandler.thirst && Loader.isModLoaded("toughasnails")) { newThirst.setThirst(oldThirst.getThirst()); newThirst.setHydration(oldThirst.getHydration()); } } @Nullable public static IThirst getThirst(final EntityLivingBase entity) { return entity.getCapability(TANCapabilities.THIRST, null); } I just needed getThirst method from which I get THIRST capability and in my Clone method I just getThirst from original and the entityplayer. Of course I needed to register the event. I used this for tough as nails hydration too.
February 21, 20178 yr Author I have another problem.... Is there a way to put this into an IF statement so my mod can load without ToughAsNails? @Nullable public static IThirst getThirst(final EntityLivingBase entity) { return entity.getCapability(TANCapabilities.THIRST, null); } Edited February 21, 20178 yr by Terrails
February 21, 20178 yr You could put @Optional.Method("modid") above both of those methods to let Forge remove them in case ToughAsNails is not loaded. Edited February 21, 20178 yr by XFactHD
February 21, 20178 yr Author Thanks! Everything works perfectly. Only problem is if I die sometimes my thirst is full, Its a visual bug is there a way to fix this? If I relog or drink water the bug fixes itself, or if I lose thirst Edited February 21, 20178 yr by Terrails
February 21, 20178 yr That looks like a client-server sync issue. You will need to find some way of sending the data to the client. You might want to take a look at how ToughAsNails does that.
February 21, 20178 yr Author Do I need to do something like this? (sorry I never did this kind of stuff) https://github.com/Glitchfiend/ToughAsNails/blob/85ec7ddd56574a22fccf4cd021b0e63f6429f0b4/src/main/java/toughasnails/thirst/ThirstHandler.java#L132
February 21, 20178 yr Author How can I do that without creating a special class for that? (Not making my own ThirstHandler)
February 21, 20178 yr 24 minutes ago, Terrails said: How can I do that without creating a special class for that? (Not making my own ThirstHandler) No, you do not need to make a custom ThirstHandler. From what I can tell, PlayerEvent.Clone only fires on the server-side. That means that when you set your thirst level, you are only setting it on the server-side. In order for you to see the changes visually, you need to update the client-side as well. You can do that via a packet, which you can send to the client after you update the player's thirst level. You can read about networking here.
February 21, 20178 yr Author I somehow made my game to throw an connection terminated error when I try to join my world. In my PlayerEvent.Clone it worked fine but sometimes when I login into the world my thirst would have that glitch again, so I wanted to put it into EntityJoinWorldEvent and than it started giving me that error. Event Class (I have a lot of isModLoaded because I want to my mod to work with 1.9-1.11 and ToughAsNails changed their modid to lowercase in 1.11 and I think I can't add 2 modid's into @Optional.Method("modid")): Spoiler public class TANEvent { @SubscribeEvent public void onClonePlayer(PlayerEvent.Clone player) { final IThirst oldThirst = getThirst(player.getOriginal()); final IThirst newThirst = getThirst(player.getEntityPlayer()); if (oldThirst.getThirst() <= ConfigHandler.thirstAmount && ConfigHandler.thirstBoolean && Loader.isModLoaded("toughasnails") && player.isWasDeath()) { newThirst.setThirst(ConfigHandler.thirstAmount); newThirst.setHydration(oldThirst.getHydration()); } else if (oldThirst.getThirst() <= ConfigHandler.thirstAmount && ConfigHandler.thirstBoolean && Loader.isModLoaded("ToughAsNails") && player.isWasDeath()) { newThirst.setThirst(ConfigHandler.thirstAmount); newThirst.setHydration(oldThirst.getHydration()); } else if (ConfigHandler.thirst && Loader.isModLoaded("toughasnails") && player.isWasDeath()) { newThirst.setThirst(oldThirst.getThirst()); newThirst.setHydration(oldThirst.getHydration()); } else if (ConfigHandler.thirst && Loader.isModLoaded("ToughAsNails") && player.isWasDeath()) { newThirst.setThirst(oldThirst.getThirst()); newThirst.setHydration(oldThirst.getHydration()); } // MainClass.instance.sendToAll(new ThirstMessage(newThirst.getThirst(), newThirst.getHydration())); } @SubscribeEvent public void onJoin(EntityJoinWorldEvent event) { if(Loader.isModLoaded("ToughAsNails")) { ThirstHandler thirst = new ThirstHandler(); MainClass.instance.sendToAll(new ThirstMessage(thirst.getThirst(), thirst.getHydration())); } else if(Loader.isModLoaded("toughasnails")){ ThirstHandler thirst = new ThirstHandler(); MainClass.instance.sendToAll(new ThirstMessage(thirst.getThirst(), thirst.getHydration())); } } @Nullable public static IThirst getThirst(final EntityLivingBase entity) { return entity.getCapability(TANCapabilities.THIRST, null); } } ThirstMessage and ThirstMessageHandler: Spoiler public class ThirstMessage implements IMessage { private String text; private int thirst; private float hydration; public ThirstMessage() {} public ThirstMessage(int thirst, float hydration) { this.thirst = thirst; this.hydration = hydration; } @Override public void fromBytes(ByteBuf buf) { thirst = buf.readInt(); hydration = buf.readFloat(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(thirst); buf.writeFloat(hydration); } public static class ThirstMessageHandler implements IMessageHandler<ThirstMessage, IMessage>{ @Override public IMessage onMessage(ThirstMessage message, MessageContext ctx) { IThreadListener mainThread = (WorldServer) ctx.getServerHandler().playerEntity.getEntityWorld(); mainThread.addScheduledTask(new Runnable() { @Override public void run() { ThirstHandler thirst = new ThirstHandler(); thirst.setThirst(message.thirst); thirst.setHydration(message.hydration); } }); return null; } } } Error: http://pastebin.com/YudBAdz5 Edited February 21, 20178 yr by Terrails
February 22, 20178 yr Author I was trying this for a little bit in PlayerEvent.Clone and it was still happening... what am I doing wrong?
February 23, 20178 yr Author I just looked through their code once more and they write their ThirstHandler to NBT and than read it in their MessageUpdateStat packet. How should I than just send thirst level to that NBT? I just somehow need to send the thirst level once when I die or join the world but how...
February 23, 20178 yr Author I tried couple of things and I still can't do anything: Message: Spoiler public class ThirstMessage implements IMessage, IMessageHandler<ThirstMessage, IMessage> { public int thirst; public ThirstMessage() {} public ThirstMessage(int thirst){ this.thirst = thirst; } @Override public void fromBytes(ByteBuf buf) { thirst = buf.readInt(); } @Override public void toBytes(ByteBuf buf) { buf.writeInt(thirst); } @Override public IMessage onMessage(ThirstMessage message, MessageContext ctx) { IThreadListener mainThread = Minecraft.getMinecraft(); EntityPlayer player = Minecraft.getMinecraft().player; ThirstHandler thirstStats = (ThirstHandler)player.getCapability(TANCapabilities.THIRST, null); mainThread.addScheduledTask(new Runnable() { @Override public void run() { thirstStats.setThirst(message.thirst); } }); return null; } } Event Spoiler @Nullable public static IThirst getThirst(final EntityLivingBase entity) { return entity.getCapability(TANCapabilities.THIRST, null); } @SubscribeEvent public void onClonePlayer(PlayerEvent.Clone player) { final IThirst oldThirst = getThirst(player.getOriginal()); EntityPlayer entityPlayer = player.getEntityPlayer(); ThirstHandler thirstStats = (ThirstHandler)entityPlayer.getCapability(TANCapabilities.THIRST, null); if (oldThirst.getThirst() <= ConfigHandler.thirstAmount && ConfigHandler.thirstBoolean && Loader.isModLoaded("toughasnails") && player.isWasDeath()) { thirstStats.setThirst(ConfigHandler.thirstAmount); thirstStats.setHydration(oldThirst.getHydration()); MainClass.network.sendToAll(new ThirstMessage(thirstStats.getThirst())); } else if (oldThirst.getThirst() <= ConfigHandler.thirstAmount && ConfigHandler.thirstBoolean && Loader.isModLoaded("ToughAsNails") && player.isWasDeath()) { thirstStats.setThirst(ConfigHandler.thirstAmount); thirstStats.setHydration(oldThirst.getHydration()); MainClass.network.sendToAll(new ThirstMessage(thirstStats.getThirst())); } else if (ConfigHandler.thirst && Loader.isModLoaded("toughasnails") && player.isWasDeath()) { thirstStats.setThirst(oldThirst.getThirst()); thirstStats.setHydration(oldThirst.getHydration()); MainClass.network.sendToAll(new ThirstMessage(thirstStats.getThirst())); } else if (ConfigHandler.thirst && Loader.isModLoaded("ToughAsNails") && player.isWasDeath()) { thirstStats.setThirst(oldThirst.getThirst()); thirstStats.setHydration(oldThirst.getHydration()); MainClass.network.sendToAll(new ThirstMessage(thirstStats.getThirst())); } }
February 23, 20178 yr Author I did all of that and its still happening: @SubscribeEvent public void respawn(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent event) { EntityPlayer entityPlayer = event.player; ThirstHandler thirstStats = (ThirstHandler)entityPlayer.getCapability(TANCapabilities.THIRST, null); MainClass.network.sendTo(new ThirstMessage(thirstStats.getThirst()), (EntityPlayerMP) event.player); }
February 23, 20178 yr Author I kinda figured it out. If I die with this Message and this kind of PlayerRespawnEvent my visual thirst gets set to 0 Message(pretty much the same one as tough as nails uses): Spoiler public class PacketMessageThirst implements IMessage, IMessageHandler<PacketMessageThirst, IMessage> { public String identifier; public NBTTagCompound data; public PacketMessageThirst() {} public PacketMessageThirst(Capability<?> capability, NBTTagCompound data) { if (data == null) throw new IllegalArgumentException("Data cannot be null!"); this.identifier = capability.getName(); this.data = data; } @Override public void fromBytes(ByteBuf buf) { this.identifier = ByteBufUtils.readUTF8String(buf); this.data = ByteBufUtils.readTag(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeUTF8String(buf, this.identifier); ByteBufUtils.writeTag(buf, this.data); } @Override public IMessage onMessage(PacketMessageThirst message, MessageContext ctx) { EntityPlayerSP player = Minecraft.getMinecraft().player; if (player != null) { Capability<IPlayerStat> capability = (Capability<IPlayerStat>) PlayerStatRegistry.getCapability(message.identifier); StatHandlerBase stat = (StatHandlerBase)player.getCapability(capability, null); capability.getStorage().readNBT(capability, stat, null, message.data); } return null; } } Event (class needs to extend their ThirstHandler): Spoiler @SubscribeEvent public void respawn(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent event) { NBTTagCompound data = (NBTTagCompound) TANCapabilities.THIRST.getStorage().writeNBT(TANCapabilities.THIRST, this, null); new PacketMessageThirst(TANCapabilities.THIRST, data); } What should I do further... I'm getting really confused by these packet's. Edited February 23, 20178 yr by Terrails
February 24, 20178 yr Author I got some help from Adubbz and I'm not sure what he means by "update list", how should I do that?
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.