Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions src/main/kotlin/de/snowii/extractor/extractors/Particles.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package de.snowii.extractor.extractors

import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import de.snowii.extractor.Extractor
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.core.particles.SimpleParticleType
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.server.MinecraftServer
import java.lang.reflect.ParameterizedType


class Particles : Extractor.Extractor {
Expand All @@ -13,10 +17,42 @@ class Particles : Extractor.Extractor {
}

override fun extract(server: MinecraftServer): JsonElement {
val particlesJson = JsonArray()
val particlesJson = JsonObject()

for (particle in BuiltInRegistries.PARTICLE_TYPE) {
val fields = JsonArray()

// Extract the fields of the particle type, using the class of the particle type
// This is done using the constructor of the particle type and reading the parameters
// SimpleParticleType does not have any fields, so we skip particles of this type
if (particle !is SimpleParticleType) {
val id = BuiltInRegistries.PARTICLE_TYPE.getKey(particle)!!.path
val particleType = ParticleTypes::class.java.getDeclaredField(id.uppercase()).genericType

if (particleType is ParameterizedType) {
// The registry items are ParticleType<T>, we need to get the type T using reflection
val parameterizedType = particleType as ParameterizedType?
val typeArguments = parameterizedType!!.actualTypeArguments
val typeArg = typeArguments[0]

if (typeArg is Class<*>) {
// Based on the type T, we convert it back to a class and get the parameters using reflection
val typeClass = typeArg as Class<*>?

for (field in typeClass?.constructors?.first()?.parameters!!) {
val name = field.name

// Parameter 'type' is in every constructor, we do not need it for our purposes
if (name != "type") {
fields.add(name)
}
}
}
}
}

particlesJson.add(
BuiltInRegistries.PARTICLE_TYPE.getKey(particle)!!.path,
BuiltInRegistries.PARTICLE_TYPE.getKey(particle)!!.path, fields
)
}

Expand Down
7 changes: 6 additions & 1 deletion src/main/resources/extractor.accesswidener
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ accessible field net/minecraft/stats/Stat value Ljava/lang/Object;
accessible field net/minecraft/stats/StatType registry Lnet/minecraft/core/Registry;
accessible field net/minecraft/stats/StatType displayName Lnet/minecraft/network/chat/Component;
# accessible field net/minecraft/entity/data/TrackedDataHandlerRegistry DATA_HANDLERS Lnet/minecraft/util/collection/Int2ObjectBiMap;
# accessible field net/minecraft/entity/data/DataTracker CLASS_TO_LAST_ID Lnet/minecraft/util/collection/Class2IntMap;
# accessible field net/minecraft/entity/data/DataTracker CLASS_TO_LAST_ID Lnet/minecraft/util/collection/Class2IntMap;

# For some reason, these constructors are private. We need them to be public to read the parameters from them
accessible method net/minecraft/core/particles/PowerParticleOption <init> (Lnet/minecraft/core/particles/ParticleType;F)V
accessible method net/minecraft/core/particles/SpellParticleOption <init> (Lnet/minecraft/core/particles/ParticleType;IF)V
accessible method net/minecraft/core/particles/ColorParticleOption <init> (Lnet/minecraft/core/particles/ParticleType;I)V