Thornack Posted September 20, 2015 Posted September 20, 2015 Hi everyone, I was wondering if anyone would happen to know how to disable hp regeneration for the player. I want it disabled when a condition is true for my player. Since peaceful mode makes it so that your hp regens over time i want this disabled for my player when he is morphed into one of his party members. Any ideas? [EDIT] This has been Solved see the solution in http://www.minecraftforge.net/forum/index.php/topic,34056.0.html Quote
Ernio Posted September 20, 2015 Posted September 20, 2015 LivingHealEvent? Note: As far as I remember it is impossible to know how healing was applied. Only thing you can do is to deal damage whenever you know that entity might have been healed (mening: when food is above healing requirement). Quote 1.7.10 is no longer supported by forge, you are on your own.
Thornack Posted September 20, 2015 Author Posted September 20, 2015 Awesome.... That kind of sucks actually... Quote
weckar Posted September 20, 2015 Posted September 20, 2015 You could register the current health at the point where the regen should be disabled. From there on, override that value whenever it goes down, and override the health with that value whenever it goes up. Not a perfect solution, but it should cover most cases. Quote If anyone has a comprehensive, visual guide to GUIs - don't hesitate to message me. They make my head spin.
Thornack Posted September 21, 2015 Author Posted September 21, 2015 Hmm Im looking for a better solution than that. Thats a bit too hacky for my liking Quote
Thornack Posted September 21, 2015 Author Posted September 21, 2015 Hey I cant find the LivingHealEvent. Im in forge version 1.7.10-10.13.2.1230.jar Is this event a new one? Quote
Choonster Posted September 21, 2015 Posted September 21, 2015 Hey I cant find the LivingHealEvent. Im in forge version 1.7.10-10.13.2.1230.jar Is this event a new one? Looking at the changelog, it was added in 1.7.10-10.13.2.1256 and 1.8-11.14.0.1257. Quote Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.
Thornack Posted September 21, 2015 Author Posted September 21, 2015 Ok Ill have to update thanks for the tip Quote
Failender Posted September 21, 2015 Posted September 21, 2015 Yes ernio is right. There is no way to detect the source of healing. What you could do is store some data in IEEP, e.g. the last healing. Everytime the player wants to heal check the amount (normal regen is half a heart) and the time. If you know how much time between healing ticks is u can exactly find out if the source COULD be regen. Quote
Ernio Posted September 21, 2015 Posted September 21, 2015 Sometimes I wonder where do you get those ideas from. I mean - you find something challenging so you just sit there until you find a way to do it your way, or you just know even more than I thought. Anyway - that's some good shit. Useful AF, now I don't have to do "regen=vanilla(+1)+myStats(+x)" but directly "regen=myStats(+x)". Quote 1.7.10 is no longer supported by forge, you are on your own.
Abastro Posted September 22, 2015 Posted September 22, 2015 Also, wrapping existing FoodStats object is preferable, since there are some mods using same method. Quote I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP) II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.
Thornack Posted September 23, 2015 Author Posted September 23, 2015 Would it be preferable to create my own custom class that extends the foodstats class and override its onUpdate method to conditionally disable the hp regen or would just updating forge be a better solution so that I can use the LivingHealEvent? Quote
Thornack Posted September 23, 2015 Author Posted September 23, 2015 Also, Im not really sure how to Override the food stats object for the player. I know how to override methods but Ive never overridden an object before. In Entityplayer the food stats variable is protected. I made my custom Food Stats Class extend the vanilla Food Stats class and in the onUpdate method I call super.onUpdate() and I put a @Override annotation above it as per usual. Not sure what else I am missing Quote
Abastro Posted September 23, 2015 Posted September 23, 2015 1. You would have to completely change the onUpdate method. 2. This is what I mean by 'overlap': store the existing FoodStats object, and call its method which you would not want to change. Quote I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP) II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.
Thornack Posted September 23, 2015 Author Posted September 23, 2015 Ok, Im not sure exactly how to do this. So far I have the following in my custom class (its all based on vanilla except the onUpdate method which is different (I changed it completely to just outprint to consol (the outprint doesnt currently show up btw))) The CustomFoodStats class public class CustomFoodStats extends FoodStats { /** The player's food level. */ private int foodLevel = 20; /** The player's food saturation. */ private float foodSaturationLevel = 5.0F; /** The player's food exhaustion. */ private float foodExhaustionLevel; /** The player's food timer value. */ private int foodTimer; private int prevFoodLevel = 20; /** * Args: int foodLevel, float foodSaturationModifier */ @Override public void addStats(int min, float max) { super.addStats(min, max); this.foodLevel = Math.min(min + this.foodLevel, 20); this.foodSaturationLevel = Math.min(this.foodSaturationLevel + (float)min * max * 2.0F, (float)this.foodLevel); } @Override public void func_151686_a(ItemFood food, ItemStack itemStack) { super.func_151686_a(food, itemStack); this.addStats(food.func_150905_g(itemStack), food.func_150906_h(itemStack)); } /** * Handles the food game logic. */ @Override public void onUpdate(EntityPlayer player) { super.onUpdate(player); System.out.println("OVERRIDDEN"); } /** * Reads food stats from an NBT object. */ @Override public void readNBT(NBTTagCompound nbt) { super.readNBT(nbt); if (nbt.hasKey("foodLevel", 99)) { this.foodLevel = nbt.getInteger("foodLevel"); this.foodTimer = nbt.getInteger("foodTickTimer"); this.foodSaturationLevel = nbt.getFloat("foodSaturationLevel"); this.foodExhaustionLevel = nbt.getFloat("foodExhaustionLevel"); } } /** * Writes food stats to an NBT object. */ @Override public void writeNBT(NBTTagCompound nbt) { super.writeNBT(nbt); nbt.setInteger("foodLevel", this.foodLevel); nbt.setInteger("foodTickTimer", this.foodTimer); nbt.setFloat("foodSaturationLevel", this.foodSaturationLevel); nbt.setFloat("foodExhaustionLevel", this.foodExhaustionLevel); } /** * Get the player's food level. */ @Override public int getFoodLevel() { super.getFoodLevel(); return this.foodLevel; } @Override @SideOnly(Side.CLIENT) public int getPrevFoodLevel() { super.getPrevFoodLevel(); return this.prevFoodLevel; } /** * If foodLevel is not max. */ @Override public boolean needFood() { super.needFood(); return this.foodLevel < 20; } /** * adds input to foodExhaustionLevel to a max of 40 */ @Override public void addExhaustion(float amount) { super.addExhaustion(amount); this.foodExhaustionLevel = Math.min(this.foodExhaustionLevel + amount, 40.0F); } /** * Get the player's food saturation level. */ @Override public float getSaturationLevel() { super.getSaturationLevel(); return this.foodSaturationLevel; } @Override @SideOnly(Side.CLIENT) public void setFoodLevel(int amount) { super.setFoodLevel(amount); this.foodLevel = amount; } @Override @SideOnly(Side.CLIENT) public void setFoodSaturationLevel(float amount) { super.setFoodSaturationLevel(amount); this.foodSaturationLevel = amount; } } Quote
Thornack Posted September 23, 2015 Author Posted September 23, 2015 in my IEEP I do the following. public CustomFoodStats foodStats = new CustomFoodStats(); to initialize it, Then inside the onLivingUpdate Event I get the IEEP instance from the player and then do ieep.foodStats.onUpdate((EntityPlayer) event.entity); but this doesnt override anything it just calls my onUpdate method Quote
Abastro Posted September 23, 2015 Posted September 23, 2015 You should set the foodstats field of the player. Also don't just copy-paste the code.. Quote I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP) II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.
Ernio Posted September 23, 2015 Posted September 23, 2015 That is what happens when you don't understand how Java (or programming) works. (I wasn't expecting this from you really ) Just making class won't do anything. You need to actually replace FoodStats object in EntityPlayer field. In EntityPlayer there is a field: protected FoodStats foodStats = new FoodStats(); Basically - you need to replace it whenever it is not set yours. Init in Java goes like this: (refresh my memory if not) Static initalization. Instance initialization. Constructor executed. So You can probably use EntityConstructing event to access player#foodStats with reflection and set value to your own. ObfuscationReflectionHelper.getPrivateValue(EntityPlayer.class, event.player, "foodStats", "findSrgInFiles"); Mentioned before object wrapping is passing previous FoodStats (no matter the extension) into your new one. So e.g you can have FoodStatsOfModOne inside FoodStatsOfYourMod. Quote 1.7.10 is no longer supported by forge, you are on your own.
Thornack Posted September 23, 2015 Author Posted September 23, 2015 I understand that copying the class wont do anything, I am bad at reflection so I guess I wasnt being clear I wasnt sure how to actually override the actual object so that I can use my class instead. Quote
Thornack Posted September 23, 2015 Author Posted September 23, 2015 Ok, so in my EntityConstructing event I get the access player#foodStats. But this outprints as Null when I do this. Im not sure what else to do @SubscribeEvent public void onEntityConstructing(EntityConstructing event) { if (event.entity instanceof EntityPlayer) { if (BattlePlayerProperties.get((EntityPlayer) event.entity) == null) { BattlePlayerProperties.register((EntityPlayer) event.entity); } FoodStats foodStats = ObfuscationReflectionHelper.getPrivateValue(EntityPlayer.class, (EntityPlayer)event.entity, "foodStats", "findSrgInFiles"); System.out.println(foodStats); //PRINTS A VALUE OF NULL } } Quote
Thornack Posted September 23, 2015 Author Posted September 23, 2015 I believe the SRG-name is field_71100_bB for 1.7.10 but I still get null when I use it Quote
Thornack Posted September 23, 2015 Author Posted September 23, 2015 Im not really sure what I have to do here to replace the FoodStats object that the player is using with my own. I know that I have to get the object but when I do that using Entity Constructing event I get a value of null for it and I know that I have to replace the object after it has been initialized with my own (the class is above) But i am not sure what the steps are Quote
Thornack Posted September 23, 2015 Author Posted September 23, 2015 I tried the following to get the field and it doesnt seem to fail, it outprints the following on EntityConstructing: TRYING custommod.player.properties.CustomFoodStats@16c8fa04 try{ Field field = ReflectionHelper.findField(EntityPlayer.class,"field_71100_bB","foodStats"); field.setAccessible(true); field.set((EntityPlayer)event.entity, new CustomFoodStats()); System.out.println("TRYING " + field.get(event.entity)); }catch (Throwable e){ System.out.println("Reflection on foodStats variable for Player has FAILED!!"); e.printStackTrace(); } Quote
Recommended Posts
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.