package net.minestom.codegen.entity; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.squareup.javapoet.*; import net.minestom.codegen.MinestomCodeGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.lang.model.element.Modifier; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; public final class VillagerTypeGenerator extends MinestomCodeGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(VillagerTypeGenerator.class); private final InputStream villagerTypesFile; private final File outputFolder; public VillagerTypeGenerator(@Nullable InputStream villagerTypesFile, @NotNull File outputFolder) { this.villagerTypesFile = villagerTypesFile; this.outputFolder = outputFolder; } @Override public void generate() { if (villagerTypesFile == null) { LOGGER.error("Failed to find villager_types.json."); LOGGER.error("Stopped code generation for villager types."); return; } if (!outputFolder.exists() && !outputFolder.mkdirs()) { LOGGER.error("Output folder for code generation does not exist and could not be created."); return; } // Important classes we use alot ClassName namespaceIDClassName = ClassName.get("net.minestom.server.utils", "NamespaceID"); ClassName registryClassName = ClassName.get("net.minestom.server.registry", "Registry"); JsonArray villagerTypes = GSON.fromJson(new InputStreamReader(villagerTypesFile), JsonArray.class); ClassName villagerTypeClassName = ClassName.get("net.minestom.server.entity.metadata.villager", "VillagerType"); // Particle TypeSpec.Builder villagerTypeClass = TypeSpec.classBuilder(villagerTypeClassName) .addSuperinterface(ClassName.get("net.kyori.adventure.key", "Keyed")) .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); villagerTypeClass.addField( FieldSpec.builder(namespaceIDClassName, "id") .addModifiers(Modifier.PRIVATE, Modifier.FINAL).addAnnotation(NotNull.class).build() ); villagerTypeClass.addMethod( MethodSpec.constructorBuilder() .addParameter(ParameterSpec.builder(namespaceIDClassName, "id").addAnnotation(NotNull.class).build()) .addStatement("this.id = id") .addModifiers(Modifier.PROTECTED) .build() ); // Override key method (adventure) villagerTypeClass.addMethod( MethodSpec.methodBuilder("key") .returns(ClassName.get("net.kyori.adventure.key", "Key")) .addAnnotation(Override.class) .addAnnotation(NotNull.class) .addStatement("return this.id") .addModifiers(Modifier.PUBLIC) .build() ); // getId method villagerTypeClass.addMethod( MethodSpec.methodBuilder("getId") .returns(namespaceIDClassName) .addAnnotation(NotNull.class) .addStatement("return this.id") .addModifiers(Modifier.PUBLIC) .build() ); // getNumericalId villagerTypeClass.addMethod( MethodSpec.methodBuilder("getNumericalId") .returns(TypeName.INT) .addStatement("return $T.VILLAGER_TYPE_REGISTRY.getId(this)", registryClassName) .addModifiers(Modifier.PUBLIC) .build() ); // fromId Method villagerTypeClass.addMethod( MethodSpec.methodBuilder("fromId") .returns(villagerTypeClassName) .addAnnotation(Nullable.class) .addParameter(TypeName.INT, "id") .addStatement("return $T.VILLAGER_TYPE_REGISTRY.get((short) id)", registryClassName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build() ); // fromId Method villagerTypeClass.addMethod( MethodSpec.methodBuilder("fromId") .returns(villagerTypeClassName) .addAnnotation(NotNull.class) .addParameter(ClassName.get("net.kyori.adventure.key", "Key"), "id") .addStatement("return $T.VILLAGER_TYPE_REGISTRY.get(id)", registryClassName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build() ); // toString method villagerTypeClass.addMethod( MethodSpec.methodBuilder("toString") .addAnnotation(NotNull.class) .addAnnotation(Override.class) .returns(String.class) // this resolves to [Namespace] .addStatement("return \"[\" + this.id + \"]\"") .addModifiers(Modifier.PUBLIC) .build() ); // values method villagerTypeClass.addMethod( MethodSpec.methodBuilder("values") .addAnnotation(NotNull.class) .returns(ParameterizedTypeName.get(ClassName.get(List.class), villagerTypeClassName)) .addStatement("return $T.VILLAGER_TYPE_REGISTRY.values()", registryClassName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build() ); CodeBlock.Builder staticBlock = CodeBlock.builder(); // Use data for (JsonElement vp : villagerTypes) { JsonObject villagerProfession = vp.getAsJsonObject(); String villagerProfessionName = villagerProfession.get("name").getAsString(); villagerTypeClass.addField( FieldSpec.builder( villagerTypeClassName, villagerProfessionName ).initializer( "new $T($T.from($S))", villagerTypeClassName, namespaceIDClassName, villagerProfession.get("id").getAsString() ).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build() ); // Add to static init. staticBlock.addStatement("$T.VILLAGER_TYPE_REGISTRY.register($N)", registryClassName, villagerProfessionName); } villagerTypeClass.addStaticBlock(staticBlock.build()); // Write files to outputFolder writeFiles( List.of( JavaFile.builder("net.minestom.server.entity.metadata.villager", villagerTypeClass.build()) .indent(" ") .skipJavaLangImports(true) .build() ), outputFolder ); } }