Minestom/code-generators/src/main/java/net/minestom/codegen/attribute/AttributeGenerator.java

254 lines
12 KiB
Java

package net.minestom.codegen.attribute;
import com.google.gson.*;
import com.google.gson.stream.JsonReader;
import com.squareup.javapoet.*;
import net.minestom.codegen.MinestomCodeGenerator;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.lang.model.element.Modifier;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
public final class AttributeGenerator extends MinestomCodeGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(AttributeGenerator.class);
private final File attributesFile;
private final File outputFolder;
public AttributeGenerator(@NotNull File attributesFile, @NotNull File outputFolder) {
this.attributesFile = attributesFile;
this.outputFolder = outputFolder;
}
@Override
public void generate() {
if (!attributesFile.exists()) {
LOGGER.error("Failed to find attributes.json.");
LOGGER.error("Stopped code generation for attributes.");
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 attributes;
try {
attributes = GSON.fromJson(new JsonReader(new FileReader(attributesFile)), JsonArray.class);
} catch (FileNotFoundException e) {
LOGGER.error("Failed to find attributes.json.");
LOGGER.error("Stopped code generation for attributes.");
return;
}
List<JavaFile> filesToWrite = new ArrayList<>();
ClassName attributeClassName = ClassName.get("net.minestom.server.attribute", "Attribute");
// Attribute
TypeSpec.Builder attributeClass = TypeSpec.classBuilder(attributeClassName)
.addSuperinterface(ClassName.get("net.kyori.adventure.key", "Keyed"))
.addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName());
attributeClass.addField(
FieldSpec.builder(namespaceIDClassName, "id")
.addModifiers(Modifier.PRIVATE, Modifier.FINAL).addAnnotation(NotNull.class).build()
);
attributeClass.addField(
FieldSpec.builder(TypeName.DOUBLE, "defaultValue")
.addModifiers(Modifier.PRIVATE, Modifier.FINAL).build()
);
attributeClass.addField(
FieldSpec.builder(TypeName.BOOLEAN, "clientSyncable")
.addModifiers(Modifier.PRIVATE, Modifier.FINAL).build()
);
attributeClass.addMethod(
MethodSpec.constructorBuilder()
.addParameter(ParameterSpec.builder(namespaceIDClassName, "id").addAnnotation(NotNull.class).build())
.addParameter(ParameterSpec.builder(TypeName.BOOLEAN, "clientSyncable").build())
.addParameter(ParameterSpec.builder(TypeName.DOUBLE, "defaultValue").build())
.addStatement("this.id = id")
.addStatement("this.clientSyncable = clientSyncable")
.addStatement("this.defaultValue = defaultValue")
.addModifiers(Modifier.PROTECTED)
.build()
);
// Override key method (adventure)
attributeClass.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
attributeClass.addMethod(
MethodSpec.methodBuilder("getId")
.returns(namespaceIDClassName)
.addAnnotation(NotNull.class)
.addStatement("return this.id")
.addModifiers(Modifier.PUBLIC)
.build()
);
// getDefaultValue
attributeClass.addMethod(
MethodSpec.methodBuilder("getDefaultValue")
.returns(TypeName.DOUBLE)
.addStatement("return this.defaultValue")
.addModifiers(Modifier.PUBLIC)
.build()
);
// isClientSyncable
attributeClass.addMethod(
MethodSpec.methodBuilder("isClientSyncable")
.returns(TypeName.BOOLEAN)
.addStatement("return this.clientSyncable")
.addModifiers(Modifier.PUBLIC)
.build()
);
// isShared
attributeClass.addMethod(
MethodSpec.methodBuilder("isShared")
.addAnnotation(Deprecated.class)
.returns(TypeName.BOOLEAN)
.addStatement("return this.clientSyncable")
.addModifiers(Modifier.PUBLIC)
.build()
);
// values method
attributeClass.addMethod(
MethodSpec.methodBuilder("values")
.addAnnotation(NotNull.class)
.returns(ParameterizedTypeName.get(ClassName.get(List.class), attributeClassName))
.addStatement("return $T.ATTRIBUTE_REGISTRY.values()", registryClassName)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.build()
);
// toString method
attributeClass.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()
);
// Creating ClampedAttribute
ClassName clampedAttributeClassName = ClassName.get("net.minestom.server.attribute", "ClampedAttribute");
TypeSpec.Builder clampedAttributeClass = TypeSpec.classBuilder(clampedAttributeClassName)
.superclass(attributeClassName)
.addModifiers(Modifier.PUBLIC).addJavadoc("AUTOGENERATED by " + getClass().getSimpleName());
clampedAttributeClass.addField(
FieldSpec.builder(TypeName.DOUBLE, "minValue")
.addModifiers(Modifier.PRIVATE, Modifier.FINAL).build()
);
clampedAttributeClass.addField(
FieldSpec.builder(TypeName.DOUBLE, "maxValue")
.addModifiers(Modifier.PRIVATE, Modifier.FINAL).build()
);
clampedAttributeClass.addMethod(
MethodSpec.constructorBuilder()
.addParameter(ParameterSpec.builder(namespaceIDClassName, "id").addAnnotation(NotNull.class).build())
.addParameter(ParameterSpec.builder(TypeName.BOOLEAN, "clientSyncable").build())
.addParameter(ParameterSpec.builder(TypeName.DOUBLE, "defaultValue").build())
.addParameter(ParameterSpec.builder(TypeName.DOUBLE, "minValue").build())
.addParameter(ParameterSpec.builder(TypeName.DOUBLE, "maxValue").build())
.addStatement("super(id, clientSyncable, defaultValue)")
.addStatement("this.minValue = minValue")
.addStatement("this.maxValue = maxValue")
.addModifiers(Modifier.PROTECTED)
.build()
);
// getMinValue
clampedAttributeClass.addMethod(
MethodSpec.methodBuilder("getMinValue")
.returns(TypeName.DOUBLE)
.addStatement("return this.minValue")
.addModifiers(Modifier.PUBLIC)
.build()
);
// getMaxValue
clampedAttributeClass.addMethod(
MethodSpec.methodBuilder("getMaxValue")
.returns(TypeName.DOUBLE)
.addStatement("return this.maxValue")
.addModifiers(Modifier.PUBLIC)
.build()
);
CodeBlock.Builder staticBlock = CodeBlock.builder();
// Use data
for (JsonElement a : attributes) {
JsonObject attribute = a.getAsJsonObject();
String attributeName = attribute.get("name").getAsString();
JsonObject range = attribute.getAsJsonObject("range");
if (range == null) {
// Normal attribute
attributeClass.addField(
FieldSpec.builder(
attributeClassName,
attributeName
).initializer(
"new $T($T.from($S), $L, $L)",
attributeClassName,
namespaceIDClassName,
attribute.get("id").getAsString(),
attribute.get("clientSync").getAsBoolean(),
attribute.get("defaultValue").getAsDouble()
).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build()
);
} else {
// ClampedAttribute
attributeClass.addField(
FieldSpec.builder(
attributeClassName,
attributeName
).initializer(
"new $T($T.from($S), $L, $L, $L, $L)",
clampedAttributeClassName,
namespaceIDClassName,
attribute.get("id").getAsString(),
attribute.get("clientSync").getAsBoolean(),
attribute.get("defaultValue").getAsDouble(),
range.get("minValue").getAsDouble(),
range.get("maxValue").getAsDouble()
).addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).build()
);
}
// Add to static init.
staticBlock.addStatement("$T.ATTRIBUTE_REGISTRY.register($N)", registryClassName, attributeName);
}
attributeClass.addStaticBlock(staticBlock.build());
filesToWrite.add(
JavaFile.builder("net.minestom.server.attribute", attributeClass.build())
.indent(" ")
.skipJavaLangImports(true)
.build()
);
filesToWrite.add(
JavaFile.builder("net.minestom.server.attribute", clampedAttributeClass.build())
.indent(" ")
.skipJavaLangImports(true)
.build()
);
// Write files to outputFolder
writeFiles(
filesToWrite,
outputFolder
);
}
}