From a132e686837760767c2dc34406f4869a85f53ffa Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:53:14 +0100 Subject: [PATCH 01/16] prepare 1.20.4 port --- .github/ISSUE_TEMPLATE/bug.yml | 46 ++-- .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/ISSUE_TEMPLATE/crash.yml | 44 ++-- .github/ISSUE_TEMPLATE/suggestion.yml | 36 ++- .idea/gradle.xml | 44 ---- .../.idea}/scopes/Fabric_sources.xml | 0 .../.idea}/scopes/Forge_sources.xml | 0 {1.18 => 1.18.2}/CHANGELOG.md | 0 {1.18 => 1.18.2}/Common/build.gradle | 0 .../main/java/fuzs/examplemod/ExampleMod.java | 0 .../examplemod/client/ExampleModClient.java | 0 .../resources/examplemod.common.mixins.json | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 {1.18 => 1.18.2}/Fabric/build.gradle | 0 .../fuzs/examplemod/ExampleModFabric.java | 0 .../client/ExampleModFabricClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../resources/examplemod.fabric.mixins.json | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.18 => 1.18.2}/Forge/build.gradle | 0 .../java/fuzs/examplemod/ExampleModForge.java | 0 .../client/ExampleModForgeClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 .../resources/examplemod.forge.mixins.json | 0 {1.18 => 1.18.2}/build.gradle | 0 {1.18 => 1.18.2}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.18 => 1.18.2}/gradlew | 0 {1.18 => 1.18.2}/gradlew.bat | 0 {1.18 => 1.18.2}/settings.gradle | 0 .../.idea/scopes/Fabric_sources.xml | 0 .../.idea/scopes/Forge_sources.xml | 0 {1.19 => 1.19.2}/CHANGELOG.md | 0 {1.19 => 1.19.2}/Common/build.gradle | 0 .../main/java/fuzs/examplemod/ExampleMod.java | 0 .../examplemod/client/ExampleModClient.java | 0 .../resources/examplemod.common.mixins.json | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 {1.19 => 1.19.2}/Fabric/build.gradle | 0 .../fuzs/examplemod/ExampleModFabric.java | 0 .../client/ExampleModFabricClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../resources/examplemod.fabric.mixins.json | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.19 => 1.19.2}/Forge/build.gradle | 0 .../java/fuzs/examplemod/ExampleModForge.java | 0 .../client/ExampleModForgeClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 .../resources/examplemod.forge.mixins.json | 0 {1.19 => 1.19.2}/build.gradle | 0 {1.19 => 1.19.2}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.19 => 1.19.2}/gradlew | 0 {1.19 => 1.19.2}/gradlew.bat | 0 {1.19 => 1.19.2}/settings.gradle | 0 .../.idea/scopes/Fabric_sources.xml | 0 .../.idea/scopes/Forge_sources.xml | 0 {1.20 => 1.20.1}/CHANGELOG.md | 0 {1.20 => 1.20.1}/Common/build.gradle | 0 .../fuzs/visualworkbench/VisualWorkbench.java | 0 .../client/VisualWorkbenchClient.java | 0 .../WorkbenchBlockEntityRenderer.java | 0 .../visualworkbench/config/ClientConfig.java | 0 .../config/JsonConfigBuilder.java | 0 .../core/CommonAbstractions.java | 0 .../handler/OpenMenuHandler.java | 0 .../visualworkbench/init/ModRegistry.java | 0 .../jei/VisualWorkbenchJEIPlugin.java | 0 .../mixin/CraftingTableBlockMixin.java | 0 .../mixin/accessor/CraftingMenuAccessor.java | 0 .../fuzs/visualworkbench/util/MathHelper.java | 0 .../ForwardingCraftingContainer.java | 0 .../world/inventory/ModCraftingMenu.java | 0 .../level/block/VisualCraftingTableBlock.java | 0 .../entity/CraftingTableBlockEntity.java | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 .../visualworkbench.common.mixins.json | 0 {1.20 => 1.20.1}/Fabric/build.gradle | 0 .../VisualWorkbenchFabric.java | 0 .../client/VisualWorkbenchFabricClient.java | 0 .../core/FabricAbstractions.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../BlockEntityTypeFabricAccessor.java | 0 ...zs.visualworkbench.core.CommonAbstractions | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 .../visualworkbench.fabric.mixins.json | 0 {1.20 => 1.20.1}/Forge/build.gradle | 0 .../visualworkbench/VisualWorkbenchForge.java | 0 .../client/VisualWorkbenchForgeClient.java | 0 .../core/ForgeAbstractions.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 ...zs.visualworkbench.core.CommonAbstractions | 0 {1.20 => 1.20.1}/build.gradle | 0 {1.20 => 1.20.1}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.20 => 1.20.1}/gradlew | 0 {1.20 => 1.20.1}/gradlew.bat | 0 {1.20 => 1.20.1}/settings.gradle | 0 1.20.4/CHANGELOG.md | 9 + 1.20.4/Common/build.gradle | 14 + .../fuzs/visualworkbench/VisualWorkbench.java | 36 +++ .../client/VisualWorkbenchClient.java | 31 +++ .../WorkbenchBlockEntityRenderer.java | 96 +++++++ .../visualworkbench/config/ClientConfig.java | 13 + .../core/CommonAbstractions.java | 17 ++ .../data/ModBlockTagsProvider.java | 19 ++ .../data/client/DynamicModelProvider.java | 36 +++ .../handler/OpenMenuHandler.java | 78 ++++++ .../visualworkbench/init/ModRegistry.java | 31 +++ .../jei/VisualWorkbenchJEIPlugin.java | 24 ++ .../BlockEntityTypeBuilderAccessor.java | 17 ++ .../mixin/accessor/CraftingMenuAccessor.java | 27 ++ .../fuzs/visualworkbench/util/MathHelper.java | 9 + .../world/inventory/VisualCraftingMenu.java | 106 ++++++++ .../level/block/VisualCraftingTableBlock.java | 85 ++++++ .../entity/ContainerSerializationHelper.java | 41 +++ .../VisualCraftingTableBlockEntity.java | 187 ++++++++++++++ .../Common/src/main/resources/mod_banner.png | Bin 0 -> 17426 bytes 1.20.4/Common/src/main/resources/mod_logo.png | Bin 0 -> 9349 bytes 1.20.4/Common/src/main/resources/pack.mcmeta | 8 + .../visualworkbench.common.mixins.json | 17 ++ 1.20.4/Fabric/build.gradle | 33 +++ .../VisualWorkbenchFabric.java | 12 + .../client/VisualWorkbenchFabricClient.java | 13 + .../mixin/ModMixinConfigPlugin.java | 47 ++++ .../Fabric/src/main/resources/fabric.mod.json | 47 ++++ 1.20.4/Forge/build.gradle | 32 +++ .../visualworkbench/VisualWorkbenchForge.java | 19 ++ .../client/VisualWorkbenchForgeClient.java | 17 ++ .../mixin/ModMixinConfigPlugin.java | 47 ++++ .../src/main/resources/META-INF/mods.toml | 40 +++ 1.20.4/NeoForge/build.gradle | 32 +++ .../visualworkbench/VisualWorkbenchForge.java | 19 ++ .../client/VisualWorkbenchForgeClient.java | 17 ++ .../mixin/ModMixinConfigPlugin.java | 47 ++++ .../src/main/resources/META-INF/mods.toml | 40 +++ 1.20.4/build.gradle | 12 + 1.20.4/gradle.properties | 37 +++ 1.20.4/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + 1.20.4/gradlew | 244 ++++++++++++++++++ 1.20.4/gradlew.bat | 92 +++++++ 1.20.4/settings.gradle | 38 +++ 1.20/.idea/scopes/Fabric_sources.xml | 3 - 1.20/.idea/scopes/Forge_sources.xml | 3 - 157 files changed, 1887 insertions(+), 85 deletions(-) delete mode 100644 .idea/gradle.xml rename {.idea => 1.18.2/.idea}/scopes/Fabric_sources.xml (100%) rename {.idea => 1.18.2/.idea}/scopes/Forge_sources.xml (100%) rename {1.18 => 1.18.2}/CHANGELOG.md (100%) rename {1.18 => 1.18.2}/Common/build.gradle (100%) rename {1.18 => 1.18.2}/Common/src/main/java/fuzs/examplemod/ExampleMod.java (100%) rename {1.18 => 1.18.2}/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/examplemod.common.mixins.json (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/mod_banner.png (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/mod_logo.png (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/pack.mcmeta (100%) rename {1.18 => 1.18.2}/Fabric/build.gradle (100%) rename {1.18 => 1.18.2}/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java (100%) rename {1.18 => 1.18.2}/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java (100%) rename {1.18 => 1.18.2}/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.18 => 1.18.2}/Fabric/src/main/resources/examplemod.fabric.mixins.json (100%) rename {1.18 => 1.18.2}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.18 => 1.18.2}/Forge/build.gradle (100%) rename {1.18 => 1.18.2}/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java (100%) rename {1.18 => 1.18.2}/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java (100%) rename {1.18 => 1.18.2}/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.18 => 1.18.2}/Forge/src/main/resources/META-INF/mods.toml (100%) rename {1.18 => 1.18.2}/Forge/src/main/resources/examplemod.forge.mixins.json (100%) rename {1.18 => 1.18.2}/build.gradle (100%) rename {1.18 => 1.18.2}/gradle.properties (100%) rename {1.18 => 1.18.2}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.18 => 1.18.2}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.18 => 1.18.2}/gradlew (100%) rename {1.18 => 1.18.2}/gradlew.bat (100%) rename {1.18 => 1.18.2}/settings.gradle (100%) rename {1.18 => 1.19.2}/.idea/scopes/Fabric_sources.xml (100%) rename {1.18 => 1.19.2}/.idea/scopes/Forge_sources.xml (100%) rename {1.19 => 1.19.2}/CHANGELOG.md (100%) rename {1.19 => 1.19.2}/Common/build.gradle (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/examplemod/ExampleMod.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/examplemod.common.mixins.json (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/mod_banner.png (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/mod_logo.png (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/pack.mcmeta (100%) rename {1.19 => 1.19.2}/Fabric/build.gradle (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/resources/examplemod.fabric.mixins.json (100%) rename {1.19 => 1.19.2}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.19 => 1.19.2}/Forge/build.gradle (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/META-INF/mods.toml (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/examplemod.forge.mixins.json (100%) rename {1.19 => 1.19.2}/build.gradle (100%) rename {1.19 => 1.19.2}/gradle.properties (100%) rename {1.19 => 1.19.2}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.19 => 1.19.2}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.19 => 1.19.2}/gradlew (100%) rename {1.19 => 1.19.2}/gradlew.bat (100%) rename {1.19 => 1.19.2}/settings.gradle (100%) rename {1.19 => 1.20.1}/.idea/scopes/Fabric_sources.xml (100%) rename {1.19 => 1.20.1}/.idea/scopes/Forge_sources.xml (100%) rename {1.20 => 1.20.1}/CHANGELOG.md (100%) rename {1.20 => 1.20.1}/Common/build.gradle (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/config/JsonConfigBuilder.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/mixin/CraftingTableBlockMixin.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/world/inventory/ForwardingCraftingContainer.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/world/inventory/ModCraftingMenu.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/mod_banner.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/mod_logo.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/pack.mcmeta (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/visualworkbench.common.mixins.json (100%) rename {1.20 => 1.20.1}/Fabric/build.gradle (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/visualworkbench/core/FabricAbstractions.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeFabricAccessor.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions (100%) rename {1.20 => 1.20.1}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.20 => 1.20.1}/Fabric/src/main/resources/visualworkbench.fabric.mixins.json (100%) rename {1.20 => 1.20.1}/Forge/build.gradle (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/visualworkbench/core/ForgeAbstractions.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/resources/META-INF/mods.toml (100%) rename {1.20 => 1.20.1}/Forge/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions (100%) rename {1.20 => 1.20.1}/build.gradle (100%) rename {1.20 => 1.20.1}/gradle.properties (100%) rename {1.20 => 1.20.1}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.20 => 1.20.1}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.20 => 1.20.1}/gradlew (100%) rename {1.20 => 1.20.1}/gradlew.bat (100%) rename {1.20 => 1.20.1}/settings.gradle (100%) create mode 100644 1.20.4/CHANGELOG.md create mode 100644 1.20.4/Common/build.gradle create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java create mode 100644 1.20.4/Common/src/main/resources/mod_banner.png create mode 100644 1.20.4/Common/src/main/resources/mod_logo.png create mode 100755 1.20.4/Common/src/main/resources/pack.mcmeta create mode 100644 1.20.4/Common/src/main/resources/visualworkbench.common.mixins.json create mode 100644 1.20.4/Fabric/build.gradle create mode 100644 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java create mode 100644 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java create mode 100644 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.20.4/Forge/build.gradle create mode 100644 1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.20.4/NeoForge/build.gradle create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/NeoForge/src/main/resources/META-INF/mods.toml create mode 100644 1.20.4/build.gradle create mode 100755 1.20.4/gradle.properties create mode 100644 1.20.4/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.20.4/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.20.4/gradlew create mode 100644 1.20.4/gradlew.bat create mode 100644 1.20.4/settings.gradle delete mode 100644 1.20/.idea/scopes/Fabric_sources.xml delete mode 100644 1.20/.idea/scopes/Forge_sources.xml diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 7726363..a2056ad 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -1,7 +1,7 @@ -name: Bug Report +name: Report A Bug description: >- - Please use this template when you have encountered a bug in this mod. Please note that only the latest mod version for Minecraft 1.18.2, 1.19.2 and 1.20.1 is supported. -title: '[Bug]: ' + Only Minecraft versions listed on the main branch are supported. Support may additionally vary based on the severity of an issue. +title: "[Bug]: " labels: ["bug"] assignees: - Fuzss @@ -14,35 +14,49 @@ body: id: loader attributes: label: Mod Loader (Required) - description: What mod loader are you using the mod on? + description: What mod loader are you using to play the mod? multiple: false options: - - Forge - - Fabric - - Quilt + - "⸺" + - "Fabric" + - "NeoForge" + - "Forge" + - "Quilt" validations: required: true - type: input id: minecraft attributes: - label: Minecraft Version (Required) - description: What is the Minecraft version you are playing with? + label: Minecraft Version(s) (Required) + description: What Minecraft version(s) are you using the play the mod? placeholder: ex. 1.20.1 validations: required: true - type: input id: version attributes: - label: Mod Version (Required) - description: What version of the mod are you playing with? + label: Mod Version(s) (Required) + description: What mod version(s) are you using to play? placeholder: ex. v8.0.0 validations: required: true + - type: dropdown + id: mods + attributes: + label: Other Mods Involved (Required) + description: Can your issue be reproduced with a minimal set of mods (only this mod + dependencies)? + multiple: false + options: + - "⸺" + - "Yes" + - "No" + validations: + required: true - type: textarea id: notes attributes: label: Notes (Required) - description: Please explain what happens because of the bug (including all the steps required to cause the bug), and what behavior you would expect if the bug were fixed. + description: Please explain what happens because of the issue (including all the steps required to cause it), and what behavior you would expect if the issue were fixed. placeholder: >- ex. @@ -60,6 +74,8 @@ body: - type: input id: latest-log attributes: - label: latest.log (Optional) - description: Please paste the url to your shared `latest.log` file. [To share your `latest.log` here, please follow these steps.](https://gist.github.com/Fuzss/866b384d353912986e37b17eeef7a285) - placeholder: ex. https://gist.github.com// \ No newline at end of file + label: latest.log (Required) + description: Please paste the url to your shared `latest.log` file. Note that issue reports without this file are difficult to solve and unlikely to be processed. [To share your `latest.log` here, please follow these steps.](https://gist.github.com/Fuzss/866b384d353912986e37b17eeef7a285) + placeholder: ex. https://gist.github.com// + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e0133b0..cbe96b9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Questions + - name: Ask A Question url: https://lunapixel.studio/discord - about: "Please ask questions on the Luna Pixel Studios Discord in #fuzs-projects." \ No newline at end of file + about: "Join the Luna Pixel Studios Discord Server in the #fuzs-projects channel for additional support." \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 5ca6180..20493b1 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -1,8 +1,8 @@ -name: Crash Report +name: Submit A Crash Report description: >- - Please use this template when this mod has caused your game to crash. Please note that only the latest mod version for Minecraft 1.18.2, 1.19.2 and 1.20.1 is supported. -title: '[Crash]: ' -labels: ["bug"] + Only Minecraft versions listed on the main branch are supported. Support may additionally vary based on the severity of an issue. +title: "[Crash]: " +labels: ["bug", "high priority"] assignees: - Fuzss body: @@ -14,35 +14,49 @@ body: id: loader attributes: label: Mod Loader (Required) - description: What mod loader are you using the mod on? + description: What mod loader are you using to play the mod? multiple: false options: - - Forge - - Fabric - - Quilt + - "⸺" + - "Fabric" + - "NeoForge" + - "Forge" + - "Quilt" validations: required: true - type: input id: minecraft attributes: - label: Minecraft Version (Required) - description: What is the Minecraft version you are playing with? + label: Minecraft Version(s) (Required) + description: What Minecraft version(s) are you using the play the mod? placeholder: ex. 1.20.1 validations: required: true - type: input id: version attributes: - label: Mod Version (Required) - description: What version of the mod are you playing with? + label: Mod Version(s) (Required) + description: What mod version(s) are you using to play? placeholder: ex. v8.0.0 validations: required: true + - type: dropdown + id: mods + attributes: + label: Other Mods Involved (Required) + description: Can your issue be reproduced with a minimal set of mods (only this mod + dependencies)? + multiple: false + options: + - "⸺" + - "Yes" + - "No" + validations: + required: true - type: textarea id: notes attributes: label: Notes (Required) - description: Please explain which steps we need to do to reproduce the crash. Please include anything else you'd like to say about the crash. + description: Please explain which steps we need to do to reproduce the issue. Please include anything else you'd like to say about it. placeholder: >- ex. @@ -58,7 +72,7 @@ body: attributes: label: Crash Report (Required) description: >- - Please paste the url to your shared crash report. [To share your crash report here, please follow these steps.](https://gist.github.com/Fuzss/9692f6ed5e8cca485a58004c28c9045b) + Please paste the url to your shared crash report. Note that issue reports without this file are difficult to solve and unlikely to be processed. [To share your crash report here, please follow these steps.](https://gist.github.com/Fuzss/9692f6ed5e8cca485a58004c28c9045b) placeholder: ex. https://gist.github.com// validations: required: true @@ -67,4 +81,4 @@ body: attributes: label: latest.log (Optional) description: Please paste the url to your shared `latest.log` file. [To share your `latest.log` here, please follow these steps.](https://gist.github.com/Fuzss/866b384d353912986e37b17eeef7a285) - placeholder: ex. https://gist.github.com// \ No newline at end of file + placeholder: ex. https://gist.github.com// diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml index 0eb9a33..2a25400 100644 --- a/.github/ISSUE_TEMPLATE/suggestion.yml +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -1,11 +1,41 @@ -name: Suggestion +name: Leave A Suggestion description: >- - Please use this template when you want to suggest a feature. Please do not ask for mod updates or ports, they will come when they are ready. -title: '[Suggestion]: ' + Please do not ask for mod updates or ports, they will come when they are ready. +title: "[Suggestion]: " labels: ["enhancement"] assignees: - Fuzss body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this issue report! + - type: dropdown + id: loader + attributes: + label: Mod Loader (Optional) + description: What mod loader are you using to play the mod? + multiple: false + options: + - "⸺" + - "Fabric" + - "NeoForge" + - "Forge" + - "Quilt" + validations: + required: true + - type: input + id: minecraft + attributes: + label: Minecraft Version(s) (Optional) + description: What Minecraft version(s) are you using the play the mod? + placeholder: ex. 1.20.1 + - type: input + id: version + attributes: + label: Mod Version(s) (Optional) + description: What mod version(s) are you using to play? + placeholder: ex. v8.0.0 - type: textarea id: suggestion attributes: diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 311bce0..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/scopes/Fabric_sources.xml b/1.18.2/.idea/scopes/Fabric_sources.xml similarity index 100% rename from .idea/scopes/Fabric_sources.xml rename to 1.18.2/.idea/scopes/Fabric_sources.xml diff --git a/.idea/scopes/Forge_sources.xml b/1.18.2/.idea/scopes/Forge_sources.xml similarity index 100% rename from .idea/scopes/Forge_sources.xml rename to 1.18.2/.idea/scopes/Forge_sources.xml diff --git a/1.18/CHANGELOG.md b/1.18.2/CHANGELOG.md similarity index 100% rename from 1.18/CHANGELOG.md rename to 1.18.2/CHANGELOG.md diff --git a/1.18/Common/build.gradle b/1.18.2/Common/build.gradle similarity index 100% rename from 1.18/Common/build.gradle rename to 1.18.2/Common/build.gradle diff --git a/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.18.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java similarity index 100% rename from 1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java rename to 1.18.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java diff --git a/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.18.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java similarity index 100% rename from 1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java rename to 1.18.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java diff --git a/1.18/Common/src/main/resources/examplemod.common.mixins.json b/1.18.2/Common/src/main/resources/examplemod.common.mixins.json similarity index 100% rename from 1.18/Common/src/main/resources/examplemod.common.mixins.json rename to 1.18.2/Common/src/main/resources/examplemod.common.mixins.json diff --git a/1.18/Common/src/main/resources/mod_banner.png b/1.18.2/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.18/Common/src/main/resources/mod_banner.png rename to 1.18.2/Common/src/main/resources/mod_banner.png diff --git a/1.18/Common/src/main/resources/mod_logo.png b/1.18.2/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.18/Common/src/main/resources/mod_logo.png rename to 1.18.2/Common/src/main/resources/mod_logo.png diff --git a/1.18/Common/src/main/resources/pack.mcmeta b/1.18.2/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.18/Common/src/main/resources/pack.mcmeta rename to 1.18.2/Common/src/main/resources/pack.mcmeta diff --git a/1.18/Fabric/build.gradle b/1.18.2/Fabric/build.gradle similarity index 100% rename from 1.18/Fabric/build.gradle rename to 1.18.2/Fabric/build.gradle diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.18.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java similarity index 100% rename from 1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java rename to 1.18.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.18.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java similarity index 100% rename from 1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java rename to 1.18.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.18.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.18.2/Fabric/src/main/resources/examplemod.fabric.mixins.json similarity index 100% rename from 1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json rename to 1.18.2/Fabric/src/main/resources/examplemod.fabric.mixins.json diff --git a/1.18/Fabric/src/main/resources/fabric.mod.json b/1.18.2/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.18/Fabric/src/main/resources/fabric.mod.json rename to 1.18.2/Fabric/src/main/resources/fabric.mod.json diff --git a/1.18/Forge/build.gradle b/1.18.2/Forge/build.gradle similarity index 100% rename from 1.18/Forge/build.gradle rename to 1.18.2/Forge/build.gradle diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.18.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java similarity index 100% rename from 1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java rename to 1.18.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.18.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java similarity index 100% rename from 1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java rename to 1.18.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.18.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.18/Forge/src/main/resources/META-INF/mods.toml b/1.18.2/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from 1.18/Forge/src/main/resources/META-INF/mods.toml rename to 1.18.2/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.18/Forge/src/main/resources/examplemod.forge.mixins.json b/1.18.2/Forge/src/main/resources/examplemod.forge.mixins.json similarity index 100% rename from 1.18/Forge/src/main/resources/examplemod.forge.mixins.json rename to 1.18.2/Forge/src/main/resources/examplemod.forge.mixins.json diff --git a/1.18/build.gradle b/1.18.2/build.gradle similarity index 100% rename from 1.18/build.gradle rename to 1.18.2/build.gradle diff --git a/1.18/gradle.properties b/1.18.2/gradle.properties similarity index 100% rename from 1.18/gradle.properties rename to 1.18.2/gradle.properties diff --git a/1.18/gradle/wrapper/gradle-wrapper.jar b/1.18.2/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.18/gradle/wrapper/gradle-wrapper.jar rename to 1.18.2/gradle/wrapper/gradle-wrapper.jar diff --git a/1.18/gradle/wrapper/gradle-wrapper.properties b/1.18.2/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.18/gradle/wrapper/gradle-wrapper.properties rename to 1.18.2/gradle/wrapper/gradle-wrapper.properties diff --git a/1.18/gradlew b/1.18.2/gradlew similarity index 100% rename from 1.18/gradlew rename to 1.18.2/gradlew diff --git a/1.18/gradlew.bat b/1.18.2/gradlew.bat similarity index 100% rename from 1.18/gradlew.bat rename to 1.18.2/gradlew.bat diff --git a/1.18/settings.gradle b/1.18.2/settings.gradle similarity index 100% rename from 1.18/settings.gradle rename to 1.18.2/settings.gradle diff --git a/1.18/.idea/scopes/Fabric_sources.xml b/1.19.2/.idea/scopes/Fabric_sources.xml similarity index 100% rename from 1.18/.idea/scopes/Fabric_sources.xml rename to 1.19.2/.idea/scopes/Fabric_sources.xml diff --git a/1.18/.idea/scopes/Forge_sources.xml b/1.19.2/.idea/scopes/Forge_sources.xml similarity index 100% rename from 1.18/.idea/scopes/Forge_sources.xml rename to 1.19.2/.idea/scopes/Forge_sources.xml diff --git a/1.19/CHANGELOG.md b/1.19.2/CHANGELOG.md similarity index 100% rename from 1.19/CHANGELOG.md rename to 1.19.2/CHANGELOG.md diff --git a/1.19/Common/build.gradle b/1.19.2/Common/build.gradle similarity index 100% rename from 1.19/Common/build.gradle rename to 1.19.2/Common/build.gradle diff --git a/1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.19.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java rename to 1.19.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java diff --git a/1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.19.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java rename to 1.19.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java diff --git a/1.19/Common/src/main/resources/examplemod.common.mixins.json b/1.19.2/Common/src/main/resources/examplemod.common.mixins.json similarity index 100% rename from 1.19/Common/src/main/resources/examplemod.common.mixins.json rename to 1.19.2/Common/src/main/resources/examplemod.common.mixins.json diff --git a/1.19/Common/src/main/resources/mod_banner.png b/1.19.2/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.19/Common/src/main/resources/mod_banner.png rename to 1.19.2/Common/src/main/resources/mod_banner.png diff --git a/1.19/Common/src/main/resources/mod_logo.png b/1.19.2/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.19/Common/src/main/resources/mod_logo.png rename to 1.19.2/Common/src/main/resources/mod_logo.png diff --git a/1.19/Common/src/main/resources/pack.mcmeta b/1.19.2/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.19/Common/src/main/resources/pack.mcmeta rename to 1.19.2/Common/src/main/resources/pack.mcmeta diff --git a/1.19/Fabric/build.gradle b/1.19.2/Fabric/build.gradle similarity index 100% rename from 1.19/Fabric/build.gradle rename to 1.19.2/Fabric/build.gradle diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.19.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java rename to 1.19.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.19.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java rename to 1.19.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.19.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.19.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.19.2/Fabric/src/main/resources/examplemod.fabric.mixins.json similarity index 100% rename from 1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json rename to 1.19.2/Fabric/src/main/resources/examplemod.fabric.mixins.json diff --git a/1.19/Fabric/src/main/resources/fabric.mod.json b/1.19.2/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.19/Fabric/src/main/resources/fabric.mod.json rename to 1.19.2/Fabric/src/main/resources/fabric.mod.json diff --git a/1.19/Forge/build.gradle b/1.19.2/Forge/build.gradle similarity index 100% rename from 1.19/Forge/build.gradle rename to 1.19.2/Forge/build.gradle diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.19.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java rename to 1.19.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.19.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java rename to 1.19.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.19.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.19.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.19/Forge/src/main/resources/META-INF/mods.toml b/1.19.2/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from 1.19/Forge/src/main/resources/META-INF/mods.toml rename to 1.19.2/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.19/Forge/src/main/resources/examplemod.forge.mixins.json b/1.19.2/Forge/src/main/resources/examplemod.forge.mixins.json similarity index 100% rename from 1.19/Forge/src/main/resources/examplemod.forge.mixins.json rename to 1.19.2/Forge/src/main/resources/examplemod.forge.mixins.json diff --git a/1.19/build.gradle b/1.19.2/build.gradle similarity index 100% rename from 1.19/build.gradle rename to 1.19.2/build.gradle diff --git a/1.19/gradle.properties b/1.19.2/gradle.properties similarity index 100% rename from 1.19/gradle.properties rename to 1.19.2/gradle.properties diff --git a/1.19/gradle/wrapper/gradle-wrapper.jar b/1.19.2/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.19/gradle/wrapper/gradle-wrapper.jar rename to 1.19.2/gradle/wrapper/gradle-wrapper.jar diff --git a/1.19/gradle/wrapper/gradle-wrapper.properties b/1.19.2/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.19/gradle/wrapper/gradle-wrapper.properties rename to 1.19.2/gradle/wrapper/gradle-wrapper.properties diff --git a/1.19/gradlew b/1.19.2/gradlew similarity index 100% rename from 1.19/gradlew rename to 1.19.2/gradlew diff --git a/1.19/gradlew.bat b/1.19.2/gradlew.bat similarity index 100% rename from 1.19/gradlew.bat rename to 1.19.2/gradlew.bat diff --git a/1.19/settings.gradle b/1.19.2/settings.gradle similarity index 100% rename from 1.19/settings.gradle rename to 1.19.2/settings.gradle diff --git a/1.19/.idea/scopes/Fabric_sources.xml b/1.20.1/.idea/scopes/Fabric_sources.xml similarity index 100% rename from 1.19/.idea/scopes/Fabric_sources.xml rename to 1.20.1/.idea/scopes/Fabric_sources.xml diff --git a/1.19/.idea/scopes/Forge_sources.xml b/1.20.1/.idea/scopes/Forge_sources.xml similarity index 100% rename from 1.19/.idea/scopes/Forge_sources.xml rename to 1.20.1/.idea/scopes/Forge_sources.xml diff --git a/1.20/CHANGELOG.md b/1.20.1/CHANGELOG.md similarity index 100% rename from 1.20/CHANGELOG.md rename to 1.20.1/CHANGELOG.md diff --git a/1.20/Common/build.gradle b/1.20.1/Common/build.gradle similarity index 100% rename from 1.20/Common/build.gradle rename to 1.20.1/Common/build.gradle diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/config/JsonConfigBuilder.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/config/JsonConfigBuilder.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/config/JsonConfigBuilder.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/config/JsonConfigBuilder.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/mixin/CraftingTableBlockMixin.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/mixin/CraftingTableBlockMixin.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/mixin/CraftingTableBlockMixin.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/mixin/CraftingTableBlockMixin.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/world/inventory/ForwardingCraftingContainer.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/world/inventory/ForwardingCraftingContainer.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/world/inventory/ForwardingCraftingContainer.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/world/inventory/ForwardingCraftingContainer.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/world/inventory/ModCraftingMenu.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/world/inventory/ModCraftingMenu.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/world/inventory/ModCraftingMenu.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/world/inventory/ModCraftingMenu.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java diff --git a/1.20/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.20.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java rename to 1.20.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java diff --git a/1.20/Common/src/main/resources/mod_banner.png b/1.20.1/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.20/Common/src/main/resources/mod_banner.png rename to 1.20.1/Common/src/main/resources/mod_banner.png diff --git a/1.20/Common/src/main/resources/mod_logo.png b/1.20.1/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.20/Common/src/main/resources/mod_logo.png rename to 1.20.1/Common/src/main/resources/mod_logo.png diff --git a/1.20/Common/src/main/resources/pack.mcmeta b/1.20.1/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.20/Common/src/main/resources/pack.mcmeta rename to 1.20.1/Common/src/main/resources/pack.mcmeta diff --git a/1.20/Common/src/main/resources/visualworkbench.common.mixins.json b/1.20.1/Common/src/main/resources/visualworkbench.common.mixins.json similarity index 100% rename from 1.20/Common/src/main/resources/visualworkbench.common.mixins.json rename to 1.20.1/Common/src/main/resources/visualworkbench.common.mixins.json diff --git a/1.20/Fabric/build.gradle b/1.20.1/Fabric/build.gradle similarity index 100% rename from 1.20/Fabric/build.gradle rename to 1.20.1/Fabric/build.gradle diff --git a/1.20/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java b/1.20.1/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java rename to 1.20.1/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java diff --git a/1.20/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java b/1.20.1/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java rename to 1.20.1/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java diff --git a/1.20/Fabric/src/main/java/fuzs/visualworkbench/core/FabricAbstractions.java b/1.20.1/Fabric/src/main/java/fuzs/visualworkbench/core/FabricAbstractions.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/visualworkbench/core/FabricAbstractions.java rename to 1.20.1/Fabric/src/main/java/fuzs/visualworkbench/core/FabricAbstractions.java diff --git a/1.20/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.1/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java rename to 1.20.1/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java diff --git a/1.20/Fabric/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeFabricAccessor.java b/1.20.1/Fabric/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeFabricAccessor.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeFabricAccessor.java rename to 1.20.1/Fabric/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeFabricAccessor.java diff --git a/1.20/Fabric/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions b/1.20.1/Fabric/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions similarity index 100% rename from 1.20/Fabric/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions rename to 1.20.1/Fabric/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions diff --git a/1.20/Fabric/src/main/resources/fabric.mod.json b/1.20.1/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.20/Fabric/src/main/resources/fabric.mod.json rename to 1.20.1/Fabric/src/main/resources/fabric.mod.json diff --git a/1.20/Fabric/src/main/resources/visualworkbench.fabric.mixins.json b/1.20.1/Fabric/src/main/resources/visualworkbench.fabric.mixins.json similarity index 100% rename from 1.20/Fabric/src/main/resources/visualworkbench.fabric.mixins.json rename to 1.20.1/Fabric/src/main/resources/visualworkbench.fabric.mixins.json diff --git a/1.20/Forge/build.gradle b/1.20.1/Forge/build.gradle similarity index 100% rename from 1.20/Forge/build.gradle rename to 1.20.1/Forge/build.gradle diff --git a/1.20/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java b/1.20.1/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java rename to 1.20.1/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java diff --git a/1.20/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java b/1.20.1/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java rename to 1.20.1/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java diff --git a/1.20/Forge/src/main/java/fuzs/visualworkbench/core/ForgeAbstractions.java b/1.20.1/Forge/src/main/java/fuzs/visualworkbench/core/ForgeAbstractions.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/visualworkbench/core/ForgeAbstractions.java rename to 1.20.1/Forge/src/main/java/fuzs/visualworkbench/core/ForgeAbstractions.java diff --git a/1.20/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.1/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java rename to 1.20.1/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java diff --git a/1.20/Forge/src/main/resources/META-INF/mods.toml b/1.20.1/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from 1.20/Forge/src/main/resources/META-INF/mods.toml rename to 1.20.1/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.20/Forge/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions b/1.20.1/Forge/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions similarity index 100% rename from 1.20/Forge/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions rename to 1.20.1/Forge/src/main/resources/META-INF/services/fuzs.visualworkbench.core.CommonAbstractions diff --git a/1.20/build.gradle b/1.20.1/build.gradle similarity index 100% rename from 1.20/build.gradle rename to 1.20.1/build.gradle diff --git a/1.20/gradle.properties b/1.20.1/gradle.properties similarity index 100% rename from 1.20/gradle.properties rename to 1.20.1/gradle.properties diff --git a/1.20/gradle/wrapper/gradle-wrapper.jar b/1.20.1/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.20/gradle/wrapper/gradle-wrapper.jar rename to 1.20.1/gradle/wrapper/gradle-wrapper.jar diff --git a/1.20/gradle/wrapper/gradle-wrapper.properties b/1.20.1/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.20/gradle/wrapper/gradle-wrapper.properties rename to 1.20.1/gradle/wrapper/gradle-wrapper.properties diff --git a/1.20/gradlew b/1.20.1/gradlew similarity index 100% rename from 1.20/gradlew rename to 1.20.1/gradlew diff --git a/1.20/gradlew.bat b/1.20.1/gradlew.bat similarity index 100% rename from 1.20/gradlew.bat rename to 1.20.1/gradlew.bat diff --git a/1.20/settings.gradle b/1.20.1/settings.gradle similarity index 100% rename from 1.20/settings.gradle rename to 1.20.1/settings.gradle diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md new file mode 100644 index 0000000..c7f9a93 --- /dev/null +++ b/1.20.4/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog]. + +## [v8.0.0-1.20.1] - 2023-06-27 +- Ported to Minecraft 1.20.1 + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.20.4/Common/build.gradle b/1.20.4/Common/build.gradle new file mode 100644 index 0000000..4ce2222 --- /dev/null +++ b/1.20.4/Common/build.gradle @@ -0,0 +1,14 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common + + // Just Enough Items + compileOnly libs.jeiapi.common +} + +// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { + it.targetNamespace = "named" +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java new file mode 100644 index 0000000..d95d14d --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java @@ -0,0 +1,36 @@ +package fuzs.visualworkbench; + +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.event.v1.RegistryEntryAddedCallback; +import fuzs.puzzleslib.api.event.v1.server.TagsUpdatedCallback; +import fuzs.visualworkbench.config.ClientConfig; +import fuzs.visualworkbench.handler.OpenMenuHandler; +import fuzs.visualworkbench.init.ModRegistry; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VisualWorkbench implements ModConstructor { + public static final String MOD_ID = "visualworkbench"; + public static final String MOD_NAME = "Visual Workbench"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class); + + @Override + public void onConstructMod() { + ModRegistry.touch(); + registerHandlers(); + } + + private static void registerHandlers() { + RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK).register(OpenMenuHandler::onRegistryEntryAdded); + TagsUpdatedCallback.EVENT.register(OpenMenuHandler::onTagsUpdated); + } + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java new file mode 100644 index 0000000..377e39a --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java @@ -0,0 +1,31 @@ +package fuzs.visualworkbench.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; +import fuzs.puzzleslib.api.core.v1.context.PackRepositorySourcesContext; +import fuzs.puzzleslib.api.resources.v1.DynamicPackResources; +import fuzs.puzzleslib.api.resources.v1.PackResourcesHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.client.renderer.blockentity.WorkbenchBlockEntityRenderer; +import fuzs.visualworkbench.data.client.DynamicModelProvider; +import fuzs.visualworkbench.init.ModRegistry; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.gui.screens.inventory.CraftingScreen; + +public class VisualWorkbenchClient implements ClientModConstructor { + + @Override + public void onClientSetup() { + MenuScreens.register(ModRegistry.CRAFTING_MENU_TYPE.get(), CraftingScreen::new); + } + + @Override + public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { + context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.get(), WorkbenchBlockEntityRenderer::new); + } + + @Override + public void onAddResourcePackFinders(PackRepositorySourcesContext context) { + context.addRepositorySource(PackResourcesHelper.buildClientPack(VisualWorkbench.id("default_block_models"), DynamicPackResources.create(DynamicModelProvider::new), true)); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java new file mode 100644 index 0000000..7227811 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java @@ -0,0 +1,96 @@ +package fuzs.visualworkbench.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ClientConfig; +import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +public class WorkbenchBlockEntityRenderer implements BlockEntityRenderer { + private final ItemRenderer itemRenderer; + + public WorkbenchBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + this.itemRenderer = context.getItemRenderer(); + } + + @Override + public void render(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above + combinedLightIn = blockEntity.getLevel() != null ? LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : 15728880; + for (int i = 0; i < blockEntity.getCraftSlots().getContainerSize(); ++i) { + ItemStack itemStack = blockEntity.getCraftSlots().getItem(i); + if (!itemStack.isEmpty()) { + this.renderIngredientItem(blockEntity, partialTicks, poseStack, bufferIn, combinedLightIn, combinedOverlayIn, i, itemStack); + } + } + if (VisualWorkbench.CONFIG.get(ClientConfig.class).renderResult && blockEntity.getResultSlots().getRecipeUsed() != null) { + ItemStack resultItem = blockEntity.getResultSlots().getRecipeUsed().getResultItem(Minecraft.getInstance().level.registryAccess()); + if (!resultItem.isEmpty()) { + this.renderResultItem(resultItem, blockEntity.getLevel(), blockEntity.ticks + partialTicks, poseStack, bufferIn, combinedLightIn); + } + } + } + + private void renderIngredientItem(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, int i, ItemStack itemStack) { + poseStack.pushPose(); + if (VisualWorkbench.CONFIG.get(ClientConfig.class).flatRendering) { + this.setupLayingRenderer(blockEntity, partialTicks, poseStack, itemStack, i); + } else { + this.setupFloatingRenderer(blockEntity, partialTicks, poseStack, itemStack, i); + } + this.itemRenderer.renderStatic(itemStack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, poseStack, bufferIn, blockEntity.getLevel(), (int) blockEntity.getBlockPos().asLong() + i); + poseStack.popPose(); + } + + private void setupFloatingRenderer(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, ItemStack itemStack, int index) { + // -0.0125 to 0.0125 + float shift = (float) Math.abs(((blockEntity.ticks + partialTicks) * 50.0 + (index * 1000L)) % 5000L - 2500L) / 200000.0F; + BakedModel model = this.itemRenderer.getModel(itemStack, null, null, 0); + boolean blockItem = model.isGui3d(); + poseStack.translate(0.5, shift, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, blockEntity.currentAngle, blockEntity.nextAngle))); + poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, 1.09375, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); + float scale = blockItem ? 0.24F : 0.18F; + poseStack.scale(scale, scale, scale); + } + + private void setupLayingRenderer(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, ItemStack itemStack, int index) { + BakedModel model = this.itemRenderer.getModel(itemStack, null, null, 0); + boolean blockItem = model.isGui3d(); + poseStack.translate(0.5, 0.0, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, blockEntity.currentAngle, blockEntity.nextAngle))); + poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, blockItem ? 1.0625 : 1.005, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); + poseStack.mulPose(Axis.XP.rotationDegrees(90.0F)); + poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F)); + float scale = blockItem ? 0.25F : 0.175F; + poseStack.scale(scale, scale, scale); + } + + private void renderResultItem(ItemStack stack, @Nullable Level worldIn, float time, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn) { + poseStack.pushPose(); + poseStack.translate(0.5F, 1.15F, 0.5F); + BakedModel model = this.itemRenderer.getModel(stack, worldIn, null, 0); + float hoverOffset = Mth.sin(time / 10.0F) * 0.04F + 0.1F; + float modelYScale = model.getTransforms().getTransform(ItemDisplayContext.GROUND).scale.y(); + poseStack.translate(0.0, hoverOffset + 0.25F * modelYScale, 0.0); + poseStack.mulPose(Axis.YP.rotation(time / 20.0F)); + if (!model.isGui3d()) { + poseStack.scale(0.75F, 0.75F, 0.75F); + } + this.itemRenderer.render(stack, ItemDisplayContext.GROUND, false, poseStack, bufferIn, combinedLightIn, OverlayTexture.NO_OVERLAY, model); + poseStack.popPose(); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java new file mode 100644 index 0000000..0fd88e7 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java @@ -0,0 +1,13 @@ +package fuzs.visualworkbench.config; + +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; + +public class ClientConfig implements ConfigCore { + @Config(description = "Makes crafting table contents lay flat on the table instead of floating above.") + public boolean flatRendering = false; + @Config(description = "Render the result of the crafting operation in addition to crafting table contents.") + public boolean renderResult = true; + @Config(description = "Rotate crafting table contents so they always face the closest player.") + public boolean rotateIngredients = true; +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java new file mode 100644 index 0000000..0c8813f --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java @@ -0,0 +1,17 @@ +package fuzs.visualworkbench.core; + +import fuzs.puzzleslib.api.core.v1.ServiceProviderHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.LevelReader; + +public interface CommonAbstractions { + CommonAbstractions INSTANCE = ServiceProviderHelper.load(CommonAbstractions.class); + + boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player); + + InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context); +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java new file mode 100644 index 0000000..b9fbc4d --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java @@ -0,0 +1,19 @@ +package fuzs.visualworkbench.data; + +import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.visualworkbench.init.ModRegistry; +import net.minecraft.core.HolderLookup; +import net.minecraft.world.level.block.Blocks; + +public class ModBlockTagsProvider extends AbstractTagProvider.Blocks { + + public ModBlockTagsProvider(DataProviderContext context) { + super(context); + } + + @Override + protected void addTags(HolderLookup.Provider provider) { + this.tag(ModRegistry.NON_VISUAL_WORKBENCHES_BLOCK_TAG).add(Blocks.SMITHING_TABLE, Blocks.FLETCHING_TABLE); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java new file mode 100644 index 0000000..eeb4474 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java @@ -0,0 +1,36 @@ +package fuzs.visualworkbench.data.client; + +import fuzs.puzzlesaccessapi.api.client.data.v2.BlockModelBuilder; +import fuzs.puzzlesaccessapi.api.client.data.v2.ItemModelBuilder; +import fuzs.puzzleslib.api.client.data.v2.AbstractModelProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.visualworkbench.handler.OpenMenuHandler; +import net.minecraft.data.models.blockstates.MultiVariantGenerator; +import net.minecraft.data.models.blockstates.Variant; +import net.minecraft.data.models.blockstates.VariantProperties; +import net.minecraft.data.models.model.ModelLocationUtils; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Blocks; + +public class DynamicModelProvider extends AbstractModelProvider { + + public DynamicModelProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addBlockModels(BlockModelBuilder builder) { + // dynamically generate a basic stone block model for every diagonal block so the model bakery logs no missing model + // don't use an air model so the blocks remain visible + ResourceLocation resourceLocation = ModelLocationUtils.getModelLocation(Blocks.STONE); + OpenMenuHandler.BLOCK_CONVERSIONS.values().forEach((block) -> { + builder.getBlockStateOutput().accept(MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, resourceLocation))); + builder.skipAutoItemBlock(block); + }); + } + + @Override + public void addItemModels(ItemModelBuilder builder) { + + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java new file mode 100644 index 0000000..907997b --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java @@ -0,0 +1,78 @@ +package fuzs.visualworkbench.handler; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import fuzs.puzzleslib.api.block.v1.BlockConversionHelper; +import fuzs.puzzleslib.api.init.v3.RegistryHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.level.block.VisualCraftingTableBlock; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CraftingTableBlock; + +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +public class OpenMenuHandler { + public static final BiMap BLOCK_CONVERSIONS = HashBiMap.create(); + + public static void onRegistryEntryAdded(Registry registry, ResourceLocation id, Block entry, BiConsumer> registrar) { + if (entry instanceof CraftingTableBlock) { + ResourceLocation resourceLocation = VisualWorkbench.id(id.getNamespace() + "/" + id.getPath()); + registrar.accept(resourceLocation, () -> { + BLOCK_CONVERSIONS.put(entry, new VisualCraftingTableBlock(entry)); + return BLOCK_CONVERSIONS.get(entry); + }); + } + } + + public static void onTagsUpdated(RegistryAccess registryAccess, boolean client) { + for (Map.Entry, Item> entry : BuiltInRegistries.ITEM.entrySet()) { + if (entry.getValue() instanceof BlockItem blockItem) { + Block block = blockItem.getBlock(); + setItemForBlock(entry.getKey().location(), blockItem, block); + setBlockForItem(blockItem, block); + } + } + copyBoundTags(); + } + + private static void setItemForBlock(ResourceLocation resourceLocation, BlockItem blockItem, Block block) { + if (BLOCK_CONVERSIONS.containsKey(block)) { + BlockConversionHelper.setItemForBlock(BLOCK_CONVERSIONS.get(block), blockItem); + } + } + + private static void setBlockForItem(BlockItem blockItem, Block block) { + BiMap conversions = BLOCK_CONVERSIONS; + Block baseBlock; + Block diagonalBlock = conversions.get(block); + if (diagonalBlock != null) { + baseBlock = block; + } else { + baseBlock = conversions.inverse().get(block); + if (baseBlock != null) { + diagonalBlock = block; + } else { + return; + } + } + if (RegistryHelper.is(ModRegistry.NON_VISUAL_WORKBENCHES_BLOCK_TAG, baseBlock)) { + BlockConversionHelper.setBlockForItem(blockItem, baseBlock); + } else { + BlockConversionHelper.setBlockForItem(blockItem, diagonalBlock); + } + } + + private static void copyBoundTags() { + BLOCK_CONVERSIONS.forEach(BlockConversionHelper::copyBoundTags); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java new file mode 100644 index 0000000..92340cb --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java @@ -0,0 +1,31 @@ +package fuzs.visualworkbench.init; + +import fuzs.puzzleslib.api.init.v2.RegistryManager; +import fuzs.puzzleslib.api.init.v2.RegistryReference; +import fuzs.puzzleslib.api.init.v3.tags.BoundTagFactory; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.handler.OpenMenuHandler; +import fuzs.visualworkbench.mixin.accessor.BlockEntityTypeBuilderAccessor; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; +import net.minecraft.tags.TagKey; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.instant(VisualWorkbench.MOD_ID); + public static final RegistryReference> CRAFTING_TABLE_BLOCK_ENTITY = REGISTRY.registerBlockEntityType("crafting_table", () -> { + BlockEntityType.Builder builder = BlockEntityType.Builder.of(VisualCraftingTableBlockEntity::new); + BlockEntityTypeBuilderAccessor.class.cast(builder).visualworkbench$setValidBlocks(OpenMenuHandler.BLOCK_CONVERSIONS.values()); + return builder; + }); + public static final RegistryReference> CRAFTING_MENU_TYPE = REGISTRY.registerMenuType("crafting", () -> VisualCraftingMenu::new); + + static final BoundTagFactory TAGS = BoundTagFactory.make(VisualWorkbench.MOD_ID); + public static final TagKey NON_VISUAL_WORKBENCHES_BLOCK_TAG = TAGS.registerBlockTag("non_visual_workbenches"); + + public static void touch() { + + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java new file mode 100644 index 0000000..fe4a7ce --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java @@ -0,0 +1,24 @@ +package fuzs.visualworkbench.integration.jei; + +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.RecipeTypes; +import mezz.jei.api.registration.IRecipeTransferRegistration; +import net.minecraft.resources.ResourceLocation; + +@JeiPlugin +public class VisualWorkbenchJEIPlugin implements IModPlugin { + + @Override + public ResourceLocation getPluginUid() { + return new ResourceLocation(VisualWorkbench.MOD_ID, "crafting"); + } + + @Override + public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { + registration.addRecipeTransferHandler(VisualCraftingMenu.class, ModRegistry.CRAFTING_MENU_TYPE.get(), RecipeTypes.CRAFTING, 1, 9, 10, 36); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java new file mode 100644 index 0000000..08f0561 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java @@ -0,0 +1,17 @@ +package fuzs.visualworkbench.mixin.accessor; + +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Set; + +@Mixin(BlockEntityType.Builder.class) +public interface BlockEntityTypeBuilderAccessor { + + @Accessor("validBlocks") + @Mutable + void visualworkbench$setValidBlocks(Set validBlocks); +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java new file mode 100644 index 0000000..be55441 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java @@ -0,0 +1,27 @@ +package fuzs.visualworkbench.mixin.accessor; + +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.inventory.CraftingMenu; +import net.minecraft.world.inventory.ResultContainer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(CraftingMenu.class) +public interface CraftingMenuAccessor { + + @Mutable + @Accessor("craftSlots") + void visualworkbench$setCraftSlots(CraftingContainer craftSlots); + + @Mutable + @Accessor("resultSlots") + void visualworkbench$setResultSlots(ResultContainer resultSlots); + + @Mutable + @Accessor("craftSlots") + CraftingContainer visualworkbench$getCraftSlots(); + + @Accessor("resultSlots") + ResultContainer visualworkbench$getResultSlots(); +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java new file mode 100644 index 0000000..4539b89 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java @@ -0,0 +1,9 @@ +package fuzs.visualworkbench.util; + +public class MathHelper { + + public static float easeOutQuad(double t, float b, float c, double d) { + float z = (float) t / (float) d; + return -c * z * (z - 2.0F) + b; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java new file mode 100644 index 0000000..66f67c9 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -0,0 +1,106 @@ +package fuzs.visualworkbench.world.inventory; + +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.mixin.accessor.CraftingMenuAccessor; +import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.*; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class VisualCraftingMenu extends CraftingMenu implements ContainerListener { + private final CraftingContainer craftSlots; + private final ResultContainer resultSlots; + @Nullable + private final VisualCraftingTableBlockEntity blockEntity; + private final ContainerLevelAccess access; + + public VisualCraftingMenu(int id, Inventory inventory) { + super(id, inventory); + this.craftSlots = ((CraftingMenuAccessor) this).visualworkbench$getCraftSlots(); + this.resultSlots = ((CraftingMenuAccessor) this).visualworkbench$getResultSlots(); + this.blockEntity = null; + this.access = ContainerLevelAccess.NULL; + } + + public VisualCraftingMenu(int id, Inventory inventory, VisualCraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { + super(id, inventory, access); + this.craftSlots = blockEntity.getCraftSlots(); + ((CraftingMenuAccessor) this).visualworkbench$setCraftSlots(this.craftSlots); + this.resultSlots = blockEntity.getResultSlots(); + ((CraftingMenuAccessor) this).visualworkbench$setResultSlots(this.resultSlots); + this.blockEntity = blockEntity; + this.access = access; + this.addSlots(inventory); + this.addSlotListener(this); + } + + private void addSlots(Inventory inventory) { + this.slots.set(0, Util.make(new ResultSlot(inventory.player, this.craftSlots, this.resultSlots, 0, 124, 35) { + + @Override + public void set(ItemStack stack) { + // fast workbench makes this do nothing (via mixin), but in our case it is needed to avoid client desync + this.container.setItem(this.getContainerSlot(), stack); + this.setChanged(); + } + }, slot -> slot.index = 0)); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + int slotIndex = j + i * 3; + this.slots.set(slotIndex + 1, Util.make(new Slot(this.craftSlots, slotIndex, 30 + j * 18, 17 + i * 18), slot -> slot.index = slotIndex + 1)); + } + } + } + + @Override + public MenuType getType() { + return ModRegistry.CRAFTING_MENU_TYPE.get(); + } + + @Override + public void slotChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, ItemStack itemStack) { + if (containerMenu == this) { + this.access.execute((Level level, BlockPos blockPos) -> { + if (dataSlotIndex >= 1 && dataSlotIndex < 10) { + this.slotsChanged(this.craftSlots); + } + }); + } + } + + @Override + public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) { + + } + + @Override + public boolean stillValid(Player player) { + Objects.requireNonNull(this.blockEntity, "block entity is null"); + return Container.stillValidBlockEntity(this.blockEntity, player); + } + + @Override + public void removed(Player player) { + // copied from container base class + if (player instanceof ServerPlayer) { + ItemStack itemstack = this.getCarried(); + if (!itemstack.isEmpty()) { + if (player.isAlive() && !((ServerPlayer) player).hasDisconnected()) { + player.getInventory().placeItemBackInInventory(itemstack); + } else { + player.drop(itemstack, false); + } + this.setCarried(ItemStack.EMPTY); + } + } + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java new file mode 100644 index 0000000..732607b --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java @@ -0,0 +1,85 @@ +package fuzs.visualworkbench.world.level.block; + +import fuzs.puzzleslib.api.block.v1.TickingBlockEntity; +import fuzs.puzzleslib.api.block.v1.TickingEntityBlock; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.stats.Stats; +import net.minecraft.world.Containers; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +public class VisualCraftingTableBlock extends BaseEntityBlock implements TickingEntityBlock { + private final Block block; + + public VisualCraftingTableBlock(Block block) { + super(BlockBehaviour.Properties.copy(block).dropsLike(block)); + this.block = block; + } + + @Override + public String getDescriptionId() { + return this.block.getDescriptionId(); + } + + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Override + public boolean hasAnalogOutputSignal(BlockState blockState) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos blockPos) { + return level.getBlockEntity(blockPos) instanceof VisualCraftingTableBlockEntity crafterBlockEntity ? crafterBlockEntity.getRedstoneSignal() : 0; + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new VisualCraftingTableBlockEntity(pos, state); + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if (level.isClientSide) { + return InteractionResult.SUCCESS; + } else { + if (level.getBlockEntity(pos) instanceof VisualCraftingTableBlockEntity blockEntity) { + player.openMenu(blockEntity); + player.awardStat(Stats.INTERACT_WITH_CRAFTING_TABLE); + } + return InteractionResult.CONSUME; + } + } + + @Override + public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { + if (!state.is(newState.getBlock())) { + if (level.getBlockEntity(pos) instanceof VisualCraftingTableBlockEntity blockEntity) { + Containers.dropContents(level, pos, blockEntity.getCraftSlots()); + } + super.onRemove(state, level, pos, newState, movedByPiston); + } + } + + @Override + public BlockEntityType getBlockEntityType() { + return (BlockEntityType) ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.get(); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java new file mode 100644 index 0000000..6c15f26 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java @@ -0,0 +1,41 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; + +public class ContainerSerializationHelper { + + public static CompoundTag saveAllItems(CompoundTag tag, Container container) { + return saveAllItems(tag, container, true); + } + + public static CompoundTag saveAllItems(CompoundTag tag, Container container, boolean saveEmpty) { + ListTag listTag = new ListTag(); + for (int i = 0; i < container.getContainerSize(); ++i) { + ItemStack itemStack = container.getItem(i); + if (!itemStack.isEmpty()) { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putByte("Slot", (byte) i); + itemStack.save(compoundTag); + listTag.add(compoundTag); + } + } + if (!listTag.isEmpty() || saveEmpty) { + tag.put("Items", listTag); + } + return tag; + } + + public static void loadAllItems(CompoundTag tag, Container container) { + ListTag listTag = tag.getList("Items", 10); + for (int i = 0; i < listTag.size(); ++i) { + CompoundTag compoundTag = listTag.getCompound(i); + int j = compoundTag.getByte("Slot") & 255; + if (j < container.getContainerSize()) { + container.setItem(j, ItemStack.of(compoundTag)); + } + } + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java new file mode 100644 index 0000000..5e214e0 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java @@ -0,0 +1,187 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import fuzs.puzzleslib.api.block.v1.TickingBlockEntity; +import fuzs.puzzleslib.api.core.v1.CommonAbstractions; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ClientConfig; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.util.MathHelper; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.*; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class VisualCraftingTableBlockEntity extends BlockEntity implements MenuProvider, TickingBlockEntity { + private static final String TAG_CRAFT_SLOTS = "CraftSlots"; + private static final String TAG_RESULT_SLOTS = "ResultSlots"; + private static final String TAG_RECIPE_USED = "RecipeUsed"; + + private TransientCraftingContainer craftSlots; + private ResultContainer resultSlots; + public int ticks; + public float currentAngle; + public float nextAngle; + private int sector; + private boolean animating; + private float animationAngleStart; + private float animationAngleEnd; + private double startTicks; + private double playerAngle; + + public VisualCraftingTableBlockEntity(BlockPos pos, BlockState state) { + super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.get(), pos, state); + } + + @Override + public Component getDisplayName() { + return Component.translatable("container.crafting"); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + this.craftSlots = new TransientCraftingContainer(new AbstractContainerMenu(null, -1) { + @Override + public ItemStack quickMoveStack(Player player, int index) { + return null; + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void slotsChanged(Container container) { + VisualCraftingTableBlockEntity.this.setChanged(); + } + }, 3, 3, NonNullList.createWithCapacity(9)); + ContainerSerializationHelper.loadAllItems(tag.getCompound(TAG_CRAFT_SLOTS), this.craftSlots); + this.resultSlots = new ResultContainer(); + ContainerSerializationHelper.loadAllItems(tag.getCompound(TAG_RESULT_SLOTS), this.resultSlots); + Optional> recipe = CommonAbstractions.INSTANCE.getMinecraftServer().getRecipeManager().byKey(ResourceLocation.tryParse(tag.getString(TAG_RECIPE_USED))); + recipe.ifPresent(this.resultSlots::setRecipeUsed); + } + + @Override + protected void saveAdditional(CompoundTag tag) { + super.saveAdditional(tag); + CompoundTag compoundTag1 = new CompoundTag(); + ContainerSerializationHelper.saveAllItems(compoundTag1, this.craftSlots); + tag.put(TAG_CRAFT_SLOTS, compoundTag1); + CompoundTag compoundTag2 = new CompoundTag(); + ContainerSerializationHelper.saveAllItems(compoundTag2, this.resultSlots); + tag.put(TAG_RESULT_SLOTS, compoundTag2); + if (this.resultSlots.getRecipeUsed() != null) { + tag.putString(TAG_RECIPE_USED, this.resultSlots.getRecipeUsed().getId().toString()); + } + } + + @Override + @Nullable + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public CompoundTag getUpdateTag() { + return this.saveWithoutMetadata(); + } + + @Override + public void setChanged() { + super.setChanged(); + if (this.level != null) { + this.level.sendBlockUpdated(this.worldPosition, this.getBlockState(), this.getBlockState(), 3); + } + } + + public CraftingContainer getCraftSlots() { + return this.craftSlots; + } + + public ResultContainer getResultSlots() { + return this.resultSlots; + } + + @Override + public AbstractContainerMenu createMenu(int id, Inventory playerInventory, Player player) { + return new VisualCraftingMenu(id, playerInventory, this, ContainerLevelAccess.create(this.getLevel(), this.getBlockPos())); + } + + public int getRedstoneSignal() { + int i = 0; + for (int j = 0; j < this.craftSlots.getContainerSize(); ++j) { + ItemStack itemStack = this.craftSlots.getItem(j); + if (!itemStack.isEmpty()) { + ++i; + } + } + return i; + } + + @Override + public void clientTick() { + ++this.ticks; + if (this.craftSlots.isEmpty() || !VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients) return; + Player player = this.getLevel().getNearestPlayer((double) this.worldPosition.getX() + 0.5D, (double) this.worldPosition.getY() + 0.5D, (double) this.worldPosition.getZ() + 0.5D, 3.0D, false); + if (player != null) { + double d0 = player.getX() - ((double) this.worldPosition.getX() + 0.5D); + double d1 = player.getZ() - ((double) this.worldPosition.getZ() + 0.5D); + this.playerAngle = (Math.atan2(-d0, -d1) + 3.9269908169872414D) % 6.283185307179586D; + } + // most animation code is taken from the old RealBench mod (https://www.curseforge.com/minecraft/mc-mods/realbench) + int sector = (int) (this.playerAngle * 2.0 / Math.PI); + if (this.sector != sector) { + this.animating = true; + this.animationAngleStart = this.currentAngle; + float delta1 = sector * 90.0F - this.currentAngle; + float abs1 = Math.abs(delta1); + float delta2 = delta1 + 360.0F; + float shift = Math.abs(delta2); + float delta3 = delta1 - 360.0F; + float abs3 = Math.abs(delta3); + if (abs3 < abs1 && abs3 < shift) { + this.animationAngleEnd = delta3 + this.currentAngle; + } else if (shift < abs1 && shift < abs3) { + this.animationAngleEnd = delta2 + this.currentAngle; + } else { + this.animationAngleEnd = delta1 + this.currentAngle; + } + this.startTicks = this.ticks; + this.sector = sector; + } + if (this.animating) { + if (this.ticks >= this.startTicks + 20) { + this.animating = false; + this.currentAngle = this.nextAngle = (this.animationAngleEnd + 360.0F) % 360.0F; + } else { + this.currentAngle = (MathHelper.easeOutQuad(this.ticks - this.startTicks, this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; + this.nextAngle = (MathHelper.easeOutQuad(Math.min(this.ticks + 1 - this.startTicks, 20), this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; + if (this.currentAngle != 0.0F || this.nextAngle != 0.0F) { + if (this.currentAngle == 0.0F && this.nextAngle >= 180.0F) { + this.currentAngle = 360.0F; + } + if (this.nextAngle == 0.0F && this.currentAngle >= 180.0F) { + this.nextAngle = 360.0F; + } + } + } + } + } +} diff --git a/1.20.4/Common/src/main/resources/mod_banner.png b/1.20.4/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..7b831557d05a594b4656129c710ca01c24ed72a2 GIT binary patch literal 17426 zcmV(`K-0g8P)SBg^-SVUP@D1KR|qckAr%6Pd-yIF&MA5$#$fxNJvmbLOxbm zNirJ_PB%MLJ3Mn+RCr=+I#DWew9`|M60#TDqdh2D-%#wH8n6VJ6R!|n6*+>XNGlfh=z)9X;M#gE)ow4Ixre$ zWG``hT17HCMmRZSO;%@CS!h-^cV=pfWNUU=XnS02cxQNbcXyU~czu#vX?AIMhg)}pT624Og_%V|N-1MUCRIKnTSFvaP%e>gN|$Ifi()f~Rw{B* zENV?Eh*m3mRV=M}NL))ROFbhhDk`dTIHzkfl~*YzCKe?f5i%weIxZO;92^u42q_;C z6%`dBAR!D43%7YXnPV<)IT@;?q@ib5R7hCVbY7OSR{%aTr1L@B|(zBVfv$%;aun}<$7 zBvL{q#KXhP$Fs84b|T&_y{P5(@_c0s&)4C)JTf z*Of@qjzZCgJ<^Lm&4N3`bThnYE=p`G!EZ5Ec{8h3CA?%Sz-uq2qK%@SjJRGYQFSg= zdoi|ICZkUxO>-=?Rwb86A6kSnvaOk1hcsf0I8uBrW|KO%vYp7otirvhySAm!%eJqu zmQ8pn!MdJ^d5L*;YmV=_#_`7b z^wsIoreON>{`cv(`u_a*`}q3d^!@w({_yh0+^(ohv6BD*K$A&C zK~#8NoY8A*@-Q3)aHS@=3|2R!LJ74X))ymFVc-AT^m_5W>+`(W`Dba0*bUi_(r|MA zEv4yceaCqo{OG2eDgTNwc2R_E2n@Io;+EM+kS-(G&_>+5aV|JN&r+#7P((^$@sMEls$~T)3 zS5bIgQEX1olxVyOd0GC8V<}flU&p19B*}X1SyY+cr@;g$n#RXV&Qw(u$Mg9-wkS%a z7TQ#i?JiAINiq%dS(Ykz#kx~!iqRkl7TRpKmGCyhuJMk&6}|_2k!7N;>j_Y_J~f2> z{=aoNd@oOp;}QRn4vbFBoR*`{>5DV_>unpk!Z^G|Q~1Ug-9;UsfKV4uon9lj4G-I^ndv8NndQIcgQcsF{w)cWtk%ql$&zMw z(&_2xFTcD)^!ok>nJQ4JQlL^PK!t);pel;tut0%@RGl&~MmJ5W> zRZD&L9-I|xSka{iD_R~iXVr`4p=gLzz%m>aH6#_9t=jEF1Si+6x&*7$XmqQsPB>PK zqqs6>6fmz-5f0H^--b)s4rt!yyxR6DHFRK`mC_Tj^an$>?WSYfOJmc7EN-Zm>FSmK17 zRr(5vNXLFt!^%;q6)%bvb;0A}Cg-tAQ1~!a94oOxe&}?6RIEm-SHoiDA<4cZ z0u_^^1#PO;tzN)N9biQ%wE|W*U01BSD2<}W#)?W|Zf~Ma&1#YWgIfHs7@Q}$@T=Y` zrXJ%a$X%#hEFQzEka3&J1*m4lf)&Coq%cz)9xx$N1ubn4`(LO(Fbq`0(qXDprMk0L zr|1IIC)$2wci#0|oM60zOEEKE|tvXsNyH!WA@O`8TRvW){fwAh9RV!lIjtSze zNF`Q^MMx{yOBk&*dIYVI$Kpm93RW{xh5Hex?nk8ZP(dqXnfm-SHinZ$E2RoVwW-21 zr92OU3h7wA3yIa=e|+4EJ#9rSSa~eiAP6FSM7U>I&OwD5W2IDnta|c??DxP4QY|@N zz>0aQAej)0Q7~9BYhjfc_~K0Dg_lf4RNXh)?dE=&ToOup0+BSRa9u+s!OYsMcmU8V7+QsRjCS@IXPKO z%BmH!TE}%Oi$X{ZH?i8P*1{JyKUqC#b)jLEGhoU+wB$#UpQ#w}A_2%*Eti%GR->+QUa#gGttSX20RHz~-;S;5b zg&S+7`FV;^Hz^Z&3*ky8frb7j)YeQh~q%T0EN_wV|BS%)9O?kiqJm8b;#w_Gwy-ABi0qQRA(rG##sqgGz?bu zAWtR6kx9D*?b1r)fca$yrAd}&Wl~}Q7I2c;=+%q0Ubl`VPHvW9RUNiq6?|$D>&S`l z)n7}n@+Osbl;h2p{HzLA3HCe%kUdadE@jyORC)e+rM1jiKY`VDtkmy;-ilc)w|d&@ z;7U8V5}oj>LhsUbymnT8ut=p&G$EEoD<7l@MJo9}HZxO}YDKADvj!Eh5|_6PR)X$S z7Te1KJ)Wt0R{kxY_K;9r_>oaXg7NwW7{4nLrBvHC9UwG2a57|N8m!ZH^4B`tWR)qPsh{ z2O`haiAY2$F5ZdNkGpn1=oEs*wOTPsR5w8{(+nE(8<%^ckAOJG+l^Ry_#>6n>M^Qg z^tM;q1>@3Hw@Q5F6Ij^>)(jn8NLY}HPg=%UD$J0pODiB@IF~|ody55*77J1>2Xb&3 z3k|O zah!0Oaju9ZR^x%~C&9`RX`9x1&3Ep1mE=_hw?Yh9=M??U)HVPItb=pNz=!Wx!;MaaJ*Yj?lH->^c9fO7HBODAbL$3G!TaxAU_XGjA1AIja4#aS{ONMrjhd{tn$I^@!LTLxb*x2b7!zIpt-_rM>L;K!TZm9H=WTghD zA0f#}haKPNvmISaK-T_?(Q%$QKi~?o8c?*ViWn40V<_e#IA$v>W>?pFH9}pO4I|GH z`Qsp4@uWg`mxYG8QdtT~$+FdISdCvJhW}!qhBDj;Y671EGP2g_uq+o<3pn7%-%(kh zFuIPU6hGKO9|gHvI~2=5)Rlp7HRKU~l3Zl1&&lW(waTPXmK+Hs5g4jkZR!d1!r(wmy{DhQ*=WLbO*7O`os%QRy1U^6{dbGciKC3UL9V3oF8|N=ZGDQtB;1O;;6xpGYmaT0FIYE)oFR z-I!xS#;t&E7i1Ce5dxIk6bcpj(VB`ps#Zja65|BsihAQsu!ILVnfhs0z{c2Iod9ed zcsydHCMVn#O|Y(M+DNAD5gR9ZM7ORh+UgGjZUl1nd zalq5A(8Q`0&5cX4a*{=c%fhN-%~7vcXa*HvVETG}ES&@8L}*P5Q@HnvT^*FCH0)SoAsP zTyw?)QXVOiZ}^zZ{pmRv%Msz+-dc9v{jr0G_*drLlLVZPS^>)|rJ^{F9bh33JWnJ^ zZ=ArW;H*}w;&OQGhrrsh)fQ9^8c2{yf6oe7Lgg5Y16U-akKUjPx!X6bc6TEjE0(dU zVr87ab%}EiESLAG93>W>!JcZxF}zu`IcYXCXwfsfwsmq6W4moDrh~kjWpIFs;E0oE zOOY@2aveIiEGx%P1oqa7;|T9%V#QGu#kaL&=~S&k;vp#ui6dEhft}miAdWn;5~en1 zwL-auzVm^tw%ZR5G>1t7O_YvIG(sgQYo$>sBsgs4AGXqFnPM%~s*7YM(`%zyiCP5?9@onG=EE#dD_}{yT^uJ4 zG&{wuF4gL|Vs&|`#bPYL8Y^2^lnUt@J+%@n#?+^DD{J&XUIVM?NU+i)SRvM|JjmtQ z9b0Vp`-V+XD=8ELD#1z_%e;lLn#n4vZiY!511d(!T8)z=v}WaNLP}t#wGm+fZ#XaJ z$-HRyT9iAhBI#oY2Bnpsz==x7SRt@vAR}rOBK|J4f>#{GA_&N8v7C}>&k9j2V}wW+Vxh37SjZGaGj!%?4qDAWC#rZu{N1Y#exy`1qTSm8NYu9S*BTj#EP(7H_ft94aHI` zu@@_uX$P@{${)`$0_7!a1&4@6qF`;~M9wODt+m|Bj%tz2JVEG`V#UL;CtwAd<&{24 zWri>7NFYd>CDvF3SxiyK6d8e@SV`2%J7krqRc5GurGUX$0Z*-LVC`9Pv6{{4^tb6` zv!P<0f(Z3Mu}-l&d6vn!Bfe!xIuctxt(HWkGf?)k=4RcjRulMWXN6z}QZ2BlzF;}D z6|{A_YyOx4m9aEZVmV*j4QfLnl8RK5W2cSSaf4PwMqg#{!~IRs76`0z7ed4mPMH9Ot37=ipHy6 zZLe$B~JK23BpjMMvc*Cd*VHsTrs2B}TgpCI>OIK)};@%z@L z@7U=PhgzQ7c{i1HIvU+=W=m&0Mgxm>i=6}n8U+l=h}{tIA#mcLTl^JUt&EYg^NT}2 zF&V-NppIGzl|;`ic7atD%T_FkQo%}PV3m{A4v@Ze@kQDzX8MnjGwN+4tKv8>XeC}F zkU(B-Bp!IML}uTjl9d=icaWMzBekMTn*v)=^?^;GF>PYIb~3hG`^GblJx(*5Hi;)q zQ#P*IxZ8EQq}`9RZeRq#fLf^gz&YpMxihXC#9yj?{GWSg(*APpJ@<~M98)%%%>~LA zlIe7^K!|`|9)x!C#&{s}CIs-lbnV)^@6KOOmB}+u7KQZ5W`=BO z$vkgU~epa}i*@#3w!u|9hW=DD^^d&-IclA z++4Mqyx9+|x~a*-zEKato)wcVjM1<~99k&s7GA1v^}{AzNA|pNHF5FcpHEDT_4~>h zyVYN`G0wL}rs@2uigysg)FjOm+?z)aKD(#pxA!GI9WG-K= zRtse%upIM*JUnVRLD*xuw8youMI2h_zUjl8!rqc6@w?$Q*5+>~rWgMOV?*}NItZQ} zT3`RR&|70&d{XY{NAJ)~HpuJwTEog;&F@22dF& zOeV4MN7X}mb~aPUFK0J4HnIVwO%Uc)p3qUuvq?bYYVP@U~!c?J&w zL)})Z)o?B%@fm7JgsO^zV0L>OMoM^t_ma}|JW7R_k73Um_mGvvOcnA9L9!V5BCjgt zJd)2n(81Gu4_Qsn89ZWzue>EgRw7|XrLCF7isZ(b&ET5NzRj!?XiyWin9o&{=~`ko zQ^hf$1!Dyb3HTGYTCHsm0bF1IBTQz`V5c1yZajN}tv=jgq?H_J1<57Ex98CUMF5^1 z(qPU0Oo+omS~9Z+VVwpAtZc?^l%Qb#bZ>WI0Sar-@6x|-G#a&9=H9)eP=QoMad^N9 zih}EKXnu|c6{rW{b-t*#o6U!9kmtwR&4)e9_nK|TtQd+5X4C5$44bq`YUS44&Q7bf z{GbkAO!1lzJ+lj8ll}lJ3{eVmWG`*B8Q7}nf{lWn2D2@t-E1qiWofdBYtC&h=L@M? zEuF+c;Ime1V>vP=v|68_wzpwGTnACPaR>kq7J))m0@VvKjY(ZbQ__;j7%~e>_F-1T zurB;eu#$?hV%AFeqs6`5-336!SzW!7XgqrKc_UOUqEwRBPPBST-A<=d8T^n*QP0E; zr_I&z3>^ZkqJiPqzCxy}nap-NZJ};uYrX}_J#YfcGu0q;e4`nhO<`fLp5K->u#!D} z#w_ft1FN5ec6_e2iB)SRlPu8ey3?Z3T#O3Kn+Qwj4&>KZUy0#!kVHief*)R{0g!B> zNDPUfSdI}Y3G47M!fNUy=I6N~Rub0#$I7;D-7GBvDL@6RNLThsYx^T3BcFptNRJ=_ zW@t1L=?p2Ax(%q(w{Ih)-NotYnVC}Ab^%081@#PMGK#D^x~+HMRaG^{nB7xRE;zl) zR%!>7dw|_KC}0H#T*d1kEAZM1wjQ;@UdXD`BwHi!o<~%CW?9&|4y@wTy6<&5P2+kC zG8bsk(2!pRSRkHSScC$umc-S{qQ=(G=tqc4R2Y~*FHXrtGcgpfh!tfUno>wWX4TZx z`C(R4k`)#1uMdK!Q4v=6r-2nH!m7N#542Dah>&wD-oA}CQ z&rop}Le*CQfNneRs`x0w=KGCs6j{|)K~-P{tq3twA&i+09wt^j>QynQ8`@nT>?XHu zYNsIOwg#+v5IDe!UqqvyCes3K0vZl0N33|Ilp}&sS}meQ*#%D-na9m@kO8)>mIPi+BM7J2z zWiQp2wr)Gnu{S}N(kx04d_PDblS9rhr9Mb9t-{-|K&M zD7Q7lW+9J)j0?ZS!Eb!guK(ExswtA#+WpQjD+y~VEH5qqETk2%612pGwKhYnh!zIB zdrwODi$zH)gaxS9N_%f)werQ%($bdSIXLhP3t%z7eGo_i7J<4(7;9TwBRCm0@OVcf z#1#b&Agcpl)d^ba3=APPv>jW=cBb#**(#Q$f$7C977s7dn)9tHSxm_P9iSJORz%yI4T?{r}(IdwYr2AK_yv*u!g6sa|r8|ghi+XEleydE`@2FH$JJH~h&!)prsT``^Tf_HbKlB6UpDZbQ4R9M-9@Mb{o z<@+ZOpGSF}5*lJfQ&_OF60istXZ3QJRTLI9BU%HQbtwwV09H_3L|7rJyNip9Gxy8; zD=RBeR^?*p$>N@v*Q8+3+(lMTft7`m2(uW#GJUByGh}Q=V!QGsq${vmLeJ)`Oqz$t zu);G`qGynyVHtFKdSk%KMw2lsdXYvRwTg6VJSf;8&n3t#14Cf;FtDCs=lScj zB!`rAN$HY9o+QiibOh~>W%)l#8b3=^%B><0GD1rGI15M_&C`sI~exud1q{rD9kY>-E->Z>p;7`ffeSfgRS8v{39I4DSjUl~zD>lXASa(arMUfU1t{=Z#jrf7Wm6frvCB1Da47;t**P5t*X@I%KNSX#Ht*% z`*1$Rg4K>GA}U`n-6VVuk(S7WCD|AiOXF=-{a z)g=+Zt}>+{>s`t1NN~>?ZW6xFNWE&i*jAV?ekqah?mjS$8h@pR9g;SgR-7k^Dbf|G zN_m@D>JqchLDm0q_4~JgLCI`ZGw(sn+LRAs1R>JK%ux`=1BvM1(~;PRCsomQxmKCI zW6#IqIm89Q(A8WJqudBa#FE!hS2_#_xocf&aLWpjhg`Bi9(Px@N)~WO+TCiLMwm2!HuqV8qq_Bk+&!5vK!Hf(KQULyTe!g}lOw zdnr6R**0ah&uInr7kxP%FUt5n0cD8D>>$%q>T1PA4Sg4Y$dF9$UX@VT5&3)rZXs3R z+o|mfYv!-pwho2yyL7pa(1*C_OC-qBxoDdf=$wQA59!4ml1vg*r;`Lo+Qh*?mUb{u zwTKVjCTM^TMKgA)DDjV(kVdYPZ!pi{kxd&vd^!{jVnd995)o+t=9LvVeJ6{BWW-() z(xSq_;-dAic!qfNHe|IIVP#S2Rz<)e2~nvBpbD@x-2WyK5#^jyhfP-asj3=%2tuk! zMNv#6c6umvTqEjD1`bUjKJ4ms)yQ#%w5-yr$l1WuL9}e=dV^tT=$83KVN<9ClyWal=@4SWe5qbP0g%0gBbwb1>2+Gq3t4=Ts9I z{lX+4M+N*$GJyMFD5Q;L#~gDVreOv1F<44gxVZJsI^3J~>=9Ns2c}hdR4#TD9*)W@ zZ7bNo#tD9>GcS7T)Lkq(GL0`%ImI4LRc?CYm;u4OGs> zgJF3-29|GH2ZsihZdVCkUB3=nRd~~T1S*lR6@<3pa$R4}He^ZB(-K`F z$re_$Ot9iPkwHIl*cgL2c2FV(%LhBc3Y(UG(i*ho>~{Ym+NvmhdQ{$4J|4t+Jeg_K zp|9xdOI^FpmuFQL@W^XyL`prDEXIlwBB@U~qdOTZWc0sbQ5tJn9bUYfj&DSCVLf5yGN3 zLAu3QDqeUxSiWf;y?NzWh3D)y=h!Wkvq9U={pvmznqg8AZo@EsLQDcUjFtI(-U8QR za@`$YU0t1=oM~iU70S60%gjS{YbHdq#=JFYs9|>1m3gc*SA!HVlP6o$L$rjO94=qq&5ayMNMrKL}B zF~}AiRmY-pl|^z>sAiGEL=cw=c%anK#atLlqj5BOmJ5Zu>$2QMCEG_%7=5e%SpK7t z|2e`*Okih51X>Br1XxRYcdjoHh)PT-3`nYKWMY>?GcL`fjUBV99^JMW_x2jFRC=XLRO_2L=|)nC`*waVDt2PiqNLNPYeMF z)4V`S3#36>i^7cTVB_9=f0fB9^1->P>qmCVT0uo8kn}NV)g4EDNh47tyF^5l{51=n z3|?`zqe6^X@umA~6?q-PBEq+qYX@Yjmk%XI%w+9~gWFrwnJE@%_lHe+%wdWGX%!tJ z@`hZZ3OYkCI5XLmh{lhAK>RYTfPSKgLTrmuk zdh+_PadIW8JZB*lUvIF_aD<{zqz#uc{S$Ur$w?D5!0Dt*49+X;l$02-W)1|Ul;B_3 zytcCG{XhrSTB)g$&b|3=dMix#?C9MWIWf9`{|NU^lpJ9~Mq+@qjph_Iv+pn)KvkJfW6VjUE`u7+2 zGkMz@tumCHK-JKI!n*Z2Vq=jO7|>~iq3JVpiep3TRby7wYDsJlcSUu5J%qJ&?mG^R0XexyCvtvy|D~@qVEKYZAC3oqiTDfp^ZD> z9Gj)8^E%uHemwh#X~^pH5LRFc>y>lAwZ01kvkcxgy%GXxZ7t9YKAuT5ip^6?#JOrL z6P_?yr>ueVMbcwd90`kC_s8#l20~yf_eidGUs(+7fvn~F?xy#7`kT$8$PKpTYH!FT zz|YiG+4u}5Zh<}nFxgyWAcPfEEf6*7?wl5^GRb1?P<0XW&be3g)NN$SY6$CU3hP_v zSo<6~c?fQ3PXog)c=Cahe-=ak42QiIXGpX<-&lgpEeB6eDIfF1>l5i0Sv}pmEj^ZT zeY;NUs`!{y${*Kv^(0R)GGF{3e|@|mZ9t^C+iF#{R5U>mEmrcGUTz^E4MAB#GKe#% zt!7M0p&9m}Q-n-}vqpdA>b-Xr#Ld>lJ21baWF2TG$ODPAy8Lz!*kwnf+}m>2CG`A zJ9dZPZvbMWX*ZAOSY#V61C%fqIrkq9-8ruqeI`5)2Cw8fX@S79R>v(^mpHqOwSu%P zN2-U_n{{;g^hdb`hOxA?rKm;PEJJY#Gd3a+;2IfkjOoI2kynd$;L@vP)?N6PC4EG3 zja-!gnNLuyW!8dLFht=K3=p)kS8e?Oe6kTgG^lKX5<*M9CCi3ETROP_a65CCCUSN? z^@EQI$M@AB>IhJeWXw)@aEp{>S>9E(SAk99$zlGXrikpdW>X1zne~7?&+#=A$026~ zB0`BIK(SYzfMzXDgqJyl)QvcOIv#iP<=2M*;rKqcJ~6T>pCa9U#w4fY)v5D|W`Fy| zuh4C8-upr+f7`Zgqx=dZImxxW1Qcue>2eI%EB}wKGuUyQ2IDvvG!HNrggEd7X!a2} zfH;7(AS47xJi$z)v^fwv5hK;BM!P@~X|TGvR2iWiaap9cDkCkPTS6zzZlJsacdo#J ze;nIslk_LG`tsRdYWp95sZy(6NJ6jk{ARKkf=|Ww@8EBnTA{!{jaKGgf13TzaLXEp zi!93!79|OZVAN#Df?S`DBp%#-CX}{!u znIfDw-z%U-E7ccDE2#A)-qikE4?cM$QljE=4-<8w4mc)FuIwlwaQ6u@<8+;goLIVq z+0;bv$s{y>$BDGYR`+_d5Z$F4z zmP(6#dl{9A7YCxa3+Cb?@F!IMz@Vj_mVee;*D29Zn=(^iC%iliD9gOekpy|!fEyMyBuIg{YMv~u%gYzRQ>=7MS$Tw7D`ldQ z63VpWbT-d>5s{Zz!Kmx6n?J(sikE$O;*h$2-XWqkgL4p>iWIEvnFIv`6l?MAzc(*m zz53K}22N_N{yUUOi6z8}71g%JtGm6G@Pa@$g_{s}AFlibMRf%x7A2J_uu;&*bsXcj zM+Yg;O0huonf2nrT4H(pOvL4O7`7IxwqcUC6{qRk)Qe+RncTGkI&dZriI`{yXKrCi zkN~t@xGlscrtjSjLLVJp`P9&4!2NR-`d}r}2RAo2FQFFXGMt>e{@UA0r{8PtLH+i} z{Uaf6Z{uCH+f{{6ZBoFfU}BQ7s-b|L&=$8+xReyiWE3!6;M-(Z^(jV`}Ut}u~cT|8Lb*eu}W5jafIYWG-($hki-^ECHa8>`Go5- zlsKaH%vX^TIiluqXgBHx7{GtOkFJoXuD<%>@rXPk=i|t4r_<^DdCq||ZID@(DLr7e zY+~D8hL4CHneIm9E{$zl$4QdJ(%#7MtvYJQv9e8_ViIU>=1A}MTj05Ig=gTa?V$zH z&5+u)(N&;b=mCnU4kfeAKMT00c2~Sv^c1R>E>^sX)D$;!ua!oLzFa1j)s7~!B9rq~ zX|rvoDe;VC7wZu@9Pu7oyN1dRhVYlN4&e0S`K81sWF@1s)iq~ zNEJe=$d#3KCP>!lSqTASmC};HU9<}yfYI7;clZ)yDqs7^_J@kbq+zI>H|B|>RzE_y z*=&ugyBFruM>wdt9_Bi-HXi--t#cJPSE|nU(&}VFx-Ig4b?bAIMoZ;O`!c1=tOQuh z5L6wGt`Z^ubmf%x zopsXkm9~h3V3W7azV{gqBA-GP&dZ7eFXE}P7=Vc5>{9zJ+0jZwJ6B@`z}ItCepkj5 zL8|^bJ$w1`0XWly{C4>Y_-hChJv4gXdkbs9%d%DZ%v1B^!AhXR< zb)<$b8Yu6`U5`=A{bglI7NMO1w6l#8Mb}IC@b>R{SzWra|10RPAgMC^b9{iBRRmi@ zd3{|%LH!0q<$-b7aA4A6D+xWfIMsroC@|Z2!xT_9+wJ}O`OVGE^LO`o&Zl9l1&%;V zA!=BE&pGuR0`A}Cz}&hHE;u%VuVwasij zZah1{cmGp%_q=T+XB@zNMQ~|U_)>(98tFP2ha3c4p(4H9CUD~-4Z(6reuOB6cK666 z)e_K_Zg@B>tl%KP%Z2D#P?3WV5FkrBzufs?KxTEZ8U`uy{GXSd*&XSG{0oyS$t1`h zXXcrQE9xProR!5}ugvP0V^o5*j^7@v^K7qke!k+qf=Mz6zWldt@ofH^W}ZEZbN|2I zb~E%i@;J_WTUTqB%ieC4Wslt*Kc0_9qdj*#+4(xhQ7iOX-|@cw?1uZFJihHA-Tvig zb2>?GF!F9FFZR5MDkP1{Y%*tnQ8KNvY$8W< z{uvzZL4YG)o@7-!ahlsf8U2&epH})1vwRTcBO;(@=F7i6TGmZ=Rm_Us*4L9Uj+31_vhzl96G?E2G`F|k2)JwJdOAa%;n<4_8M7r@yP?rZZA#Z zY=mbv8>jSbmwx|{GZ;i^k;Iev9%q!5<8huRnqq5#KTfge0S;fyadVPcnM87vc$%nf zxU(;z8$XoLWt3<1N}xchN(TH>bYd^*4)7@`GwF@==?BZnY&OgCbfEulHkxZjGZZ<{ zuzbz=i(K#*^c#HlcyNOhA22YV#J%_TUcUN<@=Eg>c_Vp=ypVh)39Q;Rd!xDll|-yW zrMB{<_*>6AyH%M-c*NZyK2w#fhRZb?4_CvTK~iQjN;W>|`;QjSsRW;#MTMSPRV+2- z6h&`qjs7CozZboNn2@+MRq#*KXfWvGHPXzXMxHUxDi_^-=yG{U!;`G&ON8^3sDN?^ z?9{Uwjb>FoP%DQOMzr)%(ISgMy4%})_~x4*erReTYK0h8XoZ-S#7cIta#CUyM5)e% z@w@evs>+LKKvv!5;=y7u?|XG^Hkk4GfNISeu=#!V|4Y-B}P_!JJdii<<4HTxJy^SM~b{(Iz&t1`LO%6ZAy zF5(g9iQVP9f4wFvV40Lrg;oe#JqfIiG|!#Yg)p@ulb;SRH!HH*DO*ip)h8p$7OV(O ztR^GMtd!UEKBtXU#AY>4iJa5jqB(uBwoO@V^?GRmtg>=em@jFl;k-`-yb)#KCz{5v z;)oT6=RvZHC&WPa*vAo%vN$W-)d!A$PTStWHqUZtIvOY^#c-EAvamU zD6qnsb>gfzu!0FZ2x@ip^b|a9Dr^j}v-K4$SUepu(vqxj$yU=iW2u z0TxCJ24DYnD~nj=WHp~uy|s^DVpw@2ORXf%%3<-a3a#qh@CgMPqIRcbf z8I@R}xF~5&7Obr;P|>JRD=RMIB*L1;3$KqBSm|?dwT8c+uy%E|yt-Ul`+!jzMMYlD z<`g%sVATkDrOb42Fr6lN#>{G-M3wJu0(ug-J%!nj6#{d$@c%oKX8QBzQxoup* zevgoQoA=&0D}P*R!g1BIy63EpEM#=7Ru^JLQbcvZM;3E}o`ed)-Kxsv)l68Fey_)7 zuo{ciq~xEF+D~5HVCy4TRb*`AG zTNROn1aQ&gM77n7e?qMo4TY^Fs;x#e*>DL`TP=q> z!>es#qans0we{3K59ujxP{TMBh`}m?6>9v_v)Y^RKvc|wWL%b2yi40{%CMJb*s+y` z47#M8`Bu4F-RQO7jFlGE?(*}mUVQ^5#J5tYYptGmQh^mktUzT87O0R_loldmV@a%( z?E=L`oENsb`$?xLs9=Q&h+M=fvMUlAEovndG;!G+2rFfS)gXDA%{UpB7Tc_;JJf8s zVyt}Ju*%AqS2!l+!ZN2V950F8BF4sgJmpsrR~o+6pl#K%X=k9zRYA)Yl@`v*uvp5h zkZ`#IRnzLkz^uZMJr)N}S_DD`@vLn5;z=-z`8g;K(ner4)7`LI4ZN6@Y_PPfW`N=F za+|_dOJ)nKrf$c!@2Mf6qoGqIe8WmLCo3yQ5W>o*)EVKwgtqMEF?}~r4kF5Q+_b7o z_8Y1Ae*2cg)RwFFSgxEEVpbuQS$!K?Y1=}zpd`hhU$v`=xwNd#*b0*%zhjVG7eP(fxF?dAzEv5ws}bsA(FZdA zjNZsJm#|_r(!GI>D{GPXcLO8Kp&u-Ux?FWPpSSPxz zXH-_xQ%+zdFIs5n6vN52D}>@ANw0+h8fFY+jvkL%VLSbRtkAhqHf&kVif+%_U55b| zx(CjRhPE(GH3bzKk6`s5SQRjmjIqqQ=$z1}>|CEdfGqNWbh&!hTCUu^!gx2ys@zB}6c4leLNs5 zu#pwmtoOs2J=NWH=+)f0)mD=@NxfR6$3e&O=bzbXD!ma*h1wqRTO`v0Es|DyMD?sp zvgky?%hiil3KeXxEIhCr)%8~EUPDl=BCL zb5vk{?PgYJo>`NrpkrutX<+ewx@H@8`-8eq$Ghu++o*+Vp;ev&*YAsLp)-QQg{*o- zQ7{&)bXYMmo^;*H)$6fM32N7#+Y7WIUE|ggQaLM%N?Bv+Wnq{%%KUEDaZwmB^5|ofZkA&r-Fld*^PWa(#7zJ2w{PkYv2_wetj=74p#cxVUj!Usp%9!@xmJQ4aPbs~IndtkuzERh;mv6}HLHp(46>+e?f!Da4 z)lDI1MUNbgGPjIlOgaLZ(>M!jkRAn>H(RM2(yGUtl`9;@>d$P2>P6&elzol9f0Q@d z79|^Lg?p`)%VcEU>bY%ZVG6%hXv-WWyF(`5U)}l@*R+g_;6QEVeSaOYC&f zVw#|n#gSGf#XY3L%$yYhs~nMsf-Are@D3Nb3SvVmnYAX8avV4;$D`}RVz zx>{SE*&ImUJwb7im9k#dT1A1XsYuXnmBMYR-*8y5P*t$9`9^9KT?Nu+ZnU!CT6Ck8 ztZ49}CgV0b!e(VNqFOzLl_sM#R8~Jk??BM%Dg%eG%GGMlR^3gqsuS$4Ov>M05f!XB zM)kQ_8I{!Su6joYR|eHvIuI;v4H^}!hzeF(TqM9krW_nJts;c5C^o{drEwdYxxc4A z(BS5@4KlvPszDW6aglFrk?r4a(+-=DY?NIQm34?Mct>Pksz<+<<)KB0wTm%bO!$$Y zwD{>3s~4PrO5$5}gvu>Z6gi{aQLz;UmW?YbEjT>r%qsS3_8j2@wbBzL1Pe}9fLM3K zSpkc+rWRL`lx9VEZ+)oR>yK4lcJH-#dE@Nli;aruLuifphAv#!72p^ zfs`GMtCJ{`I;cd}jy6h)UT zSYh6?B14h*z_(H;=CjTPTJ6}}w}R=Lt@z0;#7eQWUt^nL^a!M~mn9o<%UWH8)NOMs zLF${a++@|az>2f%ij~TBF{hzqpZg~VrZyV){TP-;v9!C1o>sNnxlg~4xVgFc?%k(^ z2DXO*<^vi0Kto<2kP5AQDz^HySvAWGIiC~7MJsMt0ZF7NJS&n_XP2zd5~N&bMGD*z zED*J-)3AymP?(~<9dAXWS@Clb3oArj3IuJ|z$$T8Xk0Cq3v@%|z_YUEh+$=N_JMg> zOfIxa_)f7G-tBcdo#F64@?O+F{UgYpK!(^jp!y}N-`>4*SL;9*#sXDnMNqoSy0E+z zt243Ms06EoS7UI+6|A_IsYSg$sTNf6aRw{fU`<8JqBV#+nbT`pK^EWB@PsMavUQ$^ zR@@-(YDA9QD3Ci0tndbbb+g?659B~4R&u9%|Cr!x@)b%CWVITRVU%(1fz3OM6A7$- z^~s%2)T+5;N!%Q$mylY;pmI=Rb*fe?u*xb5bHU5%0kfKwRvIEsjV{_&wi!mOGRBYP zsM+f(Bo1mBy-zdDX&DTx4y_x-QmjB`TU*+4v=)CT1iwK<)!i5Cq`aV`G1Y&Gv zZ1?XUZ+@zQ8nkY)`baid3Z-uCiOvYyp7aSj-pEDQ6R$yf{J1tiq-Jwa4{*#Nrg;cQOBK_0~3X`&`9XqUzN|H%* zgz4KNW)%i#p_MIIMx`l|dV@7XsX~#aer{1K*AHp0Mk(-@S8(1{SaaE1$~^E9u_C21Fu;3+$r_b-mM}5l&-0 z1{cn}6EK9WY}UFyVx?!D!wOLzOfNpVzGb`PA4nseZY$!dYwp5D`ZV{Tmrgf+zKgSd(R{!hWUQ!T-fiM6kYOqjdkz}Lp>aI`_b@U`XQ|{nN ziYE{^q9Ax3lkt&~G!|X>t=jU>1Tqw|Ntp&Tt?QYFbzHh%s}8Qnk(tO8BV3{zR}ovK z-K^Jhm@RBKuu5y)sqsw9-Y1NPG~M`MI;V*-UF#d89Y_nxG<;>}E6Yy+s>*L29S!S; z@zWv~B9olGa3v+uz+!_wQII|%8U6vbgs)y73>wCPK0huzLTqi_M&xgTY^741Id?Cr Vw-nuebjbh!002ovPDHLkV1mL?sY(C< literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/mod_logo.png b/1.20.4/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6715625ac40927c660208cd97c0aba641822edb8 GIT binary patch literal 9349 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 myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.20.4/Fabric/src/main/resources/fabric.mod.json b/1.20.4/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..e48b691 --- /dev/null +++ b/1.20.4/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,47 @@ +{ + "schemaVersion": 1, + "id": "${modId}", + "version": "${modVersion}", + + "name": "${modName}", + "description": "${modDescription}", + + "authors": [ + "${modAuthor}" + ], + + "contact": { + "homepage": "${modPageUrl}", + "issues": "${modIssueUrl}", + "sources": "${modPageUrl}" + }, + + "license": "${modLicense}", + "icon": "mod_logo.png", + + "environment": "${modFabricEnvironment}", + + "entrypoints": { + "main": [ + "${mainEntryPoint}" + ], + "client": [ + "${clientEntryPoint}" + ], + "jei_mod_plugin": [ + "${modGroup}.integration.jei.VisualWorkbenchJEIPlugin" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.20.4/Forge/build.gradle b/1.20.4/Forge/build.gradle new file mode 100644 index 0000000..170d164 --- /dev/null +++ b/1.20.4/Forge/build.gradle @@ -0,0 +1,32 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Just Enough Items + compileOnly libs.jeiapi.common + runtimeOnly fg.deobf(libs.jei.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java new file mode 100644 index 0000000..5a938a2 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java @@ -0,0 +1,19 @@ +package fuzs.visualworkbench; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.data.v2.core.DataProviderHelper; +import fuzs.visualworkbench.data.ModBlockTagsProvider; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(VisualWorkbench.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class VisualWorkbenchForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbench::new); + DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModBlockTagsProvider::new); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java new file mode 100644 index 0000000..1e3d306 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.visualworkbench.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.visualworkbench.VisualWorkbench; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = VisualWorkbench.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class VisualWorkbenchForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbenchClient::new); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..bd78e35 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.visualworkbench.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.20.4/Forge/src/main/resources/META-INF/mods.toml b/1.20.4/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.20.4/Forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,40 @@ +modLoader = "javafml" +loaderVersion = "[${minFMLVersion},)" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[dependencies.${ modId }]] +modId = "forge" +mandatory = true +versionRange = "[${minForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.20.4/NeoForge/build.gradle b/1.20.4/NeoForge/build.gradle new file mode 100644 index 0000000..170d164 --- /dev/null +++ b/1.20.4/NeoForge/build.gradle @@ -0,0 +1,32 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Just Enough Items + compileOnly libs.jeiapi.common + runtimeOnly fg.deobf(libs.jei.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java new file mode 100644 index 0000000..5a938a2 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java @@ -0,0 +1,19 @@ +package fuzs.visualworkbench; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.data.v2.core.DataProviderHelper; +import fuzs.visualworkbench.data.ModBlockTagsProvider; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(VisualWorkbench.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class VisualWorkbenchForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbench::new); + DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModBlockTagsProvider::new); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java new file mode 100644 index 0000000..1e3d306 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.visualworkbench.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.visualworkbench.VisualWorkbench; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = VisualWorkbench.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class VisualWorkbenchForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbenchClient::new); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..bd78e35 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.visualworkbench.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,40 @@ +modLoader = "javafml" +loaderVersion = "[${minFMLVersion},)" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[dependencies.${ modId }]] +modId = "forge" +mandatory = true +versionRange = "[${minForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.20.4/build.gradle b/1.20.4/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.20.4/build.gradle @@ -0,0 +1,12 @@ +plugins { + alias libs.plugins.loom apply false + alias libs.plugins.quiltflower apply false + alias libs.plugins.forgegradle apply false + alias libs.plugins.mixin apply false + alias libs.plugins.librarian apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties new file mode 100755 index 0000000..63e4adb --- /dev/null +++ b/1.20.4/gradle.properties @@ -0,0 +1,37 @@ +# 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 +org.gradle.parallel=true +copyBuildJar=true + +# Mod Attributes +modId=visualworkbench +modName=Visual Workbench +modVersion=8.0.0 +modAuthor=Fuzs +modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/visualworkbench +modIssueUrl=https://github.com/Fuzss/visualworkbench/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/visualworkbench.json +modMavenGroup=fuzs.visualworkbench +# "MATCH_VERSION" for a mod required on both sides, "IGNORE_SERVER_VERSION" for a server only mod, "IGNORE_ALL_VERSION" for a client only mod +modForgeDisplayTest=MATCH_VERSION +# "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod +modFabricEnvironment=* + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=500273 +projectModrinthId=kfqD1JRw + +dependenciesVersionCatalog=1.20.1-v25 +dependenciesPuzzlesLibVersion=8.1.11 +dependenciesMinPuzzlesLibVersion=8.1.11 +dependenciesRequiredForgeCurseForge=puzzles-lib +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +#dependenciesEmbeddedFabricCurseForge=cardinal-components +#dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/1.20.4/gradle/wrapper/gradle-wrapper.jar b/1.20.4/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/1.20.4/gradle/wrapper/gradle-wrapper.properties b/1.20.4/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37aef8d --- /dev/null +++ b/1.20.4/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/1.20.4/gradlew b/1.20.4/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.20.4/gradlew @@ -0,0 +1,244 @@ +#!/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 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/HEAD/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 +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 + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +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 ;; #( + 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 + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + 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 +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +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" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + 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 + # 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 +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 \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# 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/1.20.4/gradlew.bat b/1.20.4/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.20.4/gradlew.bat @@ -0,0 +1,92 @@ +@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 +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +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="-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% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +: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 %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.20.4/settings.gradle b/1.20.4/settings.gradle new file mode 100644 index 0000000..697dd5f --- /dev/null +++ b/1.20.4/settings.gradle @@ -0,0 +1,38 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'Sponge' + url = 'https://repo.spongepowered.org/repository/maven-public/' + } + maven { + name = 'Quilt' + url = 'https://maven.quiltmc.org/repository/release' + } + maven { + name = 'Minecraft Forge' + url = 'https://maven.minecraftforge.net/' + } + } +} + +dependencyResolutionManagement { + repositories { + maven { + name = "Fuzs Mod Resources" + url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" + } + } + versionCatalogs { + libs { + from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") + } + } +} + +rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" +include("Common", "Fabric", "Forge") diff --git a/1.20/.idea/scopes/Fabric_sources.xml b/1.20/.idea/scopes/Fabric_sources.xml deleted file mode 100644 index 0448412..0000000 --- a/1.20/.idea/scopes/Fabric_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/1.20/.idea/scopes/Forge_sources.xml b/1.20/.idea/scopes/Forge_sources.xml deleted file mode 100644 index 7b5f24d..0000000 --- a/1.20/.idea/scopes/Forge_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file From 08cec854afaf443fdc644cc6fbf8ef6537eac835 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:37:15 +0100 Subject: [PATCH 02/16] experimental 1.20.4 port --- 1.20.4/CHANGELOG.md | 10 +- 1.20.4/Common/build.gradle | 10 +- .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../50b16d832771f8a8317f4d1b88c5121208c8c4f9 | 2 + .../assets/visualworkbench/lang/en_us.json | 3 + .../tags/blocks/unaltered_workbenches.json | 6 + .../fuzs/visualworkbench/VisualWorkbench.java | 12 +- .../client/VisualWorkbenchClient.java | 23 ++- .../client/handler/BlockModelHandler.java | 76 +++++++ .../CraftingTableBlockEntityRenderer.java | 93 +++++++++ .../WorkbenchBlockEntityRenderer.java | 96 --------- .../visualworkbench/config/ServerConfig.java | 9 + .../core/CommonAbstractions.java | 17 -- .../data/ModBlockTagsProvider.java | 4 +- .../data/client/DynamicModelProvider.java | 17 +- .../data/client/ModLanguageProvider.java | 17 ++ ...ndler.java => BlockConversionHandler.java} | 46 +++-- .../visualworkbench/init/ModRegistry.java | 21 +- .../jei/VisualWorkbenchJEIPlugin.java | 48 ++--- .../BlockEntityTypeBuilderAccessor.java | 17 -- .../mixin/accessor/CraftingMenuAccessor.java | 27 --- .../fuzs/visualworkbench/util/MathHelper.java | 9 - .../world/inventory/VisualCraftingMenu.java | 108 +++++----- .../inventory/VisualResultContainer.java | 30 +++ ...a => CraftingTableWithInventoryBlock.java} | 66 +++---- .../entity/ContainerSerializationHelper.java | 119 ++++++++++- .../CraftingTableAnimationController.java | 98 +++++++++ .../entity/CraftingTableBlockEntity.java | 136 +++++++++++++ .../VisualCraftingTableBlockEntity.java | 187 ------------------ .../main/resources/architectury.common.json | 3 + .../src/main/resources/common.mixins.json | 13 ++ 1.20.4/Common/src/main/resources/pack.mcmeta | 4 +- .../resources/visualworkbench.accesswidener | 11 ++ .../visualworkbench.common.mixins.json | 17 -- 1.20.4/Fabric/build.gradle | 16 +- .../{ => fabric}/VisualWorkbenchFabric.java | 3 +- .../client/VisualWorkbenchFabricClient.java | 3 +- .../mixin/ModMixinConfigPlugin.java | 47 ----- .../src/main/resources/fabric.mixins.json | 14 ++ .../Fabric/src/main/resources/fabric.mod.json | 5 +- 1.20.4/Forge/build.gradle | 30 +-- 1.20.4/Forge/gradle.properties | 1 + .../{ => forge}/VisualWorkbenchForge.java | 6 +- .../client/VisualWorkbenchForgeClient.java | 3 +- .../mixin/ModMixinConfigPlugin.java | 47 ----- .../src/main/resources/META-INF/mods.toml | 13 +- .../src/main/resources/forge.mixins.json | 14 ++ 1.20.4/NeoForge/build.gradle | 30 +-- 1.20.4/NeoForge/gradle.properties | 1 + .../visualworkbench/VisualWorkbenchForge.java | 19 -- .../mixin/ModMixinConfigPlugin.java | 47 ----- .../neoforge/VisualWorkbenchNeoForge.java | 21 ++ .../VisualWorkbenchNeoForgeClient.java} | 13 +- .../src/main/resources/META-INF/mods.toml | 15 +- .../src/main/resources/neoforge.mixins.json | 13 ++ 1.20.4/build.gradle | 11 +- 1.20.4/gradle.properties | 31 +-- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 1.20.4/settings.gradle | 37 +--- 59 files changed, 949 insertions(+), 850 deletions(-) create mode 100644 1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 create mode 100644 1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 create mode 100644 1.20.4/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json create mode 100644 1.20.4/Common/src/generated/resources/data/visualworkbench/tags/blocks/unaltered_workbenches.json create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java rename 1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/{OpenMenuHandler.java => BlockConversionHandler.java} (54%) delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java rename 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/{VisualCraftingTableBlock.java => CraftingTableWithInventoryBlock.java} (52%) create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java create mode 100644 1.20.4/Common/src/main/resources/architectury.common.json create mode 100644 1.20.4/Common/src/main/resources/common.mixins.json create mode 100644 1.20.4/Common/src/main/resources/visualworkbench.accesswidener delete mode 100644 1.20.4/Common/src/main/resources/visualworkbench.common.mixins.json rename 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/{ => fabric}/VisualWorkbenchFabric.java (78%) rename 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/{ => fabric}/client/VisualWorkbenchFabricClient.java (79%) delete mode 100644 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Fabric/src/main/resources/fabric.mixins.json create mode 100644 1.20.4/Forge/gradle.properties rename 1.20.4/Forge/src/main/java/fuzs/visualworkbench/{ => forge}/VisualWorkbenchForge.java (68%) rename 1.20.4/Forge/src/main/java/fuzs/visualworkbench/{ => forge}/client/VisualWorkbenchForgeClient.java (86%) delete mode 100644 1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Forge/src/main/resources/forge.mixins.json create mode 100644 1.20.4/NeoForge/gradle.properties delete mode 100644 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java delete mode 100644 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java rename 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/{client/VisualWorkbenchForgeClient.java => neoforge/client/VisualWorkbenchNeoForgeClient.java} (55%) create mode 100644 1.20.4/NeoForge/src/main/resources/neoforge.mixins.json diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index c7f9a93..c078143 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -1,9 +1,9 @@ # Changelog All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog]. +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [v8.0.0-1.20.1] - 2023-06-27 -- Ported to Minecraft 1.20.1 - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +## [v20.4.0-1.20.4] - 2024-01-24 +- Ported to Minecraft 1.20.4 +- Ported to NeoForge diff --git a/1.20.4/Common/build.gradle b/1.20.4/Common/build.gradle index 4ce2222..13b80d3 100644 --- a/1.20.4/Common/build.gradle +++ b/1.20.4/Common/build.gradle @@ -1,14 +1,10 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/common.gradle" dependencies { // Puzzles Lib modApi libs.puzzleslib.common - - // Just Enough Items - compileOnly libs.jeiapi.common } -// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 -tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { - it.targetNamespace = "named" +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).configureEach { + targetNamespace = "named" } diff --git a/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 new file mode 100644 index 0000000..c9c8c3d --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.20.4 2024-01-24T23:42:33.58688 Language (en_us) +df9da4d2378015f87d23586f120ab375074989f6 assets/visualworkbench/lang/en_us.json diff --git a/1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 b/1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 new file mode 100644 index 0000000..3bdc066 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 @@ -0,0 +1,2 @@ +// 1.20.4 2024-01-24T23:42:33.58585 Tags for minecraft:block mod id vanilla +d00da1153a305b41cd0709e40bbab70031f6f7fb data/visualworkbench/tags/blocks/unaltered_workbenches.json diff --git a/1.20.4/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json b/1.20.4/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json new file mode 100644 index 0000000..89746d3 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "container.invalidBlock": "Unable to open. Break and replace to use." +} \ No newline at end of file diff --git a/1.20.4/Common/src/generated/resources/data/visualworkbench/tags/blocks/unaltered_workbenches.json b/1.20.4/Common/src/generated/resources/data/visualworkbench/tags/blocks/unaltered_workbenches.json new file mode 100644 index 0000000..a9e9b4d --- /dev/null +++ b/1.20.4/Common/src/generated/resources/data/visualworkbench/tags/blocks/unaltered_workbenches.json @@ -0,0 +1,6 @@ +{ + "values": [ + "minecraft:smithing_table", + "minecraft:fletching_table" + ] +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java index d95d14d..1ae89c2 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java @@ -3,9 +3,12 @@ import fuzs.puzzleslib.api.config.v3.ConfigHolder; import fuzs.puzzleslib.api.core.v1.ModConstructor; import fuzs.puzzleslib.api.event.v1.RegistryEntryAddedCallback; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; import fuzs.puzzleslib.api.event.v1.server.TagsUpdatedCallback; import fuzs.visualworkbench.config.ClientConfig; -import fuzs.visualworkbench.handler.OpenMenuHandler; +import fuzs.visualworkbench.config.ServerConfig; +import fuzs.visualworkbench.handler.BlockConversionHandler; import fuzs.visualworkbench.init.ModRegistry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceLocation; @@ -17,7 +20,7 @@ public class VisualWorkbench implements ModConstructor { public static final String MOD_NAME = "Visual Workbench"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class).server(ServerConfig.class); @Override public void onConstructMod() { @@ -26,8 +29,9 @@ public void onConstructMod() { } private static void registerHandlers() { - RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK).register(OpenMenuHandler::onRegistryEntryAdded); - TagsUpdatedCallback.EVENT.register(OpenMenuHandler::onTagsUpdated); + RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK).register(BlockConversionHandler::onRegistryEntryAdded); + PlayerInteractEvents.USE_BLOCK.register(BlockConversionHandler::onUseBlock); + TagsUpdatedCallback.EVENT.register(EventPhase.FIRST, BlockConversionHandler::onTagsUpdated); } public static ResourceLocation id(String path) { diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java index 377e39a..502fdc0 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java @@ -2,26 +2,39 @@ import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; +import fuzs.puzzleslib.api.client.event.v1.ModelEvents; import fuzs.puzzleslib.api.core.v1.context.PackRepositorySourcesContext; +import fuzs.puzzleslib.api.event.v1.LoadCompleteCallback; import fuzs.puzzleslib.api.resources.v1.DynamicPackResources; import fuzs.puzzleslib.api.resources.v1.PackResourcesHelper; import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.client.renderer.blockentity.WorkbenchBlockEntityRenderer; +import fuzs.visualworkbench.client.handler.BlockModelHandler; +import fuzs.visualworkbench.client.renderer.blockentity.CraftingTableBlockEntityRenderer; import fuzs.visualworkbench.data.client.DynamicModelProvider; import fuzs.visualworkbench.init.ModRegistry; -import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.gui.screens.inventory.CraftingScreen; public class VisualWorkbenchClient implements ClientModConstructor { @Override - public void onClientSetup() { - MenuScreens.register(ModRegistry.CRAFTING_MENU_TYPE.get(), CraftingScreen::new); + public void onConstructMod() { + registerHandlers(); + } + + private static void registerHandlers() { + ModelEvents.MODIFY_UNBAKED_MODEL.register(BlockModelHandler::onModifyUnbakedModel); + LoadCompleteCallback.EVENT.register(BlockModelHandler::onLoadComplete); + } + + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { + context.registerMenuScreen(ModRegistry.CRAFTING_MENU_TYPE.value(), CraftingScreen::new); } @Override public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { - context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.get(), WorkbenchBlockEntityRenderer::new); + context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), CraftingTableBlockEntityRenderer::new); } @Override diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java new file mode 100644 index 0000000..8725d34 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java @@ -0,0 +1,76 @@ +package fuzs.visualworkbench.client.handler; + +import com.google.common.base.Suppliers; +import com.google.common.collect.Maps; +import fuzs.puzzleslib.api.client.core.v1.ClientAbstractions; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import net.minecraft.Util; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.Property; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class BlockModelHandler { + private static final Supplier> MODEL_LOCATIONS; + + static { + MODEL_LOCATIONS = Suppliers.memoize(() -> { + return BlockConversionHandler.BLOCK_CONVERSIONS.inverse().entrySet().stream().flatMap(entry -> { + return convertAllBlockStates(entry.getKey(), entry.getValue()).entrySet().stream(); + }).collect(Util.toMap()); + }); + } + + public static void onLoadComplete() { + // run a custom implementation here, the appropriate method in client mod constructor runs together with other mods, so we might miss some entries + for (Map.Entry entry : BlockConversionHandler.BLOCK_CONVERSIONS.entrySet()) { + RenderType renderType = ClientAbstractions.INSTANCE.getRenderType(entry.getKey()); + ClientAbstractions.INSTANCE.registerRenderType(entry.getValue(), renderType); + } + } + + public static EventResultHolder onModifyUnbakedModel(ResourceLocation modelLocation, Supplier unbakedModel, Function modelGetter, BiConsumer modelAdder) { + if (MODEL_LOCATIONS.get().containsKey(modelLocation)) { + return EventResultHolder.interrupt(modelGetter.apply(MODEL_LOCATIONS.get().get(modelLocation))); + } else { + return EventResultHolder.pass(); + } + } + + private static Map convertAllBlockStates(Block oldBlock, Block newBlock) { + Map modelLocations = Maps.newHashMap(); + for (BlockState oldBlockState : oldBlock.getStateDefinition().getPossibleStates()) { + BlockState newBlockState = convertBlockState(newBlock.getStateDefinition(), oldBlockState); + modelLocations.put(BlockModelShaper.stateToModelLocation(oldBlockState), BlockModelShaper.stateToModelLocation(newBlockState)); + } + return modelLocations; + } + + private static BlockState convertBlockState(StateDefinition newStateDefinition, BlockState oldBlockState) { + BlockState newBlockState = newStateDefinition.any(); + for (Map.Entry, Comparable> entry : oldBlockState.getValues().entrySet()) { + newBlockState = setBlockStateValue(entry.getKey(), entry.getValue(), newStateDefinition::getProperty, newBlockState); + } + return newBlockState; + } + + private static , V extends T> BlockState setBlockStateValue(Property oldProperty, Comparable oldValue, Function> propertyGetter, BlockState blockState) { + Property newProperty = propertyGetter.apply(oldProperty.getName()); + if (newProperty != null) { + return blockState.setValue((Property) newProperty, (V) oldValue); + } + return blockState; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java new file mode 100644 index 0000000..46d7983 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java @@ -0,0 +1,93 @@ +package fuzs.visualworkbench.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ClientConfig; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableAnimationController; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +public class CraftingTableBlockEntityRenderer implements BlockEntityRenderer { + private final ItemRenderer itemRenderer; + + public CraftingTableBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + this.itemRenderer = context.getItemRenderer(); + } + + @Override + public void render(CraftingTableBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { + // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above + packedLight = blockEntity.getLevel() != null ? LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : 15728880; + for (int i = 0; i < blockEntity.getContainerSize(); ++i) { + ItemStack itemStack = blockEntity.getItem(i); + if (!itemStack.isEmpty()) { + this.renderIngredientItem(blockEntity, partialTick, poseStack, multiBufferSource, packedLight, packedOverlay, i, itemStack); + } + } + ItemStack itemStack = blockEntity.getResultItems().get(0); + if (!itemStack.isEmpty()) { + this.renderResultItem(itemStack, blockEntity.getLevel(), blockEntity.getAnimationController().ticks + partialTick, poseStack, multiBufferSource, packedLight); + } + } + + private void renderIngredientItem(CraftingTableBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay, int i, ItemStack itemStack) { + poseStack.pushPose(); + if (VisualWorkbench.CONFIG.get(ClientConfig.class).flatRendering) { + this.setupFlatRenderer(blockEntity.getAnimationController(), partialTick, poseStack, itemStack, i); + } else { + this.setupFloatingRenderer(blockEntity.getAnimationController(), partialTick, poseStack, itemStack, i); + } + this.itemRenderer.renderStatic(itemStack, ItemDisplayContext.FIXED, packedLight, packedOverlay, poseStack, multiBufferSource, blockEntity.getLevel(), (int) blockEntity.getBlockPos().asLong() + i); + poseStack.popPose(); + } + + private void setupFloatingRenderer(CraftingTableAnimationController animationController, float partialTick, PoseStack poseStack, ItemStack itemStack, int index) { + // -0.0125 to 0.0125 + float shift = (float) Math.abs(((animationController.ticks + partialTick) * 50.0 + (index * 1000L)) % 5000L - 2500L) / 200000.0F; + BakedModel model = this.itemRenderer.getModel(itemStack, null, null, 0); + boolean blockItem = model.isGui3d(); + poseStack.translate(0.5, shift, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTick, animationController.currentAngle, animationController.nextAngle))); + poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, 1.09375, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); + float scale = blockItem ? 0.24F : 0.18F; + poseStack.scale(scale, scale, scale); + } + + private void setupFlatRenderer(CraftingTableAnimationController animationController, float partialTick, PoseStack poseStack, ItemStack itemStack, int index) { + BakedModel bakedModel = this.itemRenderer.getModel(itemStack, null, null, 0); + boolean gui3d = bakedModel.isGui3d(); + poseStack.translate(0.5, 0.0, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTick, animationController.currentAngle, animationController.nextAngle))); + poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, gui3d ? 1.0625 : 1.005, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); + poseStack.mulPose(Axis.XP.rotationDegrees(90.0F)); + poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F)); + float scale = gui3d ? 0.25F : 0.175F; + poseStack.scale(scale, scale, scale); + } + + private void renderResultItem(ItemStack itemStack, @Nullable Level level, float time, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { + if (!VisualWorkbench.CONFIG.get(ClientConfig.class).renderResult) return; + poseStack.pushPose(); + poseStack.translate(0.5F, 1.15F, 0.5F); + BakedModel model = this.itemRenderer.getModel(itemStack, level, null, 0); + float hoverOffset = Mth.sin(time / 10.0F) * 0.04F + 0.1F; + float modelYScale = model.getTransforms().getTransform(ItemDisplayContext.GROUND).scale.y(); + poseStack.translate(0.0, hoverOffset + 0.25F * modelYScale, 0.0); + poseStack.mulPose(Axis.YP.rotation(time / 20.0F)); + if (!model.isGui3d()) poseStack.scale(0.75F, 0.75F, 0.75F); + this.itemRenderer.render(itemStack, ItemDisplayContext.GROUND, false, poseStack, multiBufferSource, packedLight, OverlayTexture.NO_OVERLAY, model); + poseStack.popPose(); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java deleted file mode 100644 index 7227811..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/WorkbenchBlockEntityRenderer.java +++ /dev/null @@ -1,96 +0,0 @@ -package fuzs.visualworkbench.client.renderer.blockentity; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Axis; -import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.config.ClientConfig; -import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; -import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemDisplayContext; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import org.jetbrains.annotations.Nullable; - -public class WorkbenchBlockEntityRenderer implements BlockEntityRenderer { - private final ItemRenderer itemRenderer; - - public WorkbenchBlockEntityRenderer(BlockEntityRendererProvider.Context context) { - this.itemRenderer = context.getItemRenderer(); - } - - @Override - public void render(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { - // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above - combinedLightIn = blockEntity.getLevel() != null ? LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : 15728880; - for (int i = 0; i < blockEntity.getCraftSlots().getContainerSize(); ++i) { - ItemStack itemStack = blockEntity.getCraftSlots().getItem(i); - if (!itemStack.isEmpty()) { - this.renderIngredientItem(blockEntity, partialTicks, poseStack, bufferIn, combinedLightIn, combinedOverlayIn, i, itemStack); - } - } - if (VisualWorkbench.CONFIG.get(ClientConfig.class).renderResult && blockEntity.getResultSlots().getRecipeUsed() != null) { - ItemStack resultItem = blockEntity.getResultSlots().getRecipeUsed().getResultItem(Minecraft.getInstance().level.registryAccess()); - if (!resultItem.isEmpty()) { - this.renderResultItem(resultItem, blockEntity.getLevel(), blockEntity.ticks + partialTicks, poseStack, bufferIn, combinedLightIn); - } - } - } - - private void renderIngredientItem(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, int i, ItemStack itemStack) { - poseStack.pushPose(); - if (VisualWorkbench.CONFIG.get(ClientConfig.class).flatRendering) { - this.setupLayingRenderer(blockEntity, partialTicks, poseStack, itemStack, i); - } else { - this.setupFloatingRenderer(blockEntity, partialTicks, poseStack, itemStack, i); - } - this.itemRenderer.renderStatic(itemStack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, poseStack, bufferIn, blockEntity.getLevel(), (int) blockEntity.getBlockPos().asLong() + i); - poseStack.popPose(); - } - - private void setupFloatingRenderer(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, ItemStack itemStack, int index) { - // -0.0125 to 0.0125 - float shift = (float) Math.abs(((blockEntity.ticks + partialTicks) * 50.0 + (index * 1000L)) % 5000L - 2500L) / 200000.0F; - BakedModel model = this.itemRenderer.getModel(itemStack, null, null, 0); - boolean blockItem = model.isGui3d(); - poseStack.translate(0.5, shift, 0.5); - poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, blockEntity.currentAngle, blockEntity.nextAngle))); - poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, 1.09375, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); - float scale = blockItem ? 0.24F : 0.18F; - poseStack.scale(scale, scale, scale); - } - - private void setupLayingRenderer(VisualCraftingTableBlockEntity blockEntity, float partialTicks, PoseStack poseStack, ItemStack itemStack, int index) { - BakedModel model = this.itemRenderer.getModel(itemStack, null, null, 0); - boolean blockItem = model.isGui3d(); - poseStack.translate(0.5, 0.0, 0.5); - poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, blockEntity.currentAngle, blockEntity.nextAngle))); - poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, blockItem ? 1.0625 : 1.005, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); - poseStack.mulPose(Axis.XP.rotationDegrees(90.0F)); - poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F)); - float scale = blockItem ? 0.25F : 0.175F; - poseStack.scale(scale, scale, scale); - } - - private void renderResultItem(ItemStack stack, @Nullable Level worldIn, float time, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn) { - poseStack.pushPose(); - poseStack.translate(0.5F, 1.15F, 0.5F); - BakedModel model = this.itemRenderer.getModel(stack, worldIn, null, 0); - float hoverOffset = Mth.sin(time / 10.0F) * 0.04F + 0.1F; - float modelYScale = model.getTransforms().getTransform(ItemDisplayContext.GROUND).scale.y(); - poseStack.translate(0.0, hoverOffset + 0.25F * modelYScale, 0.0); - poseStack.mulPose(Axis.YP.rotation(time / 20.0F)); - if (!model.isGui3d()) { - poseStack.scale(0.75F, 0.75F, 0.75F); - } - this.itemRenderer.render(stack, ItemDisplayContext.GROUND, false, poseStack, bufferIn, combinedLightIn, OverlayTexture.NO_OVERLAY, model); - poseStack.popPose(); - } -} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java new file mode 100644 index 0000000..f9f8358 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java @@ -0,0 +1,9 @@ +package fuzs.visualworkbench.config; + +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; + +public class ServerConfig implements ConfigCore { + @Config(description = "Leftover vanilla crafting tables in a world become unusable until they are broken and replaced.") + public boolean disableVanillaWorkbench = true; +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java deleted file mode 100644 index 0c8813f..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/core/CommonAbstractions.java +++ /dev/null @@ -1,17 +0,0 @@ -package fuzs.visualworkbench.core; - -import fuzs.puzzleslib.api.core.v1.ServiceProviderHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.LevelReader; - -public interface CommonAbstractions { - CommonAbstractions INSTANCE = ServiceProviderHelper.load(CommonAbstractions.class); - - boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player); - - InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context); -} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java index b9fbc4d..6453f43 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java @@ -13,7 +13,7 @@ public ModBlockTagsProvider(DataProviderContext context) { } @Override - protected void addTags(HolderLookup.Provider provider) { - this.tag(ModRegistry.NON_VISUAL_WORKBENCHES_BLOCK_TAG).add(Blocks.SMITHING_TABLE, Blocks.FLETCHING_TABLE); + public void addTags(HolderLookup.Provider provider) { + this.tag(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG).add(Blocks.SMITHING_TABLE, Blocks.FLETCHING_TABLE); } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java index eeb4474..57aaff6 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java @@ -1,15 +1,15 @@ package fuzs.visualworkbench.data.client; -import fuzs.puzzlesaccessapi.api.client.data.v2.BlockModelBuilder; -import fuzs.puzzlesaccessapi.api.client.data.v2.ItemModelBuilder; import fuzs.puzzleslib.api.client.data.v2.AbstractModelProvider; import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; -import fuzs.visualworkbench.handler.OpenMenuHandler; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.blockstates.MultiVariantGenerator; import net.minecraft.data.models.blockstates.Variant; import net.minecraft.data.models.blockstates.VariantProperties; import net.minecraft.data.models.model.ModelLocationUtils; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; public class DynamicModelProvider extends AbstractModelProvider { @@ -19,18 +19,13 @@ public DynamicModelProvider(DataProviderContext context) { } @Override - public void addBlockModels(BlockModelBuilder builder) { + public void addBlockModels(BlockModelGenerators builder) { // dynamically generate a basic stone block model for every diagonal block so the model bakery logs no missing model // don't use an air model so the blocks remain visible ResourceLocation resourceLocation = ModelLocationUtils.getModelLocation(Blocks.STONE); - OpenMenuHandler.BLOCK_CONVERSIONS.values().forEach((block) -> { - builder.getBlockStateOutput().accept(MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, resourceLocation))); + BlockConversionHandler.BLOCK_CONVERSIONS.values().forEach((Block block) -> { + builder.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, resourceLocation))); builder.skipAutoItemBlock(block); }); } - - @Override - public void addItemModels(ItemModelBuilder builder) { - - } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..07595b1 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java @@ -0,0 +1,17 @@ +package fuzs.visualworkbench.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.visualworkbench.handler.BlockConversionHandler; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(BlockConversionHandler.INVALID_BLOCK_COMPONENT, "Unable to open. Break and replace to use."); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java similarity index 54% rename from 1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java rename to 1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java index 907997b..bf52e91 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/OpenMenuHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java @@ -3,37 +3,60 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import fuzs.puzzleslib.api.block.v1.BlockConversionHelper; -import fuzs.puzzleslib.api.init.v3.RegistryHelper; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.puzzleslib.api.init.v3.registry.RegistryHelper; import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ServerConfig; import fuzs.visualworkbench.init.ModRegistry; -import fuzs.visualworkbench.world.level.block.VisualCraftingTableBlock; +import fuzs.visualworkbench.world.level.block.CraftingTableWithInventoryBlock; +import net.minecraft.ChatFormatting; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.CraftingTableBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Supplier; -public class OpenMenuHandler { +public class BlockConversionHandler { + public static final Component INVALID_BLOCK_COMPONENT = Component.translatable("container.invalidBlock"); public static final BiMap BLOCK_CONVERSIONS = HashBiMap.create(); - public static void onRegistryEntryAdded(Registry registry, ResourceLocation id, Block entry, BiConsumer> registrar) { - if (entry instanceof CraftingTableBlock) { + public static void onRegistryEntryAdded(Registry registry, ResourceLocation id, Block block, BiConsumer> registrar) { + if (block instanceof CraftingTableBlock) { ResourceLocation resourceLocation = VisualWorkbench.id(id.getNamespace() + "/" + id.getPath()); registrar.accept(resourceLocation, () -> { - BLOCK_CONVERSIONS.put(entry, new VisualCraftingTableBlock(entry)); - return BLOCK_CONVERSIONS.get(entry); + Block newBlock = new CraftingTableWithInventoryBlock(block); + BLOCK_CONVERSIONS.put(block, newBlock); + return newBlock; }); } } + public static EventResultHolder onUseBlock(Player player, Level level, InteractionHand interactionHand, BlockHitResult hitResult) { + if (!VisualWorkbench.CONFIG.get(ServerConfig.class).disableVanillaWorkbench) return EventResultHolder.pass(); + BlockState blockState = level.getBlockState(hitResult.getBlockPos()); + if (BLOCK_CONVERSIONS.containsKey(blockState.getBlock()) && !blockState.is(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG)) { + player.displayClientMessage(Component.empty().append(INVALID_BLOCK_COMPONENT).withStyle(ChatFormatting.RED), true); + return EventResultHolder.interrupt(InteractionResult.sidedSuccess(level.isClientSide)); + } else { + return EventResultHolder.pass(); + } + } + public static void onTagsUpdated(RegistryAccess registryAccess, boolean client) { for (Map.Entry, Item> entry : BuiltInRegistries.ITEM.entrySet()) { if (entry.getValue() instanceof BlockItem blockItem) { @@ -46,26 +69,25 @@ public static void onTagsUpdated(RegistryAccess registryAccess, boolean client) } private static void setItemForBlock(ResourceLocation resourceLocation, BlockItem blockItem, Block block) { - if (BLOCK_CONVERSIONS.containsKey(block)) { + if (block instanceof CraftingTableBlock) { BlockConversionHelper.setItemForBlock(BLOCK_CONVERSIONS.get(block), blockItem); } } private static void setBlockForItem(BlockItem blockItem, Block block) { - BiMap conversions = BLOCK_CONVERSIONS; Block baseBlock; - Block diagonalBlock = conversions.get(block); + Block diagonalBlock = BLOCK_CONVERSIONS.get(block); if (diagonalBlock != null) { baseBlock = block; } else { - baseBlock = conversions.inverse().get(block); + baseBlock = BLOCK_CONVERSIONS.inverse().get(block); if (baseBlock != null) { diagonalBlock = block; } else { return; } } - if (RegistryHelper.is(ModRegistry.NON_VISUAL_WORKBENCHES_BLOCK_TAG, baseBlock)) { + if (RegistryHelper.is(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG, baseBlock)) { BlockConversionHelper.setBlockForItem(blockItem, baseBlock); } else { BlockConversionHelper.setBlockForItem(blockItem, diagonalBlock); diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java index 92340cb..fa484be 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java @@ -1,29 +1,28 @@ package fuzs.visualworkbench.init; -import fuzs.puzzleslib.api.init.v2.RegistryManager; -import fuzs.puzzleslib.api.init.v2.RegistryReference; +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; import fuzs.puzzleslib.api.init.v3.tags.BoundTagFactory; import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.handler.OpenMenuHandler; -import fuzs.visualworkbench.mixin.accessor.BlockEntityTypeBuilderAccessor; +import fuzs.visualworkbench.handler.BlockConversionHandler; import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; -import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.core.Holder; import net.minecraft.tags.TagKey; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; public class ModRegistry { - static final RegistryManager REGISTRY = RegistryManager.instant(VisualWorkbench.MOD_ID); - public static final RegistryReference> CRAFTING_TABLE_BLOCK_ENTITY = REGISTRY.registerBlockEntityType("crafting_table", () -> { - BlockEntityType.Builder builder = BlockEntityType.Builder.of(VisualCraftingTableBlockEntity::new); - BlockEntityTypeBuilderAccessor.class.cast(builder).visualworkbench$setValidBlocks(OpenMenuHandler.BLOCK_CONVERSIONS.values()); + static final RegistryManager REGISTRY = RegistryManager.from(VisualWorkbench.MOD_ID); + public static final Holder.Reference> CRAFTING_TABLE_BLOCK_ENTITY = REGISTRY.registerBlockEntityType("crafting_table", () -> { + BlockEntityType.Builder builder = BlockEntityType.Builder.of(CraftingTableBlockEntity::new); + builder.validBlocks = BlockConversionHandler.BLOCK_CONVERSIONS.values(); return builder; }); - public static final RegistryReference> CRAFTING_MENU_TYPE = REGISTRY.registerMenuType("crafting", () -> VisualCraftingMenu::new); + public static final Holder.Reference> CRAFTING_MENU_TYPE = REGISTRY.registerMenuType("crafting", () -> VisualCraftingMenu::new); static final BoundTagFactory TAGS = BoundTagFactory.make(VisualWorkbench.MOD_ID); - public static final TagKey NON_VISUAL_WORKBENCHES_BLOCK_TAG = TAGS.registerBlockTag("non_visual_workbenches"); + public static final TagKey UNALTERED_WORKBENCHES_BLOCK_TAG = TAGS.registerBlockTag("unaltered_workbenches"); public static void touch() { diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java index fe4a7ce..063aa38 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java @@ -1,24 +1,24 @@ -package fuzs.visualworkbench.integration.jei; - -import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.init.ModRegistry; -import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; -import mezz.jei.api.IModPlugin; -import mezz.jei.api.JeiPlugin; -import mezz.jei.api.constants.RecipeTypes; -import mezz.jei.api.registration.IRecipeTransferRegistration; -import net.minecraft.resources.ResourceLocation; - -@JeiPlugin -public class VisualWorkbenchJEIPlugin implements IModPlugin { - - @Override - public ResourceLocation getPluginUid() { - return new ResourceLocation(VisualWorkbench.MOD_ID, "crafting"); - } - - @Override - public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { - registration.addRecipeTransferHandler(VisualCraftingMenu.class, ModRegistry.CRAFTING_MENU_TYPE.get(), RecipeTypes.CRAFTING, 1, 9, 10, 36); - } -} +//package fuzs.visualworkbench.integration.jei; +// +//import fuzs.visualworkbench.VisualWorkbench; +//import fuzs.visualworkbench.init.ModRegistry; +//import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +//import mezz.jei.api.IModPlugin; +//import mezz.jei.api.JeiPlugin; +//import mezz.jei.api.constants.RecipeTypes; +//import mezz.jei.api.registration.IRecipeTransferRegistration; +//import net.minecraft.resources.ResourceLocation; +// +//@JeiPlugin +//public class VisualWorkbenchJEIPlugin implements IModPlugin { +// +// @Override +// public ResourceLocation getPluginUid() { +// return new ResourceLocation(VisualWorkbench.MOD_ID, "crafting"); +// } +// +// @Override +// public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { +// registration.addRecipeTransferHandler(VisualCraftingMenu.class, ModRegistry.CRAFTING_MENU_TYPE.get(), RecipeTypes.CRAFTING, 1, 9, 10, 36); +// } +//} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java deleted file mode 100644 index 08f0561..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/BlockEntityTypeBuilderAccessor.java +++ /dev/null @@ -1,17 +0,0 @@ -package fuzs.visualworkbench.mixin.accessor; - -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.gen.Accessor; - -import java.util.Set; - -@Mixin(BlockEntityType.Builder.class) -public interface BlockEntityTypeBuilderAccessor { - - @Accessor("validBlocks") - @Mutable - void visualworkbench$setValidBlocks(Set validBlocks); -} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java deleted file mode 100644 index be55441..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/mixin/accessor/CraftingMenuAccessor.java +++ /dev/null @@ -1,27 +0,0 @@ -package fuzs.visualworkbench.mixin.accessor; - -import net.minecraft.world.inventory.CraftingContainer; -import net.minecraft.world.inventory.CraftingMenu; -import net.minecraft.world.inventory.ResultContainer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(CraftingMenu.class) -public interface CraftingMenuAccessor { - - @Mutable - @Accessor("craftSlots") - void visualworkbench$setCraftSlots(CraftingContainer craftSlots); - - @Mutable - @Accessor("resultSlots") - void visualworkbench$setResultSlots(ResultContainer resultSlots); - - @Mutable - @Accessor("craftSlots") - CraftingContainer visualworkbench$getCraftSlots(); - - @Accessor("resultSlots") - ResultContainer visualworkbench$getResultSlots(); -} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java deleted file mode 100644 index 4539b89..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/util/MathHelper.java +++ /dev/null @@ -1,9 +0,0 @@ -package fuzs.visualworkbench.util; - -public class MathHelper { - - public static float easeOutQuad(double t, float b, float c, double d) { - float z = (float) t / (float) d; - return -c * z * (z - 2.0F) + b; - } -} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java index 66f67c9..8b3c710 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -1,106 +1,106 @@ package fuzs.visualworkbench.world.inventory; import fuzs.visualworkbench.init.ModRegistry; -import fuzs.visualworkbench.mixin.accessor.CraftingMenuAccessor; -import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; -import net.minecraft.Util; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; +import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.*; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; public class VisualCraftingMenu extends CraftingMenu implements ContainerListener { - private final CraftingContainer craftSlots; - private final ResultContainer resultSlots; - @Nullable - private final VisualCraftingTableBlockEntity blockEntity; - private final ContainerLevelAccess access; + private final Container container; public VisualCraftingMenu(int id, Inventory inventory) { super(id, inventory); - this.craftSlots = ((CraftingMenuAccessor) this).visualworkbench$getCraftSlots(); - this.resultSlots = ((CraftingMenuAccessor) this).visualworkbench$getResultSlots(); - this.blockEntity = null; - this.access = ContainerLevelAccess.NULL; + this.container = new SimpleContainer(); } - public VisualCraftingMenu(int id, Inventory inventory, VisualCraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { + public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { super(id, inventory, access); - this.craftSlots = blockEntity.getCraftSlots(); - ((CraftingMenuAccessor) this).visualworkbench$setCraftSlots(this.craftSlots); - this.resultSlots = blockEntity.getResultSlots(); - ((CraftingMenuAccessor) this).visualworkbench$setResultSlots(this.resultSlots); - this.blockEntity = blockEntity; - this.access = access; - this.addSlots(inventory); + this.container = blockEntity; + this.craftSlots = new TransientCraftingContainer(this, 3, 3, blockEntity.getItems()); + this.resultSlots = new ResultContainer(); +// this.resultSlots = new VisualResultContainer(blockEntity); + this.setCraftingSlots(inventory.player); this.addSlotListener(this); } - private void addSlots(Inventory inventory) { - this.slots.set(0, Util.make(new ResultSlot(inventory.player, this.craftSlots, this.resultSlots, 0, 124, 35) { + private void setCraftingSlots(Player player) { +// for (int i = 0; i < 10; i++) { +// Slot slot = this.getSlot(i); +// if (slot instanceof ResultSlot resultSlot) { +// resultSlot.craftSlots = this.craftSlots; +// slot.container = this.resultSlots; +// } else if (slot.container instanceof TransientCraftingContainer) { +// slot.container = this.craftSlots; +// } +// } + + + // TODO don't replace slots, instead change containers + this.setSlot(0, new ResultSlot(player, this.craftSlots, this.resultSlots, 0, 124, 35) { @Override - public void set(ItemStack stack) { - // fast workbench makes this do nothing (via mixin), but in our case it is needed to avoid client desync - this.container.setItem(this.getContainerSlot(), stack); - this.setChanged(); + public void setChanged() { + // Update block entity. + this.container.setChanged(); } - }, slot -> slot.index = 0)); + }); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { int slotIndex = j + i * 3; - this.slots.set(slotIndex + 1, Util.make(new Slot(this.craftSlots, slotIndex, 30 + j * 18, 17 + i * 18), slot -> slot.index = slotIndex + 1)); + this.setSlot(slotIndex + 1, new Slot(this.craftSlots, slotIndex, 30 + j * 18, 17 + i * 18)); } } } + public Slot setSlot(int index, Slot slot) { + slot.index = index; + this.slots.set(index, slot); + return slot; + } + @Override public MenuType getType() { - return ModRegistry.CRAFTING_MENU_TYPE.get(); + return ModRegistry.CRAFTING_MENU_TYPE.value(); + } + + @Override + public void slotsChanged(Container container) { + super.slotsChanged(container); + this.access.execute((Level level, BlockPos blockPos) -> { + // Update block entity. + this.container.setChanged(); + }); } @Override public void slotChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, ItemStack itemStack) { - if (containerMenu == this) { - this.access.execute((Level level, BlockPos blockPos) -> { - if (dataSlotIndex >= 1 && dataSlotIndex < 10) { - this.slotsChanged(this.craftSlots); - } - }); + if (dataSlotIndex >= 1 && dataSlotIndex < 10) { + this.slotsChanged(this.craftSlots); } } @Override public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) { - + // NO-OP } @Override public boolean stillValid(Player player) { - Objects.requireNonNull(this.blockEntity, "block entity is null"); - return Container.stillValidBlockEntity(this.blockEntity, player); + return this.container.stillValid(player); } @Override public void removed(Player player) { - // copied from container base class - if (player instanceof ServerPlayer) { - ItemStack itemstack = this.getCarried(); - if (!itemstack.isEmpty()) { - if (player.isAlive() && !((ServerPlayer) player).hasDisconnected()) { - player.getInventory().placeItemBackInInventory(itemstack); - } else { - player.drop(itemstack, false); - } - this.setCarried(ItemStack.EMPTY); - } - } + // Prevent items from being cleared out of the container. + ContainerLevelAccess containerLevelAccess = this.access; + this.access = ContainerLevelAccess.NULL; + super.removed(player); + this.access = containerLevelAccess; } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java new file mode 100644 index 0000000..1d0d893 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java @@ -0,0 +1,30 @@ +package fuzs.visualworkbench.world.inventory; + +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ResultContainer; +import net.minecraft.world.item.ItemStack; + +public class VisualResultContainer extends ResultContainer { + private final Container container; + + public VisualResultContainer(CraftingTableBlockEntity container) { + this.container = container; + this.itemStacks = container.getResultItems(); + } + + @Override + public ItemStack removeItem(int slot, int amount) { + ItemStack result = ContainerHelper.removeItem(this.itemStacks, slot, amount); + if (!result.isEmpty()) this.container.setChanged(); + return result; + } + + @Override + public void setItem(int slot, ItemStack stack) { + super.setItem(slot, stack); + this.container.setChanged(); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java similarity index 52% rename from 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java rename to 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java index 732607b..69dc90d 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/VisualCraftingTableBlock.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java @@ -1,31 +1,32 @@ package fuzs.visualworkbench.world.level.block; -import fuzs.puzzleslib.api.block.v1.TickingBlockEntity; -import fuzs.puzzleslib.api.block.v1.TickingEntityBlock; +import com.mojang.serialization.MapCodec; +import fuzs.puzzleslib.api.block.v1.entity.TickingEntityBlock; import fuzs.visualworkbench.init.ModRegistry; -import fuzs.visualworkbench.world.level.block.entity.VisualCraftingTableBlockEntity; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.stats.Stats; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import org.jetbrains.annotations.Nullable; -public class VisualCraftingTableBlock extends BaseEntityBlock implements TickingEntityBlock { +import java.util.function.Predicate; + +public class CraftingTableWithInventoryBlock extends BaseEntityBlock implements TickingEntityBlock { private final Block block; - public VisualCraftingTableBlock(Block block) { - super(BlockBehaviour.Properties.copy(block).dropsLike(block)); + public CraftingTableWithInventoryBlock(Block block) { + super(BlockBehaviour.Properties.ofFullCopy(block).dropsLike(block)); this.block = block; } @@ -35,51 +36,48 @@ public String getDescriptionId() { } @Override - public RenderShape getRenderShape(BlockState state) { - return RenderShape.MODEL; + protected MapCodec codec() { + return null; } @Override - public boolean hasAnalogOutputSignal(BlockState blockState) { - return true; - } - - @Override - public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos blockPos) { - return level.getBlockEntity(blockPos) instanceof VisualCraftingTableBlockEntity crafterBlockEntity ? crafterBlockEntity.getRedstoneSignal() : 0; + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; } - @Nullable @Override - public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { - return new VisualCraftingTableBlockEntity(pos, state); + public BlockEntityType getBlockEntityType() { + return ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(); } @Override public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { if (level.isClientSide) { return InteractionResult.SUCCESS; - } else { - if (level.getBlockEntity(pos) instanceof VisualCraftingTableBlockEntity blockEntity) { - player.openMenu(blockEntity); - player.awardStat(Stats.INTERACT_WITH_CRAFTING_TABLE); - } - return InteractionResult.CONSUME; + } else if (level.getBlockEntity(pos) instanceof CraftingTableBlockEntity blockEntity) { + player.openMenu(blockEntity); + player.awardStat(Stats.INTERACT_WITH_CRAFTING_TABLE); } + return InteractionResult.CONSUME; } @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { - if (!state.is(newState.getBlock())) { - if (level.getBlockEntity(pos) instanceof VisualCraftingTableBlockEntity blockEntity) { - Containers.dropContents(level, pos, blockEntity.getCraftSlots()); - } - super.onRemove(state, level, pos, newState, movedByPiston); - } + Containers.dropContentsOnDestroy(state, newState, level, pos); + super.onRemove(state, level, pos, newState, movedByPiston); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState blockState) { + return true; } @Override - public BlockEntityType getBlockEntityType() { - return (BlockEntityType) ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.get(); + public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos blockPos) { + if (level.getBlockEntity(blockPos) instanceof CraftingTableBlockEntity blockEntity) { + return (int) blockEntity.getItems().stream().filter(Predicate.not(ItemStack::isEmpty)).count(); + } else { + return 0; + } } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java index 6c15f26..bff9ee2 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java @@ -1,20 +1,90 @@ package fuzs.visualworkbench.world.level.block.entity; +import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; import net.minecraft.world.item.ItemStack; -public class ContainerSerializationHelper { +import java.util.function.IntFunction; +import java.util.function.ObjIntConsumer; +/** + * An adjusted version of {@link ContainerHelper} that allows for using {@link Container} instead of {@link NonNullList}. + *

Also allows for changing the nbt key which is usually Items. + */ +@Deprecated +public final class ContainerSerializationHelper extends ContainerHelper { + public static final String TAG_ITEMS = "Items"; + + private ContainerSerializationHelper() { + + } + + /** + * Save items to a given tag, reading from a container. + * + * @param tag tag to save to + * @param container container to save + * @return the original tag + */ public static CompoundTag saveAllItems(CompoundTag tag, Container container) { return saveAllItems(tag, container, true); } + /** + * Save items to a given tag, reading from an item list. + * + * @param tagKey nbt tag key + * @param tag tag to save to + * @param items item list to save + * @return the original tag + */ + public static CompoundTag saveAllItems(String tagKey, CompoundTag tag, NonNullList items) { + return saveAllItems(tagKey, tag, items, true); + } + + /** + * Save items to a given tag, reading from a container. + * + * @param tag tag to save to + * @param container container to save + * @param saveEmpty save to tag if completely empty + * @return the original tag + */ public static CompoundTag saveAllItems(CompoundTag tag, Container container, boolean saveEmpty) { + return saveAllItems(TAG_ITEMS, tag, container.getContainerSize(), container::getItem, saveEmpty); + } + + /** + * Save items to a given tag, reading from an item list. + * + * @param tagKey nbt tag key + * @param tag tag to save to + * @param items item list to save + * @param saveEmpty save to tag if completely empty + * @return the original tag + */ + public static CompoundTag saveAllItems(String tagKey, CompoundTag tag, NonNullList items, boolean saveEmpty) { + return saveAllItems(tagKey, tag, items.size(), items::get, saveEmpty); + } + + /** + * Save items to a given tag, reading from a provider. + * + * @param tagKey nbt tag key + * @param tag tag to save to + * @param size item provider size + * @param itemGetter get items from the provider + * @param saveEmpty save to tag if completely empty + * @return the original tag + */ + public static CompoundTag saveAllItems(String tagKey, CompoundTag tag, int size, IntFunction itemGetter, boolean saveEmpty) { ListTag listTag = new ListTag(); - for (int i = 0; i < container.getContainerSize(); ++i) { - ItemStack itemStack = container.getItem(i); + for (int i = 0; i < size; ++i) { + ItemStack itemStack = itemGetter.apply(i); if (!itemStack.isEmpty()) { CompoundTag compoundTag = new CompoundTag(); compoundTag.putByte("Slot", (byte) i); @@ -23,18 +93,51 @@ public static CompoundTag saveAllItems(CompoundTag tag, Container container, boo } } if (!listTag.isEmpty() || saveEmpty) { - tag.put("Items", listTag); + tag.put(tagKey, listTag); } return tag; } + /** + * Read items from a given tag, saving them to a container. + * + * @param tag tag to read from + * @param container container to fill + */ public static void loadAllItems(CompoundTag tag, Container container) { - ListTag listTag = tag.getList("Items", 10); + loadAllItems(TAG_ITEMS, tag, container.getContainerSize(), (ItemStack stack, int value) -> { + container.setItem(value, stack); + }); + } + + /** + * Read items from a given tag, saving them to an item list. + * + * @param tagKey nbt tag key + * @param tag tag to read from + * @param items item list to fill + */ + public static void loadAllItems(String tagKey, CompoundTag tag, NonNullList items) { + loadAllItems(tagKey, tag, items.size(), (ItemStack stack, int value) -> { + items.set(value, stack); + }); + } + + /** + * Read items from a given tag, saving to a provider. + * + * @param tagKey nbt tag key + * @param tag tag to read from + * @param size item provider size + * @param itemSetter set items to the provider + */ + public static void loadAllItems(String tagKey, CompoundTag tag, int size, ObjIntConsumer itemSetter) { + ListTag listTag = tag.getList(tagKey, Tag.TAG_COMPOUND); for (int i = 0; i < listTag.size(); ++i) { CompoundTag compoundTag = listTag.getCompound(i); - int j = compoundTag.getByte("Slot") & 255; - if (j < container.getContainerSize()) { - container.setItem(j, ItemStack.of(compoundTag)); + int slot = compoundTag.getByte("Slot") & 255; + if (slot < size) { + itemSetter.accept(ItemStack.of(compoundTag), slot); } } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java new file mode 100644 index 0000000..1d8f4c8 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java @@ -0,0 +1,98 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ClientConfig; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +/** + * All animation code in this class is taken from the old RealBench mod. + */ +public class CraftingTableAnimationController { + private final Vec3 position; + + public int ticks; + public float currentAngle; + public float nextAngle; + public int sector; + public boolean animating; + public float animationAngleStart; + public float animationAngleEnd; + public double startTicks; + public double playerAngle; + + public CraftingTableAnimationController(BlockPos blockPos) { + this.position = blockPos.getCenter(); + } + + public void tick(Level level) { + ++this.ticks; + this.setPlayerAngle(level); + this.setCurrentSector(); + this.tryAnimate(); + } + + private void setPlayerAngle(Level level) { + Player player; + if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients) { + player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, false); + } else { + player = null; + } + if (player != null) { + double d0 = player.getX() - this.position.x(); + double d1 = player.getZ() - this.position.z(); + this.playerAngle = (Math.atan2(-d0, -d1) + 3.9269908169872414D) % 6.283185307179586D; + } + } + + private void setCurrentSector() { + int sector = (int) (this.playerAngle * 2.0 / Math.PI); + if (this.sector != sector) { + this.animating = true; + this.animationAngleStart = this.currentAngle; + float delta1 = sector * 90.0F - this.currentAngle; + float abs1 = Math.abs(delta1); + float delta2 = delta1 + 360.0F; + float shift = Math.abs(delta2); + float delta3 = delta1 - 360.0F; + float abs3 = Math.abs(delta3); + if (abs3 < abs1 && abs3 < shift) { + this.animationAngleEnd = delta3 + this.currentAngle; + } else if (shift < abs1 && shift < abs3) { + this.animationAngleEnd = delta2 + this.currentAngle; + } else { + this.animationAngleEnd = delta1 + this.currentAngle; + } + this.startTicks = this.ticks; + this.sector = sector; + } + } + + private void tryAnimate() { + if (this.animating) { + if (this.ticks >= this.startTicks + 20) { + this.animating = false; + this.currentAngle = this.nextAngle = (this.animationAngleEnd + 360.0F) % 360.0F; + } else { + this.currentAngle = (calcEaseOutQuad(this.ticks - this.startTicks, this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; + this.nextAngle = (calcEaseOutQuad(Math.min(this.ticks + 1 - this.startTicks, 20), this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; + if (this.currentAngle != 0.0F || this.nextAngle != 0.0F) { + if (this.currentAngle == 0.0F && this.nextAngle >= 180.0F) { + this.currentAngle = 360.0F; + } + if (this.nextAngle == 0.0F && this.currentAngle >= 180.0F) { + this.nextAngle = 360.0F; + } + } + } + } + } + + private static float calcEaseOutQuad(double t, float b, float c, double d) { + float z = (float) t / (float) d; + return -c * z * (z - 2.0F) + b; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java new file mode 100644 index 0000000..e76aed1 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -0,0 +1,136 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements CraftingContainer, TickingBlockEntity { + public static final MutableComponent CRAFTING_COMPONENT = Component.translatable("container.crafting"); + public static final String TAG_RESULT = "Result"; + + private NonNullList items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); + private NonNullList resultItems = NonNullList.withSize(1, ItemStack.EMPTY); + private final CraftingTableAnimationController animationController; + + public CraftingTableBlockEntity(BlockPos pos, BlockState blockState) { + super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), pos, blockState); + this.animationController = new CraftingTableAnimationController(pos); + } + + @Override + public void load(CompoundTag tag) { + super.load(tag); + this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); + this.resultItems = NonNullList.withSize(1, ItemStack.EMPTY); + if (!this.tryLoadLootTable(tag)) { + ContainerHelper.loadAllItems(tag, this.items); + ContainerSerializationHelper.loadAllItems(TAG_RESULT, tag, this.resultItems); + } + } + + @Override + protected void saveAdditional(CompoundTag tag) { + super.saveAdditional(tag); + if (!this.trySaveLootTable(tag)) { + ContainerHelper.saveAllItems(tag, this.items); + ContainerSerializationHelper.saveAllItems(TAG_RESULT, tag, this.resultItems); + } + } + + @Override + @Nullable + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public CompoundTag getUpdateTag() { + return this.saveWithoutMetadata(); + } + + @Override + public void setChanged() { + super.setChanged(); + if (this.level != null) { + this.level.sendBlockUpdated(this.worldPosition, this.getBlockState(), this.getBlockState(), 3); + } + } + + @Override + public int getWidth() { + return 3; + } + + @Override + public int getHeight() { + return 3; + } + + @Override + public NonNullList getItems() { + return this.items; + } + + @Override + protected void setItems(NonNullList itemStacks) { + this.items = itemStacks; + } + + @Override + public void fillStackedContents(StackedContents contents) { + for (ItemStack itemStack : this.items) { + contents.accountSimpleStack(itemStack); + } + } + + @Override + protected Component getDefaultName() { + return CRAFTING_COMPONENT; + } + + @Override + protected AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return new VisualCraftingMenu(containerId, inventory, this, ContainerLevelAccess.create(this.getLevel(), this.getBlockPos())); + } + + @Override + public int getContainerSize() { + return 9; + } + + @Override + public boolean stillValid(Player player) { + return Container.stillValidBlockEntity(this, player); + } + + @Override + public void clientTick() { + this.animationController.tick(this.getLevel()); + } + + public NonNullList getResultItems() { + return this.resultItems; + } + + public CraftingTableAnimationController getAnimationController() { + return this.animationController; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java deleted file mode 100644 index 5e214e0..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/VisualCraftingTableBlockEntity.java +++ /dev/null @@ -1,187 +0,0 @@ -package fuzs.visualworkbench.world.level.block.entity; - -import fuzs.puzzleslib.api.block.v1.TickingBlockEntity; -import fuzs.puzzleslib.api.core.v1.CommonAbstractions; -import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.config.ClientConfig; -import fuzs.visualworkbench.init.ModRegistry; -import fuzs.visualworkbench.util.MathHelper; -import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; -import net.minecraft.core.BlockPos; -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.Container; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.*; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.Nullable; - -import java.util.Optional; - -public class VisualCraftingTableBlockEntity extends BlockEntity implements MenuProvider, TickingBlockEntity { - private static final String TAG_CRAFT_SLOTS = "CraftSlots"; - private static final String TAG_RESULT_SLOTS = "ResultSlots"; - private static final String TAG_RECIPE_USED = "RecipeUsed"; - - private TransientCraftingContainer craftSlots; - private ResultContainer resultSlots; - public int ticks; - public float currentAngle; - public float nextAngle; - private int sector; - private boolean animating; - private float animationAngleStart; - private float animationAngleEnd; - private double startTicks; - private double playerAngle; - - public VisualCraftingTableBlockEntity(BlockPos pos, BlockState state) { - super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.get(), pos, state); - } - - @Override - public Component getDisplayName() { - return Component.translatable("container.crafting"); - } - - @Override - public void load(CompoundTag tag) { - super.load(tag); - this.craftSlots = new TransientCraftingContainer(new AbstractContainerMenu(null, -1) { - @Override - public ItemStack quickMoveStack(Player player, int index) { - return null; - } - - @Override - public boolean stillValid(Player player) { - return true; - } - - @Override - public void slotsChanged(Container container) { - VisualCraftingTableBlockEntity.this.setChanged(); - } - }, 3, 3, NonNullList.createWithCapacity(9)); - ContainerSerializationHelper.loadAllItems(tag.getCompound(TAG_CRAFT_SLOTS), this.craftSlots); - this.resultSlots = new ResultContainer(); - ContainerSerializationHelper.loadAllItems(tag.getCompound(TAG_RESULT_SLOTS), this.resultSlots); - Optional> recipe = CommonAbstractions.INSTANCE.getMinecraftServer().getRecipeManager().byKey(ResourceLocation.tryParse(tag.getString(TAG_RECIPE_USED))); - recipe.ifPresent(this.resultSlots::setRecipeUsed); - } - - @Override - protected void saveAdditional(CompoundTag tag) { - super.saveAdditional(tag); - CompoundTag compoundTag1 = new CompoundTag(); - ContainerSerializationHelper.saveAllItems(compoundTag1, this.craftSlots); - tag.put(TAG_CRAFT_SLOTS, compoundTag1); - CompoundTag compoundTag2 = new CompoundTag(); - ContainerSerializationHelper.saveAllItems(compoundTag2, this.resultSlots); - tag.put(TAG_RESULT_SLOTS, compoundTag2); - if (this.resultSlots.getRecipeUsed() != null) { - tag.putString(TAG_RECIPE_USED, this.resultSlots.getRecipeUsed().getId().toString()); - } - } - - @Override - @Nullable - public ClientboundBlockEntityDataPacket getUpdatePacket() { - return ClientboundBlockEntityDataPacket.create(this); - } - - @Override - public CompoundTag getUpdateTag() { - return this.saveWithoutMetadata(); - } - - @Override - public void setChanged() { - super.setChanged(); - if (this.level != null) { - this.level.sendBlockUpdated(this.worldPosition, this.getBlockState(), this.getBlockState(), 3); - } - } - - public CraftingContainer getCraftSlots() { - return this.craftSlots; - } - - public ResultContainer getResultSlots() { - return this.resultSlots; - } - - @Override - public AbstractContainerMenu createMenu(int id, Inventory playerInventory, Player player) { - return new VisualCraftingMenu(id, playerInventory, this, ContainerLevelAccess.create(this.getLevel(), this.getBlockPos())); - } - - public int getRedstoneSignal() { - int i = 0; - for (int j = 0; j < this.craftSlots.getContainerSize(); ++j) { - ItemStack itemStack = this.craftSlots.getItem(j); - if (!itemStack.isEmpty()) { - ++i; - } - } - return i; - } - - @Override - public void clientTick() { - ++this.ticks; - if (this.craftSlots.isEmpty() || !VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients) return; - Player player = this.getLevel().getNearestPlayer((double) this.worldPosition.getX() + 0.5D, (double) this.worldPosition.getY() + 0.5D, (double) this.worldPosition.getZ() + 0.5D, 3.0D, false); - if (player != null) { - double d0 = player.getX() - ((double) this.worldPosition.getX() + 0.5D); - double d1 = player.getZ() - ((double) this.worldPosition.getZ() + 0.5D); - this.playerAngle = (Math.atan2(-d0, -d1) + 3.9269908169872414D) % 6.283185307179586D; - } - // most animation code is taken from the old RealBench mod (https://www.curseforge.com/minecraft/mc-mods/realbench) - int sector = (int) (this.playerAngle * 2.0 / Math.PI); - if (this.sector != sector) { - this.animating = true; - this.animationAngleStart = this.currentAngle; - float delta1 = sector * 90.0F - this.currentAngle; - float abs1 = Math.abs(delta1); - float delta2 = delta1 + 360.0F; - float shift = Math.abs(delta2); - float delta3 = delta1 - 360.0F; - float abs3 = Math.abs(delta3); - if (abs3 < abs1 && abs3 < shift) { - this.animationAngleEnd = delta3 + this.currentAngle; - } else if (shift < abs1 && shift < abs3) { - this.animationAngleEnd = delta2 + this.currentAngle; - } else { - this.animationAngleEnd = delta1 + this.currentAngle; - } - this.startTicks = this.ticks; - this.sector = sector; - } - if (this.animating) { - if (this.ticks >= this.startTicks + 20) { - this.animating = false; - this.currentAngle = this.nextAngle = (this.animationAngleEnd + 360.0F) % 360.0F; - } else { - this.currentAngle = (MathHelper.easeOutQuad(this.ticks - this.startTicks, this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; - this.nextAngle = (MathHelper.easeOutQuad(Math.min(this.ticks + 1 - this.startTicks, 20), this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; - if (this.currentAngle != 0.0F || this.nextAngle != 0.0F) { - if (this.currentAngle == 0.0F && this.nextAngle >= 180.0F) { - this.currentAngle = 360.0F; - } - if (this.nextAngle == 0.0F && this.currentAngle >= 180.0F) { - this.nextAngle = 360.0F; - } - } - } - } - } -} diff --git a/1.20.4/Common/src/main/resources/architectury.common.json b/1.20.4/Common/src/main/resources/architectury.common.json new file mode 100644 index 0000000..822cfd0 --- /dev/null +++ b/1.20.4/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "visualworkbench.accesswidener" +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/common.mixins.json b/1.20.4/Common/src/main/resources/common.mixins.json new file mode 100644 index 0000000..77fc8f4 --- /dev/null +++ b/1.20.4/Common/src/main/resources/common.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20.4/Common/src/main/resources/pack.mcmeta b/1.20.4/Common/src/main/resources/pack.mcmeta index 19bfab2..546f4f1 100755 --- a/1.20.4/Common/src/main/resources/pack.mcmeta +++ b/1.20.4/Common/src/main/resources/pack.mcmeta @@ -1,8 +1,6 @@ { "pack": { "description": "${modDescription}", - "pack_format": ${resourcePackFormat}, - "forge:resource_pack_format": ${resourcePackFormat}, - "forge:data_pack_format": ${dataPackFormat} + "pack_format": ${resourcePackFormat} } } diff --git a/1.20.4/Common/src/main/resources/visualworkbench.accesswidener b/1.20.4/Common/src/main/resources/visualworkbench.accesswidener new file mode 100644 index 0000000..0cce57a --- /dev/null +++ b/1.20.4/Common/src/main/resources/visualworkbench.accesswidener @@ -0,0 +1,11 @@ +accessWidener v2 named +accessible field net/minecraft/world/level/block/entity/BlockEntityType$Builder validBlocks Ljava/util/Set; +mutable field net/minecraft/world/level/block/entity/BlockEntityType$Builder validBlocks Ljava/util/Set; +accessible field net/minecraft/world/inventory/CraftingMenu craftSlots Lnet/minecraft/world/inventory/CraftingContainer; +mutable field net/minecraft/world/inventory/CraftingMenu craftSlots Lnet/minecraft/world/inventory/CraftingContainer; +accessible field net/minecraft/world/inventory/CraftingMenu resultSlots Lnet/minecraft/world/inventory/ResultContainer; +mutable field net/minecraft/world/inventory/CraftingMenu resultSlots Lnet/minecraft/world/inventory/ResultContainer; +accessible field net/minecraft/world/inventory/CraftingMenu access Lnet/minecraft/world/inventory/ContainerLevelAccess; +mutable field net/minecraft/world/inventory/CraftingMenu access Lnet/minecraft/world/inventory/ContainerLevelAccess; +accessible field net/minecraft/world/inventory/ResultContainer itemStacks Lnet/minecraft/core/NonNullList; +mutable field net/minecraft/world/inventory/ResultContainer itemStacks Lnet/minecraft/core/NonNullList; diff --git a/1.20.4/Common/src/main/resources/visualworkbench.common.mixins.json b/1.20.4/Common/src/main/resources/visualworkbench.common.mixins.json deleted file mode 100644 index 37873b0..0000000 --- a/1.20.4/Common/src/main/resources/visualworkbench.common.mixins.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "package": "fuzs.visualworkbench.mixin", - "refmap": "visualworkbench.refmap.json", - "plugin": "fuzs.visualworkbench.mixin.ModMixinConfigPlugin", - "mixins": [ - "accessor.BlockEntityTypeBuilderAccessor", - "accessor.CraftingMenuAccessor" - ], - "client": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/1.20.4/Fabric/build.gradle b/1.20.4/Fabric/build.gradle index 2389637..4de494c 100644 --- a/1.20.4/Fabric/build.gradle +++ b/1.20.4/Fabric/build.gradle @@ -1,6 +1,4 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' - -def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/fabric.gradle" dependencies { // Fabric Api @@ -18,16 +16,4 @@ dependencies { // Extensible Enums // modApi(include(libs.extensibleenums.fabric.get())) - - // Just Enough Items - compileOnly libs.jeiapi.common - modLocalRuntime libs.jei.fabric - - // Quality of Life Mods - versionCatalog.findLibrary("modmenu.fabric").ifPresent { - modLocalRuntime(it) - } - versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { - modLocalRuntime(it) - } } diff --git a/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java b/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java similarity index 78% rename from 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java rename to 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java index e93170d..3d458b9 100644 --- a/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/VisualWorkbenchFabric.java +++ b/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java @@ -1,6 +1,7 @@ -package fuzs.visualworkbench; +package fuzs.visualworkbench.fabric; import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.visualworkbench.VisualWorkbench; import net.fabricmc.api.ModInitializer; public class VisualWorkbenchFabric implements ModInitializer { diff --git a/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java b/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java similarity index 79% rename from 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java rename to 1.20.4/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java index e4841e2..11075e8 100644 --- a/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchFabricClient.java +++ b/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java @@ -1,7 +1,8 @@ -package fuzs.visualworkbench.client; +package fuzs.visualworkbench.fabric.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.client.VisualWorkbenchClient; import net.fabricmc.api.ClientModInitializer; public class VisualWorkbenchFabricClient implements ClientModInitializer { diff --git a/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index c129fc8..0000000 --- a/1.20.4/Fabric/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.visualworkbench.mixin; - -import net.fabricmc.loader.api.FabricLoader; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.List; -import java.util.Set; - -public class ModMixinConfigPlugin implements IMixinConfigPlugin { - - @Override - public void onLoad(String mixinPackage) { - - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return FabricLoader.getInstance().isModLoaded("puzzleslib"); - } - - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/1.20.4/Fabric/src/main/resources/fabric.mixins.json b/1.20.4/Fabric/src/main/resources/fabric.mixins.json new file mode 100644 index 0000000..6bf7940 --- /dev/null +++ b/1.20.4/Fabric/src/main/resources/fabric.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.fabric.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "${modId}.fabric.refmap.json" +} diff --git a/1.20.4/Fabric/src/main/resources/fabric.mod.json b/1.20.4/Fabric/src/main/resources/fabric.mod.json index e48b691..243503b 100644 --- a/1.20.4/Fabric/src/main/resources/fabric.mod.json +++ b/1.20.4/Fabric/src/main/resources/fabric.mod.json @@ -9,7 +9,7 @@ "authors": [ "${modAuthor}" ], - + "contact": { "homepage": "${modPageUrl}", "issues": "${modIssueUrl}", @@ -34,7 +34,8 @@ }, "mixins": [ - "${modId}.common.mixins.json" + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" ], "depends": { diff --git a/1.20.4/Forge/build.gradle b/1.20.4/Forge/build.gradle index 170d164..f9839f1 100644 --- a/1.20.4/Forge/build.gradle +++ b/1.20.4/Forge/build.gradle @@ -1,32 +1,6 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' - -def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/forge.gradle" dependencies { // Puzzles Lib - api fg.deobf(libs.puzzleslib.forge.get()) - - // Just Enough Items - compileOnly libs.jeiapi.common - runtimeOnly fg.deobf(libs.jei.forge.get()) - - // Quality of Life Mods - versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } - versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } + modApi libs.puzzleslib.forge } - -task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { - onlyIf { project.hasProperty('keyStore') } - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = outputFile = tasks.jarJar.archivePath -} - -jar.finalizedBy 'signJar' -signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/Forge/gradle.properties b/1.20.4/Forge/gradle.properties new file mode 100644 index 0000000..32f842a --- /dev/null +++ b/1.20.4/Forge/gradle.properties @@ -0,0 +1 @@ +loom.platform=forge \ No newline at end of file diff --git a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/forge/VisualWorkbenchForge.java similarity index 68% rename from 1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java rename to 1.20.4/Forge/src/main/java/fuzs/visualworkbench/forge/VisualWorkbenchForge.java index 5a938a2..ed04091 100644 --- a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java +++ b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/forge/VisualWorkbenchForge.java @@ -1,8 +1,7 @@ -package fuzs.visualworkbench; +package fuzs.visualworkbench.forge; import fuzs.puzzleslib.api.core.v1.ModConstructor; -import fuzs.puzzleslib.api.data.v2.core.DataProviderHelper; -import fuzs.visualworkbench.data.ModBlockTagsProvider; +import fuzs.visualworkbench.VisualWorkbench; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; @@ -14,6 +13,5 @@ public class VisualWorkbenchForge { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { ModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbench::new); - DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModBlockTagsProvider::new); } } diff --git a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/forge/client/VisualWorkbenchForgeClient.java similarity index 86% rename from 1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java rename to 1.20.4/Forge/src/main/java/fuzs/visualworkbench/forge/client/VisualWorkbenchForgeClient.java index 1e3d306..79b7760 100644 --- a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java +++ b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/forge/client/VisualWorkbenchForgeClient.java @@ -1,7 +1,8 @@ -package fuzs.visualworkbench.client; +package fuzs.visualworkbench.forge.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.client.VisualWorkbenchClient; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; diff --git a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index bd78e35..0000000 --- a/1.20.4/Forge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.visualworkbench.mixin; - -import net.minecraftforge.fml.loading.FMLLoader; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.List; -import java.util.Set; - -public class ModMixinConfigPlugin implements IMixinConfigPlugin { - - @Override - public void onLoad(String mixinPackage) { - - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; - } - - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/1.20.4/Forge/src/main/resources/META-INF/mods.toml b/1.20.4/Forge/src/main/resources/META-INF/mods.toml index e15b638..6c2e585 100644 --- a/1.20.4/Forge/src/main/resources/META-INF/mods.toml +++ b/1.20.4/Forge/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader = "javafml" -loaderVersion = "[${minFMLVersion},)" +loaderVersion = "*" license = "${modLicense}" issueTrackerURL = "${modIssueUrl}" @@ -18,6 +18,7 @@ displayTest = "${modForgeDisplayTest}" [[dependencies.${ modId }]] modId = "forge" mandatory = true +type = "required" versionRange = "[${minForgeVersion},)" ordering = "NONE" side = "BOTH" @@ -25,13 +26,23 @@ side = "BOTH" [[dependencies.${ modId }]] modId = "minecraft" mandatory = true +type = "required" versionRange = "[${minecraftVersion}]" ordering = "NONE" side = "BOTH" +[[dependencies.${ modId }]] +modId = "forgeconfigapiport" +mandatory = true +type = "required" +versionRange = "*" +ordering = "NONE" +side = "BOTH" + [[dependencies.${ modId }]] modId = "puzzleslib" mandatory = true +type = "required" versionRange = "[${minPuzzlesVersion},)" ordering = "NONE" side = "BOTH" diff --git a/1.20.4/Forge/src/main/resources/forge.mixins.json b/1.20.4/Forge/src/main/resources/forge.mixins.json new file mode 100644 index 0000000..f2b4276 --- /dev/null +++ b/1.20.4/Forge/src/main/resources/forge.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.forge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "${modId}.forge.refmap.json" +} diff --git a/1.20.4/NeoForge/build.gradle b/1.20.4/NeoForge/build.gradle index 170d164..310efce 100644 --- a/1.20.4/NeoForge/build.gradle +++ b/1.20.4/NeoForge/build.gradle @@ -1,32 +1,6 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' - -def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/neoforge.gradle" dependencies { // Puzzles Lib - api fg.deobf(libs.puzzleslib.forge.get()) - - // Just Enough Items - compileOnly libs.jeiapi.common - runtimeOnly fg.deobf(libs.jei.forge.get()) - - // Quality of Life Mods - versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } - versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } + modApi libs.puzzleslib.neoforge } - -task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { - onlyIf { project.hasProperty('keyStore') } - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = outputFile = tasks.jarJar.archivePath -} - -jar.finalizedBy 'signJar' -signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/NeoForge/gradle.properties b/1.20.4/NeoForge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/1.20.4/NeoForge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java deleted file mode 100644 index 5a938a2..0000000 --- a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/VisualWorkbenchForge.java +++ /dev/null @@ -1,19 +0,0 @@ -package fuzs.visualworkbench; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import fuzs.puzzleslib.api.data.v2.core.DataProviderHelper; -import fuzs.visualworkbench.data.ModBlockTagsProvider; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -@Mod(VisualWorkbench.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -public class VisualWorkbenchForge { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbench::new); - DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModBlockTagsProvider::new); - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index bd78e35..0000000 --- a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.visualworkbench.mixin; - -import net.minecraftforge.fml.loading.FMLLoader; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.List; -import java.util.Set; - -public class ModMixinConfigPlugin implements IMixinConfigPlugin { - - @Override - public void onLoad(String mixinPackage) { - - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; - } - - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java new file mode 100644 index 0000000..4266164 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java @@ -0,0 +1,21 @@ +package fuzs.visualworkbench.neoforge; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.data.ModBlockTagsProvider; +import fuzs.visualworkbench.data.client.ModLanguageProvider; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(VisualWorkbench.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class VisualWorkbenchNeoForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbench::new); + DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModBlockTagsProvider::new, ModLanguageProvider::new); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java similarity index 55% rename from 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java rename to 1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java index 1e3d306..b27cd11 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchForgeClient.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java @@ -1,14 +1,15 @@ -package fuzs.visualworkbench.client; +package fuzs.visualworkbench.neoforge.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.visualworkbench.VisualWorkbench; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +import fuzs.visualworkbench.client.VisualWorkbenchClient; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; @Mod.EventBusSubscriber(modid = VisualWorkbench.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class VisualWorkbenchForgeClient { +public class VisualWorkbenchNeoForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { diff --git a/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml index e15b638..ef10121 100644 --- a/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml +++ b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader = "javafml" -loaderVersion = "[${minFMLVersion},)" +loaderVersion = "*" license = "${modLicense}" issueTrackerURL = "${modIssueUrl}" @@ -15,16 +15,24 @@ displayURL = "${modPageUrl}" updateJSONURL = "${modUpdateUrl}" displayTest = "${modForgeDisplayTest}" +[[mixins]] +config="${modId}.common.mixins.json" + +[[mixins]] +config="${modId}.neoforge.mixins.json" + [[dependencies.${ modId }]] -modId = "forge" +modId = "neoforge" mandatory = true -versionRange = "[${minForgeVersion},)" +type = "required" +versionRange = "[${minNeoForgeVersion},)" ordering = "NONE" side = "BOTH" [[dependencies.${ modId }]] modId = "minecraft" mandatory = true +type = "required" versionRange = "[${minecraftVersion}]" ordering = "NONE" side = "BOTH" @@ -32,6 +40,7 @@ side = "BOTH" [[dependencies.${ modId }]] modId = "puzzleslib" mandatory = true +type = "required" versionRange = "[${minPuzzlesVersion},)" ordering = "NONE" side = "BOTH" diff --git a/1.20.4/NeoForge/src/main/resources/neoforge.mixins.json b/1.20.4/NeoForge/src/main/resources/neoforge.mixins.json new file mode 100644 index 0000000..1fb3919 --- /dev/null +++ b/1.20.4/NeoForge/src/main/resources/neoforge.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.neoforge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20.4/build.gradle b/1.20.4/build.gradle index fadade3..2417d2e 100644 --- a/1.20.4/build.gradle +++ b/1.20.4/build.gradle @@ -1,12 +1,9 @@ plugins { - alias libs.plugins.loom apply false - alias libs.plugins.quiltflower apply false - alias libs.plugins.forgegradle apply false - alias libs.plugins.mixin apply false - alias libs.plugins.librarian apply false + alias libs.plugins.architecturyloom apply false + alias libs.plugins.architecturyplugin apply false + alias libs.plugins.shadow apply false alias libs.plugins.cursegradle apply false alias libs.plugins.minotaur apply false } -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/main.gradle" diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index 63e4adb..a44d00f 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -1,14 +1,11 @@ -# 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.jvmargs=-Xmx4G org.gradle.daemon=false -org.gradle.parallel=true copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=8.0.0 +modVersion=20.4.0 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -21,17 +18,29 @@ modForgeDisplayTest=MATCH_VERSION # "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod modFabricEnvironment=* +# Version Catalog +dependenciesVersionCatalog=1.20.4-v13 +dependenciesPuzzlesLibVersion=20.4.7 +dependenciesMinPuzzlesLibVersion=20.4.7 + # Mod Publishing projectReleaseType=release projectCurseForgeId=500273 projectModrinthId=kfqD1JRw -dependenciesVersionCatalog=1.20.1-v25 -dependenciesPuzzlesLibVersion=8.1.11 -dependenciesMinPuzzlesLibVersion=8.1.11 -dependenciesRequiredForgeCurseForge=puzzles-lib dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib -dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredNeoForgeCurseForge=puzzles-lib +dependenciesRequiredForgeCurseForge=forge-config-api-port-fabric, puzzles-lib dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib -#dependenciesEmbeddedFabricCurseForge=cardinal-components +dependenciesRequiredNeoForgeModrinth=puzzles-lib +dependenciesRequiredForgeModrinth=forge-config-api-port, puzzles-lib + +dependenciesOptionalFabricCurseForge=config-menus-forge +dependenciesOptionalNeoForgeCurseForge=config-menus-forge +dependenciesOptionalForgeCurseForge=config-menus-forge +dependenciesOptionalFabricModrinth=forge-config-screens +dependenciesOptionalNeoForgeModrinth=forge-config-screens +dependenciesOptionalForgeModrinth=forge-config-screens + +#dependenciesEmbeddedFabricCurseForge=cardinal-components-api #dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/1.20.4/gradle/wrapper/gradle-wrapper.properties b/1.20.4/gradle/wrapper/gradle-wrapper.properties index 37aef8d..3499ded 100644 --- a/1.20.4/gradle/wrapper/gradle-wrapper.properties +++ b/1.20.4/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/1.20.4/settings.gradle b/1.20.4/settings.gradle index 697dd5f..e401f79 100644 --- a/1.20.4/settings.gradle +++ b/1.20.4/settings.gradle @@ -1,38 +1,13 @@ pluginManagement { repositories { gradlePluginPortal() - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'Sponge' - url = 'https://repo.spongepowered.org/repository/maven-public/' - } - maven { - name = 'Quilt' - url = 'https://maven.quiltmc.org/repository/release' - } - maven { - name = 'Minecraft Forge' - url = 'https://maven.minecraftforge.net/' - } + maven { url "https://maven.architectury.dev/" } + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.neoforged.net/releases/" } + maven { url "https://maven.minecraftforge.net/" } } } -dependencyResolutionManagement { - repositories { - maven { - name = "Fuzs Mod Resources" - url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" - } - } - versionCatalogs { - libs { - from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") - } - } -} +include("Common", "Fabric", "NeoForge", "Forge") -rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" -include("Common", "Fabric", "Forge") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From 12545f9f4f38d8a96fbabf5d28c3d4f916b036ca Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 25 Jan 2024 23:28:51 +0100 Subject: [PATCH 03/16] finish mod rework, mod compat still missing --- .../visualworkbench/config/ClientConfig.java | 6 +- .../world/inventory/VisualCraftingMenu.java | 87 ++++--------------- .../inventory/VisualResultContainer.java | 11 ++- .../VisualTransientCraftingContainer.java | 35 ++++++++ .../CraftingTableWithInventoryBlock.java | 1 + .../CraftingTableAnimationController.java | 20 ++++- .../entity/CraftingTableBlockEntity.java | 23 +---- .../resources/visualworkbench.accesswidener | 3 + 8 files changed, 89 insertions(+), 97 deletions(-) create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java index 0fd88e7..6a3b315 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java @@ -9,5 +9,9 @@ public class ClientConfig implements ConfigCore { @Config(description = "Render the result of the crafting operation in addition to crafting table contents.") public boolean renderResult = true; @Config(description = "Rotate crafting table contents so they always face the closest player.") - public boolean rotateIngredients = true; + public RotateIngredients rotateIngredients = RotateIngredients.CLOSEST_PLAYER; + + public enum RotateIngredients { + CLOSEST_PLAYER, CRAFTING_PLAYER, NEVER + } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java index 8b3c710..235b79a 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -2,102 +2,49 @@ import fuzs.visualworkbench.init.ModRegistry; import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; -import net.minecraft.core.BlockPos; -import net.minecraft.world.Container; -import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.*; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -public class VisualCraftingMenu extends CraftingMenu implements ContainerListener { - private final Container container; +public class VisualCraftingMenu extends CraftingMenu { public VisualCraftingMenu(int id, Inventory inventory) { super(id, inventory); - this.container = new SimpleContainer(); } public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { super(id, inventory, access); - this.container = blockEntity; - this.craftSlots = new TransientCraftingContainer(this, 3, 3, blockEntity.getItems()); - this.resultSlots = new ResultContainer(); -// this.resultSlots = new VisualResultContainer(blockEntity); - this.setCraftingSlots(inventory.player); - this.addSlotListener(this); - } - - private void setCraftingSlots(Player player) { -// for (int i = 0; i < 10; i++) { -// Slot slot = this.getSlot(i); -// if (slot instanceof ResultSlot resultSlot) { -// resultSlot.craftSlots = this.craftSlots; -// slot.container = this.resultSlots; -// } else if (slot.container instanceof TransientCraftingContainer) { -// slot.container = this.craftSlots; -// } -// } - - - // TODO don't replace slots, instead change containers - this.setSlot(0, new ResultSlot(player, this.craftSlots, this.resultSlots, 0, 124, 35) { - - @Override - public void setChanged() { - // Update block entity. - this.container.setChanged(); - } - }); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - int slotIndex = j + i * 3; - this.setSlot(slotIndex + 1, new Slot(this.craftSlots, slotIndex, 30 + j * 18, 17 + i * 18)); + this.craftSlots = new VisualTransientCraftingContainer(this, 3, 3, blockEntity.getItems(), blockEntity); + this.resultSlots = new VisualResultContainer(blockEntity.getResultItems(), blockEntity); + this.setCraftingSlotContainer(); + } + + private void setCraftingSlotContainer() { + for (int i = 0; i < 10; i++) { + Slot slot = this.getSlot(i); + if (slot instanceof ResultSlot resultSlot) { + resultSlot.craftSlots = this.craftSlots; + slot.container = this.resultSlots; + } else if (slot.container instanceof TransientCraftingContainer) { + slot.container = this.craftSlots; } } } - public Slot setSlot(int index, Slot slot) { - slot.index = index; - this.slots.set(index, slot); - return slot; - } - @Override public MenuType getType() { return ModRegistry.CRAFTING_MENU_TYPE.value(); } - @Override - public void slotsChanged(Container container) { - super.slotsChanged(container); - this.access.execute((Level level, BlockPos blockPos) -> { - // Update block entity. - this.container.setChanged(); - }); - } - - @Override - public void slotChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, ItemStack itemStack) { - if (dataSlotIndex >= 1 && dataSlotIndex < 10) { - this.slotsChanged(this.craftSlots); - } - } - - @Override - public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) { - // NO-OP - } - @Override public boolean stillValid(Player player) { - return this.container.stillValid(player); + // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true + return this.craftSlots.stillValid(player); } @Override public void removed(Player player) { - // Prevent items from being cleared out of the container. + // prevent items from being cleared out of the container ContainerLevelAccess containerLevelAccess = this.access; this.access = ContainerLevelAccess.NULL; super.removed(player); diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java index 1d0d893..bb6d893 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java @@ -1,6 +1,6 @@ package fuzs.visualworkbench.world.inventory; -import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.core.NonNullList; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; import net.minecraft.world.entity.player.Player; @@ -10,9 +10,9 @@ public class VisualResultContainer extends ResultContainer { private final Container container; - public VisualResultContainer(CraftingTableBlockEntity container) { + public VisualResultContainer(NonNullList items, Container container) { this.container = container; - this.itemStacks = container.getResultItems(); + this.itemStacks = items; } @Override @@ -27,4 +27,9 @@ public void setItem(int slot, ItemStack stack) { super.setItem(slot, stack); this.container.setChanged(); } + + @Override + public boolean stillValid(Player player) { + return this.container.stillValid(player); + } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java new file mode 100644 index 0000000..e56f409 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java @@ -0,0 +1,35 @@ +package fuzs.visualworkbench.world.inventory; + +import net.minecraft.core.NonNullList; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.TransientCraftingContainer; +import net.minecraft.world.item.ItemStack; + +public class VisualTransientCraftingContainer extends TransientCraftingContainer { + private final Container container; + + public VisualTransientCraftingContainer(AbstractContainerMenu menu, int width, int height, NonNullList items, Container container) { + super(menu, width, height, items); + this.container = container; + } + + @Override + public ItemStack removeItem(int slot, int amount) { + ItemStack itemStack = super.removeItem(slot, amount); + if (!itemStack.isEmpty()) this.container.setChanged(); + return itemStack; + } + + @Override + public void setItem(int slot, ItemStack stack) { + super.setItem(slot, stack); + this.container.setChanged(); + } + + @Override + public boolean stillValid(Player player) { + return this.container.stillValid(player); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java index 69dc90d..919a88b 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java @@ -74,6 +74,7 @@ public boolean hasAnalogOutputSignal(BlockState blockState) { @Override public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos blockPos) { + // similar to Crafter if (level.getBlockEntity(blockPos) instanceof CraftingTableBlockEntity blockEntity) { return (int) blockEntity.getItems().stream().filter(Predicate.not(ItemStack::isEmpty)).count(); } else { diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java index 1d8f4c8..8bccee7 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java @@ -1,8 +1,12 @@ package fuzs.visualworkbench.world.level.block.entity; +import fuzs.puzzleslib.api.core.v1.Proxy; import fuzs.visualworkbench.VisualWorkbench; import fuzs.visualworkbench.config.ClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.CraftingScreen; import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -36,8 +40,20 @@ public void tick(Level level) { private void setPlayerAngle(Level level) { Player player; - if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients) { - player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, false); + if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients != ClientConfig.RotateIngredients.NEVER) { + player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, (Entity entity) -> { + if (!entity.isSpectator()) { + return false; + } else if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients == ClientConfig.RotateIngredients.CLOSEST_PLAYER) { + return true; + } else { + if (entity == Proxy.INSTANCE.getClientPlayer()) { + return Minecraft.getInstance().screen instanceof CraftingScreen; + } else { + return false; + } + } + }); } else { player = null; } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java index e76aed1..fea8728 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -13,22 +13,20 @@ import net.minecraft.world.ContainerHelper; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.player.StackedContents; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerLevelAccess; -import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements CraftingContainer, TickingBlockEntity { +public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements TickingBlockEntity { public static final MutableComponent CRAFTING_COMPONENT = Component.translatable("container.crafting"); public static final String TAG_RESULT = "Result"; + private final CraftingTableAnimationController animationController; private NonNullList items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); private NonNullList resultItems = NonNullList.withSize(1, ItemStack.EMPTY); - private final CraftingTableAnimationController animationController; public CraftingTableBlockEntity(BlockPos pos, BlockState blockState) { super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), pos, blockState); @@ -74,16 +72,6 @@ public void setChanged() { } } - @Override - public int getWidth() { - return 3; - } - - @Override - public int getHeight() { - return 3; - } - @Override public NonNullList getItems() { return this.items; @@ -94,13 +82,6 @@ protected void setItems(NonNullList itemStacks) { this.items = itemStacks; } - @Override - public void fillStackedContents(StackedContents contents) { - for (ItemStack itemStack : this.items) { - contents.accountSimpleStack(itemStack); - } - } - @Override protected Component getDefaultName() { return CRAFTING_COMPONENT; diff --git a/1.20.4/Common/src/main/resources/visualworkbench.accesswidener b/1.20.4/Common/src/main/resources/visualworkbench.accesswidener index 0cce57a..f6b21e6 100644 --- a/1.20.4/Common/src/main/resources/visualworkbench.accesswidener +++ b/1.20.4/Common/src/main/resources/visualworkbench.accesswidener @@ -9,3 +9,6 @@ accessible field net/minecraft/world/inventory/CraftingMenu access Lnet/mine mutable field net/minecraft/world/inventory/CraftingMenu access Lnet/minecraft/world/inventory/ContainerLevelAccess; accessible field net/minecraft/world/inventory/ResultContainer itemStacks Lnet/minecraft/core/NonNullList; mutable field net/minecraft/world/inventory/ResultContainer itemStacks Lnet/minecraft/core/NonNullList; +accessible field net/minecraft/world/inventory/ResultSlot craftSlots Lnet/minecraft/world/inventory/CraftingContainer; +mutable field net/minecraft/world/inventory/ResultSlot craftSlots Lnet/minecraft/world/inventory/CraftingContainer; +mutable field net/minecraft/world/inventory/Slot container Lnet/minecraft/world/Container; From d7bcdce999fa854bdfab80d072d6813268d35cee Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 27 Jan 2024 15:49:36 +0100 Subject: [PATCH 04/16] setup jei again --- 1.20.4/CHANGELOG.md | 9 +- 1.20.4/Common/build.gradle | 3 + .../CraftingTableBlockEntityRenderer.java | 14 +- .../jei/VisualWorkbenchJEIPlugin.java | 48 +++--- .../world/inventory/VisualCraftingMenu.java | 4 +- .../CraftingTableWithInventoryBlock.java | 8 +- .../entity/ContainerSerializationHelper.java | 144 ------------------ .../CraftingTableAnimationController.java | 5 +- .../entity/CraftingTableBlockEntity.java | 9 +- .../entity/WorkbenchVisualsProvider.java | 22 +++ 1.20.4/Fabric/build.gradle | 11 +- 1.20.4/Forge/build.gradle | 4 + 1.20.4/NeoForge/build.gradle | 4 + 1.20.4/gradle.properties | 6 +- 14 files changed, 99 insertions(+), 192 deletions(-) delete mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java create mode 100644 1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index c078143..502901b 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [v20.4.0-1.20.4] - 2024-01-24 -- Ported to Minecraft 1.20.4 -- Ported to NeoForge +## [v20.4.0-1.20.4] - 2024-01-27 +- Rewritten for Minecraft 1.20.4 +- All modded crafting tables are supported automatically, use `visualworkbench:unaltered_workbenches` for individual exclusions +- New implementation should work much more reliably with mods like CraftTweaker +- Greatly reduce number of update packets send to clients +- Publish for NeoForge diff --git a/1.20.4/Common/build.gradle b/1.20.4/Common/build.gradle index 13b80d3..141a7aa 100644 --- a/1.20.4/Common/build.gradle +++ b/1.20.4/Common/build.gradle @@ -3,6 +3,9 @@ apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2 dependencies { // Puzzles Lib modApi libs.puzzleslib.common + + // Just Enough Items + compileOnly libs.jeiapi.common } tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).configureEach { diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java index 46d7983..da38e5f 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java @@ -3,9 +3,9 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.config.ClientConfig; import fuzs.visualworkbench.world.level.block.entity.CraftingTableAnimationController; -import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import fuzs.visualworkbench.world.level.block.entity.WorkbenchVisualsProvider; +import fuzs.visualworkbench.config.ClientConfig; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; @@ -14,12 +14,14 @@ import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.util.Mth; +import net.minecraft.world.Container; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; -public class CraftingTableBlockEntityRenderer implements BlockEntityRenderer { +public class CraftingTableBlockEntityRenderer implements BlockEntityRenderer { private final ItemRenderer itemRenderer; public CraftingTableBlockEntityRenderer(BlockEntityRendererProvider.Context context) { @@ -27,7 +29,7 @@ public CraftingTableBlockEntityRenderer(BlockEntityRendererProvider.Context cont } @Override - public void render(CraftingTableBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { + public void render(T blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above packedLight = blockEntity.getLevel() != null ? LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : 15728880; for (int i = 0; i < blockEntity.getContainerSize(); ++i) { @@ -36,13 +38,13 @@ public void render(CraftingTableBlockEntity blockEntity, float partialTick, Pose this.renderIngredientItem(blockEntity, partialTick, poseStack, multiBufferSource, packedLight, packedOverlay, i, itemStack); } } - ItemStack itemStack = blockEntity.getResultItems().get(0); + ItemStack itemStack = blockEntity.getCraftingResult(); if (!itemStack.isEmpty()) { this.renderResultItem(itemStack, blockEntity.getLevel(), blockEntity.getAnimationController().ticks + partialTick, poseStack, multiBufferSource, packedLight); } } - private void renderIngredientItem(CraftingTableBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay, int i, ItemStack itemStack) { + private void renderIngredientItem(T blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay, int i, ItemStack itemStack) { poseStack.pushPose(); if (VisualWorkbench.CONFIG.get(ClientConfig.class).flatRendering) { this.setupFlatRenderer(blockEntity.getAnimationController(), partialTick, poseStack, itemStack, i); diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java index 063aa38..e104dde 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java @@ -1,24 +1,24 @@ -//package fuzs.visualworkbench.integration.jei; -// -//import fuzs.visualworkbench.VisualWorkbench; -//import fuzs.visualworkbench.init.ModRegistry; -//import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; -//import mezz.jei.api.IModPlugin; -//import mezz.jei.api.JeiPlugin; -//import mezz.jei.api.constants.RecipeTypes; -//import mezz.jei.api.registration.IRecipeTransferRegistration; -//import net.minecraft.resources.ResourceLocation; -// -//@JeiPlugin -//public class VisualWorkbenchJEIPlugin implements IModPlugin { -// -// @Override -// public ResourceLocation getPluginUid() { -// return new ResourceLocation(VisualWorkbench.MOD_ID, "crafting"); -// } -// -// @Override -// public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { -// registration.addRecipeTransferHandler(VisualCraftingMenu.class, ModRegistry.CRAFTING_MENU_TYPE.get(), RecipeTypes.CRAFTING, 1, 9, 10, 36); -// } -//} +package fuzs.visualworkbench.integration.jei; + +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.RecipeTypes; +import mezz.jei.api.registration.IRecipeTransferRegistration; +import net.minecraft.resources.ResourceLocation; + +@JeiPlugin +public class VisualWorkbenchJEIPlugin implements IModPlugin { + + @Override + public ResourceLocation getPluginUid() { + return new ResourceLocation(VisualWorkbench.MOD_ID, "crafting"); + } + + @Override + public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { + registration.addRecipeTransferHandler(VisualCraftingMenu.class, ModRegistry.CRAFTING_MENU_TYPE.value(), RecipeTypes.CRAFTING, 1, 9, 10, 36); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java index 235b79a..333318a 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -16,10 +16,10 @@ public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity super(id, inventory, access); this.craftSlots = new VisualTransientCraftingContainer(this, 3, 3, blockEntity.getItems(), blockEntity); this.resultSlots = new VisualResultContainer(blockEntity.getResultItems(), blockEntity); - this.setCraftingSlotContainer(); + this.setCraftingSlotsContainer(); } - private void setCraftingSlotContainer() { + private void setCraftingSlotsContainer() { for (int i = 0; i < 10; i++) { Slot slot = this.getSlot(i); if (slot instanceof ResultSlot resultSlot) { diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java index 919a88b..6fbd582 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java @@ -1,6 +1,7 @@ package fuzs.visualworkbench.world.level.block; import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import fuzs.puzzleslib.api.block.v1.entity.TickingEntityBlock; import fuzs.visualworkbench.init.ModRegistry; import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; @@ -14,6 +15,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BlockTypes; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; @@ -23,6 +25,10 @@ import java.util.function.Predicate; public class CraftingTableWithInventoryBlock extends BaseEntityBlock implements TickingEntityBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group(BlockTypes.CODEC.fieldOf("block").forGetter(block -> block.block)).apply(instance, CraftingTableWithInventoryBlock::new) + ); + private final Block block; public CraftingTableWithInventoryBlock(Block block) { @@ -37,7 +43,7 @@ public String getDescriptionId() { @Override protected MapCodec codec() { - return null; + return CODEC; } @Override diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java deleted file mode 100644 index bff9ee2..0000000 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/ContainerSerializationHelper.java +++ /dev/null @@ -1,144 +0,0 @@ -package fuzs.visualworkbench.world.level.block.entity; - -import net.minecraft.core.NonNullList; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; -import net.minecraft.world.Container; -import net.minecraft.world.ContainerHelper; -import net.minecraft.world.item.ItemStack; - -import java.util.function.IntFunction; -import java.util.function.ObjIntConsumer; - -/** - * An adjusted version of {@link ContainerHelper} that allows for using {@link Container} instead of {@link NonNullList}. - *

Also allows for changing the nbt key which is usually Items. - */ -@Deprecated -public final class ContainerSerializationHelper extends ContainerHelper { - public static final String TAG_ITEMS = "Items"; - - private ContainerSerializationHelper() { - - } - - /** - * Save items to a given tag, reading from a container. - * - * @param tag tag to save to - * @param container container to save - * @return the original tag - */ - public static CompoundTag saveAllItems(CompoundTag tag, Container container) { - return saveAllItems(tag, container, true); - } - - /** - * Save items to a given tag, reading from an item list. - * - * @param tagKey nbt tag key - * @param tag tag to save to - * @param items item list to save - * @return the original tag - */ - public static CompoundTag saveAllItems(String tagKey, CompoundTag tag, NonNullList items) { - return saveAllItems(tagKey, tag, items, true); - } - - /** - * Save items to a given tag, reading from a container. - * - * @param tag tag to save to - * @param container container to save - * @param saveEmpty save to tag if completely empty - * @return the original tag - */ - public static CompoundTag saveAllItems(CompoundTag tag, Container container, boolean saveEmpty) { - return saveAllItems(TAG_ITEMS, tag, container.getContainerSize(), container::getItem, saveEmpty); - } - - /** - * Save items to a given tag, reading from an item list. - * - * @param tagKey nbt tag key - * @param tag tag to save to - * @param items item list to save - * @param saveEmpty save to tag if completely empty - * @return the original tag - */ - public static CompoundTag saveAllItems(String tagKey, CompoundTag tag, NonNullList items, boolean saveEmpty) { - return saveAllItems(tagKey, tag, items.size(), items::get, saveEmpty); - } - - /** - * Save items to a given tag, reading from a provider. - * - * @param tagKey nbt tag key - * @param tag tag to save to - * @param size item provider size - * @param itemGetter get items from the provider - * @param saveEmpty save to tag if completely empty - * @return the original tag - */ - public static CompoundTag saveAllItems(String tagKey, CompoundTag tag, int size, IntFunction itemGetter, boolean saveEmpty) { - ListTag listTag = new ListTag(); - for (int i = 0; i < size; ++i) { - ItemStack itemStack = itemGetter.apply(i); - if (!itemStack.isEmpty()) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putByte("Slot", (byte) i); - itemStack.save(compoundTag); - listTag.add(compoundTag); - } - } - if (!listTag.isEmpty() || saveEmpty) { - tag.put(tagKey, listTag); - } - return tag; - } - - /** - * Read items from a given tag, saving them to a container. - * - * @param tag tag to read from - * @param container container to fill - */ - public static void loadAllItems(CompoundTag tag, Container container) { - loadAllItems(TAG_ITEMS, tag, container.getContainerSize(), (ItemStack stack, int value) -> { - container.setItem(value, stack); - }); - } - - /** - * Read items from a given tag, saving them to an item list. - * - * @param tagKey nbt tag key - * @param tag tag to read from - * @param items item list to fill - */ - public static void loadAllItems(String tagKey, CompoundTag tag, NonNullList items) { - loadAllItems(tagKey, tag, items.size(), (ItemStack stack, int value) -> { - items.set(value, stack); - }); - } - - /** - * Read items from a given tag, saving to a provider. - * - * @param tagKey nbt tag key - * @param tag tag to read from - * @param size item provider size - * @param itemSetter set items to the provider - */ - public static void loadAllItems(String tagKey, CompoundTag tag, int size, ObjIntConsumer itemSetter) { - ListTag listTag = tag.getList(tagKey, Tag.TAG_COMPOUND); - for (int i = 0; i < listTag.size(); ++i) { - CompoundTag compoundTag = listTag.getCompound(i); - int slot = compoundTag.getByte("Slot") & 255; - if (slot < size) { - itemSetter.accept(ItemStack.of(compoundTag), slot); - } - } - } -} diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java index 8bccee7..65e905b 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java @@ -12,7 +12,10 @@ import net.minecraft.world.phys.Vec3; /** - * All animation code in this class is taken from the old RealBench mod. + * A client-side provider for ticking and storing crafting table item animations on a block entity. + *

Initialize an instance in your block entity constructor, then implement a call for {@link CraftingTableAnimationController#tick(Level)} on the client. + *

Make sure the code is never accidentally called on the server as it accesses client-only classes. + *

All animation code in this class is taken from the old RealBench mod. */ public class CraftingTableAnimationController { private final Vec3 position; diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java index fea8728..11694da 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -1,6 +1,7 @@ package fuzs.visualworkbench.world.level.block.entity; import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; +import fuzs.puzzleslib.api.container.v1.ContainerSerializationHelper; import fuzs.visualworkbench.init.ModRegistry; import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; import net.minecraft.core.BlockPos; @@ -20,7 +21,7 @@ import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements TickingBlockEntity { +public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements TickingBlockEntity, WorkbenchVisualsProvider { public static final MutableComponent CRAFTING_COMPONENT = Component.translatable("container.crafting"); public static final String TAG_RESULT = "Result"; @@ -111,6 +112,12 @@ public NonNullList getResultItems() { return this.resultItems; } + @Override + public ItemStack getCraftingResult() { + return this.resultItems.get(0); + } + + @Override public CraftingTableAnimationController getAnimationController() { return this.animationController; } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java new file mode 100644 index 0000000..3962ba5 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java @@ -0,0 +1,22 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import net.minecraft.world.item.ItemStack; + +/** + * An extension for a {@link net.minecraft.world.level.block.entity.BlockEntity} providing access to data required for rendering. + */ +public interface WorkbenchVisualsProvider { + + /** + * Get the crafting result for the currently stored ingredients. + *

Can return {@link ItemStack#EMPTY} to not render anything. + * + * @return the crafting result + */ + ItemStack getCraftingResult(); + + /** + * @return storage for animation data + */ + CraftingTableAnimationController getAnimationController(); +} diff --git a/1.20.4/Fabric/build.gradle b/1.20.4/Fabric/build.gradle index 4de494c..1123f46 100644 --- a/1.20.4/Fabric/build.gradle +++ b/1.20.4/Fabric/build.gradle @@ -7,13 +7,10 @@ dependencies { // Puzzles Lib modApi libs.puzzleslib.fabric - // Cardinal Components -// modApi(include(libs.cardinalcomponentsbase.fabric.get())) -// modApi(include(libs.cardinalcomponentsentity.fabric.get())) -// modApi(include(libs.cardinalcomponentsblock.fabric.get())) -// modApi(include(libs.cardinalcomponentschunk.fabric.get())) -// modApi(include(libs.cardinalcomponentsworld.fabric.get())) - // Extensible Enums // modApi(include(libs.extensibleenums.fabric.get())) + + // Just Enough Items + compileOnly libs.jeiapi.common + modLocalRuntime libs.jei.fabric } diff --git a/1.20.4/Forge/build.gradle b/1.20.4/Forge/build.gradle index f9839f1..de59471 100644 --- a/1.20.4/Forge/build.gradle +++ b/1.20.4/Forge/build.gradle @@ -3,4 +3,8 @@ apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2 dependencies { // Puzzles Lib modApi libs.puzzleslib.forge + + // Just Enough Items + compileOnly libs.jeiapi.common + modLocalRuntime libs.jei.forge } diff --git a/1.20.4/NeoForge/build.gradle b/1.20.4/NeoForge/build.gradle index 310efce..15447df 100644 --- a/1.20.4/NeoForge/build.gradle +++ b/1.20.4/NeoForge/build.gradle @@ -3,4 +3,8 @@ apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2 dependencies { // Puzzles Lib modApi libs.puzzleslib.neoforge + + // Just Enough Items + compileOnly libs.jeiapi.common + modLocalRuntime libs.jei.neoforge } diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index a44d00f..d7d2422 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -19,9 +19,9 @@ modForgeDisplayTest=MATCH_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.20.4-v13 -dependenciesPuzzlesLibVersion=20.4.7 -dependenciesMinPuzzlesLibVersion=20.4.7 +dependenciesVersionCatalog=1.20.4-v14 +dependenciesPuzzlesLibVersion=20.4.9 +dependenciesMinPuzzlesLibVersion=20.4.9 # Mod Publishing projectReleaseType=release From 6451e14c5a13a65d5577e9b2ca8f62711aee2462 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Mon, 5 Feb 2024 16:30:05 +0100 Subject: [PATCH 05/16] fix item rotation --- 1.20.4/CHANGELOG.md | 4 ++++ .../world/inventory/VisualCraftingMenu.java | 18 +++++++++++------ .../inventory/VisualResultContainer.java | 8 +++++++- .../VisualTransientCraftingContainer.java | 8 +++++++- .../CraftingTableAnimationController.java | 3 +-- .../entity/CraftingTableBlockEntity.java | 20 ++++++++++--------- 1.20.4/gradle.properties | 8 ++++---- 7 files changed, 46 insertions(+), 23 deletions(-) diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index 502901b..408cffb 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v20.4.1-1.20.4] - 2024-02-05 +### Fixed +- Fix rendered crafting tables contents failing to rotate towards the closest player + ## [v20.4.0-1.20.4] - 2024-01-27 - Rewritten for Minecraft 1.20.4 - All modded crafting tables are supported automatically, use `visualworkbench:unaltered_workbenches` for individual exclusions diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java index 333318a..b8e23d7 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -17,6 +17,8 @@ public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity this.craftSlots = new VisualTransientCraftingContainer(this, 3, 3, blockEntity.getItems(), blockEntity); this.resultSlots = new VisualResultContainer(blockEntity.getResultItems(), blockEntity); this.setCraftingSlotsContainer(); + // always update recipe output when opening menu, otherwise could be missing or outdated if the block entity didn't save it correctly + this.refreshRecipeResult(); } private void setCraftingSlotsContainer() { @@ -31,15 +33,13 @@ private void setCraftingSlotsContainer() { } } - @Override - public MenuType getType() { - return ModRegistry.CRAFTING_MENU_TYPE.value(); + private void refreshRecipeResult() { + this.slotsChanged(this.craftSlots); } @Override - public boolean stillValid(Player player) { - // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true - return this.craftSlots.stillValid(player); + public MenuType getType() { + return ModRegistry.CRAFTING_MENU_TYPE.value(); } @Override @@ -50,4 +50,10 @@ public void removed(Player player) { super.removed(player); this.access = containerLevelAccess; } + + @Override + public boolean stillValid(Player player) { + // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true + return this.craftSlots.stillValid(player); + } } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java index bb6d893..015cc56 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java @@ -18,13 +18,19 @@ public VisualResultContainer(NonNullList items, Container container) @Override public ItemStack removeItem(int slot, int amount) { ItemStack result = ContainerHelper.removeItem(this.itemStacks, slot, amount); - if (!result.isEmpty()) this.container.setChanged(); + if (!result.isEmpty()) this.setChanged(); return result; } @Override public void setItem(int slot, ItemStack stack) { super.setItem(slot, stack); + this.setChanged(); + } + + @Override + public void setChanged() { + super.setChanged(); this.container.setChanged(); } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java index e56f409..9f24398 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java @@ -18,13 +18,19 @@ public VisualTransientCraftingContainer(AbstractContainerMenu menu, int width, i @Override public ItemStack removeItem(int slot, int amount) { ItemStack itemStack = super.removeItem(slot, amount); - if (!itemStack.isEmpty()) this.container.setChanged(); + if (!itemStack.isEmpty()) this.setChanged(); return itemStack; } @Override public void setItem(int slot, ItemStack stack) { super.setItem(slot, stack); + this.setChanged(); + } + + @Override + public void setChanged() { + super.setChanged(); this.container.setChanged(); } diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java index 65e905b..2091af1 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java @@ -19,7 +19,6 @@ */ public class CraftingTableAnimationController { private final Vec3 position; - public int ticks; public float currentAngle; public float nextAngle; @@ -45,7 +44,7 @@ private void setPlayerAngle(Level level) { Player player; if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients != ClientConfig.RotateIngredients.NEVER) { player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, (Entity entity) -> { - if (!entity.isSpectator()) { + if (entity.isSpectator()) { return false; } else if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients == ClientConfig.RotateIngredients.CLOSEST_PLAYER) { return true; diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java index 11694da..db19dba 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -2,6 +2,7 @@ import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; import fuzs.puzzleslib.api.container.v1.ContainerSerializationHelper; +import fuzs.visualworkbench.VisualWorkbench; import fuzs.visualworkbench.init.ModRegistry; import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; import net.minecraft.core.BlockPos; @@ -22,12 +23,12 @@ import org.jetbrains.annotations.Nullable; public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements TickingBlockEntity, WorkbenchVisualsProvider { - public static final MutableComponent CRAFTING_COMPONENT = Component.translatable("container.crafting"); - public static final String TAG_RESULT = "Result"; + public static final MutableComponent COMPONENT_CRAFTING = Component.translatable("container.crafting"); + public static final String TAG_RESULT = VisualWorkbench.id("result").toString(); private final CraftingTableAnimationController animationController; - private NonNullList items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); - private NonNullList resultItems = NonNullList.withSize(1, ItemStack.EMPTY); + private final NonNullList items = NonNullList.withSize(9, ItemStack.EMPTY); + private final NonNullList resultItems = NonNullList.withSize(1, ItemStack.EMPTY); public CraftingTableBlockEntity(BlockPos pos, BlockState blockState) { super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), pos, blockState); @@ -37,8 +38,8 @@ public CraftingTableBlockEntity(BlockPos pos, BlockState blockState) { @Override public void load(CompoundTag tag) { super.load(tag); - this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY); - this.resultItems = NonNullList.withSize(1, ItemStack.EMPTY); + this.items.clear(); + this.resultItems.clear(); if (!this.tryLoadLootTable(tag)) { ContainerHelper.loadAllItems(tag, this.items); ContainerSerializationHelper.loadAllItems(TAG_RESULT, tag, this.resultItems); @@ -80,12 +81,13 @@ public NonNullList getItems() { @Override protected void setItems(NonNullList itemStacks) { - this.items = itemStacks; + // why does this event exist... + throw new UnsupportedOperationException(); } @Override protected Component getDefaultName() { - return CRAFTING_COMPONENT; + return COMPONENT_CRAFTING; } @Override @@ -95,7 +97,7 @@ protected AbstractContainerMenu createMenu(int containerId, Inventory inventory) @Override public int getContainerSize() { - return 9; + return this.items.size(); } @Override diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index d7d2422..33870aa 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=20.4.0 +modVersion=20.4.1 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -19,9 +19,9 @@ modForgeDisplayTest=MATCH_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.20.4-v14 -dependenciesPuzzlesLibVersion=20.4.9 -dependenciesMinPuzzlesLibVersion=20.4.9 +dependenciesVersionCatalog=1.20.4-v19 +#dependenciesPuzzlesLibVersion=20.4.9 +#dependenciesMinPuzzlesLibVersion=20.4.9 # Mod Publishing projectReleaseType=release From a925a872db8705a1963c93e1fb56b9a9c5ca80d4 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 16 May 2024 15:54:16 +0200 Subject: [PATCH 06/16] fix right-clicking halving recipe output --- 1.20.4/CHANGELOG.md | 4 ++++ .../world/inventory/VisualResultContainer.java | 3 +-- 1.20.4/gradle.properties | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index 408cffb..eaf4a33 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v20.4.2-1.20.4] - 2024-05-16 +### Fixed +- Fix right-clicking halving recipe output + ## [v20.4.1-1.20.4] - 2024-02-05 ### Fixed - Fix rendered crafting tables contents failing to rotate towards the closest player diff --git a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java index 015cc56..06c03ca 100644 --- a/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java +++ b/1.20.4/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java @@ -2,7 +2,6 @@ import net.minecraft.core.NonNullList; import net.minecraft.world.Container; -import net.minecraft.world.ContainerHelper; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ResultContainer; import net.minecraft.world.item.ItemStack; @@ -17,7 +16,7 @@ public VisualResultContainer(NonNullList items, Container container) @Override public ItemStack removeItem(int slot, int amount) { - ItemStack result = ContainerHelper.removeItem(this.itemStacks, slot, amount); + ItemStack result = super.removeItem(slot, amount); if (!result.isEmpty()) this.setChanged(); return result; } diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index 33870aa..eab00e2 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=20.4.1 +modVersion=20.4.2 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -19,7 +19,7 @@ modForgeDisplayTest=MATCH_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.20.4-v19 +dependenciesVersionCatalog=1.20.4-v40 #dependenciesPuzzlesLibVersion=20.4.9 #dependenciesMinPuzzlesLibVersion=20.4.9 From bcf467b5e65755355687d3052b5c6ca174db0b6a Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 6 Jul 2024 23:11:56 +0200 Subject: [PATCH 07/16] full 1.21 port --- 1.21/CHANGELOG.md | 9 + 1.21/Common/build.gradle | 13 + .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../50b16d832771f8a8317f4d1b88c5121208c8c4f9 | 2 + .../assets/visualworkbench/lang/en_us.json | 4 + .../tags/block/unaltered_workbenches.json | 6 + .../fuzs/visualworkbench/VisualWorkbench.java | 41 +++ .../client/VisualWorkbenchClient.java | 44 ++++ .../client/handler/BlockModelHandler.java | 77 ++++++ .../CraftingTableBlockEntityRenderer.java | 95 +++++++ .../visualworkbench/config/ClientConfig.java | 17 ++ .../visualworkbench/config/ServerConfig.java | 9 + .../data/ModBlockTagsProvider.java | 21 ++ .../data/client/DynamicModelProvider.java | 31 +++ .../data/client/ModLanguageProvider.java | 19 ++ .../handler/BlockConversionHandler.java | 99 +++++++ .../visualworkbench/init/ModRegistry.java | 37 +++ .../jei/VisualWorkbenchJEIPlugin.java | 24 ++ .../world/inventory/VisualCraftingMenu.java | 59 +++++ .../inventory/VisualResultContainer.java | 40 +++ .../VisualTransientCraftingContainer.java | 41 +++ .../CraftingTableWithInventoryBlock.java | 90 +++++++ .../CraftingTableAnimationController.java | 116 +++++++++ .../entity/CraftingTableBlockEntity.java | 131 ++++++++++ .../entity/WorkbenchVisualsProvider.java | 22 ++ .../main/resources/architectury.common.json | 3 + .../src/main/resources/common.mixins.json | 13 + 1.21/Common/src/main/resources/mod_banner.png | Bin 0 -> 17426 bytes 1.21/Common/src/main/resources/mod_logo.png | Bin 0 -> 9349 bytes 1.21/Common/src/main/resources/pack.mcmeta | 6 + .../resources/visualworkbench.accesswidener | 14 + 1.21/Fabric/build.gradle | 13 + .../fabric/VisualWorkbenchFabric.java | 13 + .../client/VisualWorkbenchFabricClient.java | 14 + .../src/main/resources/fabric.mixins.json | 14 + .../Fabric/src/main/resources/fabric.mod.json | 48 ++++ 1.21/NeoForge/build.gradle | 10 + 1.21/NeoForge/gradle.properties | 1 + .../neoforge/VisualWorkbenchNeoForge.java | 16 ++ .../client/VisualWorkbenchNeoForgeClient.java | 18 ++ .../resources/META-INF/neoforge.mods.toml | 49 ++++ .../src/main/resources/neoforge.mixins.json | 13 + 1.21/build.gradle | 9 + 1.21/gradle.properties | 45 ++++ 1.21/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes 1.21/gradle/wrapper/gradle-wrapper.properties | 6 + 1.21/gradlew | 244 ++++++++++++++++++ 1.21/gradlew.bat | 92 +++++++ 1.21/settings.gradle | 16 ++ 49 files changed, 1706 insertions(+) create mode 100644 1.21/CHANGELOG.md create mode 100644 1.21/Common/build.gradle create mode 100644 1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 create mode 100644 1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 create mode 100644 1.21/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json create mode 100644 1.21/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java create mode 100644 1.21/Common/src/main/resources/architectury.common.json create mode 100644 1.21/Common/src/main/resources/common.mixins.json create mode 100644 1.21/Common/src/main/resources/mod_banner.png create mode 100644 1.21/Common/src/main/resources/mod_logo.png create mode 100755 1.21/Common/src/main/resources/pack.mcmeta create mode 100644 1.21/Common/src/main/resources/visualworkbench.accesswidener create mode 100644 1.21/Fabric/build.gradle create mode 100644 1.21/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java create mode 100644 1.21/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java create mode 100644 1.21/Fabric/src/main/resources/fabric.mixins.json create mode 100644 1.21/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.21/NeoForge/build.gradle create mode 100644 1.21/NeoForge/gradle.properties create mode 100644 1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java create mode 100644 1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java create mode 100644 1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 1.21/NeoForge/src/main/resources/neoforge.mixins.json create mode 100644 1.21/build.gradle create mode 100755 1.21/gradle.properties create mode 100644 1.21/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.21/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.21/gradlew create mode 100644 1.21/gradlew.bat create mode 100644 1.21/settings.gradle diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md new file mode 100644 index 0000000..1a62a4b --- /dev/null +++ b/1.21/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v21.0.0-1.21] - 2024-07-06 +- Port to Minecraft 1.21 +- Forge is no longer support in favor of NeoForge diff --git a/1.21/Common/build.gradle b/1.21/Common/build.gradle new file mode 100644 index 0000000..73d65b1 --- /dev/null +++ b/1.21/Common/build.gradle @@ -0,0 +1,13 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/common.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common + + // Just Enough Items + compileOnly libs.jeiapi.common +} + +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).configureEach { + targetNamespace = "named" +} diff --git a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 new file mode 100644 index 0000000..381f28e --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.21 2024-07-06T22:52:38.447202 Language (en_us) +7383cbefca98a20426cf709fdfe773e860fc5f23 assets/visualworkbench/lang/en_us.json diff --git a/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 b/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 new file mode 100644 index 0000000..becbd2f --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 @@ -0,0 +1,2 @@ +// 1.21 2024-07-06T21:57:20.433682 Tags for minecraft:block mod id vanilla +d00da1153a305b41cd0709e40bbab70031f6f7fb data/visualworkbench/tags/block/unaltered_workbenches.json diff --git a/1.21/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json b/1.21/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json new file mode 100644 index 0000000..e3d7d8d --- /dev/null +++ b/1.21/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "container.invalidBlock": "Unable to open. Break and replace to use.", + "tag.block.visualworkbench.unaltered_workbenches": "Unaltered Workbenches" +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json b/1.21/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json new file mode 100644 index 0000000..a9e9b4d --- /dev/null +++ b/1.21/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json @@ -0,0 +1,6 @@ +{ + "values": [ + "minecraft:smithing_table", + "minecraft:fletching_table" + ] +} \ No newline at end of file diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java new file mode 100644 index 0000000..77e6849 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java @@ -0,0 +1,41 @@ +package fuzs.visualworkbench; + +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; +import fuzs.puzzleslib.api.event.v1.RegistryEntryAddedCallback; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import fuzs.puzzleslib.api.event.v1.server.TagsUpdatedCallback; +import fuzs.visualworkbench.config.ClientConfig; +import fuzs.visualworkbench.config.ServerConfig; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import fuzs.visualworkbench.init.ModRegistry; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VisualWorkbench implements ModConstructor { + public static final String MOD_ID = "visualworkbench"; + public static final String MOD_NAME = "Visual Workbench"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class).server(ServerConfig.class); + + @Override + public void onConstructMod() { + ModRegistry.touch(); + registerHandlers(); + } + + private static void registerHandlers() { + RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK).register(BlockConversionHandler::onRegistryEntryAdded); + PlayerInteractEvents.USE_BLOCK.register(BlockConversionHandler::onUseBlock); + TagsUpdatedCallback.EVENT.register(EventPhase.FIRST, BlockConversionHandler::onTagsUpdated); + } + + public static ResourceLocation id(String path) { + return ResourceLocationHelper.fromNamespaceAndPath(MOD_ID, path); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java new file mode 100644 index 0000000..502fdc0 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java @@ -0,0 +1,44 @@ +package fuzs.visualworkbench.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; +import fuzs.puzzleslib.api.client.event.v1.ModelEvents; +import fuzs.puzzleslib.api.core.v1.context.PackRepositorySourcesContext; +import fuzs.puzzleslib.api.event.v1.LoadCompleteCallback; +import fuzs.puzzleslib.api.resources.v1.DynamicPackResources; +import fuzs.puzzleslib.api.resources.v1.PackResourcesHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.client.handler.BlockModelHandler; +import fuzs.visualworkbench.client.renderer.blockentity.CraftingTableBlockEntityRenderer; +import fuzs.visualworkbench.data.client.DynamicModelProvider; +import fuzs.visualworkbench.init.ModRegistry; +import net.minecraft.client.gui.screens.inventory.CraftingScreen; + +public class VisualWorkbenchClient implements ClientModConstructor { + + @Override + public void onConstructMod() { + registerHandlers(); + } + + private static void registerHandlers() { + ModelEvents.MODIFY_UNBAKED_MODEL.register(BlockModelHandler::onModifyUnbakedModel); + LoadCompleteCallback.EVENT.register(BlockModelHandler::onLoadComplete); + } + + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { + context.registerMenuScreen(ModRegistry.CRAFTING_MENU_TYPE.value(), CraftingScreen::new); + } + + @Override + public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { + context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), CraftingTableBlockEntityRenderer::new); + } + + @Override + public void onAddResourcePackFinders(PackRepositorySourcesContext context) { + context.addRepositorySource(PackResourcesHelper.buildClientPack(VisualWorkbench.id("default_block_models"), DynamicPackResources.create(DynamicModelProvider::new), true)); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java new file mode 100644 index 0000000..a0212d4 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java @@ -0,0 +1,77 @@ +package fuzs.visualworkbench.client.handler; + +import com.google.common.base.Suppliers; +import com.google.common.collect.Maps; +import fuzs.puzzleslib.api.client.core.v1.ClientAbstractions; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import net.minecraft.Util; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.Property; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class BlockModelHandler { + private static final Supplier> MODEL_LOCATIONS; + + static { + MODEL_LOCATIONS = Suppliers.memoize(() -> { + return BlockConversionHandler.BLOCK_CONVERSIONS.inverse().entrySet().stream().flatMap(entry -> { + return convertAllBlockStates(entry.getKey(), entry.getValue()).entrySet().stream(); + }).collect(Util.toMap()); + }); + } + + public static void onLoadComplete() { + // run a custom implementation here, the appropriate method in client mod constructor runs together with other mods, so we might miss some entries + for (Map.Entry entry : BlockConversionHandler.BLOCK_CONVERSIONS.entrySet()) { + RenderType renderType = ClientAbstractions.INSTANCE.getRenderType(entry.getKey()); + ClientAbstractions.INSTANCE.registerRenderType(entry.getValue(), renderType); + } + } + + public static EventResultHolder onModifyUnbakedModel(ModelResourceLocation modelLocation, Supplier unbakedModel, Function modelGetter, BiConsumer modelAdder) { + if (MODEL_LOCATIONS.get().containsKey(modelLocation)) { + ResourceLocation resourceLocation = MODEL_LOCATIONS.get().get(modelLocation).id().withPrefix("block/"); + return EventResultHolder.interrupt(modelGetter.apply(resourceLocation)); + } else { + return EventResultHolder.pass(); + } + } + + private static Map convertAllBlockStates(Block oldBlock, Block newBlock) { + Map modelLocations = Maps.newHashMap(); + for (BlockState oldBlockState : oldBlock.getStateDefinition().getPossibleStates()) { + BlockState newBlockState = convertBlockState(newBlock.getStateDefinition(), oldBlockState); + modelLocations.put(BlockModelShaper.stateToModelLocation(oldBlockState), BlockModelShaper.stateToModelLocation(newBlockState)); + } + return modelLocations; + } + + private static BlockState convertBlockState(StateDefinition newStateDefinition, BlockState oldBlockState) { + BlockState newBlockState = newStateDefinition.any(); + for (Map.Entry, Comparable> entry : oldBlockState.getValues().entrySet()) { + newBlockState = setBlockStateValue(entry.getKey(), entry.getValue(), newStateDefinition::getProperty, newBlockState); + } + return newBlockState; + } + + private static , V extends T> BlockState setBlockStateValue(Property oldProperty, Comparable oldValue, Function> propertyGetter, BlockState blockState) { + Property newProperty = propertyGetter.apply(oldProperty.getName()); + if (newProperty != null) { + return blockState.setValue((Property) newProperty, (V) oldValue); + } + return blockState; + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java new file mode 100644 index 0000000..da38e5f --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java @@ -0,0 +1,95 @@ +package fuzs.visualworkbench.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableAnimationController; +import fuzs.visualworkbench.world.level.block.entity.WorkbenchVisualsProvider; +import fuzs.visualworkbench.config.ClientConfig; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.util.Mth; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + +public class CraftingTableBlockEntityRenderer implements BlockEntityRenderer { + private final ItemRenderer itemRenderer; + + public CraftingTableBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + this.itemRenderer = context.getItemRenderer(); + } + + @Override + public void render(T blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { + // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above + packedLight = blockEntity.getLevel() != null ? LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : 15728880; + for (int i = 0; i < blockEntity.getContainerSize(); ++i) { + ItemStack itemStack = blockEntity.getItem(i); + if (!itemStack.isEmpty()) { + this.renderIngredientItem(blockEntity, partialTick, poseStack, multiBufferSource, packedLight, packedOverlay, i, itemStack); + } + } + ItemStack itemStack = blockEntity.getCraftingResult(); + if (!itemStack.isEmpty()) { + this.renderResultItem(itemStack, blockEntity.getLevel(), blockEntity.getAnimationController().ticks + partialTick, poseStack, multiBufferSource, packedLight); + } + } + + private void renderIngredientItem(T blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay, int i, ItemStack itemStack) { + poseStack.pushPose(); + if (VisualWorkbench.CONFIG.get(ClientConfig.class).flatRendering) { + this.setupFlatRenderer(blockEntity.getAnimationController(), partialTick, poseStack, itemStack, i); + } else { + this.setupFloatingRenderer(blockEntity.getAnimationController(), partialTick, poseStack, itemStack, i); + } + this.itemRenderer.renderStatic(itemStack, ItemDisplayContext.FIXED, packedLight, packedOverlay, poseStack, multiBufferSource, blockEntity.getLevel(), (int) blockEntity.getBlockPos().asLong() + i); + poseStack.popPose(); + } + + private void setupFloatingRenderer(CraftingTableAnimationController animationController, float partialTick, PoseStack poseStack, ItemStack itemStack, int index) { + // -0.0125 to 0.0125 + float shift = (float) Math.abs(((animationController.ticks + partialTick) * 50.0 + (index * 1000L)) % 5000L - 2500L) / 200000.0F; + BakedModel model = this.itemRenderer.getModel(itemStack, null, null, 0); + boolean blockItem = model.isGui3d(); + poseStack.translate(0.5, shift, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTick, animationController.currentAngle, animationController.nextAngle))); + poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, 1.09375, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); + float scale = blockItem ? 0.24F : 0.18F; + poseStack.scale(scale, scale, scale); + } + + private void setupFlatRenderer(CraftingTableAnimationController animationController, float partialTick, PoseStack poseStack, ItemStack itemStack, int index) { + BakedModel bakedModel = this.itemRenderer.getModel(itemStack, null, null, 0); + boolean gui3d = bakedModel.isGui3d(); + poseStack.translate(0.5, 0.0, 0.5); + poseStack.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTick, animationController.currentAngle, animationController.nextAngle))); + poseStack.translate((double) (index % 3) * 3.0 / 16.0 + 0.3125 - 0.5, gui3d ? 1.0625 : 1.005, (double) (index / 3) * 3.0 / 16.0 + 0.3125 - 0.5); + poseStack.mulPose(Axis.XP.rotationDegrees(90.0F)); + poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F)); + float scale = gui3d ? 0.25F : 0.175F; + poseStack.scale(scale, scale, scale); + } + + private void renderResultItem(ItemStack itemStack, @Nullable Level level, float time, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight) { + if (!VisualWorkbench.CONFIG.get(ClientConfig.class).renderResult) return; + poseStack.pushPose(); + poseStack.translate(0.5F, 1.15F, 0.5F); + BakedModel model = this.itemRenderer.getModel(itemStack, level, null, 0); + float hoverOffset = Mth.sin(time / 10.0F) * 0.04F + 0.1F; + float modelYScale = model.getTransforms().getTransform(ItemDisplayContext.GROUND).scale.y(); + poseStack.translate(0.0, hoverOffset + 0.25F * modelYScale, 0.0); + poseStack.mulPose(Axis.YP.rotation(time / 20.0F)); + if (!model.isGui3d()) poseStack.scale(0.75F, 0.75F, 0.75F); + this.itemRenderer.render(itemStack, ItemDisplayContext.GROUND, false, poseStack, multiBufferSource, packedLight, OverlayTexture.NO_OVERLAY, model); + poseStack.popPose(); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java b/1.21/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java new file mode 100644 index 0000000..6a3b315 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java @@ -0,0 +1,17 @@ +package fuzs.visualworkbench.config; + +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; + +public class ClientConfig implements ConfigCore { + @Config(description = "Makes crafting table contents lay flat on the table instead of floating above.") + public boolean flatRendering = false; + @Config(description = "Render the result of the crafting operation in addition to crafting table contents.") + public boolean renderResult = true; + @Config(description = "Rotate crafting table contents so they always face the closest player.") + public RotateIngredients rotateIngredients = RotateIngredients.CLOSEST_PLAYER; + + public enum RotateIngredients { + CLOSEST_PLAYER, CRAFTING_PLAYER, NEVER + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java b/1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java new file mode 100644 index 0000000..f9f8358 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java @@ -0,0 +1,9 @@ +package fuzs.visualworkbench.config; + +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; + +public class ServerConfig implements ConfigCore { + @Config(description = "Leftover vanilla crafting tables in a world become unusable until they are broken and replaced.") + public boolean disableVanillaWorkbench = true; +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java b/1.21/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java new file mode 100644 index 0000000..1920a4c --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java @@ -0,0 +1,21 @@ +package fuzs.visualworkbench.data; + +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.puzzleslib.api.data.v2.tags.AbstractTagProvider; +import fuzs.visualworkbench.init.ModRegistry; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; + +public class ModBlockTagsProvider extends AbstractTagProvider { + + public ModBlockTagsProvider(DataProviderContext context) { + super(Registries.BLOCK, context); + } + + @Override + public void addTags(HolderLookup.Provider provider) { + this.add(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG).add(Blocks.SMITHING_TABLE, Blocks.FLETCHING_TABLE); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java b/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java new file mode 100644 index 0000000..57aaff6 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java @@ -0,0 +1,31 @@ +package fuzs.visualworkbench.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractModelProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import net.minecraft.data.models.BlockModelGenerators; +import net.minecraft.data.models.blockstates.MultiVariantGenerator; +import net.minecraft.data.models.blockstates.Variant; +import net.minecraft.data.models.blockstates.VariantProperties; +import net.minecraft.data.models.model.ModelLocationUtils; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; + +public class DynamicModelProvider extends AbstractModelProvider { + + public DynamicModelProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addBlockModels(BlockModelGenerators builder) { + // dynamically generate a basic stone block model for every diagonal block so the model bakery logs no missing model + // don't use an air model so the blocks remain visible + ResourceLocation resourceLocation = ModelLocationUtils.getModelLocation(Blocks.STONE); + BlockConversionHandler.BLOCK_CONVERSIONS.values().forEach((Block block) -> { + builder.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, resourceLocation))); + builder.skipAutoItemBlock(block); + }); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java b/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..59b5923 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java @@ -0,0 +1,19 @@ +package fuzs.visualworkbench.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import fuzs.visualworkbench.init.ModRegistry; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(BlockConversionHandler.INVALID_BLOCK_COMPONENT, "Unable to open. Break and replace to use."); + builder.add(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG, "Unaltered Workbenches"); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java new file mode 100644 index 0000000..1191bd0 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java @@ -0,0 +1,99 @@ +package fuzs.visualworkbench.handler; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import fuzs.puzzleslib.api.block.v1.BlockConversionHelper; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.puzzleslib.api.init.v3.registry.RegistryHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ServerConfig; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.level.block.CraftingTableWithInventoryBlock; +import net.minecraft.ChatFormatting; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CraftingTableBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +public class BlockConversionHandler { + public static final Component INVALID_BLOCK_COMPONENT = Component.translatable("container.invalidBlock"); + public static final BiMap BLOCK_CONVERSIONS = HashBiMap.create(); + + public static void onRegistryEntryAdded(Registry registry, ResourceLocation id, Block block, BiConsumer> registrar) { + if (block instanceof CraftingTableBlock) { + ResourceLocation resourceLocation = VisualWorkbench.id(id.getNamespace() + "/" + id.getPath()); + registrar.accept(resourceLocation, () -> { + Block newBlock = new CraftingTableWithInventoryBlock(block); + BLOCK_CONVERSIONS.put(block, newBlock); + return newBlock; + }); + } + } + + public static EventResultHolder onUseBlock(Player player, Level level, InteractionHand interactionHand, BlockHitResult hitResult) { + if (!VisualWorkbench.CONFIG.get(ServerConfig.class).disableVanillaWorkbench) return EventResultHolder.pass(); + BlockState blockState = level.getBlockState(hitResult.getBlockPos()); + if (BLOCK_CONVERSIONS.containsKey(blockState.getBlock()) && !blockState.is(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG)) { + player.displayClientMessage(Component.empty().append(INVALID_BLOCK_COMPONENT).withStyle(ChatFormatting.RED), true); + return EventResultHolder.interrupt(InteractionResult.sidedSuccess(level.isClientSide)); + } else { + return EventResultHolder.pass(); + } + } + + public static void onTagsUpdated(RegistryAccess registryAccess, boolean client) { + for (Map.Entry, Item> entry : BuiltInRegistries.ITEM.entrySet()) { + if (entry.getValue() instanceof BlockItem blockItem) { + Block block = blockItem.getBlock(); + setItemForBlock(entry.getKey().location(), blockItem, block); + setBlockForItem(blockItem, block); + } + } + if (!client) { + BLOCK_CONVERSIONS.forEach(BlockConversionHelper::copyBoundTags); + } + } + + private static void setItemForBlock(ResourceLocation resourceLocation, BlockItem blockItem, Block block) { + if (block instanceof CraftingTableBlock) { + BlockConversionHelper.setItemForBlock(BLOCK_CONVERSIONS.get(block), blockItem); + } + } + + private static void setBlockForItem(BlockItem blockItem, Block block) { + Block baseBlock; + Block diagonalBlock = BLOCK_CONVERSIONS.get(block); + if (diagonalBlock != null) { + baseBlock = block; + } else { + baseBlock = BLOCK_CONVERSIONS.inverse().get(block); + if (baseBlock != null) { + diagonalBlock = block; + } else { + return; + } + } + if (RegistryHelper.is(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG, baseBlock)) { + BlockConversionHelper.setBlockForItem(blockItem, baseBlock); + } else { + BlockConversionHelper.setBlockForItem(blockItem, diagonalBlock); + } + } + +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java new file mode 100644 index 0000000..729f635 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java @@ -0,0 +1,37 @@ +package fuzs.visualworkbench.init; + +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; +import fuzs.puzzleslib.api.init.v3.tags.BoundTagFactory; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.core.Holder; +import net.minecraft.tags.TagKey; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.from(VisualWorkbench.MOD_ID); + public static final Holder.Reference> CRAFTING_TABLE_BLOCK_ENTITY = REGISTRY.registerBlockEntityType( + "crafting_table", + () -> { + BlockEntityType.Builder builder = BlockEntityType.Builder.of( + CraftingTableBlockEntity::new); + builder.validBlocks = BlockConversionHandler.BLOCK_CONVERSIONS.values(); + return builder; + } + ); + public static final Holder.Reference> CRAFTING_MENU_TYPE = REGISTRY.registerMenuType( + "crafting", + () -> VisualCraftingMenu::new + ); + + static final BoundTagFactory TAGS = BoundTagFactory.make(VisualWorkbench.MOD_ID); + public static final TagKey UNALTERED_WORKBENCHES_BLOCK_TAG = TAGS.registerBlockTag("unaltered_workbenches"); + + public static void touch() { + // NO-OP + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java b/1.21/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java new file mode 100644 index 0000000..9696586 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java @@ -0,0 +1,24 @@ +package fuzs.visualworkbench.integration.jei; + +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.RecipeTypes; +import mezz.jei.api.registration.IRecipeTransferRegistration; +import net.minecraft.resources.ResourceLocation; + +@JeiPlugin +public class VisualWorkbenchJEIPlugin implements IModPlugin { + + @Override + public ResourceLocation getPluginUid() { + return VisualWorkbench.id("crafting"); + } + + @Override + public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { + registration.addRecipeTransferHandler(VisualCraftingMenu.class, ModRegistry.CRAFTING_MENU_TYPE.value(), RecipeTypes.CRAFTING, 1, 9, 10, 36); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java new file mode 100644 index 0000000..b8e23d7 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -0,0 +1,59 @@ +package fuzs.visualworkbench.world.inventory; + +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.*; + +public class VisualCraftingMenu extends CraftingMenu { + + public VisualCraftingMenu(int id, Inventory inventory) { + super(id, inventory); + } + + public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { + super(id, inventory, access); + this.craftSlots = new VisualTransientCraftingContainer(this, 3, 3, blockEntity.getItems(), blockEntity); + this.resultSlots = new VisualResultContainer(blockEntity.getResultItems(), blockEntity); + this.setCraftingSlotsContainer(); + // always update recipe output when opening menu, otherwise could be missing or outdated if the block entity didn't save it correctly + this.refreshRecipeResult(); + } + + private void setCraftingSlotsContainer() { + for (int i = 0; i < 10; i++) { + Slot slot = this.getSlot(i); + if (slot instanceof ResultSlot resultSlot) { + resultSlot.craftSlots = this.craftSlots; + slot.container = this.resultSlots; + } else if (slot.container instanceof TransientCraftingContainer) { + slot.container = this.craftSlots; + } + } + } + + private void refreshRecipeResult() { + this.slotsChanged(this.craftSlots); + } + + @Override + public MenuType getType() { + return ModRegistry.CRAFTING_MENU_TYPE.value(); + } + + @Override + public void removed(Player player) { + // prevent items from being cleared out of the container + ContainerLevelAccess containerLevelAccess = this.access; + this.access = ContainerLevelAccess.NULL; + super.removed(player); + this.access = containerLevelAccess; + } + + @Override + public boolean stillValid(Player player) { + // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true + return this.craftSlots.stillValid(player); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java new file mode 100644 index 0000000..06c03ca --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java @@ -0,0 +1,40 @@ +package fuzs.visualworkbench.world.inventory; + +import net.minecraft.core.NonNullList; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ResultContainer; +import net.minecraft.world.item.ItemStack; + +public class VisualResultContainer extends ResultContainer { + private final Container container; + + public VisualResultContainer(NonNullList items, Container container) { + this.container = container; + this.itemStacks = items; + } + + @Override + public ItemStack removeItem(int slot, int amount) { + ItemStack result = super.removeItem(slot, amount); + if (!result.isEmpty()) this.setChanged(); + return result; + } + + @Override + public void setItem(int slot, ItemStack stack) { + super.setItem(slot, stack); + this.setChanged(); + } + + @Override + public void setChanged() { + super.setChanged(); + this.container.setChanged(); + } + + @Override + public boolean stillValid(Player player) { + return this.container.stillValid(player); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java new file mode 100644 index 0000000..9f24398 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java @@ -0,0 +1,41 @@ +package fuzs.visualworkbench.world.inventory; + +import net.minecraft.core.NonNullList; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.TransientCraftingContainer; +import net.minecraft.world.item.ItemStack; + +public class VisualTransientCraftingContainer extends TransientCraftingContainer { + private final Container container; + + public VisualTransientCraftingContainer(AbstractContainerMenu menu, int width, int height, NonNullList items, Container container) { + super(menu, width, height, items); + this.container = container; + } + + @Override + public ItemStack removeItem(int slot, int amount) { + ItemStack itemStack = super.removeItem(slot, amount); + if (!itemStack.isEmpty()) this.setChanged(); + return itemStack; + } + + @Override + public void setItem(int slot, ItemStack stack) { + super.setItem(slot, stack); + this.setChanged(); + } + + @Override + public void setChanged() { + super.setChanged(); + this.container.setChanged(); + } + + @Override + public boolean stillValid(Player player) { + return this.container.stillValid(player); + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java new file mode 100644 index 0000000..4f599c9 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java @@ -0,0 +1,90 @@ +package fuzs.visualworkbench.world.level.block; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import fuzs.puzzleslib.api.block.v1.entity.TickingEntityBlock; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.stats.Stats; +import net.minecraft.world.Containers; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BlockTypes; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +import java.util.function.Predicate; + +public class CraftingTableWithInventoryBlock extends BaseEntityBlock implements TickingEntityBlock { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group(BlockTypes.CODEC.fieldOf("block").forGetter(block -> block.block)).apply(instance, CraftingTableWithInventoryBlock::new) + ); + + private final Block block; + + public CraftingTableWithInventoryBlock(Block block) { + super(BlockBehaviour.Properties.ofFullCopy(block).dropsLike(block)); + this.block = block; + } + + @Override + public String getDescriptionId() { + return this.block.getDescriptionId(); + } + + @Override + protected MapCodec codec() { + return CODEC; + } + + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Override + public BlockEntityType getBlockEntityType() { + return ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(); + } + + @Override + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + if (level.isClientSide) { + return InteractionResult.SUCCESS; + } else if (level.getBlockEntity(pos) instanceof CraftingTableBlockEntity blockEntity) { + player.openMenu(blockEntity); + player.awardStat(Stats.INTERACT_WITH_CRAFTING_TABLE); + } + + return InteractionResult.CONSUME; + } + + @Override + public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) { + Containers.dropContentsOnDestroy(state, newState, level, pos); + super.onRemove(state, level, pos, newState, movedByPiston); + } + + @Override + public boolean hasAnalogOutputSignal(BlockState blockState) { + return true; + } + + @Override + public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos blockPos) { + // similar to Crafter + if (level.getBlockEntity(blockPos) instanceof CraftingTableBlockEntity blockEntity) { + return (int) blockEntity.getItems().stream().filter(Predicate.not(ItemStack::isEmpty)).count(); + } else { + return 0; + } + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java new file mode 100644 index 0000000..2091af1 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java @@ -0,0 +1,116 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import fuzs.puzzleslib.api.core.v1.Proxy; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.ClientConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.CraftingScreen; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +/** + * A client-side provider for ticking and storing crafting table item animations on a block entity. + *

Initialize an instance in your block entity constructor, then implement a call for {@link CraftingTableAnimationController#tick(Level)} on the client. + *

Make sure the code is never accidentally called on the server as it accesses client-only classes. + *

All animation code in this class is taken from the old RealBench mod. + */ +public class CraftingTableAnimationController { + private final Vec3 position; + public int ticks; + public float currentAngle; + public float nextAngle; + public int sector; + public boolean animating; + public float animationAngleStart; + public float animationAngleEnd; + public double startTicks; + public double playerAngle; + + public CraftingTableAnimationController(BlockPos blockPos) { + this.position = blockPos.getCenter(); + } + + public void tick(Level level) { + ++this.ticks; + this.setPlayerAngle(level); + this.setCurrentSector(); + this.tryAnimate(); + } + + private void setPlayerAngle(Level level) { + Player player; + if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients != ClientConfig.RotateIngredients.NEVER) { + player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, (Entity entity) -> { + if (entity.isSpectator()) { + return false; + } else if (VisualWorkbench.CONFIG.get(ClientConfig.class).rotateIngredients == ClientConfig.RotateIngredients.CLOSEST_PLAYER) { + return true; + } else { + if (entity == Proxy.INSTANCE.getClientPlayer()) { + return Minecraft.getInstance().screen instanceof CraftingScreen; + } else { + return false; + } + } + }); + } else { + player = null; + } + if (player != null) { + double d0 = player.getX() - this.position.x(); + double d1 = player.getZ() - this.position.z(); + this.playerAngle = (Math.atan2(-d0, -d1) + 3.9269908169872414D) % 6.283185307179586D; + } + } + + private void setCurrentSector() { + int sector = (int) (this.playerAngle * 2.0 / Math.PI); + if (this.sector != sector) { + this.animating = true; + this.animationAngleStart = this.currentAngle; + float delta1 = sector * 90.0F - this.currentAngle; + float abs1 = Math.abs(delta1); + float delta2 = delta1 + 360.0F; + float shift = Math.abs(delta2); + float delta3 = delta1 - 360.0F; + float abs3 = Math.abs(delta3); + if (abs3 < abs1 && abs3 < shift) { + this.animationAngleEnd = delta3 + this.currentAngle; + } else if (shift < abs1 && shift < abs3) { + this.animationAngleEnd = delta2 + this.currentAngle; + } else { + this.animationAngleEnd = delta1 + this.currentAngle; + } + this.startTicks = this.ticks; + this.sector = sector; + } + } + + private void tryAnimate() { + if (this.animating) { + if (this.ticks >= this.startTicks + 20) { + this.animating = false; + this.currentAngle = this.nextAngle = (this.animationAngleEnd + 360.0F) % 360.0F; + } else { + this.currentAngle = (calcEaseOutQuad(this.ticks - this.startTicks, this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; + this.nextAngle = (calcEaseOutQuad(Math.min(this.ticks + 1 - this.startTicks, 20), this.animationAngleStart, this.animationAngleEnd - this.animationAngleStart, 20.0) + 360.0F) % 360.0F; + if (this.currentAngle != 0.0F || this.nextAngle != 0.0F) { + if (this.currentAngle == 0.0F && this.nextAngle >= 180.0F) { + this.currentAngle = 360.0F; + } + if (this.nextAngle == 0.0F && this.currentAngle >= 180.0F) { + this.nextAngle = 360.0F; + } + } + } + } + } + + private static float calcEaseOutQuad(double t, float b, float c, double d) { + float z = (float) t / (float) d; + return -c * z * (z - 2.0F) + b; + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java new file mode 100644 index 0000000..82fecff --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -0,0 +1,131 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; +import fuzs.puzzleslib.api.container.v1.ContainerItemHelper; +import fuzs.puzzleslib.api.container.v1.ContainerSerializationHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.Container; +import net.minecraft.world.ContainerHelper; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity implements TickingBlockEntity, WorkbenchVisualsProvider { + public static final MutableComponent COMPONENT_CRAFTING = Component.translatable("container.crafting"); + public static final String TAG_RESULT = VisualWorkbench.id("result").toString(); + + private final CraftingTableAnimationController animationController; + private final NonNullList items = NonNullList.withSize(9, ItemStack.EMPTY); + private final NonNullList resultItems = NonNullList.withSize(1, ItemStack.EMPTY); + + public CraftingTableBlockEntity(BlockPos pos, BlockState blockState) { + super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), pos, blockState); + this.animationController = new CraftingTableAnimationController(pos); + } + + @Override + public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + this.items.clear(); + this.resultItems.clear(); + if (!this.tryLoadLootTable(tag)) { + ContainerHelper.loadAllItems(tag, this.items, registries); + ContainerSerializationHelper.loadAllItems(TAG_RESULT, tag, this.resultItems, registries); + } + } + + @Override + protected void saveAdditional(CompoundTag compoundTag, HolderLookup.Provider registries) { + super.saveAdditional(compoundTag, registries); + if (!this.trySaveLootTable(compoundTag)) { + ContainerHelper.saveAllItems(compoundTag, this.items, registries); + ContainerSerializationHelper.saveAllItems(TAG_RESULT, compoundTag, this.resultItems, registries); + } + } + + @Override + @Nullable + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + return this.saveWithoutMetadata(registries); + } + + @Override + public void setChanged() { + super.setChanged(); + if (this.level != null) { + this.level.sendBlockUpdated(this.worldPosition, this.getBlockState(), this.getBlockState(), 3); + } + } + + @Override + public NonNullList getItems() { + return this.items; + } + + @Override + protected void setItems(NonNullList items) { + ContainerItemHelper.copyItemsToContainer(this, items); + } + + @Override + protected Component getDefaultName() { + return COMPONENT_CRAFTING; + } + + @Override + protected AbstractContainerMenu createMenu(int containerId, Inventory inventory) { + return new VisualCraftingMenu(containerId, + inventory, + this, + ContainerLevelAccess.create(this.getLevel(), this.getBlockPos()) + ); + } + + @Override + public int getContainerSize() { + return this.items.size(); + } + + @Override + public boolean stillValid(Player player) { + return Container.stillValidBlockEntity(this, player); + } + + @Override + public void clientTick() { + this.animationController.tick(this.getLevel()); + } + + public NonNullList getResultItems() { + return this.resultItems; + } + + @Override + public ItemStack getCraftingResult() { + return this.resultItems.get(0); + } + + @Override + public CraftingTableAnimationController getAnimationController() { + return this.animationController; + } +} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java new file mode 100644 index 0000000..3962ba5 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java @@ -0,0 +1,22 @@ +package fuzs.visualworkbench.world.level.block.entity; + +import net.minecraft.world.item.ItemStack; + +/** + * An extension for a {@link net.minecraft.world.level.block.entity.BlockEntity} providing access to data required for rendering. + */ +public interface WorkbenchVisualsProvider { + + /** + * Get the crafting result for the currently stored ingredients. + *

Can return {@link ItemStack#EMPTY} to not render anything. + * + * @return the crafting result + */ + ItemStack getCraftingResult(); + + /** + * @return storage for animation data + */ + CraftingTableAnimationController getAnimationController(); +} diff --git a/1.21/Common/src/main/resources/architectury.common.json b/1.21/Common/src/main/resources/architectury.common.json new file mode 100644 index 0000000..822cfd0 --- /dev/null +++ b/1.21/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "visualworkbench.accesswidener" +} \ No newline at end of file diff --git a/1.21/Common/src/main/resources/common.mixins.json b/1.21/Common/src/main/resources/common.mixins.json new file mode 100644 index 0000000..77fc8f4 --- /dev/null +++ b/1.21/Common/src/main/resources/common.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.21/Common/src/main/resources/mod_banner.png b/1.21/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..7b831557d05a594b4656129c710ca01c24ed72a2 GIT binary patch literal 17426 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 Vw-nuebjbh!002ovPDHLkV1mL?sY(C< literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/mod_logo.png b/1.21/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6715625ac40927c660208cd97c0aba641822edb8 GIT binary patch literal 9349 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", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.21/NeoForge/build.gradle b/1.21/NeoForge/build.gradle new file mode 100644 index 0000000..15a3f5c --- /dev/null +++ b/1.21/NeoForge/build.gradle @@ -0,0 +1,10 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/neoforge.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.neoforge + + // Just Enough Items + compileOnly libs.jeiapi.common + modLocalRuntime libs.jei.neoforge +} diff --git a/1.21/NeoForge/gradle.properties b/1.21/NeoForge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/1.21/NeoForge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java b/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java new file mode 100644 index 0000000..9d33e3f --- /dev/null +++ b/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java @@ -0,0 +1,16 @@ +package fuzs.visualworkbench.neoforge; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.data.ModBlockTagsProvider; +import net.neoforged.fml.common.Mod; + +@Mod(VisualWorkbench.MOD_ID) +public class VisualWorkbenchNeoForge { + + public VisualWorkbenchNeoForge() { + ModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbench::new); + DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModBlockTagsProvider::new); + } +} diff --git a/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java b/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java new file mode 100644 index 0000000..7f1c0db --- /dev/null +++ b/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java @@ -0,0 +1,18 @@ +package fuzs.visualworkbench.neoforge.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.client.VisualWorkbenchClient; +import fuzs.visualworkbench.data.client.ModLanguageProvider; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.common.Mod; + +@Mod(value = VisualWorkbench.MOD_ID, dist = Dist.CLIENT) +public class VisualWorkbenchNeoForgeClient { + + public VisualWorkbenchNeoForgeClient() { + ClientModConstructor.construct(VisualWorkbench.MOD_ID, VisualWorkbenchClient::new); + DataProviderHelper.registerDataProviders(VisualWorkbench.MOD_ID, ModLanguageProvider::new); + } +} diff --git a/1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml b/1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..ef10121 --- /dev/null +++ b/1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,49 @@ +modLoader = "javafml" +loaderVersion = "*" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[mixins]] +config="${modId}.common.mixins.json" + +[[mixins]] +config="${modId}.neoforge.mixins.json" + +[[dependencies.${ modId }]] +modId = "neoforge" +mandatory = true +type = "required" +versionRange = "[${minNeoForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +type = "required" +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +type = "required" +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.21/NeoForge/src/main/resources/neoforge.mixins.json b/1.21/NeoForge/src/main/resources/neoforge.mixins.json new file mode 100644 index 0000000..1fb3919 --- /dev/null +++ b/1.21/NeoForge/src/main/resources/neoforge.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.neoforge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.21/build.gradle b/1.21/build.gradle new file mode 100644 index 0000000..dea2bca --- /dev/null +++ b/1.21/build.gradle @@ -0,0 +1,9 @@ +plugins { + alias libs.plugins.architecturyloom apply false + alias libs.plugins.architecturyplugin apply false + alias libs.plugins.shadow apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/main.gradle" diff --git a/1.21/gradle.properties b/1.21/gradle.properties new file mode 100755 index 0000000..6eac445 --- /dev/null +++ b/1.21/gradle.properties @@ -0,0 +1,45 @@ +org.gradle.jvmargs=-Xmx4G +org.gradle.daemon=false +copyBuildJar=true + +# Mod Attributes +modId=visualworkbench +modName=Visual Workbench +modVersion=21.0.0 +modAuthor=Fuzs +modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/visualworkbench +modIssueUrl=https://github.com/Fuzss/visualworkbench/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/visualworkbench.json +modMavenGroup=fuzs.visualworkbench +# "MATCH_VERSION" for a mod required on both sides, "IGNORE_SERVER_VERSION" for a server only mod, "IGNORE_ALL_VERSION" for a client only mod +modForgeDisplayTest=MATCH_VERSION +# "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod +modFabricEnvironment=* + +# Version Catalog +dependenciesVersionCatalog=1.21-v8 +dependenciesPuzzlesLibVersion=21.0.6 +dependenciesMinPuzzlesLibVersion=21.0.6 + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=682567 +projectModrinthId=OZBR5JT5 + +# Required Dependencies +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredNeoForgeCurseForge=puzzles-lib +dependenciesRequiredForgeCurseForge=forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +dependenciesRequiredNeoForgeModrinth=puzzles-lib +dependenciesRequiredForgeModrinth=forge-config-api-port, puzzles-lib + +# Optional Dependencies +dependenciesOptionalFabricCurseForge=config-menus-forge +dependenciesOptionalNeoForgeCurseForge=config-menus-forge +dependenciesOptionalForgeCurseForge=config-menus-forge +dependenciesOptionalFabricModrinth=forge-config-screens +dependenciesOptionalNeoForgeModrinth=forge-config-screens +dependenciesOptionalForgeModrinth=forge-config-screens diff --git a/1.21/gradle/wrapper/gradle-wrapper.jar b/1.21/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/1.21/gradle/wrapper/gradle-wrapper.properties b/1.21/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2617362 --- /dev/null +++ b/1.21/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/1.21/gradlew b/1.21/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.21/gradlew @@ -0,0 +1,244 @@ +#!/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 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/HEAD/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 +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 + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +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 ;; #( + 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 + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + 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 +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +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" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + 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 + # 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 +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 \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# 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/1.21/gradlew.bat b/1.21/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.21/gradlew.bat @@ -0,0 +1,92 @@ +@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 +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +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="-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% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +: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 %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.21/settings.gradle b/1.21/settings.gradle new file mode 100644 index 0000000..5cfe5eb --- /dev/null +++ b/1.21/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url "https://maven.architectury.dev/" } + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.neoforged.net/releases/" } + maven { url "https://maven.minecraftforge.net/" } + } +} + +include "Common" +include "Fabric" +include "NeoForge" +//include "Forge" + +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From 7edd69c6ff7e5ef278ee3c1c321624927ddbe944 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 6 Jul 2024 23:30:05 +0200 Subject: [PATCH 08/16] Update gradle.properties --- 1.21/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 6eac445..5f11139 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -25,8 +25,8 @@ dependenciesMinPuzzlesLibVersion=21.0.6 # Mod Publishing projectReleaseType=release -projectCurseForgeId=682567 -projectModrinthId=OZBR5JT5 +projectCurseForgeId=500273 +projectModrinthId=kfqD1JRw # Required Dependencies dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib From be3edc88d3b0221100a4915760a12572673d0139 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sun, 7 Jul 2024 08:49:46 +0200 Subject: [PATCH 09/16] update puzzles lib --- 1.21/CHANGELOG.md | 4 ++++ .../visualworkbench/client/handler/BlockModelHandler.java | 5 ++--- 1.21/gradle.properties | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 1a62a4b..85c9fd2 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v21.0.1-1.21] - 2024-07-07 +### Changed +- Updated for Puzzles Lib v21.0.8 + ## [v21.0.0-1.21] - 2024-07-06 - Port to Minecraft 1.21 - Forge is no longer support in favor of NeoForge diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java index a0212d4..f023106 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java @@ -41,10 +41,9 @@ public static void onLoadComplete() { } } - public static EventResultHolder onModifyUnbakedModel(ModelResourceLocation modelLocation, Supplier unbakedModel, Function modelGetter, BiConsumer modelAdder) { + public static EventResultHolder onModifyUnbakedModel(ModelResourceLocation modelLocation, Supplier unbakedModel, Function modelGetter, BiConsumer modelAdder) { if (MODEL_LOCATIONS.get().containsKey(modelLocation)) { - ResourceLocation resourceLocation = MODEL_LOCATIONS.get().get(modelLocation).id().withPrefix("block/"); - return EventResultHolder.interrupt(modelGetter.apply(resourceLocation)); + return EventResultHolder.interrupt(modelGetter.apply(MODEL_LOCATIONS.get().get(modelLocation))); } else { return EventResultHolder.pass(); } diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 5f11139..1e9f431 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=21.0.0 +modVersion=21.0.1 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -20,8 +20,8 @@ modFabricEnvironment=* # Version Catalog dependenciesVersionCatalog=1.21-v8 -dependenciesPuzzlesLibVersion=21.0.6 -dependenciesMinPuzzlesLibVersion=21.0.6 +dependenciesPuzzlesLibVersion=21.0.8 +dependenciesMinPuzzlesLibVersion=21.0.8 # Mod Publishing projectReleaseType=release From 739833a6120182e7b8821bc00ecce114cd46f27f Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:50:03 +0200 Subject: [PATCH 10/16] try fix fastbench mod --- 1.21/CHANGELOG.md | 5 ++ .../handler/BlockConversionHandler.java | 4 +- .../world/inventory/VisualCraftingMenu.java | 57 ++++++++++++------- .../inventory/VisualResultContainer.java | 40 ------------- .../VisualTransientCraftingContainer.java | 41 ------------- .../resources/visualworkbench.accesswidener | 7 +-- 1.21/gradle.properties | 8 +-- 7 files changed, 47 insertions(+), 115 deletions(-) delete mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java delete mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 85c9fd2..1154720 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v21.0.2-1.21] - 2024-07-23 +### Fixed +- Fix incompatibility with FastBench mod +- Fix crafting tables ignoring tools when breaking in multiplayer + ## [v21.0.1-1.21] - 2024-07-07 ### Changed - Updated for Puzzles Lib v21.0.8 diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java index 1191bd0..0212b48 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java @@ -65,9 +65,7 @@ public static void onTagsUpdated(RegistryAccess registryAccess, boolean client) setBlockForItem(blockItem, block); } } - if (!client) { - BLOCK_CONVERSIONS.forEach(BlockConversionHelper::copyBoundTags); - } + BLOCK_CONVERSIONS.forEach(BlockConversionHelper::copyBoundTags); } private static void setItemForBlock(ResourceLocation resourceLocation, BlockItem blockItem, Block block) { diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java index b8e23d7..eb76dde 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -2,38 +2,29 @@ import fuzs.visualworkbench.init.ModRegistry; import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.world.Container; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.*; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; -public class VisualCraftingMenu extends CraftingMenu { +public class VisualCraftingMenu extends CraftingMenu implements ContainerListener { + private final Container container; public VisualCraftingMenu(int id, Inventory inventory) { super(id, inventory); + this.container = null; } public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { super(id, inventory, access); - this.craftSlots = new VisualTransientCraftingContainer(this, 3, 3, blockEntity.getItems(), blockEntity); - this.resultSlots = new VisualResultContainer(blockEntity.getResultItems(), blockEntity); - this.setCraftingSlotsContainer(); + ((TransientCraftingContainer) this.craftSlots).items = blockEntity.getItems(); + this.resultSlots.itemStacks = blockEntity.getResultItems(); + this.container = blockEntity; + this.addSlotListener(this); // always update recipe output when opening menu, otherwise could be missing or outdated if the block entity didn't save it correctly - this.refreshRecipeResult(); - } - - private void setCraftingSlotsContainer() { - for (int i = 0; i < 10; i++) { - Slot slot = this.getSlot(i); - if (slot instanceof ResultSlot resultSlot) { - resultSlot.craftSlots = this.craftSlots; - slot.container = this.resultSlots; - } else if (slot.container instanceof TransientCraftingContainer) { - slot.container = this.craftSlots; - } - } - } - - private void refreshRecipeResult() { this.slotsChanged(this.craftSlots); } @@ -42,6 +33,16 @@ public MenuType getType() { return ModRegistry.CRAFTING_MENU_TYPE.value(); } + @Override + public void slotsChanged(Container container) { + super.slotsChanged(container); + if (container == this.craftSlots || container == this.resultSlots) { + this.access.execute((Level level, BlockPos blockPos) -> { + this.container.setChanged(); + }); + } + } + @Override public void removed(Player player) { // prevent items from being cleared out of the container @@ -53,7 +54,19 @@ public void removed(Player player) { @Override public boolean stillValid(Player player) { - // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true - return this.craftSlots.stillValid(player); + return this.access.evaluate((Level level, BlockPos blockPos) -> { + // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true + return this.container.stillValid(player); + }, true); + } + + @Override + public void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack itemStack) { + if (dataSlotIndex >= 0 && dataSlotIndex < this.getSize()) this.container.setChanged(); + } + + @Override + public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) { + // NO-OP } } diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java deleted file mode 100644 index 06c03ca..0000000 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualResultContainer.java +++ /dev/null @@ -1,40 +0,0 @@ -package fuzs.visualworkbench.world.inventory; - -import net.minecraft.core.NonNullList; -import net.minecraft.world.Container; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ResultContainer; -import net.minecraft.world.item.ItemStack; - -public class VisualResultContainer extends ResultContainer { - private final Container container; - - public VisualResultContainer(NonNullList items, Container container) { - this.container = container; - this.itemStacks = items; - } - - @Override - public ItemStack removeItem(int slot, int amount) { - ItemStack result = super.removeItem(slot, amount); - if (!result.isEmpty()) this.setChanged(); - return result; - } - - @Override - public void setItem(int slot, ItemStack stack) { - super.setItem(slot, stack); - this.setChanged(); - } - - @Override - public void setChanged() { - super.setChanged(); - this.container.setChanged(); - } - - @Override - public boolean stillValid(Player player) { - return this.container.stillValid(player); - } -} diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java deleted file mode 100644 index 9f24398..0000000 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualTransientCraftingContainer.java +++ /dev/null @@ -1,41 +0,0 @@ -package fuzs.visualworkbench.world.inventory; - -import net.minecraft.core.NonNullList; -import net.minecraft.world.Container; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.TransientCraftingContainer; -import net.minecraft.world.item.ItemStack; - -public class VisualTransientCraftingContainer extends TransientCraftingContainer { - private final Container container; - - public VisualTransientCraftingContainer(AbstractContainerMenu menu, int width, int height, NonNullList items, Container container) { - super(menu, width, height, items); - this.container = container; - } - - @Override - public ItemStack removeItem(int slot, int amount) { - ItemStack itemStack = super.removeItem(slot, amount); - if (!itemStack.isEmpty()) this.setChanged(); - return itemStack; - } - - @Override - public void setItem(int slot, ItemStack stack) { - super.setItem(slot, stack); - this.setChanged(); - } - - @Override - public void setChanged() { - super.setChanged(); - this.container.setChanged(); - } - - @Override - public boolean stillValid(Player player) { - return this.container.stillValid(player); - } -} diff --git a/1.21/Common/src/main/resources/visualworkbench.accesswidener b/1.21/Common/src/main/resources/visualworkbench.accesswidener index f6b21e6..dc12db6 100644 --- a/1.21/Common/src/main/resources/visualworkbench.accesswidener +++ b/1.21/Common/src/main/resources/visualworkbench.accesswidener @@ -2,13 +2,10 @@ accessWidener v2 named accessible field net/minecraft/world/level/block/entity/BlockEntityType$Builder validBlocks Ljava/util/Set; mutable field net/minecraft/world/level/block/entity/BlockEntityType$Builder validBlocks Ljava/util/Set; accessible field net/minecraft/world/inventory/CraftingMenu craftSlots Lnet/minecraft/world/inventory/CraftingContainer; -mutable field net/minecraft/world/inventory/CraftingMenu craftSlots Lnet/minecraft/world/inventory/CraftingContainer; accessible field net/minecraft/world/inventory/CraftingMenu resultSlots Lnet/minecraft/world/inventory/ResultContainer; -mutable field net/minecraft/world/inventory/CraftingMenu resultSlots Lnet/minecraft/world/inventory/ResultContainer; accessible field net/minecraft/world/inventory/CraftingMenu access Lnet/minecraft/world/inventory/ContainerLevelAccess; mutable field net/minecraft/world/inventory/CraftingMenu access Lnet/minecraft/world/inventory/ContainerLevelAccess; +accessible field net/minecraft/world/inventory/TransientCraftingContainer items Lnet/minecraft/core/NonNullList; +mutable field net/minecraft/world/inventory/TransientCraftingContainer items Lnet/minecraft/core/NonNullList; accessible field net/minecraft/world/inventory/ResultContainer itemStacks Lnet/minecraft/core/NonNullList; mutable field net/minecraft/world/inventory/ResultContainer itemStacks Lnet/minecraft/core/NonNullList; -accessible field net/minecraft/world/inventory/ResultSlot craftSlots Lnet/minecraft/world/inventory/CraftingContainer; -mutable field net/minecraft/world/inventory/ResultSlot craftSlots Lnet/minecraft/world/inventory/CraftingContainer; -mutable field net/minecraft/world/inventory/Slot container Lnet/minecraft/world/Container; diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 1e9f431..7f5991c 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=21.0.1 +modVersion=21.0.2 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -19,9 +19,9 @@ modForgeDisplayTest=MATCH_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.21-v8 -dependenciesPuzzlesLibVersion=21.0.8 -dependenciesMinPuzzlesLibVersion=21.0.8 +dependenciesVersionCatalog=1.21-v17 +#dependenciesPuzzlesLibVersion=21.0.8 +#dependenciesMinPuzzlesLibVersion=21.0.8 # Mod Publishing projectReleaseType=release From b48f97c4912a672423bc0f767b23ff593bd6664d Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:06:53 +0200 Subject: [PATCH 11/16] update for latest fabric api --- 1.21/CHANGELOG.md | 4 ++++ .../fuzs/visualworkbench/VisualWorkbench.java | 2 ++ .../client/VisualWorkbenchClient.java | 2 +- .../handler/BlockConversionHandler.java | 7 +++++++ .../fuzs/visualworkbench/init/ModRegistry.java | 16 +++------------- .../block/CraftingTableWithInventoryBlock.java | 2 +- .../block/entity/CraftingTableBlockEntity.java | 2 +- .../main/resources/visualworkbench.accesswidener | 2 -- 1.21/gradle.properties | 4 ++-- 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 1154720..6f22dda 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v21.0.3-1.21] - 2024-08-09 +### Changed +- Compatible with Fabric Api 1.21+0.102.0 + ## [v21.0.2-1.21] - 2024-07-23 ### Fixed - Fix incompatibility with FastBench mod diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java index 77e6849..776e38d 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java @@ -3,6 +3,7 @@ import fuzs.puzzleslib.api.config.v3.ConfigHolder; import fuzs.puzzleslib.api.core.v1.ModConstructor; import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; +import fuzs.puzzleslib.api.event.v1.AddBlockEntityTypeBlocksCallback; import fuzs.puzzleslib.api.event.v1.RegistryEntryAddedCallback; import fuzs.puzzleslib.api.event.v1.core.EventPhase; import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; @@ -31,6 +32,7 @@ public void onConstructMod() { private static void registerHandlers() { RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK).register(BlockConversionHandler::onRegistryEntryAdded); + AddBlockEntityTypeBlocksCallback.EVENT.register(BlockConversionHandler::onAddBlockEntityTypeBlocks); PlayerInteractEvents.USE_BLOCK.register(BlockConversionHandler::onUseBlock); TagsUpdatedCallback.EVENT.register(EventPhase.FIRST, BlockConversionHandler::onTagsUpdated); } diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java index 502fdc0..d1ee432 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java @@ -34,7 +34,7 @@ public void onRegisterMenuScreens(MenuScreensContext context) { @Override public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { - context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), CraftingTableBlockEntityRenderer::new); + context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(), CraftingTableBlockEntityRenderer::new); } @Override diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java index 0212b48..ba49d59 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java @@ -24,6 +24,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.CraftingTableBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; @@ -46,6 +47,12 @@ public static void onRegistryEntryAdded(Registry registry, ResourceLocati } } + public static void onAddBlockEntityTypeBlocks(BiConsumer, Block> consumer) { + BLOCK_CONVERSIONS.values().forEach((Block block) -> { + consumer.accept(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(), block); + }); + } + public static EventResultHolder onUseBlock(Player player, Level level, InteractionHand interactionHand, BlockHitResult hitResult) { if (!VisualWorkbench.CONFIG.get(ServerConfig.class).disableVanillaWorkbench) return EventResultHolder.pass(); BlockState blockState = level.getBlockState(hitResult.getBlockPos()); diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java index 729f635..b7b3861 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java @@ -3,7 +3,6 @@ import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; import fuzs.puzzleslib.api.init.v3.tags.BoundTagFactory; import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.handler.BlockConversionHandler; import fuzs.visualworkbench.world.inventory.VisualCraftingMenu; import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; import net.minecraft.core.Holder; @@ -14,19 +13,10 @@ public class ModRegistry { static final RegistryManager REGISTRY = RegistryManager.from(VisualWorkbench.MOD_ID); - public static final Holder.Reference> CRAFTING_TABLE_BLOCK_ENTITY = REGISTRY.registerBlockEntityType( - "crafting_table", - () -> { - BlockEntityType.Builder builder = BlockEntityType.Builder.of( - CraftingTableBlockEntity::new); - builder.validBlocks = BlockConversionHandler.BLOCK_CONVERSIONS.values(); - return builder; - } - ); + public static final Holder.Reference> CRAFTING_TABLE_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType( + "crafting_table", () -> BlockEntityType.Builder.of(CraftingTableBlockEntity::new)); public static final Holder.Reference> CRAFTING_MENU_TYPE = REGISTRY.registerMenuType( - "crafting", - () -> VisualCraftingMenu::new - ); + "crafting", () -> VisualCraftingMenu::new); static final BoundTagFactory TAGS = BoundTagFactory.make(VisualWorkbench.MOD_ID); public static final TagKey UNALTERED_WORKBENCHES_BLOCK_TAG = TAGS.registerBlockTag("unaltered_workbenches"); diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java index 4f599c9..caf409a 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java @@ -52,7 +52,7 @@ public RenderShape getRenderShape(BlockState state) { @Override public BlockEntityType getBlockEntityType() { - return ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(); + return ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(); } @Override diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java index 82fecff..45a2717 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -33,7 +33,7 @@ public class CraftingTableBlockEntity extends RandomizableContainerBlockEntity i private final NonNullList resultItems = NonNullList.withSize(1, ItemStack.EMPTY); public CraftingTableBlockEntity(BlockPos pos, BlockState blockState) { - super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY.value(), pos, blockState); + super(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(), pos, blockState); this.animationController = new CraftingTableAnimationController(pos); } diff --git a/1.21/Common/src/main/resources/visualworkbench.accesswidener b/1.21/Common/src/main/resources/visualworkbench.accesswidener index dc12db6..6608cde 100644 --- a/1.21/Common/src/main/resources/visualworkbench.accesswidener +++ b/1.21/Common/src/main/resources/visualworkbench.accesswidener @@ -1,6 +1,4 @@ accessWidener v2 named -accessible field net/minecraft/world/level/block/entity/BlockEntityType$Builder validBlocks Ljava/util/Set; -mutable field net/minecraft/world/level/block/entity/BlockEntityType$Builder validBlocks Ljava/util/Set; accessible field net/minecraft/world/inventory/CraftingMenu craftSlots Lnet/minecraft/world/inventory/CraftingContainer; accessible field net/minecraft/world/inventory/CraftingMenu resultSlots Lnet/minecraft/world/inventory/ResultContainer; accessible field net/minecraft/world/inventory/CraftingMenu access Lnet/minecraft/world/inventory/ContainerLevelAccess; diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 7f5991c..04b7ed3 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=21.0.2 +modVersion=21.0.3 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -19,7 +19,7 @@ modForgeDisplayTest=MATCH_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.21-v17 +dependenciesVersionCatalog=1.21-v23 #dependenciesPuzzlesLibVersion=21.0.8 #dependenciesMinPuzzlesLibVersion=21.0.8 From 71d4e0c0cf8db618443b828aa0f589e91d401e1d Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:19:42 +0200 Subject: [PATCH 12/16] fix NullPointerException in menu --- 1.21/CHANGELOG.md | 4 ++++ .../world/inventory/VisualCraftingMenu.java | 17 +++++++++++------ 1.21/gradle.properties | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 6f22dda..3582956 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v21.0.4-1.21] - 2024-08-16 +### Fixed +- Fix `NullPointerException` when interacting with the crafting table menu + ## [v21.0.3-1.21] - 2024-08-09 ### Changed - Compatible with Fabric Api 1.21+0.102.0 diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java index eb76dde..b4371fa 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java @@ -4,6 +4,7 @@ import fuzs.visualworkbench.world.level.block.entity.CraftingTableBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.world.Container; +import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.*; @@ -11,18 +12,18 @@ import net.minecraft.world.level.Level; public class VisualCraftingMenu extends CraftingMenu implements ContainerListener { - private final Container container; + private final Container blockEntity; public VisualCraftingMenu(int id, Inventory inventory) { super(id, inventory); - this.container = null; + this.blockEntity = new SimpleContainer(); } public VisualCraftingMenu(int id, Inventory inventory, CraftingTableBlockEntity blockEntity, ContainerLevelAccess access) { super(id, inventory, access); ((TransientCraftingContainer) this.craftSlots).items = blockEntity.getItems(); this.resultSlots.itemStacks = blockEntity.getResultItems(); - this.container = blockEntity; + this.blockEntity = blockEntity; this.addSlotListener(this); // always update recipe output when opening menu, otherwise could be missing or outdated if the block entity didn't save it correctly this.slotsChanged(this.craftSlots); @@ -38,7 +39,7 @@ public void slotsChanged(Container container) { super.slotsChanged(container); if (container == this.craftSlots || container == this.resultSlots) { this.access.execute((Level level, BlockPos blockPos) -> { - this.container.setChanged(); + this.blockEntity.setChanged(); }); } } @@ -56,13 +57,17 @@ public void removed(Player player) { public boolean stillValid(Player player) { return this.access.evaluate((Level level, BlockPos blockPos) -> { // craft slots are extended to forward this to the block entity, normally in vanilla this would always return true - return this.container.stillValid(player); + return this.blockEntity.stillValid(player); }, true); } @Override public void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack itemStack) { - if (dataSlotIndex >= 0 && dataSlotIndex < this.getSize()) this.container.setChanged(); + this.access.execute((Level level, BlockPos blockPos) -> { + if (dataSlotIndex >= 0 && dataSlotIndex < this.getSize()) { + this.blockEntity.setChanged(); + } + }); } @Override diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 04b7ed3..47e0314 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=21.0.3 +modVersion=21.0.4 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 From b111133a50611647988516258b5181086dce389f Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:16:56 +0200 Subject: [PATCH 13/16] replace blocks during world gen --- 1.21/CHANGELOG.md | 4 + .../fuzs/visualworkbench/VisualWorkbench.java | 35 +++- .../client/VisualWorkbenchClient.java | 8 +- .../client/handler/BlockModelHandler.java | 6 +- .../{ServerConfig.java => CommonConfig.java} | 4 +- .../data/client/DynamicModelProvider.java | 2 +- .../handler/BlockConversionHandler.java | 162 ++++++++++++------ .../visualworkbench/init/ModRegistry.java | 6 +- .../mixin/WorldGenRegionMixin.java | 23 +++ .../src/main/resources/common.mixins.json | 1 + 1.21/gradle.properties | 2 +- 11 files changed, 183 insertions(+), 70 deletions(-) rename 1.21/Common/src/main/java/fuzs/visualworkbench/config/{ServerConfig.java => CommonConfig.java} (53%) create mode 100644 1.21/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 3582956..7be0379 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v21.0.5-1.21] - 2024-09-03 +### Changed +- Blocks created during world generation are now automatically converted to the mod replacement + ## [v21.0.4-1.21] - 2024-08-16 ### Fixed - Fix `NullPointerException` when interacting with the crafting table menu diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java index 776e38d..4391673 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java @@ -9,32 +9,51 @@ import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; import fuzs.puzzleslib.api.event.v1.server.TagsUpdatedCallback; import fuzs.visualworkbench.config.ClientConfig; -import fuzs.visualworkbench.config.ServerConfig; +import fuzs.visualworkbench.config.CommonConfig; import fuzs.visualworkbench.handler.BlockConversionHandler; import fuzs.visualworkbench.init.ModRegistry; +import fuzs.visualworkbench.world.level.block.CraftingTableWithInventoryBlock; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CraftingTableBlock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.function.Predicate; + public class VisualWorkbench implements ModConstructor { public static final String MOD_ID = "visualworkbench"; public static final String MOD_NAME = "Visual Workbench"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class).server(ServerConfig.class); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID) + .client(ClientConfig.class) + .common(CommonConfig.class); + public static final Predicate BLOCK_PREDICATE = (Block block) -> { + return block instanceof CraftingTableBlock && !(block instanceof CraftingTableWithInventoryBlock); + }; @Override public void onConstructMod() { ModRegistry.touch(); - registerHandlers(); + registerEventHandlers(); } - private static void registerHandlers() { - RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK).register(BlockConversionHandler::onRegistryEntryAdded); - AddBlockEntityTypeBlocksCallback.EVENT.register(BlockConversionHandler::onAddBlockEntityTypeBlocks); - PlayerInteractEvents.USE_BLOCK.register(BlockConversionHandler::onUseBlock); - TagsUpdatedCallback.EVENT.register(EventPhase.FIRST, BlockConversionHandler::onTagsUpdated); + private static void registerEventHandlers() { + RegistryEntryAddedCallback.registryEntryAdded(Registries.BLOCK) + .register(BlockConversionHandler.onRegistryEntryAdded(BLOCK_PREDICATE, + CraftingTableWithInventoryBlock::new, MOD_ID + )); + AddBlockEntityTypeBlocksCallback.EVENT.register( + BlockConversionHandler.onAddBlockEntityTypeBlocks(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE)); + PlayerInteractEvents.USE_BLOCK.register( + BlockConversionHandler.onUseBlock(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG, + () -> CONFIG.get(CommonConfig.class).disableVanillaWorkbench + )); + TagsUpdatedCallback.EVENT.register(EventPhase.FIRST, + BlockConversionHandler.onTagsUpdated(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG, BLOCK_PREDICATE) + ); } public static ResourceLocation id(String path) { diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java index d1ee432..c8a8d8c 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java @@ -34,11 +34,15 @@ public void onRegisterMenuScreens(MenuScreensContext context) { @Override public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { - context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(), CraftingTableBlockEntityRenderer::new); + context.registerBlockEntityRenderer(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(), + CraftingTableBlockEntityRenderer::new + ); } @Override public void onAddResourcePackFinders(PackRepositorySourcesContext context) { - context.addRepositorySource(PackResourcesHelper.buildClientPack(VisualWorkbench.id("default_block_models"), DynamicPackResources.create(DynamicModelProvider::new), true)); + context.addRepositorySource(PackResourcesHelper.buildClientPack(VisualWorkbench.id("default_block_models"), + DynamicPackResources.create(DynamicModelProvider::new), true + )); } } diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java index f023106..ff12847 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java @@ -27,15 +27,15 @@ public class BlockModelHandler { static { MODEL_LOCATIONS = Suppliers.memoize(() -> { - return BlockConversionHandler.BLOCK_CONVERSIONS.inverse().entrySet().stream().flatMap(entry -> { - return convertAllBlockStates(entry.getKey(), entry.getValue()).entrySet().stream(); + return BlockConversionHandler.getBlockConversions().entrySet().stream().flatMap(entry -> { + return convertAllBlockStates(entry.getValue(), entry.getKey()).entrySet().stream(); }).collect(Util.toMap()); }); } public static void onLoadComplete() { // run a custom implementation here, the appropriate method in client mod constructor runs together with other mods, so we might miss some entries - for (Map.Entry entry : BlockConversionHandler.BLOCK_CONVERSIONS.entrySet()) { + for (Map.Entry entry : BlockConversionHandler.getBlockConversions().entrySet()) { RenderType renderType = ClientAbstractions.INSTANCE.getRenderType(entry.getKey()); ClientAbstractions.INSTANCE.registerRenderType(entry.getValue(), renderType); } diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java b/1.21/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java similarity index 53% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java rename to 1.21/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java index f9f8358..d431c09 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/config/ServerConfig.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java @@ -3,7 +3,9 @@ import fuzs.puzzleslib.api.config.v3.Config; import fuzs.puzzleslib.api.config.v3.ConfigCore; -public class ServerConfig implements ConfigCore { +public class CommonConfig implements ConfigCore { @Config(description = "Leftover vanilla crafting tables in a world become unusable until they are broken and replaced.") public boolean disableVanillaWorkbench = true; + @Config(description = "Replace vanilla crafting tables created in structures during world generation. Does not affect already generated blocks.") + public boolean convertVanillaWorkbenchDuringWorldGen = true; } diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java b/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java index 57aaff6..59b9810 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java @@ -23,7 +23,7 @@ public void addBlockModels(BlockModelGenerators builder) { // dynamically generate a basic stone block model for every diagonal block so the model bakery logs no missing model // don't use an air model so the blocks remain visible ResourceLocation resourceLocation = ModelLocationUtils.getModelLocation(Blocks.STONE); - BlockConversionHandler.BLOCK_CONVERSIONS.values().forEach((Block block) -> { + BlockConversionHandler.getBlockConversions().values().forEach((Block block) -> { builder.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, resourceLocation))); builder.skipAutoItemBlock(block); }); diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java index ba49d59..73dacc3 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java @@ -2,20 +2,25 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import com.google.common.collect.MapMaker; +import com.google.common.collect.Maps; import fuzs.puzzleslib.api.block.v1.BlockConversionHelper; +import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; +import fuzs.puzzleslib.api.event.v1.AddBlockEntityTypeBlocksCallback; +import fuzs.puzzleslib.api.event.v1.RegistryEntryAddedCallback; import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import fuzs.puzzleslib.api.event.v1.server.TagsUpdatedCallback; import fuzs.puzzleslib.api.init.v3.registry.RegistryHelper; -import fuzs.visualworkbench.VisualWorkbench; -import fuzs.visualworkbench.config.ServerConfig; -import fuzs.visualworkbench.init.ModRegistry; -import fuzs.visualworkbench.world.level.block.CraftingTableWithInventoryBlock; import net.minecraft.ChatFormatting; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; @@ -23,82 +28,137 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.CraftingTableBlock; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Supplier; +import java.util.function.*; public class BlockConversionHandler { public static final Component INVALID_BLOCK_COMPONENT = Component.translatable("container.invalidBlock"); - public static final BiMap BLOCK_CONVERSIONS = HashBiMap.create(); + private static final BiMap BLOCK_CONVERSIONS = HashBiMap.create(); + private static final Map BLOCK_STATE_CONVERSIONS_CACHE = new MapMaker().weakKeys().weakValues().makeMap(); - public static void onRegistryEntryAdded(Registry registry, ResourceLocation id, Block block, BiConsumer> registrar) { - if (block instanceof CraftingTableBlock) { - ResourceLocation resourceLocation = VisualWorkbench.id(id.getNamespace() + "/" + id.getPath()); - registrar.accept(resourceLocation, () -> { - Block newBlock = new CraftingTableWithInventoryBlock(block); - BLOCK_CONVERSIONS.put(block, newBlock); - return newBlock; - }); - } + public static RegistryEntryAddedCallback onRegistryEntryAdded(Predicate filter, UnaryOperator factory, String modId) { + return (Registry registry, ResourceLocation id, Block block, BiConsumer> registrar) -> { + if (filter.test(block)) { + ResourceLocation resourceLocation = ResourceLocationHelper.fromNamespaceAndPath(modId, + id.getNamespace() + "/" + id.getPath() + ); + registrar.accept(resourceLocation, () -> { + Block newBlock = factory.apply(block); + BLOCK_CONVERSIONS.put(block, newBlock); + return newBlock; + }); + } + }; } - public static void onAddBlockEntityTypeBlocks(BiConsumer, Block> consumer) { - BLOCK_CONVERSIONS.values().forEach((Block block) -> { - consumer.accept(ModRegistry.CRAFTING_TABLE_BLOCK_ENTITY_TYPE.value(), block); - }); + public static BiMap getBlockConversions() { + return Maps.unmodifiableBiMap(BLOCK_CONVERSIONS); } - public static EventResultHolder onUseBlock(Player player, Level level, InteractionHand interactionHand, BlockHitResult hitResult) { - if (!VisualWorkbench.CONFIG.get(ServerConfig.class).disableVanillaWorkbench) return EventResultHolder.pass(); - BlockState blockState = level.getBlockState(hitResult.getBlockPos()); - if (BLOCK_CONVERSIONS.containsKey(blockState.getBlock()) && !blockState.is(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG)) { - player.displayClientMessage(Component.empty().append(INVALID_BLOCK_COMPONENT).withStyle(ChatFormatting.RED), true); - return EventResultHolder.interrupt(InteractionResult.sidedSuccess(level.isClientSide)); - } else { - return EventResultHolder.pass(); - } + public static AddBlockEntityTypeBlocksCallback onAddBlockEntityTypeBlocks(Holder.Reference> blockEntityType) { + return (BiConsumer, Block> consumer) -> { + for (Map.Entry entry : BLOCK_CONVERSIONS.entrySet()) { + consumer.accept(blockEntityType.value(), entry.getValue()); + } + }; + } + + public static PlayerInteractEvents.UseBlock onUseBlock(TagKey unalteredBlocks, BooleanSupplier disableVanillaBlock) { + return (Player player, Level level, InteractionHand interactionHand, BlockHitResult hitResult) -> { + if (!disableVanillaBlock.getAsBoolean()) return EventResultHolder.pass(); + BlockState blockState = level.getBlockState(hitResult.getBlockPos()); + if (BLOCK_CONVERSIONS.containsKey(blockState.getBlock()) && !blockState.is(unalteredBlocks)) { + player.displayClientMessage( + Component.empty().append(INVALID_BLOCK_COMPONENT).withStyle(ChatFormatting.RED), true); + return EventResultHolder.interrupt(InteractionResult.sidedSuccess(level.isClientSide)); + } else { + return EventResultHolder.pass(); + } + }; } - public static void onTagsUpdated(RegistryAccess registryAccess, boolean client) { - for (Map.Entry, Item> entry : BuiltInRegistries.ITEM.entrySet()) { - if (entry.getValue() instanceof BlockItem blockItem) { - Block block = blockItem.getBlock(); - setItemForBlock(entry.getKey().location(), blockItem, block); - setBlockForItem(blockItem, block); + public static TagsUpdatedCallback onTagsUpdated(TagKey unalteredBlocks, Predicate filter) { + return (RegistryAccess registryAccess, boolean client) -> { + for (Map.Entry, Item> entry : BuiltInRegistries.ITEM.entrySet()) { + if (entry.getValue() instanceof BlockItem blockItem) { + Block block = blockItem.getBlock(); + setItemForBlock(filter, blockItem, block); + setBlockForItem(unalteredBlocks, blockItem, block); + } } - } - BLOCK_CONVERSIONS.forEach(BlockConversionHelper::copyBoundTags); + BLOCK_CONVERSIONS.forEach(BlockConversionHelper::copyBoundTags); + }; } - private static void setItemForBlock(ResourceLocation resourceLocation, BlockItem blockItem, Block block) { - if (block instanceof CraftingTableBlock) { + private static void setItemForBlock(Predicate filter, BlockItem blockItem, Block block) { + if (filter.test(block)) { BlockConversionHelper.setItemForBlock(BLOCK_CONVERSIONS.get(block), blockItem); } } - private static void setBlockForItem(BlockItem blockItem, Block block) { - Block baseBlock; - Block diagonalBlock = BLOCK_CONVERSIONS.get(block); - if (diagonalBlock != null) { - baseBlock = block; + private static void setBlockForItem(TagKey tagKey, BlockItem blockItem, Block block) { + Block oldBlock; + Block newBlock = BLOCK_CONVERSIONS.get(block); + if (newBlock != null) { + oldBlock = block; } else { - baseBlock = BLOCK_CONVERSIONS.inverse().get(block); - if (baseBlock != null) { - diagonalBlock = block; + oldBlock = BLOCK_CONVERSIONS.inverse().get(block); + if (oldBlock != null) { + newBlock = block; } else { return; } } - if (RegistryHelper.is(ModRegistry.UNALTERED_WORKBENCHES_BLOCK_TAG, baseBlock)) { - BlockConversionHelper.setBlockForItem(blockItem, baseBlock); + if (RegistryHelper.is(tagKey, oldBlock)) { + BlockConversionHelper.setBlockForItem(blockItem, oldBlock); + } else { + BlockConversionHelper.setBlockForItem(blockItem, newBlock); + } + } + + @Nullable + public static BlockState convertToVanillaBlock(@Nullable BlockState blockState) { + // mod replacement block coming in, we need to forward the original + return applyBlockConversion(blockState, true); + } + + @Nullable + public static BlockState convertFromVanillaBlock(@Nullable BlockState blockState) { + // original block coming in, we need to convert back to our replacement + return applyBlockConversion(blockState, false); + } + + @Nullable + private static BlockState applyBlockConversion(@Nullable BlockState blockState, boolean inverse) { + if (blockState != null) { + return BLOCK_STATE_CONVERSIONS_CACHE.computeIfAbsent(blockState, applyBlockConversion(inverse)); } else { - BlockConversionHelper.setBlockForItem(blockItem, diagonalBlock); + return null; } } + private static UnaryOperator applyBlockConversion(boolean inverse) { + return (BlockState blockState) -> { + BiMap blockConversions = inverse ? BLOCK_CONVERSIONS.inverse() : BLOCK_CONVERSIONS; + if (blockState != null && blockConversions.containsKey(blockState.getBlock())) { + Block block = blockConversions.get(blockState.getBlock()); + return copyAllProperties(blockState, block.defaultBlockState()); + } else { + return blockState; + } + }; + } + + private static , V extends T> BlockState copyAllProperties(BlockState oldBlockState, BlockState newBlockState) { + for (Map.Entry, Comparable> entry : oldBlockState.getValues().entrySet()) { + newBlockState = newBlockState.trySetValue((Property) entry.getKey(), (V) entry.getValue()); + } + return newBlockState; + } } diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java index b7b3861..bc81904 100644 --- a/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java @@ -12,10 +12,10 @@ import net.minecraft.world.level.block.entity.BlockEntityType; public class ModRegistry { - static final RegistryManager REGISTRY = RegistryManager.from(VisualWorkbench.MOD_ID); - public static final Holder.Reference> CRAFTING_TABLE_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType( + static final RegistryManager REGISTRIES = RegistryManager.from(VisualWorkbench.MOD_ID); + public static final Holder.Reference> CRAFTING_TABLE_BLOCK_ENTITY_TYPE = REGISTRIES.registerBlockEntityType( "crafting_table", () -> BlockEntityType.Builder.of(CraftingTableBlockEntity::new)); - public static final Holder.Reference> CRAFTING_MENU_TYPE = REGISTRY.registerMenuType( + public static final Holder.Reference> CRAFTING_MENU_TYPE = REGISTRIES.registerMenuType( "crafting", () -> VisualCraftingMenu::new); static final BoundTagFactory TAGS = BoundTagFactory.make(VisualWorkbench.MOD_ID); diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java b/1.21/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java new file mode 100644 index 0000000..14c64ab --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java @@ -0,0 +1,23 @@ +package fuzs.visualworkbench.mixin; + +import fuzs.visualworkbench.VisualWorkbench; +import fuzs.visualworkbench.config.CommonConfig; +import fuzs.visualworkbench.handler.BlockConversionHandler; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(WorldGenRegion.class) +abstract class WorldGenRegionMixin { + + @ModifyVariable(method = "setBlock", at = @At(value = "LOAD", ordinal = 0), argsOnly = true) + public BlockState setBlock(BlockState blockState) { + if (VisualWorkbench.CONFIG.get(CommonConfig.class).convertVanillaWorkbenchDuringWorldGen) { + return BlockConversionHandler.convertFromVanillaBlock(blockState); + } else { + return blockState; + } + } +} diff --git a/1.21/Common/src/main/resources/common.mixins.json b/1.21/Common/src/main/resources/common.mixins.json index 77fc8f4..bf44b95 100644 --- a/1.21/Common/src/main/resources/common.mixins.json +++ b/1.21/Common/src/main/resources/common.mixins.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_17", "package": "${modGroup}.mixin", "mixins": [ + "WorldGenRegionMixin" ], "client": [ ], diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 47e0314..9bd3219 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=21.0.4 +modVersion=21.0.5 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 From 7cc18fa442b3d9536a3acf7b9218de26be094bbe Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:28:02 +0200 Subject: [PATCH 14/16] prepare 1.21.1 port --- {1.21 => 1.21.1}/CHANGELOG.md | 0 {1.21 => 1.21.1}/Common/build.gradle | 0 .../.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 0 .../.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 | 0 .../assets/visualworkbench/lang/en_us.json | 0 .../tags/block/unaltered_workbenches.json | 0 .../java/fuzs/visualworkbench/VisualWorkbench.java | 0 .../client/VisualWorkbenchClient.java | 0 .../client/handler/BlockModelHandler.java | 0 .../CraftingTableBlockEntityRenderer.java | 0 .../fuzs/visualworkbench/config/ClientConfig.java | 0 .../fuzs/visualworkbench/config/CommonConfig.java | 0 .../visualworkbench/data/ModBlockTagsProvider.java | 0 .../data/client/DynamicModelProvider.java | 0 .../data/client/ModLanguageProvider.java | 0 .../handler/BlockConversionHandler.java | 0 .../java/fuzs/visualworkbench/init/ModRegistry.java | 0 .../integration/jei/VisualWorkbenchJEIPlugin.java | 0 .../visualworkbench/mixin/WorldGenRegionMixin.java | 0 .../world/inventory/VisualCraftingMenu.java | 0 .../block/CraftingTableWithInventoryBlock.java | 0 .../entity/CraftingTableAnimationController.java | 0 .../block/entity/CraftingTableBlockEntity.java | 0 .../block/entity/WorkbenchVisualsProvider.java | 0 .../src/main/resources/architectury.common.json | 0 .../Common/src/main/resources/common.mixins.json | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 .../main/resources/visualworkbench.accesswidener | 0 {1.21 => 1.21.1}/Fabric/build.gradle | 0 .../fabric/VisualWorkbenchFabric.java | 0 .../fabric/client/VisualWorkbenchFabricClient.java | 0 .../Fabric/src/main/resources/fabric.mixins.json | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.21 => 1.21.1}/NeoForge/build.gradle | 0 {1.21 => 1.21.1}/NeoForge/gradle.properties | 0 .../neoforge/VisualWorkbenchNeoForge.java | 0 .../client/VisualWorkbenchNeoForgeClient.java | 0 .../src/main/resources/META-INF/neoforge.mods.toml | 0 .../src/main/resources/neoforge.mixins.json | 0 {1.21 => 1.21.1}/build.gradle | 0 {1.21 => 1.21.1}/gradle.properties | 0 {1.21 => 1.21.1}/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.21 => 1.21.1}/gradlew | 0 {1.21 => 1.21.1}/gradlew.bat | 0 {1.21 => 1.21.1}/settings.gradle | 0 48 files changed, 0 insertions(+), 0 deletions(-) rename {1.21 => 1.21.1}/CHANGELOG.md (100%) rename {1.21 => 1.21.1}/Common/build.gradle (100%) rename {1.21 => 1.21.1}/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 (100%) rename {1.21 => 1.21.1}/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 (100%) rename {1.21 => 1.21.1}/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json (100%) rename {1.21 => 1.21.1}/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java (100%) rename {1.21 => 1.21.1}/Common/src/main/resources/architectury.common.json (100%) rename {1.21 => 1.21.1}/Common/src/main/resources/common.mixins.json (100%) rename {1.21 => 1.21.1}/Common/src/main/resources/mod_banner.png (100%) rename {1.21 => 1.21.1}/Common/src/main/resources/mod_logo.png (100%) rename {1.21 => 1.21.1}/Common/src/main/resources/pack.mcmeta (100%) rename {1.21 => 1.21.1}/Common/src/main/resources/visualworkbench.accesswidener (100%) rename {1.21 => 1.21.1}/Fabric/build.gradle (100%) rename {1.21 => 1.21.1}/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java (100%) rename {1.21 => 1.21.1}/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java (100%) rename {1.21 => 1.21.1}/Fabric/src/main/resources/fabric.mixins.json (100%) rename {1.21 => 1.21.1}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.21 => 1.21.1}/NeoForge/build.gradle (100%) rename {1.21 => 1.21.1}/NeoForge/gradle.properties (100%) rename {1.21 => 1.21.1}/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java (100%) rename {1.21 => 1.21.1}/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java (100%) rename {1.21 => 1.21.1}/NeoForge/src/main/resources/META-INF/neoforge.mods.toml (100%) rename {1.21 => 1.21.1}/NeoForge/src/main/resources/neoforge.mixins.json (100%) rename {1.21 => 1.21.1}/build.gradle (100%) rename {1.21 => 1.21.1}/gradle.properties (100%) rename {1.21 => 1.21.1}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.21 => 1.21.1}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.21 => 1.21.1}/gradlew (100%) rename {1.21 => 1.21.1}/gradlew.bat (100%) rename {1.21 => 1.21.1}/settings.gradle (100%) diff --git a/1.21/CHANGELOG.md b/1.21.1/CHANGELOG.md similarity index 100% rename from 1.21/CHANGELOG.md rename to 1.21.1/CHANGELOG.md diff --git a/1.21/Common/build.gradle b/1.21.1/Common/build.gradle similarity index 100% rename from 1.21/Common/build.gradle rename to 1.21.1/Common/build.gradle diff --git a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21.1/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 similarity index 100% rename from 1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 rename to 1.21.1/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 diff --git a/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 b/1.21.1/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 similarity index 100% rename from 1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 rename to 1.21.1/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 diff --git a/1.21/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json b/1.21.1/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json similarity index 100% rename from 1.21/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json rename to 1.21.1/Common/src/generated/resources/assets/visualworkbench/lang/en_us.json diff --git a/1.21/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json b/1.21.1/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json similarity index 100% rename from 1.21/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json rename to 1.21.1/Common/src/generated/resources/data/visualworkbench/tags/block/unaltered_workbenches.json diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/VisualWorkbench.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/client/VisualWorkbenchClient.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/client/handler/BlockModelHandler.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/client/renderer/blockentity/CraftingTableBlockEntityRenderer.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/config/ClientConfig.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/config/CommonConfig.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/data/ModBlockTagsProvider.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/data/client/DynamicModelProvider.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/data/client/ModLanguageProvider.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/handler/BlockConversionHandler.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/init/ModRegistry.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/integration/jei/VisualWorkbenchJEIPlugin.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/mixin/WorldGenRegionMixin.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/world/inventory/VisualCraftingMenu.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/CraftingTableWithInventoryBlock.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableAnimationController.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java diff --git a/1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java rename to 1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/WorkbenchVisualsProvider.java diff --git a/1.21/Common/src/main/resources/architectury.common.json b/1.21.1/Common/src/main/resources/architectury.common.json similarity index 100% rename from 1.21/Common/src/main/resources/architectury.common.json rename to 1.21.1/Common/src/main/resources/architectury.common.json diff --git a/1.21/Common/src/main/resources/common.mixins.json b/1.21.1/Common/src/main/resources/common.mixins.json similarity index 100% rename from 1.21/Common/src/main/resources/common.mixins.json rename to 1.21.1/Common/src/main/resources/common.mixins.json diff --git a/1.21/Common/src/main/resources/mod_banner.png b/1.21.1/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.21/Common/src/main/resources/mod_banner.png rename to 1.21.1/Common/src/main/resources/mod_banner.png diff --git a/1.21/Common/src/main/resources/mod_logo.png b/1.21.1/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.21/Common/src/main/resources/mod_logo.png rename to 1.21.1/Common/src/main/resources/mod_logo.png diff --git a/1.21/Common/src/main/resources/pack.mcmeta b/1.21.1/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.21/Common/src/main/resources/pack.mcmeta rename to 1.21.1/Common/src/main/resources/pack.mcmeta diff --git a/1.21/Common/src/main/resources/visualworkbench.accesswidener b/1.21.1/Common/src/main/resources/visualworkbench.accesswidener similarity index 100% rename from 1.21/Common/src/main/resources/visualworkbench.accesswidener rename to 1.21.1/Common/src/main/resources/visualworkbench.accesswidener diff --git a/1.21/Fabric/build.gradle b/1.21.1/Fabric/build.gradle similarity index 100% rename from 1.21/Fabric/build.gradle rename to 1.21.1/Fabric/build.gradle diff --git a/1.21/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java b/1.21.1/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java similarity index 100% rename from 1.21/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java rename to 1.21.1/Fabric/src/main/java/fuzs/visualworkbench/fabric/VisualWorkbenchFabric.java diff --git a/1.21/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java b/1.21.1/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java similarity index 100% rename from 1.21/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java rename to 1.21.1/Fabric/src/main/java/fuzs/visualworkbench/fabric/client/VisualWorkbenchFabricClient.java diff --git a/1.21/Fabric/src/main/resources/fabric.mixins.json b/1.21.1/Fabric/src/main/resources/fabric.mixins.json similarity index 100% rename from 1.21/Fabric/src/main/resources/fabric.mixins.json rename to 1.21.1/Fabric/src/main/resources/fabric.mixins.json diff --git a/1.21/Fabric/src/main/resources/fabric.mod.json b/1.21.1/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.21/Fabric/src/main/resources/fabric.mod.json rename to 1.21.1/Fabric/src/main/resources/fabric.mod.json diff --git a/1.21/NeoForge/build.gradle b/1.21.1/NeoForge/build.gradle similarity index 100% rename from 1.21/NeoForge/build.gradle rename to 1.21.1/NeoForge/build.gradle diff --git a/1.21/NeoForge/gradle.properties b/1.21.1/NeoForge/gradle.properties similarity index 100% rename from 1.21/NeoForge/gradle.properties rename to 1.21.1/NeoForge/gradle.properties diff --git a/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java b/1.21.1/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java similarity index 100% rename from 1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java rename to 1.21.1/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/VisualWorkbenchNeoForge.java diff --git a/1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java b/1.21.1/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java similarity index 100% rename from 1.21/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java rename to 1.21.1/NeoForge/src/main/java/fuzs/visualworkbench/neoforge/client/VisualWorkbenchNeoForgeClient.java diff --git a/1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml b/1.21.1/NeoForge/src/main/resources/META-INF/neoforge.mods.toml similarity index 100% rename from 1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml rename to 1.21.1/NeoForge/src/main/resources/META-INF/neoforge.mods.toml diff --git a/1.21/NeoForge/src/main/resources/neoforge.mixins.json b/1.21.1/NeoForge/src/main/resources/neoforge.mixins.json similarity index 100% rename from 1.21/NeoForge/src/main/resources/neoforge.mixins.json rename to 1.21.1/NeoForge/src/main/resources/neoforge.mixins.json diff --git a/1.21/build.gradle b/1.21.1/build.gradle similarity index 100% rename from 1.21/build.gradle rename to 1.21.1/build.gradle diff --git a/1.21/gradle.properties b/1.21.1/gradle.properties similarity index 100% rename from 1.21/gradle.properties rename to 1.21.1/gradle.properties diff --git a/1.21/gradle/wrapper/gradle-wrapper.jar b/1.21.1/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.21/gradle/wrapper/gradle-wrapper.jar rename to 1.21.1/gradle/wrapper/gradle-wrapper.jar diff --git a/1.21/gradle/wrapper/gradle-wrapper.properties b/1.21.1/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.21/gradle/wrapper/gradle-wrapper.properties rename to 1.21.1/gradle/wrapper/gradle-wrapper.properties diff --git a/1.21/gradlew b/1.21.1/gradlew similarity index 100% rename from 1.21/gradlew rename to 1.21.1/gradlew diff --git a/1.21/gradlew.bat b/1.21.1/gradlew.bat similarity index 100% rename from 1.21/gradlew.bat rename to 1.21.1/gradlew.bat diff --git a/1.21/settings.gradle b/1.21.1/settings.gradle similarity index 100% rename from 1.21/settings.gradle rename to 1.21.1/settings.gradle From e52173e42eab2be3582bf494f8d451b77df04097 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:54:33 +0200 Subject: [PATCH 15/16] full 1.21.1 port --- 1.21.1/CHANGELOG.md | 26 ++----------------- .../entity/CraftingTableBlockEntity.java | 4 +-- 1.21.1/gradle.properties | 4 +-- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/1.21.1/CHANGELOG.md b/1.21.1/CHANGELOG.md index 7be0379..c36ef0b 100644 --- a/1.21.1/CHANGELOG.md +++ b/1.21.1/CHANGELOG.md @@ -4,27 +4,5 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [v21.0.5-1.21] - 2024-09-03 -### Changed -- Blocks created during world generation are now automatically converted to the mod replacement - -## [v21.0.4-1.21] - 2024-08-16 -### Fixed -- Fix `NullPointerException` when interacting with the crafting table menu - -## [v21.0.3-1.21] - 2024-08-09 -### Changed -- Compatible with Fabric Api 1.21+0.102.0 - -## [v21.0.2-1.21] - 2024-07-23 -### Fixed -- Fix incompatibility with FastBench mod -- Fix crafting tables ignoring tools when breaking in multiplayer - -## [v21.0.1-1.21] - 2024-07-07 -### Changed -- Updated for Puzzles Lib v21.0.8 - -## [v21.0.0-1.21] - 2024-07-06 -- Port to Minecraft 1.21 -- Forge is no longer support in favor of NeoForge +## [v21.1.0-1.21.1] - 2024-09-11 +- Port to Minecraft 1.21.1 diff --git a/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java index 45a2717..8939321 100644 --- a/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java +++ b/1.21.1/Common/src/main/java/fuzs/visualworkbench/world/level/block/entity/CraftingTableBlockEntity.java @@ -1,7 +1,7 @@ package fuzs.visualworkbench.world.level.block.entity; import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; -import fuzs.puzzleslib.api.container.v1.ContainerItemHelper; +import fuzs.puzzleslib.api.container.v1.ContainerMenuHelper; import fuzs.puzzleslib.api.container.v1.ContainerSerializationHelper; import fuzs.visualworkbench.VisualWorkbench; import fuzs.visualworkbench.init.ModRegistry; @@ -83,7 +83,7 @@ public NonNullList getItems() { @Override protected void setItems(NonNullList items) { - ContainerItemHelper.copyItemsToContainer(this, items); + ContainerMenuHelper.copyItemsIntoContainer(items, this); } @Override diff --git a/1.21.1/gradle.properties b/1.21.1/gradle.properties index 9bd3219..1d8f9be 100755 --- a/1.21.1/gradle.properties +++ b/1.21.1/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=visualworkbench modName=Visual Workbench -modVersion=21.0.5 +modVersion=21.1.0 modAuthor=Fuzs modDescription=Items stay inside crafting tables and are also rendered on top. It's really fancy! modLicense=MPL-2.0 @@ -19,7 +19,7 @@ modForgeDisplayTest=MATCH_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.21-v23 +dependenciesVersionCatalog=1.21.1-v4 #dependenciesPuzzlesLibVersion=21.0.8 #dependenciesMinPuzzlesLibVersion=21.0.8 From 2146e026b013101dd73d3a02504d544b1bc9067e Mon Sep 17 00:00:00 2001 From: mash1133 <49663704+mash1133@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:10:09 +0900 Subject: [PATCH 16/16] Create ja_jp.json --- .../resources/assets/visualworkbench/lang/ja_jp.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 1.21.1/Common/src/generated/resources/assets/visualworkbench/lang/ja_jp.json diff --git a/1.21.1/Common/src/generated/resources/assets/visualworkbench/lang/ja_jp.json b/1.21.1/Common/src/generated/resources/assets/visualworkbench/lang/ja_jp.json new file mode 100644 index 0000000..96e8e9e --- /dev/null +++ b/1.21.1/Common/src/generated/resources/assets/visualworkbench/lang/ja_jp.json @@ -0,0 +1,4 @@ +{ + "container.invalidBlock": "使用不可。回収し交換してください。", + "tag.block.visualworkbench.unaltered_workbenches": "変更前の作業台" +}