Mixin Configuration - Harveykang/AsyncParticles GitHub Wiki
请帮忙翻译这个页面
Path
config/asyncparticles/asyncparticles-mixin.properties
Default
particle$noLightCache=dev.shadowsoffire.gateways.client.GatewayParticle,\
com.chailotl.particular.particles.FireflyParticle,com.lowdragmc.photon.client.gameobject.FXObject,\
net.diebuddies.minecraft.weather.WeatherParticle
particle$noCulling=pigcart.particlerain.particle.GroundFogParticle,\
com.lowdragmc.photon.client.gameobject.FXObject
particle$lockRequired=yesman.epicfight.client.particle.TrailParticle,\
com.dfdyz.epicacg.client.particle.BloomTrailParticle,\
com.brandon3055.draconicevolution.client.render.effect.ExplosionFX,\
com.brandon3055.draconicevolution.client.render.effect.CrystalFXWireless,\
com.lowdragmc.photon.client.gameobject.emitter.Emitter,\
com.lowdragmc.photon.client.gameobject.emitter.particle.ParticleEmitter,\
com.lowdragmc.photon.client.gameobject.emitter.beam.BeamEmitter,\
com.lowdragmc.photon.client.gameobject.emitter.trail.TrailEmitter
particle$lockProvider=yesman.epicfight.client.particle.TrailParticle,\
com.dfdyz.epicacg.client.particle.BloomTrailParticle,\
com.brandon3055.draconicevolution.client.render.effect.ExplosionFX,\
com.brandon3055.draconicevolution.client.render.effect.CrystalFXWireless,\
com.lowdragmc.photon.client.gameobject.FXObject
'particle$noCulling'
- 对特定的粒子类禁用剔除
'particle$noLightCache'
- 对特定的粒子类禁用光照缓存
'particle$lockProvider' and 'particle$lockRequired'
- 提供锁或需要加锁的粒子类
- 用于在
tick
和render
方法上加一个自旋锁 - 有时一个类不会同时实现
tick
和render
方法,此时需要:- 将实现了实现
tick
或render
方法的最终子类加入'particle$lockRequired' - 将实现了实现
tick
或render
方法的最终子类的最小公共父类加入'particle$lockProvider'
- 将实现了实现
实现原理
在预启动阶段读取原始Mixin类文件的字节码,修改其目标类和类名,生成一份字节码。
因为Mixin的本质不是Java类,不会被JVM加载,因此只需保存一个“生成的完整类名->byte[]”的Map即可(未来可能会将它持久化以减少内存占用),且不需要严格遵守类文件格式。
每个xxx.mixins.json
对应一个MixinConfig
和IMixinConfigPlugin
。
IMixinConfigPlugin
可以通过getMixins
方法提供一份额外Mixin类的短名列表。
Mixin被应用时会从MixinConfig
拿到MixinService
拿到ClassBytecodeProvider
,调用getClassNode
,入参为Mixin的完整内部类名,其中就包括我们在getMixins
提供的额外Mixin类。
将我们的xxx.mixins.json
对应的MixinConfig
中的MixinService
替换为我们的包装对象,这样在调用getClassNode
方法时,先检查类名是否包含在上文提到的Map中,如果在,就返回修改过的字节码,转为ClassNode
。这样我们运行时生成的Mixin类就会被应用,从而达到修改目标类的目的。
另外还需要通过MixinSquared的MixinCanceller取消原始Mixin的注入。
具体实现见此处。
Qwen 3.
The following content was translated by'particle$noCulling'
- Disables culling for specific particle classes
'particle$noLightCache'
- Disables light caching for specific particle classes
'particle$lockProvider' and 'particle$lockRequired'
- Particle classes that provide or require a lock
- Used to add a spinlock to the
tick
andrender
methods - Sometimes a class does not implement both
tick
andrender
methods, in which case:- Add the final subclass that implements either
tick
orrender
to'particle$lockRequired'
- Add the minimal common parent class of that final subclass to
'particle$lockProvider'
- Add the final subclass that implements either
Implementation Details
During the pre-launch phase, the bytecode of the original Mixin class file is read. The target class and class name are modified to generate new bytecode.
Since Mixins are not actual Java classes and will not be loaded by the JVM, it's sufficient to maintain a Map from generated full class names to byte arrays (in the future, this may be persisted to reduce memory usage), and there is no strict need to follow the class file format.
Each xxx.mixins.json
corresponds to a MixinConfig
and an IMixinConfigPlugin
.
The IMixinConfigPlugin
can provide an additional list of mixin via the getMixins
method.
When a Mixin is applied, it retrieves the MixinService
from the MixinConfig
, then gets the ClassBytecodeProvider
, and calls getClassNode
. The parameter is the full internal name of the applying Mixin. The additional Mixins also pass through here.
By replacing the MixinService
in the MixinConfig
corresponding to our xxx.mixins.json
with our wrapper object, during the call to getClassNode
, we first check whether the class name exists in the aforementioned Map. If so, we return the modified bytecode converted into a ClassNode
. This allows our runtime-generated Mixin classes to be applied, thus achieving the goal of modifying the target class.
Additionally, the original Mixin injection must be canceled using MixinSquared's MixinCanceller
.
The specific implementation can be found here.