77import net .minecraft .client .particle .ParticleManager ;
88import net .minecraft .client .particle .ParticleTextureSheet ;
99import org .spongepowered .asm .mixin .Final ;
10+ import net .minecraft .particle .ParticleGroup ;
1011import org .spongepowered .asm .mixin .Mixin ;
1112import org .spongepowered .asm .mixin .Shadow ;
13+ import org .spongepowered .asm .mixin .Unique ;
1214import org .spongepowered .asm .mixin .injection .At ;
15+ import org .spongepowered .asm .mixin .injection .Inject ;
1316import org .spongepowered .asm .mixin .injection .Redirect ;
17+ import org .spongepowered .asm .mixin .injection .callback .CallbackInfo ;
1418
1519import java .util .Map ;
1620import java .util .Queue ;
@@ -25,6 +29,9 @@ public abstract class ParticleManagerMixin {
2529 @ Shadow
2630 private Queue <Particle > newParticles ;
2731
32+ @ Shadow
33+ protected abstract void addTo (ParticleGroup group , int count );
34+
2835 @ Redirect (method = "tick" , at = @ At (value = "INVOKE" , target = "Ljava/util/Queue;poll()Ljava/lang/Object;" ))
2936 public Object changeMaxParticles (Queue <Object > queue ) {
3037 // 不需要判断 EnabledParticleCountInject 了,已在注入时判断,关这个一般都是因为会注入失败,所以不用担心
@@ -34,13 +41,29 @@ public Object changeMaxParticles(Queue<Object> queue) {
3441 Queue <Particle > queue1 = particles .computeIfAbsent (particle .getType (),
3542 sheet -> EvictingQueue .create (limit ));
3643 // limit 在程序生命周期内不会改变,这里可以直接判断
37- if (queue1 .size () < limit ) {
38- queue1 .add (particle );
39- } else {
44+ if (queue1 .size () == limit ) {
4045 // 这样驱逐队列就没用了但是可以避免内存泄漏
41- particle .markDead ();
46+ Particle poll = queue1 .poll ();
47+ if (poll != null ) onEvict (poll );
4248 }
49+ queue1 .add (particle );
4350 }
4451 return null ;
4552 }
53+
54+ @ Inject (method = "clearParticles" , at = @ At ("HEAD" ))
55+ public void clearParticles (CallbackInfo ci ) {
56+ particles .values ().forEach (q -> q .forEach (this ::onEvict ));
57+ newParticles .forEach (this ::onEvict );
58+ }
59+
60+ @ Unique
61+ private void onEvict (Particle p ) {
62+ // 这是原版 bug,但本模组会放大这个问题所以有必要修复一下
63+ // 判断 isAlive 以保证幂等性(其他模组可能注入类似方法)
64+ if (p .isAlive ()) {
65+ p .markDead ();
66+ p .getGroup ().ifPresent (group -> addTo (group , -1 ));
67+ }
68+ }
4669}
0 commit comments