The bug
Potion effect shadowing is imperfect. The precise problem is rather difficult to describe and I won't attempt to do so at the current time; suffice to say, this mainly manifests as particles appearing when they should not or being opaque when they should be ambient; due to the particle changes in 24w11a, this issue can be thought of as MC-96535 on a per-effect basis.
To reproduce
Build a level 1 beacon and set it to Speed, but put a solid block over it so you don't get the effect
Run
/effect give @s minecraft:speed infinite 0 true
Unblock the beacon
→ ❌ Notice how you have opaque Speed particles emanating form you.
Thoughts on a fix
Firstly, the show_particles
and ambient
booleans should be condensed into a single int, particle_opacity_level
, and the logic related to adding and rendering shadowed effects should be as follows:
void applyEffect(Effect new, Entity entity){
Effect current = entity.effects.get(new.id);
if(current == null){
entity.applyNewEffect(new);
return;
}
Effect prev = null;
while(current != null){
if(new > current){
if(new.amplifier == current.amplifier && new.duration == current.duration){
current.particleOpacityLevel = Math.max(current.particleOpacityLevel, new.particleOpacityLevel);
current.showIcon = Math.max(current.particleOpacityLevel, new.particleOpacityLevel);
}
else if(prev == null){
entity.applyNewEffect(new);
}
else{
prev.hiddenEffect = new;
}
new.hiddenEffect = current;
return;
}
prev = current;
current = current.hiddenEffect;
}
current.hiddenEffect = new;
}
// When given the highest effect in the hierarchy, determine how it should be displayed
EffectDisplayData getDisplayDataFor(Effect e){
int amplifier = e.amplifier;
int duration = e.duration;
int particleOpacityLevel = -1;
int showIcon = -1;
for(Effect current = e; e.hiddenEffect != null; e = e.hiddenEffect){
particleOpacityLevel = Math.max(particleOpacityLevel, e.particleOpacityLevel);
showIcon = Math.max(showIcon, e.showIcon)
}
return new EffectDisplayData(amplifier, duration, particleOpacityLevel, showIcon)
}
where the Effect comparator is
public int compareTo(Effect other){
if(this.amplifier != other.amplifier) return this.amplifier - other.amplifier;
if(this.duration != other.duration) return this.duration - other.duration;
if(this.particleOpacityLevel != other.particleOpacityLevel) return this.particleOpacityLevel - other.particleOpacityLevel;
return this.showIcon - other.showIcon;
}
The result is that, when it comes time to put this NBT to use by creating particles and rendering the duration in the UI, the game does the following for each effect ID:
Get the
amplifier
of the highest-level instance and use that as the level to show in the UI.Get the
duration
of the highest-level instance and use that as the duration to show in the UI.Get the highest
particle_opacity_level
in the entire hierarchy and use that to render the particles.Get the highest
show_icon
in the entire hierarchy and use that to render the icon.
Linked issues
is duplicated by 3
relates to 1
Attachments
Comments 9
Affects 21w37a.
So basically, the bug is that beacons and conduits seem to override the particle visibility settings of existing hidden effects when attempting to apply an effect of the same type, unless the hidden effect is of a lower amplifier than the new one, in which case it gets stored in the HiddenEffect tag as expected. This exception is also the case with MC-96535, but that bug is more of a rendering bug whereas here data is being modified improperly. (I was unable to reproduce this using ambient splash potions so the problem seems specific to beacons and conduits.)
Can you reproduce this bug in 1.15.2?