Jump to content

Potions wont recolor even when i change the liquidColor...?


powns

Recommended Posts

As the title says, I used reflection to modify the liquidColor value of a healing potion (Potion.heal).

Whenever i use a command to change its color i let it print out the RGB color int in the console which does actually change (System.out.println(Potion.heal.getLiquidColor());)

but it does not seem to actually change the color once the potion texture has been loaded once...

 

Is there something i forgot to do? Let me know if you need to have some insight on my source code.

Link to comment
Share on other sites

public void changeHealpotColor(int color){
    	try{
        	Class potionClass = Potion.class;
        	Field f = potionClass.getField("heal");
        	
        	f.setAccessible(true);

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
          
        	ReflectionHelper.setPrivateValue(potionClass, Potion.heal, color, "liquidColor");
        }
        catch(Exception e){
        	e.printStackTrace();
        }
    }

this is the source code i use to change the liquidColor

Link to comment
Share on other sites

2 minutes ago, diesieben07 said:

Why are you even accessing the "heal" field? You are not using it...

I thought this would remove the "final" modifier . I know it works without but i seem to not have removed it after testing. Even when i remove it it doesnt work.

I feel like i need to reload something within forge for the recoloring to work without restarting the game, but i do not know how

Link to comment
Share on other sites

5 minutes ago, diesieben07 said:

Why are you even accessing the "heal" field? You are not using it...

public void changeHealpotColor(int color){
    	try{
        	Class potionClass = Potion.class;
        	ReflectionHelper.setPrivateValue(potionClass, Potion.heal, color, "liquidColor");
        	//Minecraft.getMinecraft().refreshResources();
        }
        catch(Exception e){
        	e.printStackTrace();
        }
    }

this is what i am using, the method i commented out is what i tried to do to re-render the potion overlay to hopefully update the color. But that did not work

Link to comment
Share on other sites

Just now, diesieben07 said:

Why are you bumping? It's been barely over an hour since your last post. Plus you have not even posted and kind of question.

 

Please clarify what you actually want to achieve. You cannot really change the color at runtime, it is designed to be static.

My question is: Would there be any way to maybe reload the Potion class and the textures so that it would possibly work without having to restart minecraft?

Link to comment
Share on other sites

Just now, diesieben07 said:

If you change the color field on client and server you do not need to update anything.

As i said before, when i change the color field it does work as long as i do not load any potions.

Once i have loaded them the color will stay to the last color i set it to before loading them in, even if i change the liquidColor again.

 

If i would log the color int in the console it will log the most recent color i want it to be. But it will still not render with that color because it loaded with another, previous, color.

 

How would i be able to make it update instantly after changing the color using the method i showed?

Link to comment
Share on other sites

Just now, diesieben07 said:

I am not familiar with the term "loading a potion", please clarify.

If i start up a game and do not get the potion item to show up at all, either in an inventory or in my hand, i can change the color. Once i "load" the potion by showing it in an inventory or in my hand the color will have changed to the latest color i changed it to. But after that i can still change the liquidColor Integer but it will no longer update potion colors anymore.

 

I thought it wouldve been possible to make it still work by making all the textures reload, but that does not seem to work. Now I am lowkey clueless on how to make it possible to change the color whenever i want, even if i have shown/seen the item before.

Link to comment
Share on other sites

4 minutes ago, diesieben07 said:

I am not familiar with how this works on 1.8.9 exactly. However that version is old and outdated, you should update.

I would do that if 1.9+ would be good for pvp. The mods i make have an audience that either plays on 1.7.10 or 1.8.9.

But you said that the color is queried and computed every tick, is there a way that i can see where that happens in the vanilla source code?

Link to comment
Share on other sites

Just now, diesieben07 said:

That's what I deduced from the 1.12.x code. I do not have a 1.8.x workspace.

 

You can use the debugger to see what's going on in the code.

I will do that, I might have found a solution and i will post it here if it works so that other people would be able to benefit from it too

 

thanks for your help!

Link to comment
Share on other sites

Events don't work that way. Events are coded by Forge as patches against the vanilla code, so you can't just add the same code yourself in an older version. However, if you look at the code around where the event is called in 1.11+ you might get ideas about other ways to intercept it.

 

For example, I noticed that the event is actually fired during the metadata update and interestingly the metadata includes the potion color that is set to the data manager. So it may well be possible to set the datamanager directly. Here is the code in the event:

    protected void updatePotionMetadata()
    {
        if (this.activePotionsMap.isEmpty())
        {
            this.resetPotionEffectMetadata();
            this.setInvisible(false);
        }
        else
        {
            Collection<PotionEffect> collection = this.activePotionsMap.values();
            net.minecraftforge.event.entity.living.PotionColorCalculationEvent event = new net.minecraftforge.event.entity.living.PotionColorCalculationEvent(this, PotionUtils.getPotionColorFromEffectList(collection), areAllPotionsAmbient(collection), collection);
            net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event);
            this.dataManager.set(HIDE_PARTICLES, event.areParticlesHidden());
            this.dataManager.set(POTION_EFFECTS, event.getColor());
            this.setInvisible(this.isPotionActive(MobEffects.INVISIBILITY));
        }
    }

 

However, I can't remember if the datamanager was used in 1.8.9 or it might have been the data watcher instead. If so, you should look at the data watcher for potions to see if the color is in that. If so, then you might be able to override it directly.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

5 minutes ago, jabelar said:

Events don't work that way. Events are coded by Forge as patches against the vanilla code, so you can't just add the same code yourself in an older version. However, if you look at the code around where the event is called in 1.11+ you might get ideas about other ways to intercept it.

 

For example, I noticed that the event is actually fired during the metadata update and interestingly the metadata includes the potion color that is set to the data manager. So it may well be possible to set the datamanager directly. Here is the code in the event:


    protected void updatePotionMetadata()
    {
        if (this.activePotionsMap.isEmpty())
        {
            this.resetPotionEffectMetadata();
            this.setInvisible(false);
        }
        else
        {
            Collection<PotionEffect> collection = this.activePotionsMap.values();
            net.minecraftforge.event.entity.living.PotionColorCalculationEvent event = new net.minecraftforge.event.entity.living.PotionColorCalculationEvent(this, PotionUtils.getPotionColorFromEffectList(collection), areAllPotionsAmbient(collection), collection);
            net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event);
            this.dataManager.set(HIDE_PARTICLES, event.areParticlesHidden());
            this.dataManager.set(POTION_EFFECTS, event.getColor());
            this.setInvisible(this.isPotionActive(MobEffects.INVISIBILITY));
        }
    }

 

However, I can't remember if the datamanager was used in 1.8.9 or it might have been the data watcher instead. If so, you should look at the data watcher for potions to see if the color is in that. If so, then you might be able to override it directly.

Yeah, in 1.8.9 it is handled by a DataWatcher, but unfortunately I have no idea how to override the method you mentioned above. 

Could you maybe explain that to me a bit more?

Link to comment
Share on other sites

Just now, diesieben07 said:

I don't think you understand what "override" means.

 

The problem with this approach is that you need to set the color for every entity that has the potion effect and there is no fast way to get those, you'd have to loop through every entity in the world.

I do know what overriding means. I do not know how to get that to work in forge modding as i am still rather new to this.

 

The way i would want this to work is by setting the private boolean potionsNeedUpdate to true as soon as i change the color of a certain potion type. That way, correct me if im wrong, it should update all the potions to have its new liquidColor. My idea was to override the updatePotionMetadata() method from the LivingEntityBase class so that i can call that method whenever i need it. It makes sense for me, but it is probably a rather amateuristic way of seeing this.

Link to comment
Share on other sites

1 minute ago, diesieben07 said:

Except there is not just one of these fields, it exists for every entity. You need to set it to true for every entity that is loaded and has the potion.

But modifying the vanilla EntityLivingBase class would be possible with ASM right? What if i just modify the vanilla method that updates potions so that i can get it to un every tick regardless of the boolean's state?

Link to comment
Share on other sites

2 minutes ago, diesieben07 said:

Coremodding will not be supported on this forum. There is a perfectly adequate solution to your problem: Update.

Hacking around with a coremod is not a good idea.

As i said before, if mojang did not completely ignore the pvp community and keep the combat mechanics the same i would have never ever used minecraft versions from 2014.

But in that case I understand and respect it that you guys are not willing to support me into doing this. Regardless of that, I want to thank you for all your help.

Link to comment
Share on other sites

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.