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 VillagerProfessionGenerator extends MinestomCodeGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(VillagerProfessionGenerator.class); private final InputStream villagerProfessionsFile; private final File outputFolder; public VillagerProfessionGenerator(@Nullable InputStream villagerProfessionsFile, @NotNull File outputFolder) { this.villagerProfessionsFile = villagerProfessionsFile; this.outputFolder = outputFolder; } @Override public void generate() { if (villagerProfessionsFile == null) { LOGGER.error("Failed to find villager_professions.json."); LOGGER.error("Stopped code generation for villager professions."); 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 rawVillagerProfessionDataClassName = ClassName.get("net.minestom.server.raw_data", "RawVillagerProfessionData"); ClassName registryClassName = ClassName.get("net.minestom.server.registry", "Registry"); JsonArray villagerProfessions = GSON.fromJson(new InputStreamReader(villagerProfessionsFile), JsonArray.class); ClassName villagerProfessionClassName = ClassName.get("net.minestom.server.entity.metadata.villager", "VillagerProfession"); // Particle TypeSpec.Builder villagerProfessionClass = TypeSpec.classBuilder(villagerProfessionClassName) .addSuperinterface(ClassName.get("net.kyori.adventure.key", "Keyed")) .addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName()); villagerProfessionClass.addField( FieldSpec.builder(namespaceIDClassName, "id") .addModifiers(Modifier.PRIVATE, Modifier.FINAL).addAnnotation(NotNull.class).build() ); villagerProfessionClass.addField( FieldSpec.builder(rawVillagerProfessionDataClassName, "villagerProfessionData") .addModifiers(Modifier.PRIVATE, Modifier.VOLATILE) .addAnnotation(NotNull.class) .build() ); villagerProfessionClass.addMethod( MethodSpec.constructorBuilder() .addParameter(ParameterSpec.builder(namespaceIDClassName, "id").addAnnotation(NotNull.class).build()) .addParameter(ParameterSpec.builder(rawVillagerProfessionDataClassName, "villagerProfessionData").addAnnotation(NotNull.class).build()) .addStatement("this.id = id") .addStatement("this.villagerProfessionData = villagerProfessionData") .addModifiers(Modifier.PROTECTED) .build() ); // Override key method (adventure) villagerProfessionClass.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 villagerProfessionClass.addMethod( MethodSpec.methodBuilder("getId") .returns(namespaceIDClassName) .addAnnotation(NotNull.class) .addStatement("return this.id") .addModifiers(Modifier.PUBLIC) .build() ); // getVillagerProfessionData method villagerProfessionClass.addMethod( MethodSpec.methodBuilder("getVillagerProfessionData") .returns(rawVillagerProfessionDataClassName) .addAnnotation(NotNull.class) .addStatement("return this.villagerProfessionData") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .build() ); // setVillagerProfessionData method villagerProfessionClass.addMethod( MethodSpec.methodBuilder("setVillagerProfessionData") .addParameter(ParameterSpec.builder(rawVillagerProfessionDataClassName, "villagerProfessionData").addAnnotation(NotNull.class).build()) .addStatement("this.villagerProfessionData = villagerProfessionData") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .build() ); // getNumericalId villagerProfessionClass.addMethod( MethodSpec.methodBuilder("getNumericalId") .returns(TypeName.INT) .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.getId(this)", registryClassName) .addModifiers(Modifier.PUBLIC) .build() ); // fromId Method villagerProfessionClass.addMethod( MethodSpec.methodBuilder("fromId") .returns(villagerProfessionClassName) .addAnnotation(Nullable.class) .addParameter(TypeName.INT, "id") .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.get((short) id)", registryClassName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build() ); // fromId Method villagerProfessionClass.addMethod( MethodSpec.methodBuilder("fromId") .returns(villagerProfessionClassName) .addAnnotation(NotNull.class) .addParameter(ClassName.get("net.kyori.adventure.key", "Key"), "id") .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.get(id)", registryClassName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build() ); // toString method villagerProfessionClass.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 villagerProfessionClass.addMethod( MethodSpec.methodBuilder("values") .addAnnotation(NotNull.class) .returns(ParameterizedTypeName.get(ClassName.get(List.class), villagerProfessionClassName)) .addStatement("return $T.VILLAGER_PROFESSION_REGISTRY.values()", registryClassName) .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build() ); CodeBlock.Builder staticBlock = CodeBlock.builder(); // Use data for (JsonElement vp : villagerProfessions) { JsonObject villagerProfession = vp.getAsJsonObject(); String villagerProfessionName = villagerProfession.get("name").getAsString(); JsonElement workSound = villagerProfession.get("workSound"); if (workSound == null) { villagerProfessionClass.addField( FieldSpec.builder( villagerProfessionClassName, villagerProfessionName ).initializer( "new $T($T.from($S), new $T(() -> null))", villagerProfessionClassName, namespaceIDClassName, villagerProfession.get("id").getAsString(), rawVillagerProfessionDataClassName ).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build() ); } else { villagerProfessionClass.addField( FieldSpec.builder( villagerProfessionClassName, villagerProfessionName ).initializer( "new $T($T.from($S), new $T(() -> $T.SOUND_EVENT_REGISTRY.get($S)))", villagerProfessionClassName, namespaceIDClassName, villagerProfession.get("id").getAsString(), rawVillagerProfessionDataClassName, registryClassName, workSound.getAsString() ).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build() ); } // Add to static init. staticBlock.addStatement("$T.VILLAGER_PROFESSION_REGISTRY.register($N)", registryClassName, villagerProfessionName); } villagerProfessionClass.addStaticBlock(staticBlock.build()); // Write files to outputFolder writeFiles( List.of( JavaFile.builder("net.minestom.server.entity.metadata.villager", villagerProfessionClass.build()) .indent(" ") .skipJavaLangImports(true) .build() ), outputFolder ); } }