From b2b5e4f0030a23f162914d0ff2fb863343d0f822 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 01:44:58 +0100 Subject: [PATCH 01/10] Update to Architectury 1.18.1 --- .gitignore | 36 +-- build.gradle | 198 +++--------- common/build.gradle | 25 ++ .../ClientTickHandler.java | 33 +- .../itemtransformhelper/HUDTextRenderer.java | 259 +++++++++++++++ .../java/itemtransformhelper/ItemCamera.java | 32 ++ .../ItemModelFlexibleCamera.java | 109 +++++++ .../ItemTransformHelper.java | 12 + .../MenuItemCameraTransforms.java | 255 +++++++++++++++ .../ModelBakeEventHandler.java | 50 +++ .../main/java/itemtransformhelper/Notes.txt | 0 .../StartupClientOnly.java | 31 ++ .../itemtransformhelper/StartupCommon.java | 40 +++ .../itemtransformhelper/lang/en_us.json | 4 + .../models/item/item_camera.json | 144 +++++++++ .../textures/items/item_camera_icon.png | Bin fabric/build.gradle | 75 +++++ .../fabric/ItemTransformHelperFabric.java | 15 + .../fabric/MenuItemCameraTransformsImpl.java | 20 ++ .../fabric/StartupClientOnlyImpl.java | 8 + .../fabric/mixin/BakedModelManagerMixin.java | 31 ++ .../fabric/mixin/InGameHudMixin.java | 21 ++ .../fabric/mixin/MinecraftClientMixin.java | 22 ++ fabric/src/main/resources/fabric.mod.json | 34 ++ .../resources/itemtransformhelper.mixins.json | 16 + forge/build.gradle | 76 +++++ forge/gradle.properties | 1 + .../forge/ItemTransformHelperForge.java | 21 +- .../forge/MenuItemCameraTransformsImpl.java | 39 +++ .../forge/StartupClientOnlyImpl.java | 32 ++ forge/src/main/resources/META-INF/mods.toml | 34 ++ forge/src/main/resources/pack.mcmeta | 6 + gradle.properties | 20 +- gradle/wrapper/gradle-wrapper.jar | Bin 54708 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 282 +++++++++------- gradlew.bat | 43 +-- settings.gradle | 14 + .../itemtransformhelper/CreativeTabITH.java | 22 -- .../itemtransformhelper/HUDtextRenderer.java | 300 ------------------ .../java/itemtransformhelper/ItemCamera.java | 31 -- .../ItemModelFlexibleCamera.java | 65 ---- .../MenuItemCameraTransforms.java | 299 ----------------- .../ModelBakeEventHandler.java | 48 --- .../StartupClientOnly.java | 29 -- .../itemtransformhelper/StartupCommon.java | 30 -- src/main/resources/META-INF/mods.toml | 24 -- .../itemtransformhelper/lang/en_us.json | 4 - .../models/item/item_camera.json | 47 --- src/main/resources/pack.mcmeta | 7 - 50 files changed, 1710 insertions(+), 1236 deletions(-) create mode 100644 common/build.gradle rename {src => common/src}/main/java/itemtransformhelper/ClientTickHandler.java (53%) create mode 100644 common/src/main/java/itemtransformhelper/HUDTextRenderer.java create mode 100644 common/src/main/java/itemtransformhelper/ItemCamera.java create mode 100644 common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java create mode 100644 common/src/main/java/itemtransformhelper/ItemTransformHelper.java create mode 100644 common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java create mode 100644 common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java rename {src => common/src}/main/java/itemtransformhelper/Notes.txt (100%) create mode 100644 common/src/main/java/itemtransformhelper/StartupClientOnly.java create mode 100644 common/src/main/java/itemtransformhelper/StartupCommon.java create mode 100644 common/src/main/resources/assets/itemtransformhelper/lang/en_us.json create mode 100644 common/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json rename {src => common/src}/main/resources/assets/itemtransformhelper/textures/items/item_camera_icon.png (100%) create mode 100644 fabric/build.gradle create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java create mode 100644 fabric/src/main/resources/fabric.mod.json create mode 100644 fabric/src/main/resources/itemtransformhelper.mixins.json create mode 100644 forge/build.gradle create mode 100644 forge/gradle.properties rename src/main/java/itemtransformhelper/ItemTransformHelper.java => forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java (66%) create mode 100644 forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java create mode 100644 forge/src/main/java/itemtransformhelper/forge/StartupClientOnlyImpl.java create mode 100644 forge/src/main/resources/META-INF/mods.toml create mode 100644 forge/src/main/resources/pack.mcmeta create mode 100644 settings.gradle delete mode 100644 src/main/java/itemtransformhelper/CreativeTabITH.java delete mode 100644 src/main/java/itemtransformhelper/HUDtextRenderer.java delete mode 100644 src/main/java/itemtransformhelper/ItemCamera.java delete mode 100644 src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java delete mode 100644 src/main/java/itemtransformhelper/MenuItemCameraTransforms.java delete mode 100644 src/main/java/itemtransformhelper/ModelBakeEventHandler.java delete mode 100644 src/main/java/itemtransformhelper/StartupClientOnly.java delete mode 100644 src/main/java/itemtransformhelper/StartupCommon.java delete mode 100644 src/main/resources/META-INF/mods.toml delete mode 100644 src/main/resources/assets/itemtransformhelper/lang/en_us.json delete mode 100644 src/main/resources/assets/itemtransformhelper/models/item/item_camera.json delete mode 100644 src/main/resources/pack.mcmeta diff --git a/.gitignore b/.gitignore index 12f86447..ccb0c562 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,19 @@ -# eclipse -bin -*.launch -.settings -.metadata -.classpath -.project - -# idea -out +build/ *.ipr +run/ *.iws +out/ *.iml -.idea - -# gradle -build -.gradle +.gradle/ +output/ +bin/ +libs/ -# other -eclipse -run - -# Files from Forge MDK -forge*changelog.txt +.classpath +.project +.idea/ +classes/ +.metadata +.vscode +.settings +*.launch \ No newline at end of file diff --git a/build.gradle b/build.gradle index 31450988..dcb2037e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,147 +1,51 @@ -buildscript { - repositories { - maven { url = 'https://files.minecraftforge.net/maven' } - jcenter() - mavenCentral() - } - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true - } -} -apply plugin: 'net.minecraftforge.gradle' -// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -apply plugin: 'eclipse' -apply plugin: 'maven-publish' - -version = '1.0' -group = 'thegreyghost' // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = 'itemtransformhelper' - -sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. - -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) -minecraft { - // The mappings can be changed at any time, and must be in the following format. - // snapshot_YYYYMMDD Snapshot are built nightly. - // stable_# Stables are built at the discretion of the MCP team. - // Use non-default mappings at your own risk. they may not always work. - // Simply re-run your setup task after changing the mappings to update your workspace. - mappings channel: 'snapshot', version: '20200723-1.16.1' - // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. - - // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - - // Default run configurations. - // These can be tweaked, removed, or duplicated as needed. - runs { - client { - workingDirectory project.file('run') - - // Recommended logging data for a userdev environment - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - - // Recommended logging level for the console - property 'forge.logging.console.level', 'debug' - - mods { - itemtransformhelper { - source sourceSets.main - } - } - } - - server { - workingDirectory project.file('run') - - // Recommended logging data for a userdev environment - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - - // Recommended logging level for the console - property 'forge.logging.console.level', 'debug' - - mods { - itemtransformhelper { - source sourceSets.main - } - } - } - - data { - workingDirectory project.file('run') - - // Recommended logging data for a userdev environment - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - - // Recommended logging level for the console - property 'forge.logging.console.level', 'debug' - - args '--mod', 'itemtransformhelper', '--all', '--output', file('src/generated/resources/') - - mods { - itemtransformhelper { - source sourceSets.main - } - } - } - } -} - -dependencies { - // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed - // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. - // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft 'net.minecraftforge:forge:1.16.1-32.0.108' - - // You may put jars on which you depend on in ./libs or you may define them like so.. - // compile "some.group:artifact:version:classifier" - // compile "some.group:artifact:version" - - // Real examples - // compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env - // compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env - - // The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. - // provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' - - // These dependencies get remapped to your current MCP mappings - // deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev' - - // For more info... - // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html - // http://www.gradle.org/docs/current/userguide/dependency_management.html - -} - -// Example for how to get properties into the manifest for reading by the runtime.. -jar { - manifest { - attributes([ - "Specification-Title": "itemtransformhelper", - "Specification-Vendor": "tgg", - "Specification-Version": "1", // We are version 1 of ourselves - "Implementation-Title": project.name, - "Implementation-Version": "${version}", - "Implementation-Vendor" :"tgg", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - ]) - } -} - -// Example configuration to allow publishing using the maven-publish task -// This is the preferred method to reobfuscate your jar file -jar.finalizedBy('reobfJar') -// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing -//publish.dependsOn('reobfJar') - -publishing { - publications { - mavenJava(MavenPublication) { - artifact jar - } - } - repositories { - maven { - url "file:///${project.projectDir}/mcmodsrepo" - } - } -} +plugins { + id "architectury-plugin" version "3.4-SNAPSHOT" + id "dev.architectury.loom" version "0.10.0-SNAPSHOT" apply false +} + +architectury { + minecraft = rootProject.minecraft_version +} + +subprojects { + apply plugin: "dev.architectury.loom" + + loom { + silentMojangMappingsLicense() + } + + dependencies { + minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" + // The following line declares the mojmap mappings, you may use other mappings as well + // mappings loom.officialMojangMappings() + // The following line declares the yarn mappings you may select this one as well. + mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2" + } +} + +allprojects { + apply plugin: "java" + apply plugin: "architectury-plugin" + apply plugin: "maven-publish" + + archivesBaseName = rootProject.archives_base_name + version = rootProject.mod_version + group = rootProject.maven_group + + repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. + } + + tasks.withType(JavaCompile) { + options.encoding = "UTF-8" + options.release = 17 + } + + java { + withSourcesJar() + } +} diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 00000000..c253f86f --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,25 @@ +dependencies { + // We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies + // Do NOT use other classes from fabric loader + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + // Remove the next line if you don't want to depend on the API + modApi "dev.architectury:architectury:${rootProject.architectury_version}" +} + +architectury { + common() +} + +publishing { + publications { + mavenCommon(MavenPublication) { + artifactId = rootProject.archives_base_name + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + } +} diff --git a/src/main/java/itemtransformhelper/ClientTickHandler.java b/common/src/main/java/itemtransformhelper/ClientTickHandler.java similarity index 53% rename from src/main/java/itemtransformhelper/ClientTickHandler.java rename to common/src/main/java/itemtransformhelper/ClientTickHandler.java index 9c14aab9..c7d3f754 100644 --- a/src/main/java/itemtransformhelper/ClientTickHandler.java +++ b/common/src/main/java/itemtransformhelper/ClientTickHandler.java @@ -1,13 +1,11 @@ package itemtransformhelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.player.ClientPlayerEntity; -import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; -import net.minecraft.util.Hand; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; /** * User: The Grey Ghost @@ -15,21 +13,16 @@ * Every tick, check all the items in the hotbar to see if any are the camera If so, apply the transform * override to the held item. */ -@SuppressWarnings("deprecation") public class ClientTickHandler { - @SubscribeEvent - public void clientTickEvent(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.START) { - return; - } - ClientPlayerEntity player = Minecraft.getInstance().player; + public void clientTickEvent() { + ClientPlayerEntity player = MinecraftClient.getInstance().player; if (player == null) return; boolean foundCamera = false; - PlayerInventory inventoryPlayer = player.inventory; + PlayerInventory inventoryPlayer = player.getInventory(); for (int i = 0; i < PlayerInventory.getHotbarSize(); ++i) { - ItemStack slotItemStack = inventoryPlayer.mainInventory.get(i); + ItemStack slotItemStack = inventoryPlayer.main.get(i); if (slotItemStack.getItem() == StartupCommon.ITEM_CAMERA.get()) { foundCamera = true; break; @@ -37,14 +30,15 @@ public void clientTickEvent(TickEvent.ClientTickEvent event) { } StartupClientOnly.menuItemCameraTransforms.changeMenuVisible(foundCamera); - IBakedModel ibakedmodel = null; + BakedModel ibakedmodel = null; if (foundCamera) { - ItemStack heldItemStack = player.getHeldItem(Hand.MAIN_HAND); + ItemStack heldItemStack = player.getEquippedStack(EquipmentSlot.MAINHAND); if (heldItemStack.isEmpty()) { - heldItemStack = player.getHeldItem(Hand.OFF_HAND); + heldItemStack = player.getEquippedStack(EquipmentSlot.OFFHAND); } if (!heldItemStack.isEmpty()) { - ibakedmodel = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getItemModel(heldItemStack); + ibakedmodel = + MinecraftClient.getInstance().getItemRenderer().getModels().getModel(heldItemStack); } } @@ -52,4 +46,5 @@ public void clientTickEvent(TickEvent.ClientTickEvent event) { link.itemModelToOverride = ibakedmodel; link.forcedTransform = StartupClientOnly.menuItemCameraTransforms.getItemCameraTransforms(); } + } diff --git a/common/src/main/java/itemtransformhelper/HUDTextRenderer.java b/common/src/main/java/itemtransformhelper/HUDTextRenderer.java new file mode 100644 index 00000000..1bbd85b4 --- /dev/null +++ b/common/src/main/java/itemtransformhelper/HUDTextRenderer.java @@ -0,0 +1,259 @@ +package itemtransformhelper; + +import java.util.ArrayList; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.render.model.json.Transformation; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Vec3f; + +/** + * User: The Grey Ghost + * Date: 20/01/2015 + * Class to draw the menu on the screen + */ +public class HUDTextRenderer { + + private final HUDInfoUpdateLink hudInfoUpdateLink; + + /** + * Create the HUDTextRenderer; caller needs to register this class on the forge event bus + * + * @param hudInfoUpdateLink the menu state information needed to draw the Heads Up Display + */ + public HUDTextRenderer(HUDInfoUpdateLink hudInfoUpdateLink) { + this.hudInfoUpdateLink = hudInfoUpdateLink; + } + + /** + * Draw the Head Up Display menu on screen. + * The information is taken from the hudInfoUpdateLink which is updated by other classes. + */ + public void displayHUDText(MatrixStack matrixStack) { + if (hudInfoUpdateLink == null || !hudInfoUpdateLink.menuVisible || hudInfoUpdateLink.itemCameraTransforms == null) + return; + ArrayList displayText = new ArrayList<>(); + ArrayList selectableField = new ArrayList<>(); + + final HUDInfoUpdateLink.SelectedField NOT_SELECTABLE = null; + + displayText.add("======"); + selectableField.add(NOT_SELECTABLE); + displayText.add("VIEW "); + selectableField.add(NOT_SELECTABLE); + Transformation transformVec3f; + + switch (hudInfoUpdateLink.selectedTransform) { + case THIRD_LEFT -> { + displayText.add("3rd-L"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.thirdPersonLeftHand; + } + case THIRD_RIGHT -> { + displayText.add("3rd-R"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.thirdPersonRightHand; + } + case FIRST_LEFT -> { + displayText.add("1st-L"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.firstPersonLeftHand; + } + case FIRST_RIGHT -> { + displayText.add("1st-R"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.firstPersonRightHand; + } + case GUI -> { + displayText.add("gui"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.gui; + } + case HEAD -> { + displayText.add("head"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.head; + } + case FIXED -> { + displayText.add("fixed"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.fixed; + } + case GROUND -> { + displayText.add("grnd"); + transformVec3f = hudInfoUpdateLink.itemCameraTransforms.ground; + } + default -> { + throw new IllegalArgumentException("Unknown cameraTransformType:" + hudInfoUpdateLink.selectedTransform); + } + } + selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSFORM); + + displayText.add("======"); + selectableField.add(NOT_SELECTABLE); + displayText.add("SCALE"); + selectableField.add(NOT_SELECTABLE); + displayText.add("X:" + String.format("%.2f", transformVec3f.scale.getX())); + selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_X); + displayText.add("Y:" + String.format("%.2f", transformVec3f.scale.getY())); + selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_Y); + displayText.add("Z:" + String.format("%.2f", transformVec3f.scale.getZ())); + selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_Z); + + displayText.add("======"); + selectableField.add(NOT_SELECTABLE); + displayText.add("ROTATE"); + selectableField.add(NOT_SELECTABLE); + displayText.add("X:" + String.format("%3.0f", transformVec3f.rotation.getX())); + selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_X); + displayText.add("Y:" + String.format("%3.0f", transformVec3f.rotation.getY())); + selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_Y); + displayText.add("Z:" + String.format("%3.0f", transformVec3f.rotation.getZ())); + selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_Z); + + final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see ItemTransformVec3f::deserialize0() + displayText.add("======"); + selectableField.add(NOT_SELECTABLE); + displayText.add("TRANSL"); + selectableField.add(NOT_SELECTABLE); + displayText.add("X:" + String.format("%.2f", transformVec3f.translation.getX() * TRANSLATE_MULTIPLIER)); + selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_X); + displayText.add("Y:" + String.format("%.2f", transformVec3f.translation.getY() * TRANSLATE_MULTIPLIER)); + selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_Y); + displayText.add("Z:" + String.format("%.2f", transformVec3f.translation.getZ() * TRANSLATE_MULTIPLIER)); + selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_Z); + + displayText.add("======"); + selectableField.add(NOT_SELECTABLE); + displayText.add("RESET"); + selectableField.add(HUDInfoUpdateLink.SelectedField.RESTORE_DEFAULT); + displayText.add("RSTALL"); + selectableField.add(HUDInfoUpdateLink.SelectedField.RESTORE_DEFAULT_ALL); + displayText.add("PRINT"); + selectableField.add(HUDInfoUpdateLink.SelectedField.PRINT); + displayText.add("======"); + selectableField.add(NOT_SELECTABLE); + + TextRenderer fontRenderer = MinecraftClient.getInstance().textRenderer; + int ypos = 2; + int xpos = 2; + for (int i = 0; i < displayText.size(); ++i) { + String msg = displayText.get(i); + ypos += fontRenderer.fontHeight; + if (msg == null) continue; + final int MED_GRAY_HALF_TRANSPARENT = 0x6FAFAFB0; + final int GREEN_HALF_TRANSPARENT = 0x6F00FF00; + boolean fieldIsSelected = (hudInfoUpdateLink.selectedField == selectableField.get(i)); + int highlightColour = fieldIsSelected ? GREEN_HALF_TRANSPARENT : MED_GRAY_HALF_TRANSPARENT; + DrawableHelper.fill(matrixStack, xpos - 1, ypos - 1, xpos + fontRenderer.getWidth(msg) + 1, + ypos + fontRenderer.fontHeight - 1, highlightColour); + final int LIGHT_GRAY = 0xE0E0E0; + final int BLACK = 0x000000; + int stringColour = fieldIsSelected ? BLACK : LIGHT_GRAY; + fontRenderer.draw(matrixStack, msg, xpos, ypos, stringColour); + } + } + + /** + * Used to provide the information that the HUDTextRenderer needs to draw the menu + */ + public static class HUDInfoUpdateLink { + public ModelTransformation itemCameraTransforms; + public SelectedField selectedField; + public TransformName selectedTransform; + public boolean menuVisible; + + public HUDInfoUpdateLink() { + final Vec3f ROTATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); + final Vec3f TRANSLATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); + final Vec3f SCALE_DEFAULT = new Vec3f(1.0F, 1.0F, 1.0F); + + Transformation itvThirdLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, + SCALE_DEFAULT); + Transformation itvThirdRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, + SCALE_DEFAULT); + Transformation itvFirstLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, + SCALE_DEFAULT); + Transformation itvFirstRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, + SCALE_DEFAULT); + Transformation itvHead = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation itvGui = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation itvGround = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation itvFixed = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + itemCameraTransforms = new ModelTransformation(itvThirdLeft, itvThirdRight, itvFirstLeft, itvFirstRight, + itvHead, itvGui, itvGround, itvFixed); + + selectedField = SelectedField.TRANSFORM; + selectedTransform = TransformName.FIRST_RIGHT; + menuVisible = false; + } + + public enum TransformName { + THIRD_LEFT(ModelTransformation.Mode.THIRD_PERSON_LEFT_HAND), + THIRD_RIGHT(ModelTransformation.Mode.THIRD_PERSON_RIGHT_HAND), + FIRST_LEFT(ModelTransformation.Mode.FIRST_PERSON_LEFT_HAND), + FIRST_RIGHT(ModelTransformation.Mode.FIRST_PERSON_RIGHT_HAND), + HEAD(ModelTransformation.Mode.HEAD), + GUI(ModelTransformation.Mode.GUI), + GROUND(ModelTransformation.Mode.GROUND), + FIXED(ModelTransformation.Mode.FIXED); + + public TransformName getNext() { + for (TransformName transformName : TransformName.values()) { + if (transformName.ordinal() == this.ordinal() + 1) return transformName; + } + return THIRD_LEFT; + } + + public TransformName getPrevious() { + for (TransformName transformName : TransformName.values()) { + if (transformName.ordinal() == this.ordinal() - 1) return transformName; + } + return FIXED; + } + + public ModelTransformation.Mode getVanillaTransformType() { + return vanillaType; + } + + TransformName(ModelTransformation.Mode i_type) { + vanillaType = i_type; + } + + private final ModelTransformation.Mode vanillaType; + } + + public enum SelectedField { + TRANSFORM(0), + SCALE_X(1), SCALE_Y(2), SCALE_Z(3), + ROTATE_X(4), ROTATE_Y(5), ROTATE_Z(6), + TRANSLATE_X(7), TRANSLATE_Y(8), TRANSLATE_Z(9), + RESTORE_DEFAULT(10), RESTORE_DEFAULT_ALL(11), PRINT(12); + + public final int fieldIndex; + private static final SelectedField FIRST_FIELD = TRANSFORM; + private static final SelectedField LAST_FIELD = PRINT; + + SelectedField(int index) { + fieldIndex = index; + } + + public static SelectedField getFieldName(int indexToFind) { + for (SelectedField checkField : SelectedField.values()) { + if (checkField.fieldIndex == indexToFind) return checkField; + } + return null; + } + + public SelectedField getNextField() { + SelectedField nextField = getFieldName(fieldIndex + 1); + if (nextField == null) nextField = FIRST_FIELD; + return nextField; + } + + public SelectedField getPreviousField() { + SelectedField previousField = getFieldName(fieldIndex - 1); + if (previousField == null) previousField = LAST_FIELD; + return previousField; + } + + } + + } + +} diff --git a/common/src/main/java/itemtransformhelper/ItemCamera.java b/common/src/main/java/itemtransformhelper/ItemCamera.java new file mode 100644 index 00000000..caf536f0 --- /dev/null +++ b/common/src/main/java/itemtransformhelper/ItemCamera.java @@ -0,0 +1,32 @@ +package itemtransformhelper; + +import java.util.List; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +/** + * User: The Grey Ghost + * Date: 26/01/2015 + * ItemCamera is very simple item used to activate the ItemCameraTransforms override when it is held in the hotbar. + * See the Notes. + */ +public class ItemCamera extends Item { + + public ItemCamera() { + super(new Settings().maxCount(1).group(StartupCommon.ITH_ITEM_GROUP)); + } + + @Override + public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext context) { + tooltip.add(new LiteralText("1) Place the camera in your hotbar")); + tooltip.add(new LiteralText("2) Hold an item in your hand")); + tooltip.add(new LiteralText("3) Use the cursor keys to")); + tooltip.add(new LiteralText(" modify the item transform.")); + } + +} diff --git a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java new file mode 100644 index 00000000..5c280d12 --- /dev/null +++ b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java @@ -0,0 +1,109 @@ +package itemtransformhelper; + + +import java.util.List; +import java.util.Random; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.util.math.Direction; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: The Grey Ghost + * Date: 20/01/2015 + * This class is a simple wrapper to substitute a new set of camera transforms for an existing item + * Usage: + * 1) Construct a new ItemModelFlexibleCamera with the model to wrap and an UpdateLink using getWrappedModel() + * 2) Replace the ItemModelFlexibleCamera into the modelRegistry in place of the model to wrap + * 3) Alter the UpdateLink to control the ItemCameraTransform of a given model: + * a) itemModelToOverride selects the item to be overridden + * b) forcedTransform is the transform to apply + * Models which don't match itemModelToOverride will use their original transform + *

+ * NB Starting with Forge 1.8-11.14.4.1563, it appears that all items now implement IPerspectiveAwareModel + */ +public class ItemModelFlexibleCamera implements BakedModel { + + protected final BakedModel originalModel; + + protected final UpdateLink updateLink; + + public ItemModelFlexibleCamera(BakedModel originalModel, UpdateLink updateLink) { + this.originalModel = originalModel; + this.updateLink = updateLink; + } + + @NotNull + @Override + public ModelTransformation getTransformation() { + return (updateLink.itemModelToOverride == this) + ? updateLink.forcedTransform + : originalModel.getTransformation(); + } + + /* TODO This does not seem to be needed. Remove if this is really the case. Otherwise implement it somehow... + @NotNull + @Override + public BakedModel handlePerspective(@NotNull ModelTransformation.Mode cameraTransformType, + @NotNull MatrixStack poseStack) { + if (updateLink.itemModelToOverride == this) { + AffineTransformation tr = + TransformationHelper.toTransformation(getTransformation().getTransformation(cameraTransformType)); + if (!tr.isIdentity()) { + tr.push(poseStack); + } + return this; + } else { + return super.handlePerspective(cameraTransformType, poseStack); + } + }*/ + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) { + return originalModel.getQuads(state, side, rand); + } + + @Override + public boolean useAmbientOcclusion() { + return originalModel.useAmbientOcclusion(); + } + + @Override + public boolean hasDepth() { + return originalModel.hasDepth(); + } + + @Override + public boolean isSideLit() { + return originalModel.isSideLit(); + } + + @Override + public boolean isBuiltin() { + return originalModel.isBuiltin(); + } + + @Override + public Sprite getParticleSprite() { + return originalModel.getParticleSprite(); + } + + @Override + public ModelOverrideList getOverrides() { + return originalModel.getOverrides(); + } + + public static class UpdateLink { + + public BakedModel itemModelToOverride; + + public ModelTransformation forcedTransform; + + } + +} diff --git a/common/src/main/java/itemtransformhelper/ItemTransformHelper.java b/common/src/main/java/itemtransformhelper/ItemTransformHelper.java new file mode 100644 index 00000000..8d61b985 --- /dev/null +++ b/common/src/main/java/itemtransformhelper/ItemTransformHelper.java @@ -0,0 +1,12 @@ +package itemtransformhelper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ItemTransformHelper { + + public static final String MODID = "itemtransformhelper"; + + public static final Logger logger = LogManager.getLogger(MODID); + +} diff --git a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java new file mode 100644 index 00000000..ef54a1d6 --- /dev/null +++ b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java @@ -0,0 +1,255 @@ +package itemtransformhelper; + +import dev.architectury.injectables.annotations.ExpectPlatform; +import java.util.Locale; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.render.model.json.Transformation; +import net.minecraft.text.LiteralText; +import net.minecraft.util.math.MathHelper; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.glfw.GLFW; + + +/** + * The menu used to select and alter the different parts of the ItemCameraTransform for the currently selected item. + * The menu state is rendered on the screen by HUDtextRenderer. + * The class registers its components on the Forge and FML event buses. + * Created by TheGreyGhost on 22/01/15. + */ +public class MenuItemCameraTransforms { + + private static final Logger LOGGER = LogManager.getLogger(); + + private final HUDTextRenderer.HUDInfoUpdateLink linkToHUDrenderer; + + private final MenuKeyHandler menuKeyHandler; + + public MenuItemCameraTransforms() { + linkToHUDrenderer = new HUDTextRenderer.HUDInfoUpdateLink(); + menuKeyHandler = new MenuKeyHandler(this.new KeyPressCallback()); + registerListeners(new HUDTextRenderer(linkToHUDrenderer), menuKeyHandler); + } + + @ExpectPlatform + public static void registerListeners(HUDTextRenderer hudTextRenderer, MenuKeyHandler menuKeyHandler) { + throw new UnsupportedOperationException(); + } + + /** + * get the current ItemCameraTransforms + * + * @return the transform + */ + public ModelTransformation getItemCameraTransforms() { + return linkToHUDrenderer.itemCameraTransforms; + } + + /** + * turn menu on or off + * + * @param visible true = make visible + */ + public void changeMenuVisible(boolean visible) { + linkToHUDrenderer.menuVisible = visible; + } + + public class KeyPressCallback { + void keyPressed(MenuKeyHandler.ArrowKeys whichKey) { + if (!linkToHUDrenderer.menuVisible) return; + + switch (whichKey) { + case DOWN: + linkToHUDrenderer.selectedField = linkToHUDrenderer.selectedField.getNextField(); + break; + case UP: + linkToHUDrenderer.selectedField = linkToHUDrenderer.selectedField.getPreviousField(); + break; + case RIGHT: + case LEFT: + alterField(whichKey == MenuKeyHandler.ArrowKeys.RIGHT); + break; + case NONE: + } + } + } + + private void alterField(boolean increase) { + Transformation transformVec3f = getItemTransformRef(linkToHUDrenderer, linkToHUDrenderer.selectedTransform); + if (transformVec3f == null) return; // should never happen + + final float SCALE_INCREMENT = 0.01F; + final float ROTATION_INCREMENT = 2F; + final float TRANSLATION_INCREMENT = 0.25F * 0.0625F; // 1/4 of a block, with multiplier from + // ItemTransformVec3f::deserialize0() + switch (linkToHUDrenderer.selectedField) { + case TRANSFORM -> linkToHUDrenderer.selectedTransform = increase ? linkToHUDrenderer.selectedTransform.getNext() + : linkToHUDrenderer.selectedTransform.getPrevious(); + case SCALE_X -> transformVec3f.scale.add(increase ? SCALE_INCREMENT : -SCALE_INCREMENT, 0, 0); + case SCALE_Y -> transformVec3f.scale.add(0, increase ? SCALE_INCREMENT : -SCALE_INCREMENT, 0); + case SCALE_Z -> transformVec3f.scale.add(0, 0, increase ? SCALE_INCREMENT : -SCALE_INCREMENT); + case ROTATE_X -> { + float newAngle = transformVec3f.rotation.getX() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); + newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; + transformVec3f.rotation.set(newAngle, transformVec3f.rotation.getY(), transformVec3f.rotation.getZ()); + } + case ROTATE_Y -> { + float newAngle = transformVec3f.rotation.getY() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); + newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; + transformVec3f.rotation.set(transformVec3f.rotation.getX(), newAngle, transformVec3f.rotation.getZ()); + } + case ROTATE_Z -> { + float newAngle = transformVec3f.rotation.getZ() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); + newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; + transformVec3f.rotation.set(transformVec3f.rotation.getX(), transformVec3f.rotation.getY(), newAngle); + } + case TRANSLATE_X -> transformVec3f.translation + .add(increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT, 0, 0); + case TRANSLATE_Y -> transformVec3f.translation + .add(0, increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT, 0); + case TRANSLATE_Z -> transformVec3f.translation + .add(0, 0, increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT); + case RESTORE_DEFAULT_ALL, RESTORE_DEFAULT -> { + ItemModelFlexibleCamera.UpdateLink link = StartupClientOnly.modelBakeEventHandler.getItemOverrideLink(); + BakedModel savedModel = link.itemModelToOverride; + if (savedModel != null) { // not sure why this would ever be null, but it was (in a bug report), so just + // check to make sure. + link.itemModelToOverride = null; + if (linkToHUDrenderer.selectedField == HUDTextRenderer.HUDInfoUpdateLink.SelectedField.RESTORE_DEFAULT) { + copySingleTransform(linkToHUDrenderer, savedModel, linkToHUDrenderer.selectedTransform); + } else { + for (HUDTextRenderer.HUDInfoUpdateLink.TransformName transformName + : HUDTextRenderer.HUDInfoUpdateLink.TransformName.values()) { + copySingleTransform(linkToHUDrenderer, savedModel, transformName); + } + } + } + link.itemModelToOverride = savedModel; + } + case PRINT -> { + StringBuilder output = new StringBuilder(); + output.append("\n\"display\": {\n"); + printTransform(output, "thirdperson_righthand", + linkToHUDrenderer.itemCameraTransforms.thirdPersonRightHand); + output.append(",\n"); + printTransform(output, "thirdperson_lefthand", linkToHUDrenderer.itemCameraTransforms.thirdPersonLeftHand); + output.append(",\n"); + printTransform(output, "firstperson_righthand", + linkToHUDrenderer.itemCameraTransforms.firstPersonRightHand); + output.append(",\n"); + printTransform(output, "firstperson_lefthand", linkToHUDrenderer.itemCameraTransforms.firstPersonLeftHand); + output.append(",\n"); + printTransform(output, "gui", linkToHUDrenderer.itemCameraTransforms.gui); + output.append(",\n"); + printTransform(output, "head", linkToHUDrenderer.itemCameraTransforms.head); + output.append(",\n"); + printTransform(output, "fixed", linkToHUDrenderer.itemCameraTransforms.fixed); + output.append(",\n"); + printTransform(output, "ground", linkToHUDrenderer.itemCameraTransforms.ground); + output.append("\n}"); + LOGGER.info(output); + LiteralText text = new LiteralText("\"display\" JSON section printed to console (LOGGER.info)..."); + MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(text); + } + } + } + + // points to the appropriate transform based on which transform has been selected. + private static Transformation getItemTransformRef(HUDTextRenderer.HUDInfoUpdateLink linkToHUDRenderer, + HUDTextRenderer.HUDInfoUpdateLink.TransformName transformName) { + return switch (transformName) { + case THIRD_LEFT -> linkToHUDRenderer.itemCameraTransforms.thirdPersonLeftHand; + case THIRD_RIGHT -> linkToHUDRenderer.itemCameraTransforms.thirdPersonRightHand; + case FIRST_LEFT -> linkToHUDRenderer.itemCameraTransforms.firstPersonLeftHand; + case FIRST_RIGHT -> linkToHUDRenderer.itemCameraTransforms.firstPersonRightHand; + case GUI -> linkToHUDRenderer.itemCameraTransforms.gui; + case HEAD -> linkToHUDRenderer.itemCameraTransforms.head; + case FIXED -> linkToHUDRenderer.itemCameraTransforms.fixed; + case GROUND -> linkToHUDRenderer.itemCameraTransforms.ground; + }; + } + + private void copySingleTransform(HUDTextRenderer.HUDInfoUpdateLink linkToHUDRenderer, BakedModel savedModel, + HUDTextRenderer.HUDInfoUpdateLink.TransformName transformToBeCopied + ) { + Transformation transformVec3f = getItemTransformRef(linkToHUDRenderer, transformToBeCopied); + ModelTransformation.Mode currentType = transformToBeCopied.getVanillaTransformType(); + Transformation transform = savedModel.getTransformation().getTransformation(currentType); + copyTransforms(transform, transformVec3f); + } + + private static void printTransform(StringBuilder output, String transformView, Transformation itemTransformVec3f) { + output.append(" \"").append(transformView).append("\": {\n"); + output.append(" \"rotation\": [ "); + output.append(String.format(Locale.US, "%.0f, ", itemTransformVec3f.rotation.getX())); + output.append(String.format(Locale.US, "%.0f, ", itemTransformVec3f.rotation.getY())); + output.append(String.format(Locale.US, "%.0f ],", itemTransformVec3f.rotation.getZ())); + output.append("\n"); + + final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see ItemTransformVec3f::deserialize0() + output.append(" \"translation\": [ "); + output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.translation.getX() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.translation.getY() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f ],", + itemTransformVec3f.translation.getZ() * TRANSLATE_MULTIPLIER)); + output.append("\n"); + output.append(" \"scale\": [ "); + output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.scale.getX())); + output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.scale.getY())); + output.append(String.format(Locale.US, "%.2f ]", itemTransformVec3f.scale.getZ())); + output.append("\n }"); + } + + private static void copyTransforms(Transformation from, Transformation to) { + to.translation.set(from.translation); + to.scale.set(from.scale); + to.rotation.set(from.rotation); + } + + /** + * Intercept arrow keys and handle repeats + */ + public static class MenuKeyHandler { + + private long keyDownTimeTicks = 0; + + private ArrowKeys lastKey = ArrowKeys.NONE; + + private final KeyPressCallback keyPressCallback; + + public MenuKeyHandler(KeyPressCallback keyPressCallback) { + this.keyPressCallback = keyPressCallback; + } + + public void clientTick() { + ArrowKeys keyPressed = ArrowKeys.NONE; + if (isKeyDown(GLFW.GLFW_KEY_LEFT)) keyPressed = ArrowKeys.LEFT; + if (isKeyDown(GLFW.GLFW_KEY_RIGHT)) keyPressed = ArrowKeys.RIGHT; + if (isKeyDown(GLFW.GLFW_KEY_DOWN)) keyPressed = ArrowKeys.DOWN; + if (isKeyDown(GLFW.GLFW_KEY_UP)) keyPressed = ArrowKeys.UP; + + if (keyPressed == ArrowKeys.NONE) { + lastKey = ArrowKeys.NONE; + return; + } + if (keyPressed != lastKey) { + lastKey = keyPressed; + keyDownTimeTicks = 0; + } else { + ++keyDownTimeTicks; + final int INITIAL_PAUSE_TICKS = 10; // wait 10 ticks before repeating + if (keyDownTimeTicks < INITIAL_PAUSE_TICKS) return; + } + keyPressCallback.keyPressed(keyPressed); + } + + static boolean isKeyDown(int key) { + return GLFW.glfwGetKey(MinecraftClient.getInstance().getWindow().getHandle(), key) == GLFW.GLFW_PRESS; + } + + public enum ArrowKeys {NONE, UP, DOWN, LEFT, RIGHT} + } + +} diff --git a/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java b/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java new file mode 100644 index 00000000..e779c3b6 --- /dev/null +++ b/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java @@ -0,0 +1,50 @@ +package itemtransformhelper; + +import java.util.Map; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.render.model.json.Transformation; +import net.minecraft.util.Identifier; + +/** + * User: The Grey Ghost + * Date: 20/01/2015 + * We use the ModelBakeEvent to iterate through all the registered models, wrap each one in an + * ItemModelFlexibleCamera, and write it + * back into the registry. + * Each wrapped model gets a reference to ModelBakeEventHandler::itemOverrideLink. + * Later, we can alter the members of itemOverrideLink to change the ItemCameraTransforms for a desired Item + */ +public class ModelBakeEventHandler { + + private final ItemModelFlexibleCamera.UpdateLink itemOverrideLink = new ItemModelFlexibleCamera.UpdateLink(); + + public ModelBakeEventHandler() { + itemOverrideLink.forcedTransform = new ModelTransformation( + Transformation.IDENTITY, Transformation.IDENTITY, + Transformation.IDENTITY, Transformation.IDENTITY, + Transformation.IDENTITY, Transformation.IDENTITY, + Transformation.IDENTITY, Transformation.IDENTITY); + } + + public void modelBakeEvent(Map modelRegistry) { + for (Identifier modelKey : modelRegistry.keySet()) { + BakedModel bakedModel = modelRegistry.get(modelKey); + ItemModelFlexibleCamera wrappedModel = new ItemModelFlexibleCamera(bakedModel, itemOverrideLink); + modelRegistry.put(modelKey, wrappedModel); + } + ItemTransformHelper.logger.warn("Warning - The Item Transform Helper replaces your BakedModels with a " + + "wrapped version, this"); + ItemTransformHelper.logger.warn(" is done even when the helper is not in your hotbar, and might cause " + + "problems if your"); + ItemTransformHelper.logger.warn(" BakedModel implements an interface ItemTransformHelper doesn't know about" + + "."); + ItemTransformHelper.logger.warn(" I recommend you disable the mod when you're not actively using it to " + + "transform your items."); + } + + public ItemModelFlexibleCamera.UpdateLink getItemOverrideLink() { + return itemOverrideLink; + } + +} diff --git a/src/main/java/itemtransformhelper/Notes.txt b/common/src/main/java/itemtransformhelper/Notes.txt similarity index 100% rename from src/main/java/itemtransformhelper/Notes.txt rename to common/src/main/java/itemtransformhelper/Notes.txt diff --git a/common/src/main/java/itemtransformhelper/StartupClientOnly.java b/common/src/main/java/itemtransformhelper/StartupClientOnly.java new file mode 100644 index 00000000..24f2093c --- /dev/null +++ b/common/src/main/java/itemtransformhelper/StartupClientOnly.java @@ -0,0 +1,31 @@ +package itemtransformhelper; + +import dev.architectury.injectables.annotations.ExpectPlatform; + +/** + * User: The Grey Ghost + * Date: 24/12/2014 + *

+ * The Startup classes for this example are called during startup, in the following order: + * preInitCommon + * preInitClientOnly + * initCommon + * initClientOnly + * postInitCommon + * postInitClientOnly + * See MinecraftByExample class for more information + */ +public class StartupClientOnly { + + public static final ModelBakeEventHandler modelBakeEventHandler = new ModelBakeEventHandler(); + + public static final ClientTickHandler clientTickHandler = new ClientTickHandler(); + + public static final MenuItemCameraTransforms menuItemCameraTransforms = new MenuItemCameraTransforms(); + + @ExpectPlatform + public static void clientSetup() { + throw new UnsupportedOperationException(); + } + +} diff --git a/common/src/main/java/itemtransformhelper/StartupCommon.java b/common/src/main/java/itemtransformhelper/StartupCommon.java new file mode 100644 index 00000000..b133b15a --- /dev/null +++ b/common/src/main/java/itemtransformhelper/StartupCommon.java @@ -0,0 +1,40 @@ +package itemtransformhelper; + +import dev.architectury.registry.CreativeTabRegistry; +import dev.architectury.registry.registries.DeferredRegister; +import dev.architectury.registry.registries.RegistrySupplier; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import static itemtransformhelper.ItemTransformHelper.MODID; + +/** + * User: The Grey Ghost + * Date: 24/12/2014 + *

+ * The Startup classes for this example are called during startup, in the following order: + * preInitCommon + * preInitClientOnly + * initCommon + * initClientOnly + * postInitCommon + * postInitClientOnly + * See MinecraftByExample class for more information + */ +public class StartupCommon { + + public static final DeferredRegister ITEMS = DeferredRegister.create(MODID, Registry.ITEM_KEY); + + public static final RegistrySupplier ITEM_CAMERA = ITEMS.register("item_camera", ItemCamera::new); + + public static final ItemGroup ITH_ITEM_GROUP = + CreativeTabRegistry.create(new Identifier(MODID, "items"), () -> new ItemStack(ITEM_CAMERA.get())); + + public static void init() { + ITEMS.register(); + } + +} diff --git a/common/src/main/resources/assets/itemtransformhelper/lang/en_us.json b/common/src/main/resources/assets/itemtransformhelper/lang/en_us.json new file mode 100644 index 00000000..3dfc125b --- /dev/null +++ b/common/src/main/resources/assets/itemtransformhelper/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "item.itemtransformhelper.item_camera": "Item Transform Helper", + "itemGroup.itemtransformhelper.items": "Item Transform Helper" +} diff --git a/common/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json b/common/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json new file mode 100644 index 00000000..464edba8 --- /dev/null +++ b/common/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json @@ -0,0 +1,144 @@ +{ + "parent": "builtin/generated", + "textures": { + "layer0": "itemtransformhelper:items/item_camera_icon" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0.00, + 3.00, + 1.00 + ], + "scale": [ + 0.55, + 0.55, + 0.55 + ] + }, + "thirdperson_lefthand": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0.00, + 3.00, + 1.00 + ], + "scale": [ + 0.55, + 0.55, + 0.55 + ] + }, + "firstperson_righthand": { + "rotation": [ + -25, + -90, + 0 + ], + "translation": [ + 1.13, + 3.20, + 1.13 + ], + "scale": [ + 0.68, + 0.68, + 0.68 + ] + }, + "firstperson_lefthand": { + "rotation": [ + -25, + -90, + 0 + ], + "translation": [ + 1.13, + 3.20, + 1.13 + ], + "scale": [ + 0.68, + 0.68, + 0.68 + ] + }, + "gui": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0.00, + 0.00, + 0.00 + ], + "scale": [ + 1.00, + 1.00, + 1.00 + ] + }, + "head": { + "rotation": [ + -180, + -0, + -180 + ], + "translation": [ + -0.00, + 13.00, + 7.00 + ], + "scale": [ + 1.00, + 1.00, + 1.00 + ] + }, + "fixed": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0.00, + 0.00, + 0.00 + ], + "scale": [ + 1.00, + 1.00, + 1.00 + ] + }, + "ground": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0.00, + 2.00, + 0.00 + ], + "scale": [ + 0.50, + 0.50, + 0.50 + ] + } + } +} diff --git a/src/main/resources/assets/itemtransformhelper/textures/items/item_camera_icon.png b/common/src/main/resources/assets/itemtransformhelper/textures/items/item_camera_icon.png similarity index 100% rename from src/main/resources/assets/itemtransformhelper/textures/items/item_camera_icon.png rename to common/src/main/resources/assets/itemtransformhelper/textures/items/item_camera_icon.png diff --git a/fabric/build.gradle b/fabric/build.gradle new file mode 100644 index 00000000..9fbb2720 --- /dev/null +++ b/fabric/build.gradle @@ -0,0 +1,75 @@ +plugins { + id "com.github.johnrengelman.shadow" version "7.1.2" +} + +architectury { + platformSetupLoomIde() + fabric() +} + +configurations { + common + shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this. + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentFabric.extendsFrom common +} + +dependencies { + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" + // Remove the next line if you don't want to depend on the API + modApi "dev.architectury:architectury-fabric:${rootProject.architectury_version}" + + common(project(path: ":common", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false } +} + +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +shadowJar { + configurations = [project.configurations.shadowCommon] + classifier "dev-shadow" +} + +remapJar { + input.set shadowJar.archiveFile + dependsOn shadowJar + classifier null +} + +jar { + classifier "dev" +} + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +components.java { + withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + skip() + } +} + +publishing { + publications { + mavenFabric(MavenPublication) { + artifactId = rootProject.archives_base_name + "-" + project.name + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + } +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java b/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java new file mode 100644 index 00000000..b9c5b7e7 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java @@ -0,0 +1,15 @@ +package itemtransformhelper.fabric; + +import itemtransformhelper.StartupClientOnly; +import itemtransformhelper.StartupCommon; +import net.fabricmc.api.ModInitializer; + +public class ItemTransformHelperFabric implements ModInitializer { + + @Override + public void onInitialize() { + StartupCommon.init(); + StartupClientOnly.clientSetup(); + } + +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java b/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java new file mode 100644 index 00000000..096c7646 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java @@ -0,0 +1,20 @@ +package itemtransformhelper.fabric; + +import itemtransformhelper.HUDTextRenderer; +import itemtransformhelper.MenuItemCameraTransforms; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class MenuItemCameraTransformsImpl { + + public static Queue RENDERERS = new ConcurrentLinkedQueue<>(); + + public static Queue HANDLERS = new ConcurrentLinkedQueue<>(); + + public static void registerListeners(HUDTextRenderer hudTextRenderer, + MenuItemCameraTransforms.MenuKeyHandler menuKeyHandler) { + RENDERERS.offer(hudTextRenderer); + HANDLERS.offer(menuKeyHandler); + } + +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java b/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java new file mode 100644 index 00000000..7689a536 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java @@ -0,0 +1,8 @@ +package itemtransformhelper.fabric; + +public class StartupClientOnlyImpl { + + public static void clientSetup() { + } + +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java new file mode 100644 index 00000000..1c2576a6 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java @@ -0,0 +1,31 @@ +package itemtransformhelper.fabric.mixin; + +import java.util.Map; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedModelManager; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static itemtransformhelper.StartupClientOnly.modelBakeEventHandler; + +@Mixin(BakedModelManager.class) +public class BakedModelManagerMixin { + + @Shadow + private Map models; + + @Inject(method = "apply(Lnet/minecraft/client/render/model/ModelLoader;Lnet/minecraft/resource/ResourceManager;" + + "Lnet/minecraft/util/profiler/Profiler;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V")) + public void apply(ModelLoader modelLoader, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci) { + modelBakeEventHandler.modelBakeEvent(models); + } + +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java new file mode 100644 index 00000000..8c360967 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java @@ -0,0 +1,21 @@ +package itemtransformhelper.fabric.mixin; + +import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static itemtransformhelper.fabric.MenuItemCameraTransformsImpl.RENDERERS; + +@Mixin(InGameHud.class) +public class InGameHudMixin { + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;" + + "renderStatusEffectOverlay(Lnet/minecraft/client/util/math/MatrixStack;)V")) + public void render(MatrixStack matrices, float tickDelta, CallbackInfo ci) { + RENDERERS.forEach(r -> r.displayHUDText(matrices)); + } + +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java new file mode 100644 index 00000000..a5867ba6 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java @@ -0,0 +1,22 @@ +package itemtransformhelper.fabric.mixin; + +import itemtransformhelper.MenuItemCameraTransforms; +import net.minecraft.client.MinecraftClient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static itemtransformhelper.StartupClientOnly.clientTickHandler; +import static itemtransformhelper.fabric.MenuItemCameraTransformsImpl.HANDLERS; + +@Mixin(MinecraftClient.class) +public class MinecraftClientMixin { + + @Inject(method = "tick", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;push(Ljava/lang/String;)V")) + public void tick(CallbackInfo ci) { + clientTickHandler.clientTickEvent(); + HANDLERS.forEach(MenuItemCameraTransforms.MenuKeyHandler::clientTick); + } +} diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..fb783e84 --- /dev/null +++ b/fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "schemaVersion": 1, + "id": "itemtransformhelper", + "version": "${version}", + "name": "Item Transform Helper", + "description": "Interactively change the position, scale, and rotation of an item.", + "authors": [ + "TGG", + "Romejanic", + "lehjr", + "ThexXTURBOXx" + ], + "contact": { + "homepage": "https://www.planetminecraft.com/mod/item-transform-helper---interactively-rotate-scale-translate/", + "sources": "https://github.com/TheGreyGhost/ItemTransformHelper", + "issues": "https://github.com/TheGreyGhost/ItemTransformHelper/issues" + }, + "license": "All rights reserved", + "environment": "*", + "entrypoints": { + "main": [ + "itemtransformhelper.fabric.ItemTransformHelperFabric" + ] + }, + "mixins": [ + "itemtransformhelper.mixins.json" + ], + "depends": { + "minecraft": ">=1.18.1", + "fabricloader": ">=0.12.12", + "fabric": "*", + "architectury": ">=3.4.9" + } +} diff --git a/fabric/src/main/resources/itemtransformhelper.mixins.json b/fabric/src/main/resources/itemtransformhelper.mixins.json new file mode 100644 index 00000000..5236f881 --- /dev/null +++ b/fabric/src/main/resources/itemtransformhelper.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "itemtransformhelper.fabric.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [], + "client": [ + "BakedModelManagerMixin", + "InGameHudMixin", + "MinecraftClientMixin" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/forge/build.gradle b/forge/build.gradle new file mode 100644 index 00000000..8b93a128 --- /dev/null +++ b/forge/build.gradle @@ -0,0 +1,76 @@ +plugins { + id "com.github.johnrengelman.shadow" version "7.1.2" +} + +architectury { + platformSetupLoomIde() + forge() +} + +configurations { + common + shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this. + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentForge.extendsFrom common +} + +dependencies { + forge "net.minecraftforge:forge:${rootProject.forge_version}" + // Remove the next line if you don't want to depend on the API + modApi "dev.architectury:architectury-forge:${rootProject.architectury_version}" + + common(project(path: ":common", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false } +} + +processResources { + inputs.property "version", project.version + + filesMatching("META-INF/mods.toml") { + expand "version": project.version + } +} + +shadowJar { + exclude "fabric.mod.json" + + configurations = [project.configurations.shadowCommon] + classifier "dev-shadow" +} + +remapJar { + input.set shadowJar.archiveFile + dependsOn shadowJar + classifier null +} + +jar { + classifier "dev" +} + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +components.java { + withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + skip() + } +} + +publishing { + publications { + mavenForge(MavenPublication) { + artifactId = rootProject.archives_base_name + "-" + project.name + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + } +} diff --git a/forge/gradle.properties b/forge/gradle.properties new file mode 100644 index 00000000..a58ba141 --- /dev/null +++ b/forge/gradle.properties @@ -0,0 +1 @@ +loom.platform = forge diff --git a/src/main/java/itemtransformhelper/ItemTransformHelper.java b/forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java similarity index 66% rename from src/main/java/itemtransformhelper/ItemTransformHelper.java rename to forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java index f99b0d05..fd6f0a7f 100644 --- a/src/main/java/itemtransformhelper/ItemTransformHelper.java +++ b/forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java @@ -1,20 +1,22 @@ -package itemtransformhelper; +package itemtransformhelper.forge; +import dev.architectury.platform.forge.EventBuses; +import itemtransformhelper.StartupClientOnly; +import itemtransformhelper.StartupCommon; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -@Mod(ItemTransformHelper.MODID) -public class ItemTransformHelper { - public static final String MODID = "itemtransformhelper"; - public static final Logger logger = LogManager.getLogger(MODID); +import static itemtransformhelper.ItemTransformHelper.MODID; - public ItemTransformHelper() { +@Mod(MODID) +public class ItemTransformHelperForge { + + public ItemTransformHelperForge() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + EventBuses.registerModEventBus(MODID, modEventBus); // Register the setup method for modloading modEventBus.addListener(this::setup); @@ -22,7 +24,7 @@ public ItemTransformHelper() { // Register the doClientStuff method for modloading modEventBus.addListener(this::clientSetup); - StartupCommon.ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); + StartupCommon.init(); } private void setup(final FMLCommonSetupEvent event) { @@ -32,4 +34,5 @@ private void setup(final FMLCommonSetupEvent event) { public void clientSetup(final FMLClientSetupEvent event) { StartupClientOnly.clientSetup(); } + } diff --git a/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java b/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java new file mode 100644 index 00000000..fdbf421d --- /dev/null +++ b/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java @@ -0,0 +1,39 @@ +package itemtransformhelper.forge; + +import itemtransformhelper.HUDTextRenderer; +import itemtransformhelper.MenuItemCameraTransforms; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +public class MenuItemCameraTransformsImpl { + + private final HUDTextRenderer hudTextRenderer; + + private final MenuItemCameraTransforms.MenuKeyHandler menuKeyHandler; + + public MenuItemCameraTransformsImpl(HUDTextRenderer hudTextRenderer, + MenuItemCameraTransforms.MenuKeyHandler menuKeyHandler) { + this.hudTextRenderer = hudTextRenderer; + this.menuKeyHandler = menuKeyHandler; + } + + public static void registerListeners(HUDTextRenderer hudTextRenderer, + MenuItemCameraTransforms.MenuKeyHandler menuKeyHandler) { + MinecraftForge.EVENT_BUS.register(new MenuItemCameraTransformsImpl(hudTextRenderer, menuKeyHandler)); + } + + @SubscribeEvent + public void displayHUDText(RenderGameOverlayEvent.Text event) { + hudTextRenderer.displayHUDText(event.getMatrixStack()); + } + + @SubscribeEvent + public void clientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.START) { + menuKeyHandler.clientTick(); + } + } + +} diff --git a/forge/src/main/java/itemtransformhelper/forge/StartupClientOnlyImpl.java b/forge/src/main/java/itemtransformhelper/forge/StartupClientOnlyImpl.java new file mode 100644 index 00000000..70fba62e --- /dev/null +++ b/forge/src/main/java/itemtransformhelper/forge/StartupClientOnlyImpl.java @@ -0,0 +1,32 @@ +package itemtransformhelper.forge; + +import net.minecraftforge.client.event.ModelBakeEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +import static itemtransformhelper.StartupClientOnly.clientTickHandler; +import static itemtransformhelper.StartupClientOnly.modelBakeEventHandler; + +public class StartupClientOnlyImpl { + + public static void clientSetup() { + StartupClientOnlyImpl instance = new StartupClientOnlyImpl(); + FMLJavaModLoadingContext.get().getModEventBus().addListener(instance::modelBakeEvent); + MinecraftForge.EVENT_BUS.register(instance); + } + + @SubscribeEvent + public void modelBakeEvent(ModelBakeEvent event) { + modelBakeEventHandler.modelBakeEvent(event.getModelRegistry()); + } + + @SubscribeEvent + public void clientTickEvent(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.START) { + clientTickHandler.clientTickEvent(); + } + } + +} diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..13c8e834 --- /dev/null +++ b/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,34 @@ +modLoader = "javafml" +loaderVersion = "[39,)" +issueTrackerURL = "https://github.com/TheGreyGhost/ItemTransformHelper" +license = "All rights reserved" + +[[mods]] +modId = "itemtransformhelper" +version = "${version}" +displayName = "Item Transform Helper" +authors = "TGG, Romejanic, lehjr, ThexXTURBOXx" +description = ''' +Interactively change the position, scale, and rotation of an item. +''' + +[[dependencies.itemtransformhelper]] +modId = "forge" +mandatory = true +versionRange = "[39,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.itemtransformhelper]] +modId = "minecraft" +mandatory = true +versionRange = "[1.18.1,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.itemtransformhelper]] +modId = "architectury" +mandatory = true +versionRange = "[3.4.9,)" +ordering = "AFTER" +side = "BOTH" diff --git a/forge/src/main/resources/pack.mcmeta b/forge/src/main/resources/pack.mcmeta new file mode 100644 index 00000000..57570a49 --- /dev/null +++ b/forge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "ItemTransformHelper resources", + "pack_format": 8 + } +} diff --git a/gradle.properties b/gradle.properties index 878bf1f7..bb83848f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,16 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +org.gradle.jvmargs = -Xmx2048M + +minecraft_version = 1.18.1 + +archives_base_name = itemtransformhelper +mod_version = 1.0 +maven_group = thegreyghost + +architectury_version = 3.4.9 + +yarn_mappings = 1.18.1+build.18 + +fabric_loader_version = 0.12.12 +fabric_api_version = 0.45.2+1.18 + +forge_version = 1.18.1-39.0.10 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7a3265ee94c0ab25cf079ac8ccdf87f41d455d42..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 54708 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

_x$+l{{cH8$W#CT diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1d5b29fb..669386b8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip diff --git a/gradlew b/gradlew index cccdd3d5..1b6c7873 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -89,84 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e95643d6..ac1b06f9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..c22c48fb --- /dev/null +++ b/settings.gradle @@ -0,0 +1,14 @@ +pluginManagement { + repositories { + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.architectury.dev/" } + maven { url "https://maven.minecraftforge.net/" } + gradlePluginPortal() + } +} + +include("common") +include("fabric") +include("forge") + +rootProject.name = "itemtransformhelper" diff --git a/src/main/java/itemtransformhelper/CreativeTabITH.java b/src/main/java/itemtransformhelper/CreativeTabITH.java deleted file mode 100644 index 833596f8..00000000 --- a/src/main/java/itemtransformhelper/CreativeTabITH.java +++ /dev/null @@ -1,22 +0,0 @@ -package itemtransformhelper; - -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -/** - * User: The Grey Ghost - * Date: 26/01/2015 - */ -public class CreativeTabITH extends ItemGroup { - public CreativeTabITH(String unlocalizedName) { - super(unlocalizedName); - } - - @OnlyIn(Dist.CLIENT) - @Override - public ItemStack createIcon() { - return new ItemStack(StartupCommon.ITEM_CAMERA.get()); - } -} \ No newline at end of file diff --git a/src/main/java/itemtransformhelper/HUDtextRenderer.java b/src/main/java/itemtransformhelper/HUDtextRenderer.java deleted file mode 100644 index 85f1eff6..00000000 --- a/src/main/java/itemtransformhelper/HUDtextRenderer.java +++ /dev/null @@ -1,300 +0,0 @@ -package itemtransformhelper; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.model.ItemCameraTransforms; -import net.minecraft.client.renderer.model.ItemTransformVec3f; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.util.math.vector.Matrix4f; -import net.minecraft.util.math.vector.Vector3f; -import net.minecraftforge.client.event.RenderGameOverlayEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; - -import java.util.ArrayList; - -/** - * User: The Grey Ghost - * Date: 20/01/2015 - * Class to draw the menu on the screen - */ -@SuppressWarnings("deprecation") -public class HUDtextRenderer { - /** - * Create the HUDtextRenderer; caller needs to register this class on the forge event bus - * - * @param i_HUDinfoUpdateLink the menu state information needed to draw the Heads Up Display - */ - public HUDtextRenderer(HUDinfoUpdateLink i_HUDinfoUpdateLink) { - huDinfoUpdateLink = i_HUDinfoUpdateLink; - } - - /** - * Draw the Head Up Display menu on screen. - * The information is taken from the hudInfoUpdateLink which is updated by other classes. - * - * @param event - */ - @SubscribeEvent - public void displayHUDtext(RenderGameOverlayEvent.Text event) { - if (huDinfoUpdateLink == null || !huDinfoUpdateLink.menuVisible || huDinfoUpdateLink.itemCameraTransforms == null) - return; - ArrayList displayText = new ArrayList<>(); - ArrayList selectableField = new ArrayList<>(); - - final HUDinfoUpdateLink.SelectedField NOT_SELECTABLE = null; - - displayText.add("======"); - selectableField.add(NOT_SELECTABLE); - displayText.add("VIEW "); - selectableField.add(NOT_SELECTABLE); - ItemTransformVec3f transformVec3f = huDinfoUpdateLink.itemCameraTransforms.thirdperson_right; - - switch (huDinfoUpdateLink.selectedTransform) { - case THIRD_LEFT: { - displayText.add("3rd-L"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.thirdperson_left; - break; - } - case THIRD_RIGHT: { - displayText.add("3rd-R"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.thirdperson_right; - break; - } - case FIRST_LEFT: { - displayText.add("1st-L"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.firstperson_left; - break; - } - case FIRST_RIGHT: { - displayText.add("1st-R"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.firstperson_right; - break; - } - case GUI: { - displayText.add("gui"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.gui; - break; - } - case HEAD: { - displayText.add("head"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.head; - break; - } - case FIXED: { - displayText.add("fixed"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.fixed; - break; - } - case GROUND: { - displayText.add("grnd"); - transformVec3f = huDinfoUpdateLink.itemCameraTransforms.ground; - break; - } - default: { - throw new IllegalArgumentException("Unknown cameraTransformType:" + huDinfoUpdateLink.selectedTransform); - } - } - selectableField.add(HUDinfoUpdateLink.SelectedField.TRANSFORM); - - displayText.add("======"); - selectableField.add(NOT_SELECTABLE); - displayText.add("SCALE"); - selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%.2f", transformVec3f.scale.getX())); - selectableField.add(HUDinfoUpdateLink.SelectedField.SCALE_X); - displayText.add("Y:" + String.format("%.2f", transformVec3f.scale.getY())); - selectableField.add(HUDinfoUpdateLink.SelectedField.SCALE_Y); - displayText.add("Z:" + String.format("%.2f", transformVec3f.scale.getZ())); - selectableField.add(HUDinfoUpdateLink.SelectedField.SCALE_Z); - - displayText.add("======"); - selectableField.add(NOT_SELECTABLE); - displayText.add("ROTATE"); - selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%3.0f", transformVec3f.rotation.getX())); - selectableField.add(HUDinfoUpdateLink.SelectedField.ROTATE_X); - displayText.add("Y:" + String.format("%3.0f", transformVec3f.rotation.getY())); - selectableField.add(HUDinfoUpdateLink.SelectedField.ROTATE_Y); - displayText.add("Z:" + String.format("%3.0f", transformVec3f.rotation.getZ())); - selectableField.add(HUDinfoUpdateLink.SelectedField.ROTATE_Z); - - final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see ItemTransformVec3f::deserialize0() - displayText.add("======"); - selectableField.add(NOT_SELECTABLE); - displayText.add("TRANSL"); - selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%.2f", transformVec3f.translation.getX() * TRANSLATE_MULTIPLIER)); - selectableField.add(HUDinfoUpdateLink.SelectedField.TRANSLATE_X); - displayText.add("Y:" + String.format("%.2f", transformVec3f.translation.getY() * TRANSLATE_MULTIPLIER)); - selectableField.add(HUDinfoUpdateLink.SelectedField.TRANSLATE_Y); - displayText.add("Z:" + String.format("%.2f", transformVec3f.translation.getZ() * TRANSLATE_MULTIPLIER)); - selectableField.add(HUDinfoUpdateLink.SelectedField.TRANSLATE_Z); - - displayText.add("======"); - selectableField.add(NOT_SELECTABLE); - displayText.add("RESET"); - selectableField.add(HUDinfoUpdateLink.SelectedField.RESTORE_DEFAULT); - displayText.add("RSTALL"); - selectableField.add(HUDinfoUpdateLink.SelectedField.RESTORE_DEFAULT_ALL); - displayText.add("PRINT"); - selectableField.add(HUDinfoUpdateLink.SelectedField.PRINT); - displayText.add("======"); - selectableField.add(NOT_SELECTABLE); - - FontRenderer fontRenderer = Minecraft.getInstance().fontRenderer; - int ypos = 2; - int xpos = 2; - for (int i = 0; i < displayText.size(); ++i) { - String msg = displayText.get(i); - ypos += fontRenderer.FONT_HEIGHT; - if (msg == null) continue; - final int MED_GRAY_HALF_TRANSPARENT = 0x6FAFAFB0; - final int GREEN_HALF_TRANSPARENT = 0x6F00FF00; - boolean fieldIsSelected = (huDinfoUpdateLink.selectedField == selectableField.get(i)); - int highlightColour = fieldIsSelected ? GREEN_HALF_TRANSPARENT : MED_GRAY_HALF_TRANSPARENT; - drawRect(event.getMatrixStack(), xpos - 1, ypos - 1, xpos + fontRenderer.getStringWidth(msg) + 1, ypos + fontRenderer.FONT_HEIGHT - 1, highlightColour); - final int LIGHT_GRAY = 0xE0E0E0; - final int BLACK = 0x000000; - int stringColour = fieldIsSelected ? BLACK : LIGHT_GRAY; - fontRenderer.drawString(event.getMatrixStack(), msg, xpos, ypos, stringColour); - } - } - - /** - * Used to provide the information that the HUDtextRenderer needs to draw the menu - */ - public static class HUDinfoUpdateLink { - public ItemCameraTransforms itemCameraTransforms; - public SelectedField selectedField; - public TransformName selectedTransform; - public boolean menuVisible; - - public HUDinfoUpdateLink() { - final Vector3f ROTATION_DEFAULT = new Vector3f(0.0F, 0.0F, 0.0F); - final Vector3f TRANSLATION_DEFAULT = new Vector3f(0.0F, 0.0F, 0.0F); - final Vector3f SCALE_DEFAULT = new Vector3f(1.0F, 1.0F, 1.0F); - - ItemTransformVec3f itvThirdLeft = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvThirdRight = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvFirstLeft = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvFirstRight = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvHead = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvGui = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvGround = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - ItemTransformVec3f itvFixed = new ItemTransformVec3f(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - itemCameraTransforms = new ItemCameraTransforms(itvThirdLeft, itvThirdRight, itvFirstLeft, itvFirstRight, itvHead, itvGui, itvGround, itvFixed); - - selectedField = SelectedField.TRANSFORM; - selectedTransform = TransformName.FIRST_RIGHT; - menuVisible = false; - } - - public enum TransformName { - THIRD_LEFT(ItemCameraTransforms.TransformType.THIRD_PERSON_LEFT_HAND), - THIRD_RIGHT(ItemCameraTransforms.TransformType.THIRD_PERSON_RIGHT_HAND), - FIRST_LEFT(ItemCameraTransforms.TransformType.FIRST_PERSON_LEFT_HAND), - FIRST_RIGHT(ItemCameraTransforms.TransformType.FIRST_PERSON_RIGHT_HAND), - HEAD(ItemCameraTransforms.TransformType.HEAD), - GUI(ItemCameraTransforms.TransformType.GUI), - GROUND(ItemCameraTransforms.TransformType.GROUND), - FIXED(ItemCameraTransforms.TransformType.FIXED); - - public TransformName getNext() { - for (TransformName transformName : TransformName.values()) { - if (transformName.ordinal() == this.ordinal() + 1) return transformName; - } - return THIRD_LEFT; - } - - public TransformName getPrevious() { - for (TransformName transformName : TransformName.values()) { - if (transformName.ordinal() == this.ordinal() - 1) return transformName; - } - return FIXED; - } - - public ItemCameraTransforms.TransformType getVanillaTransformType() { - return vanillaType; - } - - TransformName(ItemCameraTransforms.TransformType i_type) { - vanillaType = i_type; - } - - private ItemCameraTransforms.TransformType vanillaType; - } - - public enum SelectedField { - TRANSFORM(0), SCALE_X(1), SCALE_Y(2), SCALE_Z(3), ROTATE_X(4), ROTATE_Y(5), ROTATE_Z(6), TRANSLATE_X(7), - TRANSLATE_Y(8), TRANSLATE_Z(9), RESTORE_DEFAULT(10), RESTORE_DEFAULT_ALL(11), PRINT(12); - - SelectedField(int index) { - fieldIndex = index; - } - - public final int fieldIndex; - private static final SelectedField FIRST_FIELD = TRANSFORM; - private static final SelectedField LAST_FIELD = PRINT; - - public static SelectedField getFieldName(int indexToFind) { - for (SelectedField checkField : SelectedField.values()) { - if (checkField.fieldIndex == indexToFind) return checkField; - } - return null; - } - - public SelectedField getNextField() { - SelectedField nextField = getFieldName(fieldIndex + 1); - if (nextField == null) nextField = FIRST_FIELD; - return nextField; - } - - public SelectedField getPreviousField() { - SelectedField previousField = getFieldName(fieldIndex - 1); - if (previousField == null) previousField = LAST_FIELD; - return previousField; - } - } - - } - - private HUDinfoUpdateLink huDinfoUpdateLink; - - // copied straight from vanilla ForgeIngameGui - private static void drawRect(MatrixStack matrixStackIn, int left, int top, int right, int bottom, int color) { - if (left < right) { - int i = left; - left = right; - right = i; - } - - if (top < bottom) { - int j = top; - top = bottom; - bottom = j; - } - - float alpha = (float) (color >> 24 & 255) / 255.0F; - float red = (float) (color >> 16 & 255) / 255.0F; - float green = (float) (color >> 8 & 255) / 255.0F; - float blue = (float) (color & 255) / 255.0F; - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder builder = tessellator.getBuffer(); - GlStateManager.enableBlend(); - RenderSystem.disableTexture(); - builder.begin(7, DefaultVertexFormats.POSITION_COLOR); - Matrix4f matrix = matrixStackIn.getLast().getMatrix(); - builder.pos(matrix, (float) left, (float) bottom, 0F).color(red, green, blue, alpha).endVertex(); - builder.pos(matrix, (float) right, (float) bottom, 0F).color(red, green, blue, alpha).endVertex(); - builder.pos(matrix, (float) right, (float) top, 0F).color(red, green, blue, alpha).endVertex(); - builder.pos(matrix, (float) left, (float) top, 0F).color(red, green, blue, alpha).endVertex(); - tessellator.draw(); - RenderSystem.enableTexture(); - GlStateManager.disableBlend(); - } -} \ No newline at end of file diff --git a/src/main/java/itemtransformhelper/ItemCamera.java b/src/main/java/itemtransformhelper/ItemCamera.java deleted file mode 100644 index 9c98dcea..00000000 --- a/src/main/java/itemtransformhelper/ItemCamera.java +++ /dev/null @@ -1,31 +0,0 @@ -package itemtransformhelper; - -import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.world.World; - -import javax.annotation.Nullable; -import java.util.List; - -/** - * User: The Grey Ghost - * Date: 26/01/2015 - * ItemCamera is very simple item used to activate the ItemCameraTransforms override when it is held in the hotbar. - * See the Notes. - */ -public class ItemCamera extends Item { - public ItemCamera(Properties properties) { - super(properties); - } - - @Override - public void addInformation(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { - tooltip.add(new StringTextComponent("1) Place the camera in your hotbar")); - tooltip.add(new StringTextComponent("2) Hold an item in your hand")); - tooltip.add(new StringTextComponent("3) Use the cursor keys to ")); - tooltip.add(new StringTextComponent(" modify the item transform.")); - } -} diff --git a/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java b/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java deleted file mode 100644 index dffc044f..00000000 --- a/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java +++ /dev/null @@ -1,65 +0,0 @@ -package itemtransformhelper; - - -import com.mojang.blaze3d.matrix.MatrixStack; -import net.minecraft.block.BlockState; -import net.minecraft.client.renderer.model.BakedQuad; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ItemCameraTransforms; -import net.minecraft.util.Direction; -import net.minecraft.util.math.vector.TransformationMatrix; -import net.minecraftforge.client.model.BakedModelWrapper; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.common.model.TransformationHelper; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.List; -import java.util.Random; - -/** - * User: The Grey Ghost - * Date: 20/01/2015 - * This class is a simple wrapper to substitute a new set of camera transforms for an existing item - * Usage: - * 1) Construct a new ItemModelFlexibleCamera with the model to wrap and an UpdateLink using getWrappedModel() - * 2) Replace the ItemModelFlexibleCamera into the modelRegistry in place of the model to wrap - * 3) Alter the UpdateLink to control the ItemCameraTransform of a given model: - * a) itemModelToOverride selects the item to be overridden - * b) forcedTransform is the transform to apply - * Models which don't match itemModelToOverride will use their original transform - *

- * NB Starting with Forge 1.8-11.14.4.1563, it appears that all items now implement IPerspectiveAwareModel - */ -@SuppressWarnings({"deprecation", "unchecked"}) -public class ItemModelFlexibleCamera extends BakedModelWrapper { - protected final UpdateLink updateLink; - - public ItemModelFlexibleCamera(IBakedModel i_modelToWrap, UpdateLink linkToCurrentInformation) { - super(i_modelToWrap); - updateLink = linkToCurrentInformation; - } - - @Override - public ItemCameraTransforms getItemCameraTransforms() { - return (updateLink.itemModelToOverride == this) ? updateLink.forcedTransform : originalModel.getItemCameraTransforms(); - } - - @Override - public IBakedModel handlePerspective(ItemCameraTransforms.TransformType cameraTransformType, MatrixStack mat) { - if (updateLink.itemModelToOverride == this) { - TransformationMatrix tr = TransformationHelper.toTransformation(getItemCameraTransforms().getTransform(cameraTransformType)); - if (!tr.isIdentity()) { - tr.push(mat); - } - return this; - } else { - return super.handlePerspective(cameraTransformType, mat); - } - } - - public static class UpdateLink { - public IBakedModel itemModelToOverride; - public ItemCameraTransforms forcedTransform; - } -} \ No newline at end of file diff --git a/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java b/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java deleted file mode 100644 index 026d3b77..00000000 --- a/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java +++ /dev/null @@ -1,299 +0,0 @@ -package itemtransformhelper; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ItemCameraTransforms; -import net.minecraft.client.renderer.model.ItemTransformVec3f; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.text.StringTextComponent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.lwjgl.glfw.GLFW; - -import java.util.Locale; - - -/** - * The menu used to select and alter the different parts of the ItemCameraTransform for the currently selected item. - * The menu state is rendered on the screen by HUDtextRenderer. - * The class registers its components on the Forge and FML event buses. - * Created by TheGreyGhost on 22/01/15. - */ -@SuppressWarnings("deprecation") -public class MenuItemCameraTransforms { - public MenuItemCameraTransforms() { - linkToHUDrenderer = new HUDtextRenderer.HUDinfoUpdateLink(); - MinecraftForge.EVENT_BUS.register(new HUDtextRenderer(linkToHUDrenderer)); - menuKeyHandler = new MenuKeyHandler(this.new KeyPressCallback()); - MinecraftForge.EVENT_BUS.register(menuKeyHandler); - } - - /** - * get the current ItemCameraTransforms - * - * @return the transform - */ - public ItemCameraTransforms getItemCameraTransforms() { - return linkToHUDrenderer.itemCameraTransforms; - } - - /** - * turn menu on or off - * - * @param visible true = make visible - */ - public void changeMenuVisible(boolean visible) { - linkToHUDrenderer.menuVisible = visible; - } - - public class KeyPressCallback { - void keyPressed(MenuKeyHandler.ArrowKeys whichKey) { - if (!linkToHUDrenderer.menuVisible) return; - - switch (whichKey) { - case DOWN: { - linkToHUDrenderer.selectedField = linkToHUDrenderer.selectedField.getNextField(); - break; - } - case UP: { - linkToHUDrenderer.selectedField = linkToHUDrenderer.selectedField.getPreviousField(); - break; - } - case RIGHT: - case LEFT: { - alterField(whichKey == MenuKeyHandler.ArrowKeys.RIGHT); - break; - } - case NONE: - } - } - } - - private void alterField(boolean increase) { - ItemTransformVec3f transformVec3f = getItemTransformRef(linkToHUDrenderer, linkToHUDrenderer.selectedTransform); - if (transformVec3f == null) return; // should never happen - - final float SCALE_INCREMENT = 0.01F; - final float ROTATION_INCREMENT = 2F; - final float TRANSLATION_INCREMENT = 0.25F * 0.0625F; // 1/4 of a block, with multiplier from ItemTransformVec3f::deserialize0() - switch (linkToHUDrenderer.selectedField) { - case TRANSFORM: { - linkToHUDrenderer.selectedTransform = increase ? linkToHUDrenderer.selectedTransform.getNext() - : linkToHUDrenderer.selectedTransform.getPrevious(); - break; - } - case SCALE_X: { - transformVec3f.scale.setX(transformVec3f.scale.getX() + (increase ? SCALE_INCREMENT : -SCALE_INCREMENT)); - break; - } - case SCALE_Y: { - transformVec3f.scale.setY(transformVec3f.scale.getY() + (increase ? SCALE_INCREMENT : -SCALE_INCREMENT)); - break; - } - case SCALE_Z: { - transformVec3f.scale.setZ(transformVec3f.scale.getZ() + (increase ? SCALE_INCREMENT : -SCALE_INCREMENT)); - break; - } - case ROTATE_X: { - float newAngle = transformVec3f.rotation.getX() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); - newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; - transformVec3f.rotation.setX(newAngle); - break; - } - case ROTATE_Y: { - float newAngle = transformVec3f.rotation.getY() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); - newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; - transformVec3f.rotation.setY(newAngle); - break; - } - case ROTATE_Z: { - float newAngle = transformVec3f.rotation.getZ() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); - newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; - transformVec3f.rotation.setZ(newAngle); - break; - } - case TRANSLATE_X: { - transformVec3f.translation.setX(transformVec3f.translation.getX() + (increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT)); - break; - } - case TRANSLATE_Y: { - transformVec3f.translation.setY(transformVec3f.translation.getY() + (increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT)); - break; - } - case TRANSLATE_Z: { - transformVec3f.translation.setZ(transformVec3f.translation.getZ() + (increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT)); - break; - } - case RESTORE_DEFAULT_ALL: - case RESTORE_DEFAULT: { - ItemModelFlexibleCamera.UpdateLink link = StartupClientOnly.modelBakeEventHandler.getItemOverrideLink(); - IBakedModel savedModel = link.itemModelToOverride; - if (savedModel != null) { // not sure why this would ever be null, but it was (in a bug report), so just check to make sure. - link.itemModelToOverride = null; - if (linkToHUDrenderer.selectedField == HUDtextRenderer.HUDinfoUpdateLink.SelectedField.RESTORE_DEFAULT) { - copySingleTransform(linkToHUDrenderer, savedModel, linkToHUDrenderer.selectedTransform); - } else { - for (HUDtextRenderer.HUDinfoUpdateLink.TransformName transformName - : HUDtextRenderer.HUDinfoUpdateLink.TransformName.values()) { - copySingleTransform(linkToHUDrenderer, savedModel, transformName); - } - } - } - link.itemModelToOverride = savedModel; - break; - } - case PRINT: { - StringBuilder output = new StringBuilder(); - output.append("\n\"display\": {\n"); - printTransform(output, "thirdperson_righthand", linkToHUDrenderer.itemCameraTransforms.thirdperson_right); - output.append(",\n"); - printTransform(output, "thirdperson_lefthand", linkToHUDrenderer.itemCameraTransforms.thirdperson_left); - output.append(",\n"); - printTransform(output, "firstperson_righthand", linkToHUDrenderer.itemCameraTransforms.firstperson_right); - output.append(",\n"); - printTransform(output, "firstperson_lefthand", linkToHUDrenderer.itemCameraTransforms.firstperson_left); - output.append(",\n"); - printTransform(output, "gui", linkToHUDrenderer.itemCameraTransforms.gui); - output.append(",\n"); - printTransform(output, "head", linkToHUDrenderer.itemCameraTransforms.head); - output.append(",\n"); - printTransform(output, "fixed", linkToHUDrenderer.itemCameraTransforms.fixed); - output.append(",\n"); - printTransform(output, "ground", linkToHUDrenderer.itemCameraTransforms.ground); - output.append("\n}"); - LOGGER.info(output); - StringTextComponent text = new StringTextComponent(" \"display\" JSON section printed to console (LOGGER.info)..."); - Minecraft.getInstance().ingameGUI.getChatGUI().printChatMessage(text); - break; - } - } - } - - // points to the appropriate transform based on which transform has been selected. - private static ItemTransformVec3f getItemTransformRef(HUDtextRenderer.HUDinfoUpdateLink linkToHUDrenderer, - HUDtextRenderer.HUDinfoUpdateLink.TransformName transformName) { - switch (transformName) { - case THIRD_LEFT: { - return linkToHUDrenderer.itemCameraTransforms.thirdperson_left; - } - case THIRD_RIGHT: { - return linkToHUDrenderer.itemCameraTransforms.thirdperson_right; - } - case FIRST_LEFT: { - return linkToHUDrenderer.itemCameraTransforms.firstperson_left; - } - case FIRST_RIGHT: { - return linkToHUDrenderer.itemCameraTransforms.firstperson_right; - } - case GUI: { - return linkToHUDrenderer.itemCameraTransforms.gui; - } - case HEAD: { - return linkToHUDrenderer.itemCameraTransforms.head; - } - case FIXED: { - return linkToHUDrenderer.itemCameraTransforms.fixed; - } - case GROUND: { - return linkToHUDrenderer.itemCameraTransforms.ground; - } - } - return null; - } - - private void copySingleTransform(HUDtextRenderer.HUDinfoUpdateLink linkToHUDrenderer, - IBakedModel savedModel, - HUDtextRenderer.HUDinfoUpdateLink.TransformName transformToBeCopied - ) { - ItemTransformVec3f transformVec3f = getItemTransformRef(linkToHUDrenderer, transformToBeCopied); - ItemCameraTransforms.TransformType currentType = transformToBeCopied.getVanillaTransformType(); - ItemTransformVec3f transform = savedModel.getItemCameraTransforms().getTransform(currentType); - copyTransforms(transform, transformVec3f); - } - - private static void printTransform(StringBuilder output, String transformView, ItemTransformVec3f itemTransformVec3f) { - output.append(" \"" + transformView + "\": {\n"); - output.append(" \"rotation\": [ "); - output.append(String.format(Locale.US, "%.0f, ", itemTransformVec3f.rotation.getX())); - output.append(String.format(Locale.US, "%.0f, ", itemTransformVec3f.rotation.getY())); - output.append(String.format(Locale.US, "%.0f ],", itemTransformVec3f.rotation.getZ())); - output.append("\n"); - - final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see ItemTransformVec3f::deserialize0() - output.append(" \"translation\": [ "); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.translation.getX() * TRANSLATE_MULTIPLIER)); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.translation.getY() * TRANSLATE_MULTIPLIER)); - output.append(String.format(Locale.US, "%.2f ],", itemTransformVec3f.translation.getZ() * TRANSLATE_MULTIPLIER)); - output.append("\n"); - output.append(" \"scale\": [ "); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.scale.getX())); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.scale.getY())); - output.append(String.format(Locale.US, "%.2f ]", itemTransformVec3f.scale.getZ())); - output.append("\n }"); - } - - private static void copyTransforms(ItemTransformVec3f from, ItemTransformVec3f to) { - to.translation.setX(from.translation.getX()); - to.scale.setX(from.scale.getX()); - to.rotation.setX(from.rotation.getX()); - to.translation.setY(from.translation.getY()); - to.scale.setY(from.scale.getY()); - to.rotation.setY(from.rotation.getY()); - to.translation.setZ(from.translation.getZ()); - to.scale.setZ(from.scale.getZ()); - to.rotation.setZ(from.rotation.getZ()); - } - - private HUDtextRenderer.HUDinfoUpdateLink linkToHUDrenderer; - private MenuKeyHandler menuKeyHandler; - - /** - * Intercept arrow keys and handle repeats - */ - public static class MenuKeyHandler { - public MenuKeyHandler(KeyPressCallback i_keyPressCallback) { - keyPressCallback = i_keyPressCallback; - } - - @SubscribeEvent - public void clientTick(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.START) { - return; - } - - ArrowKeys keyPressed = ArrowKeys.NONE; - if (isKeyDown(GLFW.GLFW_KEY_LEFT)) keyPressed = ArrowKeys.LEFT; - if (isKeyDown(GLFW.GLFW_KEY_RIGHT)) keyPressed = ArrowKeys.RIGHT; - if (isKeyDown(GLFW.GLFW_KEY_DOWN)) keyPressed = ArrowKeys.DOWN; - if (isKeyDown(GLFW.GLFW_KEY_UP)) keyPressed = ArrowKeys.UP; - - if (keyPressed == ArrowKeys.NONE) { - lastKey = keyPressed; - return; - } - if (keyPressed != lastKey) { - lastKey = keyPressed; - keyDownTimeTicks = 0; - } else { - ++keyDownTimeTicks; - final int INITIAL_PAUSE_TICKS = 10; // wait 10 ticks before repeating - if (keyDownTimeTicks < INITIAL_PAUSE_TICKS) return; - } - keyPressCallback.keyPressed(keyPressed); - } - - static boolean isKeyDown(int key) { - return GLFW.glfwGetKey(Minecraft.getInstance().getMainWindow().getHandle(), key) == GLFW.GLFW_PRESS; - } - - public enum ArrowKeys {NONE, UP, DOWN, LEFT, RIGHT} - - private long keyDownTimeTicks = 0; - private ArrowKeys lastKey = ArrowKeys.NONE; - private KeyPressCallback keyPressCallback; - } - private static final Logger LOGGER = LogManager.getLogger(); -} diff --git a/src/main/java/itemtransformhelper/ModelBakeEventHandler.java b/src/main/java/itemtransformhelper/ModelBakeEventHandler.java deleted file mode 100644 index be9ef9c7..00000000 --- a/src/main/java/itemtransformhelper/ModelBakeEventHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package itemtransformhelper; - -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ItemCameraTransforms; -import net.minecraft.client.renderer.model.ItemTransformVec3f; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.client.event.ModelBakeEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; - -import java.util.Map; - -/** - * User: The Grey Ghost - * Date: 20/01/2015 - * We use the ModelBakeEvent to iterate through all the registered models, wrap each one in an ItemModelFlexibleCamera, and write it - * back into the registry. - * Each wrapped model gets a reference to ModelBakeEventHandler::itemOverrideLink. - * Later, we can alter the members of itemOverrideLink to change the ItemCameraTransforms for a desired Item - */ -@SuppressWarnings("deprecation") -public class ModelBakeEventHandler { - public ModelBakeEventHandler() { - itemOverrideLink.forcedTransform = new ItemCameraTransforms(ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, - ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, - ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, - ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT); - } - - @SubscribeEvent - public void modelBakeEvent(ModelBakeEvent event) { - Map modelRegistry = event.getModelRegistry(); - for (ResourceLocation modelKey : modelRegistry.keySet()) { - IBakedModel iBakedModel = event.getModelRegistry().get(modelKey); - ItemModelFlexibleCamera wrappedModel = new ItemModelFlexibleCamera(iBakedModel, itemOverrideLink); - event.getModelRegistry().put(modelKey, wrappedModel); - } - ItemTransformHelper.logger.warn("Warning - The Item Transform Helper replaces your IBakedModels with a wrapped version, this"); - ItemTransformHelper.logger.warn(" is done even when the helper is not in your hotbar, and might cause problems if your"); - ItemTransformHelper.logger.warn(" IBakedModel implements an interface ItemTransformHelper doesn't know about."); - ItemTransformHelper.logger.warn(" I recommend you disable the mod when you're not actively using it to transform your items."); - } - - public ItemModelFlexibleCamera.UpdateLink getItemOverrideLink() { - return itemOverrideLink; - } - - private ItemModelFlexibleCamera.UpdateLink itemOverrideLink = new ItemModelFlexibleCamera.UpdateLink(); -} diff --git a/src/main/java/itemtransformhelper/StartupClientOnly.java b/src/main/java/itemtransformhelper/StartupClientOnly.java deleted file mode 100644 index 34d22002..00000000 --- a/src/main/java/itemtransformhelper/StartupClientOnly.java +++ /dev/null @@ -1,29 +0,0 @@ -package itemtransformhelper; - -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; - -/** - * User: The Grey Ghost - * Date: 24/12/2014 - *

- * The Startup classes for this example are called during startup, in the following order: - * preInitCommon - * preInitClientOnly - * initCommon - * initClientOnly - * postInitCommon - * postInitClientOnly - * See MinecraftByExample class for more information - */ -public class StartupClientOnly { - public final static ModelBakeEventHandler modelBakeEventHandler = new ModelBakeEventHandler(); - public final static ClientTickHandler clientTickHandler = new ClientTickHandler(); - public static MenuItemCameraTransforms menuItemCameraTransforms; - - public static void clientSetup() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(modelBakeEventHandler::modelBakeEvent); - MinecraftForge.EVENT_BUS.register(clientTickHandler); - menuItemCameraTransforms = new MenuItemCameraTransforms(); - } -} \ No newline at end of file diff --git a/src/main/java/itemtransformhelper/StartupCommon.java b/src/main/java/itemtransformhelper/StartupCommon.java deleted file mode 100644 index 948a3d26..00000000 --- a/src/main/java/itemtransformhelper/StartupCommon.java +++ /dev/null @@ -1,30 +0,0 @@ -package itemtransformhelper; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraftforge.fml.RegistryObject; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; - -import static itemtransformhelper.ItemTransformHelper.MODID; - -/** - * User: The Grey Ghost - * Date: 24/12/2014 - *

- * The Startup classes for this example are called during startup, in the following order: - * preInitCommon - * preInitClientOnly - * initCommon - * initClientOnly - * postInitCommon - * postInitClientOnly - * See MinecraftByExample class for more information - */ -public class StartupCommon { - public static ItemGroup tabITH = new CreativeTabITH("itemtransformhelper"); - - public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID); - public static final RegistryObject ITEM_CAMERA = ITEMS.register("item_camera", () -> new ItemCamera( - new Item.Properties().group(tabITH).maxStackSize(1))); -} \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml deleted file mode 100644 index f94e7f5c..00000000 --- a/src/main/resources/META-INF/mods.toml +++ /dev/null @@ -1,24 +0,0 @@ -modLoader="javafml" -loaderVersion="[32,)" -# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. -# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. -license="All rights reserved" -[[mods]] -modId="itemtransformhelper" -version="${file.jarVersion}" -displayName="Item Transform Helper" -credits="The Forge, MCP, and FML guys. Maruohon" -authors="TGG, Romejanic, lehjr" -description="Interactively change the position, scale, and rotation of an item" -[[dependencies.itemtransformhelper]] - modId="forge" - mandatory=true - versionRange="[32,)" - ordering="NONE" - side="BOTH" -[[dependencies.itemtransformhelper]] - modId="minecraft" - mandatory=true - versionRange="[1.16.1]" - ordering="NONE" - side="BOTH" diff --git a/src/main/resources/assets/itemtransformhelper/lang/en_us.json b/src/main/resources/assets/itemtransformhelper/lang/en_us.json deleted file mode 100644 index 19bde922..00000000 --- a/src/main/resources/assets/itemtransformhelper/lang/en_us.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "item.itemtransformhelper.item_camera": "Item Transform Helper", - "itemGroup.itemtransformhelper": "Item Transform Helper" -} \ No newline at end of file diff --git a/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json b/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json deleted file mode 100644 index 0573f6f2..00000000 --- a/src/main/resources/assets/itemtransformhelper/models/item/item_camera.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "parent": "builtin/generated", - "textures": { - "layer0": "itemtransformhelper:items/item_camera_icon" - }, - "display": { - "thirdperson_righthand": { - "rotation": [ 0, 0, 0 ], - "translation": [ 0.00, 3.00, 1.00 ], - "scale": [ 0.55, 0.55, 0.55 ] - }, - "thirdperson_lefthand": { - "rotation": [ 0, 0, 0 ], - "translation": [ 0.00, 3.00, 1.00 ], - "scale": [ 0.55, 0.55, 0.55 ] - }, - "firstperson_righthand": { - "rotation": [ -25, -90, 0 ], - "translation": [ 1.13, 3.20, 1.13 ], - "scale": [ 0.68, 0.68, 0.68 ] - }, - "firstperson_lefthand": { - "rotation": [ -25, -90, 0 ], - "translation": [ 1.13, 3.20, 1.13 ], - "scale": [ 0.68, 0.68, 0.68 ] - }, - "gui": { - "rotation": [ 0, 0, 0 ], - "translation": [ 0.00, 0.00, 0.00 ], - "scale": [ 1.00, 1.00, 1.00 ] - }, - "head": { - "rotation": [ -180, -0, -180 ], - "translation": [ -0.00, 13.00, 7.00 ], - "scale": [ 1.00, 1.00, 1.00 ] - }, - "fixed": { - "rotation": [ 0, 0, 0 ], - "translation": [ 0.00, 0.00, 0.00 ], - "scale": [ 1.00, 1.00, 1.00 ] - }, - "ground": { - "rotation": [ 0, 0, 0 ], - "translation": [ 0.00, 2.00, 0.00 ], - "scale": [ 0.50, 0.50, 0.50 ] - } - }} diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta deleted file mode 100644 index 148fbf9c..00000000 --- a/src/main/resources/pack.mcmeta +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pack": { - "description": "itemtransformhelper resources", - "pack_format": 5, - "_comment": "A pack_format of 5 requires json lang files and some texture changes from 1.15. Note: we require v5 pack meta for all mods." - } -} From a363fdb401e7f3dd0e67723e28d140bc2977a812 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 12:39:42 +0100 Subject: [PATCH 02/10] Add License --- LICENSE | 24 ++++++++++++++++++++++++ README.md | 26 ++------------------------ 2 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..68a49daa --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md index 6452facd..9d917bb5 100644 --- a/README.md +++ b/README.md @@ -36,28 +36,6 @@ As an alternative to the Item Transform Helper, you can also use BlockBench (htt Thanks to Romejanic for updating to 1.12.2, and to lehrj for updating to 1.16.1! -## Licence Info: -This is free and unencumbered software released into the public domain. +## Licence Info -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to +See [here](https://github.com/TheGreyGhost/ItemTransformHelper/blob/master/LICENSE). From e535caf38958c724c33d1dc09d2ecb23c65b9c09 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 12:40:49 +0100 Subject: [PATCH 03/10] Improve metadata and README --- README.md | 22 +++++++++---------- .../main/java/itemtransformhelper/Notes.txt | 22 +++++++++---------- fabric/src/main/resources/fabric.mod.json | 4 ++-- forge/src/main/resources/META-INF/mods.toml | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 9d917bb5..5f46c3d4 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ -Item Transform Helper +# Item Transform Helper ================== -When you create a custom item, you need to provide ItemCameraTransforms for it. This project is an interactive +When you create a custom item, you need to provide ItemCameraTransforms for it. This project is an interactive tool to help you get the transforms right by interactively adjusting them. How to use:
-1) Place the ItemCamera somewhere in the player's hotbar
+1) Place the Camera item somewhere in the player's hotbar
2) Hold the Item you want to modify in the player's hand
3) Use the up/down keys to move up and down the menu.
-4) Use the left/right keys to edit the value (eg scaleX)
-5) To select a different view (eg first person, third person) use left/right to change the VIEW menu item. +4) Use the left/right keys to edit the value (e.g. scaleX)
+5) To select a different view (e.g. first person, third person) use left/right to change the VIEW menu item. 6) To modify the transform for an item on the ground: - * throw your Item onto the ground, and then put another copy of your Item into the player's hand + * Throw your Item onto the ground, and then put another copy of your Item into the player's hand * Use left/right to change the VIEW menu item to grnd
Use the same technique for items in the gui, on your head (eg pumpkin), fixed (in picture frames), or in the player's left hand. -7) To reset the parameters for the current view, select the RESET menu item and press left or right. Use RESET ALL (RSTALL) to reset the parameters for all views.
+7) To reset the parameters for the current view, select the RESET menu item and press left or right. Use RESET ALL (RSTALL) to reset the parameters for all views.
You can also copy parameters from a vanilla item to your custom item: * Hold the vanilla item in your hand * Select RESET or RSTALL, press left or right. @@ -25,16 +25,16 @@ How to use:
The item will appear in the Helpers tab in the creative inventory. For background information on
-- items: see here http://greyminecraftcoder.blogspot.com/2013/12/items.html
-- rendering items: see here http://greyminecraftcoder.blogspot.com.au/2014/12/item-rendering-18.html
+- Items: see here https://greyminecraftcoder.blogspot.com/2013/12/items.html
+- Rendering items: see here https://greyminecraftcoder.blogspot.com/2014/12/item-rendering-18.html
- This link describes the structure of the JSON Item Model file (see the Item Models section halfway down):
-- http://minecraft.gamepedia.com/Block_models +- https://minecraft.fandom.com/wiki/Model#Item_models As an alternative to the Item Transform Helper, you can also use BlockBench (https://blockbench.net/) to determine the correct transforms for your model, i.e. either
1) Create a new model in BlockBench; or
2) Import an existing model (either the json model file, or the item "generated" texture)
-Thanks to Romejanic for updating to 1.12.2, and to lehrj for updating to 1.16.1! +Thanks to ThexXTURBOXx for updating to 1.11.2 and Architectury (Forge + Fabric) 1.18.1, Romejanic for updating to 1.12.2, and to lehrj for updating to 1.16.1! ## Licence Info diff --git a/common/src/main/java/itemtransformhelper/Notes.txt b/common/src/main/java/itemtransformhelper/Notes.txt index 8ac0cf56..ca4b195a 100644 --- a/common/src/main/java/itemtransformhelper/Notes.txt +++ b/common/src/main/java/itemtransformhelper/Notes.txt @@ -1,20 +1,20 @@ -ITEM_TRANSFORM_HELPER +Item Transform Helper -When you create a custom item, you need to provide ItemCameraTransforms for it. This example is an interactive - tool to help you get the transforms right. +When you create a custom item, you need to provide ItemCameraTransforms for it. This project is an interactive + tool to help you get the transforms right by interactively adjusting them. How to use: -1) Place the ItemCamera somewhere in the player's hotbar +1) Place the Camera item somewhere in the player's hotbar 2) Hold the Item you want to modify in the player's hand 3) Use the up/down keys to move up and down the menu. -4) Use the left/right keys to edit the value (eg scaleX) -5) To select a different view (eg first person, third person) use left/right to change the VIEW menu item. +4) Use the left/right keys to edit the value (e.g. scaleX) +5) To select a different view (e.g. first person, third person) use left/right to change the VIEW menu item. 6) To modify the transform for an item on the ground: - a) throw your Item onto the ground, and then put another copy of your Item into the player's hand + a) Throw your Item onto the ground, and then put another copy of your Item into the player's hand b) Use left/right to change the VIEW menu item to grnd Use the same technique for items in the gui, on your head (eg pumpkin), fixed (in picture frames), or in the player's left hand. -7) To reset the parameters for the current view, select the RESET menu item and press left or right. Use RESET ALL (RSTALL) to reset the parameters for all views. +7) To reset the parameters for the current view, select the RESET menu item and press left or right. Use RESET ALL (RSTALL) to reset the parameters for all views. You can also copy parameters from a vanilla item to your custom item: a) Hold the vanilla item in your hand b) Select RESET or RSTALL, press left or right. @@ -25,7 +25,7 @@ How to use: The item will appear in the Helpers tab in the creative inventory. For background information on -- items: see here http://greyminecraftcoder.blogspot.com/2013/12/items.html -- rendering items: see here http://greyminecraftcoder.blogspot.com.au/2014/12/item-rendering-18.html +- Items: see here https://greyminecraftcoder.blogspot.com/2013/12/items.html +- Rendering items: see here https://greyminecraftcoder.blogspot.com/2014/12/item-rendering-18.html - This link describes the structure of the JSON Item Model file (see the Item Models section halfway down): - http://minecraft.gamepedia.com/Block_models + https://minecraft.fandom.com/wiki/Model#Item_models diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index fb783e84..02614b73 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -6,9 +6,9 @@ "description": "Interactively change the position, scale, and rotation of an item.", "authors": [ "TGG", + "ThexXTURBOXx", "Romejanic", - "lehjr", - "ThexXTURBOXx" + "lehjr" ], "contact": { "homepage": "https://www.planetminecraft.com/mod/item-transform-helper---interactively-rotate-scale-translate/", diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 13c8e834..6106356f 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -7,7 +7,7 @@ license = "All rights reserved" modId = "itemtransformhelper" version = "${version}" displayName = "Item Transform Helper" -authors = "TGG, Romejanic, lehjr, ThexXTURBOXx" +authors = "TGG, ThexXTURBOXx, Romejanic, lehjr" description = ''' Interactively change the position, scale, and rotation of an item. ''' From dd0ccadfa3f9d138fcd4edce05e234de98d604e0 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 12:40:58 +0100 Subject: [PATCH 04/10] Ignore another folder --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ccb0c562..aa984279 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ classes/ .metadata .vscode .settings -*.launch \ No newline at end of file +*.launch +.architectury-transformer/ From 098612dc373eebdedf10b1f8eb454822531b6961 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 12:41:42 +0100 Subject: [PATCH 05/10] More refactoring --- .../ClientTickHandler.java | 13 +- .../itemtransformhelper/HUDTextRenderer.java | 126 +++++++++--------- .../ItemModelFlexibleCamera.java | 28 ++-- .../ItemTransformHelper.java | 4 + .../MenuItemCameraTransforms.java | 105 +++++++-------- .../ModelBakeEventHandler.java | 3 +- .../StartupClientOnly.java | 2 - .../itemtransformhelper/StartupCommon.java | 3 + .../fabric/ItemModelFlexibleCameraImpl.java | 17 +++ .../fabric/ItemTransformHelperFabric.java | 4 +- .../fabric/MenuItemCameraTransformsImpl.java | 1 - .../fabric/StartupClientOnlyImpl.java | 3 + .../fabric/mixin/MinecraftClientMixin.java | 1 + .../forge/ItemModelFlexibleCameraImpl.java | 39 ++++++ .../forge/ItemTransformHelperForge.java | 4 +- .../forge/MenuItemCameraTransformsImpl.java | 1 - 16 files changed, 199 insertions(+), 155 deletions(-) create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java create mode 100644 forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java diff --git a/common/src/main/java/itemtransformhelper/ClientTickHandler.java b/common/src/main/java/itemtransformhelper/ClientTickHandler.java index c7d3f754..228c4769 100644 --- a/common/src/main/java/itemtransformhelper/ClientTickHandler.java +++ b/common/src/main/java/itemtransformhelper/ClientTickHandler.java @@ -20,30 +20,29 @@ public void clientTickEvent() { if (player == null) return; boolean foundCamera = false; - PlayerInventory inventoryPlayer = player.getInventory(); + PlayerInventory inventory = player.getInventory(); for (int i = 0; i < PlayerInventory.getHotbarSize(); ++i) { - ItemStack slotItemStack = inventoryPlayer.main.get(i); - if (slotItemStack.getItem() == StartupCommon.ITEM_CAMERA.get()) { + ItemStack stack = inventory.main.get(i); + if (stack.getItem() == StartupCommon.ITEM_CAMERA.get()) { foundCamera = true; break; } } StartupClientOnly.menuItemCameraTransforms.changeMenuVisible(foundCamera); - BakedModel ibakedmodel = null; + BakedModel bakedModel = null; if (foundCamera) { ItemStack heldItemStack = player.getEquippedStack(EquipmentSlot.MAINHAND); if (heldItemStack.isEmpty()) { heldItemStack = player.getEquippedStack(EquipmentSlot.OFFHAND); } if (!heldItemStack.isEmpty()) { - ibakedmodel = - MinecraftClient.getInstance().getItemRenderer().getModels().getModel(heldItemStack); + bakedModel = MinecraftClient.getInstance().getItemRenderer().getModels().getModel(heldItemStack); } } ItemModelFlexibleCamera.UpdateLink link = StartupClientOnly.modelBakeEventHandler.getItemOverrideLink(); - link.itemModelToOverride = ibakedmodel; + link.itemModelToOverride = bakedModel; link.forcedTransform = StartupClientOnly.menuItemCameraTransforms.getItemCameraTransforms(); } diff --git a/common/src/main/java/itemtransformhelper/HUDTextRenderer.java b/common/src/main/java/itemtransformhelper/HUDTextRenderer.java index 1bbd85b4..b665a395 100644 --- a/common/src/main/java/itemtransformhelper/HUDTextRenderer.java +++ b/common/src/main/java/itemtransformhelper/HUDTextRenderer.java @@ -16,10 +16,16 @@ */ public class HUDTextRenderer { + private static final HUDInfoUpdateLink.SelectedField NOT_SELECTABLE = null; + private static final int MED_GRAY_HALF_TRANSPARENT = 0x6FAFAFB0; + private static final int GREEN_HALF_TRANSPARENT = 0x6F00FF00; + private static final int LIGHT_GRAY = 0xE0E0E0; + private static final int BLACK = 0x000000; + private final HUDInfoUpdateLink hudInfoUpdateLink; /** - * Create the HUDTextRenderer; caller needs to register this class on the forge event bus + * Create the HUDTextRenderer; displayHUDText needs to be called on RenderGameOverlayEvent.Text * * @param hudInfoUpdateLink the menu state information needed to draw the Heads Up Display */ @@ -37,50 +43,46 @@ public void displayHUDText(MatrixStack matrixStack) { ArrayList displayText = new ArrayList<>(); ArrayList selectableField = new ArrayList<>(); - final HUDInfoUpdateLink.SelectedField NOT_SELECTABLE = null; - displayText.add("======"); selectableField.add(NOT_SELECTABLE); displayText.add("VIEW "); selectableField.add(NOT_SELECTABLE); - Transformation transformVec3f; + Transformation transformation; switch (hudInfoUpdateLink.selectedTransform) { case THIRD_LEFT -> { displayText.add("3rd-L"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.thirdPersonLeftHand; + transformation = hudInfoUpdateLink.itemCameraTransforms.thirdPersonLeftHand; } case THIRD_RIGHT -> { displayText.add("3rd-R"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.thirdPersonRightHand; + transformation = hudInfoUpdateLink.itemCameraTransforms.thirdPersonRightHand; } case FIRST_LEFT -> { displayText.add("1st-L"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.firstPersonLeftHand; + transformation = hudInfoUpdateLink.itemCameraTransforms.firstPersonLeftHand; } case FIRST_RIGHT -> { displayText.add("1st-R"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.firstPersonRightHand; + transformation = hudInfoUpdateLink.itemCameraTransforms.firstPersonRightHand; } case GUI -> { displayText.add("gui"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.gui; + transformation = hudInfoUpdateLink.itemCameraTransforms.gui; } case HEAD -> { displayText.add("head"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.head; + transformation = hudInfoUpdateLink.itemCameraTransforms.head; } case FIXED -> { displayText.add("fixed"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.fixed; + transformation = hudInfoUpdateLink.itemCameraTransforms.fixed; } case GROUND -> { displayText.add("grnd"); - transformVec3f = hudInfoUpdateLink.itemCameraTransforms.ground; - } - default -> { - throw new IllegalArgumentException("Unknown cameraTransformType:" + hudInfoUpdateLink.selectedTransform); + transformation = hudInfoUpdateLink.itemCameraTransforms.ground; } + default -> throw new IllegalArgumentException("Unknown cameraTransformType:" + hudInfoUpdateLink.selectedTransform); } selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSFORM); @@ -88,34 +90,34 @@ public void displayHUDText(MatrixStack matrixStack) { selectableField.add(NOT_SELECTABLE); displayText.add("SCALE"); selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%.2f", transformVec3f.scale.getX())); + displayText.add("X:" + String.format("%.2f", transformation.scale.getX())); selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_X); - displayText.add("Y:" + String.format("%.2f", transformVec3f.scale.getY())); + displayText.add("Y:" + String.format("%.2f", transformation.scale.getY())); selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_Y); - displayText.add("Z:" + String.format("%.2f", transformVec3f.scale.getZ())); + displayText.add("Z:" + String.format("%.2f", transformation.scale.getZ())); selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_Z); displayText.add("======"); selectableField.add(NOT_SELECTABLE); displayText.add("ROTATE"); selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%3.0f", transformVec3f.rotation.getX())); + displayText.add("X:" + String.format("%3.0f", transformation.rotation.getX())); selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_X); - displayText.add("Y:" + String.format("%3.0f", transformVec3f.rotation.getY())); + displayText.add("Y:" + String.format("%3.0f", transformation.rotation.getY())); selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_Y); - displayText.add("Z:" + String.format("%3.0f", transformVec3f.rotation.getZ())); + displayText.add("Z:" + String.format("%3.0f", transformation.rotation.getZ())); selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_Z); - final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see ItemTransformVec3f::deserialize0() + final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see Transformation.Deserializer::deserialize displayText.add("======"); selectableField.add(NOT_SELECTABLE); displayText.add("TRANSL"); selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%.2f", transformVec3f.translation.getX() * TRANSLATE_MULTIPLIER)); + displayText.add("X:" + String.format("%.2f", transformation.translation.getX() * TRANSLATE_MULTIPLIER)); selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_X); - displayText.add("Y:" + String.format("%.2f", transformVec3f.translation.getY() * TRANSLATE_MULTIPLIER)); + displayText.add("Y:" + String.format("%.2f", transformation.translation.getY() * TRANSLATE_MULTIPLIER)); selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_Y); - displayText.add("Z:" + String.format("%.2f", transformVec3f.translation.getZ() * TRANSLATE_MULTIPLIER)); + displayText.add("Z:" + String.format("%.2f", transformation.translation.getZ() * TRANSLATE_MULTIPLIER)); selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_Z); displayText.add("======"); @@ -129,23 +131,19 @@ public void displayHUDText(MatrixStack matrixStack) { displayText.add("======"); selectableField.add(NOT_SELECTABLE); - TextRenderer fontRenderer = MinecraftClient.getInstance().textRenderer; - int ypos = 2; - int xpos = 2; + TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + int yPos = 2; + int xPos = 2; for (int i = 0; i < displayText.size(); ++i) { String msg = displayText.get(i); - ypos += fontRenderer.fontHeight; + yPos += textRenderer.fontHeight; if (msg == null) continue; - final int MED_GRAY_HALF_TRANSPARENT = 0x6FAFAFB0; - final int GREEN_HALF_TRANSPARENT = 0x6F00FF00; - boolean fieldIsSelected = (hudInfoUpdateLink.selectedField == selectableField.get(i)); + boolean fieldIsSelected = hudInfoUpdateLink.selectedField == selectableField.get(i); int highlightColour = fieldIsSelected ? GREEN_HALF_TRANSPARENT : MED_GRAY_HALF_TRANSPARENT; - DrawableHelper.fill(matrixStack, xpos - 1, ypos - 1, xpos + fontRenderer.getWidth(msg) + 1, - ypos + fontRenderer.fontHeight - 1, highlightColour); - final int LIGHT_GRAY = 0xE0E0E0; - final int BLACK = 0x000000; + DrawableHelper.fill(matrixStack, xPos - 1, yPos - 1, + xPos + textRenderer.getWidth(msg) + 1, yPos + textRenderer.fontHeight - 1, highlightColour); int stringColour = fieldIsSelected ? BLACK : LIGHT_GRAY; - fontRenderer.draw(matrixStack, msg, xpos, ypos, stringColour); + textRenderer.draw(matrixStack, msg, xPos, yPos, stringColour); } } @@ -153,30 +151,27 @@ public void displayHUDText(MatrixStack matrixStack) { * Used to provide the information that the HUDTextRenderer needs to draw the menu */ public static class HUDInfoUpdateLink { + + private static final Vec3f ROTATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); + private static final Vec3f TRANSLATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); + private static final Vec3f SCALE_DEFAULT = new Vec3f(1.0F, 1.0F, 1.0F); + public ModelTransformation itemCameraTransforms; public SelectedField selectedField; public TransformName selectedTransform; public boolean menuVisible; public HUDInfoUpdateLink() { - final Vec3f ROTATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); - final Vec3f TRANSLATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); - final Vec3f SCALE_DEFAULT = new Vec3f(1.0F, 1.0F, 1.0F); - - Transformation itvThirdLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, - SCALE_DEFAULT); - Transformation itvThirdRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, - SCALE_DEFAULT); - Transformation itvFirstLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, - SCALE_DEFAULT); - Transformation itvFirstRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, - SCALE_DEFAULT); - Transformation itvHead = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation itvGui = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation itvGround = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation itvFixed = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - itemCameraTransforms = new ModelTransformation(itvThirdLeft, itvThirdRight, itvFirstLeft, itvFirstRight, - itvHead, itvGui, itvGround, itvFixed); + Transformation trThirdLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trThirdRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trFirstLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trFirstRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trHead = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trGui = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trGround = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + Transformation trFixed = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + itemCameraTransforms = new ModelTransformation(trThirdLeft, trThirdRight, trFirstLeft, trFirstRight, + trHead, trGui, trGround, trFixed); selectedField = SelectedField.TRANSFORM; selectedTransform = TransformName.FIRST_RIGHT; @@ -184,6 +179,7 @@ public HUDInfoUpdateLink() { } public enum TransformName { + THIRD_LEFT(ModelTransformation.Mode.THIRD_PERSON_LEFT_HAND), THIRD_RIGHT(ModelTransformation.Mode.THIRD_PERSON_RIGHT_HAND), FIRST_LEFT(ModelTransformation.Mode.FIRST_PERSON_LEFT_HAND), @@ -193,15 +189,19 @@ public enum TransformName { GROUND(ModelTransformation.Mode.GROUND), FIXED(ModelTransformation.Mode.FIXED); + public static final TransformName[] VALUES = TransformName.values(); + + private final ModelTransformation.Mode vanillaType; + public TransformName getNext() { - for (TransformName transformName : TransformName.values()) { + for (TransformName transformName : VALUES) { if (transformName.ordinal() == this.ordinal() + 1) return transformName; } return THIRD_LEFT; } public TransformName getPrevious() { - for (TransformName transformName : TransformName.values()) { + for (TransformName transformName : VALUES) { if (transformName.ordinal() == this.ordinal() - 1) return transformName; } return FIXED; @@ -211,30 +211,32 @@ public ModelTransformation.Mode getVanillaTransformType() { return vanillaType; } - TransformName(ModelTransformation.Mode i_type) { - vanillaType = i_type; + TransformName(ModelTransformation.Mode vanillaType) { + this.vanillaType = vanillaType; } - private final ModelTransformation.Mode vanillaType; } public enum SelectedField { + TRANSFORM(0), SCALE_X(1), SCALE_Y(2), SCALE_Z(3), ROTATE_X(4), ROTATE_Y(5), ROTATE_Z(6), TRANSLATE_X(7), TRANSLATE_Y(8), TRANSLATE_Z(9), RESTORE_DEFAULT(10), RESTORE_DEFAULT_ALL(11), PRINT(12); - public final int fieldIndex; + public static final SelectedField[] VALUES = SelectedField.values(); private static final SelectedField FIRST_FIELD = TRANSFORM; private static final SelectedField LAST_FIELD = PRINT; + public final int fieldIndex; + SelectedField(int index) { fieldIndex = index; } public static SelectedField getFieldName(int indexToFind) { - for (SelectedField checkField : SelectedField.values()) { + for (SelectedField checkField : VALUES) { if (checkField.fieldIndex == indexToFind) return checkField; } return null; diff --git a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java index 5c280d12..b90790bd 100644 --- a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java +++ b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java @@ -1,6 +1,7 @@ package itemtransformhelper; +import dev.architectury.injectables.annotations.ExpectPlatform; import java.util.List; import java.util.Random; import net.minecraft.block.BlockState; @@ -27,17 +28,21 @@ *

* NB Starting with Forge 1.8-11.14.4.1563, it appears that all items now implement IPerspectiveAwareModel */ -public class ItemModelFlexibleCamera implements BakedModel { +public abstract class ItemModelFlexibleCamera implements BakedModel { protected final BakedModel originalModel; - protected final UpdateLink updateLink; - public ItemModelFlexibleCamera(BakedModel originalModel, UpdateLink updateLink) { + protected ItemModelFlexibleCamera(BakedModel originalModel, UpdateLink updateLink) { this.originalModel = originalModel; this.updateLink = updateLink; } + @ExpectPlatform + public static ItemModelFlexibleCamera create(BakedModel originalModel, UpdateLink updateLink) { + throw new UnsupportedOperationException(); + } + @NotNull @Override public ModelTransformation getTransformation() { @@ -46,23 +51,6 @@ public ModelTransformation getTransformation() { : originalModel.getTransformation(); } - /* TODO This does not seem to be needed. Remove if this is really the case. Otherwise implement it somehow... - @NotNull - @Override - public BakedModel handlePerspective(@NotNull ModelTransformation.Mode cameraTransformType, - @NotNull MatrixStack poseStack) { - if (updateLink.itemModelToOverride == this) { - AffineTransformation tr = - TransformationHelper.toTransformation(getTransformation().getTransformation(cameraTransformType)); - if (!tr.isIdentity()) { - tr.push(poseStack); - } - return this; - } else { - return super.handlePerspective(cameraTransformType, poseStack); - } - }*/ - @Override public List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) { return originalModel.getQuads(state, side, rand); diff --git a/common/src/main/java/itemtransformhelper/ItemTransformHelper.java b/common/src/main/java/itemtransformhelper/ItemTransformHelper.java index 8d61b985..8aada8f4 100644 --- a/common/src/main/java/itemtransformhelper/ItemTransformHelper.java +++ b/common/src/main/java/itemtransformhelper/ItemTransformHelper.java @@ -9,4 +9,8 @@ public class ItemTransformHelper { public static final Logger logger = LogManager.getLogger(MODID); + public static void init() { + StartupCommon.init(); + } + } diff --git a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java index ef54a1d6..c7703c00 100644 --- a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java +++ b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java @@ -15,7 +15,7 @@ /** * The menu used to select and alter the different parts of the ItemCameraTransform for the currently selected item. - * The menu state is rendered on the screen by HUDtextRenderer. + * The menu state is rendered on the screen by HUDTextRenderer. * The class registers its components on the Forge and FML event buses. * Created by TheGreyGhost on 22/01/15. */ @@ -23,14 +23,12 @@ public class MenuItemCameraTransforms { private static final Logger LOGGER = LogManager.getLogger(); - private final HUDTextRenderer.HUDInfoUpdateLink linkToHUDrenderer; - - private final MenuKeyHandler menuKeyHandler; + private final HUDTextRenderer.HUDInfoUpdateLink linkToHudRenderer; public MenuItemCameraTransforms() { - linkToHUDrenderer = new HUDTextRenderer.HUDInfoUpdateLink(); - menuKeyHandler = new MenuKeyHandler(this.new KeyPressCallback()); - registerListeners(new HUDTextRenderer(linkToHUDrenderer), menuKeyHandler); + linkToHudRenderer = new HUDTextRenderer.HUDInfoUpdateLink(); + registerListeners(new HUDTextRenderer(linkToHudRenderer), + new MenuKeyHandler(this.new KeyPressCallback())); } @ExpectPlatform @@ -44,7 +42,7 @@ public static void registerListeners(HUDTextRenderer hudTextRenderer, MenuKeyHan * @return the transform */ public ModelTransformation getItemCameraTransforms() { - return linkToHUDrenderer.itemCameraTransforms; + return linkToHudRenderer.itemCameraTransforms; } /** @@ -53,40 +51,36 @@ public ModelTransformation getItemCameraTransforms() { * @param visible true = make visible */ public void changeMenuVisible(boolean visible) { - linkToHUDrenderer.menuVisible = visible; + linkToHudRenderer.menuVisible = visible; } public class KeyPressCallback { + void keyPressed(MenuKeyHandler.ArrowKeys whichKey) { - if (!linkToHUDrenderer.menuVisible) return; + if (!linkToHudRenderer.menuVisible) return; switch (whichKey) { - case DOWN: - linkToHUDrenderer.selectedField = linkToHUDrenderer.selectedField.getNextField(); - break; - case UP: - linkToHUDrenderer.selectedField = linkToHUDrenderer.selectedField.getPreviousField(); - break; - case RIGHT: - case LEFT: - alterField(whichKey == MenuKeyHandler.ArrowKeys.RIGHT); - break; - case NONE: + case DOWN -> linkToHudRenderer.selectedField = linkToHudRenderer.selectedField.getNextField(); + case UP -> linkToHudRenderer.selectedField = linkToHudRenderer.selectedField.getPreviousField(); + case RIGHT, LEFT -> alterField(whichKey == MenuKeyHandler.ArrowKeys.RIGHT); + default -> { + } } } + } private void alterField(boolean increase) { - Transformation transformVec3f = getItemTransformRef(linkToHUDrenderer, linkToHUDrenderer.selectedTransform); + Transformation transformVec3f = getItemTransformRef(linkToHudRenderer, linkToHudRenderer.selectedTransform); if (transformVec3f == null) return; // should never happen final float SCALE_INCREMENT = 0.01F; final float ROTATION_INCREMENT = 2F; final float TRANSLATION_INCREMENT = 0.25F * 0.0625F; // 1/4 of a block, with multiplier from - // ItemTransformVec3f::deserialize0() - switch (linkToHUDrenderer.selectedField) { - case TRANSFORM -> linkToHUDrenderer.selectedTransform = increase ? linkToHUDrenderer.selectedTransform.getNext() - : linkToHUDrenderer.selectedTransform.getPrevious(); + // Transformation.Deserializer::deserialize + switch (linkToHudRenderer.selectedField) { + case TRANSFORM -> linkToHudRenderer.selectedTransform = increase ? linkToHudRenderer.selectedTransform.getNext() + : linkToHudRenderer.selectedTransform.getPrevious(); case SCALE_X -> transformVec3f.scale.add(increase ? SCALE_INCREMENT : -SCALE_INCREMENT, 0, 0); case SCALE_Y -> transformVec3f.scale.add(0, increase ? SCALE_INCREMENT : -SCALE_INCREMENT, 0); case SCALE_Z -> transformVec3f.scale.add(0, 0, increase ? SCALE_INCREMENT : -SCALE_INCREMENT); @@ -117,12 +111,12 @@ private void alterField(boolean increase) { if (savedModel != null) { // not sure why this would ever be null, but it was (in a bug report), so just // check to make sure. link.itemModelToOverride = null; - if (linkToHUDrenderer.selectedField == HUDTextRenderer.HUDInfoUpdateLink.SelectedField.RESTORE_DEFAULT) { - copySingleTransform(linkToHUDrenderer, savedModel, linkToHUDrenderer.selectedTransform); + if (linkToHudRenderer.selectedField == HUDTextRenderer.HUDInfoUpdateLink.SelectedField.RESTORE_DEFAULT) { + copySingleTransform(linkToHudRenderer, savedModel, linkToHudRenderer.selectedTransform); } else { for (HUDTextRenderer.HUDInfoUpdateLink.TransformName transformName - : HUDTextRenderer.HUDInfoUpdateLink.TransformName.values()) { - copySingleTransform(linkToHUDrenderer, savedModel, transformName); + : HUDTextRenderer.HUDInfoUpdateLink.TransformName.VALUES) { + copySingleTransform(linkToHudRenderer, savedModel, transformName); } } } @@ -132,22 +126,22 @@ private void alterField(boolean increase) { StringBuilder output = new StringBuilder(); output.append("\n\"display\": {\n"); printTransform(output, "thirdperson_righthand", - linkToHUDrenderer.itemCameraTransforms.thirdPersonRightHand); + linkToHudRenderer.itemCameraTransforms.thirdPersonRightHand); output.append(",\n"); - printTransform(output, "thirdperson_lefthand", linkToHUDrenderer.itemCameraTransforms.thirdPersonLeftHand); + printTransform(output, "thirdperson_lefthand", linkToHudRenderer.itemCameraTransforms.thirdPersonLeftHand); output.append(",\n"); printTransform(output, "firstperson_righthand", - linkToHUDrenderer.itemCameraTransforms.firstPersonRightHand); + linkToHudRenderer.itemCameraTransforms.firstPersonRightHand); output.append(",\n"); - printTransform(output, "firstperson_lefthand", linkToHUDrenderer.itemCameraTransforms.firstPersonLeftHand); + printTransform(output, "firstperson_lefthand", linkToHudRenderer.itemCameraTransforms.firstPersonLeftHand); output.append(",\n"); - printTransform(output, "gui", linkToHUDrenderer.itemCameraTransforms.gui); + printTransform(output, "gui", linkToHudRenderer.itemCameraTransforms.gui); output.append(",\n"); - printTransform(output, "head", linkToHUDrenderer.itemCameraTransforms.head); + printTransform(output, "head", linkToHudRenderer.itemCameraTransforms.head); output.append(",\n"); - printTransform(output, "fixed", linkToHUDrenderer.itemCameraTransforms.fixed); + printTransform(output, "fixed", linkToHudRenderer.itemCameraTransforms.fixed); output.append(",\n"); - printTransform(output, "ground", linkToHUDrenderer.itemCameraTransforms.ground); + printTransform(output, "ground", linkToHudRenderer.itemCameraTransforms.ground); output.append("\n}"); LOGGER.info(output); LiteralText text = new LiteralText("\"display\" JSON section printed to console (LOGGER.info)..."); @@ -172,33 +166,31 @@ private static Transformation getItemTransformRef(HUDTextRenderer.HUDInfoUpdateL } private void copySingleTransform(HUDTextRenderer.HUDInfoUpdateLink linkToHUDRenderer, BakedModel savedModel, - HUDTextRenderer.HUDInfoUpdateLink.TransformName transformToBeCopied - ) { - Transformation transformVec3f = getItemTransformRef(linkToHUDRenderer, transformToBeCopied); + HUDTextRenderer.HUDInfoUpdateLink.TransformName transformToBeCopied) { + Transformation transformation = getItemTransformRef(linkToHUDRenderer, transformToBeCopied); ModelTransformation.Mode currentType = transformToBeCopied.getVanillaTransformType(); Transformation transform = savedModel.getTransformation().getTransformation(currentType); - copyTransforms(transform, transformVec3f); + copyTransforms(transform, transformation); } - private static void printTransform(StringBuilder output, String transformView, Transformation itemTransformVec3f) { + private static void printTransform(StringBuilder output, String transformView, Transformation transformation) { output.append(" \"").append(transformView).append("\": {\n"); output.append(" \"rotation\": [ "); - output.append(String.format(Locale.US, "%.0f, ", itemTransformVec3f.rotation.getX())); - output.append(String.format(Locale.US, "%.0f, ", itemTransformVec3f.rotation.getY())); - output.append(String.format(Locale.US, "%.0f ],", itemTransformVec3f.rotation.getZ())); + output.append(String.format(Locale.US, "%.0f, ", transformation.rotation.getX())); + output.append(String.format(Locale.US, "%.0f, ", transformation.rotation.getY())); + output.append(String.format(Locale.US, "%.0f ],", transformation.rotation.getZ())); output.append("\n"); - final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see ItemTransformVec3f::deserialize0() + final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see Transformation.Deserializer::deserialize output.append(" \"translation\": [ "); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.translation.getX() * TRANSLATE_MULTIPLIER)); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.translation.getY() * TRANSLATE_MULTIPLIER)); - output.append(String.format(Locale.US, "%.2f ],", - itemTransformVec3f.translation.getZ() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f, ", transformation.translation.getX() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f, ", transformation.translation.getY() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f ],", transformation.translation.getZ() * TRANSLATE_MULTIPLIER)); output.append("\n"); output.append(" \"scale\": [ "); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.scale.getX())); - output.append(String.format(Locale.US, "%.2f, ", itemTransformVec3f.scale.getY())); - output.append(String.format(Locale.US, "%.2f ]", itemTransformVec3f.scale.getZ())); + output.append(String.format(Locale.US, "%.2f, ", transformation.scale.getX())); + output.append(String.format(Locale.US, "%.2f, ", transformation.scale.getY())); + output.append(String.format(Locale.US, "%.2f ]", transformation.scale.getZ())); output.append("\n }"); } @@ -213,12 +205,10 @@ private static void copyTransforms(Transformation from, Transformation to) { */ public static class MenuKeyHandler { + private final KeyPressCallback keyPressCallback; private long keyDownTimeTicks = 0; - private ArrowKeys lastKey = ArrowKeys.NONE; - private final KeyPressCallback keyPressCallback; - public MenuKeyHandler(KeyPressCallback keyPressCallback) { this.keyPressCallback = keyPressCallback; } @@ -250,6 +240,7 @@ static boolean isKeyDown(int key) { } public enum ArrowKeys {NONE, UP, DOWN, LEFT, RIGHT} + } } diff --git a/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java b/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java index e779c3b6..8cd0f018 100644 --- a/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java +++ b/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java @@ -30,9 +30,10 @@ public ModelBakeEventHandler() { public void modelBakeEvent(Map modelRegistry) { for (Identifier modelKey : modelRegistry.keySet()) { BakedModel bakedModel = modelRegistry.get(modelKey); - ItemModelFlexibleCamera wrappedModel = new ItemModelFlexibleCamera(bakedModel, itemOverrideLink); + ItemModelFlexibleCamera wrappedModel = ItemModelFlexibleCamera.create(bakedModel, itemOverrideLink); modelRegistry.put(modelKey, wrappedModel); } + ItemTransformHelper.logger.warn("Warning - The Item Transform Helper replaces your BakedModels with a " + "wrapped version, this"); ItemTransformHelper.logger.warn(" is done even when the helper is not in your hotbar, and might cause " diff --git a/common/src/main/java/itemtransformhelper/StartupClientOnly.java b/common/src/main/java/itemtransformhelper/StartupClientOnly.java index 24f2093c..1f87de88 100644 --- a/common/src/main/java/itemtransformhelper/StartupClientOnly.java +++ b/common/src/main/java/itemtransformhelper/StartupClientOnly.java @@ -18,9 +18,7 @@ public class StartupClientOnly { public static final ModelBakeEventHandler modelBakeEventHandler = new ModelBakeEventHandler(); - public static final ClientTickHandler clientTickHandler = new ClientTickHandler(); - public static final MenuItemCameraTransforms menuItemCameraTransforms = new MenuItemCameraTransforms(); @ExpectPlatform diff --git a/common/src/main/java/itemtransformhelper/StartupCommon.java b/common/src/main/java/itemtransformhelper/StartupCommon.java index b133b15a..e4cc638c 100644 --- a/common/src/main/java/itemtransformhelper/StartupCommon.java +++ b/common/src/main/java/itemtransformhelper/StartupCommon.java @@ -26,10 +26,13 @@ */ public class StartupCommon { + // Registries public static final DeferredRegister ITEMS = DeferredRegister.create(MODID, Registry.ITEM_KEY); + // Items public static final RegistrySupplier ITEM_CAMERA = ITEMS.register("item_camera", ItemCamera::new); + // Item Groups public static final ItemGroup ITH_ITEM_GROUP = CreativeTabRegistry.create(new Identifier(MODID, "items"), () -> new ItemStack(ITEM_CAMERA.get())); diff --git a/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java b/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java new file mode 100644 index 00000000..6e651ae3 --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java @@ -0,0 +1,17 @@ +package itemtransformhelper.fabric; + +import itemtransformhelper.ItemModelFlexibleCamera; +import net.minecraft.client.render.model.BakedModel; + +public class ItemModelFlexibleCameraImpl extends ItemModelFlexibleCamera { + + public ItemModelFlexibleCameraImpl(BakedModel originalModel, UpdateLink updateLink) { + super(originalModel, updateLink); + } + + public static ItemModelFlexibleCamera create(BakedModel originalModel, + ItemModelFlexibleCamera.UpdateLink updateLink) { + return new ItemModelFlexibleCameraImpl(originalModel, updateLink); + } + +} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java b/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java index b9c5b7e7..50f4b4a8 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java @@ -1,14 +1,14 @@ package itemtransformhelper.fabric; +import itemtransformhelper.ItemTransformHelper; import itemtransformhelper.StartupClientOnly; -import itemtransformhelper.StartupCommon; import net.fabricmc.api.ModInitializer; public class ItemTransformHelperFabric implements ModInitializer { @Override public void onInitialize() { - StartupCommon.init(); + ItemTransformHelper.init(); StartupClientOnly.clientSetup(); } diff --git a/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java b/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java index 096c7646..3db5b742 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java @@ -8,7 +8,6 @@ public class MenuItemCameraTransformsImpl { public static Queue RENDERERS = new ConcurrentLinkedQueue<>(); - public static Queue HANDLERS = new ConcurrentLinkedQueue<>(); public static void registerListeners(HUDTextRenderer hudTextRenderer, diff --git a/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java b/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java index 7689a536..2ffd9ac4 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java @@ -3,6 +3,9 @@ public class StartupClientOnlyImpl { public static void clientSetup() { + // Nothing to do here as this handled by these mixins: + // BakedModelManagerMixin + // MinecraftClientMixin } } diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java index a5867ba6..b6c36383 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java @@ -19,4 +19,5 @@ public void tick(CallbackInfo ci) { clientTickHandler.clientTickEvent(); HANDLERS.forEach(MenuItemCameraTransforms.MenuKeyHandler::clientTick); } + } diff --git a/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java b/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java new file mode 100644 index 00000000..b896cbc0 --- /dev/null +++ b/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java @@ -0,0 +1,39 @@ +package itemtransformhelper.forge; + +import itemtransformhelper.ItemModelFlexibleCamera; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.AffineTransformation; +import net.minecraftforge.common.model.TransformationHelper; +import org.jetbrains.annotations.NotNull; + +public class ItemModelFlexibleCameraImpl extends ItemModelFlexibleCamera { + + public ItemModelFlexibleCameraImpl(BakedModel originalModel, UpdateLink updateLink) { + super(originalModel, updateLink); + } + + public static ItemModelFlexibleCamera create(BakedModel originalModel, + ItemModelFlexibleCamera.UpdateLink updateLink) { + return new ItemModelFlexibleCameraImpl(originalModel, updateLink); + } + + @NotNull + @Override + @SuppressWarnings("deprecation") + public BakedModel handlePerspective(@NotNull ModelTransformation.Mode cameraTransformType, + @NotNull MatrixStack poseStack) { + if (updateLink.itemModelToOverride == this) { + AffineTransformation tr = + TransformationHelper.toTransformation(getTransformation().getTransformation(cameraTransformType)); + if (!tr.isIdentity()) { + tr.push(poseStack); + } + return this; + } else { + return super.handlePerspective(cameraTransformType, poseStack); + } + } + +} diff --git a/forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java b/forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java index fd6f0a7f..a4a4a1b2 100644 --- a/forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java +++ b/forge/src/main/java/itemtransformhelper/forge/ItemTransformHelperForge.java @@ -1,8 +1,8 @@ package itemtransformhelper.forge; import dev.architectury.platform.forge.EventBuses; +import itemtransformhelper.ItemTransformHelper; import itemtransformhelper.StartupClientOnly; -import itemtransformhelper.StartupCommon; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -24,7 +24,7 @@ public ItemTransformHelperForge() { // Register the doClientStuff method for modloading modEventBus.addListener(this::clientSetup); - StartupCommon.init(); + ItemTransformHelper.init(); } private void setup(final FMLCommonSetupEvent event) { diff --git a/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java b/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java index fdbf421d..82f299db 100644 --- a/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java +++ b/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java @@ -10,7 +10,6 @@ public class MenuItemCameraTransformsImpl { private final HUDTextRenderer hudTextRenderer; - private final MenuItemCameraTransforms.MenuKeyHandler menuKeyHandler; public MenuItemCameraTransformsImpl(HUDTextRenderer hudTextRenderer, From 9122e2375797fff8a69d08915553862e95aa3402 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 12:48:19 +0100 Subject: [PATCH 06/10] Fix notes --- ReadMeFirst.txt | 44 +++++-------------- .../Notes.txt | 0 2 files changed, 11 insertions(+), 33 deletions(-) rename common/src/main/{java/itemtransformhelper => resources}/Notes.txt (100%) diff --git a/ReadMeFirst.txt b/ReadMeFirst.txt index 73afcece..96a31a84 100644 --- a/ReadMeFirst.txt +++ b/ReadMeFirst.txt @@ -1,20 +1,20 @@ Item Transform Helper ================== -When you create a custom item, you need to provide ItemCameraTransforms for it. This project is an interactive +When you create a custom item, you need to provide ItemCameraTransforms for it. This project is an interactive tool to help you get the transforms right by interactively adjusting them. How to use: -1) Place the ItemCamera somewhere in the player's hotbar +1) Place the Camera item somewhere in the player's hotbar 2) Hold the Item you want to modify in the player's hand 3) Use the up/down keys to move up and down the menu. -4) Use the left/right keys to edit the value (eg scaleX) -5) To select a different view (eg first person, third person) use left/right to change the VIEW menu item. +4) Use the left/right keys to edit the value (e.g. scaleX) +5) To select a different view (e.g. first person, third person) use left/right to change the VIEW menu item. 6) To modify the transform for an item on the ground: - a) throw your Item onto the ground, and then put another copy of your Item into the player's hand + a) Throw your Item onto the ground, and then put another copy of your Item into the player's hand b) Use left/right to change the VIEW menu item to grnd Use the same technique for items in the gui, on your head (eg pumpkin), fixed (in picture frames), or in the player's left hand. -7) To reset the parameters for the current view, select the RESET menu item and press left or right. Use RESET ALL (RSTALL) to reset the parameters for all views. +7) To reset the parameters for the current view, select the RESET menu item and press left or right. Use RESET ALL (RSTALL) to reset the parameters for all views. You can also copy parameters from a vanilla item to your custom item: a) Hold the vanilla item in your hand b) Select RESET or RSTALL, press left or right. @@ -25,40 +25,18 @@ How to use: The item will appear in the Helpers tab in the creative inventory. For background information on -- items: see here http://greyminecraftcoder.blogspot.com/2013/12/items.html -- rendering items: see here http://greyminecraftcoder.blogspot.com.au/2014/12/item-rendering-18.html +- Items: see here https://greyminecraftcoder.blogspot.com/2013/12/items.html +- Rendering items: see here https://greyminecraftcoder.blogspot.com/2014/12/item-rendering-18.html - This link describes the structure of the JSON Item Model file (see the Item Models section halfway down): - http://minecraft.gamepedia.com/Block_models + https://minecraft.fandom.com/wiki/Model#Item_models As an alternative to the Item Transform Helper, you can also use BlockBench (https://blockbench.net/) to determine the correct transforms for your model, i.e. either 1) Create a new model in BlockBench; or 2) Import an existing model (either the json model file, or the item "generated" texture) -Thanks to Romejanic for updating to 1.12.2, and to lehrj for updating to 1.16.1! +Thanks to ThexXTURBOXx for updating to 1.11.2 and Architectury (Forge + Fabric) 1.18.1, Romejanic for updating to 1.12.2, and to lehrj for updating to 1.16.1! -------------- Licence Info -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to +See here: https://github.com/TheGreyGhost/ItemTransformHelper/blob/master/LICENSE diff --git a/common/src/main/java/itemtransformhelper/Notes.txt b/common/src/main/resources/Notes.txt similarity index 100% rename from common/src/main/java/itemtransformhelper/Notes.txt rename to common/src/main/resources/Notes.txt From 1dfd829c18672b6a1b5460f36c861b62e68db52d Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Fri, 7 Jan 2022 17:10:37 +0100 Subject: [PATCH 07/10] Fix README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f46c3d4..b3fa4ac9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Item Transform Helper -================== + When you create a custom item, you need to provide ItemCameraTransforms for it. This project is an interactive tool to help you get the transforms right by interactively adjusting them. From a09cc5585f8ea0bf7dd6ed3e22ec54abffe26e43 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Wed, 23 Mar 2022 10:13:16 +0100 Subject: [PATCH 08/10] Update to 1.18.2 --- build.gradle | 2 +- fabric/src/main/resources/fabric.mod.json | 6 +++--- gradle.properties | 12 ++++++------ gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index dcb2037e..fabeb056 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "0.10.0-SNAPSHOT" apply false + id "dev.architectury.loom" version "0.11.0-SNAPSHOT" apply false } architectury { diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 02614b73..824ca69e 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -26,9 +26,9 @@ "itemtransformhelper.mixins.json" ], "depends": { - "minecraft": ">=1.18.1", - "fabricloader": ">=0.12.12", + "minecraft": ">=1.18.2", + "fabricloader": ">=0.13.3", "fabric": "*", - "architectury": ">=3.4.9" + "architectury": ">=4.1.32" } } diff --git a/gradle.properties b/gradle.properties index bb83848f..69bd733d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,16 @@ org.gradle.jvmargs = -Xmx2048M -minecraft_version = 1.18.1 +minecraft_version = 1.18.2 archives_base_name = itemtransformhelper mod_version = 1.0 maven_group = thegreyghost -architectury_version = 3.4.9 +architectury_version = 4.1.34 -yarn_mappings = 1.18.1+build.18 +yarn_mappings = 1.18.2+build.2 -fabric_loader_version = 0.12.12 -fabric_api_version = 0.45.2+1.18 +fabric_loader_version = 0.13.3 +fabric_api_version = 0.48.0+1.18.2 -forge_version = 1.18.1-39.0.10 +forge_version = 1.18.2-40.0.24 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 669386b8..00e33ede 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From dda0ede6e27be7a6bd2e072998082ceb18546f11 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Wed, 8 Jun 2022 00:24:56 +0200 Subject: [PATCH 09/10] Initial Fabric update to 1.19 --- common/build.gradle | 8 +- .../java/itemtransformhelper/ItemCamera.java | 9 +- .../ItemModelFlexibleCamera.java | 2 +- .../MenuItemCameraTransforms.java | 4 +- fabric-like/build.gradle | 12 +++ .../ItemTransformHelperFabricLike.java | 13 +++ fabric/build.gradle | 2 + .../fabric/ItemTransformHelperFabric.java | 6 +- fabric/src/main/resources/fabric.mod.json | 6 +- gradle.properties | 17 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- quilt/build.gradle | 88 +++++++++++++++++++ quilt/gradle.properties | 1 + .../fabric/ExampleExpectPlatformImpl.java | 15 ++++ .../net/examplemod/quilt/ExampleModQuilt.java | 12 +++ .../src/main/resources/examplemod.mixins.json | 12 +++ quilt/src/main/resources/quilt.mod.json | 45 ++++++++++ settings.gradle | 4 +- 18 files changed, 231 insertions(+), 27 deletions(-) create mode 100644 fabric-like/build.gradle create mode 100644 fabric-like/src/main/java/itemtransformhelper.fabriclike/ItemTransformHelperFabricLike.java create mode 100644 quilt/build.gradle create mode 100644 quilt/gradle.properties create mode 100644 quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java create mode 100644 quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java create mode 100644 quilt/src/main/resources/examplemod.mixins.json create mode 100644 quilt/src/main/resources/quilt.mod.json diff --git a/common/build.gradle b/common/build.gradle index c253f86f..e79b62ba 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,3 +1,7 @@ +architectury { + common(rootProject.enabled_platforms.split(",")) +} + dependencies { // We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies // Do NOT use other classes from fabric loader @@ -6,10 +10,6 @@ dependencies { modApi "dev.architectury:architectury:${rootProject.architectury_version}" } -architectury { - common() -} - publishing { publications { mavenCommon(MavenPublication) { diff --git a/common/src/main/java/itemtransformhelper/ItemCamera.java b/common/src/main/java/itemtransformhelper/ItemCamera.java index caf536f0..37d65098 100644 --- a/common/src/main/java/itemtransformhelper/ItemCamera.java +++ b/common/src/main/java/itemtransformhelper/ItemCamera.java @@ -4,7 +4,6 @@ import net.minecraft.client.item.TooltipContext; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.text.LiteralText; import net.minecraft.text.Text; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; @@ -23,10 +22,10 @@ public ItemCamera() { @Override public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext context) { - tooltip.add(new LiteralText("1) Place the camera in your hotbar")); - tooltip.add(new LiteralText("2) Hold an item in your hand")); - tooltip.add(new LiteralText("3) Use the cursor keys to")); - tooltip.add(new LiteralText(" modify the item transform.")); + tooltip.add(Text.literal("1) Place the camera in your hotbar")); + tooltip.add(Text.literal("2) Hold an item in your hand")); + tooltip.add(Text.literal("3) Use the cursor keys to")); + tooltip.add(Text.literal(" modify the item transform.")); } } diff --git a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java index b90790bd..f002a2ad 100644 --- a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java +++ b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java @@ -3,7 +3,6 @@ import dev.architectury.injectables.annotations.ExpectPlatform; import java.util.List; -import java.util.Random; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedQuad; @@ -11,6 +10,7 @@ import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java index c7703c00..28319898 100644 --- a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java +++ b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java @@ -6,7 +6,7 @@ import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.render.model.json.Transformation; -import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -144,7 +144,7 @@ private void alterField(boolean increase) { printTransform(output, "ground", linkToHudRenderer.itemCameraTransforms.ground); output.append("\n}"); LOGGER.info(output); - LiteralText text = new LiteralText("\"display\" JSON section printed to console (LOGGER.info)..."); + Text text = Text.literal("\"display\" JSON section printed to console (LOGGER.info)..."); MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(text); } } diff --git a/fabric-like/build.gradle b/fabric-like/build.gradle new file mode 100644 index 00000000..ef34aacc --- /dev/null +++ b/fabric-like/build.gradle @@ -0,0 +1,12 @@ +architectury { + common(rootProject.enabled_platforms.split(",")) +} + +dependencies { + modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" + modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" + // Remove the next line if you don't want to depend on the API + modApi "dev.architectury:architectury-fabric:${rootProject.architectury_version}" + + compileClasspath(project(path: ":common", configuration: "namedElements")) { transitive false } +} diff --git a/fabric-like/src/main/java/itemtransformhelper.fabriclike/ItemTransformHelperFabricLike.java b/fabric-like/src/main/java/itemtransformhelper.fabriclike/ItemTransformHelperFabricLike.java new file mode 100644 index 00000000..5ce92428 --- /dev/null +++ b/fabric-like/src/main/java/itemtransformhelper.fabriclike/ItemTransformHelperFabricLike.java @@ -0,0 +1,13 @@ +package itemtransformhelper.fabriclike; + +import itemtransformhelper.ItemTransformHelper; +import itemtransformhelper.StartupClientOnly; + +public class ItemTransformHelperFabricLike { + + public static void init() { + ItemTransformHelper.init(); + StartupClientOnly.clientSetup(); + } + +} diff --git a/fabric/build.gradle b/fabric/build.gradle index 9fbb2720..3c8f1520 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -23,6 +23,8 @@ dependencies { common(project(path: ":common", configuration: "namedElements")) { transitive false } shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false } + common(project(path: ":fabric-like", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":fabric-like", configuration: "transformProductionFabric")) { transitive false } } processResources { diff --git a/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java b/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java index 50f4b4a8..333f8a66 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/ItemTransformHelperFabric.java @@ -1,15 +1,13 @@ package itemtransformhelper.fabric; -import itemtransformhelper.ItemTransformHelper; -import itemtransformhelper.StartupClientOnly; +import itemtransformhelper.fabriclike.ItemTransformHelperFabricLike; import net.fabricmc.api.ModInitializer; public class ItemTransformHelperFabric implements ModInitializer { @Override public void onInitialize() { - ItemTransformHelper.init(); - StartupClientOnly.clientSetup(); + ItemTransformHelperFabricLike.init(); } } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 824ca69e..48d04be6 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -26,9 +26,9 @@ "itemtransformhelper.mixins.json" ], "depends": { - "minecraft": ">=1.18.2", - "fabricloader": ">=0.13.3", + "minecraft": ">=1.19", + "fabricloader": ">=0.14.6", "fabric": "*", - "architectury": ">=4.1.32" + "architectury": ">=5.4.15" } } diff --git a/gradle.properties b/gradle.properties index 69bd733d..aca1b4ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,21 @@ org.gradle.jvmargs = -Xmx2048M -minecraft_version = 1.18.2 +minecraft_version = 1.19 +#TODO: enabled_platforms = quilt,fabric,forge +enabled_platforms = fabric archives_base_name = itemtransformhelper mod_version = 1.0 maven_group = thegreyghost -architectury_version = 4.1.34 +architectury_version = 5.4.15 -yarn_mappings = 1.18.2+build.2 +yarn_mappings = 1.19+build.1 -fabric_loader_version = 0.13.3 -fabric_api_version = 0.48.0+1.18.2 +fabric_loader_version = 0.14.6 +fabric_api_version = 0.55.2+1.19 -forge_version = 1.18.2-40.0.24 +forge_version = 1.19-41.0.1 + +quilt_loader_version = 0.16.0 +quilt_fabric_api_version = 1.0.0-beta.13+0.51.1-1.18.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 00e33ede..aa991fce 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/quilt/build.gradle b/quilt/build.gradle new file mode 100644 index 00000000..3fb1bf54 --- /dev/null +++ b/quilt/build.gradle @@ -0,0 +1,88 @@ +plugins { + id "com.github.johnrengelman.shadow" version "7.1.2" +} + +repositories { + maven { url "https://maven.quiltmc.org/repository/release/" } +} + +architectury { + platformSetupLoomIde() + loader("quilt") +} + +configurations { + common + shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this. + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentQuilt.extendsFrom common +} + +dependencies { + modImplementation "org.quiltmc:quilt-loader:${rootProject.quilt_loader_version}" + modApi "org.quiltmc.quilted-fabric-api:quilted-fabric-api:${rootProject.quilt_fabric_api_version}" + // Remove the next few lines if you don't want to depend on the API + modApi("dev.architectury:architectury-fabric:${rootProject.architectury_version}") { + // We must not pull Fabric Loader from Architectury Fabric + exclude group: "net.fabricmc" + exclude group: "net.fabricmc.fabric-api" + } + + common(project(path: ":common", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":common", configuration: "transformProductionQuilt")) { transitive false } + common(project(path: ":fabric-like", configuration: "namedElements")) { transitive false } + shadowCommon(project(path: ":fabric-like", configuration: "transformProductionQuilt")) { transitive false } +} + +processResources { + inputs.property "group", rootProject.maven_group + inputs.property "version", project.version + + filesMatching("quilt.mod.json") { + expand "group": rootProject.maven_group, + "version": project.version + } +} + +shadowJar { + configurations = [project.configurations.shadowCommon] + classifier "dev-shadow" +} + +remapJar { + injectAccessWidener = true + input.set shadowJar.archiveFile + dependsOn shadowJar + classifier null +} + +jar { + classifier "dev" +} + +sourcesJar { + def commonSources = project(":common").sourcesJar + dependsOn commonSources + from commonSources.archiveFile.map { zipTree(it) } +} + +components.java { + withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) { + skip() + } +} + +publishing { + publications { + mavenQuilt(MavenPublication) { + artifactId = rootProject.archives_base_name + "-" + project.name + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + } +} diff --git a/quilt/gradle.properties b/quilt/gradle.properties new file mode 100644 index 00000000..96758ce8 --- /dev/null +++ b/quilt/gradle.properties @@ -0,0 +1 @@ +loom.platform=quilt \ No newline at end of file diff --git a/quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java b/quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java new file mode 100644 index 00000000..7aaae485 --- /dev/null +++ b/quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java @@ -0,0 +1,15 @@ +package net.examplemod.fabric; + +import net.examplemod.ExampleExpectPlatform; +import org.quiltmc.loader.api.QuiltLoader; + +import java.nio.file.Path; + +public class ExampleExpectPlatformImpl { + /** + * This is our actual method to {@link ExampleExpectPlatform#getConfigDirectory()}. + */ + public static Path getConfigDirectory() { + return QuiltLoader.getConfigDir(); + } +} diff --git a/quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java b/quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java new file mode 100644 index 00000000..10e21537 --- /dev/null +++ b/quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java @@ -0,0 +1,12 @@ +package net.examplemod.quilt; + +import net.examplemod.fabriclike.ExampleModFabricLike; +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; + +public class ExampleModQuilt implements ModInitializer { + @Override + public void onInitialize(ModContainer mod) { + ExampleModFabricLike.init(); + } +} diff --git a/quilt/src/main/resources/examplemod.mixins.json b/quilt/src/main/resources/examplemod.mixins.json new file mode 100644 index 00000000..ab40cb1a --- /dev/null +++ b/quilt/src/main/resources/examplemod.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "package": "net.examplemod.mixin.fabric", + "compatibilityLevel": "JAVA_16", + "client": [ + ], + "mixins": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/quilt/src/main/resources/quilt.mod.json b/quilt/src/main/resources/quilt.mod.json new file mode 100644 index 00000000..832b923c --- /dev/null +++ b/quilt/src/main/resources/quilt.mod.json @@ -0,0 +1,45 @@ +{ + "schema_version": 1, + "mixin": [ + "examplemod.mixins.json", + "examplemod-common.mixins.json" + ], + "quilt_loader": { + "group": "${group}", + "id": "examplemod", + "version": "${version}", + "name": "Example Mod", + "description": "This is an example description! Tell everyone what your mod is about!", + "authors": ["Me!"], + "contact": { + "sources": "https://github.com/architectury/architectury-templates" + }, + "license": "Insert License Here", + "icon": "assets/examplemod/icon.png", + "intermediate_mappings": "net.fabricmc:intermediary", + "environment": "*", + "entrypoints": { + "init": [ + "net.examplemod.quilt.ExampleModQuilt" + ] + }, + "depends": [ + { + "id": "quilt_loader", + "version": "*" + }, + { + "id": "quilt_base", + "version": "*" + }, + { + "id": "minecraft", + "version": ">=1.18.2" + }, + { + "id": "architectury", + "version": ">=4.4.59" + } + ] + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c22c48fb..8e0761d5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,9 @@ pluginManagement { } include("common") +include("fabric-like") include("fabric") -include("forge") +//TODO: Activate later again include("quilt") +//TODO: Activate later again include("forge") rootProject.name = "itemtransformhelper" From 3dc38961ad0ecf982cb9df2ccd80944eb9aa6544 Mon Sep 17 00:00:00 2001 From: Nico Mexis Date: Sun, 12 Jun 2022 19:19:19 +0200 Subject: [PATCH 10/10] Enable all platforms on 1.19 --- build.gradle | 6 +- .../ClientTickHandler.java | 26 ++--- .../itemtransformhelper/HUDTextRenderer.java | 97 ++++++++++--------- .../java/itemtransformhelper/ItemCamera.java | 24 ++--- .../ItemModelFlexibleCamera.java | 42 ++++---- .../MenuItemCameraTransforms.java | 78 +++++++-------- .../ModelBakeEventHandler.java | 22 ++--- .../itemtransformhelper/StartupCommon.java | 16 +-- .../fabric/ItemModelFlexibleCameraImpl.java | 2 +- .../fabric/mixin/BakedModelManagerMixin.java | 31 ------ .../{InGameHudMixin.java => GuiMixin.java} | 14 +-- ...ftClientMixin.java => MinecraftMixin.java} | 9 +- .../fabric/mixin/ModelManagerMixin.java | 33 +++++++ fabric/src/main/resources/fabric.mod.json | 4 +- .../resources/itemtransformhelper.mixins.json | 8 +- .../forge/ItemModelFlexibleCameraImpl.java | 16 +-- .../forge/MenuItemCameraTransformsImpl.java | 2 +- forge/src/main/resources/META-INF/mods.toml | 8 +- forge/src/main/resources/pack.mcmeta | 2 +- gradle.properties | 19 ++-- .../fabric/ItemModelFlexibleCameraImpl.java | 17 ++++ .../fabric/MenuItemCameraTransformsImpl.java | 19 ++++ .../fabric/StartupClientOnlyImpl.java | 11 +++ .../quilt/ItemTransformHelperQuilt.java | 14 +++ .../quilt/mixin/GuiMixin.java | 20 ++++ .../quilt/mixin/MinecraftMixin.java | 24 +++++ .../quilt/mixin/ModelManagerMixin.java | 33 +++++++ .../fabric/ExampleExpectPlatformImpl.java | 15 --- .../net/examplemod/quilt/ExampleModQuilt.java | 12 --- .../src/main/resources/examplemod.mixins.json | 12 --- .../resources/itemtransformhelper.mixins.json | 14 +++ quilt/src/main/resources/quilt.mod.json | 31 +++--- settings.gradle | 4 +- 33 files changed, 403 insertions(+), 282 deletions(-) delete mode 100644 fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java rename fabric/src/main/java/itemtransformhelper/fabric/mixin/{InGameHudMixin.java => GuiMixin.java} (56%) rename fabric/src/main/java/itemtransformhelper/fabric/mixin/{MinecraftClientMixin.java => MinecraftMixin.java} (80%) create mode 100644 fabric/src/main/java/itemtransformhelper/fabric/mixin/ModelManagerMixin.java create mode 100644 quilt/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java create mode 100644 quilt/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java create mode 100644 quilt/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java create mode 100644 quilt/src/main/java/itemtransformhelper/quilt/ItemTransformHelperQuilt.java create mode 100644 quilt/src/main/java/itemtransformhelper/quilt/mixin/GuiMixin.java create mode 100644 quilt/src/main/java/itemtransformhelper/quilt/mixin/MinecraftMixin.java create mode 100644 quilt/src/main/java/itemtransformhelper/quilt/mixin/ModelManagerMixin.java delete mode 100644 quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java delete mode 100644 quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java delete mode 100644 quilt/src/main/resources/examplemod.mixins.json create mode 100644 quilt/src/main/resources/itemtransformhelper.mixins.json diff --git a/build.gradle b/build.gradle index fabeb056..0ff8b6bc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "0.11.0-SNAPSHOT" apply false + id "dev.architectury.loom" version "0.12.0-SNAPSHOT" apply false } architectury { @@ -17,9 +17,9 @@ subprojects { dependencies { minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" // The following line declares the mojmap mappings, you may use other mappings as well - // mappings loom.officialMojangMappings() + mappings loom.officialMojangMappings() // The following line declares the yarn mappings you may select this one as well. - mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2" + // mappings "net.fabricmc:yarn:${rootProject.yarn_mappings}:v2" } } diff --git a/common/src/main/java/itemtransformhelper/ClientTickHandler.java b/common/src/main/java/itemtransformhelper/ClientTickHandler.java index 228c4769..29c3684b 100644 --- a/common/src/main/java/itemtransformhelper/ClientTickHandler.java +++ b/common/src/main/java/itemtransformhelper/ClientTickHandler.java @@ -1,11 +1,11 @@ package itemtransformhelper; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.entity.EquipmentSlot; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.ItemStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; /** * User: The Grey Ghost @@ -16,13 +16,13 @@ public class ClientTickHandler { public void clientTickEvent() { - ClientPlayerEntity player = MinecraftClient.getInstance().player; + LocalPlayer player = Minecraft.getInstance().player; if (player == null) return; boolean foundCamera = false; - PlayerInventory inventory = player.getInventory(); - for (int i = 0; i < PlayerInventory.getHotbarSize(); ++i) { - ItemStack stack = inventory.main.get(i); + Inventory inventory = player.getInventory(); + for (int i = 0; i < Inventory.getSelectionSize(); ++i) { + ItemStack stack = inventory.items.get(i); if (stack.getItem() == StartupCommon.ITEM_CAMERA.get()) { foundCamera = true; break; @@ -32,12 +32,12 @@ public void clientTickEvent() { BakedModel bakedModel = null; if (foundCamera) { - ItemStack heldItemStack = player.getEquippedStack(EquipmentSlot.MAINHAND); + ItemStack heldItemStack = player.getItemInHand(InteractionHand.MAIN_HAND); if (heldItemStack.isEmpty()) { - heldItemStack = player.getEquippedStack(EquipmentSlot.OFFHAND); + heldItemStack = player.getItemInHand(InteractionHand.OFF_HAND); } if (!heldItemStack.isEmpty()) { - bakedModel = MinecraftClient.getInstance().getItemRenderer().getModels().getModel(heldItemStack); + bakedModel = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(heldItemStack); } } diff --git a/common/src/main/java/itemtransformhelper/HUDTextRenderer.java b/common/src/main/java/itemtransformhelper/HUDTextRenderer.java index b665a395..474dad51 100644 --- a/common/src/main/java/itemtransformhelper/HUDTextRenderer.java +++ b/common/src/main/java/itemtransformhelper/HUDTextRenderer.java @@ -1,13 +1,13 @@ package itemtransformhelper; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; import java.util.ArrayList; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawableHelper; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.render.model.json.Transformation; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.Vec3f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.renderer.block.model.ItemTransform; +import net.minecraft.client.renderer.block.model.ItemTransforms; /** * User: The Grey Ghost @@ -37,7 +37,7 @@ public HUDTextRenderer(HUDInfoUpdateLink hudInfoUpdateLink) { * Draw the Head Up Display menu on screen. * The information is taken from the hudInfoUpdateLink which is updated by other classes. */ - public void displayHUDText(MatrixStack matrixStack) { + public void displayHUDText(PoseStack poseStack) { if (hudInfoUpdateLink == null || !hudInfoUpdateLink.menuVisible || hudInfoUpdateLink.itemCameraTransforms == null) return; ArrayList displayText = new ArrayList<>(); @@ -47,7 +47,7 @@ public void displayHUDText(MatrixStack matrixStack) { selectableField.add(NOT_SELECTABLE); displayText.add("VIEW "); selectableField.add(NOT_SELECTABLE); - Transformation transformation; + ItemTransform transformation; switch (hudInfoUpdateLink.selectedTransform) { case THIRD_LEFT -> { @@ -82,7 +82,8 @@ public void displayHUDText(MatrixStack matrixStack) { displayText.add("grnd"); transformation = hudInfoUpdateLink.itemCameraTransforms.ground; } - default -> throw new IllegalArgumentException("Unknown cameraTransformType:" + hudInfoUpdateLink.selectedTransform); + default -> + throw new IllegalArgumentException("Unknown cameraTransformType:" + hudInfoUpdateLink.selectedTransform); } selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSFORM); @@ -90,22 +91,22 @@ public void displayHUDText(MatrixStack matrixStack) { selectableField.add(NOT_SELECTABLE); displayText.add("SCALE"); selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%.2f", transformation.scale.getX())); + displayText.add("X:" + String.format("%.2f", transformation.scale.x())); selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_X); - displayText.add("Y:" + String.format("%.2f", transformation.scale.getY())); + displayText.add("Y:" + String.format("%.2f", transformation.scale.y())); selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_Y); - displayText.add("Z:" + String.format("%.2f", transformation.scale.getZ())); + displayText.add("Z:" + String.format("%.2f", transformation.scale.z())); selectableField.add(HUDInfoUpdateLink.SelectedField.SCALE_Z); displayText.add("======"); selectableField.add(NOT_SELECTABLE); displayText.add("ROTATE"); selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%3.0f", transformation.rotation.getX())); + displayText.add("X:" + String.format("%3.0f", transformation.rotation.x())); selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_X); - displayText.add("Y:" + String.format("%3.0f", transformation.rotation.getY())); + displayText.add("Y:" + String.format("%3.0f", transformation.rotation.y())); selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_Y); - displayText.add("Z:" + String.format("%3.0f", transformation.rotation.getZ())); + displayText.add("Z:" + String.format("%3.0f", transformation.rotation.z())); selectableField.add(HUDInfoUpdateLink.SelectedField.ROTATE_Z); final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see Transformation.Deserializer::deserialize @@ -113,11 +114,11 @@ public void displayHUDText(MatrixStack matrixStack) { selectableField.add(NOT_SELECTABLE); displayText.add("TRANSL"); selectableField.add(NOT_SELECTABLE); - displayText.add("X:" + String.format("%.2f", transformation.translation.getX() * TRANSLATE_MULTIPLIER)); + displayText.add("X:" + String.format("%.2f", transformation.translation.x() * TRANSLATE_MULTIPLIER)); selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_X); - displayText.add("Y:" + String.format("%.2f", transformation.translation.getY() * TRANSLATE_MULTIPLIER)); + displayText.add("Y:" + String.format("%.2f", transformation.translation.y() * TRANSLATE_MULTIPLIER)); selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_Y); - displayText.add("Z:" + String.format("%.2f", transformation.translation.getZ() * TRANSLATE_MULTIPLIER)); + displayText.add("Z:" + String.format("%.2f", transformation.translation.z() * TRANSLATE_MULTIPLIER)); selectableField.add(HUDInfoUpdateLink.SelectedField.TRANSLATE_Z); displayText.add("======"); @@ -131,19 +132,19 @@ public void displayHUDText(MatrixStack matrixStack) { displayText.add("======"); selectableField.add(NOT_SELECTABLE); - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + Font textRenderer = Minecraft.getInstance().font; int yPos = 2; int xPos = 2; for (int i = 0; i < displayText.size(); ++i) { String msg = displayText.get(i); - yPos += textRenderer.fontHeight; + yPos += textRenderer.lineHeight; if (msg == null) continue; boolean fieldIsSelected = hudInfoUpdateLink.selectedField == selectableField.get(i); int highlightColour = fieldIsSelected ? GREEN_HALF_TRANSPARENT : MED_GRAY_HALF_TRANSPARENT; - DrawableHelper.fill(matrixStack, xPos - 1, yPos - 1, - xPos + textRenderer.getWidth(msg) + 1, yPos + textRenderer.fontHeight - 1, highlightColour); + GuiComponent.fill(poseStack, xPos - 1, yPos - 1, + xPos + textRenderer.width(msg) + 1, yPos + textRenderer.lineHeight - 1, highlightColour); int stringColour = fieldIsSelected ? BLACK : LIGHT_GRAY; - textRenderer.draw(matrixStack, msg, xPos, yPos, stringColour); + textRenderer.draw(poseStack, msg, xPos, yPos, stringColour); } } @@ -152,25 +153,25 @@ public void displayHUDText(MatrixStack matrixStack) { */ public static class HUDInfoUpdateLink { - private static final Vec3f ROTATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); - private static final Vec3f TRANSLATION_DEFAULT = new Vec3f(0.0F, 0.0F, 0.0F); - private static final Vec3f SCALE_DEFAULT = new Vec3f(1.0F, 1.0F, 1.0F); + private static final Vector3f ROTATION_DEFAULT = new Vector3f(0.0F, 0.0F, 0.0F); + private static final Vector3f TRANSLATION_DEFAULT = new Vector3f(0.0F, 0.0F, 0.0F); + private static final Vector3f SCALE_DEFAULT = new Vector3f(1.0F, 1.0F, 1.0F); - public ModelTransformation itemCameraTransforms; + public ItemTransforms itemCameraTransforms; public SelectedField selectedField; public TransformName selectedTransform; public boolean menuVisible; public HUDInfoUpdateLink() { - Transformation trThirdLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trThirdRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trFirstLeft = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trFirstRight = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trHead = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trGui = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trGround = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - Transformation trFixed = new Transformation(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); - itemCameraTransforms = new ModelTransformation(trThirdLeft, trThirdRight, trFirstLeft, trFirstRight, + ItemTransform trThirdLeft = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trThirdRight = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trFirstLeft = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trFirstRight = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trHead = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trGui = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trGround = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + ItemTransform trFixed = new ItemTransform(ROTATION_DEFAULT, TRANSLATION_DEFAULT, SCALE_DEFAULT); + itemCameraTransforms = new ItemTransforms(trThirdLeft, trThirdRight, trFirstLeft, trFirstRight, trHead, trGui, trGround, trFixed); selectedField = SelectedField.TRANSFORM; @@ -180,18 +181,18 @@ public HUDInfoUpdateLink() { public enum TransformName { - THIRD_LEFT(ModelTransformation.Mode.THIRD_PERSON_LEFT_HAND), - THIRD_RIGHT(ModelTransformation.Mode.THIRD_PERSON_RIGHT_HAND), - FIRST_LEFT(ModelTransformation.Mode.FIRST_PERSON_LEFT_HAND), - FIRST_RIGHT(ModelTransformation.Mode.FIRST_PERSON_RIGHT_HAND), - HEAD(ModelTransformation.Mode.HEAD), - GUI(ModelTransformation.Mode.GUI), - GROUND(ModelTransformation.Mode.GROUND), - FIXED(ModelTransformation.Mode.FIXED); + THIRD_LEFT(ItemTransforms.TransformType.THIRD_PERSON_LEFT_HAND), + THIRD_RIGHT(ItemTransforms.TransformType.THIRD_PERSON_RIGHT_HAND), + FIRST_LEFT(ItemTransforms.TransformType.FIRST_PERSON_LEFT_HAND), + FIRST_RIGHT(ItemTransforms.TransformType.FIRST_PERSON_RIGHT_HAND), + HEAD(ItemTransforms.TransformType.HEAD), + GUI(ItemTransforms.TransformType.GUI), + GROUND(ItemTransforms.TransformType.GROUND), + FIXED(ItemTransforms.TransformType.FIXED); public static final TransformName[] VALUES = TransformName.values(); - private final ModelTransformation.Mode vanillaType; + private final ItemTransforms.TransformType vanillaType; public TransformName getNext() { for (TransformName transformName : VALUES) { @@ -207,11 +208,11 @@ public TransformName getPrevious() { return FIXED; } - public ModelTransformation.Mode getVanillaTransformType() { + public ItemTransforms.TransformType getVanillaTransformType() { return vanillaType; } - TransformName(ModelTransformation.Mode vanillaType) { + TransformName(ItemTransforms.TransformType vanillaType) { this.vanillaType = vanillaType; } diff --git a/common/src/main/java/itemtransformhelper/ItemCamera.java b/common/src/main/java/itemtransformhelper/ItemCamera.java index 37d65098..ca26ca35 100644 --- a/common/src/main/java/itemtransformhelper/ItemCamera.java +++ b/common/src/main/java/itemtransformhelper/ItemCamera.java @@ -1,11 +1,12 @@ package itemtransformhelper; import java.util.List; -import net.minecraft.client.item.TooltipContext; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.text.Text; -import net.minecraft.world.World; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -17,15 +18,16 @@ public class ItemCamera extends Item { public ItemCamera() { - super(new Settings().maxCount(1).group(StartupCommon.ITH_ITEM_GROUP)); + super(new Properties().stacksTo(1).tab(StartupCommon.ITH_ITEM_GROUP)); } @Override - public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext context) { - tooltip.add(Text.literal("1) Place the camera in your hotbar")); - tooltip.add(Text.literal("2) Hold an item in your hand")); - tooltip.add(Text.literal("3) Use the cursor keys to")); - tooltip.add(Text.literal(" modify the item transform.")); + public void appendHoverText(@NotNull ItemStack itemStack, @Nullable Level level, List list, + @NotNull TooltipFlag tooltipFlag) { + list.add(Component.literal("1) Place the camera in your hotbar")); + list.add(Component.literal("2) Hold an item in your hand")); + list.add(Component.literal("3) Use the cursor keys to")); + list.add(Component.literal(" modify the item transform.")); } } diff --git a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java index f002a2ad..2700c73e 100644 --- a/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java +++ b/common/src/main/java/itemtransformhelper/ItemModelFlexibleCamera.java @@ -3,14 +3,14 @@ import dev.architectury.injectables.annotations.ExpectPlatform; import java.util.List; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.render.model.json.ModelOverrideList; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.texture.Sprite; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.Random; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,14 +45,14 @@ public static ItemModelFlexibleCamera create(BakedModel originalModel, UpdateLin @NotNull @Override - public ModelTransformation getTransformation() { + public ItemTransforms getTransforms() { return (updateLink.itemModelToOverride == this) ? updateLink.forcedTransform - : originalModel.getTransformation(); + : originalModel.getTransforms(); } @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) { + public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) { return originalModel.getQuads(state, side, rand); } @@ -62,27 +62,27 @@ public boolean useAmbientOcclusion() { } @Override - public boolean hasDepth() { - return originalModel.hasDepth(); + public boolean isGui3d() { + return originalModel.isGui3d(); } @Override - public boolean isSideLit() { - return originalModel.isSideLit(); + public boolean usesBlockLight() { + return originalModel.usesBlockLight(); } @Override - public boolean isBuiltin() { - return originalModel.isBuiltin(); + public boolean isCustomRenderer() { + return originalModel.isCustomRenderer(); } @Override - public Sprite getParticleSprite() { - return originalModel.getParticleSprite(); + public TextureAtlasSprite getParticleIcon() { + return originalModel.getParticleIcon(); } @Override - public ModelOverrideList getOverrides() { + public ItemOverrides getOverrides() { return originalModel.getOverrides(); } @@ -90,7 +90,7 @@ public static class UpdateLink { public BakedModel itemModelToOverride; - public ModelTransformation forcedTransform; + public ItemTransforms forcedTransform; } diff --git a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java index 28319898..84410278 100644 --- a/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java +++ b/common/src/main/java/itemtransformhelper/MenuItemCameraTransforms.java @@ -2,12 +2,12 @@ import dev.architectury.injectables.annotations.ExpectPlatform; import java.util.Locale; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.render.model.json.Transformation; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.ItemTransform; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; @@ -41,7 +41,7 @@ public static void registerListeners(HUDTextRenderer hudTextRenderer, MenuKeyHan * * @return the transform */ - public ModelTransformation getItemCameraTransforms() { + public ItemTransforms getItemCameraTransforms() { return linkToHudRenderer.itemCameraTransforms; } @@ -71,7 +71,7 @@ void keyPressed(MenuKeyHandler.ArrowKeys whichKey) { } private void alterField(boolean increase) { - Transformation transformVec3f = getItemTransformRef(linkToHudRenderer, linkToHudRenderer.selectedTransform); + ItemTransform transformVec3f = getItemTransformRef(linkToHudRenderer, linkToHudRenderer.selectedTransform); if (transformVec3f == null) return; // should never happen final float SCALE_INCREMENT = 0.01F; @@ -85,19 +85,19 @@ private void alterField(boolean increase) { case SCALE_Y -> transformVec3f.scale.add(0, increase ? SCALE_INCREMENT : -SCALE_INCREMENT, 0); case SCALE_Z -> transformVec3f.scale.add(0, 0, increase ? SCALE_INCREMENT : -SCALE_INCREMENT); case ROTATE_X -> { - float newAngle = transformVec3f.rotation.getX() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); - newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; - transformVec3f.rotation.set(newAngle, transformVec3f.rotation.getY(), transformVec3f.rotation.getZ()); + float newAngle = transformVec3f.rotation.x() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); + newAngle = Mth.wrapDegrees(newAngle - 180) + 180; + transformVec3f.rotation.set(newAngle, transformVec3f.rotation.y(), transformVec3f.rotation.z()); } case ROTATE_Y -> { - float newAngle = transformVec3f.rotation.getY() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); - newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; - transformVec3f.rotation.set(transformVec3f.rotation.getX(), newAngle, transformVec3f.rotation.getZ()); + float newAngle = transformVec3f.rotation.y() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); + newAngle = Mth.wrapDegrees(newAngle - 180) + 180; + transformVec3f.rotation.set(transformVec3f.rotation.x(), newAngle, transformVec3f.rotation.z()); } case ROTATE_Z -> { - float newAngle = transformVec3f.rotation.getZ() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); - newAngle = MathHelper.wrapDegrees(newAngle - 180) + 180; - transformVec3f.rotation.set(transformVec3f.rotation.getX(), transformVec3f.rotation.getY(), newAngle); + float newAngle = transformVec3f.rotation.z() + (increase ? ROTATION_INCREMENT : -ROTATION_INCREMENT); + newAngle = Mth.wrapDegrees(newAngle - 180) + 180; + transformVec3f.rotation.set(transformVec3f.rotation.x(), transformVec3f.rotation.y(), newAngle); } case TRANSLATE_X -> transformVec3f.translation .add(increase ? TRANSLATION_INCREMENT : -TRANSLATION_INCREMENT, 0, 0); @@ -144,15 +144,15 @@ private void alterField(boolean increase) { printTransform(output, "ground", linkToHudRenderer.itemCameraTransforms.ground); output.append("\n}"); LOGGER.info(output); - Text text = Text.literal("\"display\" JSON section printed to console (LOGGER.info)..."); - MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(text); + Component text = Component.literal("\"display\" JSON section printed to console (LOGGER.info)..."); + Minecraft.getInstance().gui.getChat().addMessage(text); } } } // points to the appropriate transform based on which transform has been selected. - private static Transformation getItemTransformRef(HUDTextRenderer.HUDInfoUpdateLink linkToHUDRenderer, - HUDTextRenderer.HUDInfoUpdateLink.TransformName transformName) { + private static ItemTransform getItemTransformRef(HUDTextRenderer.HUDInfoUpdateLink linkToHUDRenderer, + HUDTextRenderer.HUDInfoUpdateLink.TransformName transformName) { return switch (transformName) { case THIRD_LEFT -> linkToHUDRenderer.itemCameraTransforms.thirdPersonLeftHand; case THIRD_RIGHT -> linkToHUDRenderer.itemCameraTransforms.thirdPersonRightHand; @@ -167,37 +167,37 @@ private static Transformation getItemTransformRef(HUDTextRenderer.HUDInfoUpdateL private void copySingleTransform(HUDTextRenderer.HUDInfoUpdateLink linkToHUDRenderer, BakedModel savedModel, HUDTextRenderer.HUDInfoUpdateLink.TransformName transformToBeCopied) { - Transformation transformation = getItemTransformRef(linkToHUDRenderer, transformToBeCopied); - ModelTransformation.Mode currentType = transformToBeCopied.getVanillaTransformType(); - Transformation transform = savedModel.getTransformation().getTransformation(currentType); + ItemTransform transformation = getItemTransformRef(linkToHUDRenderer, transformToBeCopied); + ItemTransforms.TransformType currentType = transformToBeCopied.getVanillaTransformType(); + ItemTransform transform = savedModel.getTransforms().getTransform(currentType); copyTransforms(transform, transformation); } - private static void printTransform(StringBuilder output, String transformView, Transformation transformation) { + private static void printTransform(StringBuilder output, String transformView, ItemTransform transformation) { output.append(" \"").append(transformView).append("\": {\n"); output.append(" \"rotation\": [ "); - output.append(String.format(Locale.US, "%.0f, ", transformation.rotation.getX())); - output.append(String.format(Locale.US, "%.0f, ", transformation.rotation.getY())); - output.append(String.format(Locale.US, "%.0f ],", transformation.rotation.getZ())); + output.append(String.format(Locale.US, "%.0f, ", transformation.rotation.x())); + output.append(String.format(Locale.US, "%.0f, ", transformation.rotation.y())); + output.append(String.format(Locale.US, "%.0f ],", transformation.rotation.z())); output.append("\n"); final double TRANSLATE_MULTIPLIER = 1 / 0.0625; // see Transformation.Deserializer::deserialize output.append(" \"translation\": [ "); - output.append(String.format(Locale.US, "%.2f, ", transformation.translation.getX() * TRANSLATE_MULTIPLIER)); - output.append(String.format(Locale.US, "%.2f, ", transformation.translation.getY() * TRANSLATE_MULTIPLIER)); - output.append(String.format(Locale.US, "%.2f ],", transformation.translation.getZ() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f, ", transformation.translation.x() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f, ", transformation.translation.y() * TRANSLATE_MULTIPLIER)); + output.append(String.format(Locale.US, "%.2f ],", transformation.translation.z() * TRANSLATE_MULTIPLIER)); output.append("\n"); output.append(" \"scale\": [ "); - output.append(String.format(Locale.US, "%.2f, ", transformation.scale.getX())); - output.append(String.format(Locale.US, "%.2f, ", transformation.scale.getY())); - output.append(String.format(Locale.US, "%.2f ]", transformation.scale.getZ())); + output.append(String.format(Locale.US, "%.2f, ", transformation.scale.x())); + output.append(String.format(Locale.US, "%.2f, ", transformation.scale.y())); + output.append(String.format(Locale.US, "%.2f ]", transformation.scale.z())); output.append("\n }"); } - private static void copyTransforms(Transformation from, Transformation to) { - to.translation.set(from.translation); - to.scale.set(from.scale); - to.rotation.set(from.rotation); + private static void copyTransforms(ItemTransform from, ItemTransform to) { + to.translation.load(from.translation); + to.scale.load(from.scale); + to.rotation.load(from.rotation); } /** @@ -236,7 +236,7 @@ public void clientTick() { } static boolean isKeyDown(int key) { - return GLFW.glfwGetKey(MinecraftClient.getInstance().getWindow().getHandle(), key) == GLFW.GLFW_PRESS; + return GLFW.glfwGetKey(Minecraft.getInstance().getWindow().getWindow(), key) == GLFW.GLFW_PRESS; } public enum ArrowKeys {NONE, UP, DOWN, LEFT, RIGHT} diff --git a/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java b/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java index 8cd0f018..68cabc72 100644 --- a/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java +++ b/common/src/main/java/itemtransformhelper/ModelBakeEventHandler.java @@ -1,10 +1,10 @@ package itemtransformhelper; import java.util.Map; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.render.model.json.Transformation; -import net.minecraft.util.Identifier; +import net.minecraft.client.renderer.block.model.ItemTransform; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.resources.ResourceLocation; /** * User: The Grey Ghost @@ -20,15 +20,15 @@ public class ModelBakeEventHandler { private final ItemModelFlexibleCamera.UpdateLink itemOverrideLink = new ItemModelFlexibleCamera.UpdateLink(); public ModelBakeEventHandler() { - itemOverrideLink.forcedTransform = new ModelTransformation( - Transformation.IDENTITY, Transformation.IDENTITY, - Transformation.IDENTITY, Transformation.IDENTITY, - Transformation.IDENTITY, Transformation.IDENTITY, - Transformation.IDENTITY, Transformation.IDENTITY); + itemOverrideLink.forcedTransform = new ItemTransforms( + ItemTransform.NO_TRANSFORM, ItemTransform.NO_TRANSFORM, + ItemTransform.NO_TRANSFORM, ItemTransform.NO_TRANSFORM, + ItemTransform.NO_TRANSFORM, ItemTransform.NO_TRANSFORM, + ItemTransform.NO_TRANSFORM, ItemTransform.NO_TRANSFORM); } - public void modelBakeEvent(Map modelRegistry) { - for (Identifier modelKey : modelRegistry.keySet()) { + public void modelBakeEvent(Map modelRegistry) { + for (ResourceLocation modelKey : modelRegistry.keySet()) { BakedModel bakedModel = modelRegistry.get(modelKey); ItemModelFlexibleCamera wrappedModel = ItemModelFlexibleCamera.create(bakedModel, itemOverrideLink); modelRegistry.put(modelKey, wrappedModel); diff --git a/common/src/main/java/itemtransformhelper/StartupCommon.java b/common/src/main/java/itemtransformhelper/StartupCommon.java index e4cc638c..92696c48 100644 --- a/common/src/main/java/itemtransformhelper/StartupCommon.java +++ b/common/src/main/java/itemtransformhelper/StartupCommon.java @@ -3,11 +3,11 @@ import dev.architectury.registry.CreativeTabRegistry; import dev.architectury.registry.registries.DeferredRegister; import dev.architectury.registry.registries.RegistrySupplier; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import static itemtransformhelper.ItemTransformHelper.MODID; @@ -27,14 +27,14 @@ public class StartupCommon { // Registries - public static final DeferredRegister ITEMS = DeferredRegister.create(MODID, Registry.ITEM_KEY); + public static final DeferredRegister ITEMS = DeferredRegister.create(MODID, Registry.ITEM_REGISTRY); // Items public static final RegistrySupplier ITEM_CAMERA = ITEMS.register("item_camera", ItemCamera::new); // Item Groups - public static final ItemGroup ITH_ITEM_GROUP = - CreativeTabRegistry.create(new Identifier(MODID, "items"), () -> new ItemStack(ITEM_CAMERA.get())); + public static final CreativeModeTab ITH_ITEM_GROUP = + CreativeTabRegistry.create(new ResourceLocation(MODID, "items"), () -> new ItemStack(ITEM_CAMERA.get())); public static void init() { ITEMS.register(); diff --git a/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java b/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java index 6e651ae3..088913b1 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java @@ -1,7 +1,7 @@ package itemtransformhelper.fabric; import itemtransformhelper.ItemModelFlexibleCamera; -import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.resources.model.BakedModel; public class ItemModelFlexibleCameraImpl extends ItemModelFlexibleCamera { diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java deleted file mode 100644 index 1c2576a6..00000000 --- a/fabric/src/main/java/itemtransformhelper/fabric/mixin/BakedModelManagerMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package itemtransformhelper.fabric.mixin; - -import java.util.Map; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.BakedModelManager; -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; -import net.minecraft.util.profiler.Profiler; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import static itemtransformhelper.StartupClientOnly.modelBakeEventHandler; - -@Mixin(BakedModelManager.class) -public class BakedModelManagerMixin { - - @Shadow - private Map models; - - @Inject(method = "apply(Lnet/minecraft/client/render/model/ModelLoader;Lnet/minecraft/resource/ResourceManager;" - + "Lnet/minecraft/util/profiler/Profiler;)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V")) - public void apply(ModelLoader modelLoader, ResourceManager resourceManager, Profiler profiler, CallbackInfo ci) { - modelBakeEventHandler.modelBakeEvent(models); - } - -} diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/GuiMixin.java similarity index 56% rename from fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java rename to fabric/src/main/java/itemtransformhelper/fabric/mixin/GuiMixin.java index 8c360967..236503be 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/mixin/InGameHudMixin.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/GuiMixin.java @@ -1,7 +1,7 @@ package itemtransformhelper.fabric.mixin; -import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.util.math.MatrixStack; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.Gui; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -9,12 +9,12 @@ import static itemtransformhelper.fabric.MenuItemCameraTransformsImpl.RENDERERS; -@Mixin(InGameHud.class) -public class InGameHudMixin { +@Mixin(Gui.class) +public class GuiMixin { - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;" - + "renderStatusEffectOverlay(Lnet/minecraft/client/util/math/MatrixStack;)V")) - public void render(MatrixStack matrices, float tickDelta, CallbackInfo ci) { + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;renderEffects" + + "(Lcom/mojang/blaze3d/vertex/PoseStack;)V")) + public void render(PoseStack matrices, float tickDelta, CallbackInfo ci) { RENDERERS.forEach(r -> r.displayHUDText(matrices)); } diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftMixin.java similarity index 80% rename from fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java rename to fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftMixin.java index b6c36383..0dad52d4 100644 --- a/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftClientMixin.java +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/MinecraftMixin.java @@ -1,7 +1,7 @@ package itemtransformhelper.fabric.mixin; import itemtransformhelper.MenuItemCameraTransforms; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -10,11 +10,12 @@ import static itemtransformhelper.StartupClientOnly.clientTickHandler; import static itemtransformhelper.fabric.MenuItemCameraTransformsImpl.HANDLERS; -@Mixin(MinecraftClient.class) -public class MinecraftClientMixin { +@Mixin(Minecraft.class) +public class MinecraftMixin { @Inject(method = "tick", - at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;push(Ljava/lang/String;)V")) + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/lang/String;" + + ")V")) public void tick(CallbackInfo ci) { clientTickHandler.clientTickEvent(); HANDLERS.forEach(MenuItemCameraTransforms.MenuKeyHandler::clientTick); diff --git a/fabric/src/main/java/itemtransformhelper/fabric/mixin/ModelManagerMixin.java b/fabric/src/main/java/itemtransformhelper/fabric/mixin/ModelManagerMixin.java new file mode 100644 index 00000000..c44b7aae --- /dev/null +++ b/fabric/src/main/java/itemtransformhelper/fabric/mixin/ModelManagerMixin.java @@ -0,0 +1,33 @@ +package itemtransformhelper.fabric.mixin; + +import java.util.Map; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static itemtransformhelper.StartupClientOnly.modelBakeEventHandler; + +@Mixin(ModelManager.class) +public class ModelManagerMixin { + + @Shadow + private Map bakedRegistry; + + @Inject(method = "apply(Lnet/minecraft/client/resources/model/ModelBakery;" + + "Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush" + + "(Ljava/lang/String;)V")) + public void apply(ModelBakery modelLoader, ResourceManager resourceManager, ProfilerFiller profiler, + CallbackInfo ci) { + modelBakeEventHandler.modelBakeEvent(bakedRegistry); + } + +} diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 48d04be6..ef9c522c 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -27,8 +27,8 @@ ], "depends": { "minecraft": ">=1.19", - "fabricloader": ">=0.14.6", + "fabricloader": ">=0.14.7", "fabric": "*", - "architectury": ">=5.4.15" + "architectury": ">=5.6.22" } } diff --git a/fabric/src/main/resources/itemtransformhelper.mixins.json b/fabric/src/main/resources/itemtransformhelper.mixins.json index 5236f881..adf02d3b 100644 --- a/fabric/src/main/resources/itemtransformhelper.mixins.json +++ b/fabric/src/main/resources/itemtransformhelper.mixins.json @@ -3,12 +3,12 @@ "minVersion": "0.8", "package": "itemtransformhelper.fabric.mixin", "compatibilityLevel": "JAVA_17", - "mixins": [], "client": [ - "BakedModelManagerMixin", - "InGameHudMixin", - "MinecraftClientMixin" + "GuiMixin", + "MinecraftMixin", + "ModelManagerMixin" ], + "mixins": [], "server": [], "injectors": { "defaultRequire": 1 diff --git a/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java b/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java index b896cbc0..bcba8366 100644 --- a/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java +++ b/forge/src/main/java/itemtransformhelper/forge/ItemModelFlexibleCameraImpl.java @@ -1,10 +1,10 @@ package itemtransformhelper.forge; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Transformation; import itemtransformhelper.ItemModelFlexibleCamera; -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.json.ModelTransformation; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.util.math.AffineTransformation; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.resources.model.BakedModel; import net.minecraftforge.common.model.TransformationHelper; import org.jetbrains.annotations.NotNull; @@ -22,11 +22,11 @@ public static ItemModelFlexibleCamera create(BakedModel originalModel, @NotNull @Override @SuppressWarnings("deprecation") - public BakedModel handlePerspective(@NotNull ModelTransformation.Mode cameraTransformType, - @NotNull MatrixStack poseStack) { + public BakedModel handlePerspective(@NotNull ItemTransforms.TransformType cameraTransformType, + @NotNull PoseStack poseStack) { if (updateLink.itemModelToOverride == this) { - AffineTransformation tr = - TransformationHelper.toTransformation(getTransformation().getTransformation(cameraTransformType)); + Transformation tr = + TransformationHelper.toTransformation(getTransforms().getTransform(cameraTransformType)); if (!tr.isIdentity()) { tr.push(poseStack); } diff --git a/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java b/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java index 82f299db..a0ddbe65 100644 --- a/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java +++ b/forge/src/main/java/itemtransformhelper/forge/MenuItemCameraTransformsImpl.java @@ -25,7 +25,7 @@ public static void registerListeners(HUDTextRenderer hudTextRenderer, @SubscribeEvent public void displayHUDText(RenderGameOverlayEvent.Text event) { - hudTextRenderer.displayHUDText(event.getMatrixStack()); + hudTextRenderer.displayHUDText(event.getPoseStack()); } @SubscribeEvent diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 6106356f..ba0f2e8c 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader = "javafml" -loaderVersion = "[39,)" +loaderVersion = "[41,)" issueTrackerURL = "https://github.com/TheGreyGhost/ItemTransformHelper" license = "All rights reserved" @@ -15,20 +15,20 @@ Interactively change the position, scale, and rotation of an item. [[dependencies.itemtransformhelper]] modId = "forge" mandatory = true -versionRange = "[39,)" +versionRange = "[41,)" ordering = "NONE" side = "BOTH" [[dependencies.itemtransformhelper]] modId = "minecraft" mandatory = true -versionRange = "[1.18.1,)" +versionRange = "[1.19,)" ordering = "NONE" side = "BOTH" [[dependencies.itemtransformhelper]] modId = "architectury" mandatory = true -versionRange = "[3.4.9,)" +versionRange = "[5.6.22,)" ordering = "AFTER" side = "BOTH" diff --git a/forge/src/main/resources/pack.mcmeta b/forge/src/main/resources/pack.mcmeta index 57570a49..276f749e 100644 --- a/forge/src/main/resources/pack.mcmeta +++ b/forge/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { "description": "ItemTransformHelper resources", - "pack_format": 8 + "pack_format": 9 } } diff --git a/gradle.properties b/gradle.properties index aca1b4ed..15f13887 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,21 +1,18 @@ -org.gradle.jvmargs = -Xmx2048M +org.gradle.jvmargs = -Xmx4G minecraft_version = 1.19 -#TODO: enabled_platforms = quilt,fabric,forge -enabled_platforms = fabric +enabled_platforms = quilt,fabric,forge archives_base_name = itemtransformhelper mod_version = 1.0 maven_group = thegreyghost -architectury_version = 5.4.15 +architectury_version = 5.6.22 -yarn_mappings = 1.19+build.1 +fabric_loader_version = 0.14.7 +fabric_api_version = 0.55.3+1.19 -fabric_loader_version = 0.14.6 -fabric_api_version = 0.55.2+1.19 +forge_version = 1.19-41.0.17 -forge_version = 1.19-41.0.1 - -quilt_loader_version = 0.16.0 -quilt_fabric_api_version = 1.0.0-beta.13+0.51.1-1.18.2 +quilt_loader_version = 0.17.0 +quilt_fabric_api_version = 2.0.0-alpha.2+0.55.3-1.19 diff --git a/quilt/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java b/quilt/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java new file mode 100644 index 00000000..2781dda2 --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/fabric/ItemModelFlexibleCameraImpl.java @@ -0,0 +1,17 @@ +package itemtransformhelper.fabric; + +import itemtransformhelper.ItemModelFlexibleCamera; +import net.minecraft.client.resources.model.BakedModel; + +public class ItemModelFlexibleCameraImpl extends ItemModelFlexibleCamera { + + public ItemModelFlexibleCameraImpl(BakedModel originalModel, UpdateLink updateLink) { + super(originalModel, updateLink); + } + + public static ItemModelFlexibleCamera create(BakedModel originalModel, + UpdateLink updateLink) { + return new ItemModelFlexibleCameraImpl(originalModel, updateLink); + } + +} diff --git a/quilt/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java b/quilt/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java new file mode 100644 index 00000000..3db5b742 --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/fabric/MenuItemCameraTransformsImpl.java @@ -0,0 +1,19 @@ +package itemtransformhelper.fabric; + +import itemtransformhelper.HUDTextRenderer; +import itemtransformhelper.MenuItemCameraTransforms; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class MenuItemCameraTransformsImpl { + + public static Queue RENDERERS = new ConcurrentLinkedQueue<>(); + public static Queue HANDLERS = new ConcurrentLinkedQueue<>(); + + public static void registerListeners(HUDTextRenderer hudTextRenderer, + MenuItemCameraTransforms.MenuKeyHandler menuKeyHandler) { + RENDERERS.offer(hudTextRenderer); + HANDLERS.offer(menuKeyHandler); + } + +} diff --git a/quilt/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java b/quilt/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java new file mode 100644 index 00000000..2ffd9ac4 --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/fabric/StartupClientOnlyImpl.java @@ -0,0 +1,11 @@ +package itemtransformhelper.fabric; + +public class StartupClientOnlyImpl { + + public static void clientSetup() { + // Nothing to do here as this handled by these mixins: + // BakedModelManagerMixin + // MinecraftClientMixin + } + +} diff --git a/quilt/src/main/java/itemtransformhelper/quilt/ItemTransformHelperQuilt.java b/quilt/src/main/java/itemtransformhelper/quilt/ItemTransformHelperQuilt.java new file mode 100644 index 00000000..ef8f7284 --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/quilt/ItemTransformHelperQuilt.java @@ -0,0 +1,14 @@ +package itemtransformhelper.quilt; + +import itemtransformhelper.fabriclike.ItemTransformHelperFabricLike; +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; + +public class ItemTransformHelperQuilt implements ModInitializer { + + @Override + public void onInitialize(ModContainer mod) { + ItemTransformHelperFabricLike.init(); + } + +} diff --git a/quilt/src/main/java/itemtransformhelper/quilt/mixin/GuiMixin.java b/quilt/src/main/java/itemtransformhelper/quilt/mixin/GuiMixin.java new file mode 100644 index 00000000..1c3583f5 --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/quilt/mixin/GuiMixin.java @@ -0,0 +1,20 @@ +package itemtransformhelper.quilt.mixin; + +import com.mojang.blaze3d.vertex.PoseStack; +import itemtransformhelper.fabric.MenuItemCameraTransformsImpl; +import net.minecraft.client.gui.Gui; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Gui.class) +public class GuiMixin { + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Gui;renderEffects" + + "(Lcom/mojang/blaze3d/vertex/PoseStack;)V")) + public void render(PoseStack matrices, float tickDelta, CallbackInfo ci) { + MenuItemCameraTransformsImpl.RENDERERS.forEach(r -> r.displayHUDText(matrices)); + } + +} diff --git a/quilt/src/main/java/itemtransformhelper/quilt/mixin/MinecraftMixin.java b/quilt/src/main/java/itemtransformhelper/quilt/mixin/MinecraftMixin.java new file mode 100644 index 00000000..96848541 --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/quilt/mixin/MinecraftMixin.java @@ -0,0 +1,24 @@ +package itemtransformhelper.quilt.mixin; + +import itemtransformhelper.MenuItemCameraTransforms; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static itemtransformhelper.StartupClientOnly.clientTickHandler; +import static itemtransformhelper.fabric.MenuItemCameraTransformsImpl.HANDLERS; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Inject(method = "tick", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/lang/String;" + + ")V")) + public void tick(CallbackInfo ci) { + clientTickHandler.clientTickEvent(); + HANDLERS.forEach(MenuItemCameraTransforms.MenuKeyHandler::clientTick); + } + +} diff --git a/quilt/src/main/java/itemtransformhelper/quilt/mixin/ModelManagerMixin.java b/quilt/src/main/java/itemtransformhelper/quilt/mixin/ModelManagerMixin.java new file mode 100644 index 00000000..c77ddfbb --- /dev/null +++ b/quilt/src/main/java/itemtransformhelper/quilt/mixin/ModelManagerMixin.java @@ -0,0 +1,33 @@ +package itemtransformhelper.quilt.mixin; + +import java.util.Map; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static itemtransformhelper.StartupClientOnly.modelBakeEventHandler; + +@Mixin(ModelManager.class) +public class ModelManagerMixin { + + @Shadow + private Map bakedRegistry; + + @Inject(method = "apply(Lnet/minecraft/client/resources/model/ModelBakery;" + + "Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush" + + "(Ljava/lang/String;)V")) + public void apply(ModelBakery modelLoader, ResourceManager resourceManager, ProfilerFiller profiler, + CallbackInfo ci) { + modelBakeEventHandler.modelBakeEvent(bakedRegistry); + } + +} diff --git a/quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java b/quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java deleted file mode 100644 index 7aaae485..00000000 --- a/quilt/src/main/java/net/examplemod/fabric/ExampleExpectPlatformImpl.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.examplemod.fabric; - -import net.examplemod.ExampleExpectPlatform; -import org.quiltmc.loader.api.QuiltLoader; - -import java.nio.file.Path; - -public class ExampleExpectPlatformImpl { - /** - * This is our actual method to {@link ExampleExpectPlatform#getConfigDirectory()}. - */ - public static Path getConfigDirectory() { - return QuiltLoader.getConfigDir(); - } -} diff --git a/quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java b/quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java deleted file mode 100644 index 10e21537..00000000 --- a/quilt/src/main/java/net/examplemod/quilt/ExampleModQuilt.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.examplemod.quilt; - -import net.examplemod.fabriclike.ExampleModFabricLike; -import org.quiltmc.loader.api.ModContainer; -import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; - -public class ExampleModQuilt implements ModInitializer { - @Override - public void onInitialize(ModContainer mod) { - ExampleModFabricLike.init(); - } -} diff --git a/quilt/src/main/resources/examplemod.mixins.json b/quilt/src/main/resources/examplemod.mixins.json deleted file mode 100644 index ab40cb1a..00000000 --- a/quilt/src/main/resources/examplemod.mixins.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "required": true, - "package": "net.examplemod.mixin.fabric", - "compatibilityLevel": "JAVA_16", - "client": [ - ], - "mixins": [ - ], - "injectors": { - "defaultRequire": 1 - } -} \ No newline at end of file diff --git a/quilt/src/main/resources/itemtransformhelper.mixins.json b/quilt/src/main/resources/itemtransformhelper.mixins.json new file mode 100644 index 00000000..0c0f20f9 --- /dev/null +++ b/quilt/src/main/resources/itemtransformhelper.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "itemtransformhelper.quilt.mixin", + "compatibilityLevel": "JAVA_17", + "client": [ + "GuiMixin", + "MinecraftMixin", + "ModelManagerMixin" + ], + "mixins": [], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/quilt/src/main/resources/quilt.mod.json b/quilt/src/main/resources/quilt.mod.json index 832b923c..0ceb591a 100644 --- a/quilt/src/main/resources/quilt.mod.json +++ b/quilt/src/main/resources/quilt.mod.json @@ -1,26 +1,31 @@ { "schema_version": 1, "mixin": [ - "examplemod.mixins.json", - "examplemod-common.mixins.json" + "itemtransformhelper.mixins.json" ], "quilt_loader": { "group": "${group}", - "id": "examplemod", + "id": "itemtransformhelper", "version": "${version}", - "name": "Example Mod", - "description": "This is an example description! Tell everyone what your mod is about!", - "authors": ["Me!"], + "name": "Item Transform Helper", + "description": "Interactively change the position, scale, and rotation of an item.", + "authors": [ + "TGG", + "ThexXTURBOXx", + "Romejanic", + "lehjr" + ], "contact": { - "sources": "https://github.com/architectury/architectury-templates" + "homepage": "https://www.planetminecraft.com/mod/item-transform-helper---interactively-rotate-scale-translate/", + "sources": "https://github.com/TheGreyGhost/ItemTransformHelper", + "issues": "https://github.com/TheGreyGhost/ItemTransformHelper/issues" }, - "license": "Insert License Here", - "icon": "assets/examplemod/icon.png", + "license": "All rights reserved", "intermediate_mappings": "net.fabricmc:intermediary", "environment": "*", "entrypoints": { "init": [ - "net.examplemod.quilt.ExampleModQuilt" + "itemtransformhelper.quilt.ItemTransformHelperQuilt" ] }, "depends": [ @@ -34,12 +39,12 @@ }, { "id": "minecraft", - "version": ">=1.18.2" + "version": ">=1.19" }, { "id": "architectury", - "version": ">=4.4.59" + "version": ">=5.6.22" } ] } -} \ No newline at end of file +} diff --git a/settings.gradle b/settings.gradle index 8e0761d5..169cca43 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,7 +10,7 @@ pluginManagement { include("common") include("fabric-like") include("fabric") -//TODO: Activate later again include("quilt") -//TODO: Activate later again include("forge") +include("quilt") +include("forge") rootProject.name = "itemtransformhelper"