Jump to content

Recommended Posts

Posted (edited)

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 by Terrails
Posted

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.

 

Posted (edited)

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 by Terrails
Posted (edited)

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 by Terrails
Posted

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.

Posted (edited)

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 by Terrails
Posted (edited)

You could put @Optional.Method("modid") above both of those methods to let Forge remove them in case ToughAsNails is not loaded.

Edited by XFactHD
Posted (edited)

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 by Terrails
Posted

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.

Posted
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.

Posted (edited)

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 by Terrails
Posted

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()));
        }

    }

 

 

Posted

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);
    }

 

Posted (edited)

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 by Terrails

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.