少女祈祷中...

前言

在做弹幕踪迹台之前,首先得拿到mc内所有的粒子类型来让玩家选择。

mc原版粒子都在ParticleTypes类内,只需要把这个类里面所有的静态对象穷举为一个列表,即可解决问题,但这么做显然非常不优雅,而且,不兼容其他模组添加到粒子

当然也有planB,通过AccessTransformer,在ParticleEngine中拿到私有对象providers,是的,所有粒子也会在这里注册一遍。

附录:
1.显然,你需要一个Particle类,负责粒子的具体逻辑;
2.我们当然还需要指定粒子对应的ParticleType,这样才能知道谁是谁;
3.还要一个ParticleOption,这样才能方便粒子生成的消息通过网络传输,以及指令生成;
4.一个ParticleProvider,类似一个工厂类,将ParticleOption转换为Particle。

生成一个粒子要找四家,真不愧是你啊,麻将

正文

我想到mc原版指令Particle有一个命令提示,那里拿到了全部的粒子。然后顺藤摸瓜找到了ParticleArgument类的particles字段,它在初始化的时候拿到了所有注册在Registries.PARTICLE_TYPE下的ParticleType<?>。看到这里,我感觉这个就是我需要的东西。

下面就是打断点,看调用链,找到是哪个方法初始化了这个字段,找到了HolderLookup类的lookupOrThrow方法,传入一个ResourceKey<? extends Registry<? extends T>>对象,但这里似乎已经走进了一个死胡同,我该怎么调用这个方法呢

功夫不负有心人,我找到这个方法的实现方法,RegistryAccess类的lookupOrThrow方法,可以向它直接传入Registries.PARTICLE_TYPE

在给这个方法打断点寻找后,按着调用链,找到了RegistryLayer类的静态方法createRegistryAccess(),再调用compositeAccess返回一个列表内有全部注册表对象的RegistryAccess对象

万事俱备,只需如下代码即可拿到所有的粒子,顺便打印出来

1
2
3
4
5
6
public static void getParticle() {
RegistryAccess.Frozen access = createRegistryAccess().compositeAccess();
ResourceKey<Registry<ParticleType<?>>> type = Registries.PARTICLE_TYPE;
HolderLookup.RegistryLookup<ParticleType<?>> particle = access.lookupOrThrow(type);
particle.listElementIds().forEach(particleTypeResourceKey -> System.out.println(particleTypeResourceKey.toString()));
}

后面经过我的寻找,找到了一个弃用方法拿到对应注册表种类的对象

1
2
3
4
5
@SuppressWarnings("deprecation")
private List<ResourceKey<ParticleType<?>>> getParticle() {
HolderLookup.RegistryLookup<ParticleType<?>> particle = BuiltInRegistries.PARTICLE_TYPE.asLookup();
return particle.listElementIds().collect(Collectors.toList());
}

打印部分结果如下

1
2
3
4
5
ResourceKey[minecraft:particle_type / minecraft:ambient_entity_effect]
ResourceKey[minecraft:particle_type / minecraft:angry_villager]
ResourceKey[minecraft:particle_type / minecraft:block]
ResourceKey[minecraft:particle_type / minecraft:block_marker]
ResourceKey[minecraft:particle_type / minecraft:bubble]