From 987c47d84f3e2fffec3b507c1802f52488ea8fc9 Mon Sep 17 00:00:00 2001 From: Pabilo8 Date: Sun, 13 Aug 2023 09:58:38 +0200 Subject: [PATCH] Added item model generation --- .../annotations/item/GeneratedItemModels.java | 36 +++++++ .../item/GeneratedSubItemModel.java | 18 ++++ .../annotations/item/ItemModelType.java | 27 ++++++ .../annotations/model/GeneratedItemModel.java | 10 -- .../processors/ItemModelProcessor.java | 95 +++++++++++++++++++ .../modworks/processors/SoundProcessor.java | 1 + .../pabilo8/modworks/utils/GeneralUtils.java | 18 ++++ src/test/java/ItemModelProcessorTest.java | 42 ++++++++ src/test/java/McModInfoProcessorTest.java | 15 +-- src/test/resources/test/ItemTestDevice.java | 24 +++++ 10 files changed, 265 insertions(+), 21 deletions(-) create mode 100644 src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedItemModels.java create mode 100644 src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedSubItemModel.java create mode 100644 src/main/java/pl/pabilo8/modworks/annotations/item/ItemModelType.java delete mode 100644 src/main/java/pl/pabilo8/modworks/annotations/model/GeneratedItemModel.java create mode 100644 src/main/java/pl/pabilo8/modworks/processors/ItemModelProcessor.java create mode 100644 src/test/java/ItemModelProcessorTest.java create mode 100644 src/test/resources/test/ItemTestDevice.java diff --git a/src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedItemModels.java b/src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedItemModels.java new file mode 100644 index 0000000..e466288 --- /dev/null +++ b/src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedItemModels.java @@ -0,0 +1,36 @@ +package pl.pabilo8.modworks.annotations.item; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to annotate an enum with item + * @author Pabilo8 + * @since 11.08.2023 + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE}) +public @interface GeneratedItemModels +{ + /** + * @return item name + */ + String itemName(); + + /** + * @return item texture path + */ + String texturePath() default ""; + + /** + * @return base model type of all entries + */ + ItemModelType type() default ItemModelType.ITEM_SIMPLE; + + /** + * @return whether models should only be generated by entries annotated with {@link GeneratedSubItemModel} + */ + boolean onlyInAnnotated() default false; +} diff --git a/src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedSubItemModel.java b/src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedSubItemModel.java new file mode 100644 index 0000000..6a70b4e --- /dev/null +++ b/src/main/java/pl/pabilo8/modworks/annotations/item/GeneratedSubItemModel.java @@ -0,0 +1,18 @@ +package pl.pabilo8.modworks.annotations.item; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to annotate an enum with item + * @author Pabilo8 + * @since 11.08.2023 + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.FIELD}) +public @interface GeneratedSubItemModel +{ + String customTexturePath() default ""; +} diff --git a/src/main/java/pl/pabilo8/modworks/annotations/item/ItemModelType.java b/src/main/java/pl/pabilo8/modworks/annotations/item/ItemModelType.java new file mode 100644 index 0000000..9c377f6 --- /dev/null +++ b/src/main/java/pl/pabilo8/modworks/annotations/item/ItemModelType.java @@ -0,0 +1,27 @@ +package pl.pabilo8.modworks.annotations.item; + +/** + * @author Pabilo8 + * @since 12.08.2023 + */ +public enum ItemModelType +{ + //For simple, batched items like crafting materials + ITEM_SIMPLE("item/generated"), + //For tool item models, like hammers, wrenches, pickaxes + ITEM_SIMPLE_TOOL("item/handheld"), + //For empty item models that will have contents generated dynamically + ITEM_SIMPLE_AUTOREPLACED("item/generated"); + + private final String parentModel; + + ItemModelType(String parentModel) + { + this.parentModel = parentModel; + } + + public String getParentModel() + { + return parentModel; + } +} diff --git a/src/main/java/pl/pabilo8/modworks/annotations/model/GeneratedItemModel.java b/src/main/java/pl/pabilo8/modworks/annotations/model/GeneratedItemModel.java deleted file mode 100644 index 70a68f8..0000000 --- a/src/main/java/pl/pabilo8/modworks/annotations/model/GeneratedItemModel.java +++ /dev/null @@ -1,10 +0,0 @@ -package pl.pabilo8.modworks.annotations.model; - -/** - * @author Pabilo8 - * @since 11.08.2023 - */ -public @interface GeneratedItemModel -{ - String name(); -} diff --git a/src/main/java/pl/pabilo8/modworks/processors/ItemModelProcessor.java b/src/main/java/pl/pabilo8/modworks/processors/ItemModelProcessor.java new file mode 100644 index 0000000..aade59f --- /dev/null +++ b/src/main/java/pl/pabilo8/modworks/processors/ItemModelProcessor.java @@ -0,0 +1,95 @@ +package pl.pabilo8.modworks.processors; + +import com.google.auto.service.AutoService; +import com.google.gson.stream.JsonWriter; +import pl.pabilo8.modworks.annotations.item.GeneratedItemModels; +import pl.pabilo8.modworks.annotations.item.GeneratedSubItemModel; +import pl.pabilo8.modworks.annotations.item.ItemModelType; +import pl.pabilo8.modworks.utils.GeneralUtils; + +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic.Kind; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +@SupportedAnnotationTypes({ + "pl.pabilo8.modworks.annotations.item.GeneratedItemModels", + "pl.pabilo8.modworks.annotations.item.GeneratedSubItemModel" +}) +@SupportedSourceVersion(SourceVersion.RELEASE_8) +@AutoService(Processor.class) +public class ItemModelProcessor extends AbstractModProcessor +{ + @Override + protected boolean doProcessing(Set annotations, RoundEnvironment roundEnv) + { + Set elements = roundEnv.getElementsAnnotatedWith(GeneratedItemModels.class); + for(Element element : elements) + { + GeneratedItemModels itemModel = element.getAnnotation(GeneratedItemModels.class); + List enumValues = GeneralUtils.getEnumValues(element); + + //Model properties + String fileName = itemModel.itemName(); + String texturePath = itemModel.texturePath().isEmpty()?fileName: itemModel.itemName(); + + if(!enumValues.isEmpty()) //is an enum with multiple models + for(Element value : enumValues) + { + GeneratedSubItemModel subModel = value.getAnnotation(GeneratedSubItemModel.class); + if(itemModel.onlyInAnnotated()&&subModel==null) + continue; + + String subName = fileName+"/"+GeneralUtils.simpleNameOf(value); + String subTexture = subName; + + if(subModel!=null&&!subModel.customTexturePath().isEmpty()) + subTexture = subModel.customTexturePath(); + + tryWriteModel(subName, subTexture, itemModel.type()); + + } + else //is a class with a single model + tryWriteModel(fileName, texturePath, itemModel.type()); + } + + + return !elements.isEmpty(); + } + + void tryWriteModel(String modelName, String texturePath, ItemModelType type) + { + try(JsonWriter writer = GeneralUtils.writeJSON(processingEnv, String.format("%s/assets/%s/models/item/%s.json", DIR_RESOURCES, MODID, modelName))) + { + writer.beginObject(); + writer.name("parent").value(type.getParentModel()); + + //Add textures + writer.name("textures").beginObject(); + switch(type) + { + case ITEM_SIMPLE: + case ITEM_SIMPLE_TOOL: + writer.name("layer0").value(String.format("%s:items/%s", MODID, texturePath)); + break; + case ITEM_SIMPLE_AUTOREPLACED: + break; + } + writer.endObject(); + + writer.endObject(); + } catch(IOException e) + { + processingEnv.getMessager().printMessage(Kind.NOTE, + "Could not build a sound file for, "+modelName); + processingEnv.getMessager().printMessage(Kind.NOTE, e.getLocalizedMessage()); + } + } +} diff --git a/src/main/java/pl/pabilo8/modworks/processors/SoundProcessor.java b/src/main/java/pl/pabilo8/modworks/processors/SoundProcessor.java index e195401..3867cf0 100644 --- a/src/main/java/pl/pabilo8/modworks/processors/SoundProcessor.java +++ b/src/main/java/pl/pabilo8/modworks/processors/SoundProcessor.java @@ -23,6 +23,7 @@ }) @SupportedSourceVersion(SourceVersion.RELEASE_8) @AutoService(Processor.class) +//TODO: 13.08.2023 rewrite with json public class SoundProcessor extends AbstractModProcessor { @Override diff --git a/src/main/java/pl/pabilo8/modworks/utils/GeneralUtils.java b/src/main/java/pl/pabilo8/modworks/utils/GeneralUtils.java index 3381980..ba9834b 100644 --- a/src/main/java/pl/pabilo8/modworks/utils/GeneralUtils.java +++ b/src/main/java/pl/pabilo8/modworks/utils/GeneralUtils.java @@ -1,13 +1,19 @@ package pl.pabilo8.modworks.utils; +import com.google.common.base.Functions; import com.google.gson.stream.JsonWriter; import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; import javax.tools.FileObject; import javax.tools.StandardLocation; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; /** * @author Pabilo8 @@ -37,4 +43,16 @@ public static JsonWriter writeJSON(ProcessingEnvironment env, String path) throw writer.setIndent("\t"); return writer; } + + public static List getEnumValues(Element elementEnum) + { + return elementEnum.getEnclosedElements().stream() + .filter(element -> element.getKind().equals(ElementKind.ENUM_CONSTANT)) + .collect(Collectors.toList()); + } + + public static String simpleNameOf(Element element) + { + return element.getSimpleName().toString().toLowerCase(); + } } diff --git a/src/test/java/ItemModelProcessorTest.java b/src/test/java/ItemModelProcessorTest.java new file mode 100644 index 0000000..76400fe --- /dev/null +++ b/src/test/java/ItemModelProcessorTest.java @@ -0,0 +1,42 @@ +import com.google.testing.compile.JavaFileObjects; +import org.junit.jupiter.api.Test; +import pl.pabilo8.modworks.processors.ItemModelProcessor; + +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; + +import java.nio.charset.StandardCharsets; + +import static com.google.common.truth.Truth.assertAbout; +import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * @author Pabilo8 + * @since 01.08.2023 + */ +class ItemModelProcessorTest +{ + public static final JavaFileObject SOURCE = JavaFileObjects.forResource("test/ItemTestDevice.java"); + public static final JavaFileObject MCMOD = JavaFileObjects.forResource("jsons/mcmod.info"); + + @Test + void doProcessing() + { + final CharSequence[] text = new CharSequence[1]; + assertDoesNotThrow(() -> text[0] = MCMOD.getCharContent(true)); + + assertAbout(javaSource()) + .that(SOURCE) + .withCompilerOptions("-Amodworks.modid=testmod") + .withCompilerOptions("-Amodworks.mcmod=true") + .processedWith(new ItemModelProcessor()) + .compilesWithoutError() + .and() + .generatesFileNamed(StandardLocation.SOURCE_OUTPUT, "resources/assets/testmod/models/item/test_device", "test1.json") + .and() + .generatesFileNamed(StandardLocation.SOURCE_OUTPUT, "resources/assets/testmod/models/item/test_device", "test2.json") + .and() + .generatesFileNamed(StandardLocation.SOURCE_OUTPUT, "resources/assets/testmod/models/item/test_device", "test3.json"); + } +} \ No newline at end of file diff --git a/src/test/java/McModInfoProcessorTest.java b/src/test/java/McModInfoProcessorTest.java index 92def0a..9bc59c9 100644 --- a/src/test/java/McModInfoProcessorTest.java +++ b/src/test/java/McModInfoProcessorTest.java @@ -1,8 +1,6 @@ -import com.google.common.collect.ImmutableList; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.testing.compile.*; +import com.google.testing.compile.Compilation; +import com.google.testing.compile.CompilationSubject; +import com.google.testing.compile.JavaFileObjects; import org.junit.After; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -10,19 +8,14 @@ import javax.tools.JavaFileObject; import javax.tools.StandardLocation; - import java.io.IOException; -import java.lang.Compiler; import java.util.Arrays; import java.util.Optional; import java.util.stream.Collectors; import static com.google.common.truth.Truth.assertAbout; -import static com.google.common.truth.Truth.assertThat; import static com.google.testing.compile.Compiler.javac; import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; /** @@ -95,6 +88,6 @@ private String strip(String text) { return Arrays.stream(text.split("\n")) .map(String::trim).collect(Collectors.joining()) - .replaceAll(" ",""); + .replaceAll(" ", ""); } } \ No newline at end of file diff --git a/src/test/resources/test/ItemTestDevice.java b/src/test/resources/test/ItemTestDevice.java new file mode 100644 index 0000000..f4c0e22 --- /dev/null +++ b/src/test/resources/test/ItemTestDevice.java @@ -0,0 +1,24 @@ +package test; + +import pl.pabilo8.modworks.annotations.item.GeneratedItemModels; +import pl.pabilo8.modworks.annotations.item.GeneratedSubItemModel; +import pl.pabilo8.modworks.annotations.item.ItemModelType; +import pl.pabilo8.modworks.annotations.sound.ModSound; +import pl.pabilo8.modworks.annotations.MCModInfo; + +/** + * @author Pabilo8 + * @since 01.08.2023 + */ +public class ItemTestDevice +{ + + @GeneratedItemModels(itemName = "test_device") + public enum Devices + { + TEST1, + @GeneratedSubItemModel(customTexturePath = "nucleardevice") + TEST2, + TEST3; + } +} \ No newline at end of file