From 44dfc7487aa2ac8ecaf37b842f94d52d81df44e0 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:24:10 +0200 Subject: [PATCH 01/31] prepare release --- CHANGELOG.md | 7 +++++++ .../gui/screens/armorstand/ArmorStandStyleScreen.java | 2 +- gradle.properties | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 283da97..36945da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.2-1.19.2] - 2022-10-19 +### Changed +- Any item can now be placed into the head slot on the equipment screen (thanks to [Mephodio]) +- Tooltips on the rotations screen will no longer obstruct the armor stand model (thanks to [Mephodio]) +- Tooltips on the style screen are now split into multiple lines to prevent them from flowing off the screen + ## [v4.0.1-1.19.2] - 2022-10-15 ### Changed - Updated to Forge 43.1.40+ which is also now required @@ -13,3 +19,4 @@ The format is based on [Keep a Changelog]. - Initial release [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +[Mephodio]: https://github.com/Mephodio diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java index 4338733..f653d13 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java @@ -33,7 +33,7 @@ protected AbstractWidget makeTickBoxWidget(ArmorStand armorStand, int buttonStar return new TickBoxButton(this.leftPos + 96, this.topPos + buttonStartY + index * 22, 6, 76, option.getComponent(), option.getOption(armorStand), (Button button) -> { this.dataSyncHandler.sendStyleOption(option, ((TickBoxButton) button).isSelected()); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { - this.renderTooltip(poseStack, option.getDescriptionComponent(), mouseX, mouseY); + this.renderTooltip(poseStack, this.minecraft.font.split(option.getDescriptionComponent(), 175), mouseX, mouseY); }); } diff --git a/gradle.properties b/gradle.properties index 7f4cfed..612b1c5 100755 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ minFabricApiVersion=0.60.0 # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.1 +modVersion=4.0.2 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modSourceUrl=https://github.com/Fuzss/armorstatues From 43d95952778a8bff62e51b73920b35edf316a632 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 6 Jan 2023 00:31:12 +0100 Subject: [PATCH 02/31] fix interaction crash with new fabric api --- CHANGELOG.md | 4 ++++ .../src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java | 3 ++- gradle.properties | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36945da..d2a694e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.3-1.19.2] - 2023-01-06 +### Fixed +- Fixed crash when trying to interact with entities using Fabric API 0.72.0+1.19.2 + ## [v4.0.2-1.19.2] - 2022-10-19 ### Changed - Any item can now be placed into the head slot on the equipment screen (thanks to [Mephodio]) diff --git a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java index 87fd287..e0dc624 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java +++ b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java @@ -26,7 +26,8 @@ public void onInitialize() { private static void registerHandlers() { UseEntityCallback.EVENT.register((Player player, Level level, InteractionHand interactionHand, Entity target, EntityHitResult entityHitResult) -> { - // entityHitResult is marked as nullable in Fabric Api, but can actually not be null + // this callback runs in two places, one runs only for armor stands and is hit location aware, that's the one we need + if (entityHitResult == null) return InteractionResult.PASS; Vec3 vec3 = entityHitResult.getLocation().subtract(target.getX(), target.getY(), target.getZ()); return ArmorStandInteractHandler.onEntityInteract(player, level, interactionHand, target, vec3).orElse(InteractionResult.PASS); }); diff --git a/gradle.properties b/gradle.properties index 612b1c5..ccee99f 100755 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ minFabricApiVersion=0.60.0 # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.2 +modVersion=4.0.3 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modSourceUrl=https://github.com/Fuzss/armorstatues From 262ed8c81209c07d7c85d5dfe29b94253356f592 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Tue, 17 Jan 2023 15:27:24 +0100 Subject: [PATCH 03/31] quark compat, remove keybind, scrolling --- CHANGELOG.md | 6 +++ .../armorstand/AbstractArmorStandScreen.java | 46 +++++++++++-------- .../armorstand/ArmorStandEquipmentScreen.java | 7 ++- .../armorstand/ArmorStandRotationsScreen.java | 4 +- .../api/client/init/ModClientRegistry.java | 8 ---- .../api/helper/ArmorStandInteractHelper.java | 6 ++- .../client/ArmorStatuesClient.java | 6 --- .../handler/ArmorStandInteractHandler.java | 4 +- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../assets/armorstatues/lang/en_us.json | 2 +- .../fuzs/armorstatues/ArmorStatuesForge.java | 8 ++-- .../data/ModLanguageProvider.java | 2 +- gradle.properties | 2 +- 13 files changed, 55 insertions(+), 50 deletions(-) delete mode 100644 Common/src/main/java/fuzs/armorstatues/api/client/init/ModClientRegistry.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d2a694e..b234508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.4-1.19.2] - 2023-01-17 +### Changed +- Opening the statue menu now requires a stick to be held in addition to sneaking, this was changed to improve compatibility with the Quark mod +- Removed the option to cycle through statue menu tabs using the tab key, it was conflicting with showing the vanilla server player list (at least on Fabric) +- Instead, you can now scroll through the tabs when your cursor is hovering them + ## [v4.0.3-1.19.2] - 2023-01-06 ### Fixed - Fixed crash when trying to interact with entities using Fabric API 0.72.0+1.19.2 diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index f8fcbae..5255110 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -5,12 +5,12 @@ import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.client.gui.components.TickingButton; import fuzs.armorstatues.api.client.gui.components.UnboundedSliderButton; -import fuzs.armorstatues.api.client.init.ModClientRegistry; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.puzzleslib.client.core.ClientCoreServices; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.ImageButton; @@ -185,10 +185,7 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - // hook this in before super, as the default key tab is normally used for cycling focused widgets (which we don't really need...) - if (tryCycleTabs(this, keyCode, scanCode, modifiers)) { - return true; - } else if (super.keyPressed(keyCode, scanCode, modifiers)) { + if (super.keyPressed(keyCode, scanCode, modifiers)) { return true; } else if (this.minecraft.options.keyInventory.matches(keyCode, scanCode)) { this.onClose(); @@ -197,25 +194,38 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { return false; } - public static boolean handleTabClicked(int mouseX, int mouseY, int leftPos, int topPos, int imageHeight, T screen, ArmorStandScreenType[] tabs) { - Optional hoveredTab = findHoveredTab(leftPos, topPos, imageHeight, mouseX, mouseY, tabs); - return hoveredTab.filter(armorStandScreenType -> openTabScreen(screen, armorStandScreenType)).isPresent(); + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + if (super.mouseScrolled(mouseX, mouseY, delta)) { + return true; + } + return handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); } - private static boolean openTabScreen(T screen, ArmorStandScreenType screenType) { - if (screenType != screen.getScreenType()) { - ClientCoreServices.SCREENS.getMinecraft(screen).getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - ClientCoreServices.SCREENS.getMinecraft(screen).setScreen(screen.createScreenType(screenType)); - return true; + public static boolean handleMouseScrolled(int mouseX, int mouseY, double delta, int leftPos, int topPos, int imageHeight, T screen, ArmorStandScreenType[] tabs) { + delta = Math.signum(delta); + if (delta != 0.0) { + Optional optional = findHoveredTab(leftPos, topPos, imageHeight, mouseX, mouseY, tabs); + if (optional.isPresent()) { + ArmorStandScreenType screenType = cycleTabs(screen.getScreenType(), screen.getHolder().getDataProvider().getScreenTypes(), delta > 0.0); + return openTabScreen(screen, screenType, false); + } } return false; } - public static boolean tryCycleTabs(T screen, int keyCode, int scanCode, int modifiers) { - // keep a way to let vanilla cycle widgets - if (!hasControlDown() && !hasAltDown() && ModClientRegistry.CYCLE_TABS_KEY_MAPPING.matches(keyCode, scanCode)) { - ArmorStandScreenType screenType = cycleTabs(screen.getScreenType(), screen.getHolder().getDataProvider().getScreenTypes(), hasShiftDown()); - openTabScreen(screen, screenType); + public static boolean handleTabClicked(int mouseX, int mouseY, int leftPos, int topPos, int imageHeight, T screen, ArmorStandScreenType[] tabs) { + Optional hoveredTab = findHoveredTab(leftPos, topPos, imageHeight, mouseX, mouseY, tabs); + return hoveredTab.filter(armorStandScreenType -> openTabScreen(screen, armorStandScreenType, true)).isPresent(); + } + + private static boolean openTabScreen(T screen, ArmorStandScreenType screenType, boolean clickSound) { + if (screenType != screen.getScreenType()) { + Minecraft minecraft = ClientCoreServices.SCREENS.getMinecraft(screen); + if (clickSound) { + minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + } + minecraft.setScreen(screen.createScreenType(screenType)); return true; } return false; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java index 7d88d86..75bde66 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java @@ -75,12 +75,11 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - // hook this in before super, as the default key tab is normally used for cycling focused widgets (which we don't really need...) - if (AbstractArmorStandScreen.tryCycleTabs(this, keyCode, scanCode, modifiers)) { + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + if (super.mouseScrolled(mouseX, mouseY, delta)) { return true; } - return super.keyPressed(keyCode, scanCode, modifiers); + return AbstractArmorStandScreen.handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index ec01ee8..7ed02f7 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -6,7 +6,6 @@ import fuzs.armorstatues.api.client.gui.components.LiveSliderButton; import fuzs.armorstatues.api.client.gui.components.NewTextureTickButton; import fuzs.armorstatues.api.client.gui.components.VerticalSliderButton; -import fuzs.armorstatues.api.client.init.ModClientRegistry; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; @@ -171,8 +170,7 @@ public boolean isDirty() { private Component getTipComponent() { Component[] components = { Component.translatable("armorstatues.screen.rotations.tip1"), - Component.translatable("armorstatues.screen.rotations.tip2"), - Component.translatable("armorstatues.screen.rotations.tip3", ModClientRegistry.CYCLE_TABS_KEY_MAPPING.getTranslatedKeyMessage(), ModClientRegistry.CYCLE_TABS_KEY_MAPPING.getTranslatedKeyMessage()) + Component.translatable("armorstatues.screen.rotations.tip2") }; return components[RANDOM.nextInt(components.length)]; } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/init/ModClientRegistry.java b/Common/src/main/java/fuzs/armorstatues/api/client/init/ModClientRegistry.java deleted file mode 100644 index d6b10b0..0000000 --- a/Common/src/main/java/fuzs/armorstatues/api/client/init/ModClientRegistry.java +++ /dev/null @@ -1,8 +0,0 @@ -package fuzs.armorstatues.api.client.init; - -import com.mojang.blaze3d.platform.InputConstants; -import net.minecraft.client.KeyMapping; - -public class ModClientRegistry { - public static final KeyMapping CYCLE_TABS_KEY_MAPPING = new KeyMapping("key.cycleStatueTabs", InputConstants.KEY_TAB, "key.categories.inventory"); -} diff --git a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java b/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java index b16f641..0b2ca2b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java +++ b/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java @@ -9,14 +9,16 @@ import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import java.util.Optional; public class ArmorStandInteractHelper { - public static Optional tryOpenArmorStatueMenu(Player player, Level level, ArmorStand entity, MenuType menuType) { - if (player.isShiftKeyDown() && (!entity.isInvulnerable() || player.getAbilities().instabuild)) { + public static Optional tryOpenArmorStatueMenu(Player player, Level level, ItemStack stack, ArmorStand entity, MenuType menuType) { + if (player.isShiftKeyDown() && stack.is(Items.STICK) && (!entity.isInvulnerable() || player.getAbilities().instabuild)) { openArmorStatueMenu(player, entity, menuType); return Optional.of(InteractionResult.sidedSuccess(level.isClientSide)); } diff --git a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index c7f1cfc..12a32a5 100644 --- a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -1,7 +1,6 @@ package fuzs.armorstatues.client; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreenFactory; -import fuzs.armorstatues.api.client.init.ModClientRegistry; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.init.ModRegistry; import fuzs.puzzleslib.client.core.ClientModConstructor; @@ -17,9 +16,4 @@ public void onRegisterMenuScreens(MenuScreensContext context) { return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); }); } - - @Override - public void onRegisterKeyMappings(KeyMappingsContext context) { - context.registerKeyMappings(ModClientRegistry.CYCLE_TABS_KEY_MAPPING); - } } diff --git a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index 1a5f049..37d7482 100644 --- a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -11,6 +11,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -24,7 +25,8 @@ public class ArmorStandInteractHandler { public static Optional onEntityInteract(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { if (!player.isSpectator() && target.getType() == EntityType.ARMOR_STAND) { - Optional result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get()); + ItemStack stack = player.getItemInHand(interactionHand); + Optional result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, stack, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get()); if (result.isPresent() && level.isClientSide && !presentServerside) { // better to check for client once more, we don't want to accidentally run on the server thread when showing the screen ArmorStatues.PROXY.openArmorStandScreen((ArmorStand) target, player); diff --git a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index be7c05c..f0908a1 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2022-09-23T20:09:24.900309 Languages: en_us -6e73dfcadb10e01ff872707f9d4a53e8279ebe47 assets/armorstatues/lang/en_us.json +// 1.19.2 2023-01-17T15:26:30.642483 Languages: en_us +e12b3be2312990480ba50bd5340b054e0f0084c3 assets/armorstatues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json index 2787a16..6e8a448 100644 --- a/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json +++ b/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -12,7 +12,7 @@ "armorstatues.entity.armor_stand.pose.salute": "Salute", "armorstatues.entity.armor_stand.pose.solemn": "Solemn", "armorstatues.entity.armor_stand.pose.zombie": "Zombie", - "armorstatues.item.armor_stand.description": "Shift + right-click to open configuration screen when placed.", + "armorstatues.item.armor_stand.description": "Shift + right-click holding a stick to open configuration screen after placing.", "armorstatues.screen.alignments.block": "Align Block", "armorstatues.screen.alignments.credit": "Alignment values are taken from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!", "armorstatues.screen.alignments.itemFlat": "Align Item As Flat", diff --git a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java index 1f3f9c4..aefa51e 100644 --- a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java +++ b/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java @@ -11,6 +11,7 @@ import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; @@ -27,10 +28,11 @@ public static void onConstructMod(final FMLConstructModEvent evt) { } private static void registerHandlers() { - MinecraftForge.EVENT_BUS.addListener((final PlayerInteractEvent.EntityInteractSpecific evt) -> { + // high priority so we run before the Quark mod + MinecraftForge.EVENT_BUS.addListener(EventPriority.HIGH, (final PlayerInteractEvent.EntityInteractSpecific evt) -> { + // we use our custom event client-side, as it allows for cancelling the packet being sent to the server + if (!evt.getSide().isServer()) return; ArmorStandInteractHandler.onEntityInteract(evt.getEntity(), evt.getLevel(), evt.getHand(), evt.getTarget(), evt.getLocalPos()).ifPresent(result -> { - // we use our custom event client-side, as it allows for cancelling the packet being sent to the server - if (!evt.getSide().isServer()) return; evt.setCancellationResult(result); evt.setCanceled(true); }); diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index b27ba2b..ba408b4 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -12,7 +12,7 @@ public ModLanguageProvider(DataGenerator gen, String modId) { @Override protected void addTranslations() { this.add("key.cycleStatueTabs", "Cycle Statue Tabs"); - this.add("armorstatues.item.armor_stand.description", "Shift + right-click to open configuration screen when placed."); + this.add("armorstatues.item.armor_stand.description", "Shift + right-click holding a stick to open configuration screen after placing."); this.add("armorstatues.entity.armor_stand.pose.athena", "Athena"); this.add("armorstatues.entity.armor_stand.pose.brandish", "Brandish"); this.add("armorstatues.entity.armor_stand.pose.cancanA", "Cancan #1"); diff --git a/gradle.properties b/gradle.properties index ccee99f..7aa0d44 100755 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ minFabricApiVersion=0.60.0 # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.3 +modVersion=4.0.4 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modSourceUrl=https://github.com/Fuzss/armorstatues From c7ea2434f823a54fc1d699352fdae1e8dddccd6c Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Tue, 25 Jul 2023 10:13:57 +0200 Subject: [PATCH 04/31] port api update from straw statues with additions --- CHANGELOG.md | 7 + .../java/fuzs/armorstatues/ArmorStatues.java | 6 + .../armorstatues/api/ArmorStatuesApi.java | 10 +- .../api/client/ArmorStatuesApiClient.java | 1 + .../gui/components/BoxedSliderButton.java | 4 +- .../components/NewTextureSliderButton.java | 2 +- .../gui/components/NewTextureTickButton.java | 2 +- .../client/gui/components/TickBoxButton.java | 2 +- .../api/client/gui/components/TickButton.java | 4 +- .../gui/components/VerticalSliderButton.java | 2 +- .../armorstand/AbstractArmorStandScreen.java | 52 +++++-- .../ArmorStandAlignmentsScreen.java | 7 +- .../armorstand/ArmorStandEquipmentScreen.java | 32 ++-- .../ArmorStandInInventoryRenderer.java | 14 ++ .../armorstand/ArmorStandPosesScreen.java | 11 +- .../armorstand/ArmorStandPositionScreen.java | 86 +++++++---- .../armorstand/ArmorStandRotationsScreen.java | 26 ++-- .../screens/armorstand/ArmorStandScreen.java | 7 + .../armorstand/ArmorStandStyleScreen.java | 25 +++- .../armorstand/ArmorStandTickBoxScreen.java | 33 +++-- .../armorstand/ArmorStandWidgetsScreen.java | 13 +- .../api/helper/ArmorStandInteractHelper.java | 26 ++-- .../client/data/CommandDataSyncHandler.java | 44 +++--- .../network/client/data/DataSyncHandler.java | 36 +++-- .../client/data/NetworkDataSyncHandler.java | 8 +- .../data/VanillaTweaksDataSyncHandler.java | 140 ++++++++++++++++++ .../armorstatues/api/proxy/ClientProxy.java | 16 ++ .../fuzs/armorstatues/api/proxy/Proxy.java | 11 ++ .../armorstatues/api/proxy/ServerProxy.java | 11 ++ .../api/world/inventory/ArmorStandMenu.java | 11 +- .../world/inventory/data/ArmorStandPose.java | 41 ++--- .../inventory/data/ArmorStandScreenType.java | 17 +-- .../inventory/data/ArmorStandStyleOption.java | 15 +- .../data/ArmorStandStyleOptions.java | 10 +- .../world/inventory/data/PosePartMutator.java | 16 +- .../handler/ArmorStandTooltipHandler.java | 6 +- .../armorstatues/config/ClientConfig.java | 10 ++ .../handler/ArmorStandInteractHandler.java | 16 +- .../handler/DataSyncTickHandler.java | 28 ++++ .../fuzs/armorstatues/proxy/ClientProxy.java | 16 +- .../resources/armorstatues.common.mixins.json | 1 + Fabric/build.gradle | 4 +- .../fuzs/armorstatues/ArmorStatuesFabric.java | 6 +- .../client/ArmorStatuesFabricClient.java | 13 ++ .../mixin/ModMixinConfigPlugin.java | 47 ++++++ .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../{armorstatues => statues}/lang/en_us.json | 24 +-- .../fuzs/armorstatues/ArmorStatuesForge.java | 4 +- .../client/ArmorStatuesForgeClient.java | 40 ++++- .../data/ModLanguageProvider.java | 85 ++++++----- .../mixin/ModMixinConfigPlugin.java | 47 ++++++ .../client/MultiPlayerGameModeMixin.java | 39 ----- .../resources/armorstatues.forge.mixins.json | 15 -- .../gui/container/armor_stand/background.png | Bin 2985 -> 0 bytes .../gui/container/armor_stand/widgets.png | Bin 9721 -> 0 bytes .../gui/container/armor_stand/background.png | Bin 0 -> 3575 bytes .../gui/container/armor_stand/equipment.png | Bin .../gui/container/armor_stand/widgets.png | Bin 0 -> 10262 bytes .../textures/item/empty_armor_slot_sword.png | Bin README.md | 2 +- gradle.properties | 10 +- run/options.txt | 2 +- 62 files changed, 822 insertions(+), 345 deletions(-) create mode 100644 Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java create mode 100644 Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java create mode 100644 Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java create mode 100644 Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java create mode 100644 Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java create mode 100644 Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java create mode 100644 Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java create mode 100644 Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java rename Forge/src/generated/resources/assets/{armorstatues => statues}/lang/en_us.json (82%) create mode 100644 Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java delete mode 100644 Forge/src/main/java/fuzs/armorstatues/mixin/client/MultiPlayerGameModeMixin.java delete mode 100644 Forge/src/main/resources/armorstatues.forge.mixins.json delete mode 100644 Forge/src/main/resources/assets/armorstatues/textures/gui/container/armor_stand/background.png delete mode 100644 Forge/src/main/resources/assets/armorstatues/textures/gui/container/armor_stand/widgets.png create mode 100644 Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/background.png rename Forge/src/main/resources/assets/{armorstatues => statues}/textures/gui/container/armor_stand/equipment.png (100%) create mode 100644 Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/widgets.png rename Forge/src/main/resources/assets/{armorstatues => statues}/textures/item/empty_armor_slot_sword.png (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index b234508..5a766ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.5-1.19.2] - 2023-07-24 +### Changed +- Text fields now show description tooltips when hovered to make it more clear which field is for setting a new display name and which one changes the statue skin +- Opening the statue menu no longer requires a stick to be held, instead shift + right-click with an empty hand is the way to go, which the statue item tooltip reflects +### Fixed +- Fixed a rare network issue on servers when both Armor Statues and Straw Statues are installed + ## [v4.0.4-1.19.2] - 2023-01-17 ### Changed - Opening the statue menu now requires a stick to be held in addition to sneaking, this was changed to improve compatibility with the Quark mod diff --git a/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java index a6e6f8a..ff91896 100644 --- a/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java +++ b/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -1,10 +1,13 @@ package fuzs.armorstatues; +import fuzs.armorstatues.config.ClientConfig; import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.S2CPingMessage; import fuzs.armorstatues.proxy.ClientProxy; import fuzs.armorstatues.proxy.Proxy; import fuzs.armorstatues.proxy.ServerProxy; +import fuzs.puzzleslib.config.ConfigHolder; +import fuzs.puzzleslib.core.CommonFactories; import fuzs.puzzleslib.core.CoreServices; import fuzs.puzzleslib.core.DistTypeExecutor; import fuzs.puzzleslib.core.ModConstructor; @@ -20,10 +23,13 @@ public class ArmorStatues implements ModConstructor { public static final NetworkHandler NETWORK = CoreServices.FACTORIES.network(MOD_ID, true, true); @SuppressWarnings("Convert2MethodRef") + public static final ConfigHolder CONFIG = CommonFactories.INSTANCE.clientConfig(ClientConfig.class, () -> new ClientConfig()); + @SuppressWarnings("Convert2MethodRef") public static final Proxy PROXY = DistTypeExecutor.getForDistType(() -> () -> new ClientProxy(), () -> () -> new ServerProxy()); @Override public void onConstructMod() { + CONFIG.bakeConfigs(MOD_ID); ModRegistry.touch(); registerMessages(); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java b/Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java index 9ebfd20..ff77de6 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java +++ b/Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java @@ -14,8 +14,8 @@ import java.util.Locale; public class ArmorStatuesApi implements ModConstructor { - public static final String MOD_ID = "armorstatues"; - public static final String MOD_NAME = "Armor Statues"; + public static final String MOD_ID = "statues"; + public static final String MOD_NAME = "Statues"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); public static final NetworkHandler NETWORK = CoreServices.FACTORIES.network(MOD_ID, true, true); @@ -37,7 +37,11 @@ private static void registerMessages() { public void onCommonSetup() { // do this here instead of in enum constructor to avoid potential issues with the enum class not having been loaded yet on server-side, therefore nothing being registered for (ArmorStandStyleOptions styleOption : ArmorStandStyleOptions.values()) { - ArmorStandStyleOption.register(new ResourceLocation(MOD_ID, styleOption.getTranslationId().toLowerCase(Locale.ROOT)), styleOption); + ArmorStandStyleOption.register(id(styleOption.getName().toLowerCase(Locale.ROOT)), styleOption); } } + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java b/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java index f67dfb5..254d607 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java @@ -4,6 +4,7 @@ import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.PosePartMutator; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; import fuzs.puzzleslib.client.core.ClientModConstructor; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.inventory.InventoryMenu; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java index a9dbe18..df4bfc6 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java @@ -64,7 +64,7 @@ public void updateNarration(NarrationElementOutput narrationElementOutput) { @Override public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.ARMOR_STAND_WIDGETS_LOCATION); + RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.getArmorStandWidgetsLocation()); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); @@ -81,7 +81,7 @@ public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float part } else if (horizontalValueLocked) { this.blit(poseStack, this.x + sliderX, this.y, 54, 120, SLIDER_SIZE + 2, this.height); } else { - this.blit(poseStack, this.x, this.y + sliderY, 136, 45, this.width, SLIDER_SIZE + 2); + this.blit(poseStack, this.x, this.y + sliderY, 136, 49, this.width, SLIDER_SIZE + 2); } int i = this.getYImage(hoveredOrFocused); this.blit(poseStack, this.x + 1 + sliderX, this.y + 1 + sliderY, 151, i * SLIDER_SIZE, SLIDER_SIZE, SLIDER_SIZE); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java index 81446a7..6732d5b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java @@ -20,7 +20,7 @@ public abstract class NewTextureSliderButton extends AbstractSliderButton implem private final int textureY; protected final ResourceLocation textureLocation; protected final OnTooltip onTooltip; - public double snapInterval; + public double snapInterval = -1.0; public NewTextureSliderButton(int x, int y, int width, int height, int textureX, int textureY, ResourceLocation textureLocation, Component component, double value) { this(x, y, width, height, textureX, textureY, textureLocation, component, value, (button, poseStack, mouseX, mouseY) -> { diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java index 2fe914e..c8c7b27 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java @@ -20,7 +20,7 @@ public NewTextureTickButton(int x, int y, int width, int height, int imageTextur } public NewTextureTickButton(int x, int y, int width, int height, int imageTextureX, int imageTextureY, ResourceLocation imageTextureLocation, OnPress onPress, OnTooltip onTooltip) { - super(x, y, width, height, 0, 184, AbstractArmorStandScreen.ARMOR_STAND_WIDGETS_LOCATION, CommonComponents.EMPTY, onPress, onTooltip); + super(x, y, width, height, 0, 184, AbstractArmorStandScreen.getArmorStandWidgetsLocation(), CommonComponents.EMPTY, onPress, onTooltip); this.imageTextureX = imageTextureX; this.imageTextureY = imageTextureY; this.imageTextureLocation = imageTextureLocation; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java index 7238924..c2c1a03 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java @@ -39,7 +39,7 @@ public boolean isSelected() { @Override public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { Minecraft minecraft = Minecraft.getInstance(); - RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.ARMOR_STAND_WIDGETS_LOCATION); + RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.getArmorStandWidgetsLocation()); RenderSystem.enableDepthTest(); Font font = minecraft.font; RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java index 5a02786..6e51b54 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java @@ -14,13 +14,13 @@ public class TickButton extends NewTextureButton implements TickingButton { protected int lastClickedTicksDelay = 30; public TickButton(int x, int y, int width, int height, Component title, Component clickedTitle, OnPress onPress) { - super(x, y, width, height, 0, 184, AbstractArmorStandScreen.ARMOR_STAND_WIDGETS_LOCATION, title, onPress); + super(x, y, width, height, 0, 184, AbstractArmorStandScreen.getArmorStandWidgetsLocation(), title, onPress); this.title = title; this.clickedTitle = clickedTitle; } public TickButton(int x, int y, int width, int height, Component title, Component clickedTitle, OnPress onPress, OnTooltip onTooltip) { - super(x, y, width, height, 0, 184, AbstractArmorStandScreen.ARMOR_STAND_WIDGETS_LOCATION, title, onPress, onTooltip); + super(x, y, width, height, 0, 184, AbstractArmorStandScreen.getArmorStandWidgetsLocation(), title, onPress, onTooltip); this.title = title; this.clickedTitle = clickedTitle; } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java index 1dd17ca..fcbf5b4 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java @@ -57,7 +57,7 @@ public void updateNarration(NarrationElementOutput narrationElementOutput) { @Override public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.ARMOR_STAND_WIDGETS_LOCATION); + RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.getArmorStandWidgetsLocation()); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index 5255110..e7c5833 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -11,12 +11,12 @@ import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.puzzleslib.client.core.ClientCoreServices; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.ImageButton; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.InventoryScreen; import net.minecraft.client.gui.screens.inventory.MenuAccess; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.entity.ItemRenderer; @@ -27,12 +27,16 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.AbstractContainerMenu; import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.Nullable; import java.util.Optional; public abstract class AbstractArmorStandScreen extends Screen implements MenuAccess, ArmorStandScreen { - private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = new ResourceLocation(ArmorStatuesApi.MOD_ID, "textures/gui/container/armor_stand/background.png"); - public static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = new ResourceLocation(ArmorStatuesApi.MOD_ID, "textures/gui/container/armor_stand/widgets.png"); + private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/background.png"); + private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/widgets.png"); + private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/equipment.png"); + + static ArmorStandInInventoryRenderer armorStandRenderer = ArmorStandInInventoryRenderer.SIMPLE; protected final int imageWidth = 210; protected final int imageHeight = 188; @@ -46,6 +50,7 @@ public abstract class AbstractArmorStandScreen extends Screen implements MenuAcc protected boolean smallInventoryEntity; protected int mouseX; protected int mouseY; + @Nullable private AbstractWidget closeButton; public AbstractArmorStandScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { @@ -55,11 +60,28 @@ public AbstractArmorStandScreen(ArmorStandHolder holder, Inventory inventory, Co this.dataSyncHandler = dataSyncHandler; } + public static ResourceLocation getArmorStandBackgroundLocation() { + return ARMOR_STAND_BACKGROUND_LOCATION; + } + + public static ResourceLocation getArmorStandWidgetsLocation() { + return ARMOR_STAND_WIDGETS_LOCATION; + } + + public static ResourceLocation getArmorStandEquipmentLocation() { + return ARMOR_STAND_EQUIPMENT_LOCATION; + } + @Override public ArmorStandHolder getHolder() { return this.holder; } + @Override + public DataSyncHandler getDataSyncHandler() { + return this.dataSyncHandler; + } + @Override public & ArmorStandScreen> T createScreenType(ArmorStandScreenType screenType) { T screen = ArmorStandScreenFactory.createScreenType(screenType, this.holder, this.inventory, this.title, this.dataSyncHandler); @@ -80,7 +102,7 @@ public void setMouseY(int mouseY) { @Override public void tick() { - super.tick(); + this.dataSyncHandler.tick(); for (GuiEventListener child : this.children()) { if (child instanceof TickingButton button) button.tick(); } @@ -96,7 +118,7 @@ protected void init() { } public static AbstractButton makeCloseButton(Screen screen, int leftPos, int imageWidth, int topPos) { - return new ImageButton(leftPos + imageWidth - 15 - 8, topPos + 8, 15, 15, 136, 0, ARMOR_STAND_WIDGETS_LOCATION, button -> { + return new ImageButton(leftPos + imageWidth - 15 - 8, topPos + 8, 15, 15, 136, 0, getArmorStandWidgetsLocation(), button -> { screen.onClose(); }); } @@ -114,7 +136,9 @@ protected boolean disableMenuRendering() { } protected void toggleMenuRendering(boolean disableMenuRendering) { - this.closeButton.visible = !disableMenuRendering; + if (this.closeButton != null) { + this.closeButton.visible = !disableMenuRendering; + } } @Override @@ -136,7 +160,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic super.render(poseStack, mouseX, mouseY, partialTick); if (!this.disableMenuRendering()) { findHoveredTab(this.leftPos, this.topPos, this.imageHeight, mouseX, mouseY, this.dataSyncHandler.tabs()).ifPresent(hoveredTab -> { - this.renderTooltip(poseStack, hoveredTab.getComponent(), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(hoveredTab.getTranslationKey()), mouseX, mouseY); }); } this.mouseX = mouseX; @@ -147,7 +171,7 @@ protected void renderBg(PoseStack poseStack, float partialTick, int mouseX, int if (!this.disableMenuRendering()) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, ARMOR_STAND_BACKGROUND_LOCATION); + RenderSystem.setShaderTexture(0, getArmorStandBackgroundLocation()); this.blit(poseStack, this.leftPos, this.topPos, 0, 0, this.imageWidth, this.imageHeight); drawTabs(poseStack, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); this.renderEntityInInventory(poseStack); @@ -158,13 +182,13 @@ private void renderEntityInInventory(PoseStack poseStack) { if (this.renderInventoryEntity()) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, ARMOR_STAND_WIDGETS_LOCATION); + RenderSystem.setShaderTexture(0, getArmorStandWidgetsLocation()); if (this.smallInventoryEntity) { this.blit(poseStack, this.leftPos + this.inventoryEntityX, this.topPos + this.inventoryEntityY, 200, 184, 50, 72); - InventoryScreen.renderEntityInInventory(this.leftPos + this.inventoryEntityX + 24, this.topPos + this.inventoryEntityY + 65, 30, this.leftPos + this.inventoryEntityX + 24 - 10 - this.mouseX, this.topPos + this.inventoryEntityY + 65 - 44 - this.mouseY, this.holder.getArmorStand()); + this.renderArmorStandInInventory(this.leftPos + this.inventoryEntityX + 24, this.topPos + this.inventoryEntityY + 65, 30, this.leftPos + this.inventoryEntityX + 24 - 10 - this.mouseX, this.topPos + this.inventoryEntityY + 65 - 44 - this.mouseY); } else { this.blit(poseStack, this.leftPos + this.inventoryEntityX, this.topPos + this.inventoryEntityY, 0, 0, 76, 108); - InventoryScreen.renderEntityInInventory(this.leftPos + this.inventoryEntityX + 38, this.topPos + this.inventoryEntityY + 98, 45, (float) (this.leftPos + this.inventoryEntityX + 38 - 5) - this.mouseX, (float) (this.topPos + this.inventoryEntityY + 98 - 66) - this.mouseY, this.holder.getArmorStand()); + this.renderArmorStandInInventory(this.leftPos + this.inventoryEntityX + 38, this.topPos + this.inventoryEntityY + 98, 45, (float) (this.leftPos + this.inventoryEntityX + 38 - 5) - this.mouseX, (float) (this.topPos + this.inventoryEntityY + 98 - 66) - this.mouseY); } } } @@ -207,7 +231,7 @@ public static boolean handleMouseScrolled( if (delta != 0.0) { Optional optional = findHoveredTab(leftPos, topPos, imageHeight, mouseX, mouseY, tabs); if (optional.isPresent()) { - ArmorStandScreenType screenType = cycleTabs(screen.getScreenType(), screen.getHolder().getDataProvider().getScreenTypes(), delta > 0.0); + ArmorStandScreenType screenType = cycleTabs(screen.getScreenType(), tabs, delta > 0.0); return openTabScreen(screen, screenType, false); } } @@ -244,8 +268,8 @@ public static void drawTabs(PoseStack pose int tabY = topPos + tabsStartY + 27 * i; RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, ARMOR_STAND_WIDGETS_LOCATION); - screen.blit(poseStack, tabX, tabY, 212, tabType == screen.getScreenType() ? 0 : 27, 35, 26); + RenderSystem.setShaderTexture(0, getArmorStandBackgroundLocation()); + GuiComponent.blit(poseStack, tabX, tabY, tabY <= topPos ? 36 : tabY >= topPos + imageHeight - 36 ? 72 : 0, 188 + (tabType == screen.getScreenType() ? 0 : 26), 36, 26, 256, 256); ItemRenderer itemRenderer = ClientCoreServices.SCREENS.getItemRenderer(screen); itemRenderer.blitOffset = 100.0F; itemRenderer.renderAndDecorateItem(tabType.getIcon(), tabX + 10, tabY + 5); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index 094c06b..d140422 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -23,6 +23,7 @@ import java.util.List; public class ArmorStandAlignmentsScreen extends ArmorStandWidgetsScreen { + public static final String VANILLA_TWEAKS_HOMEPAGE = "https://vanillatweaks.net/"; public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); @@ -40,11 +41,11 @@ protected List buildWidgets(ArmorStand armorStand) { @Override protected void init() { super.init(); - this.addRenderableWidget(new ImageButton(this.leftPos + 6, this.topPos + 6, 20, 20, 136, 64, 20, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> { + this.addRenderableWidget(new ImageButton(this.leftPos + 6, this.topPos + 6, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { this.minecraft.setScreen(new ConfirmLinkScreen((bl) -> { - if (bl) Util.getPlatform().openUri("https://vanillatweaks.net/"); + if (bl) Util.getPlatform().openUri(VANILLA_TWEAKS_HOMEPAGE); this.minecraft.setScreen(this); - }, "https://vanillatweaks.net/", true)); + }, VANILLA_TWEAKS_HOMEPAGE, true)); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.alignments.credit"), mouseX, mouseY); }, CommonComponents.EMPTY)); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java index 75bde66..cb10d3f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java @@ -2,26 +2,21 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.client.gui.screens.inventory.InventoryScreen; import net.minecraft.client.gui.screens.inventory.MenuAccess; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.Slot; public class ArmorStandEquipmentScreen extends AbstractContainerScreen implements ArmorStandScreen { - private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = new ResourceLocation(ArmorStatuesApi.MOD_ID, "textures/gui/container/armor_stand/equipment.png"); - private final Inventory inventory; private final DataSyncHandler dataSyncHandler; private int mouseX; @@ -40,6 +35,11 @@ public ArmorStandHolder getHolder() { return this.menu; } + @Override + public DataSyncHandler getDataSyncHandler() { + return this.dataSyncHandler; + } + @Override public & ArmorStandScreen> T createScreenType(ArmorStandScreenType screenType) { T screen = ArmorStandScreenFactory.createScreenType(screenType, this.menu, this.inventory, this.title, this.dataSyncHandler); @@ -58,6 +58,11 @@ public void setMouseY(int mouseY) { this.mouseY = mouseY; } + @Override + protected void containerTick() { + this.dataSyncHandler.tick(); + } + @Override protected void init() { super.init(); @@ -83,14 +88,14 @@ public boolean mouseScrolled(double mouseX, double mouseY, double delta) { } @Override - public void render(PoseStack poseStack, int mouseX, int mouseY, float pPartialTick) { + public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { this.renderBackground(poseStack); - this.renderBg(poseStack, pPartialTick, mouseX, mouseY); - super.render(poseStack, mouseX, mouseY, pPartialTick); + this.renderBg(poseStack, partialTick, mouseX, mouseY); + super.render(poseStack, mouseX, mouseY, partialTick); this.renderTooltip(poseStack, mouseX, mouseY); if (this.menu.getCarried().isEmpty()) { AbstractArmorStandScreen.findHoveredTab(this.leftPos, this.topPos, this.imageHeight, mouseX, mouseY, this.dataSyncHandler.tabs()).ifPresent(hoveredTab -> { - this.renderTooltip(poseStack, hoveredTab.getComponent(), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(hoveredTab.getTranslationKey()), mouseX, mouseY); }); } this.mouseX = mouseX; @@ -101,20 +106,19 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float pPartialTi protected void renderBg(PoseStack poseStack, float pPartialTick, int pX, int pY) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, ARMOR_STAND_EQUIPMENT_LOCATION); + RenderSystem.setShaderTexture(0, AbstractArmorStandScreen.getArmorStandEquipmentLocation()); this.blit(poseStack, this.leftPos, this.topPos, 0, 0, this.imageWidth, this.imageHeight); for (int k = 0; k < ArmorStandMenu.SLOT_IDS.length; ++k) { Slot slot = this.menu.slots.get(k); - if (slot.isActive() && this.isSlotRestricted(ArmorStandMenu.SLOT_IDS[k])) { + if (slot.isActive() && isSlotRestricted(this.menu.getArmorStand(), ArmorStandMenu.SLOT_IDS[k])) { this.blit(poseStack, this.leftPos + slot.x - 1, this.topPos + slot.y - 1, 210, 0, 18, 18); } } AbstractArmorStandScreen.drawTabs(poseStack, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); - InventoryScreen.renderEntityInInventory(this.leftPos + 104, this.topPos + 84, 30, (float) (this.leftPos + 104 - 10) - this.mouseX, (float) (this.topPos + 84 - 44) - this.mouseY, this.menu.getArmorStand()); + this.renderArmorStandInInventory(this.leftPos + 104, this.topPos + 84, 30, (float) (this.leftPos + 104 - 10) - this.mouseX, (float) (this.topPos + 84 - 44) - this.mouseY); } - private boolean isSlotRestricted(EquipmentSlot equipmentSlot) { - ArmorStand armorStand = this.menu.getArmorStand(); + private static boolean isSlotRestricted(ArmorStand armorStand, EquipmentSlot equipmentSlot) { return ArmorStandMenu.isSlotDisabled(armorStand, equipmentSlot, 0) || ArmorStandMenu.isSlotDisabled(armorStand, equipmentSlot, ArmorStand.DISABLE_TAKING_OFFSET) || ArmorStandMenu.isSlotDisabled(armorStand, equipmentSlot, ArmorStand.DISABLE_PUTTING_OFFSET); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java new file mode 100644 index 0000000..82d276c --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java @@ -0,0 +1,14 @@ +package fuzs.armorstatues.api.client.gui.screens.armorstand; + +import net.minecraft.client.gui.screens.inventory.InventoryScreen; +import net.minecraft.world.entity.LivingEntity; + +public interface ArmorStandInInventoryRenderer { + ArmorStandInInventoryRenderer SIMPLE = InventoryScreen::renderEntityInInventory; + + void renderEntityInInventory(int posX, int posY, int scale, float mouseX, float mouseY, LivingEntity livingEntity); + + static void setArmorStandRenderer(ArmorStandInInventoryRenderer armorStandRenderer) { + AbstractArmorStandScreen.armorStandRenderer = armorStandRenderer; + } +} diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java index fbf1ca3..ab2260f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java @@ -8,7 +8,6 @@ import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.ImageButton; -import net.minecraft.client.gui.screens.inventory.InventoryScreen; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; @@ -33,20 +32,20 @@ public ArmorStandPosesScreen(ArmorStandHolder holder, Inventory inventory, Compo @Override protected void init() { super.init(); - this.cycleButtons[0] = this.addRenderableWidget(new ImageButton(this.leftPos + 17, this.topPos + 153, 20, 20, 156, 64, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.cycleButtons[0] = this.addRenderableWidget(new ImageButton(this.leftPos + 17, this.topPos + 153, 20, 20, 156, 64, getArmorStandWidgetsLocation(), button -> { firstPoseIndex -= POSES_PER_PAGE; this.toggleCycleButtons(); })); - this.cycleButtons[1] = this.addRenderableWidget(new ImageButton(this.leftPos + 49, this.topPos + 153, 20, 20, 176, 64, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.cycleButtons[1] = this.addRenderableWidget(new ImageButton(this.leftPos + 49, this.topPos + 153, 20, 20, 176, 64, getArmorStandWidgetsLocation(), button -> { firstPoseIndex += POSES_PER_PAGE; this.toggleCycleButtons(); })); for (int i = 0; i < this.poseButtons.length; i++) { final int ii = i; - this.poseButtons[i] = this.addRenderableWidget(new ImageButton(this.leftPos + 83 + i % 2 * 62, this.topPos + 9 + i / 2 * 88, 60, 82, 76, 0, 82, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> { + this.poseButtons[i] = this.addRenderableWidget(new ImageButton(this.leftPos + 83 + i % 2 * 62, this.topPos + 9 + i / 2 * 88, 60, 82, 76, 0, 82, getArmorStandWidgetsLocation(), 256, 256, button -> { getPoseAt(ii).ifPresent(this.dataSyncHandler::sendPose); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { - getPoseAt(ii).ifPresent(pose -> this.renderTooltip(poseStack, pose.getComponent(), mouseX, mouseY)); + getPoseAt(ii).ifPresent(pose -> this.renderTooltip(poseStack, Component.translatable(pose.getTranslationKey()), mouseX, mouseY)); }, CommonComponents.EMPTY)); } this.toggleCycleButtons(); @@ -69,7 +68,7 @@ protected void renderBg(PoseStack poseStack, float partialTick, int mouseX, int Optional pose = getPoseAt(i); if (pose.isPresent()) { pose.get().applyToEntity(armorStand); - InventoryScreen.renderEntityInInventory(this.leftPos + 112 + i % 2 * 62, this.topPos + 79 + i / 2 * 88, 30, this.leftPos + 112 + i % 2 * 62 - 10 - this.mouseX, this.topPos + 79 + i / 2 * 88 - 44 - this.mouseY, armorStand); + this.renderArmorStandInInventory(this.leftPos + 112 + i % 2 * 62, this.topPos + 79 + i / 2 * 88, 30, this.leftPos + 112 + i % 2 * 62 - 10 - this.mouseX, this.topPos + 79 + i / 2 * 88 - 44 - this.mouseY); } } entityPose.applyToEntity(armorStand); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java index 844a51c..09ef311 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java @@ -29,7 +29,6 @@ import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.DoubleSupplier; -import java.util.function.Supplier; import java.util.stream.Collectors; public class ArmorStandPositionScreen extends ArmorStandWidgetsScreen { @@ -60,7 +59,7 @@ public void removed() { protected List buildWidgets(ArmorStand armorStand) { // only move server-side to prevent rubber banding return Lists.newArrayList( - new RotationWidget(armorStand::getYRot, this.dataSyncHandler::sendRotation), + new RotationWidget(Component.translatable("armorstatues.screen.position.rotation"), armorStand::getYRot, this.dataSyncHandler::sendRotation), new PositionIncrementWidget(), new PositionComponentWidget("x", armorStand::getX, x -> { this.dataSyncHandler.sendPosition(x, armorStand.getY(), armorStand.getZ()); @@ -91,30 +90,59 @@ private static int getBlockPixelIncrement(double increment) { return (int) Math.round(increment * 16.0); } - public static double fromWrappedDegrees(double value) { - return (Mth.wrapDegrees(value) + 180.0) / 360.0; - } + protected class RotationWidget extends AbstractPositionScreenWidget { + protected final DoubleSupplier currentValue; + protected final Consumer newValue; + private final double snapInterval; + @Nullable + private Runnable reset; - public static float toWrappedDegrees(double value) { - return (float) Mth.wrapDegrees(value * 360.0 - 180.0); - } + public RotationWidget(Component title, DoubleSupplier currentValue, Consumer newValue) { + this(title, currentValue, newValue, ArmorStandPose.DEGREES_SNAP_INTERVAL); + } + + public RotationWidget(Component title, DoubleSupplier currentValue, Consumer newValue, double snapInterval) { + super(title); + this.currentValue = currentValue; + this.newValue = newValue; + this.snapInterval = snapInterval; + } + + protected double getCurrentValue() { + return fromWrappedDegrees(this.currentValue.getAsDouble()); + } + + protected void setNewValue(double newValue) { + this.newValue.accept(toWrappedDegrees(newValue)); + } - private class RotationWidget extends AbstractPositionScreenWidget { - private final Supplier currentRotation; - private final Consumer newRotation; + protected Component getTooltipComponent(double mouseValue) { + return Component.translatable("armorstatues.screen.position.degrees", ArmorStandPose.ROTATION_FORMAT.format(toWrappedDegrees(mouseValue))); + } + + protected static double fromWrappedDegrees(double value) { + return (Mth.wrapDegrees(value) + 180.0) / 360.0; + } + + protected static float toWrappedDegrees(double value) { + return (float) Mth.wrapDegrees(value * 360.0 - 180.0); + } + + protected void applyClientValue(double newValue) { - public RotationWidget(Supplier currentRotation, Consumer newRotation) { - super(Component.translatable("armorstatues.screen.position.rotation")); - this.currentRotation = currentRotation; - this.newRotation = newRotation; + } + + @Override + public void reset() { + if (this.reset != null) this.reset.run(); } @Override public void init(int posX, int posY) { super.init(posX, posY); - NewTextureSliderButton sliderButton = ArmorStandPositionScreen.this.addRenderableWidget(new NewTextureSliderButton(posX + 76, posY + 1, 90, 20, 0, 184, ARMOR_STAND_WIDGETS_LOCATION, CommonComponents.EMPTY, fromWrappedDegrees(this.currentRotation.get()), (button, poseStack, mouseX, mouseY) -> { - double mouseValue = ArmorStandPose.snapValue((mouseX - button.x) / (double) button.getWidth(), ArmorStandPose.DEGREES_SNAP_INTERVAL); - ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.position.degrees", ArmorStandPose.ROTATION_FORMAT.format(toWrappedDegrees(mouseValue))), mouseX, mouseY); + var sliderButton = ArmorStandPositionScreen.this.addRenderableWidget(new NewTextureSliderButton(posX + 76, posY + 1, 90, 20, 0, 184, getArmorStandWidgetsLocation(), CommonComponents.EMPTY, this.getCurrentValue(), (button, poseStack, mouseX, mouseY) -> { + double mouseValue = ArmorStandPose.snapValue((mouseX - button.x) / (double) button.getWidth(), this.snapInterval); + ArmorStandPositionScreen.this.renderTooltip(poseStack, this.getTooltipComponent(mouseValue), mouseX, mouseY); }) { private boolean dirty; @@ -123,9 +151,14 @@ protected void updateMessage() { } + public void reset() { + this.value = RotationWidget.this.getCurrentValue(); + } + @Override protected void applyValue() { this.dirty = true; + RotationWidget.this.applyClientValue(this.value); } @Override @@ -134,7 +167,7 @@ public void onRelease(double mouseX, double mouseY) { // we use #onRelease instead of directly applying in #applyValue as the armor stand will otherwise glitch out visually since the server constantly sends outdated values if (this.isDirty()) { this.dirty = false; - RotationWidget.this.newRotation.accept(toWrappedDegrees(this.value)); + RotationWidget.this.setNewValue(this.value); } } @@ -143,9 +176,10 @@ public boolean isDirty() { return this.dirty; } }); - sliderButton.snapInterval = ArmorStandPose.DEGREES_SNAP_INTERVAL; + sliderButton.snapInterval = this.snapInterval; + this.reset = sliderButton::reset; this.children.add(sliderButton); - this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, getArmorStandWidgetsLocation(), button -> { ArmorStandPositionScreen.this.setActiveWidget(this); }))); } @@ -162,7 +196,7 @@ public void init(int posX, int posY) { super.init(posX, posY); for (int i = 0; i < INCREMENTS.length; i++) { double increment = INCREMENTS[i]; - AbstractWidget widget = ArmorStandPositionScreen.this.addRenderableWidget(new NewTextureButton(posX + 76 + i * 24 + (i > 1 ? 1 : 0), posY + 1, 20, 20, 0, 184, ARMOR_STAND_WIDGETS_LOCATION, Component.literal(String.valueOf(getBlockPixelIncrement(increment))), button -> { + AbstractWidget widget = ArmorStandPositionScreen.this.addRenderableWidget(new NewTextureButton(posX + 76 + i * 24 + (i > 1 ? 1 : 0), posY + 1, 20, 20, 0, 184, getArmorStandWidgetsLocation(), Component.literal(String.valueOf(getBlockPixelIncrement(increment))), button -> { this.setActiveIncrement(button, increment); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { List lines = Lists.newArrayList(getPixelIncrementComponent(increment), getBlockIncrementComponent(increment)); @@ -173,7 +207,7 @@ public void init(int posX, int posY) { widget.active = false; } } - this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, getArmorStandWidgetsLocation(), button -> { ArmorStandPositionScreen.this.setActiveWidget(this); }))); } @@ -224,17 +258,17 @@ public void init(int posX, int posY) { this.editBox.setTextColorUneditable(14737632); this.editBox.setValue(BLOCK_INCREMENT_FORMAT.format(this.getPositionValue())); this.children.add(this.editBox); - this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 149, posY + 1, 20, 10, 196, 64, 20, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> { + this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 149, posY + 1, 20, 10, 196, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { this.setPositionValue(this.getPositionValue() + currentIncrement); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.position.increment", getPixelIncrementComponent(currentIncrement)), mouseX, mouseY); }, CommonComponents.EMPTY))); - this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 149, posY + 11, 20, 10, 216, 74, 20, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> { + this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 149, posY + 11, 20, 10, 216, 74, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { this.setPositionValue(this.getPositionValue() - currentIncrement); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.position.decrement", getPixelIncrementComponent(currentIncrement)), mouseX, mouseY); }, CommonComponents.EMPTY))); - this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, getArmorStandWidgetsLocation(), button -> { ArmorStandPositionScreen.this.setActiveWidget(this); }))); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index 7ed02f7..8077ccd 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -17,6 +17,7 @@ import net.minecraft.client.sounds.SoundManager; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; import org.apache.commons.compress.utils.Lists; @@ -51,22 +52,22 @@ public ArmorStandRotationsScreen(ArmorStandHolder holder, Inventory inventory, C protected void init() { super.init(); this.minecraft.keyboardHandler.setSendRepeatsToGui(true); - this.lockButtons[0] = this.addRenderableWidget(new ImageButton(this.leftPos + 83, this.topPos + 10, 20, 20, 156, 124, 20, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> { + this.lockButtons[0] = this.addRenderableWidget(new ImageButton(this.leftPos + 83, this.topPos + 10, 20, 20, 156, 124, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { clampRotations = true; this.toggleLockButtons(); this.refreshLiveButtons(); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.unlimited"), mouseX, mouseY); }, Component.translatable("armorstatues.screen.rotations.unlimited"))); - this.lockButtons[1] = this.addRenderableWidget(new ImageButton(this.leftPos + 83, this.topPos + 10, 20, 20, 136, 124, 20, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> { + this.lockButtons[1] = this.addRenderableWidget(new ImageButton(this.leftPos + 83, this.topPos + 10, 20, 20, 136, 124, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { clampRotations = false; this.toggleLockButtons(); this.refreshLiveButtons(); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.limited"), mouseX, mouseY); }, Component.translatable("armorstatues.screen.rotations.limited"))); - Component tipComponent = this.getTipComponent(); - this.addRenderableWidget(new ImageButton(this.leftPos + 107, this.topPos + 10, 20, 20, 136, 64, 20, ARMOR_STAND_WIDGETS_LOCATION, 256, 256, button -> {}, (button, poseStack, mouseX, mouseY) -> { + List tipComponent = this.font.split(this.getTipComponent(), 175); + this.addRenderableWidget(new ImageButton(this.leftPos + 107, this.topPos + 10, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> {}, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, tipComponent, mouseX, mouseY); }, CommonComponents.EMPTY) { @@ -75,28 +76,33 @@ public void playDownSound(SoundManager handler) { } }); - this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 34, 20, 20, 240, 124, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 34, 20, 20, 240, 124, getArmorStandWidgetsLocation(), button -> { this.setCurrentPose(ArmorStandPose.empty()); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.reset"), mouseX, mouseY); })); - this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 34, 20, 20, 192, 124, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 34, 20, 20, 192, 124, getArmorStandWidgetsLocation(), button -> { this.setCurrentPose(this.holder.getDataProvider().getRandomPose(true)); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.randomize"), mouseX, mouseY); })); - AbstractWidget pasteButton = this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 158, 44, 20, 224, 124, ARMOR_STAND_WIDGETS_LOCATION, button -> { + AbstractWidget pasteButton = this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 158, 20, 20, 224, 124, getArmorStandWidgetsLocation(), button -> { if (clipboard != null) this.setCurrentPose(clipboard); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.paste"), mouseX, mouseY); })); pasteButton.active = clipboard != null; - this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 134, 44, 20, 208, 124, ARMOR_STAND_WIDGETS_LOCATION, button -> { + this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 158, 20, 20, 208, 124, getArmorStandWidgetsLocation(), button -> { clipboard = this.currentPose; pasteButton.active = true; }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.copy"), mouseX, mouseY); })); + this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 134, 44, 20, 179, 0, getArmorStandWidgetsLocation(), button -> { + this.setCurrentPose(this.currentPose.mirror()); + }, (button, poseStack, mouseX, mouseY) -> { + this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.mirror"), mouseX, mouseY); + })); ArmorStand armorStand = this.holder.getArmorStand(); PosePartMutator[] values = this.holder.getDataProvider().getPosePartMutators(); ArmorStandPose.checkMutatorsSize(values); @@ -105,7 +111,7 @@ public void playDownSound(SoundManager handler) { boolean isLeft = i % 2 == 0; this.addRenderableWidget(new BoxedSliderButton(this.leftPos + 23 + i % 2 * 110, this.topPos + 7 + i / 2 * 60, () -> mutator.getNormalizedRotationsAtAxis(1, this.currentPose, clampRotations), () -> mutator.getNormalizedRotationsAtAxis(0, this.currentPose, clampRotations), (button, poseStack, mouseX, mouseY) -> { List lines = Lists.newArrayList(); - lines.add(mutator.getComponent()); + lines.add(Component.translatable(mutator.getTranslationKey())); lines.add(mutator.getAxisComponent(this.currentPose, 0)); lines.add(mutator.getAxisComponent(this.currentPose, 1)); int offset = isLeft ? 24 + lines.stream().mapToInt(minecraft.font::width).max().orElse(0) : 0; @@ -136,7 +142,7 @@ public boolean isDirty() { }).active = isPosePartMutatorActive(mutator, armorStand); this.addRenderableWidget(new VerticalSliderButton(this.leftPos + 6 + i % 2 * 183, this.topPos + 7 + i / 2 * 60, () -> mutator.getNormalizedRotationsAtAxis(2, this.currentPose, clampRotations), (button, poseStack, mouseX, mouseY) -> { List lines = Lists.newArrayList(); - lines.add(mutator.getComponent()); + lines.add(Component.translatable(mutator.getTranslationKey())); lines.add(mutator.getAxisComponent(this.currentPose, 2)); int offset = isLeft ? 24 + lines.stream().mapToInt(minecraft.font::width).max().orElse(0) : 0; this.renderTooltip(poseStack, lines.stream().map(Component::getVisualOrderText).collect(Collectors.toList()), mouseX - offset, mouseY); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java index db7c29d..3f0fc9c 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.api.client.gui.screens.armorstand; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; @@ -17,4 +18,10 @@ public interface ArmorStandScreen { void setMouseX(int mouseX); void setMouseY(int mouseY); + + DataSyncHandler getDataSyncHandler(); + + default void renderArmorStandInInventory(int posX, int posY, int scale, float mouseX, float mouseY) { + AbstractArmorStandScreen.armorStandRenderer.renderEntityInInventory(posX, posY, scale, mouseX, mouseY, this.getHolder().getArmorStand()); + } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java index f653d13..e1377eb 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java @@ -16,6 +16,7 @@ import java.util.stream.Stream; public class ArmorStandStyleScreen extends ArmorStandTickBoxScreen { + private static final Component STYLE_NAME_COMPONENT = Component.translatable("armorstatues.screen.style.name"); public ArmorStandStyleScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); @@ -30,13 +31,33 @@ protected ArmorStandStyleOption[] getAllTickBoxValues() { @Override protected AbstractWidget makeTickBoxWidget(ArmorStand armorStand, int buttonStartY, int index, ArmorStandStyleOption option) { - return new TickBoxButton(this.leftPos + 96, this.topPos + buttonStartY + index * 22, 6, 76, option.getComponent(), option.getOption(armorStand), (Button button) -> { + return new TickBoxButton(this.leftPos + 96, this.topPos + buttonStartY + index * 22, 6, 76, Component.translatable(option.getTranslationKey()), option.getOption(armorStand), (Button button) -> { this.dataSyncHandler.sendStyleOption(option, ((TickBoxButton) button).isSelected()); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { - this.renderTooltip(poseStack, this.minecraft.font.split(option.getDescriptionComponent(), 175), mouseX, mouseY); + this.renderTooltip(poseStack, this.minecraft.font.split(Component.translatable(option.getDescriptionKey()), 175), mouseX, mouseY); }); } + @Override + protected void syncNameChange(String input) { + this.dataSyncHandler.sendName(input); + } + + @Override + protected int getNameMaxLength() { + return 50; + } + + @Override + protected String getNameDefaultValue() { + return this.holder.getArmorStand().getName().getString(); + } + + @Override + protected Component getNameComponent() { + return STYLE_NAME_COMPONENT; + } + @Override public ArmorStandScreenType getScreenType() { return ArmorStandScreenType.STYLE; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java index a030369..234343b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java @@ -35,18 +35,15 @@ public void tick() { private void testNameInputChanged(boolean testEquality) { if (this.inputUpdateTicks == 0 || !testEquality && this.inputUpdateTicks != -1) { - this.onNameChanged(this.name.getValue()); + String name = this.name.getValue().trim(); + if (!name.equals(this.getNameDefaultValue())) { + this.syncNameChange(name); + } this.inputUpdateTicks = -1; } } - private void onNameChanged(String input) { - input = input.trim(); - ArmorStand armorStand = this.holder.getArmorStand(); - if (!input.equals(armorStand.getName().getString())) { - this.dataSyncHandler.sendName(input); - } - } + protected abstract void syncNameChange(String input); @Override protected void init() { @@ -56,8 +53,8 @@ protected void init() { this.name = new EditBox(this.font, this.leftPos + 16, this.topPos + 32, 66, 9, EntityType.ARMOR_STAND.getDescription()); this.name.setTextColor(16777215); this.name.setBordered(false); - this.name.setMaxLength(50); - this.name.setValue(armorStand.getName().getString()); + this.name.setMaxLength(this.getNameMaxLength()); + this.name.setValue(this.getNameDefaultValue()); this.name.setResponder(input -> this.inputUpdateTicks = 20); this.addWidget(this.name); this.inputUpdateTicks = -1; @@ -68,10 +65,24 @@ protected void init() { } } + protected abstract int getNameMaxLength(); + + protected abstract String getNameDefaultValue(); + protected abstract T[] getAllTickBoxValues(); protected abstract AbstractWidget makeTickBoxWidget(ArmorStand armorStand, int buttonStartY, int index, T option); + @Override + public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { + super.render(poseStack, mouseX, mouseY, partialTick); + if (this.name.isMouseOver(mouseX, mouseY)) { + this.renderTooltip(poseStack, this.font.split(this.getNameComponent(), 175), mouseX, mouseY); + } + } + + protected abstract Component getNameComponent(); + @Override public void resize(Minecraft pMinecraft, int pWidth, int pHeight) { this.testNameInputChanged(false); @@ -107,7 +118,7 @@ protected void renderBg(PoseStack poseStack, float partialTick, int mouseX, int super.renderBg(poseStack, partialTick, mouseX, mouseY); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, ARMOR_STAND_WIDGETS_LOCATION); + RenderSystem.setShaderTexture(0, getArmorStandWidgetsLocation()); // name edit box background this.blit(poseStack, this.leftPos + 14, this.topPos + 30, 0, 108, 76, 12); this.name.render(poseStack, mouseX, mouseY, partialTick); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java index b0a6e99..6993498 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java @@ -16,7 +16,7 @@ import java.util.List; public abstract class ArmorStandWidgetsScreen extends AbstractArmorStandScreen { - private final List widgets; + protected final List widgets; @Nullable private PositionScreenWidget activeWidget; @@ -97,6 +97,8 @@ protected interface PositionScreenWidget { void tick(); + void reset(); + void init(int posX, int posY); void setVisible(boolean visible); @@ -121,6 +123,11 @@ public void tick() { } + @Override + public void reset() { + + } + @Override public void init(int posX, int posY) { this.posX = posX; @@ -138,9 +145,9 @@ public final void setVisible(boolean visible) { @Override public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { if (ArmorStandWidgetsScreen.this.disableMenuRendering()) { - NewTextureButton.drawCenteredString(poseStack, ArmorStandWidgetsScreen.this.font, this.title, this.posX + 36, this.posY + 6, -1, true); + NewTextureButton.drawCenteredString(poseStack, ArmorStandWidgetsScreen.this.font, this.title, this.posX + 36, this.posY + 6, 0xFFFFFFFF, true); } else { - NewTextureButton.drawCenteredString(poseStack, ArmorStandWidgetsScreen.this.font, this.title, this.posX + 36, this.posY + 6, 4210752, false); + NewTextureButton.drawCenteredString(poseStack, ArmorStandWidgetsScreen.this.font, this.title, this.posX + 36, this.posY + 6, 0x404040, false); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java b/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java index 0b2ca2b..a1b598d 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java +++ b/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java @@ -1,24 +1,25 @@ package fuzs.armorstatues.api.helper; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; +import fuzs.puzzleslib.core.CommonAbstractions; import fuzs.armorstatues.mixin.accessor.ArmorStandAccessor; -import fuzs.puzzleslib.core.CoreServices; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.SimpleMenuProvider; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import java.util.Optional; public class ArmorStandInteractHelper { - public static Optional tryOpenArmorStatueMenu(Player player, Level level, ItemStack stack, ArmorStand entity, MenuType menuType) { - if (player.isShiftKeyDown() && stack.is(Items.STICK) && (!entity.isInvulnerable() || player.getAbilities().instabuild)) { + public static Optional tryOpenArmorStatueMenu(Player player, Level level, InteractionHand interactionHand, ArmorStand entity, MenuType menuType) { + ItemStack itemInHand = player.getItemInHand(interactionHand); + if (player.isShiftKeyDown() && itemInHand.isEmpty() && (!entity.isInvulnerable() || player.getAbilities().instabuild)) { openArmorStatueMenu(player, entity, menuType); return Optional.of(InteractionResult.sidedSuccess(level.isClientSide)); } @@ -26,14 +27,13 @@ public static Optional tryOpenArmorStatueMenu(Player player, } public static void openArmorStatueMenu(Player player, ArmorStand entity, MenuType menuType) { - if (player instanceof ServerPlayer serverPlayer) { - CoreServices.ABSTRACTIONS.openMenu(serverPlayer, new SimpleMenuProvider((containerId, inventory, player1) -> { - return ArmorStandMenu.create(menuType, containerId, inventory, entity); - }, entity.getDisplayName()), (serverPlayer1, friendlyByteBuf) -> { - friendlyByteBuf.writeInt(entity.getId()); - friendlyByteBuf.writeBoolean(entity.isInvulnerable()); - friendlyByteBuf.writeInt(((ArmorStandAccessor) entity).getDisabledSlots()); - }); - } + if (!(player instanceof ServerPlayer serverPlayer)) return; + CommonAbstractions.INSTANCE.openMenu(serverPlayer, new SimpleMenuProvider((containerId, inventory, player1) -> { + return ArmorStandMenu.create(menuType, containerId, inventory, entity); + }, entity.getDisplayName()), (serverPlayer1, friendlyByteBuf) -> { + friendlyByteBuf.writeInt(entity.getId()); + friendlyByteBuf.writeBoolean(entity.isInvulnerable()); + friendlyByteBuf.writeInt(((ArmorStandAccessor) entity).getDisabledSlots()); + }); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java index a766339..ef8096d 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java @@ -4,14 +4,13 @@ import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -22,15 +21,19 @@ import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { + private static final Component NO_PERMISSION_COMPONENT = Component.translatable("armorstatues.screen.failure.noPermission"); + @Nullable static ArmorStandScreenType lastType; private final ArmorStand armorStand; + protected final LocalPlayer player; private ArmorStandPose lastSyncedPose; - public CommandDataSyncHandler(ArmorStand armorStand) { + public CommandDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { this.armorStand = armorStand; this.lastSyncedPose = ArmorStandPose.fromEntity(armorStand); + this.player = player; } @Override @@ -41,16 +44,16 @@ public ArmorStand getArmorStand() { @Override public void sendName(String name) { if (!this.testPermissionLevel()) return; - DataSyncHandler.super.sendName(name); + DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); CompoundTag tag = new CompoundTag(); tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); - this.sendCommand(tag); + this.sendDataCommand(tag); } @Override public void sendPose(ArmorStandPose currentPose) { if (!this.testPermissionLevel()) return; - DataSyncHandler.super.sendPose(currentPose); + currentPose.applyToEntity(this.getArmorStand()); // split this into multiple chat messages as the client chat field has a very low character limit this.sendPosePart(currentPose::serializeBodyPoses, this.lastSyncedPose); this.sendPosePart(currentPose::serializeArmPoses, this.lastSyncedPose); @@ -63,42 +66,40 @@ private void sendPosePart(BiPredicate dataWriter, A if (dataWriter.test(tag, lastSyncedPose)) { CompoundTag tag1 = new CompoundTag(); tag1.put("Pose", tag); - this.sendCommand(tag1); + this.sendDataCommand(tag1); } } @Override public void sendPosition(double posX, double posY, double posZ) { if (!this.testPermissionLevel()) return; - DataSyncHandler.super.sendPosition(posX, posY, posZ); ListTag listTag = new ListTag(); listTag.add(DoubleTag.valueOf(posX)); listTag.add(DoubleTag.valueOf(posY)); listTag.add(DoubleTag.valueOf(posZ)); CompoundTag tag = new CompoundTag(); tag.put("Pos", listTag); - this.sendCommand(tag); + this.sendDataCommand(tag); } @Override public void sendRotation(float rotation) { if (!this.testPermissionLevel()) return; - DataSyncHandler.super.sendRotation(rotation); ListTag listTag = new ListTag(); listTag.add(FloatTag.valueOf(rotation)); CompoundTag tag = new CompoundTag(); tag.put("Rotation", listTag); - this.sendCommand(tag); + this.sendDataCommand(tag); } @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { if (!this.testPermissionLevel()) return; - DataSyncHandler.super.sendStyleOption(styleOption, value); + styleOption.setOption(this.getArmorStand(), value); CompoundTag tag = new CompoundTag(); styleOption.toTag(tag, value); - this.sendCommand(tag); + this.sendDataCommand(tag); } @Override @@ -118,15 +119,22 @@ public void setLastType(ArmorStandScreenType lastType) { } private boolean testPermissionLevel() { - Player player = Minecraft.getInstance().player; - if (!player.hasPermissions(2)) { - player.displayClientMessage(Component.translatable("armorstatues.screen.noPermission").withStyle(ChatFormatting.RED), false); + if (!this.player.hasPermissions(2)) { + this.sendFailureMessage(NO_PERMISSION_COMPONENT); return false; } return true; } - private void sendCommand(CompoundTag tag) { - Minecraft.getInstance().player.commandSigned("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString()), null); + protected void sendFailureMessage(Component component) { + this.sendDisplayMessage(Component.translatable("armorstatues.screen.failure", component), true); + } + + protected void sendDisplayMessage(Component component, boolean failure) { + this.player.displayClientMessage(Component.empty().append(component).withStyle(failure ? ChatFormatting.RED : ChatFormatting.GREEN), false); + } + + private void sendDataCommand(CompoundTag tag) { + this.player.commandSigned("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString()), null); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java index 0776524..6ab33d1 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java @@ -13,25 +13,15 @@ public interface DataSyncHandler extends ArmorStandHolder { - default void sendName(String name) { - setCustomArmorStandName(this.getArmorStand(), name); - } - - default void sendPose(ArmorStandPose currentPose) { - currentPose.applyToEntity(this.getArmorStand()); - } + void sendName(String name); - default void sendPosition(double posX, double posY, double posZ) { + void sendPose(ArmorStandPose currentPose); - } - - default void sendRotation(float rotation) { + void sendPosition(double posX, double posY, double posZ); - } + void sendRotation(float rotation); - default void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { - styleOption.setOption(this.getArmorStand(), value); - } + void sendStyleOption(ArmorStandStyleOption styleOption, boolean value); ArmorStandScreenType[] tabs(); @@ -39,11 +29,19 @@ default void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { void setLastType(ArmorStandScreenType lastType); + default void tick() { + + } + + default boolean shouldContinueTicking() { + return false; + } + static void setCustomArmorStandName(ArmorStand armorStand, String name) { - String s = SharedConstants.filterText(name); - if (s.length() <= 50) { - boolean remove = s.isBlank() || s.equals(EntityType.ARMOR_STAND.getDescription().getString()); - armorStand.setCustomName(remove ? null : Component.literal(s)); + name = SharedConstants.filterText(name); + if (name.length() <= 50) { + boolean remove = name.isBlank() || name.equals(EntityType.ARMOR_STAND.getDescription().getString()); + armorStand.setCustomName(remove ? null : Component.literal(name)); } } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java index fa4b3be..f59a7eb 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java @@ -30,13 +30,13 @@ public ArmorStand getArmorStand() { @Override public void sendName(String name) { - DataSyncHandler.super.sendName(name); + DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandNameMessage(name)); } @Override public void sendPose(ArmorStandPose currentPose) { - DataSyncHandler.super.sendPose(currentPose); + currentPose.applyToEntity(this.getArmorStand()); CompoundTag tag = new CompoundTag(); currentPose.serializeAllPoses(tag); ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandPoseMessage(tag)); @@ -44,19 +44,17 @@ public void sendPose(ArmorStandPose currentPose) { @Override public void sendPosition(double posX, double posY, double posZ) { - DataSyncHandler.super.sendPosition(posX, posY, posZ); ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandPositionMessage(posX, posY, posZ)); } @Override public void sendRotation(float rotation) { - DataSyncHandler.super.sendRotation(rotation); ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandRotationMessage(rotation)); } @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { - DataSyncHandler.super.sendStyleOption(styleOption, value); + styleOption.setOption(this.getArmorStand(), value); ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandStyleMessage(styleOption, value)); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java new file mode 100644 index 0000000..5c45828 --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java @@ -0,0 +1,140 @@ +package fuzs.armorstatues.api.network.client.data; + +import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; +import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; +import it.unimi.dsi.fastutil.ints.IntPriorityQueue; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; + +public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { + private static final Component NOT_FINISHED_COMPONENT = Component.translatable("armorstatues.screen.failure.notFinished"); + private static final Component FINISHED_COMPONENT = Component.translatable("armorstatues.screen.finished"); + private static final int DEFAULT_COMMAND_SEND_TICKS = 20; + private static final int MAX_INCREMENTAL_OPERATIONS = 12; + public static final int SHOW_BASE_PLATE_YES = 1; + public static final int SHOW_BASE_PLATE_NO = 2; + public static final int SHOW_ARMS_YES = 3; + public static final int SHOW_ARMS_NO = 4; + public static final int SMALL_STAND_YES = 5; + public static final int SMALL_STAND_NO = 6; + public static final int APPLY_GRAVITY_YES = 7; + public static final int APPLY_GRAVITY_NO = 8; + public static final int STAND_VISIBLE_YES = 9; + public static final int STAND_VISIBLE_NO = 10; + public static final int DISPLAY_NAME_YES = 11; + public static final int DISPLAY_NAME_NO = 12; + public static final int ADJUST_ROTATION_ANGLE_STEP_45 = 120; + public static final int ADJUST_ROTATION_ANGLE_STEP_15 = 121; + public static final int ADJUST_ROTATION_ANGLE_STEP_5 = 122; + public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; + public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; + public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + + private static final IntPriorityQueue QUEUE = new IntArrayFIFOQueue(); + private static boolean queueLocked; + private static int commandSentTicks; + + public VanillaTweaksDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { + super(armorStand, player); + } + + @Override + public void sendRotation(float rotation) { + this.getCloseWithIncrements(this.getArmorStand().getYRot(), rotation, new float[]{1.0F, 5.0F, 15.0F, 45.0F}, new int[]{ADJUST_ROTATION_ANGLE_STEP_1, ADJUST_ROTATION_ANGLE_STEP_5, ADJUST_ROTATION_ANGLE_STEP_15, ADJUST_ROTATION_ANGLE_STEP_45}); + this.finalizeCurrentOperation(); + } + + private void getCloseWithIncrements(float oldValue, float newValue, float[] increments, int[] triggerValues) { + float value = newValue - oldValue; + float signum = Math.signum(value); + value = Math.abs(value); + float lastIncrement = 0.0F; + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + if (value >= increments[0]) { + for (int j = increments.length - 1; j >= 0; j--) { + float currentIncrement = increments[j]; + if (currentIncrement < value) { + value -= currentIncrement; + if (currentIncrement != lastIncrement) { + lastIncrement = currentIncrement; + if (!this.enqueueTriggerValue(triggerValues[j])) return; + } + if (!this.enqueueTriggerValue(signum == -1.0F ? ADJUST_ROTATION_ROTATE_LEFT : ADJUST_ROTATION_ROTATE_RIGHT)) return; + break; + } + } + } else { + break; + } + } + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + int triggerValue; + if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { + triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; + } else if (styleOption == ArmorStandStyleOptions.SHOW_ARMS) { + triggerValue = value ? SHOW_ARMS_YES : SHOW_ARMS_NO; + } else if (styleOption == ArmorStandStyleOptions.SMALL) { + triggerValue = value ? SMALL_STAND_YES : SMALL_STAND_NO; + } else if (styleOption == ArmorStandStyleOptions.INVISIBLE) { + triggerValue = value ? STAND_VISIBLE_NO : STAND_VISIBLE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_BASE_PLATE) { + triggerValue = value ? SHOW_BASE_PLATE_NO : SHOW_BASE_PLATE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_GRAVITY) { + triggerValue = value ? APPLY_GRAVITY_NO : APPLY_GRAVITY_YES; + } else { + super.sendStyleOption(styleOption, value); + return; + } + if (this.enqueueTriggerValue(triggerValue)) { + styleOption.setOption(this.getArmorStand(), value); + } + this.finalizeCurrentOperation(); + } + + @Override + public void tick() { + if (commandSentTicks > 0) commandSentTicks--; + if (commandSentTicks == 0 && !QUEUE.isEmpty()) { + this.sendTriggerCommand(QUEUE.dequeueInt()); + if (QUEUE.isEmpty()) { + this.sendDisplayMessage(FINISHED_COMPONENT, false); + } + } + } + + @Override + public boolean shouldContinueTicking() { + return !QUEUE.isEmpty(); + } + + private boolean enqueueTriggerValue(int triggerValue) { + if (QUEUE.isEmpty()) { + queueLocked = false; + } else if (queueLocked) { + this.sendFailureMessage(NOT_FINISHED_COMPONENT); + return false; + } + QUEUE.enqueue(triggerValue); + return true; + } + + private void finalizeCurrentOperation() { + if (!QUEUE.isEmpty()) { + queueLocked = true; + Screen screen = Minecraft.getInstance().screen; + if (screen != null) screen.onClose(); + } + } + + private void sendTriggerCommand(int triggerValue) { + this.player.commandSigned("trigger as_trigger set %s".formatted(triggerValue), null); + commandSentTicks = DEFAULT_COMMAND_SEND_TICKS; + } +} diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java b/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java new file mode 100644 index 0000000..99047b8 --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java @@ -0,0 +1,16 @@ +package fuzs.armorstatues.api.proxy; + +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; + +public class ClientProxy extends ServerProxy { + + @Override + public Component getStatueHoverText() { + Minecraft minecraft = Minecraft.getInstance(); + Component shiftComponent = Component.empty().append(minecraft.options.keyShift.getTranslatedKeyMessage()).withStyle(ChatFormatting.LIGHT_PURPLE); + Component useComponent = Component.empty().append(minecraft.options.keyUse.getTranslatedKeyMessage()).withStyle(ChatFormatting.LIGHT_PURPLE); + return Component.translatable("armorstatues.item.armor_stand.description", shiftComponent, useComponent).withStyle(ChatFormatting.GRAY); + } +} diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java b/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java new file mode 100644 index 0000000..c7c4d24 --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java @@ -0,0 +1,11 @@ +package fuzs.armorstatues.api.proxy; + +import fuzs.puzzleslib.core.DistTypeExecutor; +import net.minecraft.network.chat.Component; + +public interface Proxy { + @SuppressWarnings("Convert2MethodRef") + Proxy INSTANCE = DistTypeExecutor.getForDistType(() -> () -> new ClientProxy(), () -> () -> new ServerProxy()); + + Component getStatueHoverText(); +} diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java b/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java new file mode 100644 index 0000000..a70146c --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java @@ -0,0 +1,11 @@ +package fuzs.armorstatues.api.proxy; + +import net.minecraft.network.chat.Component; + +public class ServerProxy implements Proxy { + + @Override + public Component getStatueHoverText() { + return Component.empty(); + } +} diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java index c6e9128..72d6a3f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java @@ -24,7 +24,7 @@ import net.minecraft.world.item.ItemStack; public class ArmorStandMenu extends AbstractContainerMenu implements ArmorStandHolder { - public static final ResourceLocation EMPTY_ARMOR_SLOT_SWORD = new ResourceLocation(ArmorStatuesApi.MOD_ID, "item/empty_armor_slot_sword"); + public static final ResourceLocation EMPTY_ARMOR_SLOT_SWORD = ArmorStatuesApi.id("item/empty_armor_slot_sword"); static final ResourceLocation[] TEXTURE_EMPTY_SLOTS = new ResourceLocation[]{InventoryMenu.EMPTY_ARMOR_SLOT_BOOTS, InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET, InventoryMenu.EMPTY_ARMOR_SLOT_SHIELD, EMPTY_ARMOR_SLOT_SWORD}; public static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET, EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND}; @@ -32,8 +32,8 @@ public class ArmorStandMenu extends AbstractContainerMenu implements ArmorStandH private final ArmorStand armorStand; public static ArmorStandMenu create(MenuType menuType, int containerId, Inventory inventory, FriendlyByteBuf buf) { - // not sure how likely it is for this to fail, in that case the menu should just close immediately - ArmorStand entity = (ArmorStand) inventory.player.level.getEntity(buf.readInt()); + int entityId = buf.readInt(); + ArmorStand entity = (ArmorStand) inventory.player.level.getEntity(entityId); if (entity != null) { // vanilla doesn't sync these automatically, we need them for the menu entity.setInvulnerable(buf.readBoolean()); @@ -41,7 +41,10 @@ public static ArmorStandMenu create(MenuType menuType, int containerId, Inven // also create the armor stand container client side, so that visual update instantly instead of having to wait for the server to resync data return create(menuType, containerId, inventory, entity); } - return new ArmorStandMenu(menuType, containerId, inventory, new SimpleContainer(6), null); + // exception is caught, so nothing will crash, only the screen will not open + // not sure how this is even possible, but there was a report about it + // report was concerning just placed statues, so maybe entity data arrived at remote after menu was opened + throw new IllegalStateException("trying to open invalid armor stand menu, entity for id %s was not found on client".formatted(entityId)); } public static ArmorStandMenu create(MenuType menuType, int containerId, Inventory inventory, ArmorStand armorStand) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index 93532bc..63b06ef 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -4,7 +4,6 @@ import net.minecraft.Util; import net.minecraft.core.Rotations; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; @@ -34,7 +33,7 @@ public class ArmorStandPose { private static final Random RANDOM = new Random(); @Nullable - private final String translationId; + private final String name; private final Rotations headPose; private final Rotations bodyPose; private final Rotations leftArmPose; @@ -42,12 +41,12 @@ public class ArmorStandPose { private final Rotations leftLegPose; private final Rotations rightLegPose; - private ArmorStandPose(@Nullable String translationId) { - this(translationId, new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F)); + private ArmorStandPose(@Nullable String name) { + this(name, new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F)); } - private ArmorStandPose(@Nullable String translationId, Rotations headPose, Rotations bodyPose, Rotations leftArmPose, Rotations rightArmPose, Rotations leftLegPose, Rotations rightLegPose) { - this.translationId = translationId; + private ArmorStandPose(@Nullable String name, Rotations headPose, Rotations bodyPose, Rotations leftArmPose, Rotations rightArmPose, Rotations leftLegPose, Rotations rightLegPose) { + this.name = name; this.headPose = headPose; this.bodyPose = bodyPose; this.leftArmPose = leftArmPose; @@ -62,14 +61,12 @@ public static ArmorStandPose empty() { @Override public String toString() { - if (this.translationId != null) { - return this.translationId.toUpperCase(Locale.ROOT); - } - return super.toString(); + return this.name != null ? this.name.toUpperCase(Locale.ROOT) : "POSE"; } - public Component getComponent() { - return Component.translatable("armorstatues.entity.armor_stand.pose." + Objects.requireNonNull(this.translationId, "Trying to get component for transient armor stand pose")); + public String getTranslationKey() { + Objects.requireNonNull(this.name, "name is null"); + return "armorstatues.entity.armor_stand.pose." + this.name; } public Rotations getHeadPose() { @@ -97,27 +94,35 @@ public Rotations getRightLegPose() { } public ArmorStandPose withHeadPose(Rotations rotation) { - return new ArmorStandPose(this.translationId, rotation, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, rotation, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withBodyPose(Rotations rotation) { - return new ArmorStandPose(this.translationId, this.headPose, rotation, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.headPose, rotation, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withLeftArmPose(Rotations rotation) { - return new ArmorStandPose(this.translationId, this.headPose, this.bodyPose, rotation, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.headPose, this.bodyPose, rotation, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withRightArmPose(Rotations rotation) { - return new ArmorStandPose(this.translationId, this.headPose, this.bodyPose, this.leftArmPose, rotation, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.headPose, this.bodyPose, this.leftArmPose, rotation, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withLeftLegPose(Rotations rotation) { - return new ArmorStandPose(this.translationId, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, rotation, this.rightLegPose); + return new ArmorStandPose(this.name, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, rotation, this.rightLegPose); } public ArmorStandPose withRightLegPose(Rotations rotation) { - return new ArmorStandPose(this.translationId, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, rotation); + return new ArmorStandPose(this.name, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, rotation); + } + + public ArmorStandPose mirror() { + return new ArmorStandPose(this.name, mirrorRotation(this.headPose), mirrorRotation(this.bodyPose), mirrorRotation(this.rightArmPose), mirrorRotation(this.leftArmPose), mirrorRotation(this.rightLegPose), mirrorRotation(this.leftLegPose)); + } + + private static Rotations mirrorRotation(Rotations rotations) { + return new Rotations(rotations.getX(), -rotations.getY(), -rotations.getZ()); } public void applyToEntity(ArmorStand armorStand) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java index b177433..41b8990 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java @@ -1,6 +1,5 @@ package fuzs.armorstatues.api.world.inventory.data; -import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -14,27 +13,27 @@ public class ArmorStandScreenType { public static final ArmorStandScreenType POSITION = new ArmorStandScreenType("position", new ItemStack(Items.GRASS_BLOCK)); public static final ArmorStandScreenType ALIGNMENTS = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); - private final String translationId; + private final String name; private final ItemStack icon; private final boolean requiresServer; - public ArmorStandScreenType(String translationId, ItemStack icon) { - this(translationId, icon, false); + public ArmorStandScreenType(String name, ItemStack icon) { + this(name, icon, false); } - public ArmorStandScreenType(String translationId, ItemStack icon, boolean requiresServer) { - this.translationId = translationId; + public ArmorStandScreenType(String name, ItemStack icon, boolean requiresServer) { + this.name = name; this.icon = icon; this.requiresServer = requiresServer; } @Override public String toString() { - return this.translationId.toUpperCase(Locale.ROOT); + return this.name.toUpperCase(Locale.ROOT); } - public Component getComponent() { - return Component.translatable("armorstatues.screen.type." + this.translationId); + public String getTranslationKey() { + return "armorstatues.screen.type." + this.name; } public ItemStack getIcon() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java index ad8d47d..b4fcb80 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java @@ -3,7 +3,6 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; @@ -14,14 +13,14 @@ public interface ArmorStandStyleOption { int ARMOR_STAND_ALL_SLOTS_DISABLED = 4144959; BiMap OPTIONS_REGISTRY = HashBiMap.create(); - String getTranslationId(); + String getName(); - default Component getComponent() { - return Component.translatable("armorstatues.screen.style." + this.getTranslationId()); + default String getTranslationKey() { + return "armorstatues.screen.style." + this.getName(); } - default Component getDescriptionComponent() { - return Component.translatable("armorstatues.screen.style." + this.getTranslationId() + ".description"); + default String getDescriptionKey() { + return this.getTranslationKey() + ".description"; } void setOption(ArmorStand armorStand, boolean setting); @@ -35,7 +34,7 @@ default boolean allowChanges(Player player) { } default ResourceLocation getId() { - return Objects.requireNonNull(OPTIONS_REGISTRY.inverse().get(this), "Armor stand style option %s has not been registered".formatted(this.getTranslationId())); + return Objects.requireNonNull(OPTIONS_REGISTRY.inverse().get(this), "Armor stand style option %s has not been registered".formatted(this.getName())); } static void register(ResourceLocation id, ArmorStandStyleOption styleOption) { @@ -54,7 +53,7 @@ static void setArmorStandData(ArmorStand armorStand, boolean setting, int offset armorStand.getEntityData().set(ArmorStand.DATA_CLIENT_FLAGS, setBit(armorStand.getEntityData().get(ArmorStand.DATA_CLIENT_FLAGS), offset, setting)); } - private static byte setBit(byte oldBit, int offset, boolean value) { + static byte setBit(byte oldBit, int offset, boolean value) { if (value) { oldBit = (byte) (oldBit | offset); } else { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java index 5040407..8dd6b2a 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java @@ -21,19 +21,19 @@ public enum ArmorStandStyleOptions implements ArmorStandStyleOption { ((ArmorStandAccessor) armorStand).setDisabledSlots(setting ? ArmorStandStyleOption.ARMOR_STAND_ALL_SLOTS_DISABLED : 0); }, Entity::isInvulnerable); - private final String translationId; + private final String name; private final BiConsumer newValue; private final Function currentValue; - ArmorStandStyleOptions(String translationId, BiConsumer newValue, Function currentValue) { - this.translationId = translationId; + ArmorStandStyleOptions(String name, BiConsumer newValue, Function currentValue) { + this.name = name; this.newValue = newValue; this.currentValue = currentValue; } @Override - public String getTranslationId() { - return this.translationId; + public String getName() { + return this.name; } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java index f9099ad..d8122db 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java @@ -18,19 +18,19 @@ public final class PosePartMutator { public static final PosePartMutator LEFT_LEG = new PosePartMutator("leftLeg", ArmorStandPose::getRightLegPose, ArmorStandPose::withRightLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(-90.0, 0.0), PosePartAxisRange.range(-120.0, 120.0)); public static final PosePartMutator RIGHT_LEG = new PosePartMutator("rightLeg", ArmorStandPose::getLeftLegPose, ArmorStandPose::withLeftLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(0.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); - private final String translationId; + private final String name; private final Function getRotations; private final BiFunction setRotations; private final PosePartAxisRange[] axisRanges; private final Direction.Axis[] axisOrder; private final byte invertedIndices; - public PosePartMutator(String translationId, Function getRotations, BiFunction setRotations, PosePartAxisRange rangeX, PosePartAxisRange rangeY, PosePartAxisRange rangeZ) { - this(translationId, getRotations, setRotations, rangeX, rangeY, rangeZ, new Direction.Axis[]{Direction.Axis.X, Direction.Axis.Y, Direction.Axis.Z}, Direction.Axis.Y); + public PosePartMutator(String name, Function getRotations, BiFunction setRotations, PosePartAxisRange rangeX, PosePartAxisRange rangeY, PosePartAxisRange rangeZ) { + this(name, getRotations, setRotations, rangeX, rangeY, rangeZ, new Direction.Axis[]{Direction.Axis.X, Direction.Axis.Y, Direction.Axis.Z}, Direction.Axis.Y); } - public PosePartMutator(String translationId, Function getRotations, BiFunction setRotations, PosePartAxisRange rangeX, PosePartAxisRange rangeY, PosePartAxisRange rangeZ, Direction.Axis[] axisOrder, Direction.Axis... invertedAxes) { - this.translationId = translationId; + public PosePartMutator(String name, Function getRotations, BiFunction setRotations, PosePartAxisRange rangeX, PosePartAxisRange rangeY, PosePartAxisRange rangeZ, Direction.Axis[] axisOrder, Direction.Axis... invertedAxes) { + this.name = name; this.getRotations = getRotations; this.setRotations = setRotations; this.axisRanges = new PosePartAxisRange[]{rangeX, rangeY, rangeZ}; @@ -48,11 +48,11 @@ private static byte computeInvertedIndices(Direction.Axis[] invertedAxes) { @Override public String toString() { - return this.translationId.toUpperCase(Locale.ROOT); + return this.name.toUpperCase(Locale.ROOT); } - public Component getComponent() { - return Component.translatable("armorstatues.screen.rotations.pose." + this.translationId); + public String getTranslationKey() { + return "armorstatues.screen.rotations.pose." + this.name; } public Component getAxisComponent(ArmorStandPose pose, int index) { diff --git a/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java index 873aa31..c6c26fc 100644 --- a/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.client.handler; -import net.minecraft.ChatFormatting; +import fuzs.armorstatues.api.proxy.Proxy; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -12,9 +12,9 @@ public class ArmorStandTooltipHandler { public static void onItemTooltip(ItemStack stack, TooltipFlag context, List lines) { if (stack.is(Items.ARMOR_STAND)) { - Component component = Component.translatable("armorstatues.item.armor_stand.description").withStyle(ChatFormatting.GRAY); + Component component = Proxy.INSTANCE.getStatueHoverText(); if (context.isAdvanced()) { - lines.add(lines.size() - 1, component); + lines.add(lines.size() - (stack.hasTag() ? 2 : 1), component); } else { lines.add(component); } diff --git a/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java new file mode 100644 index 0000000..2a1fc84 --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -0,0 +1,10 @@ +package fuzs.armorstatues.config; + +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.puzzleslib.config.ConfigCore; +import fuzs.puzzleslib.config.annotation.Config; + +public class ClientConfig implements ConfigCore { + @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + ArmorStandAlignmentsScreen.VANILLA_TWEAKS_HOMEPAGE}) + public boolean useVanillaTweaksTriggers = false; +} diff --git a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index 37d7482..9f4e207 100644 --- a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -11,7 +11,6 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -23,18 +22,15 @@ public class ArmorStandInteractHandler { private static boolean presentServerside; - public static Optional onEntityInteract(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { + public static Optional onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { if (!player.isSpectator() && target.getType() == EntityType.ARMOR_STAND) { - ItemStack stack = player.getItemInHand(interactionHand); - Optional result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, stack, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get()); - if (result.isPresent() && level.isClientSide && !presentServerside) { - // better to check for client once more, we don't want to accidentally run on the server thread when showing the screen + Optional result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get()); + if (result.isPresent() && level.isClientSide && !presentServerside) { ArmorStatues.PROXY.openArmorStandScreen((ArmorStand) target, player); // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen - // we must return InteractionResult.CONSUME so the interaction is a success, but is not sent to the server (as it will try to remove the armor stand's equipment) - // this will miss out on the player arm swing animation, which we manually play here - player.swing(interactionHand); - return Optional.of(InteractionResult.CONSUME); + // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here + player.swing(interactionHand); + return Optional.of(InteractionResult.FAIL); } return result; } diff --git a/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java b/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java new file mode 100644 index 0000000..82c56f0 --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java @@ -0,0 +1,28 @@ +package fuzs.armorstatues.handler; + +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreen; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +public class DataSyncTickHandler { + @Nullable + private static DataSyncHandler dataSyncHandler; + + public static void onScreenClose(Screen screen) { + if (screen instanceof ArmorStandScreen armorStandScreen && armorStandScreen.getDataSyncHandler().shouldContinueTicking()) { + dataSyncHandler = armorStandScreen.getDataSyncHandler(); + } + } + + public static void onClientTickEnd(Minecraft minecraft) { + if (!(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (dataSyncHandler.shouldContinueTicking()) { + dataSyncHandler.tick(); + } else { + dataSyncHandler = null; + } + } + } +} diff --git a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java index c254070..d266686 100644 --- a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java +++ b/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -1,10 +1,15 @@ package fuzs.armorstatues.proxy; +import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreenFactory; import fuzs.armorstatues.api.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; +import fuzs.armorstatues.api.network.client.data.VanillaTweaksDataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; +import fuzs.armorstatues.config.ClientConfig; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; @@ -12,7 +17,16 @@ public class ClientProxy extends ServerProxy { @Override public void openArmorStandScreen(ArmorStand armorStand, Player player) { - Screen screen = ArmorStandScreenFactory.createLastScreenType(ArmorStandHolder.simple(armorStand), player.getInventory(), armorStand.getDisplayName(), new CommandDataSyncHandler(armorStand)); + ArmorStandHolder holder = ArmorStandHolder.simple(armorStand); + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(armorStand, (LocalPlayer) player)); Minecraft.getInstance().setScreen(screen); } + + private static DataSyncHandler createDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { + if (!player.hasPermissions(2) && ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + return new VanillaTweaksDataSyncHandler(armorStand, player); + } else { + return new CommandDataSyncHandler(armorStand, player); + } + } } diff --git a/Common/src/main/resources/armorstatues.common.mixins.json b/Common/src/main/resources/armorstatues.common.mixins.json index c543bb7..6306a76 100644 --- a/Common/src/main/resources/armorstatues.common.mixins.json +++ b/Common/src/main/resources/armorstatues.common.mixins.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_17", "package": "fuzs.armorstatues.mixin", "refmap": "armorstatues.refmap.json", + "plugin": "fuzs.armorstatues.mixin.ModMixinConfigPlugin", "mixins": [ "accessor.ArmorStandAccessor", "accessor.SimpleContainerAccessor" diff --git a/Fabric/build.gradle b/Fabric/build.gradle index ec38e02..5d7ca7c 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -22,8 +22,8 @@ repositories { url = "https://maven.terraformersmc.com/" } maven { - name = "ladysnake" - url = 'https://ladysnake.jfrog.io/artifactory/mods' + name = 'Ladysnake Mods' + url = 'https://maven.ladysnake.org/releases' } maven { name = "jamieswhiteshirt" diff --git a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java index e0dc624..30247a0 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java +++ b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java @@ -3,6 +3,7 @@ import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.core.CoreServices; +import fuzs.puzzleslib.core.ModLoaderEnvironment; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.player.UseEntityCallback; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; @@ -13,12 +14,13 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; public class ArmorStatuesFabric implements ModInitializer { @Override public void onInitialize() { + // TODO remove again + if (ModLoaderEnvironment.INSTANCE.isServer()) return; CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApi()); CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatues()); registerHandlers(); @@ -29,7 +31,7 @@ private static void registerHandlers() { // this callback runs in two places, one runs only for armor stands and is hit location aware, that's the one we need if (entityHitResult == null) return InteractionResult.PASS; Vec3 vec3 = entityHitResult.getLocation().subtract(target.getX(), target.getY(), target.getZ()); - return ArmorStandInteractHandler.onEntityInteract(player, level, interactionHand, target, vec3).orElse(InteractionResult.PASS); + return ArmorStandInteractHandler.onUseEntityAt(player, level, interactionHand, target, vec3).orElse(InteractionResult.PASS); }); ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { ArmorStandInteractHandler.onPlayerLoggedIn(handler.getPlayer()); diff --git a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java index 2d2fc96..23b3a5f 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java +++ b/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java @@ -2,17 +2,24 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.client.ArmorStatuesApiClient; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreen; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.handler.DataSyncTickHandler; import fuzs.puzzleslib.client.core.ClientCoreServices; +import fuzs.puzzleslib.core.ModLoaderEnvironment; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; public class ArmorStatuesFabricClient implements ClientModInitializer { @Override public void onInitializeClient() { + // TODO remove again + if (ModLoaderEnvironment.INSTANCE.isServer()) return; ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApiClient()); ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesClient()); registerHandlers(); @@ -23,5 +30,11 @@ private static void registerHandlers() { ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { ArmorStandInteractHandler.clearPresentServerside(); }); + ClientTickEvents.END_CLIENT_TICK.register(DataSyncTickHandler::onClientTickEnd); + ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { + if (screen instanceof ArmorStandScreen) { + ScreenEvents.remove(screen).register(DataSyncTickHandler::onScreenClose); + } + }); } } diff --git a/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java b/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..33c80a2 --- /dev/null +++ b/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.armorstatues.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/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index f0908a1..ff6704d 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-01-17T15:26:30.642483 Languages: en_us -e12b3be2312990480ba50bd5340b054e0f0084c3 assets/armorstatues/lang/en_us.json +// 1.19.2 2023-07-25T07:42:53.692341 Languages: en_us +ac65fad1ef91c515edfd99af5fc88ae10f19aba3 assets/statues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/Forge/src/generated/resources/assets/statues/lang/en_us.json similarity index 82% rename from Forge/src/generated/resources/assets/armorstatues/lang/en_us.json rename to Forge/src/generated/resources/assets/statues/lang/en_us.json index 6e8a448..cf66022 100644 --- a/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json +++ b/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -1,33 +1,35 @@ { "armorstatues.entity.armor_stand.pose.athena": "Athena", "armorstatues.entity.armor_stand.pose.brandish": "Brandish", - "armorstatues.entity.armor_stand.pose.cancanA": "Cancan #1", - "armorstatues.entity.armor_stand.pose.cancanB": "Cancan #2", + "armorstatues.entity.armor_stand.pose.cancanA": "Cancan", + "armorstatues.entity.armor_stand.pose.cancanB": "Cancan (Mirrored)", "armorstatues.entity.armor_stand.pose.default": "Default", "armorstatues.entity.armor_stand.pose.entertain": "Entertain", "armorstatues.entity.armor_stand.pose.hero": "Hero", "armorstatues.entity.armor_stand.pose.honor": "Honor", - "armorstatues.entity.armor_stand.pose.none": "None", "armorstatues.entity.armor_stand.pose.riposte": "Riposte", "armorstatues.entity.armor_stand.pose.salute": "Salute", "armorstatues.entity.armor_stand.pose.solemn": "Solemn", "armorstatues.entity.armor_stand.pose.zombie": "Zombie", - "armorstatues.item.armor_stand.description": "Shift + right-click holding a stick to open configuration screen after placing.", + "armorstatues.item.armor_stand.description": "Use %s + %s with an empty hand to open configuration screen.", "armorstatues.screen.alignments.block": "Align Block", "armorstatues.screen.alignments.credit": "Alignment values are taken from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!", "armorstatues.screen.alignments.itemFlat": "Align Item As Flat", "armorstatues.screen.alignments.itemFloating": "Align Item As Floating", "armorstatues.screen.alignments.tool": "Align Tool As Flat", - "armorstatues.screen.noPermission": "Unable to set new armor stand data; no permission", + "armorstatues.screen.failure": "Unable to modify armor stand data: %s", + "armorstatues.screen.failure.noPermission": "No Permission", + "armorstatues.screen.failure.notFinished": "Last Action Not Finished", + "armorstatues.screen.finished": "Finished sending queued armor stand data", "armorstatues.screen.pose.randomize": "Randomize", "armorstatues.screen.pose.randomized": "Applied!", "armorstatues.screen.position.aligned": "Aligned!", "armorstatues.screen.position.blocks": "%s Block(s)", "armorstatues.screen.position.centered": "Align Centered", "armorstatues.screen.position.cornered": "Align Cornered", - "armorstatues.screen.position.decrement": "Decrement By %s", + "armorstatues.screen.position.decrement": "Decrement by %s", "armorstatues.screen.position.degrees": "%s°", - "armorstatues.screen.position.increment": "Increment By %s", + "armorstatues.screen.position.increment": "Increment by %s", "armorstatues.screen.position.moveBy": "Move By:", "armorstatues.screen.position.pixels": "%s Pixel(s)", "armorstatues.screen.position.rotation": "Rotation:", @@ -36,6 +38,7 @@ "armorstatues.screen.position.z": "Z-Position:", "armorstatues.screen.rotations.copy": "Copy", "armorstatues.screen.rotations.limited": "Limited Rotations", + "armorstatues.screen.rotations.mirror": "Mirror", "armorstatues.screen.rotations.paste": "Paste", "armorstatues.screen.rotations.pose.body": "Body", "armorstatues.screen.rotations.pose.head": "Head", @@ -47,15 +50,13 @@ "armorstatues.screen.rotations.reset": "Reset", "armorstatues.screen.rotations.tip1": "Hold the Shift or Alt key to lock sliders to a single axis!", "armorstatues.screen.rotations.tip2": "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking.", - "armorstatues.screen.rotations.tip3": "Press the %s key (or Shift + %s) to quickly switch between tabs!", "armorstatues.screen.rotations.unlimited": "Unlimited Rotations", "armorstatues.screen.rotations.x": "X: %s", "armorstatues.screen.rotations.y": "Y: %s", "armorstatues.screen.rotations.z": "Z: %s", - "armorstatues.screen.style.glowing": "Glowing", - "armorstatues.screen.style.glowing.description": "Adds a glowing outline to the statue, visible through blocks.", "armorstatues.screen.style.invisible": "Invisible", "armorstatues.screen.style.invisible.description": "Makes the statue itself invisible, but still shows all equipped items.", + "armorstatues.screen.style.name": "Set a name to display above the entity if enabled.", "armorstatues.screen.style.noBasePlate": "No Base Plate", "armorstatues.screen.style.noBasePlate.description": "Hide the stone base plate at the statue's feet.", "armorstatues.screen.style.noGravity": "No Gravity", @@ -73,6 +74,5 @@ "armorstatues.screen.type.poses": "Poses", "armorstatues.screen.type.position": "Position", "armorstatues.screen.type.rotations": "Rotations", - "armorstatues.screen.type.style": "Style", - "key.cycleStatueTabs": "Cycle Statue Tabs" + "armorstatues.screen.type.style": "Style" } \ No newline at end of file diff --git a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java index aefa51e..db2c0b2 100644 --- a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java +++ b/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java @@ -30,9 +30,7 @@ public static void onConstructMod(final FMLConstructModEvent evt) { private static void registerHandlers() { // high priority so we run before the Quark mod MinecraftForge.EVENT_BUS.addListener(EventPriority.HIGH, (final PlayerInteractEvent.EntityInteractSpecific evt) -> { - // we use our custom event client-side, as it allows for cancelling the packet being sent to the server - if (!evt.getSide().isServer()) return; - ArmorStandInteractHandler.onEntityInteract(evt.getEntity(), evt.getLevel(), evt.getHand(), evt.getTarget(), evt.getLocalPos()).ifPresent(result -> { + ArmorStandInteractHandler.onUseEntityAt(evt.getEntity(), evt.getLevel(), evt.getHand(), evt.getTarget(), evt.getLocalPos()).ifPresent(result -> { evt.setCancellationResult(result); evt.setCanceled(true); }); diff --git a/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java index 195de76..41a214e 100644 --- a/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java +++ b/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java @@ -1,19 +1,30 @@ package fuzs.armorstatues.client; import fuzs.armorstatues.ArmorStatues; -import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.client.ArmorStatuesApiClient; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.handler.DataSyncTickHandler; import fuzs.puzzleslib.client.core.ClientCoreServices; +import net.minecraft.client.Minecraft; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ClientPlayerNetworkEvent; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +import java.util.Optional; + @Mod.EventBusSubscriber(modid = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ArmorStatuesForgeClient { @@ -25,11 +36,38 @@ public static void onConstructMod(final FMLConstructModEvent evt) { } private static void registerHandlers() { + MinecraftForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { + + Minecraft minecraft = Minecraft.getInstance(); + if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { + + EntityHitResult hitResult = (EntityHitResult) minecraft.hitResult; + Entity entity = hitResult.getEntity(); + if (minecraft.level.getWorldBorder().isWithinBounds(entity.blockPosition()) && minecraft.player.canInteractWith(entity, 0)) { + + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + Optional result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work + if (result.filter(t -> t == InteractionResult.FAIL).isPresent()) { + evt.setSwingHand(false); + evt.setCanceled(true); + } + } + } + }); MinecraftForge.EVENT_BUS.addListener((final ItemTooltipEvent evt) -> { ArmorStandTooltipHandler.onItemTooltip(evt.getItemStack(), evt.getFlags(), evt.getToolTip()); }); MinecraftForge.EVENT_BUS.addListener((final ClientPlayerNetworkEvent.LoggingIn evt) -> { ArmorStandInteractHandler.clearPresentServerside(); }); + MinecraftForge.EVENT_BUS.addListener((final TickEvent.ClientTickEvent evt) -> { + if (evt.phase != TickEvent.Phase.END) return; + DataSyncTickHandler.onClientTickEnd(Minecraft.getInstance()); + }); + MinecraftForge.EVENT_BUS.addListener((final ScreenEvent.Closing evt) -> { + DataSyncTickHandler.onScreenClose(evt.getScreen()); + }); } } diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index ba408b4..bd3a2d1 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -1,5 +1,8 @@ package fuzs.armorstatues.data; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; import net.minecraft.data.DataGenerator; import net.minecraftforge.common.data.LanguageProvider; @@ -11,43 +14,40 @@ public ModLanguageProvider(DataGenerator gen, String modId) { @Override protected void addTranslations() { - this.add("key.cycleStatueTabs", "Cycle Statue Tabs"); - this.add("armorstatues.item.armor_stand.description", "Shift + right-click holding a stick to open configuration screen after placing."); - this.add("armorstatues.entity.armor_stand.pose.athena", "Athena"); - this.add("armorstatues.entity.armor_stand.pose.brandish", "Brandish"); - this.add("armorstatues.entity.armor_stand.pose.cancanA", "Cancan #1"); - this.add("armorstatues.entity.armor_stand.pose.cancanB", "Cancan #2"); - this.add("armorstatues.entity.armor_stand.pose.default", "Default"); - this.add("armorstatues.entity.armor_stand.pose.entertain", "Entertain"); - this.add("armorstatues.entity.armor_stand.pose.hero", "Hero"); - this.add("armorstatues.entity.armor_stand.pose.honor", "Honor"); - this.add("armorstatues.entity.armor_stand.pose.none", "None"); - this.add("armorstatues.entity.armor_stand.pose.riposte", "Riposte"); - this.add("armorstatues.entity.armor_stand.pose.salute", "Salute"); - this.add("armorstatues.entity.armor_stand.pose.solemn", "Solemn"); - this.add("armorstatues.entity.armor_stand.pose.zombie", "Zombie"); - this.add("armorstatues.screen.type.equipment", "Equipment"); - this.add("armorstatues.screen.type.rotations", "Rotations"); - this.add("armorstatues.screen.type.style", "Style"); - this.add("armorstatues.screen.type.poses", "Poses"); - this.add("armorstatues.screen.type.position", "Position"); - this.add("armorstatues.screen.type.alignments", "Alignments"); - this.add("armorstatues.screen.style.showArms", "Show Arms"); - this.add("armorstatues.screen.style.small", "Small"); - this.add("armorstatues.screen.style.invisible", "Invisible"); - this.add("armorstatues.screen.style.noBasePlate", "No Base Plate"); - this.add("armorstatues.screen.style.showName", "Show Name"); - this.add("armorstatues.screen.style.noGravity", "No Gravity"); - this.add("armorstatues.screen.style.glowing", "Glowing"); - this.add("armorstatues.screen.style.sealed", "Sealed"); - this.add("armorstatues.screen.style.showArms.description", "Shows the statue's arms, so it may hold items in both hands."); - this.add("armorstatues.screen.style.small.description", "Makes the statue half it's size like a baby mob."); - this.add("armorstatues.screen.style.invisible.description", "Makes the statue itself invisible, but still shows all equipped items."); - this.add("armorstatues.screen.style.noBasePlate.description", "Hide the stone base plate at the statue's feet."); - this.add("armorstatues.screen.style.showName.description", "Render the statue's name tag above it's head."); - this.add("armorstatues.screen.style.noGravity.description", "Prevents the statue from falling down, so it may float freely."); - this.add("armorstatues.screen.style.glowing.description", "Adds a glowing outline to the statue, visible through blocks."); - this.add("armorstatues.screen.style.sealed.description", "The statue can no longer be broken, equipment cannot be changed. Disallows opening this menu in survival mode."); + this.add("armorstatues.item.armor_stand.description", "Use %s + %s with an empty hand to open configuration screen."); + this.add("armorstatues.screen.style.name", "Set a name to display above the entity if enabled."); + this.add(ArmorStandPose.ATHENA.getTranslationKey(), "Athena"); + this.add(ArmorStandPose.BRANDISH.getTranslationKey(), "Brandish"); + this.add(ArmorStandPose.CANCAN_A.getTranslationKey(), "Cancan"); + this.add(ArmorStandPose.CANCAN_B.getTranslationKey(), "Cancan (Mirrored)"); + this.add(ArmorStandPose.DEFAULT.getTranslationKey(), "Default"); + this.add(ArmorStandPose.ENTERTAIN.getTranslationKey(), "Entertain"); + this.add(ArmorStandPose.HERO.getTranslationKey(), "Hero"); + this.add(ArmorStandPose.HONOR.getTranslationKey(), "Honor"); + this.add(ArmorStandPose.RIPOSTE.getTranslationKey(), "Riposte"); + this.add(ArmorStandPose.SALUTE.getTranslationKey(), "Salute"); + this.add(ArmorStandPose.SOLEMN.getTranslationKey(), "Solemn"); + this.add(ArmorStandPose.ZOMBIE.getTranslationKey(), "Zombie"); + this.add(ArmorStandScreenType.EQUIPMENT.getTranslationKey(), "Equipment"); + this.add(ArmorStandScreenType.ROTATIONS.getTranslationKey(), "Rotations"); + this.add(ArmorStandScreenType.STYLE.getTranslationKey(), "Style"); + this.add(ArmorStandScreenType.POSES.getTranslationKey(), "Poses"); + this.add(ArmorStandScreenType.POSITION.getTranslationKey(), "Position"); + this.add(ArmorStandScreenType.ALIGNMENTS.getTranslationKey(), "Alignments"); + this.add(ArmorStandStyleOptions.SHOW_ARMS.getTranslationKey(), "Show Arms"); + this.add(ArmorStandStyleOptions.SHOW_ARMS.getDescriptionKey(), "Shows the statue's arms, so it may hold items in both hands."); + this.add(ArmorStandStyleOptions.SMALL.getTranslationKey(), "Small"); + this.add(ArmorStandStyleOptions.SMALL.getDescriptionKey(), "Makes the statue half it's size like a baby mob."); + this.add(ArmorStandStyleOptions.INVISIBLE.getTranslationKey(), "Invisible"); + this.add(ArmorStandStyleOptions.INVISIBLE.getDescriptionKey(), "Makes the statue itself invisible, but still shows all equipped items."); + this.add(ArmorStandStyleOptions.NO_BASE_PLATE.getTranslationKey(), "No Base Plate"); + this.add(ArmorStandStyleOptions.NO_BASE_PLATE.getDescriptionKey(), "Hide the stone base plate at the statue's feet."); + this.add(ArmorStandStyleOptions.SHOW_NAME.getTranslationKey(), "Show Name"); + this.add(ArmorStandStyleOptions.SHOW_NAME.getDescriptionKey(), "Render the statue's name tag above it's head."); + this.add(ArmorStandStyleOptions.NO_GRAVITY.getTranslationKey(), "No Gravity"); + this.add(ArmorStandStyleOptions.NO_GRAVITY.getDescriptionKey(), "Prevents the statue from falling down, so it may float freely."); + this.add(ArmorStandStyleOptions.SEALED.getTranslationKey(), "Sealed"); + this.add(ArmorStandStyleOptions.SEALED.getDescriptionKey(), "The statue can no longer be broken, equipment cannot be changed. Disallows opening this menu in survival mode."); this.add("armorstatues.screen.position.rotation", "Rotation:"); this.add("armorstatues.screen.position.degrees", "%s\u00B0"); this.add("armorstatues.screen.position.moveBy", "Move By:"); @@ -56,8 +56,8 @@ protected void addTranslations() { this.add("armorstatues.screen.position.x", "X-Position:"); this.add("armorstatues.screen.position.y", "Y-Position:"); this.add("armorstatues.screen.position.z", "Z-Position:"); - this.add("armorstatues.screen.position.increment", "Increment By %s"); - this.add("armorstatues.screen.position.decrement", "Decrement By %s"); + this.add("armorstatues.screen.position.increment", "Increment by %s"); + this.add("armorstatues.screen.position.decrement", "Decrement by %s"); this.add("armorstatues.screen.position.centered", "Align Centered"); this.add("armorstatues.screen.position.cornered", "Align Cornered"); this.add("armorstatues.screen.position.aligned", "Aligned!"); @@ -71,13 +71,13 @@ protected void addTranslations() { this.add("armorstatues.screen.rotations.pose.rightLeg", "Right Leg"); this.add("armorstatues.screen.rotations.tip1", "Hold the Shift or Alt key to lock sliders to a single axis!"); this.add("armorstatues.screen.rotations.tip2", "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking."); - this.add("armorstatues.screen.rotations.tip3", "Press the %s key (or Shift + %s) to quickly switch between tabs!"); this.add("armorstatues.screen.rotations.reset", "Reset"); this.add("armorstatues.screen.rotations.randomize", "Randomize"); this.add("armorstatues.screen.rotations.limited", "Limited Rotations"); this.add("armorstatues.screen.rotations.unlimited", "Unlimited Rotations"); this.add("armorstatues.screen.rotations.copy", "Copy"); this.add("armorstatues.screen.rotations.paste", "Paste"); + this.add("armorstatues.screen.rotations.mirror", "Mirror"); this.add("armorstatues.screen.rotations.x", "X: %s"); this.add("armorstatues.screen.rotations.y", "Y: %s"); this.add("armorstatues.screen.rotations.z", "Z: %s"); @@ -86,6 +86,9 @@ protected void addTranslations() { this.add("armorstatues.screen.alignments.itemFlat", "Align Item As Flat"); this.add("armorstatues.screen.alignments.tool", "Align Tool As Flat"); this.add("armorstatues.screen.alignments.credit", "Alignment values are taken from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); - this.add("armorstatues.screen.noPermission", "Unable to set new armor stand data; no permission"); + this.add("armorstatues.screen.failure", "Unable to modify armor stand data: %s"); + this.add("armorstatues.screen.failure.noPermission", "No Permission"); + this.add("armorstatues.screen.failure.notFinished", "Last Action Not Finished"); + this.add("armorstatues.screen.finished", "Finished sending queued armor stand data"); } } diff --git a/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java b/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..b9a58bc --- /dev/null +++ b/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.armorstatues.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/Forge/src/main/java/fuzs/armorstatues/mixin/client/MultiPlayerGameModeMixin.java b/Forge/src/main/java/fuzs/armorstatues/mixin/client/MultiPlayerGameModeMixin.java deleted file mode 100644 index 12667d8..0000000 --- a/Forge/src/main/java/fuzs/armorstatues/mixin/client/MultiPlayerGameModeMixin.java +++ /dev/null @@ -1,39 +0,0 @@ -package fuzs.armorstatues.mixin.client; - -import fuzs.armorstatues.handler.ArmorStandInteractHandler; -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.client.multiplayer.MultiPlayerGameMode; -import net.minecraft.network.protocol.game.ServerboundInteractPacket; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.Vec3; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.Optional; - -@Mixin(MultiPlayerGameMode.class) -abstract class MultiPlayerGameModeMixin { - @Shadow - @Final - private ClientPacketListener connection; - - @Inject(method = "interactAt", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;ensureHasSentCarriedItem()V", shift = At.Shift.AFTER), cancellable = true) - public void interactAt(Player player, Entity target, EntityHitResult ray, InteractionHand hand, CallbackInfoReturnable callback) { - Vec3 vec3 = ray.getLocation().subtract(target.getX(), target.getY(), target.getZ()); - Optional result = ArmorStandInteractHandler.onEntityInteract(player, player.level, hand, target, vec3); - if (result.isPresent()) { - if (result.get() == InteractionResult.SUCCESS) { - this.connection.send(ServerboundInteractPacket.createInteractionPacket(target, player.isShiftKeyDown(), hand, vec3)); - } - callback.setReturnValue(result.get()); - } - } -} diff --git a/Forge/src/main/resources/armorstatues.forge.mixins.json b/Forge/src/main/resources/armorstatues.forge.mixins.json deleted file mode 100644 index 16fc290..0000000 --- a/Forge/src/main/resources/armorstatues.forge.mixins.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "package": "fuzs.armorstatues.mixin", - "refmap": "armorstatues.refmap.json", - "mixins": [ - ], - "client": [ - "client.MultiPlayerGameModeMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/Forge/src/main/resources/assets/armorstatues/textures/gui/container/armor_stand/background.png b/Forge/src/main/resources/assets/armorstatues/textures/gui/container/armor_stand/background.png deleted file mode 100644 index 7414c9e0745a3e3ed26f6c0cc764a5f7d5432d89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2985 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G!U;i$lZxy-8q?;K+dw%2+uTM zUj{88n}dOkQHX&Vqy(gmQHp^T%w}K+W0Z!o;}|udYM6j(3>knVgD4QEwP!N0K-Jd( zX%O%LVvqyCbUlpi<;HsXMd|v6mX?Mj~b4o#eu`@R^00MnO5NQK; zAc{1?dl0SuMVYC<00L_@gsMjtLsuV(-zsEjbgc-Tp?R4lc1BR!(1ek6fr7~joLD1W zGILY&ib4J}GBvZ&$0~zWX9P~2NHRz|fuV2ZT$BpR93lDnId<6cij6+HDl`Lpfr&XK zu_VzYu_V>b$N-oU4J>sHjY15~tc)zJ49&C+jI2Ph12P6hEz}$veNc)-N}-VC4;BTc ze>*OqR#;xLYRTtFeU3T|$gZ=I8rGp9C7C8$bW7`Fk+<|M|+;^|Ki(s;hVBzRYLg_@hx^BWGV%XEk?S zz1`D%rt9|^e*O65t|%}=V25Nw=P@rKg$WIe9Zm`x)DsxK<*hSpWZ`iTVQRExWZqC- z+{>wwz_3Vw;|-@o!`|81J_?M?0<8`S{s$P|+>J?Q0*Y#|FjX_LCA@zoCG2s4!9`Kv zhOhxcwfXfK4oqwcT#X0jH89@Tz4I80kO4y=2g^4Wo&)#JnyQUjIU2B|$!9c^45Fgo zH*4SV$A9_lKTNK_fB)@=e>>-#e?I;H(ksl>)uv4RsvmwzA9(on>(_;GXHE-Lur*$O zSyFrUu<@SP{_lVMJ*sbS`y?G$*lKx0R@MKQ3er#V6*vv{jwyL U%A_YtHh@~Ap00i_>zopr06*G#ga7~l diff --git a/Forge/src/main/resources/assets/armorstatues/textures/gui/container/armor_stand/widgets.png b/Forge/src/main/resources/assets/armorstatues/textures/gui/container/armor_stand/widgets.png deleted file mode 100644 index 8984ea6ab86c4d378977fc9d599296ea537e5188..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9721 zcmc(Fc|6qL_y23g#7x;`%`)~V+lbI$Vr*s264{e|8T(R@9Ug%?>!>4HB~51vz!J1fI>|b zdjkLk{~qXKkovqoDx^f@L^B3ZVr^PFPN05EkIn z?=k=wK+gTUYz8_1Cl3_l5d*+qfF8VU!t4RqpZxyd^W;(m?-K=nKeg?Bt(}}LJ#p?x zZFd|JC45QvGDsuIg8bEH7W7{-AV3z$UuBRFIHi211$-b}RgF9V;0)c#4FOWpm_Qk6 z_Iie%h8pTJRyb#2%R9K+*22Edt|uq}?JENoovl4Bk-pAOE*>(zvRuD8WWe%CwFnpT zH;bpEESI5%Hc}DiZjF=xwG-u%JB>sl(e8I_WNu)U|Ad2YvRrnao~|+?B0fGo!am}{ zIConSF==UO5mA%~3MB+`2zmIqcv|`jxp;8@A>?0ju+|<{?)I*p_Ba>hiCoLuI4@6G zF0PY?{(b$Sr>DKmUoE+K{MjwAgCZvs5iwy=k^cs>_O<^XuoKGvgn?u9?{57^W4@NI ze}H}u#veMOPc)FZVeNr)@;d2?zKgx5918tgv42+o)w4fPhJV52E~7-jOGNDC_fPcS z$^V3Ex!YTV!+O%9oY+Qs9fIh2GXTI9b{ z{)tq?IpN%OT`jGwPjvhZ`CHXLxqr7~_&?kE8|80EaIRz&-K|edNe_o}lKXF#g%*yOHWIzrKhzVN)-HVMWuyMC_NNP1|=mUe))nZO6Fu%PQ?5N@1JteA}8PP z-@fNRjOBMNXf1N5LFm6MPwq79Q2Sc|;KZt7uj=_iR!yCY*joHDNW6D}@FGu;n6$9AGHbP_DtGcD>Vj0?%Ij`Y!$B%V+7z8t`xDd#iYVU8Oj&yXFVl zDV(DA6$S2}F+_*&O1BPFIQA%*bO$(oy8U0rIZ zn@(FACGY4Fj30}OWDk#~2kVe`mX?D61_p+TSwnUtU=fx@8fLXJ)&A@DZVe(3ZH)jl zS6MVO(D`QfRwYi^cAvAcvB|}48WbzkGc-^!LJbX+R*Xw38Pbh;KL!mHdaVoxeMPBI zGhP`kH7|X{b|tUkHlry;Y{a45{KA5xGYXM)XJ@ePe&i+GRDFQM-MhEg(7wGLm&m$f zV(A&nU$@H$C$`!rvTN)*#{$<5f>U~%cvBXN9fsRP=Duhy>gWv5!G&dmy*OiRO>XJ) z093xX&lN5ApKcU1Qn5W+q+NTv!0t5_u%nc1BO}Pfekc0ihRd+kySp$|AVbt;Utu|d zjz3`~inLoqQ^buW3iaN$#a_nHfC9Rpm-F=2_#=WQ)X4b>jogLq{$}@Mcr0*WHHL^r zZE|;?cDH{_Z@XmqHV~9`B<5VF?1sOjX9Km5?q=D0j@BUSD7Z?1X;YLG4;P34+0Sgo zocvF;wvo*%Q~?RHAJgUUN39#VEd;TU0JUdCNqcMDuc1k!TJNQ@xH_KQ*&An71)SF= z#j1r$i3HJgVT>u%?7(4DQBGJY4lvQqR=0$iWC}GRM2#2Uzcgm*JT2%>kpLR&>@(kPOPS_jT6DZL(Leh66J>W>pymvrr86 z%ZE?+6T6nnTiGM;bb9KEqGQ3ql3W?$jPBCuhyIjx+ALNugXV4vcND=J_r7kyjk>9l zf9rLzxt|LIHM~`8>>r-yEuM?WX> z@ChFlYoi@!6F1TCQhAJTE|5L&r_54o$bB%DBC&bhPce1Gu2Kz%UaPlZilJfWyx^kj zIA+a@$TB@N>KJZ=XVQ=K?>;@J1hw-c8+qnu#NCiE(ll%$IZ?QO?Z{ofC`J^KB^S`g zbUg#Vzm!yLBV)kCQ=yC(xV$nXL(yu^Xm~!*@xCVs2_h>fUD74Kv}R3)S2Kob=@pXO z-ykh7$H02#;5DisNvxK_ki5EkgqF6=9S`t=#0j{z#)AA8cp+Uh4}?ddIrtLn&TQf+ z-n4goW zmfmmPJGZ>sf2jllr;SRd5q)uJGiIb?da9+byfG{*z6q(4pWbw}Ih{k}D>+6cL5zkP zCOXqmaP$aCryIa|s_oT>y}q-wfVKq^$_GWg`#~;z3InBOsbA#picLxcf?-x%7K#9t zKx3|OrsUUifp9fIh6T+Bm4t=BZb|Ov~FPX!sf%D3J1c_lKYJ{ zM{hkTgb@rs$Y%>o%q?j#0l)GjpEg;Jodx~h!+(Y1$$I1XAR7 z0zXtpfshCYEvrjf+tc)3K5QPrJpK6{->nQ?zt8>JlN=%yh-=O630oqK0}xqO@+Oki zXy{{NN6!18_Al=;P^v(D@X_JUR4M3jjgE5Z?U4{Y*u|kLI!G$<#j9706D~#D#fr3; zYd^}v;frv?bopOjvszYQrbZf%)BuSkc#4h)Z2J3cn)yw4*2u31&4<8#>n}kaVS{`# z1TCg+|NihG5M-CjF~)U=T6o`nE6CWAZ)NZ zh}gVAlYQ`j&6Tvbj56o#5Eo!esfIKhqH2CL9Vj{!6Md9Iyy>X1J*EZ>S#^qEB8PB7 zlA_1&Ie(!dzNcbomM($UZ5bWzeuDg=poIiOM~pLaV~dY zE%10b-H%GZFZvlurS$E$ueeL2dVac-#xe%9(*-ebHZo%(Wjyjz-CJM%JVdX~QgJxV zhoN5c<+7KU)<|C5k)VB%Q8c4Ki)jI>^<~qJpUF48AFHMB$Xxkx=;B99$a&&cQL*hD zO}C(8M8EI6a53)1c*MS%)Fy2f{2g0q{QLo7{;1UCnT^Zq9!isE@f_<7-(eW~$d~3ZLc)Axp*y}j`yyhnrRlk>+-+I{)!8d~iavLVnuLqw?c`1LDFx}~-`lu? z>hA3npr#ZPh?jWzAeWxMaIkyvmL19We$UN5i!L;Qx5Yg=MQ`l_#~CZQT8`gZ%mW*y z2mCuIY+B@1P2sN}BIvjakJLV>KwYmUpz`5KIRR!1jC1<&n5V=@wtA~q9V)T>9Pyq@ zmFEwcHY*-j(sCe>h%VN>(Mu#n+HnTB@ zj1EtHLOh_Ja5{IS)Lb4lCzzGzrtg#pR0h&C2pQ(;)T?1w-_HX|--$XZK8C6F=t@%4 zn_sFnuOiRwvvpti#xwsM!^}jK!i@QC%3xE3Gp+4c?{^thv$i}%byKmWLEv#~Zf`Ds z*!b2;#~3%E|5~yC#kZC4T8AT-D6fTc#AHCPt#XrUuSk2?uVc8UqSWcFCR8bnY1_I=JGYpJFe5v9 zChfzxP{xdno`Lw#-ds^Vo7tAPfbhx(C06rwUeLepee1pwh;K9GMg*ZW({cxRGhx%g z{V&yzHxxx;=Bs!X^0WfZ&dy&VX&b*Yr8TxUoLDVuv{}DOEH1q)E&bWt(6G&ctb+u$ zuFWVJ;#^70$uXA+FmN76M=1W_p|)6Xo`+o#$uLA*sS6R@Iwf_trS~#E4U%xMG_5jF z<+`dH_J$AX|FKw3jQVq5Hjs_`{gXjG9=+5x*LRpKW;-3`b#7)yU zto0YG(<@aoT=yf*c4cfyu^63~vt%aT-n@4ojy)TxT&kE`^7`mT zo;tnmc;t)Pzg`h9PH@}OR_w9&z!SwRK2xgm2h}E$sL2m!mqjR^EsnWsFS*xi{!y~7 z1T@H6`vFCrzKrId%x4hD;BYcOYUy{VnY_o zMpJgj;$huc9zv+t^SBo)UV-jC&`H(dhz4^w1LWK1$PbJS)*8_8Zy)p^u+BcYQeuZd zAzx4sv2b)IDXpe`bcDoeGxv5}u}si%YiyzfIT7^$78}Ax)TQaQg}g)lgmsEWn6K8E86LXcyx*PQbO4w$=A zvU@T-DG{1Xe*?BDg?X5=ew8U<vm=?%>rA~bCTJ^MV3q7}&CfW@UA5H*^syx{a&qyZAEw zkPzmUNGY-94yR|T#%h4vy-KThA+RkQZY?dM)VZJvO_L8BErPTJWYZgJsOPRiS+t(u zw-4Oy?ssAVcY;#iCVUs)-(6k5DHP?n?wpAW;34=1is_3%jeopR|JtL{NSZ93vCSqu zyW?12nXv;yyW0g$@#A>_jt1;gR&`D7~Pb2 zo_r=(Qk1_dQ>L*uUHP>t&U?12vonNZLxMJj?uj+OR)${ngnNgSvt8#~k($n)*N#>! zX}4dl4oq{^-`?{G;K(Gu|3`#+E_?T4cTBC|*2;pQN6|P!R!!=GBXD3@bCp8d*4B11 z#Q5Tq`2#!2DiYlSRzw>W)5u=Za|Q~zbUmkj=Z$>x5#xD7C#W}V*-~LN>M}gpWX?)XKa1;_jGk1}t75cx*6#J5!5!6sp2F1M{1q@{_#c$Joff z&(_b|bM)&AUGGosZAhV%vX1GDp8a-5r(XZoyb#?&^^kanDj=DVloNgA^#Aq!`IgKm5t zq5q7fTmZwmusj@(b!mIic&T9VAwrO5W`q@{BKv6IEq z)Nj0f0dQIrFQtZp(T0<^`I;Xqauw~z#-)+iQ}OC&la2a_sRHvt*papGY3-Xc?l;=0 zA#9M$N2Mzo9<-*yONPrM_Om0-p#gb6=y{8>x1R>tn|xNjT;JWgxSs8-Fd6m40$2FX z>tk<=Bp77|1w0OMS8RgBraQLWOjqx9_1*eaV?)>DJ4x5MRRQ7iUM4np z{FgIO!^9xsufc^D(a5;%m62A4dogTR=C^4qI|S-%Oaq37#C~PUZWayUX$dz+^NWVz z6NRf<>k`&paJPen%s{!}gbtAgwC78~i0SF#z_T7>Nsy~Ez3-W~S8pD*I8+NnZUwcn zBPuUX`qvaob#njS*cfmE3+69g+d0Q(#DHOC%F{oea}OEJL%Tcuq9Jj)5f}JlAi2Bd zXOO9T`{Ui-{c)1}iDWp&I>rI3M?Y`q`1q%i+nnM7u131uqY+J?>c5dn)Y8%lizB0A zk8&Wu`&FkG8hqmK{wUeu-n-Ipq_Le`v!*wK-=#ej?8+H5a^&J;c$__6C2%Np!$CT> z@5_y|)`vUCwe;)_NBe;-0Ck=uP=3^Ec_psETF_LAX^ehtUd#>;8O)nOIKJCml%ikJPrB*WT= zdoJ~!B@j87ZCC~Z-TbAbf^)QC^w1UYlDk$CNEok#z?KJThu5I3qff@uFlgQ%5(@ zRoRp#S9^*)Kat^Gj#Yxnn8{pgW9rufDSlOpUq4r`*~NDBmy>^N!E)zz^|CEXnQaLPOb(_H?cCvh^z2Xd<7 z_Cgqry}8|L+%Gz>pY-xQR^iNl>}rKW2%XUG11C2~acs8bbA|moo>R=!5LHaDb)VM5 zPQ$dR&XIv6gwtr*)t+mz8CQs*Et{d4*jAMBL(~n*>4TlM!-)NnV#a*j;gMrR+`gW< zFbVQvYtm82a>IGflMVVAZbBcquCMvC1Uc#;O(^roVHxwzHm+v1YF!g!aBlh_MsDBE zur+~#aW{CJ(8tpF^K!6JW2m4q^eV4ZgY#DFeYrOyrD6Q??kZ#~|>Q2G`Hq( z@t&P(w0IlGL7Ro*_WqN=>)1#q>BP4ZT@aAkA+^7Bg1+j@aTWAm|s20s@y zM@n{XDj{>MM~l4gO0gM+=I!$0o#|VBwI6#5RG@7N;d2JCEqeb#Ot<>fzIz59TU*o| zbKWGF{BZ2cw&w)>D7`>CO%MYYxDP#Z<%x!14560cVoHi6x9HT-^%S;PAUBM;ngcTa z?Y(kg%f{TcxxhRgJnZ@MM*es+URbYQqrOm$X6ZZx zP&&B)jU5E)ibu0VA%9Sk-{3BVc*qktMWezo+|*@4>&ZERAMZgXsIq8eHMmzo8i%h4 zMtq8(|8D|GpY2~!kB_Wm`mVizch-bT@sSSM z+*A8pEz*>ixY~3aYqQmG2hWXK4uSq&%Vav}X!DQChIjAPhLzf?sUEfV*}#PFU^tuP@R+SIg;8yomi~Mm=j7qr~TXc(cbKE>lm0&qS1SLA7wr z9ly9YJCqrfe>J067=a|!E&l*!1Z3Q1u;uL(C3E+vFyii z08Uzeu>b3-$!d}QO#FFboesi19Mwe%&XgIA`=IdQlsuUb%muhDhzpC^?4^)ds z61^PR)2=yP^AvWLCme0m2d53vwI-HAuHW*!R-bG7jjUl`Y5RQ*$&$I*TgA{!s*aZz z&0$ZIfe-QFm@$GteaFS=!48oJIma;>hdQHpT8y%7?%5qEe+1rBz+FS=w95JKq_ZA* z-;6mLL+Qc>4mkT~2Dx>Qr|SSIx!`D?Hyn-B80Bs_kLI^Di9r);t)*nGWqJwbbHUxd z!#=aIZqXc3o2~~(n)g$EDAT6qckQUs%x~AypC1Th-rLZ(7|{w@aRi?APfwlsfybC` zTd7f~T@bYqv)xct#z*a=&KX|ZzW0HdV2(DK+! zMyg<$N3?b=(Y^94~6}RUE96a3)9V zexwU}J!B-cYu~q*Y-fLaeO9GAI)IBclk{@tsaVO;we6L6vtX!t%m;xBMi~bYq!fMC zra>1o*r#T(y*wm_-s%Y%|1&NnEq`16_*UE;UI|7jCxXXyL%*&$v4uqca|l(VFG;Xi zMzQu*YN>Ktt%Q#;0V|W4k^RDC)+^)PoZV-O&y0pdq4P;-F^x|Dj!@DKgJDrZZC(w| zvy6VaWNj85;x``dvdLP?KJ_`~eGrRxGT=JNGOR`cX(JPK>xzLtg=}fTm0*|lWU^}- z-v#TtY@ASm``@^8m#$ri96pb7>hn@%D{qSOG7=Ck-QblM;DhjRHv99#;(l&<6tKdd z6lZ#~r{2%~l%u|!)Xl$Vv>o3bIoP91R*}~wTont%Y2U^Rf~%>-$$Ln&Z>q@X+KR}e zEu`>I&uVrnX`7fwlrlG))c?d-?#FCq?PYXW)V^4-RrT6b|EoS0_gVH}*lDt0m|Tlo zL7=cy_1rtN1y;0b-$(5{Q`2LeS!a10$oDjE5?GXDZcE&P|5NU2b;>@RfWtZuTfzz?ZP#?r(*Rx>)?r& zk=>)#TeOY7uDAoEZF+x>=#Ao@Fb&h*CJBP@7HV7-MoW!^@BqzDT)n5j)RgI>b=6}y z53*5$0JBJv#Q-%s7W^FMP1SPd-d_4K#4|9{Q{k&?!cb?<3uuNIek*5LW?Dk2?3fe3 z1v`x$I7CDvLqj_UI)$41)v%mu)~*Mx6ph#rd#+wiP(0hRljIY45}0fRmlP-4eDL7> zS+|XD1R(+dw}}5A*`B_(9?zlNW=_2ZtL1Ezh16YDQ*u_skhV(V5DaUl(emg!(3PioDF)>su=r4Fa6|REG0>MRmdpH5i4!^Bx}Vu&vmC&&(&tt` z#Aba2`=gG`{D=qq7)G(iQRaJ^{JZMq3D3x}1o#IUsk^>` z=$uf263DAE-OoH+(+|P<`E#)bx*W?F6>8Wd%@x7*Xd^q6(m}b41 zdtL>0D;!ieG`*dV267YBqC{2a5&RW3sQAf3j|*A?_RHjPHY<%CC#Wrhw_qw3W&(ER z4VRKMSFZwy5c;ks83BI-CQ@CM9=c<*LP5l>(R?Rb8doI(Z2IBZxp2%G5b-Ys8&Tg$ z2Sd}fOd!u#X^>E`8`MG6L7zUUeNXwdl#PwsI`e^!aV^{4KkTz4IZc(C^RnC zQjTU30M(%MM5U_2;!Z3AbPim-5Ks-a#XFLqMQ~z%Zw;|oBp^bj_mdMBjVk!{#)gm+ zBQRtj!ZR!WGnOkh1Wb?pUZ?><`S}8&{Pw8_iNlYNsV0Mqxml8%o}T=7lbVtywnV`q G`2PTFN%qG8 diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/background.png b/Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/background.png new file mode 100644 index 0000000000000000000000000000000000000000..46a5a9ae4d80f6e039591eba3b9cf7a5d88debc5 GIT binary patch literal 3575 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 literal 0 HcmV?d00001 diff --git a/Forge/src/main/resources/assets/armorstatues/textures/item/empty_armor_slot_sword.png b/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png similarity index 100% rename from Forge/src/main/resources/assets/armorstatues/textures/item/empty_armor_slot_sword.png rename to Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png diff --git a/README.md b/README.md index f918472..a75f2c4 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ A Minecraft mod. Downloads can be found on [CurseForge](https://www.curseforge.com/members/fuzs_/projects) and [Modrinth](https://modrinth.com/user/Fuzs). -![](https://i.imgur.com/9rluSuU.png) +![](https://raw.githubusercontent.com/Fuzss/modresources/main/pages/data/armorstatues/banner.png) diff --git a/gradle.properties b/gradle.properties index 7aa0d44..dea9c02 100755 --- a/gradle.properties +++ b/gradle.properties @@ -8,14 +8,14 @@ org.gradle.parallel=true minecraftVersion=1.19.2 minMinecraftVersion=1.19.2 parchmentMappingsVersion=2022.08.14 -puzzlesVersion=4.3.11 -minPuzzlesVersion=4.3.7 +puzzlesVersion=4.4.4 +minPuzzlesVersion=4.4.0 packFormat=9 copyBuildJar=true # Forge Project -forgeVersion=1.19.2-43.1.43 -minForgeVersion=43.1.40 +forgeVersion=1.19.2-43.2.0 +minForgeVersion=43.2.0 # Fabric Project fabricVersion=0.14.9 @@ -26,7 +26,7 @@ minFabricApiVersion=0.60.0 # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.4 +modVersion=4.0.5 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modSourceUrl=https://github.com/Fuzss/armorstatues diff --git a/run/options.txt b/run/options.txt index 54d0039..108a267 100644 --- a/run/options.txt +++ b/run/options.txt @@ -67,7 +67,7 @@ tutorialStep:none mouseWheelSensitivity:1.0 rawMouseInput:true glDebugVerbosity:1 -skipMultiplayerWarning:false +skipMultiplayerWarning:true skipRealms32bitWarning:false hideMatchedNames:true joinedFirstServer:true From e9a46391fc4e58bc1b1b6fefc4dc7c6afba2332b Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Tue, 25 Jul 2023 15:04:05 +0200 Subject: [PATCH 05/31] more poses + descriptions + vanilla tweaks integration --- CHANGELOG.md | 5 +- .../armorstand/AbstractArmorStandScreen.java | 18 +- .../ArmorStandAlignmentsScreen.java | 36 ++- .../armorstand/ArmorStandPosesScreen.java | 58 +++-- .../client/data/CommandDataSyncHandler.java | 110 ++++++++-- .../network/client/data/DataSyncHandler.java | 22 +- .../client/data/NetworkDataSyncHandler.java | 6 +- .../data/VanillaTweaksDataSyncHandler.java | 205 ++++++++++++------ .../inventory/data/ArmorStandAlignment.java | 13 +- .../world/inventory/data/ArmorStandPose.java | 92 ++++---- .../armorstatues/config/ClientConfig.java | 4 +- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../resources/assets/statues/lang/en_us.json | 48 +++- .../data/ModLanguageProvider.java | 46 +++- 14 files changed, 475 insertions(+), 192 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a766ea..f67ee69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. -## [v4.0.5-1.19.2] - 2023-07-24 +## [v4.0.5-1.19.2] - 2023-07-25 +### Added +- Added a button to the rotations screen for mirroring the current pose ### Changed - Text fields now show description tooltips when hovered to make it more clear which field is for setting a new display name and which one changes the statue skin - Opening the statue menu no longer requires a stick to be held, instead shift + right-click with an empty hand is the way to go, which the statue item tooltip reflects ### Fixed +- Fixed opening the armor stand configuration screen with a Fabric client on a server without the mod interacting with the armor stand server-side (e.g. removing equipment) - Fixed a rare network issue on servers when both Armor Statues and Straw Statues are installed ## [v4.0.4-1.19.2] - 2023-01-17 diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index e7c5833..e45edc3 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -10,17 +10,20 @@ import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.puzzleslib.client.core.ClientCoreServices; +import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.AbstractButton; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.ImageButton; import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.ConfirmLinkScreen; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.MenuAccess; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; @@ -32,6 +35,7 @@ import java.util.Optional; public abstract class AbstractArmorStandScreen extends Screen implements MenuAccess, ArmorStandScreen { + public static final String VANILLA_TWEAKS_HOMEPAGE = "https://vanillatweaks.net/"; private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/background.png"); private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/widgets.png"); private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/equipment.png"); @@ -141,6 +145,17 @@ protected void toggleMenuRendering(boolean disableMenuRendering) { } } + protected void addVanillaTweaksCreditButton() { + this.addRenderableWidget(new ImageButton(this.leftPos + 6, this.topPos + 6, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { + this.minecraft.setScreen(new ConfirmLinkScreen((bl) -> { + if (bl) Util.getPlatform().openUri(VANILLA_TWEAKS_HOMEPAGE); + this.minecraft.setScreen(this); + }, VANILLA_TWEAKS_HOMEPAGE, true)); + }, (button, poseStack, mouseX, mouseY) -> { + this.renderTooltip(poseStack, this.font.split(Component.translatable("armorstatues.screen.vanillaTweaksCredit"), 175), mouseX, mouseY); + }, CommonComponents.EMPTY)); + } + @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0) { @@ -222,8 +237,9 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { public boolean mouseScrolled(double mouseX, double mouseY, double delta) { if (super.mouseScrolled(mouseX, mouseY, delta)) { return true; + } else { + return handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); } - return handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); } public static boolean handleMouseScrolled(int mouseX, int mouseY, double delta, int leftPos, int topPos, int imageHeight, T screen, ArmorStandScreenType[] tabs) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index d140422..9891e8f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -8,13 +8,10 @@ import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; -import net.minecraft.Util; import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.components.ImageButton; -import net.minecraft.client.gui.screens.ConfirmLinkScreen; import net.minecraft.core.Direction; -import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.phys.Vec3; @@ -23,7 +20,6 @@ import java.util.List; public class ArmorStandAlignmentsScreen extends ArmorStandWidgetsScreen { - public static final String VANILLA_TWEAKS_HOMEPAGE = "https://vanillatweaks.net/"; public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); @@ -41,14 +37,7 @@ protected List buildWidgets(ArmorStand armorStand) { @Override protected void init() { super.init(); - this.addRenderableWidget(new ImageButton(this.leftPos + 6, this.topPos + 6, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { - this.minecraft.setScreen(new ConfirmLinkScreen((bl) -> { - if (bl) Util.getPlatform().openUri(VANILLA_TWEAKS_HOMEPAGE); - this.minecraft.setScreen(this); - }, VANILLA_TWEAKS_HOMEPAGE, true)); - }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.alignments.credit"), mouseX, mouseY); - }, CommonComponents.EMPTY)); + this.addVanillaTweaksCreditButton(); } @Override @@ -84,11 +73,15 @@ private class PositionAlignWidget extends BlockPositionWidget { @Override public void init(int posX, int posY) { super.init(posX, posY); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, Component.translatable("armorstatues.screen.position.centered"), Component.translatable("armorstatues.screen.position.aligned"), button -> { + this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, Component.translatable("armorstatues.screen.alignments.centered"), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5)); + }, (button, poseStack, mouseX, mouseY) -> { + ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, ArmorStandAlignmentsScreen.this.font.split(Component.translatable("armorstatues.screen.alignments.centered.description"), 175), mouseX, mouseY); }))); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, Component.translatable("armorstatues.screen.position.cornered"), Component.translatable("armorstatues.screen.position.aligned"), button -> { + this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, Component.translatable("armorstatues.screen.alignments.cornered"), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class))); + }, (button, poseStack, mouseX, mouseY) -> { + ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, ArmorStandAlignmentsScreen.this.font.split(Component.translatable("armorstatues.screen.alignments.cornered.description"), 175), mouseX, mouseY); }))); } } @@ -103,16 +96,21 @@ public AlignmentWidget(ArmorStandAlignment alignment) { @Override public void init(int posX, int posY) { super.init(posX, posY); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, this.alignment.getComponent(), Component.translatable("armorstatues.screen.position.aligned"), button -> { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPose(this.alignment.getPose()); + this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPose(this.alignment.getPose(), false); ArmorStand armorStand = ArmorStandAlignmentsScreen.this.holder.getArmorStand(); this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5).add(this.alignment.getPosition(armorStand.isSmall()))); if (!armorStand.isInvisible()) { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true); + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); } if (!armorStand.isNoGravity()) { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true); + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); } + ArmorStandAlignmentsScreen.this.dataSyncHandler.finalizeCurrentOperation(); + }, (button, poseStack, mouseX, mouseY) -> { + Component component = Component.translatable(this.alignment.getDescriptionsKey()); + List lines = ArmorStandAlignmentsScreen.this.font.split(component, 175); + ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, lines, mouseX, mouseY); }))); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java index ab2260f..8327c06 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java @@ -1,18 +1,22 @@ package fuzs.armorstatues.api.client.gui.screens.armorstand; +import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; +import net.minecraft.ChatFormatting; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.ImageButton; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; +import net.minecraft.util.StringUtil; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; +import java.util.List; import java.util.Optional; public class ArmorStandPosesScreen extends AbstractArmorStandScreen { @@ -33,30 +37,58 @@ public ArmorStandPosesScreen(ArmorStandHolder holder, Inventory inventory, Compo protected void init() { super.init(); this.cycleButtons[0] = this.addRenderableWidget(new ImageButton(this.leftPos + 17, this.topPos + 153, 20, 20, 156, 64, getArmorStandWidgetsLocation(), button -> { - firstPoseIndex -= POSES_PER_PAGE; - this.toggleCycleButtons(); + this.toggleCycleButtons(-POSES_PER_PAGE); })); this.cycleButtons[1] = this.addRenderableWidget(new ImageButton(this.leftPos + 49, this.topPos + 153, 20, 20, 176, 64, getArmorStandWidgetsLocation(), button -> { - firstPoseIndex += POSES_PER_PAGE; - this.toggleCycleButtons(); + this.toggleCycleButtons(POSES_PER_PAGE); })); for (int i = 0; i < this.poseButtons.length; i++) { - final int ii = i; + final int index = i; this.poseButtons[i] = this.addRenderableWidget(new ImageButton(this.leftPos + 83 + i % 2 * 62, this.topPos + 9 + i / 2 * 88, 60, 82, 76, 0, 82, getArmorStandWidgetsLocation(), 256, 256, button -> { - getPoseAt(ii).ifPresent(this.dataSyncHandler::sendPose); + getPoseAt(index).ifPresent(this.dataSyncHandler::sendPose); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { - getPoseAt(ii).ifPresent(pose -> this.renderTooltip(poseStack, Component.translatable(pose.getTranslationKey()), mouseX, mouseY)); + getPoseAt(index).ifPresent(pose -> { + String translationKey = pose.getTranslationKey(); + if (translationKey != null) { + Component component = Component.translatable(translationKey); + List lines = Lists.newArrayList(component); + String source = pose.getSource(); + if (!StringUtil.isNullOrEmpty(source)) { + lines.add(Component.translatable("armorstatues.entity.armor_stand.pose.by", source).withStyle(ChatFormatting.GRAY)); + } + this.renderTooltip(poseStack, lines, Optional.empty(), mouseX, mouseY); + } + }); }, CommonComponents.EMPTY)); } - this.toggleCycleButtons(); + this.toggleCycleButtons(0); + this.addVanillaTweaksCreditButton(); } - private void toggleCycleButtons() { - this.cycleButtons[0].active = firstPoseIndex > 0; - this.cycleButtons[1].active = firstPoseIndex + POSES_PER_PAGE < ArmorStandPose.values().length; - for (int i = 0; i < this.poseButtons.length; i++) { - this.poseButtons[i].visible = getPoseAt(i).isPresent(); + private void toggleCycleButtons(int increment) { + int newFirstPoseIndex = firstPoseIndex + increment; + if (newFirstPoseIndex >= 0 && newFirstPoseIndex < ArmorStandPose.values().length) { + firstPoseIndex = newFirstPoseIndex; + this.cycleButtons[0].active = newFirstPoseIndex - POSES_PER_PAGE >= 0; + this.cycleButtons[1].active = newFirstPoseIndex + POSES_PER_PAGE < ArmorStandPose.values().length; + for (int i = 0; i < this.poseButtons.length; i++) { + this.poseButtons[i].visible = getPoseAt(i).isPresent(); + } + } + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + if (super.mouseScrolled(mouseX, mouseY, delta)) { + return true; + } else if (mouseX >= this.leftPos && mouseX < this.leftPos + this.imageWidth && mouseY >= this.topPos && mouseY < this.topPos + this.imageHeight) { + delta = Math.signum(delta); + if (delta != 0.0) { + this.toggleCycleButtons((int) (-1.0 * delta * POSES_PER_PAGE)); + return true; + } } + return false; } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java index ef8096d..71cfb09 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java @@ -13,22 +13,25 @@ import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.function.BiPredicate; import java.util.function.Predicate; import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { private static final Component NO_PERMISSION_COMPONENT = Component.translatable("armorstatues.screen.failure.noPermission"); + private static final Component NOT_FINISHED_COMPONENT = Component.translatable("armorstatues.screen.failure.notFinished"); + private static final Component FINISHED_COMPONENT = Component.translatable("armorstatues.screen.finished"); + private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); @Nullable static ArmorStandScreenType lastType; + private static boolean queueLocked; + private static int itemDequeuedTicks; private final ArmorStand armorStand; protected final LocalPlayer player; - private ArmorStandPose lastSyncedPose; + protected ArmorStandPose lastSyncedPose; public CommandDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { this.armorStand = armorStand; @@ -47,31 +50,44 @@ public void sendName(String name) { DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); CompoundTag tag = new CompoundTag(); tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); - this.sendDataCommand(tag); + this.enqueueEntityData(tag); + this.finalizeCurrentOperation(); } @Override - public void sendPose(ArmorStandPose currentPose) { + public final void sendPose(ArmorStandPose pose) { + this.sendPose(pose, true); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { if (!this.testPermissionLevel()) return; - currentPose.applyToEntity(this.getArmorStand()); + pose.applyToEntity(this.getArmorStand()); // split this into multiple chat messages as the client chat field has a very low character limit - this.sendPosePart(currentPose::serializeBodyPoses, this.lastSyncedPose); - this.sendPosePart(currentPose::serializeArmPoses, this.lastSyncedPose); - this.sendPosePart(currentPose::serializeLegPoses, this.lastSyncedPose); - this.lastSyncedPose = currentPose; + this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + this.lastSyncedPose = pose; + if (finalize) this.finalizeCurrentOperation(); } private void sendPosePart(BiPredicate dataWriter, ArmorStandPose lastSyncedPose) { CompoundTag tag = new CompoundTag(); if (dataWriter.test(tag, lastSyncedPose)) { - CompoundTag tag1 = new CompoundTag(); - tag1.put("Pose", tag); - this.sendDataCommand(tag1); + CompoundTag tagToSend = new CompoundTag(); + tagToSend.put("Pose", tag); + this.enqueueEntityData(tagToSend); } } @Override - public void sendPosition(double posX, double posY, double posZ) { + public final void sendPosition(double posX, double posY, double posZ) { + this.sendPosition(posX, posY, posZ, true); + + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { if (!this.testPermissionLevel()) return; ListTag listTag = new ListTag(); listTag.add(DoubleTag.valueOf(posX)); @@ -79,27 +95,39 @@ public void sendPosition(double posX, double posY, double posZ) { listTag.add(DoubleTag.valueOf(posZ)); CompoundTag tag = new CompoundTag(); tag.put("Pos", listTag); - this.sendDataCommand(tag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + @Override + public final void sendRotation(float rotation) { + this.sendRotation(rotation, true); } @Override - public void sendRotation(float rotation) { + public void sendRotation(float rotation, boolean finalize) { if (!this.testPermissionLevel()) return; ListTag listTag = new ListTag(); listTag.add(FloatTag.valueOf(rotation)); CompoundTag tag = new CompoundTag(); tag.put("Rotation", listTag); - this.sendDataCommand(tag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + this.sendStyleOption(styleOption, value, true); } @Override - public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { if (!this.testPermissionLevel()) return; styleOption.setOption(this.getArmorStand(), value); CompoundTag tag = new CompoundTag(); styleOption.toTag(tag, value); - this.sendDataCommand(tag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); } @Override @@ -118,6 +146,26 @@ public void setLastType(ArmorStandScreenType lastType) { CommandDataSyncHandler.lastType = lastType; } + @Override + public void tick() { + if (itemDequeuedTicks > 0) itemDequeuedTicks--; + if (itemDequeuedTicks == 0 && !CLIENT_COMMAND_QUEUE.isEmpty()) { + this.player.commandSigned(CLIENT_COMMAND_QUEUE.poll(), null); + itemDequeuedTicks = this.getDefaultDequeuedTicks(); + } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { + this.sendDisplayMessage(FINISHED_COMPONENT, false); + } + } + + protected int getDefaultDequeuedTicks() { + return 5; + } + + @Override + public boolean shouldContinueTicking() { + return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; + } + private boolean testPermissionLevel() { if (!this.player.hasPermissions(2)) { this.sendFailureMessage(NO_PERMISSION_COMPONENT); @@ -126,6 +174,24 @@ private boolean testPermissionLevel() { return true; } + protected boolean enqueueClientCommand(String clientCommand) { + if (CLIENT_COMMAND_QUEUE.isEmpty()) { + queueLocked = false; + } else if (queueLocked) { + this.sendFailureMessage(NOT_FINISHED_COMPONENT); + return false; + } + CLIENT_COMMAND_QUEUE.offer(clientCommand); + return true; + } + + @Override + public void finalizeCurrentOperation() { + if (!CLIENT_COMMAND_QUEUE.isEmpty()) { + queueLocked = true; + } + } + protected void sendFailureMessage(Component component) { this.sendDisplayMessage(Component.translatable("armorstatues.screen.failure", component), true); } @@ -134,7 +200,7 @@ protected void sendDisplayMessage(Component component, boolean failure) { this.player.displayClientMessage(Component.empty().append(component).withStyle(failure ? ChatFormatting.RED : ChatFormatting.GREEN), false); } - private void sendDataCommand(CompoundTag tag) { - this.player.commandSigned("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString()), null); + private void enqueueEntityData(CompoundTag tag) { + this.enqueueClientCommand("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString())); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java index 6ab33d1..006ab5b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java @@ -15,14 +15,30 @@ public interface DataSyncHandler extends ArmorStandHolder { void sendName(String name); - void sendPose(ArmorStandPose currentPose); + void sendPose(ArmorStandPose pose); + + default void sendPose(ArmorStandPose pose, boolean finalize) { + this.sendPose(pose); + } void sendPosition(double posX, double posY, double posZ); + default void sendPosition(double posX, double posY, double posZ, boolean finalize) { + this.sendPosition(posX, posY, posZ); + } + void sendRotation(float rotation); + default void sendRotation(float rotation, boolean finalize) { + this.sendRotation(rotation); + } + void sendStyleOption(ArmorStandStyleOption styleOption, boolean value); + default void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + this.sendStyleOption(styleOption, value); + } + ArmorStandScreenType[] tabs(); Optional getLastType(); @@ -37,6 +53,10 @@ default boolean shouldContinueTicking() { return false; } + default void finalizeCurrentOperation() { + + } + static void setCustomArmorStandName(ArmorStand armorStand, String name) { name = SharedConstants.filterText(name); if (name.length() <= 50) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java index f59a7eb..19952e2 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java @@ -35,10 +35,10 @@ public void sendName(String name) { } @Override - public void sendPose(ArmorStandPose currentPose) { - currentPose.applyToEntity(this.getArmorStand()); + public void sendPose(ArmorStandPose pose) { + pose.applyToEntity(this.getArmorStand()); CompoundTag tag = new CompoundTag(); - currentPose.serializeAllPoses(tag); + pose.serializeAllPoses(tag); ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandPoseMessage(tag)); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java index 5c45828..966d427 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java @@ -1,19 +1,17 @@ package fuzs.armorstatues.api.network.client.data; +import com.google.common.collect.ImmutableSortedMap; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; -import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; -import it.unimi.dsi.fastutil.ints.IntPriorityQueue; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.chat.Component; +import net.minecraft.core.Rotations; import net.minecraft.world.entity.decoration.ArmorStand; +import java.util.Map; +import java.util.NavigableMap; + public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { - private static final Component NOT_FINISHED_COMPONENT = Component.translatable("armorstatues.screen.failure.notFinished"); - private static final Component FINISHED_COMPONENT = Component.translatable("armorstatues.screen.finished"); - private static final int DEFAULT_COMMAND_SEND_TICKS = 20; private static final int MAX_INCREMENTAL_OPERATIONS = 12; public static final int SHOW_BASE_PLATE_YES = 1; public static final int SHOW_BASE_PLATE_NO = 2; @@ -27,54 +25,164 @@ public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { public static final int STAND_VISIBLE_NO = 10; public static final int DISPLAY_NAME_YES = 11; public static final int DISPLAY_NAME_NO = 12; + public static final int NUDGE_POSITION_X8_NEGATIVE = 40; + public static final int NUDGE_POSITION_X3_NEGATIVE = 101; + public static final int NUDGE_POSITION_X1_NEGATIVE = 102; + public static final int NUDGE_POSITION_X1_POSITIVE = 103; + public static final int NUDGE_POSITION_X3_POSITIVE = 104; + public static final int NUDGE_POSITION_X8_POSITIVE = 43; + public static final int NUDGE_POSITION_Y8_NEGATIVE = 44; + public static final int NUDGE_POSITION_Y3_NEGATIVE = 105; + public static final int NUDGE_POSITION_Y1_NEGATIVE = 106; + public static final int NUDGE_POSITION_Y1_POSITIVE = 107; + public static final int NUDGE_POSITION_Y3_POSITIVE = 108; + public static final int NUDGE_POSITION_Y8_POSITIVE = 47; + public static final int NUDGE_POSITION_Z8_NEGATIVE = 48; + public static final int NUDGE_POSITION_Z3_NEGATIVE = 109; + public static final int NUDGE_POSITION_Z1_NEGATIVE = 110; + public static final int NUDGE_POSITION_Z1_POSITIVE = 111; + public static final int NUDGE_POSITION_Z3_POSITIVE = 112; + public static final int NUDGE_POSITION_Z8_POSITIVE = 51; public static final int ADJUST_ROTATION_ANGLE_STEP_45 = 120; public static final int ADJUST_ROTATION_ANGLE_STEP_15 = 121; public static final int ADJUST_ROTATION_ANGLE_STEP_5 = 122; public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; - - private static final IntPriorityQueue QUEUE = new IntArrayFIFOQueue(); - private static boolean queueLocked; - private static int commandSentTicks; + public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; + public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; + public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; + public static final int POSE_ADJUSTMENT_HEAD_Y_POSITIVE = 63; + public static final int POSE_ADJUSTMENT_HEAD_Z_NEGATIVE = 64; + public static final int POSE_ADJUSTMENT_HEAD_Z_POSITIVE = 65; + public static final int POSE_ADJUSTMENT_BODY_X_NEGATIVE = 67; + public static final int POSE_ADJUSTMENT_BODY_X_POSITIVE = 66; + public static final int POSE_ADJUSTMENT_BODY_Y_NEGATIVE = 68; + public static final int POSE_ADJUSTMENT_BODY_Y_POSITIVE = 69; + public static final int POSE_ADJUSTMENT_BODY_Z_NEGATIVE = 70; + public static final int POSE_ADJUSTMENT_BODY_Z_POSITIVE = 71; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE = 72; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE = 73; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE = 74; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE = 75; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE = 77; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE = 76; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE = 78; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE = 79; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE = 81; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE = 80; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE = 82; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE = 83; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE = 84; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE = 85; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE = 87; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE = 86; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE = 89; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE = 88; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE = 90; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE = 91; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE = 92; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE = 93; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; + private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_LEG = new int[]{POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE}; + private static final NavigableMap NUDGE_POSITIONS_X_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_X3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_X8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_X_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_X3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_X8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_POSITIVE); + private static final NavigableMap ADJUST_ROTATION_ANGLE_STEPS = ImmutableSortedMap.of(1.0F, ADJUST_ROTATION_ANGLE_STEP_1, 5.0F, ADJUST_ROTATION_ANGLE_STEP_5, 15.0F, ADJUST_ROTATION_ANGLE_STEP_15, 45.0F, ADJUST_ROTATION_ANGLE_STEP_45); public VanillaTweaksDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { super(armorStand, player); } @Override - public void sendRotation(float rotation) { - this.getCloseWithIncrements(this.getArmorStand().getYRot(), rotation, new float[]{1.0F, 5.0F, 15.0F, 45.0F}, new int[]{ADJUST_ROTATION_ANGLE_STEP_1, ADJUST_ROTATION_ANGLE_STEP_5, ADJUST_ROTATION_ANGLE_STEP_15, ADJUST_ROTATION_ANGLE_STEP_45}); - this.finalizeCurrentOperation(); + public void sendPose(ArmorStandPose pose, boolean finalize) { + $1: { + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getHeadPose(), pose.getHeadPose(), POSE_ADJUSTMENT_HEAD)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getBodyPose(), pose.getBodyPose(), POSE_ADJUSTMENT_BODY)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightArmPose(), pose.getRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftArmPose(), pose.getLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightLegPose(), pose.getRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftLegPose(), pose.getLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG)) break $1; + } + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean tryApplyPoseIncrements(Rotations oldPose, Rotations newPose, int[] poseAdjustment) { + if (oldPose.equals(newPose)) return true; + if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) return false; + return true; + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); + if (finalize) this.finalizeCurrentOperation(); + } + + private void applyPositionIncrements(double oldValue, double newValue, NavigableMap positiveNudgePositions, NavigableMap negativeNudgePositions) { + double value = newValue - oldValue; + double signum = Math.signum(value); + value = Math.abs(value); + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = (signum == -1.0F ? negativeNudgePositions : positiveNudgePositions).floorEntry(value); + if (entry != null) { + value -= entry.getKey(); + if (!this.enqueueTriggerValue(entry.getValue())) { + return; + } + } else { + break; + } + } } - private void getCloseWithIncrements(float oldValue, float newValue, float[] increments, int[] triggerValues) { + @Override + public void sendRotation(float rotation, boolean finalize) { + this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean applyIncrementsFromSteps(float oldValue, float newValue, int triggerValueNegative, int triggerValuePositive) { float value = newValue - oldValue; float signum = Math.signum(value); value = Math.abs(value); float lastIncrement = 0.0F; for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { - if (value >= increments[0]) { - for (int j = increments.length - 1; j >= 0; j--) { - float currentIncrement = increments[j]; - if (currentIncrement < value) { - value -= currentIncrement; - if (currentIncrement != lastIncrement) { - lastIncrement = currentIncrement; - if (!this.enqueueTriggerValue(triggerValues[j])) return; - } - if (!this.enqueueTriggerValue(signum == -1.0F ? ADJUST_ROTATION_ROTATE_LEFT : ADJUST_ROTATION_ROTATE_RIGHT)) return; - break; + Map.Entry entry = ADJUST_ROTATION_ANGLE_STEPS.floorEntry(value); + if (entry != null) { + float currentIncrement = entry.getKey(); + value -= currentIncrement; + if (currentIncrement != lastIncrement) { + lastIncrement = currentIncrement; + if (!this.enqueueTriggerValue(entry.getValue())) { + return false; } } + if (!this.enqueueTriggerValue(signum == -1.0F ? triggerValuePositive : triggerValueNegative)) { + return false; + } } else { break; } } + return true; } @Override - public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { int triggerValue; if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; @@ -89,52 +197,21 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { } else if (styleOption == ArmorStandStyleOptions.NO_GRAVITY) { triggerValue = value ? APPLY_GRAVITY_NO : APPLY_GRAVITY_YES; } else { - super.sendStyleOption(styleOption, value); + super.sendStyleOption(styleOption, value, finalize); return; } if (this.enqueueTriggerValue(triggerValue)) { styleOption.setOption(this.getArmorStand(), value); } - this.finalizeCurrentOperation(); + if (finalize) this.finalizeCurrentOperation(); } @Override - public void tick() { - if (commandSentTicks > 0) commandSentTicks--; - if (commandSentTicks == 0 && !QUEUE.isEmpty()) { - this.sendTriggerCommand(QUEUE.dequeueInt()); - if (QUEUE.isEmpty()) { - this.sendDisplayMessage(FINISHED_COMPONENT, false); - } - } - } - - @Override - public boolean shouldContinueTicking() { - return !QUEUE.isEmpty(); + protected int getDefaultDequeuedTicks() { + return 20; } private boolean enqueueTriggerValue(int triggerValue) { - if (QUEUE.isEmpty()) { - queueLocked = false; - } else if (queueLocked) { - this.sendFailureMessage(NOT_FINISHED_COMPONENT); - return false; - } - QUEUE.enqueue(triggerValue); - return true; - } - - private void finalizeCurrentOperation() { - if (!QUEUE.isEmpty()) { - queueLocked = true; - Screen screen = Minecraft.getInstance().screen; - if (screen != null) screen.onClose(); - } - } - - private void sendTriggerCommand(int triggerValue) { - this.player.commandSigned("trigger as_trigger set %s".formatted(triggerValue), null); - commandSentTicks = DEFAULT_COMMAND_SEND_TICKS; + return this.enqueueClientCommand("trigger as_trigger set %s".formatted(triggerValue)); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java index a7910b7..bbb3db2 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java @@ -1,9 +1,10 @@ package fuzs.armorstatues.api.world.inventory.data; import net.minecraft.core.Rotations; -import net.minecraft.network.chat.Component; import net.minecraft.world.phys.Vec3; +import java.util.Locale; + /** * values copied from Vanilla Tweaks data pack */ @@ -27,11 +28,15 @@ public enum ArmorStandAlignment { @Override public String toString() { - return this.name; + return this.name.toUpperCase(Locale.ROOT); + } + + public String getTranslationKey() { + return "armorstatues.screen.alignments." + this.name; } - public Component getComponent() { - return Component.translatable("armorstatues.screen.alignments." + this.name); + public String getDescriptionsKey() { + return this.getTranslationKey() + ".description"; } public ArmorStandPose getPose() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index 63b06ef..99ba4e6 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -10,30 +10,48 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; -import java.util.Objects; -import java.util.Random; public class ArmorStandPose { - public static final ArmorStandPose ATHENA = new ArmorStandPose("athena").withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(-5.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-3.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-60.0F, 20.0F, -10.0F)).withRightLegPose(new Rotations(3.0F, 3.0F, 3.0F)); - public static final ArmorStandPose BRANDISH = new ArmorStandPose("brandish").withBodyPose(new Rotations(0.0F, 0.0F, -2.0F)).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(20.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 50.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); - public static final ArmorStandPose CANCAN_A = new ArmorStandPose("cancanA").withBodyPose(new Rotations(0.0F, 22.0F, 0.0F)).withHeadPose(new Rotations(-5.0F, 18.0F, 0.0F)).withLeftArmPose(new Rotations(8.0F, 0.0F, -114.0F)).withLeftLegPose(new Rotations(-111.0F, 55.0F, 0.0F)).withRightArmPose(new Rotations(0.0F, 84.0F, 111.0F)).withRightLegPose(new Rotations(0.0F, 23.0F, -13.0F)); - public static final ArmorStandPose CANCAN_B = new ArmorStandPose("cancanB").withBodyPose(new Rotations(0.0F, -18.0F, 0.0F)).withHeadPose(new Rotations(-10.0F, -20.0F, 0.0F)).withLeftArmPose(new Rotations(0.0F, 0.0F, -112.0F)).withLeftLegPose(new Rotations(0.0F, 0.0F, 13.0F)).withRightArmPose(new Rotations(8.0F, 90.0F, 111.0F)).withRightLegPose(new Rotations(-119.0F, -42.0F, 0.0F)); - public static final ArmorStandPose DEFAULT = new ArmorStandPose("default").withLeftArmPose(new Rotations(-10.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-15.0F, 0.0F, 10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); - public static final ArmorStandPose ENTERTAIN = new ArmorStandPose("entertain").withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); - public static final ArmorStandPose HERO = new ArmorStandPose("hero").withBodyPose(new Rotations(0.0F, 8.0F, 0.0F)).withHeadPose(new Rotations(-4.0F, 67.0F, 0.0F)).withLeftArmPose(new Rotations(16.0F, 32.0F, -8.0F)).withLeftLegPose(new Rotations(0.0F, -75.0F, -8.0F)).withRightArmPose(new Rotations(-99.0F, 63.0F, 0.0F)).withRightLegPose(new Rotations(4.0F, 63.0F, 8.0F)); - public static final ArmorStandPose HONOR = new ArmorStandPose("honor").withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); - public static final ArmorStandPose RIPOSTE = new ArmorStandPose("riposte").withHeadPose(new Rotations(16.0F, 20.0F, 0.0F)).withLeftArmPose(new Rotations(4.0F, 8.0F, 237.0F)).withLeftLegPose(new Rotations(-14.0F, -18.0F, -16.0F)).withRightArmPose(new Rotations(246.0F, 0.0F, 89.0F)).withRightLegPose(new Rotations(8.0F, 20.0F, 4.0F)); - public static final ArmorStandPose SALUTE = new ArmorStandPose("salute").withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-70.0F, -40.0F, 0.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); - public static final ArmorStandPose SOLEMN = new ArmorStandPose("solemn").withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-30.0F, 15.0F, 15.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-60.0F, -20.0F, -10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); - public static final ArmorStandPose ZOMBIE = new ArmorStandPose("zombie").withHeadPose(new Rotations(-10.0F, 0.0F, -5.0F)).withLeftArmPose(new Rotations(-105.0F, 0.0F, 0.0F)).withLeftLegPose(new Rotations(7.0F, 0.0F, 0.0F)).withRightArmPose(new Rotations(-100.0F, 0.0F, 0.0F)).withRightLegPose(new Rotations(-46.0F, 0.0F, 0.0F)); + private static final String MINECRAFT_SOURCE = "Minecraft"; + private static final String VANILLA_TWEAKS_SOURCE = "Vanilla Tweaks"; public static final double DEGREES_SNAP_INTERVAL = 0.125; public static final DecimalFormat ROTATION_FORMAT = Util.make(new DecimalFormat("#.##"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); }); - private static final Random RANDOM = new Random(); - + public static final ArmorStandPose ATHENA = new ArmorStandPose("athena", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(-5.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-3.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-60.0F, 20.0F, -10.0F)).withRightLegPose(new Rotations(3.0F, 3.0F, 3.0F)); + public static final ArmorStandPose BRANDISH = new ArmorStandPose("brandish", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, -2.0F)).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(20.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 50.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); + public static final ArmorStandPose CANCAN = new ArmorStandPose("cancan", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 22.0F, 0.0F)).withHeadPose(new Rotations(-5.0F, 18.0F, 0.0F)).withLeftArmPose(new Rotations(8.0F, 0.0F, -114.0F)).withLeftLegPose(new Rotations(-111.0F, 55.0F, 0.0F)).withRightArmPose(new Rotations(0.0F, 84.0F, 111.0F)).withRightLegPose(new Rotations(0.0F, 23.0F, -13.0F)); + public static final ArmorStandPose DEFAULT = new ArmorStandPose("default", MINECRAFT_SOURCE).withLeftArmPose(new Rotations(-10.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-15.0F, 0.0F, 10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); + public static final ArmorStandPose ENTERTAIN = new ArmorStandPose("entertain", MINECRAFT_SOURCE).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); + public static final ArmorStandPose HERO = new ArmorStandPose("hero", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 8.0F, 0.0F)).withHeadPose(new Rotations(-4.0F, 67.0F, 0.0F)).withLeftArmPose(new Rotations(16.0F, 32.0F, -8.0F)).withLeftLegPose(new Rotations(0.0F, -75.0F, -8.0F)).withRightArmPose(new Rotations(-99.0F, 63.0F, 0.0F)).withRightLegPose(new Rotations(4.0F, 63.0F, 8.0F)); + public static final ArmorStandPose HONOR = new ArmorStandPose("honor", MINECRAFT_SOURCE).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); + public static final ArmorStandPose RIPOSTE = new ArmorStandPose("riposte", MINECRAFT_SOURCE).withHeadPose(new Rotations(16.0F, 20.0F, 0.0F)).withLeftArmPose(new Rotations(4.0F, 8.0F, 237.0F)).withLeftLegPose(new Rotations(-14.0F, -18.0F, -16.0F)).withRightArmPose(new Rotations(246.0F, 0.0F, 89.0F)).withRightLegPose(new Rotations(8.0F, 20.0F, 4.0F)); + public static final ArmorStandPose SALUTE = new ArmorStandPose("salute", MINECRAFT_SOURCE).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-70.0F, -40.0F, 0.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); + public static final ArmorStandPose SOLEMN = new ArmorStandPose("solemn", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-30.0F, 15.0F, 15.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-60.0F, -20.0F, -10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); + public static final ArmorStandPose ZOMBIE = new ArmorStandPose("zombie", MINECRAFT_SOURCE).withHeadPose(new Rotations(-10.0F, 0.0F, -5.0F)).withLeftArmPose(new Rotations(-105.0F, 0.0F, 0.0F)).withLeftLegPose(new Rotations(7.0F, 0.0F, 0.0F)).withRightArmPose(new Rotations(-100.0F, 0.0F, 0.0F)).withRightLegPose(new Rotations(-46.0F, 0.0F, 0.0F)); + public static final ArmorStandPose WALKING = new ArmorStandPose("walking", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(20.0f,0.0f,10.0f)).withLeftArmPose(new Rotations(-20.0f,0.0f,-10.0f)).withRightLegPose(new Rotations(-20.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(20.0f,0.0f,0.0f)); + public static final ArmorStandPose RUNNING = new ArmorStandPose("running", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(-40.0f,0.0f,10.0f)).withLeftArmPose(new Rotations(40.0f,0.0f,-10.0f)).withRightLegPose(new Rotations(40.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(-40.0f,0.0f,0.0f)); + public static final ArmorStandPose POINTING = new ArmorStandPose("pointing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(0.0f,20.0f,0.0f)).withRightArmPose(new Rotations(-90.0f,18.0f,0.0f)).withLeftArmPose(new Rotations(0.0f,0.0f,-10.0f)); + public static final ArmorStandPose BLOCKING = new ArmorStandPose("blocking", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(-20.0f,-20.0f,0.0f)).withLeftArmPose(new Rotations(-50.0f,50.0f,0.0f)).withRightLegPose(new Rotations(-20.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(20.0f,0.0f,0.0f)); + public static final ArmorStandPose LUNGEING = new ArmorStandPose("lungeing", VANILLA_TWEAKS_SOURCE).withBodyPose(new Rotations(15.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-60.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(10.0f,0.0f,-10.0f)).withRightLegPose(new Rotations(-15.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(30.0f,0.0f,0.0f)); + public static final ArmorStandPose WINNING = new ArmorStandPose("winning", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-15.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-120.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(10.0f,0.0f,-10.0f)).withLeftLegPose(new Rotations(15.0f,0.0f,0.0f)); + public static final ArmorStandPose SITTING = new ArmorStandPose("sitting", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(-80.0f,20.0f,0.0f)).withLeftArmPose(new Rotations(-80.0f,-20.0f,0.0f)).withRightLegPose(new Rotations(-90.0f,10.0f,0.0f)).withLeftLegPose(new Rotations(-90.0f,-10.0f,0.0f)); + public static final ArmorStandPose ARABESQUE = new ArmorStandPose("arabesque", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-15.0f,0.0f,0.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-140.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(70.0f,0.0f,-10.0f)).withLeftLegPose(new Rotations(75.0f,0.0f,0.0f)); + public static final ArmorStandPose CUPID = new ArmorStandPose("cupid", VANILLA_TWEAKS_SOURCE).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-90.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(-75.0f,0.0f,10.0f)).withLeftLegPose(new Rotations(75.0f,0.0f,0.0f)); + public static final ArmorStandPose CONFIDENT = new ArmorStandPose("confident", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-10.0f,20.0f,0.0f)).withBodyPose(new Rotations(-2.0f,0.0f,0.0f)).withRightArmPose(new Rotations(5.0f,0.0f,0.0f)).withLeftArmPose(new Rotations(5.0f,0.0f,0.0f)).withRightLegPose(new Rotations(16.0f,2.0f,10.0f)).withLeftLegPose(new Rotations(0.0f,-10.0f,-4.0f)); + public static final ArmorStandPose DEATH = new ArmorStandPose("death", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-85.0f,0.0f,0.0f)).withBodyPose(new Rotations(-90.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-90.0f,10.0f,0.0f)).withLeftArmPose(new Rotations(-90.0f,-10.0f,0.0f)); + public static final ArmorStandPose FACEPALM = new ArmorStandPose("facepalm", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(45.0f,-4.0f,1.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(18.0f,-14.0f,0.0f)).withLeftArmPose(new Rotations(-72.0f,24.0f,47.0f)).withRightLegPose(new Rotations(25.0f,-2.0f,0.0f)).withLeftLegPose(new Rotations(-4.0f,-6.0f,-2.0f)); + public static final ArmorStandPose LAZING = new ArmorStandPose("lazing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(14.0f,-12.0f,6.0f)).withBodyPose(new Rotations(5.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-40.0f,20.0f,0.0f)).withLeftArmPose(new Rotations(-4.0f,-20.0f,-10.0f)).withRightLegPose(new Rotations(-88.0f,71.0f,0.0f)).withLeftLegPose(new Rotations(-88.0f,46.0f,0.0f)); + public static final ArmorStandPose CONFUSED = new ArmorStandPose("confused", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(0.0f,30.0f,0f)).withBodyPose(new Rotations(0.0f,13.0f,0.0f)).withRightArmPose(new Rotations(-22.0f,31.0f,10.0f)).withLeftArmPose(new Rotations(145.0f,22.0f,-49.0f)).withRightLegPose(new Rotations(6.0f,-20.0f,0.0f)).withLeftLegPose(new Rotations(-6.0f,0.0f,0.0f)); + public static final ArmorStandPose FORMAL = new ArmorStandPose("formal", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(4.0f,0.0f,0.0f)).withBodyPose(new Rotations(4.0f,0.0f,0.0f)).withRightArmPose(new Rotations(30.0f,22.0f,-20.0f)).withLeftArmPose(new Rotations(30.0f,-20.0f,21.0f)).withRightLegPose(new Rotations(0.0f,0.0f,5.0f)).withLeftLegPose(new Rotations(0.0f,0.0f,-5.0f)); + public static final ArmorStandPose SAD = new ArmorStandPose("sad", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(63.0f,0.0f,0.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-5.0f,0.0f,5.0f)).withLeftArmPose(new Rotations(-5.0f,0.0f,-5.0f)).withRightLegPose(new Rotations(-5.0f,-10.0f,5.0f)).withLeftLegPose(new Rotations(-5.0f,16.0f,-5.0f)); + public static final ArmorStandPose JOYOUS = new ArmorStandPose("joyous", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-11.0f,0.0f,0.0f)).withBodyPose(new Rotations(-4.0f,0.0f,0.0f)).withRightArmPose(new Rotations(0.0f,0.0f,100.0f)).withLeftArmPose(new Rotations(0.0f,0.0f,-100.0f)).withRightLegPose(new Rotations(-8.0f,0.0f,60.0f)).withLeftLegPose(new Rotations(-8.0f,0.0f,-60.0f)); + public static final ArmorStandPose STARGAZING = new ArmorStandPose("stargazing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-22.0f,25.0f,0.0f)).withBodyPose(new Rotations(-4.0f,10.0f,0.0f)).withRightArmPose(new Rotations(-153.0f,34.0f,-3.0f)).withLeftArmPose(new Rotations(4.0f,18.0f,0.0f)).withRightLegPose(new Rotations(-4.0f,17.0f,2.0f)).withLeftLegPose(new Rotations(6.0f,24.0f,0.0f)); + @Nullable private final String name; + @Nullable + private final String source; private final Rotations headPose; private final Rotations bodyPose; private final Rotations leftArmPose; @@ -41,12 +59,13 @@ public class ArmorStandPose { private final Rotations leftLegPose; private final Rotations rightLegPose; - private ArmorStandPose(@Nullable String name) { - this(name, new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F)); + private ArmorStandPose(@Nullable String name, @Nullable String source) { + this(name, source, new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F)); } - private ArmorStandPose(@Nullable String name, Rotations headPose, Rotations bodyPose, Rotations leftArmPose, Rotations rightArmPose, Rotations leftLegPose, Rotations rightLegPose) { + private ArmorStandPose(@Nullable String name, @Nullable String source, Rotations headPose, Rotations bodyPose, Rotations leftArmPose, Rotations rightArmPose, Rotations leftLegPose, Rotations rightLegPose) { this.name = name; + this.source = source; this.headPose = headPose; this.bodyPose = bodyPose; this.leftArmPose = leftArmPose; @@ -56,7 +75,7 @@ private ArmorStandPose(@Nullable String name, Rotations headPose, Rotations body } public static ArmorStandPose empty() { - return new ArmorStandPose(null); + return new ArmorStandPose(null, null); } @Override @@ -65,8 +84,12 @@ public String toString() { } public String getTranslationKey() { - Objects.requireNonNull(this.name, "name is null"); - return "armorstatues.entity.armor_stand.pose." + this.name; + return this.name != null ? "armorstatues.entity.armor_stand.pose." + this.name : null; + } + + @Nullable + public String getSource() { + return this.source; } public Rotations getHeadPose() { @@ -94,31 +117,31 @@ public Rotations getRightLegPose() { } public ArmorStandPose withHeadPose(Rotations rotation) { - return new ArmorStandPose(this.name, rotation, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.source, rotation, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withBodyPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.headPose, rotation, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.source, this.headPose, rotation, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withLeftArmPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.headPose, this.bodyPose, rotation, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, rotation, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withRightArmPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.headPose, this.bodyPose, this.leftArmPose, rotation, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, this.leftArmPose, rotation, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withLeftLegPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, rotation, this.rightLegPose); + return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, rotation, this.rightLegPose); } public ArmorStandPose withRightLegPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, rotation); + return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, rotation); } public ArmorStandPose mirror() { - return new ArmorStandPose(this.name, mirrorRotation(this.headPose), mirrorRotation(this.bodyPose), mirrorRotation(this.rightArmPose), mirrorRotation(this.leftArmPose), mirrorRotation(this.rightLegPose), mirrorRotation(this.leftLegPose)); + return new ArmorStandPose(this.name, this.source, mirrorRotation(this.headPose), mirrorRotation(this.bodyPose), mirrorRotation(this.rightArmPose), mirrorRotation(this.leftArmPose), mirrorRotation(this.rightLegPose), mirrorRotation(this.leftLegPose)); } private static Rotations mirrorRotation(Rotations rotations) { @@ -168,7 +191,7 @@ public boolean serializeLegPoses(CompoundTag tag, @Nullable ArmorStandPose lastS } public static ArmorStandPose fromEntity(ArmorStand armorStand) { - return new ArmorStandPose(null, armorStand.getHeadPose(), armorStand.getBodyPose(), armorStand.getLeftArmPose(), armorStand.getRightArmPose(), armorStand.getLeftLegPose(), armorStand.getRightLegPose()); + return new ArmorStandPose(null, null, armorStand.getHeadPose(), armorStand.getBodyPose(), armorStand.getLeftArmPose(), armorStand.getRightArmPose(), armorStand.getLeftLegPose(), armorStand.getRightLegPose()); } public static void applyTagToEntity(ArmorStand armorStand, CompoundTag tag) { @@ -177,16 +200,11 @@ public static void applyTagToEntity(ArmorStand armorStand, CompoundTag tag) { public static ArmorStandPose random(PosePartMutator[] mutators, boolean clampRotations) { checkMutatorsSize(mutators); - return new ArmorStandPose(null, mutators[0].randomRotations(clampRotations), mutators[1].randomRotations(clampRotations), mutators[2].randomRotations(clampRotations), mutators[3].randomRotations(clampRotations), mutators[4].randomRotations(clampRotations), mutators[5].randomRotations(clampRotations)); + return new ArmorStandPose(null, null, mutators[0].randomRotations(clampRotations), mutators[1].randomRotations(clampRotations), mutators[2].randomRotations(clampRotations), mutators[3].randomRotations(clampRotations), mutators[4].randomRotations(clampRotations), mutators[5].randomRotations(clampRotations)); } public static ArmorStandPose[] values() { - return new ArmorStandPose[]{DEFAULT, SOLEMN, ATHENA, BRANDISH, HONOR, ENTERTAIN, SALUTE, HERO, RIPOSTE, ZOMBIE, CANCAN_A, CANCAN_B}; - } - - public static ArmorStandPose selectRandomPose() { - ArmorStandPose[] values = values(); - return values[RANDOM.nextInt(values().length)]; + return new ArmorStandPose[]{DEFAULT, SOLEMN, ATHENA, BRANDISH, HONOR, ENTERTAIN, SALUTE, HERO, RIPOSTE, ZOMBIE, CANCAN, WALKING, RUNNING, POINTING, BLOCKING, LUNGEING, WINNING, SITTING, ARABESQUE, CUPID, CONFIDENT, DEATH, FACEPALM, LAZING, CONFUSED, FORMAL, SAD, JOYOUS, STARGAZING}; } public static void checkMutatorsSize(PosePartMutator[] mutators) { diff --git a/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java index 2a1fc84..9c22d51 100644 --- a/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java +++ b/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -1,10 +1,10 @@ package fuzs.armorstatues.config; -import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandScreen; import fuzs.puzzleslib.config.ConfigCore; import fuzs.puzzleslib.config.annotation.Config; public class ClientConfig implements ConfigCore { - @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + ArmorStandAlignmentsScreen.VANILLA_TWEAKS_HOMEPAGE}) + @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) public boolean useVanillaTweaksTriggers = false; } diff --git a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index ff6704d..5ad84b0 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-25T07:42:53.692341 Languages: en_us -ac65fad1ef91c515edfd99af5fc88ae10f19aba3 assets/statues/lang/en_us.json +// 1.19.2 2023-07-25T14:46:14.302258 Languages: en_us +283172ead1153cedb61b98be0359d47309080a21 assets/statues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/statues/lang/en_us.json b/Forge/src/generated/resources/assets/statues/lang/en_us.json index cf66022..3ea7d30 100644 --- a/Forge/src/generated/resources/assets/statues/lang/en_us.json +++ b/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -1,32 +1,55 @@ { + "armorstatues.entity.armor_stand.pose.arabesque": "Arabesque", "armorstatues.entity.armor_stand.pose.athena": "Athena", + "armorstatues.entity.armor_stand.pose.blocking": "Blocking", "armorstatues.entity.armor_stand.pose.brandish": "Brandish", - "armorstatues.entity.armor_stand.pose.cancanA": "Cancan", - "armorstatues.entity.armor_stand.pose.cancanB": "Cancan (Mirrored)", + "armorstatues.entity.armor_stand.pose.by": "By %s", + "armorstatues.entity.armor_stand.pose.cancan": "Cancan", + "armorstatues.entity.armor_stand.pose.confident": "Confident", + "armorstatues.entity.armor_stand.pose.confused": "Confused", + "armorstatues.entity.armor_stand.pose.cupid": "Cupid", + "armorstatues.entity.armor_stand.pose.death": "Death", "armorstatues.entity.armor_stand.pose.default": "Default", "armorstatues.entity.armor_stand.pose.entertain": "Entertain", + "armorstatues.entity.armor_stand.pose.facepalm": "Facepalm", + "armorstatues.entity.armor_stand.pose.formal": "Formal", "armorstatues.entity.armor_stand.pose.hero": "Hero", "armorstatues.entity.armor_stand.pose.honor": "Honor", + "armorstatues.entity.armor_stand.pose.joyous": "Joyous", + "armorstatues.entity.armor_stand.pose.lazing": "Lazing", + "armorstatues.entity.armor_stand.pose.lungeing": "Lungeing", + "armorstatues.entity.armor_stand.pose.pointing": "Pointing", "armorstatues.entity.armor_stand.pose.riposte": "Riposte", + "armorstatues.entity.armor_stand.pose.running": "Running", + "armorstatues.entity.armor_stand.pose.sad": "Sad", "armorstatues.entity.armor_stand.pose.salute": "Salute", + "armorstatues.entity.armor_stand.pose.sitting": "Sitting", "armorstatues.entity.armor_stand.pose.solemn": "Solemn", + "armorstatues.entity.armor_stand.pose.stargazing": "Stargazing", + "armorstatues.entity.armor_stand.pose.walking": "Walking", + "armorstatues.entity.armor_stand.pose.winning": "Winning", "armorstatues.entity.armor_stand.pose.zombie": "Zombie", "armorstatues.item.armor_stand.description": "Use %s + %s with an empty hand to open configuration screen.", - "armorstatues.screen.alignments.block": "Align Block", - "armorstatues.screen.alignments.credit": "Alignment values are taken from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!", - "armorstatues.screen.alignments.itemFlat": "Align Item As Flat", - "armorstatues.screen.alignments.itemFloating": "Align Item As Floating", - "armorstatues.screen.alignments.tool": "Align Tool As Flat", + "armorstatues.screen.alignments.aligned": "Aligned!", + "armorstatues.screen.alignments.block": "Align Block on Surface", + "armorstatues.screen.alignments.block.description": "Align an armor stand placed on a surface so that a block held by it appears on the surface.", + "armorstatues.screen.alignments.centered": "Align Centered", + "armorstatues.screen.alignments.centered.description": "Align an armor stand in the center of the block position it is placed on.", + "armorstatues.screen.alignments.cornered": "Align Cornered", + "armorstatues.screen.alignments.cornered.description": "Align an armor stand at the corner of the block position it is placed on.", + "armorstatues.screen.alignments.itemFlat": "Align Item Flat On Surface", + "armorstatues.screen.alignments.itemFlat.description": "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface.", + "armorstatues.screen.alignments.itemFloating": "Align Item On Surface", + "armorstatues.screen.alignments.itemFloating.description": "Align an armor stand placed on a surface so that an item held by it appears upright on the surface.", + "armorstatues.screen.alignments.tool": "Align Tool Flat On Surface", + "armorstatues.screen.alignments.tool.description": "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface.", "armorstatues.screen.failure": "Unable to modify armor stand data: %s", "armorstatues.screen.failure.noPermission": "No Permission", - "armorstatues.screen.failure.notFinished": "Last Action Not Finished", + "armorstatues.screen.failure.notFinished": "Queue Not Empty", "armorstatues.screen.finished": "Finished sending queued armor stand data", "armorstatues.screen.pose.randomize": "Randomize", "armorstatues.screen.pose.randomized": "Applied!", - "armorstatues.screen.position.aligned": "Aligned!", "armorstatues.screen.position.blocks": "%s Block(s)", - "armorstatues.screen.position.centered": "Align Centered", - "armorstatues.screen.position.cornered": "Align Cornered", "armorstatues.screen.position.decrement": "Decrement by %s", "armorstatues.screen.position.degrees": "%s°", "armorstatues.screen.position.increment": "Increment by %s", @@ -74,5 +97,6 @@ "armorstatues.screen.type.poses": "Poses", "armorstatues.screen.type.position": "Position", "armorstatues.screen.type.rotations": "Rotations", - "armorstatues.screen.type.style": "Style" + "armorstatues.screen.type.style": "Style", + "armorstatues.screen.vanillaTweaksCredit": "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!" } \ No newline at end of file diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index bd3a2d1..a57684d 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -16,10 +16,10 @@ public ModLanguageProvider(DataGenerator gen, String modId) { protected void addTranslations() { this.add("armorstatues.item.armor_stand.description", "Use %s + %s with an empty hand to open configuration screen."); this.add("armorstatues.screen.style.name", "Set a name to display above the entity if enabled."); + this.add("armorstatues.entity.armor_stand.pose.by", "By %s"); this.add(ArmorStandPose.ATHENA.getTranslationKey(), "Athena"); this.add(ArmorStandPose.BRANDISH.getTranslationKey(), "Brandish"); - this.add(ArmorStandPose.CANCAN_A.getTranslationKey(), "Cancan"); - this.add(ArmorStandPose.CANCAN_B.getTranslationKey(), "Cancan (Mirrored)"); + this.add(ArmorStandPose.CANCAN.getTranslationKey(), "Cancan"); this.add(ArmorStandPose.DEFAULT.getTranslationKey(), "Default"); this.add(ArmorStandPose.ENTERTAIN.getTranslationKey(), "Entertain"); this.add(ArmorStandPose.HERO.getTranslationKey(), "Hero"); @@ -28,6 +28,24 @@ protected void addTranslations() { this.add(ArmorStandPose.SALUTE.getTranslationKey(), "Salute"); this.add(ArmorStandPose.SOLEMN.getTranslationKey(), "Solemn"); this.add(ArmorStandPose.ZOMBIE.getTranslationKey(), "Zombie"); + this.add(ArmorStandPose.WALKING.getTranslationKey(), "Walking"); + this.add(ArmorStandPose.RUNNING.getTranslationKey(), "Running"); + this.add(ArmorStandPose.POINTING.getTranslationKey(), "Pointing"); + this.add(ArmorStandPose.BLOCKING.getTranslationKey(), "Blocking"); + this.add(ArmorStandPose.LUNGEING.getTranslationKey(), "Lungeing"); + this.add(ArmorStandPose.WINNING.getTranslationKey(), "Winning"); + this.add(ArmorStandPose.SITTING.getTranslationKey(), "Sitting"); + this.add(ArmorStandPose.ARABESQUE.getTranslationKey(), "Arabesque"); + this.add(ArmorStandPose.CUPID.getTranslationKey(), "Cupid"); + this.add(ArmorStandPose.CONFIDENT.getTranslationKey(), "Confident"); + this.add(ArmorStandPose.DEATH.getTranslationKey(), "Death"); + this.add(ArmorStandPose.FACEPALM.getTranslationKey(), "Facepalm"); + this.add(ArmorStandPose.LAZING.getTranslationKey(), "Lazing"); + this.add(ArmorStandPose.CONFUSED.getTranslationKey(), "Confused"); + this.add(ArmorStandPose.FORMAL.getTranslationKey(), "Formal"); + this.add(ArmorStandPose.SAD.getTranslationKey(), "Sad"); + this.add(ArmorStandPose.JOYOUS.getTranslationKey(), "Joyous"); + this.add(ArmorStandPose.STARGAZING.getTranslationKey(), "Stargazing"); this.add(ArmorStandScreenType.EQUIPMENT.getTranslationKey(), "Equipment"); this.add(ArmorStandScreenType.ROTATIONS.getTranslationKey(), "Rotations"); this.add(ArmorStandScreenType.STYLE.getTranslationKey(), "Style"); @@ -58,9 +76,6 @@ protected void addTranslations() { this.add("armorstatues.screen.position.z", "Z-Position:"); this.add("armorstatues.screen.position.increment", "Increment by %s"); this.add("armorstatues.screen.position.decrement", "Decrement by %s"); - this.add("armorstatues.screen.position.centered", "Align Centered"); - this.add("armorstatues.screen.position.cornered", "Align Cornered"); - this.add("armorstatues.screen.position.aligned", "Aligned!"); this.add("armorstatues.screen.pose.randomize", "Randomize"); this.add("armorstatues.screen.pose.randomized", "Applied!"); this.add("armorstatues.screen.rotations.pose.head", "Head"); @@ -81,14 +96,23 @@ protected void addTranslations() { this.add("armorstatues.screen.rotations.x", "X: %s"); this.add("armorstatues.screen.rotations.y", "Y: %s"); this.add("armorstatues.screen.rotations.z", "Z: %s"); - this.add("armorstatues.screen.alignments.block", "Align Block"); - this.add("armorstatues.screen.alignments.itemFloating", "Align Item As Floating"); - this.add("armorstatues.screen.alignments.itemFlat", "Align Item As Flat"); - this.add("armorstatues.screen.alignments.tool", "Align Tool As Flat"); - this.add("armorstatues.screen.alignments.credit", "Alignment values are taken from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); + this.add("armorstatues.screen.alignments.centered", "Align Centered"); + this.add("armorstatues.screen.alignments.centered.description", "Align an armor stand in the center of the block position it is placed on."); + this.add("armorstatues.screen.alignments.cornered", "Align Cornered"); + this.add("armorstatues.screen.alignments.cornered.description", "Align an armor stand at the corner of the block position it is placed on."); + this.add("armorstatues.screen.alignments.aligned", "Aligned!"); + this.add("armorstatues.screen.alignments.block", "Align Block on Surface"); + this.add("armorstatues.screen.alignments.block.description", "Align an armor stand placed on a surface so that a block held by it appears on the surface."); + this.add("armorstatues.screen.alignments.itemFloating", "Align Item On Surface"); + this.add("armorstatues.screen.alignments.itemFloating.description", "Align an armor stand placed on a surface so that an item held by it appears upright on the surface."); + this.add("armorstatues.screen.alignments.itemFlat", "Align Item Flat On Surface"); + this.add("armorstatues.screen.alignments.itemFlat.description", "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface."); + this.add("armorstatues.screen.alignments.tool", "Align Tool Flat On Surface"); + this.add("armorstatues.screen.alignments.tool.description", "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface."); + this.add("armorstatues.screen.vanillaTweaksCredit", "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); this.add("armorstatues.screen.failure", "Unable to modify armor stand data: %s"); this.add("armorstatues.screen.failure.noPermission", "No Permission"); - this.add("armorstatues.screen.failure.notFinished", "Last Action Not Finished"); + this.add("armorstatues.screen.failure.notFinished", "Queue Not Empty"); this.add("armorstatues.screen.finished", "Finished sending queued armor stand data"); } } From 4826d0bf4ad38fb92422b3aa64c6daeebfe67822 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Tue, 25 Jul 2023 18:19:47 +0200 Subject: [PATCH 06/31] final fixes --- CHANGELOG.md | 10 ++++- .../api/client/ArmorStatuesApiClient.java | 1 - .../ArmorStandAlignmentsScreen.java | 39 ++++++++++++++++--- .../armorstand/ArmorStandRotationsScreen.java | 36 +++++++++-------- .../client/data/CommandDataSyncHandler.java | 21 ++++++---- .../data/VanillaTweaksDataSyncHandler.java | 14 +++---- .../decoration/ArmorStandDataProvider.java | 2 +- .../inventory/data/ArmorStandAlignment.java | 16 ++++---- .../world/inventory/data/PosePartMutator.java | 8 ++-- 9 files changed, 93 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f67ee69..4b74617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,18 @@ The format is based on [Keep a Changelog]. ## [v4.0.5-1.19.2] - 2023-07-25 ### Added +- Added support for the Vanilla Tweaks Armor Statues data pack +- This means when Armor Statues as a mod is **NOT** installed on the server you are playing on, it is now enough to install said data pack on the server to be able to use almost all features in the statue configuration screen +- Some actions such as switching poses take a couple of seconds to apply due to the nature of how data packs work unfortunately +- Alternatively players with operator permissions on the server are still able to configure armor stands from the screen without any data pack requirement - Added a button to the rotations screen for mirroring the current pose +- Added many new poses from the Vanilla Tweaks Armor Statues data pack ### Changed -- Text fields now show description tooltips when hovered to make it more clear which field is for setting a new display name and which one changes the statue skin - Opening the statue menu no longer requires a stick to be held, instead shift + right-click with an empty hand is the way to go, which the statue item tooltip reflects ### Fixed -- Fixed opening the armor stand configuration screen with a Fabric client on a server without the mod interacting with the armor stand server-side (e.g. removing equipment) +- Fixed opening the armor stand configuration screen with a Fabric client on a server without the mod interacting with the armor stand server-side (e.g. removing equipment) +- Fixed alignments on the alignment screen not working correctly if the armor stand was rotated at certain angles +- Fixed left and right arm and leg parts being swapped on the rotations screen - Fixed a rare network issue on servers when both Armor Statues and Straw Statues are installed ## [v4.0.4-1.19.2] - 2023-01-17 diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java b/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java index 254d607..f67dfb5 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java @@ -4,7 +4,6 @@ import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.PosePartMutator; -import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; import fuzs.puzzleslib.client.core.ClientModConstructor; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.inventory.InventoryMenu; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index 9891e8f..773f382 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -9,11 +9,15 @@ import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import java.util.EnumSet; @@ -63,8 +67,8 @@ protected Vec3 getCurrentPosition() { return ArmorStandAlignmentsScreen.this.holder.getArmorStand().position(); } - protected void setNewPosition(Vec3 vec3) { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPosition(vec3.x(), vec3.y(), vec3.z()); + protected void setNewPosition(Vec3 vec3, boolean finalize) { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPosition(vec3.x(), vec3.y(), vec3.z(), finalize); } } @@ -74,12 +78,12 @@ private class PositionAlignWidget extends BlockPositionWidget { public void init(int posX, int posY) { super.init(posX, posY); this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, Component.translatable("armorstatues.screen.alignments.centered"), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { - this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5)); + this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5), true); }, (button, poseStack, mouseX, mouseY) -> { ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, ArmorStandAlignmentsScreen.this.font.split(Component.translatable("armorstatues.screen.alignments.centered.description"), 175), mouseX, mouseY); }))); this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, Component.translatable("armorstatues.screen.alignments.cornered"), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { - this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class))); + this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)), true); }, (button, poseStack, mouseX, mouseY) -> { ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, ArmorStandAlignmentsScreen.this.font.split(Component.translatable("armorstatues.screen.alignments.cornered.description"), 175), mouseX, mouseY); }))); @@ -97,15 +101,17 @@ public AlignmentWidget(ArmorStandAlignment alignment) { public void init(int posX, int posY) { super.init(posX, posY); this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPose(this.alignment.getPose(), false); ArmorStand armorStand = ArmorStandAlignmentsScreen.this.holder.getArmorStand(); - this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5).add(this.alignment.getPosition(armorStand.isSmall()))); if (!armorStand.isInvisible()) { ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); } if (!armorStand.isNoGravity()) { ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); } + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPose(this.alignment.getPose(), false); + Vec3 alignmentOffset = this.alignment.getAlignmentOffset(armorStand.isSmall()); + Vec3 localPosition = getLocalPosition(armorStand, alignmentOffset); + this.setNewPosition(localPosition, false); ArmorStandAlignmentsScreen.this.dataSyncHandler.finalizeCurrentOperation(); }, (button, poseStack, mouseX, mouseY) -> { Component component = Component.translatable(this.alignment.getDescriptionsKey()); @@ -113,5 +119,26 @@ public void init(int posX, int posY) { ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, lines, mouseX, mouseY); }))); } + + /** + * Copied from {@link net.minecraft.commands.arguments.coordinates.LocalCoordinates#getPosition(CommandSourceStack)}. + */ + private static Vec3 getLocalPosition(Entity entity, Vec3 offset) { + Vec2 vec2 = entity.getRotationVector(); + Vec3 vec3 = entity.position(); + float f = Mth.cos((vec2.y + 90.0F) * 0.017453292F); + float g = Mth.sin((vec2.y + 90.0F) * 0.017453292F); + float h = Mth.cos(-vec2.x * 0.017453292F); + float i = Mth.sin(-vec2.x * 0.017453292F); + float j = Mth.cos((-vec2.x + 90.0F) * 0.017453292F); + float k = Mth.sin((-vec2.x + 90.0F) * 0.017453292F); + Vec3 vec32 = new Vec3(f * h, i, g * h); + Vec3 vec33 = new Vec3(f * j, k, g * j); + Vec3 vec34 = vec32.cross(vec33).scale(-1.0); + double d = vec32.x * offset.z() + vec33.x * offset.y() + vec34.x * offset.x(); + double e = vec32.y * offset.z() + vec33.y * offset.y() + vec34.y * offset.x(); + double l = vec32.z * offset.z() + vec33.z * offset.y() + vec34.z * offset.x(); + return new Vec3(vec3.x + d, vec3.y + e, vec3.z + l); + } } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index 8077ccd..c9bb4eb 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -15,23 +15,23 @@ import net.minecraft.client.gui.components.ImageButton; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.sounds.SoundManager; +import net.minecraft.locale.Language; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; -import net.minecraft.util.FormattedCharSequence; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; import org.apache.commons.compress.utils.Lists; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.function.Predicate; import java.util.stream.Collectors; public class ArmorStandRotationsScreen extends AbstractArmorStandScreen { + private static final String TIP_TRANSLATION_KEY = "armorstatues.screen.rotations.tip"; private static final Map> POSE_PART_MUTATOR_FILTERS = Maps.newHashMap(); - private static final Random RANDOM = new Random(); private static boolean clampRotations = true; @Nullable @@ -66,16 +66,18 @@ protected void init() { }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.limited"), mouseX, mouseY); }, Component.translatable("armorstatues.screen.rotations.limited"))); - List tipComponent = this.font.split(this.getTipComponent(), 175); - this.addRenderableWidget(new ImageButton(this.leftPos + 107, this.topPos + 10, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> {}, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, tipComponent, mouseX, mouseY); - }, CommonComponents.EMPTY) { + Component tipComponent = this.getTipComponent(); + if (tipComponent != null) { + this.addRenderableWidget(new ImageButton(this.leftPos + 107, this.topPos + 10, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> {}, (button, poseStack, mouseX, mouseY) -> { + this.renderTooltip(poseStack, this.font.split(tipComponent, 175), mouseX, mouseY); + }, CommonComponents.EMPTY) { - @Override - public void playDownSound(SoundManager handler) { + @Override + public void playDownSound(SoundManager handler) { - } - }); + } + }); + } this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 34, 20, 20, 240, 124, getArmorStandWidgetsLocation(), button -> { this.setCurrentPose(ArmorStandPose.empty()); }, (button, poseStack, mouseX, mouseY) -> { @@ -173,12 +175,14 @@ public boolean isDirty() { } } + @Nullable private Component getTipComponent() { - Component[] components = { - Component.translatable("armorstatues.screen.rotations.tip1"), - Component.translatable("armorstatues.screen.rotations.tip2") - }; - return components[RANDOM.nextInt(components.length)]; + List components = Lists.newArrayList(); + for (int i = 1; Language.getInstance().has(TIP_TRANSLATION_KEY + i); i++) { + components.add(Component.translatable(TIP_TRANSLATION_KEY + i)); + } + Collections.shuffle(components); + return components.stream().findAny().orElse(null); } private void toggleLockButtons() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java index 71cfb09..43963f7 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java @@ -26,7 +26,8 @@ public class CommandDataSyncHandler implements DataSyncHandler { @Nullable static ArmorStandScreenType lastType; - private static boolean queueLocked; + @Nullable + private static ArmorStand queueArmorStand; private static int itemDequeuedTicks; private final ArmorStand armorStand; @@ -149,15 +150,19 @@ public void setLastType(ArmorStandScreenType lastType) { @Override public void tick() { if (itemDequeuedTicks > 0) itemDequeuedTicks--; - if (itemDequeuedTicks == 0 && !CLIENT_COMMAND_QUEUE.isEmpty()) { - this.player.commandSigned(CLIENT_COMMAND_QUEUE.poll(), null); - itemDequeuedTicks = this.getDefaultDequeuedTicks(); + if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { + if (queueArmorStand.isAlive()) { + this.player.commandSigned(CLIENT_COMMAND_QUEUE.poll(), null); + } else { + CLIENT_COMMAND_QUEUE.clear(); + } + itemDequeuedTicks = this.getDequeueDelayTicks(); } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { this.sendDisplayMessage(FINISHED_COMPONENT, false); } } - protected int getDefaultDequeuedTicks() { + protected int getDequeueDelayTicks() { return 5; } @@ -176,8 +181,8 @@ private boolean testPermissionLevel() { protected boolean enqueueClientCommand(String clientCommand) { if (CLIENT_COMMAND_QUEUE.isEmpty()) { - queueLocked = false; - } else if (queueLocked) { + queueArmorStand = null; + } else if (queueArmorStand != null) { this.sendFailureMessage(NOT_FINISHED_COMPONENT); return false; } @@ -188,7 +193,7 @@ protected boolean enqueueClientCommand(String clientCommand) { @Override public void finalizeCurrentOperation() { if (!CLIENT_COMMAND_QUEUE.isEmpty()) { - queueLocked = true; + queueArmorStand = this.getArmorStand(); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java index 966d427..34b3863 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java @@ -86,10 +86,10 @@ public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; - private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; - private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE}; - private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; - private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE}; private static final int[] POSE_ADJUSTMENT_LEFT_LEG = new int[]{POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE}; private static final NavigableMap NUDGE_POSITIONS_X_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_X3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_X8_NEGATIVE); private static final NavigableMap NUDGE_POSITIONS_X_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_X3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_X8_POSITIVE); @@ -200,14 +200,12 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, bo super.sendStyleOption(styleOption, value, finalize); return; } - if (this.enqueueTriggerValue(triggerValue)) { - styleOption.setOption(this.getArmorStand(), value); - } + this.enqueueTriggerValue(triggerValue); if (finalize) this.finalizeCurrentOperation(); } @Override - protected int getDefaultDequeuedTicks() { + protected int getDequeueDelayTicks() { return 20; } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java b/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java index df86a7f..f21acbc 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java @@ -17,7 +17,7 @@ default ArmorStandScreenType getDefaultScreenType() { } default PosePartMutator[] getPosePartMutators() { - return new PosePartMutator[]{PosePartMutator.HEAD, PosePartMutator.BODY, PosePartMutator.LEFT_ARM, PosePartMutator.RIGHT_ARM, PosePartMutator.LEFT_LEG, PosePartMutator.RIGHT_LEG}; + return new PosePartMutator[]{PosePartMutator.HEAD, PosePartMutator.BODY, PosePartMutator.RIGHT_ARM, PosePartMutator.LEFT_ARM, PosePartMutator.RIGHT_LEG, PosePartMutator.LEFT_LEG}; } default ArmorStandPose getRandomPose(boolean clampRotations) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java index bbb3db2..c604a24 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java @@ -6,7 +6,7 @@ import java.util.Locale; /** - * values copied from Vanilla Tweaks data pack + * Values copied from Vanilla Tweaks data pack. */ public enum ArmorStandAlignment { BLOCK("block", new Rotations(-15.0f, 135.0f, 0.0f), new Vec3(0.5725, -0.655, 0.352), new Vec3(0.28625, -0.3275, 0.176)), @@ -16,14 +16,14 @@ public enum ArmorStandAlignment { private final String name; private final ArmorStandPose pose; - private final Vec3 position; - private final Vec3 smallPosition; + private final Vec3 offset; + private final Vec3 offsetIfSmall; - ArmorStandAlignment(String name, Rotations rightArmRotations, Vec3 position, Vec3 smallPosition) { + ArmorStandAlignment(String name, Rotations rightArmRotations, Vec3 offset, Vec3 offsetIfSmall) { this.name = name; this.pose = ArmorStandPose.empty().withRightArmPose(rightArmRotations); - this.position = position; - this.smallPosition = smallPosition; + this.offset = offset; + this.offsetIfSmall = offsetIfSmall; } @Override @@ -43,7 +43,7 @@ public ArmorStandPose getPose() { return this.pose; } - public Vec3 getPosition(boolean small) { - return small ? this.smallPosition : this.position; + public Vec3 getAlignmentOffset(boolean small) { + return small ? this.offsetIfSmall : this.offset; } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java index d8122db..fc62c8b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java @@ -13,10 +13,10 @@ public final class PosePartMutator { public static final PosePartMutator HEAD = new PosePartMutator("head", ArmorStandPose::getHeadPose, ArmorStandPose::withHeadPose, PosePartAxisRange.range(-60.0F, 60.0F), PosePartAxisRange.range(-60.0F, 60.0F), PosePartAxisRange.range(-120.0, 120.0)); public static final PosePartMutator BODY = new PosePartMutator("body", ArmorStandPose::getBodyPose, ArmorStandPose::withBodyPose, PosePartAxisRange.range(-30.0F, 30.0F), PosePartAxisRange.range(-30.0F, 30.0F), PosePartAxisRange.range(-120.0, 120.0)); - public static final PosePartMutator LEFT_ARM = new PosePartMutator("leftArm", ArmorStandPose::getRightArmPose, ArmorStandPose::withRightArmPose, PosePartAxisRange.range(-180.0, 0.0), PosePartAxisRange.range(-90.0, 45.0), PosePartAxisRange.range(-120.0, 120.0)); - public static final PosePartMutator RIGHT_ARM = new PosePartMutator("rightArm", ArmorStandPose::getLeftArmPose, ArmorStandPose::withLeftArmPose, PosePartAxisRange.range(-180.0, 0.0), PosePartAxisRange.range(-45.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); - public static final PosePartMutator LEFT_LEG = new PosePartMutator("leftLeg", ArmorStandPose::getRightLegPose, ArmorStandPose::withRightLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(-90.0, 0.0), PosePartAxisRange.range(-120.0, 120.0)); - public static final PosePartMutator RIGHT_LEG = new PosePartMutator("rightLeg", ArmorStandPose::getLeftLegPose, ArmorStandPose::withLeftLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(0.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); + public static final PosePartMutator RIGHT_ARM = new PosePartMutator("rightArm", ArmorStandPose::getRightArmPose, ArmorStandPose::withRightArmPose, PosePartAxisRange.range(-180.0, 0.0), PosePartAxisRange.range(-90.0, 45.0), PosePartAxisRange.range(-120.0, 120.0)); + public static final PosePartMutator LEFT_ARM = new PosePartMutator("leftArm", ArmorStandPose::getLeftArmPose, ArmorStandPose::withLeftArmPose, PosePartAxisRange.range(-180.0, 0.0), PosePartAxisRange.range(-45.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); + public static final PosePartMutator RIGHT_LEG = new PosePartMutator("rightLeg", ArmorStandPose::getRightLegPose, ArmorStandPose::withRightLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(-90.0, 0.0), PosePartAxisRange.range(-120.0, 120.0)); + public static final PosePartMutator LEFT_LEG = new PosePartMutator("leftLeg", ArmorStandPose::getLeftLegPose, ArmorStandPose::withLeftLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(0.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); private final String name; private final Function getRotations; From e8ed1892d05785d08a56e22b3202b0bd5bcd5a97 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 26 Jul 2023 00:34:11 +0200 Subject: [PATCH 07/31] reduce amount of trigger packets for alignments --- CHANGELOG.md | 3 +- .../armorstand/AbstractArmorStandScreen.java | 18 ++- .../armorstand/ArmorStandEquipmentScreen.java | 26 ++++ .../armorstand/ArmorStandPosesScreen.java | 6 +- .../armorstand/ArmorStandRotationsScreen.java | 2 +- .../client/data/CommandDataSyncHandler.java | 2 +- .../data/VanillaTweaksDataSyncHandler.java | 18 +-- .../world/inventory/data/ArmorStandPose.java | 114 +++++++++++++----- .../fuzs/armorstatues/ArmorStatuesFabric.java | 3 - .../client/ArmorStatuesFabricClient.java | 3 - 10 files changed, 147 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b74617..1e96942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ The format is based on [Keep a Changelog]. - Some actions such as switching poses take a couple of seconds to apply due to the nature of how data packs work unfortunately - Alternatively players with operator permissions on the server are still able to configure armor stands from the screen without any data pack requirement - Added a button to the rotations screen for mirroring the current pose -- Added many new poses from the Vanilla Tweaks Armor Statues data pack +- Added many new poses from the Vanilla Tweaks Armor Statues data pack +- Added the ability to switch between tabs by pressing hotbar keys ### Changed - Opening the statue menu no longer requires a stick to be held, instead shift + right-click with an empty hand is the way to go, which the statue item tooltip reflects ### Fixed diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index e45edc3..07d2449 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -10,6 +10,7 @@ import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.puzzleslib.client.core.ClientCoreServices; +import fuzs.puzzleslib.client.gui.screens.CommonScreens; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; @@ -229,6 +230,20 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { } else if (this.minecraft.options.keyInventory.matches(keyCode, scanCode)) { this.onClose(); return true; + } else if (handleHotbarKeyPressed(keyCode, scanCode, this, this.dataSyncHandler.tabs())) { + return true; + } + return false; + } + + public static boolean handleHotbarKeyPressed(int keyCode, int scanCode, T screen, ArmorStandScreenType[] tabs) { + Minecraft minecraft = CommonScreens.INSTANCE.getMinecraft(screen); + for (int i = 0; i < Math.min(tabs.length, 9); ++i) { + if (minecraft.options.keyHotbarSlots[i].matches(keyCode, scanCode)) { + if (openTabScreen(screen, tabs[i], true)) { + return true; + } + } } return false; } @@ -263,7 +278,8 @@ private static boolean openTabScreen(T scr if (screenType != screen.getScreenType()) { Minecraft minecraft = ClientCoreServices.SCREENS.getMinecraft(screen); if (clickSound) { - minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); + SimpleSoundInstance sound = SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F); + minecraft.getSoundManager().play(sound); } minecraft.setScreen(screen.createScreenType(screenType)); return true; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java index cb10d3f..a93433f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java @@ -127,6 +127,32 @@ protected void renderLabels(PoseStack poseStack, int mouseX, int mouseY) { } + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + ArmorStandScreenType[] tabs = this.dataSyncHandler.tabs(); + if (this.menu.getCarried().isEmpty() && this.hoveredSlot == null) { + AbstractArmorStandScreen.handleHotbarKeyPressed(keyCode, scanCode, this, tabs); + } + return super.keyPressed(keyCode, scanCode, modifiers); + } + + private boolean shouldHandleHotbarSlotKeys(int keyCode, int scanCode, ArmorStandScreenType[] tabs) { + if (this.menu.getCarried().isEmpty() && this.hoveredSlot != null) { + if (this.hoveredSlot.hasItem()) { + return false; + } else { + for (int i = 0; i < Math.min(tabs.length, 9); ++i) { + if (this.minecraft.options.keyHotbarSlots[i].matches(keyCode, scanCode)) { + if (!this.minecraft.player.getInventory().getItem(i).isEmpty()) { + return false; + } + } + } + } + } + return true; + } + @Override public ArmorStandScreenType getScreenType() { return ArmorStandScreenType.EQUIPMENT; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java index 8327c06..ce4cb32 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java @@ -67,10 +67,10 @@ protected void init() { private void toggleCycleButtons(int increment) { int newFirstPoseIndex = firstPoseIndex + increment; - if (newFirstPoseIndex >= 0 && newFirstPoseIndex < ArmorStandPose.values().length) { + if (newFirstPoseIndex >= 0 && newFirstPoseIndex < ArmorStandPose.valuesLength()) { firstPoseIndex = newFirstPoseIndex; this.cycleButtons[0].active = newFirstPoseIndex - POSES_PER_PAGE >= 0; - this.cycleButtons[1].active = newFirstPoseIndex + POSES_PER_PAGE < ArmorStandPose.values().length; + this.cycleButtons[1].active = newFirstPoseIndex + POSES_PER_PAGE < ArmorStandPose.valuesLength(); for (int i = 0; i < this.poseButtons.length; i++) { this.poseButtons[i].visible = getPoseAt(i).isPresent(); } @@ -118,7 +118,7 @@ public ArmorStandScreenType getScreenType() { private static Optional getPoseAt(int index) { index += firstPoseIndex; - if (index >= ArmorStandPose.values().length) return Optional.empty(); + if (index >= ArmorStandPose.valuesLength()) return Optional.empty(); return Optional.of(ArmorStandPose.values()[index]); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index c9bb4eb..3897099 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -79,7 +79,7 @@ public void playDownSound(SoundManager handler) { }); } this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 34, 20, 20, 240, 124, getArmorStandWidgetsLocation(), button -> { - this.setCurrentPose(ArmorStandPose.empty()); + this.setCurrentPose(ArmorStandPose.EMPTY); }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.reset"), mouseX, mouseY); })); diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java index 43963f7..08fb5f4 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java @@ -68,7 +68,7 @@ public void sendPose(ArmorStandPose pose, boolean finalize) { this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); - this.lastSyncedPose = pose; + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); if (finalize) this.finalizeCurrentOperation(); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java index 34b3863..cc39c19 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java @@ -7,6 +7,7 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Rotations; import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.NavigableMap; @@ -106,18 +107,19 @@ public VanillaTweaksDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { @Override public void sendPose(ArmorStandPose pose, boolean finalize) { $1: { - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getHeadPose(), pose.getHeadPose(), POSE_ADJUSTMENT_HEAD)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getBodyPose(), pose.getBodyPose(), POSE_ADJUSTMENT_BODY)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightArmPose(), pose.getRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftArmPose(), pose.getLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightLegPose(), pose.getRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftLegPose(), pose.getLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG)) break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG)) break $1; } + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); if (finalize) this.finalizeCurrentOperation(); } - private boolean tryApplyPoseIncrements(Rotations oldPose, Rotations newPose, int[] poseAdjustment) { - if (oldPose.equals(newPose)) return true; + private boolean tryApplyPoseIncrements(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + if (newPose == null || oldPose.equals(newPose)) return true; if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) return false; diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index 99ba4e6..4a8d623 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -14,10 +14,12 @@ public class ArmorStandPose { private static final String MINECRAFT_SOURCE = "Minecraft"; private static final String VANILLA_TWEAKS_SOURCE = "Vanilla Tweaks"; + public static final Rotations ZERO_ROTATIONS = new Rotations(0.0F, 0.0F, 0.0F); public static final double DEGREES_SNAP_INTERVAL = 0.125; public static final DecimalFormat ROTATION_FORMAT = Util.make(new DecimalFormat("#.##"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); }); + public static final ArmorStandPose EMPTY = new ArmorStandPose(null, null); public static final ArmorStandPose ATHENA = new ArmorStandPose("athena", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(-5.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-3.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-60.0F, 20.0F, -10.0F)).withRightLegPose(new Rotations(3.0F, 3.0F, 3.0F)); public static final ArmorStandPose BRANDISH = new ArmorStandPose("brandish", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, -2.0F)).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(20.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 50.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); public static final ArmorStandPose CANCAN = new ArmorStandPose("cancan", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 22.0F, 0.0F)).withHeadPose(new Rotations(-5.0F, 18.0F, 0.0F)).withLeftArmPose(new Rotations(8.0F, 0.0F, -114.0F)).withLeftLegPose(new Rotations(-111.0F, 55.0F, 0.0F)).withRightArmPose(new Rotations(0.0F, 84.0F, 111.0F)).withRightLegPose(new Rotations(0.0F, 23.0F, -13.0F)); @@ -47,23 +49,30 @@ public class ArmorStandPose { public static final ArmorStandPose SAD = new ArmorStandPose("sad", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(63.0f,0.0f,0.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-5.0f,0.0f,5.0f)).withLeftArmPose(new Rotations(-5.0f,0.0f,-5.0f)).withRightLegPose(new Rotations(-5.0f,-10.0f,5.0f)).withLeftLegPose(new Rotations(-5.0f,16.0f,-5.0f)); public static final ArmorStandPose JOYOUS = new ArmorStandPose("joyous", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-11.0f,0.0f,0.0f)).withBodyPose(new Rotations(-4.0f,0.0f,0.0f)).withRightArmPose(new Rotations(0.0f,0.0f,100.0f)).withLeftArmPose(new Rotations(0.0f,0.0f,-100.0f)).withRightLegPose(new Rotations(-8.0f,0.0f,60.0f)).withLeftLegPose(new Rotations(-8.0f,0.0f,-60.0f)); public static final ArmorStandPose STARGAZING = new ArmorStandPose("stargazing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-22.0f,25.0f,0.0f)).withBodyPose(new Rotations(-4.0f,10.0f,0.0f)).withRightArmPose(new Rotations(-153.0f,34.0f,-3.0f)).withLeftArmPose(new Rotations(4.0f,18.0f,0.0f)).withRightLegPose(new Rotations(-4.0f,17.0f,2.0f)).withLeftLegPose(new Rotations(6.0f,24.0f,0.0f)); + private static final ArmorStandPose[] VALUES = {DEFAULT, SOLEMN, ATHENA, BRANDISH, HONOR, ENTERTAIN, SALUTE, HERO, RIPOSTE, ZOMBIE, CANCAN, WALKING, RUNNING, POINTING, BLOCKING, LUNGEING, WINNING, SITTING, ARABESQUE, CUPID, CONFIDENT, DEATH, FACEPALM, LAZING, CONFUSED, FORMAL, SAD, JOYOUS, STARGAZING}; @Nullable private final String name; @Nullable private final String source; + @Nullable private final Rotations headPose; + @Nullable private final Rotations bodyPose; + @Nullable private final Rotations leftArmPose; + @Nullable private final Rotations rightArmPose; + @Nullable private final Rotations leftLegPose; + @Nullable private final Rotations rightLegPose; private ArmorStandPose(@Nullable String name, @Nullable String source) { - this(name, source, new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F), new Rotations(0.0F, 0.0F, 0.0F)); + this(name, source, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS); } - private ArmorStandPose(@Nullable String name, @Nullable String source, Rotations headPose, Rotations bodyPose, Rotations leftArmPose, Rotations rightArmPose, Rotations leftLegPose, Rotations rightLegPose) { + private ArmorStandPose(@Nullable String name, @Nullable String source, @Nullable Rotations headPose, @Nullable Rotations bodyPose, @Nullable Rotations leftArmPose, @Nullable Rotations rightArmPose, @Nullable Rotations leftLegPose, @Nullable Rotations rightLegPose) { this.name = name; this.source = source; this.headPose = headPose; @@ -75,7 +84,7 @@ private ArmorStandPose(@Nullable String name, @Nullable String source, Rotations } public static ArmorStandPose empty() { - return new ArmorStandPose(null, null); + return new ArmorStandPose(null, null, null, null, null, null, null, null); } @Override @@ -93,26 +102,56 @@ public String getSource() { } public Rotations getHeadPose() { - return this.headPose; + return this.headPose != null ? this.headPose : ZERO_ROTATIONS; } public Rotations getBodyPose() { - return this.bodyPose; + return this.bodyPose != null ? this.bodyPose : ZERO_ROTATIONS; } public Rotations getLeftArmPose() { - return this.leftArmPose; + return this.leftArmPose != null ? this.leftArmPose : ZERO_ROTATIONS; } public Rotations getRightArmPose() { - return this.rightArmPose; + return this.rightArmPose != null ? this.rightArmPose : ZERO_ROTATIONS; } public Rotations getLeftLegPose() { - return this.leftLegPose; + return this.leftLegPose != null ? this.leftLegPose : ZERO_ROTATIONS; } public Rotations getRightLegPose() { + return this.rightLegPose != null ? this.rightLegPose : ZERO_ROTATIONS; + } + + @Nullable + public Rotations getNullableHeadPose() { + return this.headPose; + } + + @Nullable + public Rotations getNullableBodyPose() { + return this.bodyPose; + } + + @Nullable + public Rotations getNullableLeftArmPose() { + return this.leftArmPose; + } + + @Nullable + public Rotations getNullableRightArmPose() { + return this.rightArmPose; + } + + @Nullable + public Rotations getNullableLeftLegPose() { + return this.leftLegPose; + } + + @Nullable + public Rotations getNullableRightLegPose() { return this.rightLegPose; } @@ -141,20 +180,25 @@ public ArmorStandPose withRightLegPose(Rotations rotation) { } public ArmorStandPose mirror() { - return new ArmorStandPose(this.name, this.source, mirrorRotation(this.headPose), mirrorRotation(this.bodyPose), mirrorRotation(this.rightArmPose), mirrorRotation(this.leftArmPose), mirrorRotation(this.rightLegPose), mirrorRotation(this.leftLegPose)); + return new ArmorStandPose(this.name, this.source, mirrorRotations(this.headPose), mirrorRotations(this.bodyPose), mirrorRotations(this.rightArmPose), mirrorRotations(this.leftArmPose), mirrorRotations(this.rightLegPose), mirrorRotations(this.leftLegPose)); + } + + @Nullable + private static Rotations mirrorRotations(@Nullable Rotations rotations) { + return rotations != null ? new Rotations(rotations.getX(), -rotations.getY(), -rotations.getZ()) : null; } - private static Rotations mirrorRotation(Rotations rotations) { - return new Rotations(rotations.getX(), -rotations.getY(), -rotations.getZ()); + public ArmorStandPose copyAndFillFrom(ArmorStandPose fillFrom) { + return new ArmorStandPose(this.name, this.source, this.headPose != null ? this.headPose : fillFrom.headPose, this.bodyPose != null ? this.bodyPose : fillFrom.bodyPose, this.leftArmPose != null ? this.leftArmPose : fillFrom.leftArmPose, this.rightArmPose != null ? this.rightArmPose : fillFrom.rightArmPose, this.leftLegPose != null ? this.leftLegPose : fillFrom.leftLegPose, this.rightLegPose != null ? this.rightLegPose : fillFrom.rightLegPose); } public void applyToEntity(ArmorStand armorStand) { - armorStand.setHeadPose(this.headPose); - armorStand.setBodyPose(this.bodyPose); - armorStand.setLeftArmPose(this.leftArmPose); - armorStand.setRightArmPose(this.rightArmPose); - armorStand.setLeftLegPose(this.leftLegPose); - armorStand.setRightLegPose(this.rightLegPose); + armorStand.setHeadPose(this.getHeadPose()); + armorStand.setBodyPose(this.getBodyPose()); + armorStand.setLeftArmPose(this.getLeftArmPose()); + armorStand.setRightArmPose(this.getRightArmPose()); + armorStand.setLeftLegPose(this.getLeftLegPose()); + armorStand.setRightLegPose(this.getRightLegPose()); } public void serializeAllPoses(CompoundTag tag) { @@ -164,30 +208,42 @@ public void serializeAllPoses(CompoundTag tag) { } public boolean serializeBodyPoses(CompoundTag tag, @Nullable ArmorStandPose lastSentPose) { - if (lastSentPose == null || !this.headPose.equals(lastSentPose.headPose) || !this.bodyPose.equals(lastSentPose.bodyPose)) { + boolean hasChanged = false; + if (this.headPose != null && (lastSentPose == null || !this.headPose.equals(lastSentPose.headPose))) { tag.put("Head", this.headPose.save()); + hasChanged = true; + } + if (this.bodyPose != null && (lastSentPose == null || !this.bodyPose.equals(lastSentPose.bodyPose))) { tag.put("Body", this.bodyPose.save()); - return true; + hasChanged = true; } - return false; + return hasChanged; } public boolean serializeArmPoses(CompoundTag tag, @Nullable ArmorStandPose lastSentPose) { - if (lastSentPose == null || !this.leftArmPose.equals(lastSentPose.leftArmPose) || !this.rightArmPose.equals(lastSentPose.rightArmPose)) { + boolean hasChanged = false; + if (this.leftArmPose != null && (lastSentPose == null || !this.leftArmPose.equals(lastSentPose.leftArmPose))) { tag.put("LeftArm", this.leftArmPose.save()); + hasChanged = true; + } + if (this.rightArmPose != null && (lastSentPose == null || !this.rightArmPose.equals(lastSentPose.rightArmPose))) { tag.put("RightArm", this.rightArmPose.save()); - return true; + hasChanged = true; } - return false; + return hasChanged; } public boolean serializeLegPoses(CompoundTag tag, @Nullable ArmorStandPose lastSentPose) { - if (lastSentPose == null || !this.leftLegPose.equals(lastSentPose.leftLegPose) || !this.rightLegPose.equals(lastSentPose.rightLegPose)) { + boolean hasChanged = false; + if (this.leftLegPose != null && (lastSentPose == null || !this.leftLegPose.equals(lastSentPose.leftLegPose))) { tag.put("LeftLeg", this.leftLegPose.save()); + hasChanged = true; + } + if (this.rightLegPose != null && (lastSentPose == null || !this.rightLegPose.equals(lastSentPose.rightLegPose))) { tag.put("RightLeg", this.rightLegPose.save()); - return true; + hasChanged = true; } - return false; + return hasChanged; } public static ArmorStandPose fromEntity(ArmorStand armorStand) { @@ -204,7 +260,11 @@ public static ArmorStandPose random(PosePartMutator[] mutators, boolean clampRot } public static ArmorStandPose[] values() { - return new ArmorStandPose[]{DEFAULT, SOLEMN, ATHENA, BRANDISH, HONOR, ENTERTAIN, SALUTE, HERO, RIPOSTE, ZOMBIE, CANCAN, WALKING, RUNNING, POINTING, BLOCKING, LUNGEING, WINNING, SITTING, ARABESQUE, CUPID, CONFIDENT, DEATH, FACEPALM, LAZING, CONFUSED, FORMAL, SAD, JOYOUS, STARGAZING}; + return VALUES.clone(); + } + + public static int valuesLength() { + return VALUES.length; } public static void checkMutatorsSize(PosePartMutator[] mutators) { diff --git a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java index 30247a0..8a2ab67 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java +++ b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java @@ -3,7 +3,6 @@ import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.core.CoreServices; -import fuzs.puzzleslib.core.ModLoaderEnvironment; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.player.UseEntityCallback; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; @@ -19,8 +18,6 @@ public class ArmorStatuesFabric implements ModInitializer { @Override public void onInitialize() { - // TODO remove again - if (ModLoaderEnvironment.INSTANCE.isServer()) return; CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApi()); CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatues()); registerHandlers(); diff --git a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java index 23b3a5f..06ce155 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java +++ b/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java @@ -7,7 +7,6 @@ import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.armorstatues.handler.DataSyncTickHandler; import fuzs.puzzleslib.client.core.ClientCoreServices; -import fuzs.puzzleslib.core.ModLoaderEnvironment; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; @@ -18,8 +17,6 @@ public class ArmorStatuesFabricClient implements ClientModInitializer { @Override public void onInitializeClient() { - // TODO remove again - if (ModLoaderEnvironment.INSTANCE.isServer()) return; ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApiClient()); ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesClient()); registerHandlers(); From 122be9ecf3cd2c06e48d82b7114dfd10cf216bc9 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:26:33 +0200 Subject: [PATCH 08/31] move translation keys to constants --- CHANGELOG.md | 4 + .../api/client/ArmorStatuesApiClient.java | 2 +- .../components/NewTextureSliderButton.java | 5 - .../gui/components/UnboundedSliderButton.java | 8 +- .../AbstractArmorStandPositionScreen.java | 52 +++++ .../armorstand/AbstractArmorStandScreen.java | 18 +- .../armorstand/ArmorStandPosesScreen.java | 4 +- .../armorstand/ArmorStandPositionScreen.java | 52 +++-- .../armorstand/ArmorStandRotationsScreen.java | 54 ++++-- .../armorstand/ArmorStandScreenFactory.java | 11 +- .../armorstand/ArmorStandStyleScreen.java | 3 +- .../armorstand/ArmorStandWidgetsScreen.java | 11 +- .../network/client/data/DataSyncHandler.java | 14 +- .../client/data/NetworkDataSyncHandler.java | 33 +--- .../armorstatues/api/proxy/ClientProxy.java | 4 +- .../decoration/ArmorStandDataProvider.java | 2 +- .../api/world/inventory/ArmorStandHolder.java | 4 - .../api/world/inventory/ArmorStandMenu.java | 15 ++ .../world/inventory/data/ArmorStandPose.java | 6 +- .../inventory/data/ArmorStandScreenType.java | 4 +- .../inventory/data/ArmorStandStyleOption.java | 4 +- .../world/inventory/data/PosePartMutator.java | 16 +- .../client/ArmorStatuesClient.java | 6 + .../ArmorStandAlignmentsScreen.java | 78 ++------ .../fuzs/armorstatues/init/ModRegistry.java | 16 +- .../client/data/CommandDataSyncHandler.java | 49 +++-- .../data/VanillaTweaksDataSyncHandler.java | 8 +- .../fuzs/armorstatues/proxy/ClientProxy.java | 30 ++- .../inventory/data/ArmorStandAlignment.java | 6 +- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../resources/assets/statues/lang/en_us.json | 183 +++++++++--------- .../data/ModLanguageProvider.java | 117 +++++------ gradle.properties | 2 +- 33 files changed, 473 insertions(+), 352 deletions(-) create mode 100644 Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java rename Common/src/main/java/fuzs/armorstatues/{api => }/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java (53%) rename Common/src/main/java/fuzs/armorstatues/{api => }/network/client/data/CommandDataSyncHandler.java (78%) rename Common/src/main/java/fuzs/armorstatues/{api => }/network/client/data/VanillaTweaksDataSyncHandler.java (98%) rename Common/src/main/java/fuzs/armorstatues/{api => }/world/inventory/data/ArmorStandAlignment.java (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e96942..f0c6550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.6-1.19.2] - 2023-07-26 +### Fixed +- Fixed an issue where new rotations set on the rotations screen wouldn't save if the sliders were moved using the arrow keys + ## [v4.0.5-1.19.2] - 2023-07-25 ### Added - Added support for the Vanilla Tweaks Armor Statues data pack diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java b/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java index f67dfb5..e9f44c1 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java @@ -4,6 +4,7 @@ import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.PosePartMutator; +import fuzs.armorstatues.init.ModRegistry; import fuzs.puzzleslib.client.core.ClientModConstructor; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.inventory.InventoryMenu; @@ -17,7 +18,6 @@ public void onClientSetup() { ArmorStandScreenFactory.register(ArmorStandScreenType.STYLE, ArmorStandStyleScreen::new); ArmorStandScreenFactory.register(ArmorStandScreenType.POSES, ArmorStandPosesScreen::new); ArmorStandScreenFactory.register(ArmorStandScreenType.POSITION, ArmorStandPositionScreen::new); - ArmorStandScreenFactory.register(ArmorStandScreenType.ALIGNMENTS, ArmorStandAlignmentsScreen::new); ArmorStandRotationsScreen.registerPosePartMutatorFilter(PosePartMutator.LEFT_ARM, ArmorStand::isShowArms); ArmorStandRotationsScreen.registerPosePartMutatorFilter(PosePartMutator.RIGHT_ARM, ArmorStand::isShowArms); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java index 6732d5b..ec56bd0 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java @@ -35,11 +35,6 @@ public NewTextureSliderButton(int x, int y, int width, int height, int textureX, this.onTooltip = onTooltip; } - @Override - public boolean isDirty() { - return false; - } - @Override public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float partialTick) { Minecraft minecraft = Minecraft.getInstance(); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java index bb20128..e2f499b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java @@ -2,5 +2,11 @@ public interface UnboundedSliderButton { - boolean isDirty(); + default boolean isDirty() { + return false; + } + + default void clearDirty() { + + } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java new file mode 100644 index 0000000..bfd3956 --- /dev/null +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java @@ -0,0 +1,52 @@ +package fuzs.armorstatues.api.client.gui.screens.armorstand; + +import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.client.gui.components.TickButton; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; +import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.phys.Vec3; + +import java.util.EnumSet; + +public abstract class AbstractArmorStandPositionScreen extends ArmorStandWidgetsScreen { + public static final String CENTERED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.centered"; + public static final String CENTERED_DESCRIPTION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.centered.description"; + public static final String CORNERED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.cornered"; + public static final String CORNERED_DESCRIPTION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.cornered.description"; + + public AbstractArmorStandPositionScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + protected class PositionAlignWidget extends AbstractPositionScreenWidget { + + public PositionAlignWidget() { + super(Component.empty()); + } + + @Override + protected boolean shouldTick() { + return true; + } + + @Override + public void init(int posX, int posY) { + super.init(posX, posY); + this.children.add(AbstractArmorStandPositionScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, Component.translatable(CENTERED_TRANSLATION_KEY), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = AbstractArmorStandPositionScreen.this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); + AbstractArmorStandPositionScreen.this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, (button, poseStack, mouseX, mouseY) -> { + AbstractArmorStandPositionScreen.this.renderTooltip(poseStack, AbstractArmorStandPositionScreen.this.font.split(Component.translatable(CENTERED_DESCRIPTION_TRANSLATION_KEY), 175), mouseX, mouseY); + }))); + this.children.add(AbstractArmorStandPositionScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, Component.translatable(CORNERED_TRANSLATION_KEY), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = AbstractArmorStandPositionScreen.this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); + AbstractArmorStandPositionScreen.this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, (button, poseStack, mouseX, mouseY) -> { + AbstractArmorStandPositionScreen.this.renderTooltip(poseStack, AbstractArmorStandPositionScreen.this.font.split(Component.translatable(CORNERED_DESCRIPTION_TRANSLATION_KEY), 175), mouseX, mouseY); + }))); + } + } +} diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index 07d2449..229301f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -37,10 +37,15 @@ public abstract class AbstractArmorStandScreen extends Screen implements MenuAccess, ArmorStandScreen { public static final String VANILLA_TWEAKS_HOMEPAGE = "https://vanillatweaks.net/"; + public static final String CREDITS_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.credits"; + public static final String APPLIED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.applied"; + public static final String ALIGNED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.aligned"; private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/background.png"); private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/widgets.png"); private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/equipment.png"); + @Nullable + static ArmorStandScreenType lastScreenType; static ArmorStandInInventoryRenderer armorStandRenderer = ArmorStandInInventoryRenderer.SIMPLE; protected final int imageWidth = 210; @@ -146,14 +151,14 @@ protected void toggleMenuRendering(boolean disableMenuRendering) { } } - protected void addVanillaTweaksCreditButton() { + protected void addVanillaTweaksCreditsButton() { this.addRenderableWidget(new ImageButton(this.leftPos + 6, this.topPos + 6, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { this.minecraft.setScreen(new ConfirmLinkScreen((bl) -> { if (bl) Util.getPlatform().openUri(VANILLA_TWEAKS_HOMEPAGE); this.minecraft.setScreen(this); }, VANILLA_TWEAKS_HOMEPAGE, true)); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, this.font.split(Component.translatable("armorstatues.screen.vanillaTweaksCredit"), 175), mouseX, mouseY); + this.renderTooltip(poseStack, this.font.split(Component.translatable(CREDITS_TRANSLATION_KEY), 175), mouseX, mouseY); }, CommonComponents.EMPTY)); } @@ -336,6 +341,15 @@ public boolean isPauseScreen() { return false; } + @Override + public void removed() { + for (GuiEventListener child : this.children()) { + if (child instanceof UnboundedSliderButton sliderButton) { + sliderButton.clearDirty(); + } + } + } + @Override public void onClose() { if (this.holder instanceof AbstractContainerMenu) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java index ce4cb32..c5a610f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java @@ -54,7 +54,7 @@ protected void init() { List lines = Lists.newArrayList(component); String source = pose.getSource(); if (!StringUtil.isNullOrEmpty(source)) { - lines.add(Component.translatable("armorstatues.entity.armor_stand.pose.by", source).withStyle(ChatFormatting.GRAY)); + lines.add(Component.translatable(ArmorStandPose.POSE_SOURCE_TRANSLATION_KEY, source).withStyle(ChatFormatting.GRAY)); } this.renderTooltip(poseStack, lines, Optional.empty(), mouseX, mouseY); } @@ -62,7 +62,7 @@ protected void init() { }, CommonComponents.EMPTY)); } this.toggleCycleButtons(0); - this.addVanillaTweaksCreditButton(); + this.addVanillaTweaksCreditsButton(); } private void toggleCycleButtons(int increment) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java index 09ef311..eb1722d 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java @@ -2,6 +2,7 @@ import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; +import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.client.gui.components.NewTextureButton; import fuzs.armorstatues.api.client.gui.components.NewTextureSliderButton; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; @@ -31,7 +32,17 @@ import java.util.function.DoubleSupplier; import java.util.stream.Collectors; -public class ArmorStandPositionScreen extends ArmorStandWidgetsScreen { +public class ArmorStandPositionScreen extends AbstractArmorStandPositionScreen { + public static final String ROTATION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.rotation"; + public static final String POSITION_X_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.x"; + public static final String POSITION_Y_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.y"; + public static final String POSITION_Z_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.z"; + public static final String INCREMENT_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.increment"; + public static final String DECREMENT_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.decrement"; + public static final String PIXELS_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.pixels"; + public static final String BLOCKS_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.blocks"; + public static final String DEGREES_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.degrees"; + public static final String MOVE_BY_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.moveBy"; private static final DecimalFormat BLOCK_INCREMENT_FORMAT = Util.make(new DecimalFormat("#.####"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); }); @@ -59,15 +70,15 @@ public void removed() { protected List buildWidgets(ArmorStand armorStand) { // only move server-side to prevent rubber banding return Lists.newArrayList( - new RotationWidget(Component.translatable("armorstatues.screen.position.rotation"), armorStand::getYRot, this.dataSyncHandler::sendRotation), + new RotationWidget(Component.translatable(ROTATION_TRANSLATION_KEY), armorStand::getYRot, this.dataSyncHandler::sendRotation), new PositionIncrementWidget(), - new PositionComponentWidget("x", armorStand::getX, x -> { + new PositionComponentWidget(POSITION_X_TRANSLATION_KEY, armorStand::getX, x -> { this.dataSyncHandler.sendPosition(x, armorStand.getY(), armorStand.getZ()); }), - new PositionComponentWidget("y", armorStand::getY, y -> { + new PositionComponentWidget(POSITION_Y_TRANSLATION_KEY, armorStand::getY, y -> { this.dataSyncHandler.sendPosition(armorStand.getX(), y, armorStand.getZ()); }), - new PositionComponentWidget("z", armorStand::getZ, z -> { + new PositionComponentWidget(POSITION_Z_TRANSLATION_KEY, armorStand::getZ, z -> { this.dataSyncHandler.sendPosition(armorStand.getX(), armorStand.getY(), z); }) ); @@ -79,11 +90,11 @@ public ArmorStandScreenType getScreenType() { } private static Component getPixelIncrementComponent(double increment) { - return Component.translatable("armorstatues.screen.position.pixels", getBlockPixelIncrement(increment)); + return Component.translatable(PIXELS_TRANSLATION_KEY, getBlockPixelIncrement(increment)); } private static Component getBlockIncrementComponent(double increment) { - return Component.translatable("armorstatues.screen.position.blocks", BLOCK_INCREMENT_FORMAT.format(increment)); + return Component.translatable(BLOCKS_TRANSLATION_KEY, BLOCK_INCREMENT_FORMAT.format(increment)); } private static int getBlockPixelIncrement(double increment) { @@ -117,7 +128,7 @@ protected void setNewValue(double newValue) { } protected Component getTooltipComponent(double mouseValue) { - return Component.translatable("armorstatues.screen.position.degrees", ArmorStandPose.ROTATION_FORMAT.format(toWrappedDegrees(mouseValue))); + return Component.translatable(DEGREES_TRANSLATION_KEY, ArmorStandPose.ROTATION_FORMAT.format(toWrappedDegrees(mouseValue))); } protected static double fromWrappedDegrees(double value) { @@ -164,17 +175,22 @@ protected void applyValue() { @Override public void onRelease(double mouseX, double mouseY) { super.onRelease(mouseX, mouseY); - // we use #onRelease instead of directly applying in #applyValue as the armor stand will otherwise glitch out visually since the server constantly sends outdated values - if (this.isDirty()) { - this.dirty = false; - RotationWidget.this.setNewValue(this.value); - } + this.clearDirty(); } @Override public boolean isDirty() { return this.dirty; } + + @Override + public void clearDirty() { + // we use #onRelease instead of directly applying in #applyValue as the armor stand will otherwise glitch out visually since the server constantly sends outdated values + if (this.isDirty()) { + this.dirty = false; + RotationWidget.this.setNewValue(this.value); + } + } }); sliderButton.snapInterval = this.snapInterval; this.reset = sliderButton::reset; @@ -188,7 +204,7 @@ public boolean isDirty() { private class PositionIncrementWidget extends AbstractPositionScreenWidget { public PositionIncrementWidget() { - super(Component.translatable("armorstatues.screen.position.moveBy")); + super(Component.translatable(MOVE_BY_TRANSLATION_KEY)); } @Override @@ -232,8 +248,8 @@ private class PositionComponentWidget extends AbstractPositionScreenWidget { private EditBox editBox; private int ticks; - public PositionComponentWidget(String translationId, DoubleSupplier currentValue, DoubleConsumer newValue) { - super(Component.translatable("armorstatues.screen.position." + translationId)); + public PositionComponentWidget(String translationKey, DoubleSupplier currentValue, DoubleConsumer newValue) { + super(Component.translatable(translationKey)); this.currentValue = currentValue; this.newValue = newValue; } @@ -261,12 +277,12 @@ public void init(int posX, int posY) { this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 149, posY + 1, 20, 10, 196, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { this.setPositionValue(this.getPositionValue() + currentIncrement); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { - ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.position.increment", getPixelIncrementComponent(currentIncrement)), mouseX, mouseY); + ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable(INCREMENT_TRANSLATION_KEY, getPixelIncrementComponent(currentIncrement)), mouseX, mouseY); }, CommonComponents.EMPTY))); this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 149, posY + 11, 20, 10, 216, 74, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { this.setPositionValue(this.getPositionValue() - currentIncrement); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { - ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.position.decrement", getPixelIncrementComponent(currentIncrement)), mouseX, mouseY); + ArmorStandPositionScreen.this.renderTooltip(poseStack, Component.translatable(DECREMENT_TRANSLATION_KEY, getPixelIncrementComponent(currentIncrement)), mouseX, mouseY); }, CommonComponents.EMPTY))); this.children.add(ArmorStandPositionScreen.this.addRenderableWidget(new ImageButton(posX + 174, posY + 1, 20, 20, 236, 64, getArmorStandWidgetsLocation(), button -> { ArmorStandPositionScreen.this.setActiveWidget(this); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index 3897099..6a2301e 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -2,6 +2,7 @@ import com.google.common.collect.Maps; import com.mojang.blaze3d.vertex.PoseStack; +import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.client.gui.components.BoxedSliderButton; import fuzs.armorstatues.api.client.gui.components.LiveSliderButton; import fuzs.armorstatues.api.client.gui.components.NewTextureTickButton; @@ -30,7 +31,14 @@ import java.util.stream.Collectors; public class ArmorStandRotationsScreen extends AbstractArmorStandScreen { - private static final String TIP_TRANSLATION_KEY = "armorstatues.screen.rotations.tip"; + public static final String TIP_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.tip"; + public static final String UNLIMITED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.unlimited"; + public static final String LIMITED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.limited"; + public static final String RESET_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.reset"; + public static final String RANDOMIZE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.randomize"; + public static final String PASTE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.paste"; + public static final String COPY_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.copy"; + public static final String MIRROR_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.mirror"; private static final Map> POSE_PART_MUTATOR_FILTERS = Maps.newHashMap(); private static boolean clampRotations = true; @@ -57,15 +65,15 @@ protected void init() { this.toggleLockButtons(); this.refreshLiveButtons(); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.unlimited"), mouseX, mouseY); - }, Component.translatable("armorstatues.screen.rotations.unlimited"))); + this.renderTooltip(poseStack, Component.translatable(UNLIMITED_TRANSLATION_KEY), mouseX, mouseY); + }, CommonComponents.EMPTY)); this.lockButtons[1] = this.addRenderableWidget(new ImageButton(this.leftPos + 83, this.topPos + 10, 20, 20, 136, 124, 20, getArmorStandWidgetsLocation(), 256, 256, button -> { clampRotations = false; this.toggleLockButtons(); this.refreshLiveButtons(); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.limited"), mouseX, mouseY); - }, Component.translatable("armorstatues.screen.rotations.limited"))); + this.renderTooltip(poseStack, Component.translatable(LIMITED_TRANSLATION_KEY), mouseX, mouseY); + }, CommonComponents.EMPTY)); Component tipComponent = this.getTipComponent(); if (tipComponent != null) { this.addRenderableWidget(new ImageButton(this.leftPos + 107, this.topPos + 10, 20, 20, 136, 64, 20, getArmorStandWidgetsLocation(), 256, 256, button -> {}, (button, poseStack, mouseX, mouseY) -> { @@ -81,29 +89,29 @@ public void playDownSound(SoundManager handler) { this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 34, 20, 20, 240, 124, getArmorStandWidgetsLocation(), button -> { this.setCurrentPose(ArmorStandPose.EMPTY); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.reset"), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(RESET_TRANSLATION_KEY), mouseX, mouseY); })); this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 34, 20, 20, 192, 124, getArmorStandWidgetsLocation(), button -> { this.setCurrentPose(this.holder.getDataProvider().getRandomPose(true)); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.randomize"), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(RANDOMIZE_TRANSLATION_KEY), mouseX, mouseY); })); AbstractWidget pasteButton = this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 107, this.topPos + 158, 20, 20, 224, 124, getArmorStandWidgetsLocation(), button -> { if (clipboard != null) this.setCurrentPose(clipboard); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.paste"), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(PASTE_TRANSLATION_KEY), mouseX, mouseY); })); pasteButton.active = clipboard != null; this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 158, 20, 20, 208, 124, getArmorStandWidgetsLocation(), button -> { clipboard = this.currentPose; pasteButton.active = true; }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.copy"), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(COPY_TRANSLATION_KEY), mouseX, mouseY); })); this.addRenderableWidget(new NewTextureTickButton(this.leftPos + 83, this.topPos + 134, 44, 20, 179, 0, getArmorStandWidgetsLocation(), button -> { this.setCurrentPose(this.currentPose.mirror()); }, (button, poseStack, mouseX, mouseY) -> { - this.renderTooltip(poseStack, Component.translatable("armorstatues.screen.rotations.mirror"), mouseX, mouseY); + this.renderTooltip(poseStack, Component.translatable(MIRROR_TRANSLATION_KEY), mouseX, mouseY); })); ArmorStand armorStand = this.holder.getArmorStand(); PosePartMutator[] values = this.holder.getDataProvider().getPosePartMutators(); @@ -131,16 +139,21 @@ protected void applyValue() { @Override public void onRelease(double mouseX, double mouseY) { super.onRelease(mouseX, mouseY); - if (this.isDirty()) { - this.dirty = false; - ArmorStandRotationsScreen.this.dataSyncHandler.sendPose(ArmorStandRotationsScreen.this.currentPose); - } + this.clearDirty(); } @Override public boolean isDirty() { return this.dirty; } + + @Override + public void clearDirty() { + if (this.isDirty()) { + this.dirty = false; + ArmorStandRotationsScreen.this.dataSyncHandler.sendPose(ArmorStandRotationsScreen.this.currentPose); + } + } }).active = isPosePartMutatorActive(mutator, armorStand); this.addRenderableWidget(new VerticalSliderButton(this.leftPos + 6 + i % 2 * 183, this.topPos + 7 + i / 2 * 60, () -> mutator.getNormalizedRotationsAtAxis(2, this.currentPose, clampRotations), (button, poseStack, mouseX, mouseY) -> { List lines = Lists.newArrayList(); @@ -160,16 +173,21 @@ protected void applyValue() { @Override public void onRelease(double mouseX, double mouseY) { super.onRelease(mouseX, mouseY); - if (this.isDirty()) { - this.dirty = false; - ArmorStandRotationsScreen.this.dataSyncHandler.sendPose(ArmorStandRotationsScreen.this.currentPose); - } + this.clearDirty(); } @Override public boolean isDirty() { return this.dirty; } + + @Override + public void clearDirty() { + if (this.isDirty()) { + this.dirty = false; + ArmorStandRotationsScreen.this.dataSyncHandler.sendPose(ArmorStandRotationsScreen.this.currentPose); + } + } }).active = isPosePartMutatorActive(mutator, armorStand); this.toggleLockButtons(); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java index bfc0647..5b20719 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java @@ -1,6 +1,7 @@ package fuzs.armorstatues.api.client.gui.screens.armorstand; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.network.client.data.NetworkDataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; @@ -12,6 +13,8 @@ import net.minecraft.world.entity.player.Inventory; import java.util.Map; +import java.util.Optional; +import java.util.Set; @FunctionalInterface public interface ArmorStandScreenFactory & ArmorStandScreen> { @@ -20,7 +23,7 @@ public interface ArmorStandScreenFactory & ArmorStandScreen> T createScreenType(ArmorStandScreenType screenType, ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { - dataSyncHandler.setLastType(screenType); + AbstractArmorStandScreen.lastScreenType = screenType; ArmorStandScreenFactory factory = FACTORIES.get(screenType); if (factory == null) throw new IllegalStateException("No screen factory registered for armor stand screen type %s".formatted(screenType)); T screen = (T) factory.create(holder, inventory, component, dataSyncHandler); @@ -29,11 +32,13 @@ static & ArmorStandScreen> T crea } static & ArmorStandScreen> T createLastScreenType(ArmorStandMenu menu, Inventory inventory, Component component) { - return createLastScreenType(menu, inventory, component, new NetworkDataSyncHandler(menu.getArmorStand())); + return createLastScreenType(menu, inventory, component, new NetworkDataSyncHandler(menu)); } static & ArmorStandScreen> T createLastScreenType(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { - ArmorStandScreenType screenType = dataSyncHandler.getLastType().orElse(dataSyncHandler.getDataProvider().getDefaultScreenType()); + Set screenTypes = Sets.newHashSet(dataSyncHandler.getArmorStandHolder().getDataProvider().getScreenTypes()); + Optional lastScreenType = Optional.ofNullable(AbstractArmorStandScreen.lastScreenType).filter(screenTypes::contains).filter(dataSyncHandler::supportsScreenType); + ArmorStandScreenType screenType = lastScreenType.orElse(dataSyncHandler.getArmorStandHolder().getDataProvider().getDefaultScreenType()); return createScreenType(screenType, holder, inventory, component, dataSyncHandler); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java index e1377eb..7bbc9e9 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java @@ -16,7 +16,6 @@ import java.util.stream.Stream; public class ArmorStandStyleScreen extends ArmorStandTickBoxScreen { - private static final Component STYLE_NAME_COMPONENT = Component.translatable("armorstatues.screen.style.name"); public ArmorStandStyleScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); @@ -55,7 +54,7 @@ protected String getNameDefaultValue() { @Override protected Component getNameComponent() { - return STYLE_NAME_COMPONENT; + return Component.translatable(ArmorStandStyleOption.STYLE_TEXT_BOX_TRANSLATION_KEY); } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java index 6993498..7fbb450 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; import fuzs.armorstatues.api.client.gui.components.NewTextureButton; +import fuzs.armorstatues.api.client.gui.components.TickingButton; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import net.minecraft.client.gui.components.AbstractWidget; @@ -120,7 +121,15 @@ protected AbstractPositionScreenWidget(Component title) { @Override public void tick() { - + if (this.shouldTick()) { + for (AbstractWidget widget : this.children) { + if (widget instanceof TickingButton tickButton) tickButton.tick(); + } + } + } + + protected boolean shouldTick() { + return false; } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java index 006ab5b..e9d4d11 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java @@ -9,9 +9,13 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; -import java.util.Optional; +public interface DataSyncHandler { -public interface DataSyncHandler extends ArmorStandHolder { + ArmorStandHolder getArmorStandHolder(); + + default ArmorStand getArmorStand() { + return this.getArmorStandHolder().getArmorStand(); + } void sendName(String name); @@ -41,9 +45,9 @@ default void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, b ArmorStandScreenType[] tabs(); - Optional getLastType(); - - void setLastType(ArmorStandScreenType lastType); + default boolean supportsScreenType(ArmorStandScreenType screenType) { + return true; + } default void tick() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java index 19952e2..52b6505 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java @@ -2,30 +2,22 @@ import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.network.client.*; +import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.entity.decoration.ArmorStand; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; public class NetworkDataSyncHandler implements DataSyncHandler { - @Nullable - private static ArmorStandScreenType lastType; - - private final ArmorStand armorStand; + private final ArmorStandHolder holder; - public NetworkDataSyncHandler(ArmorStand armorStand) { - this.armorStand = armorStand; + public NetworkDataSyncHandler(ArmorStandHolder holder) { + this.holder = holder; } @Override - public ArmorStand getArmorStand() { - return this.armorStand; + public ArmorStandHolder getArmorStandHolder() { + return this.holder; } @Override @@ -60,17 +52,6 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { @Override public ArmorStandScreenType[] tabs() { - return this.getDataProvider().getScreenTypes(); - } - - @Override - public Optional getLastType() { - List screenTypes = Arrays.asList(this.getDataProvider().getScreenTypes()); - return Optional.ofNullable(lastType).filter(screenTypes::contains); - } - - @Override - public void setLastType(ArmorStandScreenType lastType) { - NetworkDataSyncHandler.lastType = CommandDataSyncHandler.lastType = lastType; + return this.getArmorStandHolder().getDataProvider().getScreenTypes(); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java b/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java index 99047b8..ff48505 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java +++ b/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java @@ -3,14 +3,16 @@ import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Items; public class ClientProxy extends ServerProxy { + public static final String OPEN_SCREEN_TRANSLATION_KEY = Items.ARMOR_STAND.getDescriptionId() + ".description"; @Override public Component getStatueHoverText() { Minecraft minecraft = Minecraft.getInstance(); Component shiftComponent = Component.empty().append(minecraft.options.keyShift.getTranslatedKeyMessage()).withStyle(ChatFormatting.LIGHT_PURPLE); Component useComponent = Component.empty().append(minecraft.options.keyUse.getTranslatedKeyMessage()).withStyle(ChatFormatting.LIGHT_PURPLE); - return Component.translatable("armorstatues.item.armor_stand.description", shiftComponent, useComponent).withStyle(ChatFormatting.GRAY); + return Component.translatable(OPEN_SCREEN_TRANSLATION_KEY, shiftComponent, useComponent).withStyle(ChatFormatting.GRAY); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java b/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java index f21acbc..9efaec3 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java @@ -9,7 +9,7 @@ public interface ArmorStandDataProvider { ArmorStandDataProvider INSTANCE = new ArmorStandDataProvider() {}; default ArmorStandScreenType[] getScreenTypes() { - return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ArmorStandScreenType.ALIGNMENTS, ArmorStandScreenType.EQUIPMENT}; + return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ArmorStandScreenType.EQUIPMENT}; } default ArmorStandScreenType getDefaultScreenType() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java index d586756..5ca0fc1 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java @@ -10,8 +10,4 @@ public interface ArmorStandHolder { default ArmorStandDataProvider getDataProvider() { return this.getArmorStand() instanceof ArmorStandDataProvider dataProvider ? dataProvider : ArmorStandDataProvider.INSTANCE; } - - static ArmorStandHolder simple(ArmorStand armorStand) { - return () -> armorStand; - } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java index 72d6a3f..1e3012c 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java @@ -2,8 +2,11 @@ import com.mojang.datafixers.util.Pair; import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.world.entity.decoration.ArmorStandDataProvider; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import fuzs.armorstatues.core.ModServices; +import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.mixin.accessor.ArmorStandAccessor; import fuzs.armorstatues.mixin.accessor.SimpleContainerAccessor; import net.minecraft.core.NonNullList; @@ -27,6 +30,13 @@ public class ArmorStandMenu extends AbstractContainerMenu implements ArmorStandH public static final ResourceLocation EMPTY_ARMOR_SLOT_SWORD = ArmorStatuesApi.id("item/empty_armor_slot_sword"); static final ResourceLocation[] TEXTURE_EMPTY_SLOTS = new ResourceLocation[]{InventoryMenu.EMPTY_ARMOR_SLOT_BOOTS, InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET, InventoryMenu.EMPTY_ARMOR_SLOT_SHIELD, EMPTY_ARMOR_SLOT_SWORD}; public static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET, EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND}; + public static final ArmorStandDataProvider DATA_PROVIDER = new ArmorStandDataProvider() { + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS, ArmorStandScreenType.EQUIPMENT}; + } + }; private final Container armorStandInventory; private final ArmorStand armorStand; @@ -230,4 +240,9 @@ public boolean stillValid(Player player) { public ArmorStand getArmorStand() { return this.armorStand; } + + @Override + public ArmorStandDataProvider getDataProvider() { + return DATA_PROVIDER; + } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index 4a8d623..a5cf492 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.api.world.inventory.data; +import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.mixin.accessor.ArmorStandAccessor; import net.minecraft.Util; import net.minecraft.core.Rotations; @@ -12,9 +13,10 @@ import java.util.Locale; public class ArmorStandPose { + public static final String POSE_SOURCE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.pose.by"; private static final String MINECRAFT_SOURCE = "Minecraft"; private static final String VANILLA_TWEAKS_SOURCE = "Vanilla Tweaks"; - public static final Rotations ZERO_ROTATIONS = new Rotations(0.0F, 0.0F, 0.0F); + private static final Rotations ZERO_ROTATIONS = new Rotations(0.0F, 0.0F, 0.0F); public static final double DEGREES_SNAP_INTERVAL = 0.125; public static final DecimalFormat ROTATION_FORMAT = Util.make(new DecimalFormat("#.##"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); @@ -93,7 +95,7 @@ public String toString() { } public String getTranslationKey() { - return this.name != null ? "armorstatues.entity.armor_stand.pose." + this.name : null; + return this.name != null ? ArmorStatuesApi.MOD_ID + ".screen.pose." + this.name : null; } @Nullable diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java index 41b8990..ad74f7a 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.api.world.inventory.data; +import fuzs.armorstatues.api.ArmorStatuesApi; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -11,7 +12,6 @@ public class ArmorStandScreenType { public static final ArmorStandScreenType STYLE = new ArmorStandScreenType("style", new ItemStack(Items.PAINTING)); public static final ArmorStandScreenType POSES = new ArmorStandScreenType("poses", new ItemStack(Items.SPYGLASS)); public static final ArmorStandScreenType POSITION = new ArmorStandScreenType("position", new ItemStack(Items.GRASS_BLOCK)); - public static final ArmorStandScreenType ALIGNMENTS = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); private final String name; private final ItemStack icon; @@ -33,7 +33,7 @@ public String toString() { } public String getTranslationKey() { - return "armorstatues.screen.type." + this.name; + return ArmorStatuesApi.MOD_ID + ".screen.type." + this.name; } public ItemStack getIcon() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java index b4fcb80..fb357f1 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java @@ -2,6 +2,7 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import fuzs.armorstatues.api.ArmorStatuesApi; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.decoration.ArmorStand; @@ -10,13 +11,14 @@ import java.util.Objects; public interface ArmorStandStyleOption { + String STYLE_TEXT_BOX_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.style.name"; int ARMOR_STAND_ALL_SLOTS_DISABLED = 4144959; BiMap OPTIONS_REGISTRY = HashBiMap.create(); String getName(); default String getTranslationKey() { - return "armorstatues.screen.style." + this.getName(); + return ArmorStatuesApi.MOD_ID + ".screen.style." + this.getName(); } default String getDescriptionKey() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java index fc62c8b..42e2468 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.api.world.inventory.data; +import fuzs.armorstatues.api.ArmorStatuesApi; import net.minecraft.core.Direction; import net.minecraft.core.Rotations; import net.minecraft.network.chat.Component; @@ -17,6 +18,9 @@ public final class PosePartMutator { public static final PosePartMutator LEFT_ARM = new PosePartMutator("leftArm", ArmorStandPose::getLeftArmPose, ArmorStandPose::withLeftArmPose, PosePartAxisRange.range(-180.0, 0.0), PosePartAxisRange.range(-45.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); public static final PosePartMutator RIGHT_LEG = new PosePartMutator("rightLeg", ArmorStandPose::getRightLegPose, ArmorStandPose::withRightLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(-90.0, 0.0), PosePartAxisRange.range(-120.0, 120.0)); public static final PosePartMutator LEFT_LEG = new PosePartMutator("leftLeg", ArmorStandPose::getLeftLegPose, ArmorStandPose::withLeftLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(0.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); + public static final String AXIS_X_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.x"; + public static final String AXIS_Y_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.y"; + public static final String AXIS_Z_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.z"; private final String name; private final Function getRotations; @@ -52,12 +56,20 @@ public String toString() { } public String getTranslationKey() { - return "armorstatues.screen.rotations.pose." + this.name; + return ArmorStatuesApi.MOD_ID + ".screen.rotations.pose." + this.name; } public Component getAxisComponent(ArmorStandPose pose, int index) { double value = ArmorStandPose.snapValue(this.getRotationsAtAxis(index, pose), ArmorStandPose.DEGREES_SNAP_INTERVAL); - return Component.translatable("armorstatues.screen.rotations." + this.getAxisAt(index), ArmorStandPose.ROTATION_FORMAT.format(value)); + return Component.translatable(this.getAxisTranslationKey(this.getAxisAt(index)), ArmorStandPose.ROTATION_FORMAT.format(value)); + } + + private String getAxisTranslationKey(Direction.Axis axis) { + return switch (axis) { + case X -> AXIS_X_TRANSLATION_KEY; + case Y -> AXIS_Y_TRANSLATION_KEY; + case Z -> AXIS_Z_TRANSLATION_KEY; + }; } public double getRotationsAtAxis(int index, ArmorStandPose pose) { diff --git a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index 12a32a5..1f07555 100644 --- a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.client; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreenFactory; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.init.ModRegistry; @@ -9,6 +10,11 @@ public class ArmorStatuesClient implements ClientModConstructor { + @Override + public void onClientSetup() { + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS, ArmorStandAlignmentsScreen::new); + } + @Override public void onRegisterMenuScreens(MenuScreensContext context) { // compiler doesn't like method reference :( diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java similarity index 53% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java rename to Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index 773f382..76f285b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -1,16 +1,15 @@ -package fuzs.armorstatues.api.client.gui.screens.armorstand; +package fuzs.armorstatues.client.gui.screens.armorstand; import com.google.common.collect.Lists; import fuzs.armorstatues.api.client.gui.components.TickButton; -import fuzs.armorstatues.api.client.gui.components.TickingButton; +import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandPositionScreen; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; +import fuzs.armorstatues.world.inventory.data.ArmorStandAlignment; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; -import net.minecraft.client.gui.components.AbstractWidget; +import fuzs.armorstatues.init.ModRegistry; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; @@ -20,10 +19,9 @@ import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; -import java.util.EnumSet; import java.util.List; -public class ArmorStandAlignmentsScreen extends ArmorStandWidgetsScreen { +public class ArmorStandAlignmentsScreen extends AbstractArmorStandPositionScreen { public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); @@ -41,78 +39,44 @@ protected List buildWidgets(ArmorStand armorStand) { @Override protected void init() { super.init(); - this.addVanillaTweaksCreditButton(); + this.addVanillaTweaksCreditsButton(); } @Override public ArmorStandScreenType getScreenType() { - return ArmorStandScreenType.ALIGNMENTS; + return ModRegistry.ALIGNMENTS; } - private abstract class BlockPositionWidget extends AbstractPositionScreenWidget { + private class AlignmentWidget extends AbstractPositionScreenWidget { + private final ArmorStandAlignment alignment; - public BlockPositionWidget() { + public AlignmentWidget(ArmorStandAlignment alignment) { super(Component.empty()); + this.alignment = alignment; } @Override - public void tick() { - super.tick(); - for (AbstractWidget widget : this.children) { - if (widget instanceof TickingButton tickButton) tickButton.tick(); - } - } - - protected Vec3 getCurrentPosition() { - return ArmorStandAlignmentsScreen.this.holder.getArmorStand().position(); - } - - protected void setNewPosition(Vec3 vec3, boolean finalize) { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPosition(vec3.x(), vec3.y(), vec3.z(), finalize); - } - } - - private class PositionAlignWidget extends BlockPositionWidget { - - @Override - public void init(int posX, int posY) { - super.init(posX, posY); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, Component.translatable("armorstatues.screen.alignments.centered"), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { - this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5), true); - }, (button, poseStack, mouseX, mouseY) -> { - ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, ArmorStandAlignmentsScreen.this.font.split(Component.translatable("armorstatues.screen.alignments.centered.description"), 175), mouseX, mouseY); - }))); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, Component.translatable("armorstatues.screen.alignments.cornered"), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { - this.setNewPosition(this.getCurrentPosition().align(EnumSet.allOf(Direction.Axis.class)), true); - }, (button, poseStack, mouseX, mouseY) -> { - ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, ArmorStandAlignmentsScreen.this.font.split(Component.translatable("armorstatues.screen.alignments.cornered.description"), 175), mouseX, mouseY); - }))); - } - } - - private class AlignmentWidget extends BlockPositionWidget { - private final ArmorStandAlignment alignment; - - public AlignmentWidget(ArmorStandAlignment alignment) { - this.alignment = alignment; + protected boolean shouldTick() { + return true; } @Override public void init(int posX, int posY) { super.init(posX, posY); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable("armorstatues.screen.alignments.aligned"), button -> { + this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { ArmorStand armorStand = ArmorStandAlignmentsScreen.this.holder.getArmorStand(); + DataSyncHandler dataSyncHandler = ArmorStandAlignmentsScreen.this.dataSyncHandler; if (!armorStand.isInvisible()) { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); + dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); } if (!armorStand.isNoGravity()) { - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); + dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); } - ArmorStandAlignmentsScreen.this.dataSyncHandler.sendPose(this.alignment.getPose(), false); + dataSyncHandler.sendPose(this.alignment.getPose(), false); Vec3 alignmentOffset = this.alignment.getAlignmentOffset(armorStand.isSmall()); - Vec3 localPosition = getLocalPosition(armorStand, alignmentOffset); - this.setNewPosition(localPosition, false); - ArmorStandAlignmentsScreen.this.dataSyncHandler.finalizeCurrentOperation(); + Vec3 newPosition = getLocalPosition(armorStand, alignmentOffset); + dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z(), false); + dataSyncHandler.finalizeCurrentOperation(); }, (button, poseStack, mouseX, mouseY) -> { Component component = Component.translatable(this.alignment.getDescriptionsKey()); List lines = ArmorStandAlignmentsScreen.this.font.split(component, 175); diff --git a/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index ddb7afa..7a1907c 100644 --- a/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -1,23 +1,23 @@ package fuzs.armorstatues.init; import fuzs.armorstatues.ArmorStatues; -import fuzs.armorstatues.api.ArmorStatuesApi; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.puzzleslib.core.CoreServices; import fuzs.puzzleslib.init.RegistryManager; import fuzs.puzzleslib.init.RegistryReference; -import fuzs.puzzleslib.init.builder.ExtendedModMenuSupplier; import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; public class ModRegistry { - private static final RegistryManager REGISTRY = CoreServices.FACTORIES.registration(ArmorStatues.MOD_ID); - public static final RegistryReference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuTypeSupplier("armor_stand", () -> getArmorStandMenuTypeSupplier()); + static final RegistryManager REGISTRY = CoreServices.FACTORIES.registration(ArmorStatues.MOD_ID); + public static final RegistryReference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuTypeSupplier("armor_stand", () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data); + }); + public static final ArmorStandScreenType ALIGNMENTS = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); public static void touch() { } - - private static ExtendedModMenuSupplier getArmorStandMenuTypeSupplier() { - return (containerId, inventory, data) -> ArmorStandMenu.create(ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data); - } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java similarity index 78% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java rename to Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 08fb5f4..3b7d172 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -1,5 +1,8 @@ -package fuzs.armorstatues.api.network.client.data; +package fuzs.armorstatues.network.client.data; +import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; +import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; @@ -13,36 +16,36 @@ import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayDeque; +import java.util.Queue; import java.util.function.BiPredicate; import java.util.function.Predicate; import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { - private static final Component NO_PERMISSION_COMPONENT = Component.translatable("armorstatues.screen.failure.noPermission"); - private static final Component NOT_FINISHED_COMPONENT = Component.translatable("armorstatues.screen.failure.notFinished"); - private static final Component FINISHED_COMPONENT = Component.translatable("armorstatues.screen.finished"); + public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.failure"; private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); - @Nullable - static ArmorStandScreenType lastType; @Nullable private static ArmorStand queueArmorStand; private static int itemDequeuedTicks; - private final ArmorStand armorStand; + private final ArmorStandHolder holder; protected final LocalPlayer player; protected ArmorStandPose lastSyncedPose; - public CommandDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { - this.armorStand = armorStand; - this.lastSyncedPose = ArmorStandPose.fromEntity(armorStand); + public CommandDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + this.holder = holder; + this.lastSyncedPose = ArmorStandPose.fromEntity(this.holder.getArmorStand()); this.player = player; } @Override - public ArmorStand getArmorStand() { - return this.armorStand; + public ArmorStandHolder getArmorStandHolder() { + return this.holder; } @Override @@ -133,18 +136,12 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, bo @Override public ArmorStandScreenType[] tabs() { - return Stream.of(this.getDataProvider().getScreenTypes()).filter(Predicate.not(ArmorStandScreenType::requiresServer)).toArray(ArmorStandScreenType[]::new); - } - - @Override - public Optional getLastType() { - List screenTypes = Arrays.asList(this.getDataProvider().getScreenTypes()); - return Optional.ofNullable(lastType).filter(screenTypes::contains).filter(Predicate.not(ArmorStandScreenType::requiresServer)); + return Stream.of(this.getArmorStandHolder().getDataProvider().getScreenTypes()).filter(Predicate.not(ArmorStandScreenType::requiresServer)).toArray(ArmorStandScreenType[]::new); } @Override - public void setLastType(ArmorStandScreenType lastType) { - CommandDataSyncHandler.lastType = lastType; + public boolean supportsScreenType(ArmorStandScreenType screenType) { + return !screenType.requiresServer(); } @Override @@ -158,7 +155,7 @@ public void tick() { } itemDequeuedTicks = this.getDequeueDelayTicks(); } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { - this.sendDisplayMessage(FINISHED_COMPONENT, false); + this.sendDisplayMessage(Component.translatable(FINISHED_TRANSLATION_KEY), false); } } @@ -173,7 +170,7 @@ public boolean shouldContinueTicking() { private boolean testPermissionLevel() { if (!this.player.hasPermissions(2)) { - this.sendFailureMessage(NO_PERMISSION_COMPONENT); + this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); return false; } return true; @@ -183,7 +180,7 @@ protected boolean enqueueClientCommand(String clientCommand) { if (CLIENT_COMMAND_QUEUE.isEmpty()) { queueArmorStand = null; } else if (queueArmorStand != null) { - this.sendFailureMessage(NOT_FINISHED_COMPONENT); + this.sendFailureMessage(Component.translatable(NOT_FINISHED_TRANSLATION_KEY)); return false; } CLIENT_COMMAND_QUEUE.offer(clientCommand); @@ -198,7 +195,7 @@ public void finalizeCurrentOperation() { } protected void sendFailureMessage(Component component) { - this.sendDisplayMessage(Component.translatable("armorstatues.screen.failure", component), true); + this.sendDisplayMessage(Component.translatable(FAILURE_TRANSLATION_KEY, component), true); } protected void sendDisplayMessage(Component component, boolean failure) { diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java similarity index 98% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java rename to Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java index cc39c19..412b0b0 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -1,12 +1,12 @@ -package fuzs.armorstatues.api.network.client.data; +package fuzs.armorstatues.network.client.data; import com.google.common.collect.ImmutableSortedMap; +import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Rotations; -import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -100,8 +100,8 @@ public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { private static final NavigableMap NUDGE_POSITIONS_Z_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_POSITIVE); private static final NavigableMap ADJUST_ROTATION_ANGLE_STEPS = ImmutableSortedMap.of(1.0F, ADJUST_ROTATION_ANGLE_STEP_1, 5.0F, ADJUST_ROTATION_ANGLE_STEP_5, 15.0F, ADJUST_ROTATION_ANGLE_STEP_15, 45.0F, ADJUST_ROTATION_ANGLE_STEP_45); - public VanillaTweaksDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { - super(armorStand, player); + public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + super(holder, player); } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java index d266686..cf657f1 100644 --- a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java +++ b/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -2,9 +2,11 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreenFactory; -import fuzs.armorstatues.api.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.api.world.entity.decoration.ArmorStandDataProvider; +import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; -import fuzs.armorstatues.api.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.config.ClientConfig; import net.minecraft.client.Minecraft; @@ -17,16 +19,28 @@ public class ClientProxy extends ServerProxy { @Override public void openArmorStandScreen(ArmorStand armorStand, Player player) { - ArmorStandHolder holder = ArmorStandHolder.simple(armorStand); - Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(armorStand, (LocalPlayer) player)); - Minecraft.getInstance().setScreen(screen); + ArmorStandHolder holder = new ArmorStandHolder() { + + @Override + public ArmorStand getArmorStand() { + return armorStand; + } + + @Override + public ArmorStandDataProvider getDataProvider() { + return ArmorStandMenu.DATA_PROVIDER; + } + }; + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(holder, (LocalPlayer) player)); + Minecraft minecraft = Minecraft.getInstance(); + minecraft.setScreen(screen); } - private static DataSyncHandler createDataSyncHandler(ArmorStand armorStand, LocalPlayer player) { + private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { if (!player.hasPermissions(2) && ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { - return new VanillaTweaksDataSyncHandler(armorStand, player); + return new VanillaTweaksDataSyncHandler(holder, player); } else { - return new CommandDataSyncHandler(armorStand, player); + return new CommandDataSyncHandler(holder, player); } } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java b/Common/src/main/java/fuzs/armorstatues/world/inventory/data/ArmorStandAlignment.java similarity index 87% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java rename to Common/src/main/java/fuzs/armorstatues/world/inventory/data/ArmorStandAlignment.java index c604a24..003799b 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java +++ b/Common/src/main/java/fuzs/armorstatues/world/inventory/data/ArmorStandAlignment.java @@ -1,5 +1,7 @@ -package fuzs.armorstatues.api.world.inventory.data; +package fuzs.armorstatues.world.inventory.data; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import net.minecraft.core.Rotations; import net.minecraft.world.phys.Vec3; @@ -32,7 +34,7 @@ public String toString() { } public String getTranslationKey() { - return "armorstatues.screen.alignments." + this.name; + return ArmorStatues.MOD_ID + ".screen.alignments." + this.name; } public String getDescriptionsKey() { diff --git a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 5ad84b0..b35b798 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-25T14:46:14.302258 Languages: en_us -283172ead1153cedb61b98be0359d47309080a21 assets/statues/lang/en_us.json +// 1.19.2 2023-07-26T11:03:36.825853 Languages: en_us +ff1dac038e1aaf5530e4974008a28814586b5a12 assets/statues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/statues/lang/en_us.json b/Forge/src/generated/resources/assets/statues/lang/en_us.json index 3ea7d30..19b24ff 100644 --- a/Forge/src/generated/resources/assets/statues/lang/en_us.json +++ b/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -1,102 +1,101 @@ { - "armorstatues.entity.armor_stand.pose.arabesque": "Arabesque", - "armorstatues.entity.armor_stand.pose.athena": "Athena", - "armorstatues.entity.armor_stand.pose.blocking": "Blocking", - "armorstatues.entity.armor_stand.pose.brandish": "Brandish", - "armorstatues.entity.armor_stand.pose.by": "By %s", - "armorstatues.entity.armor_stand.pose.cancan": "Cancan", - "armorstatues.entity.armor_stand.pose.confident": "Confident", - "armorstatues.entity.armor_stand.pose.confused": "Confused", - "armorstatues.entity.armor_stand.pose.cupid": "Cupid", - "armorstatues.entity.armor_stand.pose.death": "Death", - "armorstatues.entity.armor_stand.pose.default": "Default", - "armorstatues.entity.armor_stand.pose.entertain": "Entertain", - "armorstatues.entity.armor_stand.pose.facepalm": "Facepalm", - "armorstatues.entity.armor_stand.pose.formal": "Formal", - "armorstatues.entity.armor_stand.pose.hero": "Hero", - "armorstatues.entity.armor_stand.pose.honor": "Honor", - "armorstatues.entity.armor_stand.pose.joyous": "Joyous", - "armorstatues.entity.armor_stand.pose.lazing": "Lazing", - "armorstatues.entity.armor_stand.pose.lungeing": "Lungeing", - "armorstatues.entity.armor_stand.pose.pointing": "Pointing", - "armorstatues.entity.armor_stand.pose.riposte": "Riposte", - "armorstatues.entity.armor_stand.pose.running": "Running", - "armorstatues.entity.armor_stand.pose.sad": "Sad", - "armorstatues.entity.armor_stand.pose.salute": "Salute", - "armorstatues.entity.armor_stand.pose.sitting": "Sitting", - "armorstatues.entity.armor_stand.pose.solemn": "Solemn", - "armorstatues.entity.armor_stand.pose.stargazing": "Stargazing", - "armorstatues.entity.armor_stand.pose.walking": "Walking", - "armorstatues.entity.armor_stand.pose.winning": "Winning", - "armorstatues.entity.armor_stand.pose.zombie": "Zombie", - "armorstatues.item.armor_stand.description": "Use %s + %s with an empty hand to open configuration screen.", - "armorstatues.screen.alignments.aligned": "Aligned!", "armorstatues.screen.alignments.block": "Align Block on Surface", "armorstatues.screen.alignments.block.description": "Align an armor stand placed on a surface so that a block held by it appears on the surface.", - "armorstatues.screen.alignments.centered": "Align Centered", - "armorstatues.screen.alignments.centered.description": "Align an armor stand in the center of the block position it is placed on.", - "armorstatues.screen.alignments.cornered": "Align Cornered", - "armorstatues.screen.alignments.cornered.description": "Align an armor stand at the corner of the block position it is placed on.", "armorstatues.screen.alignments.itemFlat": "Align Item Flat On Surface", "armorstatues.screen.alignments.itemFlat.description": "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface.", "armorstatues.screen.alignments.itemFloating": "Align Item On Surface", "armorstatues.screen.alignments.itemFloating.description": "Align an armor stand placed on a surface so that an item held by it appears upright on the surface.", "armorstatues.screen.alignments.tool": "Align Tool Flat On Surface", "armorstatues.screen.alignments.tool.description": "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface.", - "armorstatues.screen.failure": "Unable to modify armor stand data: %s", - "armorstatues.screen.failure.noPermission": "No Permission", - "armorstatues.screen.failure.notFinished": "Queue Not Empty", - "armorstatues.screen.finished": "Finished sending queued armor stand data", - "armorstatues.screen.pose.randomize": "Randomize", - "armorstatues.screen.pose.randomized": "Applied!", - "armorstatues.screen.position.blocks": "%s Block(s)", - "armorstatues.screen.position.decrement": "Decrement by %s", - "armorstatues.screen.position.degrees": "%s°", - "armorstatues.screen.position.increment": "Increment by %s", - "armorstatues.screen.position.moveBy": "Move By:", - "armorstatues.screen.position.pixels": "%s Pixel(s)", - "armorstatues.screen.position.rotation": "Rotation:", - "armorstatues.screen.position.x": "X-Position:", - "armorstatues.screen.position.y": "Y-Position:", - "armorstatues.screen.position.z": "Z-Position:", - "armorstatues.screen.rotations.copy": "Copy", - "armorstatues.screen.rotations.limited": "Limited Rotations", - "armorstatues.screen.rotations.mirror": "Mirror", - "armorstatues.screen.rotations.paste": "Paste", - "armorstatues.screen.rotations.pose.body": "Body", - "armorstatues.screen.rotations.pose.head": "Head", - "armorstatues.screen.rotations.pose.leftArm": "Left Arm", - "armorstatues.screen.rotations.pose.leftLeg": "Left Leg", - "armorstatues.screen.rotations.pose.rightArm": "Right Arm", - "armorstatues.screen.rotations.pose.rightLeg": "Right Leg", - "armorstatues.screen.rotations.randomize": "Randomize", - "armorstatues.screen.rotations.reset": "Reset", - "armorstatues.screen.rotations.tip1": "Hold the Shift or Alt key to lock sliders to a single axis!", - "armorstatues.screen.rotations.tip2": "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking.", - "armorstatues.screen.rotations.unlimited": "Unlimited Rotations", - "armorstatues.screen.rotations.x": "X: %s", - "armorstatues.screen.rotations.y": "Y: %s", - "armorstatues.screen.rotations.z": "Z: %s", - "armorstatues.screen.style.invisible": "Invisible", - "armorstatues.screen.style.invisible.description": "Makes the statue itself invisible, but still shows all equipped items.", - "armorstatues.screen.style.name": "Set a name to display above the entity if enabled.", - "armorstatues.screen.style.noBasePlate": "No Base Plate", - "armorstatues.screen.style.noBasePlate.description": "Hide the stone base plate at the statue's feet.", - "armorstatues.screen.style.noGravity": "No Gravity", - "armorstatues.screen.style.noGravity.description": "Prevents the statue from falling down, so it may float freely.", - "armorstatues.screen.style.sealed": "Sealed", - "armorstatues.screen.style.sealed.description": "The statue can no longer be broken, equipment cannot be changed. Disallows opening this menu in survival mode.", - "armorstatues.screen.style.showArms": "Show Arms", - "armorstatues.screen.style.showArms.description": "Shows the statue's arms, so it may hold items in both hands.", - "armorstatues.screen.style.showName": "Show Name", - "armorstatues.screen.style.showName.description": "Render the statue's name tag above it's head.", - "armorstatues.screen.style.small": "Small", - "armorstatues.screen.style.small.description": "Makes the statue half it's size like a baby mob.", - "armorstatues.screen.type.alignments": "Alignments", - "armorstatues.screen.type.equipment": "Equipment", - "armorstatues.screen.type.poses": "Poses", - "armorstatues.screen.type.position": "Position", - "armorstatues.screen.type.rotations": "Rotations", - "armorstatues.screen.type.style": "Style", - "armorstatues.screen.vanillaTweaksCredit": "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!" + "item.minecraft.armor_stand.description": "Use [%s] + [%s] with an empty hand to open configuration screen.", + "statues.dataSync.failure": "Unable to modify armor stand data: %s", + "statues.dataSync.failure.noPermission": "No Permission", + "statues.dataSync.failure.notFinished": "Queue Not Empty", + "statues.dataSync.finished": "Finished sending queued armor stand data", + "statues.screen.aligned": "Aligned!", + "statues.screen.applied": "Applied!", + "statues.screen.centered": "Align Centered", + "statues.screen.centered.description": "Align an armor stand in the center of the block position it is placed on.", + "statues.screen.cornered": "Align Cornered", + "statues.screen.cornered.description": "Align an armor stand at the corner of the block position it is placed on.", + "statues.screen.credits": "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!", + "statues.screen.pose.arabesque": "Arabesque", + "statues.screen.pose.athena": "Athena", + "statues.screen.pose.blocking": "Blocking", + "statues.screen.pose.brandish": "Brandish", + "statues.screen.pose.by": "By %s", + "statues.screen.pose.cancan": "Cancan", + "statues.screen.pose.confident": "Confident", + "statues.screen.pose.confused": "Confused", + "statues.screen.pose.cupid": "Cupid", + "statues.screen.pose.death": "Death", + "statues.screen.pose.default": "Default", + "statues.screen.pose.entertain": "Entertain", + "statues.screen.pose.facepalm": "Facepalm", + "statues.screen.pose.formal": "Formal", + "statues.screen.pose.hero": "Hero", + "statues.screen.pose.honor": "Honor", + "statues.screen.pose.joyous": "Joyous", + "statues.screen.pose.lazing": "Lazing", + "statues.screen.pose.lungeing": "Lungeing", + "statues.screen.pose.pointing": "Pointing", + "statues.screen.pose.riposte": "Riposte", + "statues.screen.pose.running": "Running", + "statues.screen.pose.sad": "Sad", + "statues.screen.pose.salute": "Salute", + "statues.screen.pose.sitting": "Sitting", + "statues.screen.pose.solemn": "Solemn", + "statues.screen.pose.stargazing": "Stargazing", + "statues.screen.pose.walking": "Walking", + "statues.screen.pose.winning": "Winning", + "statues.screen.pose.zombie": "Zombie", + "statues.screen.position.blocks": "%s Block(s)", + "statues.screen.position.decrement": "Decrement by %s", + "statues.screen.position.degrees": "%s°", + "statues.screen.position.increment": "Increment by %s", + "statues.screen.position.moveBy": "Move By:", + "statues.screen.position.pixels": "%s Pixel(s)", + "statues.screen.position.rotation": "Rotation:", + "statues.screen.position.x": "X-Position:", + "statues.screen.position.y": "Y-Position:", + "statues.screen.position.z": "Z-Position:", + "statues.screen.rotations.copy": "Copy", + "statues.screen.rotations.limited": "Limited Rotations", + "statues.screen.rotations.mirror": "Mirror", + "statues.screen.rotations.paste": "Paste", + "statues.screen.rotations.pose.body": "Body", + "statues.screen.rotations.pose.head": "Head", + "statues.screen.rotations.pose.leftArm": "Left Arm", + "statues.screen.rotations.pose.leftLeg": "Left Leg", + "statues.screen.rotations.pose.rightArm": "Right Arm", + "statues.screen.rotations.pose.rightLeg": "Right Leg", + "statues.screen.rotations.randomize": "Randomize", + "statues.screen.rotations.reset": "Reset", + "statues.screen.rotations.tip1": "Hold the Shift or Alt key to lock sliders to a single axis!", + "statues.screen.rotations.tip2": "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking.", + "statues.screen.rotations.unlimited": "Unlimited Rotations", + "statues.screen.rotations.x": "X: %s", + "statues.screen.rotations.y": "Y: %s", + "statues.screen.rotations.z": "Z: %s", + "statues.screen.style.invisible": "Invisible", + "statues.screen.style.invisible.description": "Makes the statue itself invisible, but still shows all equipped items.", + "statues.screen.style.name": "Set a name to display above the entity if enabled.", + "statues.screen.style.noBasePlate": "No Base Plate", + "statues.screen.style.noBasePlate.description": "Hide the stone base plate at the statue's feet.", + "statues.screen.style.noGravity": "No Gravity", + "statues.screen.style.noGravity.description": "Prevents the statue from falling down, so it may float freely.", + "statues.screen.style.sealed": "Sealed", + "statues.screen.style.sealed.description": "The statue can no longer be broken, equipment cannot be changed. Disallows opening this menu in survival mode.", + "statues.screen.style.showArms": "Show Arms", + "statues.screen.style.showArms.description": "Shows the statue's arms, so it may hold items in both hands.", + "statues.screen.style.showName": "Show Name", + "statues.screen.style.showName.description": "Render the statue's name tag above it's head.", + "statues.screen.style.small": "Small", + "statues.screen.style.small.description": "Makes the statue half it's size like a baby mob.", + "statues.screen.type.alignments": "Alignments", + "statues.screen.type.equipment": "Equipment", + "statues.screen.type.poses": "Poses", + "statues.screen.type.position": "Position", + "statues.screen.type.rotations": "Rotations", + "statues.screen.type.style": "Style" } \ No newline at end of file diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index a57684d..3fcc99b 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -1,8 +1,14 @@ package fuzs.armorstatues.data; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; +import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandPositionScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandPositionScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandRotationsScreen; +import fuzs.armorstatues.api.proxy.ClientProxy; +import fuzs.armorstatues.api.world.inventory.data.*; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.world.inventory.data.ArmorStandAlignment; import net.minecraft.data.DataGenerator; import net.minecraftforge.common.data.LanguageProvider; @@ -14,9 +20,19 @@ public ModLanguageProvider(DataGenerator gen, String modId) { @Override protected void addTranslations() { - this.add("armorstatues.item.armor_stand.description", "Use %s + %s with an empty hand to open configuration screen."); - this.add("armorstatues.screen.style.name", "Set a name to display above the entity if enabled."); - this.add("armorstatues.entity.armor_stand.pose.by", "By %s"); + // Armor Statues + this.add(ModRegistry.ALIGNMENTS.getTranslationKey(), "Alignments"); + this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block on Surface"); + this.add(ArmorStandAlignment.BLOCK.getDescriptionsKey(), "Align an armor stand placed on a surface so that a block held by it appears on the surface."); + this.add(ArmorStandAlignment.FLOATING_ITEM.getTranslationKey(), "Align Item On Surface"); + this.add(ArmorStandAlignment.FLOATING_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that an item held by it appears upright on the surface."); + this.add(ArmorStandAlignment.FLAT_ITEM.getTranslationKey(), "Align Item Flat On Surface"); + this.add(ArmorStandAlignment.FLAT_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface."); + this.add(ArmorStandAlignment.TOOL.getTranslationKey(), "Align Tool Flat On Surface"); + this.add(ArmorStandAlignment.TOOL.getDescriptionsKey(), "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface."); + // Statues Api + this.add(ClientProxy.OPEN_SCREEN_TRANSLATION_KEY, "Use [%s] + [%s] with an empty hand to open configuration screen."); + this.add(ArmorStandPose.POSE_SOURCE_TRANSLATION_KEY, "By %s"); this.add(ArmorStandPose.ATHENA.getTranslationKey(), "Athena"); this.add(ArmorStandPose.BRANDISH.getTranslationKey(), "Brandish"); this.add(ArmorStandPose.CANCAN.getTranslationKey(), "Cancan"); @@ -51,7 +67,7 @@ protected void addTranslations() { this.add(ArmorStandScreenType.STYLE.getTranslationKey(), "Style"); this.add(ArmorStandScreenType.POSES.getTranslationKey(), "Poses"); this.add(ArmorStandScreenType.POSITION.getTranslationKey(), "Position"); - this.add(ArmorStandScreenType.ALIGNMENTS.getTranslationKey(), "Alignments"); + this.add(ArmorStandStyleOption.STYLE_TEXT_BOX_TRANSLATION_KEY, "Set a name to display above the entity if enabled."); this.add(ArmorStandStyleOptions.SHOW_ARMS.getTranslationKey(), "Show Arms"); this.add(ArmorStandStyleOptions.SHOW_ARMS.getDescriptionKey(), "Shows the statue's arms, so it may hold items in both hands."); this.add(ArmorStandStyleOptions.SMALL.getTranslationKey(), "Small"); @@ -66,53 +82,44 @@ protected void addTranslations() { this.add(ArmorStandStyleOptions.NO_GRAVITY.getDescriptionKey(), "Prevents the statue from falling down, so it may float freely."); this.add(ArmorStandStyleOptions.SEALED.getTranslationKey(), "Sealed"); this.add(ArmorStandStyleOptions.SEALED.getDescriptionKey(), "The statue can no longer be broken, equipment cannot be changed. Disallows opening this menu in survival mode."); - this.add("armorstatues.screen.position.rotation", "Rotation:"); - this.add("armorstatues.screen.position.degrees", "%s\u00B0"); - this.add("armorstatues.screen.position.moveBy", "Move By:"); - this.add("armorstatues.screen.position.pixels", "%s Pixel(s)"); - this.add("armorstatues.screen.position.blocks", "%s Block(s)"); - this.add("armorstatues.screen.position.x", "X-Position:"); - this.add("armorstatues.screen.position.y", "Y-Position:"); - this.add("armorstatues.screen.position.z", "Z-Position:"); - this.add("armorstatues.screen.position.increment", "Increment by %s"); - this.add("armorstatues.screen.position.decrement", "Decrement by %s"); - this.add("armorstatues.screen.pose.randomize", "Randomize"); - this.add("armorstatues.screen.pose.randomized", "Applied!"); - this.add("armorstatues.screen.rotations.pose.head", "Head"); - this.add("armorstatues.screen.rotations.pose.body", "Body"); - this.add("armorstatues.screen.rotations.pose.leftArm", "Left Arm"); - this.add("armorstatues.screen.rotations.pose.rightArm", "Right Arm"); - this.add("armorstatues.screen.rotations.pose.leftLeg", "Left Leg"); - this.add("armorstatues.screen.rotations.pose.rightLeg", "Right Leg"); - this.add("armorstatues.screen.rotations.tip1", "Hold the Shift or Alt key to lock sliders to a single axis!"); - this.add("armorstatues.screen.rotations.tip2", "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking."); - this.add("armorstatues.screen.rotations.reset", "Reset"); - this.add("armorstatues.screen.rotations.randomize", "Randomize"); - this.add("armorstatues.screen.rotations.limited", "Limited Rotations"); - this.add("armorstatues.screen.rotations.unlimited", "Unlimited Rotations"); - this.add("armorstatues.screen.rotations.copy", "Copy"); - this.add("armorstatues.screen.rotations.paste", "Paste"); - this.add("armorstatues.screen.rotations.mirror", "Mirror"); - this.add("armorstatues.screen.rotations.x", "X: %s"); - this.add("armorstatues.screen.rotations.y", "Y: %s"); - this.add("armorstatues.screen.rotations.z", "Z: %s"); - this.add("armorstatues.screen.alignments.centered", "Align Centered"); - this.add("armorstatues.screen.alignments.centered.description", "Align an armor stand in the center of the block position it is placed on."); - this.add("armorstatues.screen.alignments.cornered", "Align Cornered"); - this.add("armorstatues.screen.alignments.cornered.description", "Align an armor stand at the corner of the block position it is placed on."); - this.add("armorstatues.screen.alignments.aligned", "Aligned!"); - this.add("armorstatues.screen.alignments.block", "Align Block on Surface"); - this.add("armorstatues.screen.alignments.block.description", "Align an armor stand placed on a surface so that a block held by it appears on the surface."); - this.add("armorstatues.screen.alignments.itemFloating", "Align Item On Surface"); - this.add("armorstatues.screen.alignments.itemFloating.description", "Align an armor stand placed on a surface so that an item held by it appears upright on the surface."); - this.add("armorstatues.screen.alignments.itemFlat", "Align Item Flat On Surface"); - this.add("armorstatues.screen.alignments.itemFlat.description", "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface."); - this.add("armorstatues.screen.alignments.tool", "Align Tool Flat On Surface"); - this.add("armorstatues.screen.alignments.tool.description", "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface."); - this.add("armorstatues.screen.vanillaTweaksCredit", "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); - this.add("armorstatues.screen.failure", "Unable to modify armor stand data: %s"); - this.add("armorstatues.screen.failure.noPermission", "No Permission"); - this.add("armorstatues.screen.failure.notFinished", "Queue Not Empty"); - this.add("armorstatues.screen.finished", "Finished sending queued armor stand data"); + this.add(ArmorStandPositionScreen.ROTATION_TRANSLATION_KEY, "Rotation:"); + this.add(ArmorStandPositionScreen.POSITION_X_TRANSLATION_KEY, "X-Position:"); + this.add(ArmorStandPositionScreen.POSITION_Y_TRANSLATION_KEY, "Y-Position:"); + this.add(ArmorStandPositionScreen.POSITION_Z_TRANSLATION_KEY, "Z-Position:"); + this.add(ArmorStandPositionScreen.INCREMENT_TRANSLATION_KEY, "Increment by %s"); + this.add(ArmorStandPositionScreen.DECREMENT_TRANSLATION_KEY, "Decrement by %s"); + this.add(ArmorStandPositionScreen.DEGREES_TRANSLATION_KEY, "%s\u00B0"); + this.add(ArmorStandPositionScreen.MOVE_BY_TRANSLATION_KEY, "Move By:"); + this.add(ArmorStandPositionScreen.PIXELS_TRANSLATION_KEY, "%s Pixel(s)"); + this.add(ArmorStandPositionScreen.BLOCKS_TRANSLATION_KEY, "%s Block(s)"); + this.add(PosePartMutator.HEAD.getTranslationKey(), "Head"); + this.add(PosePartMutator.BODY.getTranslationKey(), "Body"); + this.add(PosePartMutator.LEFT_ARM.getTranslationKey(), "Left Arm"); + this.add(PosePartMutator.RIGHT_ARM.getTranslationKey(), "Right Arm"); + this.add(PosePartMutator.LEFT_LEG.getTranslationKey(), "Left Leg"); + this.add(PosePartMutator.RIGHT_LEG.getTranslationKey(), "Right Leg"); + this.add(PosePartMutator.AXIS_X_TRANSLATION_KEY, "X: %s"); + this.add(PosePartMutator.AXIS_Y_TRANSLATION_KEY, "Y: %s"); + this.add(PosePartMutator.AXIS_Z_TRANSLATION_KEY, "Z: %s"); + this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 1, "Hold the Shift or Alt key to lock sliders to a single axis!"); + this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 2, "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking."); + this.add(ArmorStandRotationsScreen.RESET_TRANSLATION_KEY, "Reset"); + this.add(ArmorStandRotationsScreen.RANDOMIZE_TRANSLATION_KEY, "Randomize"); + this.add(ArmorStandRotationsScreen.LIMITED_TRANSLATION_KEY, "Limited Rotations"); + this.add(ArmorStandRotationsScreen.UNLIMITED_TRANSLATION_KEY, "Unlimited Rotations"); + this.add(ArmorStandRotationsScreen.COPY_TRANSLATION_KEY, "Copy"); + this.add(ArmorStandRotationsScreen.PASTE_TRANSLATION_KEY, "Paste"); + this.add(ArmorStandRotationsScreen.MIRROR_TRANSLATION_KEY, "Mirror"); + this.add(AbstractArmorStandPositionScreen.CENTERED_TRANSLATION_KEY, "Align Centered"); + this.add(AbstractArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand in the center of the block position it is placed on."); + this.add(AbstractArmorStandPositionScreen.CORNERED_TRANSLATION_KEY, "Align Cornered"); + this.add(AbstractArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand at the corner of the block position it is placed on."); + this.add(AbstractArmorStandScreen.APPLIED_TRANSLATION_KEY, "Applied!"); + this.add(AbstractArmorStandScreen.ALIGNED_TRANSLATION_KEY, "Aligned!"); + this.add(AbstractArmorStandScreen.CREDITS_TRANSLATION_KEY, "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); + this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); } } diff --git a/gradle.properties b/gradle.properties index dea9c02..337d04d 100755 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ minFabricApiVersion=0.60.0 # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.5 +modVersion=4.0.6 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modSourceUrl=https://github.com/Fuzss/armorstatues From 0e830115d8eac0f19b4f7e5f340e1b4c0e7eb31b Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:53:49 +0200 Subject: [PATCH 09/31] fix minor api stuff --- .../{ArmorStatuesApi.java => StatuesApi.java} | 2 +- ...esApiClient.java => StatuesApiClient.java} | 3 +- .../AbstractArmorStandPositionScreen.java | 10 ++--- .../armorstand/AbstractArmorStandScreen.java | 14 +++---- .../armorstand/ArmorStandPositionScreen.java | 22 +++++------ .../armorstand/ArmorStandRotationsScreen.java | 18 ++++----- .../armorstand/ArmorStandStyleScreen.java | 2 +- .../api/helper/ArmorStandInteractHelper.java | 10 +++-- .../client/C2SArmorStandPositionMessage.java | 4 +- .../client/data/NetworkDataSyncHandler.java | 12 +++--- .../api/world/inventory/ArmorStandMenu.java | 39 ++++++++----------- .../world/inventory/data/ArmorStandPose.java | 15 +++++-- .../inventory/data/ArmorStandScreenType.java | 4 +- .../inventory/data/ArmorStandStyleOption.java | 6 +-- .../world/inventory/data/PosePartMutator.java | 10 ++--- .../client/ArmorStatuesClient.java | 2 +- .../ArmorStandAlignmentsScreen.java | 2 +- .../handler/ArmorStandInteractHandler.java | 2 +- .../fuzs/armorstatues/init/ModRegistry.java | 12 +++++- .../client/data/CommandDataSyncHandler.java | 10 ++--- .../fuzs/armorstatues/proxy/ClientProxy.java | 3 +- .../fuzs/armorstatues/ArmorStatuesFabric.java | 4 +- .../client/ArmorStatuesFabricClient.java | 4 +- .../fuzs/armorstatues/ArmorStatuesForge.java | 6 +-- .../client/ArmorStatuesForgeClient.java | 4 +- .../data/ModLanguageProvider.java | 4 +- 26 files changed, 119 insertions(+), 105 deletions(-) rename Common/src/main/java/fuzs/armorstatues/api/{ArmorStatuesApi.java => StatuesApi.java} (97%) rename Common/src/main/java/fuzs/armorstatues/api/client/{ArmorStatuesApiClient.java => StatuesApiClient.java} (92%) diff --git a/Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java b/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java similarity index 97% rename from Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java rename to Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java index ff77de6..79bd724 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/ArmorStatuesApi.java +++ b/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java @@ -13,7 +13,7 @@ import java.util.Locale; -public class ArmorStatuesApi implements ModConstructor { +public class StatuesApi implements ModConstructor { public static final String MOD_ID = "statues"; public static final String MOD_NAME = "Statues"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java b/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java similarity index 92% rename from Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java rename to Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java index e9f44c1..216cb94 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/ArmorStatuesApiClient.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java @@ -4,12 +4,11 @@ import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.PosePartMutator; -import fuzs.armorstatues.init.ModRegistry; import fuzs.puzzleslib.client.core.ClientModConstructor; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.inventory.InventoryMenu; -public class ArmorStatuesApiClient implements ClientModConstructor { +public class StatuesApiClient implements ClientModConstructor { @Override public void onClientSetup() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java index bfd3956..a3ccbff 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.api.client.gui.screens.armorstand; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.client.gui.components.TickButton; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; @@ -12,10 +12,10 @@ import java.util.EnumSet; public abstract class AbstractArmorStandPositionScreen extends ArmorStandWidgetsScreen { - public static final String CENTERED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.centered"; - public static final String CENTERED_DESCRIPTION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.centered.description"; - public static final String CORNERED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.cornered"; - public static final String CORNERED_DESCRIPTION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.cornered.description"; + public static final String CENTERED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.centered"; + public static final String CENTERED_DESCRIPTION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.centered.description"; + public static final String CORNERED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.cornered"; + public static final String CORNERED_DESCRIPTION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.cornered.description"; public AbstractArmorStandPositionScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index 229301f..551c7fa 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -2,7 +2,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.client.gui.components.TickingButton; import fuzs.armorstatues.api.client.gui.components.UnboundedSliderButton; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; @@ -37,12 +37,12 @@ public abstract class AbstractArmorStandScreen extends Screen implements MenuAccess, ArmorStandScreen { public static final String VANILLA_TWEAKS_HOMEPAGE = "https://vanillatweaks.net/"; - public static final String CREDITS_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.credits"; - public static final String APPLIED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.applied"; - public static final String ALIGNED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.aligned"; - private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/background.png"); - private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/widgets.png"); - private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = ArmorStatuesApi.id("textures/gui/container/armor_stand/equipment.png"); + public static final String CREDITS_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.credits"; + public static final String APPLIED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.applied"; + public static final String ALIGNED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.aligned"; + private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = StatuesApi.id("textures/gui/container/armor_stand/background.png"); + private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = StatuesApi.id("textures/gui/container/armor_stand/widgets.png"); + private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = StatuesApi.id("textures/gui/container/armor_stand/equipment.png"); @Nullable static ArmorStandScreenType lastScreenType; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java index eb1722d..dd45781 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java @@ -2,7 +2,7 @@ import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.client.gui.components.NewTextureButton; import fuzs.armorstatues.api.client.gui.components.NewTextureSliderButton; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; @@ -33,16 +33,16 @@ import java.util.stream.Collectors; public class ArmorStandPositionScreen extends AbstractArmorStandPositionScreen { - public static final String ROTATION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.rotation"; - public static final String POSITION_X_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.x"; - public static final String POSITION_Y_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.y"; - public static final String POSITION_Z_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.z"; - public static final String INCREMENT_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.increment"; - public static final String DECREMENT_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.decrement"; - public static final String PIXELS_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.pixels"; - public static final String BLOCKS_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.blocks"; - public static final String DEGREES_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.degrees"; - public static final String MOVE_BY_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.position.moveBy"; + public static final String ROTATION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.rotation"; + public static final String POSITION_X_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.x"; + public static final String POSITION_Y_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.y"; + public static final String POSITION_Z_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.z"; + public static final String INCREMENT_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.increment"; + public static final String DECREMENT_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.decrement"; + public static final String PIXELS_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.pixels"; + public static final String BLOCKS_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.blocks"; + public static final String DEGREES_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.degrees"; + public static final String MOVE_BY_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.moveBy"; private static final DecimalFormat BLOCK_INCREMENT_FORMAT = Util.make(new DecimalFormat("#.####"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); }); diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index 6a2301e..98605c8 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -2,7 +2,7 @@ import com.google.common.collect.Maps; import com.mojang.blaze3d.vertex.PoseStack; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.client.gui.components.BoxedSliderButton; import fuzs.armorstatues.api.client.gui.components.LiveSliderButton; import fuzs.armorstatues.api.client.gui.components.NewTextureTickButton; @@ -31,14 +31,14 @@ import java.util.stream.Collectors; public class ArmorStandRotationsScreen extends AbstractArmorStandScreen { - public static final String TIP_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.tip"; - public static final String UNLIMITED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.unlimited"; - public static final String LIMITED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.limited"; - public static final String RESET_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.reset"; - public static final String RANDOMIZE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.randomize"; - public static final String PASTE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.paste"; - public static final String COPY_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.copy"; - public static final String MIRROR_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.mirror"; + public static final String TIP_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.tip"; + public static final String UNLIMITED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.unlimited"; + public static final String LIMITED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.limited"; + public static final String RESET_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.reset"; + public static final String RANDOMIZE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.randomize"; + public static final String PASTE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.paste"; + public static final String COPY_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.copy"; + public static final String MIRROR_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.mirror"; private static final Map> POSE_PART_MUTATOR_FILTERS = Maps.newHashMap(); private static boolean clampRotations = true; diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java index 7bbc9e9..b9ca213 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java @@ -54,7 +54,7 @@ protected String getNameDefaultValue() { @Override protected Component getNameComponent() { - return Component.translatable(ArmorStandStyleOption.STYLE_TEXT_BOX_TRANSLATION_KEY); + return Component.translatable(ArmorStandStyleOption.TEXT_BOX_TRANSLATION_KEY); } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java b/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java index a1b598d..6e056d1 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java +++ b/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.api.helper; +import fuzs.armorstatues.api.world.entity.decoration.ArmorStandDataProvider; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.puzzleslib.core.CommonAbstractions; import fuzs.armorstatues.mixin.accessor.ArmorStandAccessor; @@ -12,24 +13,25 @@ import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; import java.util.Optional; public class ArmorStandInteractHelper { - public static Optional tryOpenArmorStatueMenu(Player player, Level level, InteractionHand interactionHand, ArmorStand entity, MenuType menuType) { + public static Optional tryOpenArmorStatueMenu(Player player, Level level, InteractionHand interactionHand, ArmorStand entity, MenuType menuType, @Nullable ArmorStandDataProvider dataProvider) { ItemStack itemInHand = player.getItemInHand(interactionHand); if (player.isShiftKeyDown() && itemInHand.isEmpty() && (!entity.isInvulnerable() || player.getAbilities().instabuild)) { - openArmorStatueMenu(player, entity, menuType); + openArmorStatueMenu(player, entity, menuType, dataProvider); return Optional.of(InteractionResult.sidedSuccess(level.isClientSide)); } return Optional.empty(); } - public static void openArmorStatueMenu(Player player, ArmorStand entity, MenuType menuType) { + public static void openArmorStatueMenu(Player player, ArmorStand entity, MenuType menuType, @Nullable ArmorStandDataProvider dataProvider) { if (!(player instanceof ServerPlayer serverPlayer)) return; CommonAbstractions.INSTANCE.openMenu(serverPlayer, new SimpleMenuProvider((containerId, inventory, player1) -> { - return ArmorStandMenu.create(menuType, containerId, inventory, entity); + return ArmorStandMenu.create(menuType, containerId, inventory, entity, dataProvider); }, entity.getDisplayName()), (serverPlayer1, friendlyByteBuf) -> { friendlyByteBuf.writeInt(entity.getId()); friendlyByteBuf.writeBoolean(entity.isInvulnerable()); diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java index 2f8d679..7e34fdb 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.api.network.client; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.puzzleslib.network.Message; import net.minecraft.network.FriendlyByteBuf; @@ -44,7 +44,7 @@ public MessageHandler makeHandler() { public void handle(C2SArmorStandPositionMessage message, Player player, Object gameInstance) { if (player.containerMenu instanceof ArmorStandMenu menu && menu.stillValid(player)) { if (!tryMoveArmorStandTo(menu.getArmorStand(), message.posX, message.posY, message.posZ)) { - ArmorStatuesApi.LOGGER.warn("Player {} attempted to move armor stand further than allowed", player); + StatuesApi.LOGGER.warn("Player {} attempted to move armor stand further than allowed", player); } } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java index 52b6505..320dab2 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.api.network.client.data; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.network.client.*; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; @@ -23,7 +23,7 @@ public ArmorStandHolder getArmorStandHolder() { @Override public void sendName(String name) { DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); - ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandNameMessage(name)); + StatuesApi.NETWORK.sendToServer(new C2SArmorStandNameMessage(name)); } @Override @@ -31,23 +31,23 @@ public void sendPose(ArmorStandPose pose) { pose.applyToEntity(this.getArmorStand()); CompoundTag tag = new CompoundTag(); pose.serializeAllPoses(tag); - ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandPoseMessage(tag)); + StatuesApi.NETWORK.sendToServer(new C2SArmorStandPoseMessage(tag)); } @Override public void sendPosition(double posX, double posY, double posZ) { - ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandPositionMessage(posX, posY, posZ)); + StatuesApi.NETWORK.sendToServer(new C2SArmorStandPositionMessage(posX, posY, posZ)); } @Override public void sendRotation(float rotation) { - ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandRotationMessage(rotation)); + StatuesApi.NETWORK.sendToServer(new C2SArmorStandRotationMessage(rotation)); } @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { styleOption.setOption(this.getArmorStand(), value); - ArmorStatuesApi.NETWORK.sendToServer(new C2SArmorStandStyleMessage(styleOption, value)); + StatuesApi.NETWORK.sendToServer(new C2SArmorStandStyleMessage(styleOption, value)); } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java index 1e3012c..dd24750 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java @@ -1,12 +1,10 @@ package fuzs.armorstatues.api.world.inventory; import com.mojang.datafixers.util.Pair; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.world.entity.decoration.ArmorStandDataProvider; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import fuzs.armorstatues.core.ModServices; -import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.mixin.accessor.ArmorStandAccessor; import fuzs.armorstatues.mixin.accessor.SimpleContainerAccessor; import net.minecraft.core.NonNullList; @@ -25,23 +23,19 @@ import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class ArmorStandMenu extends AbstractContainerMenu implements ArmorStandHolder { - public static final ResourceLocation EMPTY_ARMOR_SLOT_SWORD = ArmorStatuesApi.id("item/empty_armor_slot_sword"); + public static final ResourceLocation EMPTY_ARMOR_SLOT_SWORD = StatuesApi.id("item/empty_armor_slot_sword"); static final ResourceLocation[] TEXTURE_EMPTY_SLOTS = new ResourceLocation[]{InventoryMenu.EMPTY_ARMOR_SLOT_BOOTS, InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET, InventoryMenu.EMPTY_ARMOR_SLOT_SHIELD, EMPTY_ARMOR_SLOT_SWORD}; public static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET, EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND}; - public static final ArmorStandDataProvider DATA_PROVIDER = new ArmorStandDataProvider() { - @Override - public ArmorStandScreenType[] getScreenTypes() { - return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS, ArmorStandScreenType.EQUIPMENT}; - } - }; - - private final Container armorStandInventory; + private final Container container; private final ArmorStand armorStand; + @Nullable + private final ArmorStandDataProvider dataProvider; - public static ArmorStandMenu create(MenuType menuType, int containerId, Inventory inventory, FriendlyByteBuf buf) { + public static ArmorStandMenu create(MenuType menuType, int containerId, Inventory inventory, FriendlyByteBuf buf, @Nullable ArmorStandDataProvider dataProvider) { int entityId = buf.readInt(); ArmorStand entity = (ArmorStand) inventory.player.level.getEntity(entityId); if (entity != null) { @@ -49,15 +43,15 @@ public static ArmorStandMenu create(MenuType menuType, int containerId, Inven entity.setInvulnerable(buf.readBoolean()); ((ArmorStandAccessor) entity).setDisabledSlots(buf.readInt()); // also create the armor stand container client side, so that visual update instantly instead of having to wait for the server to resync data - return create(menuType, containerId, inventory, entity); + return create(menuType, containerId, inventory, entity, dataProvider); } // exception is caught, so nothing will crash, only the screen will not open // not sure how this is even possible, but there was a report about it // report was concerning just placed statues, so maybe entity data arrived at remote after menu was opened - throw new IllegalStateException("trying to open invalid armor stand menu, entity for id %s was not found on client".formatted(entityId)); + throw new IllegalStateException("Entity for id %s missing on client".formatted(entityId)); } - public static ArmorStandMenu create(MenuType menuType, int containerId, Inventory inventory, ArmorStand armorStand) { + public static ArmorStandMenu create(MenuType menuType, int containerId, Inventory inventory, ArmorStand armorStand, @Nullable ArmorStandDataProvider dataProvider) { // we could also copy all items from the armor stand to a SimpleContainer, then update the armor stand using a listener using LivingEntity::setItemSlot // problem is that way we miss out on anything changing with the armor stand entity itself, therefore this approach NonNullList armorItems = ((ArmorStandAccessor) armorStand).getArmorItems(); @@ -69,7 +63,7 @@ public static ArmorStandMenu create(MenuType menuType, int containerId, Inven } }); CompoundContainer container = new CompoundContainer(simpleContainer(armorItems), handItemsContainer); - return new ArmorStandMenu(menuType, containerId, inventory, container, armorStand); + return new ArmorStandMenu(menuType, containerId, inventory, container, armorStand, dataProvider); } private static SimpleContainer simpleContainer(NonNullList items) { @@ -78,13 +72,14 @@ private static SimpleContainer simpleContainer(NonNullList items) { return container; } - private ArmorStandMenu(MenuType menuType, int containerId, Inventory inventory, Container container, ArmorStand armorStand) { + private ArmorStandMenu(MenuType menuType, int containerId, Inventory inventory, Container container, ArmorStand armorStand, @Nullable ArmorStandDataProvider dataProvider) { super(menuType, containerId); - this.armorStandInventory = container; + this.container = container; this.armorStand = armorStand; + this.dataProvider = dataProvider; for (int k = 0; k < 4; ++k) { final EquipmentSlot equipmentslot = SLOT_IDS[k]; - this.addSlot(new Slot(this.armorStandInventory, 3 - k, 58, 20 + k * 18) { + this.addSlot(new Slot(this.container, 3 - k, 58, 20 + k * 18) { @Override public void set(ItemStack stack) { @@ -134,7 +129,7 @@ public Pair getNoItemIcon() { for (int i = 0; i < 2; i++) { final EquipmentSlot equipmentslot = SLOT_IDS[4 + i]; final ResourceLocation slotTexture = TEXTURE_EMPTY_SLOTS[5 - i]; - this.addSlot(new Slot(this.armorStandInventory, 4 + i, 136, 56 + i * 18) { + this.addSlot(new Slot(this.container, 4 + i, 136, 56 + i * 18) { @Override public boolean mayPlace(ItemStack stack) { @@ -243,6 +238,6 @@ public ArmorStand getArmorStand() { @Override public ArmorStandDataProvider getDataProvider() { - return DATA_PROVIDER; + return this.dataProvider != null ? this.dataProvider : ArmorStandHolder.super.getDataProvider(); } } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index a5cf492..637601f 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.api.world.inventory.data; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.mixin.accessor.ArmorStandAccessor; import net.minecraft.Util; import net.minecraft.core.Rotations; @@ -10,10 +10,13 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Locale; public class ArmorStandPose { - public static final String POSE_SOURCE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.pose.by"; + public static final String POSE_SOURCE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.pose.by"; private static final String MINECRAFT_SOURCE = "Minecraft"; private static final String VANILLA_TWEAKS_SOURCE = "Vanilla Tweaks"; private static final Rotations ZERO_ROTATIONS = new Rotations(0.0F, 0.0F, 0.0F); @@ -95,7 +98,7 @@ public String toString() { } public String getTranslationKey() { - return this.name != null ? ArmorStatuesApi.MOD_ID + ".screen.pose." + this.name : null; + return this.name != null ? StatuesApi.MOD_ID + ".screen.pose." + this.name : null; } @Nullable @@ -269,6 +272,12 @@ public static int valuesLength() { return VALUES.length; } + public static ArmorStandPose random() { + List poses = Arrays.asList(VALUES); + Collections.shuffle(poses); + return poses.stream().findAny().orElseThrow(); + } + public static void checkMutatorsSize(PosePartMutator[] mutators) { if (mutators.length != 6) throw new IllegalArgumentException("Invalid mutators size: Expected 6, was %s".formatted(mutators.length)); } diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java index ad74f7a..4cb1e91 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.api.world.inventory.data; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -33,7 +33,7 @@ public String toString() { } public String getTranslationKey() { - return ArmorStatuesApi.MOD_ID + ".screen.type." + this.name; + return StatuesApi.MOD_ID + ".screen.type." + this.name; } public ItemStack getIcon() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java index fb357f1..da5829a 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java @@ -2,7 +2,7 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.decoration.ArmorStand; @@ -11,14 +11,14 @@ import java.util.Objects; public interface ArmorStandStyleOption { - String STYLE_TEXT_BOX_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.style.name"; + String TEXT_BOX_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.style.name"; int ARMOR_STAND_ALL_SLOTS_DISABLED = 4144959; BiMap OPTIONS_REGISTRY = HashBiMap.create(); String getName(); default String getTranslationKey() { - return ArmorStatuesApi.MOD_ID + ".screen.style." + this.getName(); + return StatuesApi.MOD_ID + ".screen.style." + this.getName(); } default String getDescriptionKey() { diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java index 42e2468..62af0a1 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.api.world.inventory.data; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import net.minecraft.core.Direction; import net.minecraft.core.Rotations; import net.minecraft.network.chat.Component; @@ -18,9 +18,9 @@ public final class PosePartMutator { public static final PosePartMutator LEFT_ARM = new PosePartMutator("leftArm", ArmorStandPose::getLeftArmPose, ArmorStandPose::withLeftArmPose, PosePartAxisRange.range(-180.0, 0.0), PosePartAxisRange.range(-45.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); public static final PosePartMutator RIGHT_LEG = new PosePartMutator("rightLeg", ArmorStandPose::getRightLegPose, ArmorStandPose::withRightLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(-90.0, 0.0), PosePartAxisRange.range(-120.0, 120.0)); public static final PosePartMutator LEFT_LEG = new PosePartMutator("leftLeg", ArmorStandPose::getLeftLegPose, ArmorStandPose::withLeftLegPose, PosePartAxisRange.range(-120.0, 120.0), PosePartAxisRange.range(0.0, 90.0), PosePartAxisRange.range(-120.0, 120.0)); - public static final String AXIS_X_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.x"; - public static final String AXIS_Y_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.y"; - public static final String AXIS_Z_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".screen.rotations.z"; + public static final String AXIS_X_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.x"; + public static final String AXIS_Y_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.y"; + public static final String AXIS_Z_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.rotations.z"; private final String name; private final Function getRotations; @@ -56,7 +56,7 @@ public String toString() { } public String getTranslationKey() { - return ArmorStatuesApi.MOD_ID + ".screen.rotations.pose." + this.name; + return StatuesApi.MOD_ID + ".screen.rotations.pose." + this.name; } public Component getAxisComponent(ArmorStandPose pose, int index) { diff --git a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index 1f07555..bdb9a83 100644 --- a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -12,7 +12,7 @@ public class ArmorStatuesClient implements ClientModConstructor { @Override public void onClientSetup() { - ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); } @Override diff --git a/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index 76f285b..f331b57 100644 --- a/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -44,7 +44,7 @@ protected void init() { @Override public ArmorStandScreenType getScreenType() { - return ModRegistry.ALIGNMENTS; + return ModRegistry.ALIGNMENTS_SCREEN_TYPE; } private class AlignmentWidget extends AbstractPositionScreenWidget { diff --git a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index 9f4e207..1170c20 100644 --- a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -24,7 +24,7 @@ public class ArmorStandInteractHandler { public static Optional onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { if (!player.isSpectator() && target.getType() == EntityType.ARMOR_STAND) { - Optional result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get()); + Optional result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get(), ModRegistry.ARMOR_STAND_DATA_PROVIDER); if (result.isPresent() && level.isClientSide && !presentServerside) { ArmorStatues.PROXY.openArmorStandScreen((ArmorStand) target, player); // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen diff --git a/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index 7a1907c..dec00cf 100644 --- a/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -1,6 +1,7 @@ package fuzs.armorstatues.init; import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.api.world.entity.decoration.ArmorStandDataProvider; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.puzzleslib.core.CoreServices; @@ -13,9 +14,16 @@ public class ModRegistry { static final RegistryManager REGISTRY = CoreServices.FACTORIES.registration(ArmorStatues.MOD_ID); public static final RegistryReference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuTypeSupplier("armor_stand", () -> (containerId, inventory, data) -> { - return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data); + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); }); - public static final ArmorStandScreenType ALIGNMENTS = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); + public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandScreenType.EQUIPMENT}; + } + }; + public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); public static void touch() { diff --git a/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 3b7d172..37408d3 100644 --- a/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.network.client.data; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; @@ -23,10 +23,10 @@ import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { - public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.failure.noPermission"; - public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.failure.notFinished"; - public static final String FINISHED_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.finished"; - public static final String FAILURE_TRANSLATION_KEY = ArmorStatuesApi.MOD_ID + ".dataSync.failure"; + public static final String NO_PERMISSION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NOT_FINISHED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.failure"; private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); @Nullable diff --git a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java index cf657f1..9ea63a2 100644 --- a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java +++ b/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -4,6 +4,7 @@ import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreenFactory; import fuzs.armorstatues.api.world.entity.decoration.ArmorStandDataProvider; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; +import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; @@ -28,7 +29,7 @@ public ArmorStand getArmorStand() { @Override public ArmorStandDataProvider getDataProvider() { - return ArmorStandMenu.DATA_PROVIDER; + return ModRegistry.ARMOR_STAND_DATA_PROVIDER; } }; Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(holder, (LocalPlayer) player)); diff --git a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java index 8a2ab67..4a639cd 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java +++ b/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java @@ -1,6 +1,6 @@ package fuzs.armorstatues; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.core.CoreServices; import net.fabricmc.api.ModInitializer; @@ -18,7 +18,7 @@ public class ArmorStatuesFabric implements ModInitializer { @Override public void onInitialize() { - CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApi()); + CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new StatuesApi()); CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatues()); registerHandlers(); } diff --git a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java index 06ce155..e147d61 100644 --- a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java +++ b/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java @@ -1,7 +1,7 @@ package fuzs.armorstatues.client; import fuzs.armorstatues.ArmorStatues; -import fuzs.armorstatues.api.client.ArmorStatuesApiClient; +import fuzs.armorstatues.api.client.StatuesApiClient; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreen; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; @@ -17,7 +17,7 @@ public class ArmorStatuesFabricClient implements ClientModInitializer { @Override public void onInitializeClient() { - ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApiClient()); + ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new StatuesApiClient()); ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesClient()); registerHandlers(); } diff --git a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java index db2c0b2..e95fa8d 100644 --- a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java +++ b/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java @@ -1,6 +1,6 @@ package fuzs.armorstatues; -import fuzs.armorstatues.api.ArmorStatuesApi; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.data.ModLanguageProvider; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.core.CoreServices; @@ -22,7 +22,7 @@ public class ArmorStatuesForge { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { - CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApi()); + CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new StatuesApi()); CoreServices.FACTORIES.modConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatues()); registerHandlers(); } @@ -44,6 +44,6 @@ private static void registerHandlers() { public static void onGatherData(final GatherDataEvent evt) { DataGenerator generator = evt.getGenerator(); final ExistingFileHelper existingFileHelper = evt.getExistingFileHelper(); - generator.addProvider(true, new ModLanguageProvider(generator, ArmorStatuesApi.MOD_ID)); + generator.addProvider(true, new ModLanguageProvider(generator, StatuesApi.MOD_ID)); } } diff --git a/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java index 41a214e..d96d8a1 100644 --- a/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java +++ b/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java @@ -1,7 +1,7 @@ package fuzs.armorstatues.client; import fuzs.armorstatues.ArmorStatues; -import fuzs.armorstatues.api.client.ArmorStatuesApiClient; +import fuzs.armorstatues.api.client.StatuesApiClient; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.armorstatues.handler.DataSyncTickHandler; @@ -30,7 +30,7 @@ public class ArmorStatuesForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { - ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesApiClient()); + ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new StatuesApiClient()); ClientCoreServices.FACTORIES.clientModConstructor(ArmorStatues.MOD_ID).accept(new ArmorStatuesClient()); registerHandlers(); } diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index 3fcc99b..3ff14c9 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -21,7 +21,7 @@ public ModLanguageProvider(DataGenerator gen, String modId) { @Override protected void addTranslations() { // Armor Statues - this.add(ModRegistry.ALIGNMENTS.getTranslationKey(), "Alignments"); + this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block on Surface"); this.add(ArmorStandAlignment.BLOCK.getDescriptionsKey(), "Align an armor stand placed on a surface so that a block held by it appears on the surface."); this.add(ArmorStandAlignment.FLOATING_ITEM.getTranslationKey(), "Align Item On Surface"); @@ -67,7 +67,7 @@ protected void addTranslations() { this.add(ArmorStandScreenType.STYLE.getTranslationKey(), "Style"); this.add(ArmorStandScreenType.POSES.getTranslationKey(), "Poses"); this.add(ArmorStandScreenType.POSITION.getTranslationKey(), "Position"); - this.add(ArmorStandStyleOption.STYLE_TEXT_BOX_TRANSLATION_KEY, "Set a name to display above the entity if enabled."); + this.add(ArmorStandStyleOption.TEXT_BOX_TRANSLATION_KEY, "Set a name to display above the entity if enabled."); this.add(ArmorStandStyleOptions.SHOW_ARMS.getTranslationKey(), "Show Arms"); this.add(ArmorStandStyleOptions.SHOW_ARMS.getDescriptionKey(), "Shows the statue's arms, so it may hold items in both hands."); this.add(ArmorStandStyleOptions.SMALL.getTranslationKey(), "Small"); From 10bf3c12e19e80f0e365144dc2d281c22eddecec Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:23:30 +0200 Subject: [PATCH 10/31] update lang file --- .../network/client/data/CommandDataSyncHandler.java | 10 +++++----- .../.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 ++-- .../generated/resources/assets/statues/lang/en_us.json | 8 ++++---- .../fuzs/armorstatues/data/ModLanguageProvider.java | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 37408d3..d82aab7 100644 --- a/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -1,6 +1,6 @@ package fuzs.armorstatues.network.client.data; -import fuzs.armorstatues.api.StatuesApi; +import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; @@ -23,10 +23,10 @@ import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { - public static final String NO_PERMISSION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.failure.noPermission"; - public static final String NOT_FINISHED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.failure.notFinished"; - public static final String FINISHED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.finished"; - public static final String FAILURE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".dataSync.failure"; + public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); @Nullable diff --git a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index b35b798..b70f701 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-26T11:03:36.825853 Languages: en_us -ff1dac038e1aaf5530e4974008a28814586b5a12 assets/statues/lang/en_us.json +// 1.19.2 2023-07-26T11:55:08.810043 Languages: en_us +6ff61f102004fe4c28571748e7db2fa8ee588cd7 assets/statues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/statues/lang/en_us.json b/Forge/src/generated/resources/assets/statues/lang/en_us.json index 19b24ff..cca5f81 100644 --- a/Forge/src/generated/resources/assets/statues/lang/en_us.json +++ b/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -1,4 +1,8 @@ { + "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.finished": "Finished sending queued armor stand data", "armorstatues.screen.alignments.block": "Align Block on Surface", "armorstatues.screen.alignments.block.description": "Align an armor stand placed on a surface so that a block held by it appears on the surface.", "armorstatues.screen.alignments.itemFlat": "Align Item Flat On Surface", @@ -8,10 +12,6 @@ "armorstatues.screen.alignments.tool": "Align Tool Flat On Surface", "armorstatues.screen.alignments.tool.description": "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface.", "item.minecraft.armor_stand.description": "Use [%s] + [%s] with an empty hand to open configuration screen.", - "statues.dataSync.failure": "Unable to modify armor stand data: %s", - "statues.dataSync.failure.noPermission": "No Permission", - "statues.dataSync.failure.notFinished": "Queue Not Empty", - "statues.dataSync.finished": "Finished sending queued armor stand data", "statues.screen.aligned": "Aligned!", "statues.screen.applied": "Applied!", "statues.screen.centered": "Align Centered", diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index 3ff14c9..a714cbe 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -21,6 +21,10 @@ public ModLanguageProvider(DataGenerator gen, String modId) { @Override protected void addTranslations() { // Armor Statues + this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block on Surface"); this.add(ArmorStandAlignment.BLOCK.getDescriptionsKey(), "Align an armor stand placed on a surface so that a block held by it appears on the surface."); @@ -117,9 +121,5 @@ protected void addTranslations() { this.add(AbstractArmorStandScreen.APPLIED_TRANSLATION_KEY, "Applied!"); this.add(AbstractArmorStandScreen.ALIGNED_TRANSLATION_KEY, "Aligned!"); this.add(AbstractArmorStandScreen.CREDITS_TRANSLATION_KEY, "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); - this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); - this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); - this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); - this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); } } From f213e6f37e1651767aa3d71f2ef53d5bbeffb7af Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:45:51 +0200 Subject: [PATCH 11/31] minor stuff again --- .../armorstand/AbstractArmorStandScreen.java | 6 +++--- .../api/world/inventory/data/ArmorStandPose.java | 2 +- .../{armor_stand => statue}/background.png | Bin .../container/{armor_stand => statue}/equipment.png | Bin .../container/{armor_stand => statue}/widgets.png | Bin 5 files changed, 4 insertions(+), 4 deletions(-) rename Forge/src/main/resources/assets/statues/textures/gui/container/{armor_stand => statue}/background.png (100%) rename Forge/src/main/resources/assets/statues/textures/gui/container/{armor_stand => statue}/equipment.png (100%) rename Forge/src/main/resources/assets/statues/textures/gui/container/{armor_stand => statue}/widgets.png (100%) diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index 551c7fa..6b90ccc 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -40,9 +40,9 @@ public abstract class AbstractArmorStandScreen extends Screen implements MenuAcc public static final String CREDITS_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.credits"; public static final String APPLIED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.applied"; public static final String ALIGNED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.aligned"; - private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = StatuesApi.id("textures/gui/container/armor_stand/background.png"); - private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = StatuesApi.id("textures/gui/container/armor_stand/widgets.png"); - private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = StatuesApi.id("textures/gui/container/armor_stand/equipment.png"); + private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = StatuesApi.id("textures/gui/container/statue/background.png"); + private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = StatuesApi.id("textures/gui/container/statue/widgets.png"); + private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = StatuesApi.id("textures/gui/container/statue/equipment.png"); @Nullable static ArmorStandScreenType lastScreenType; diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index 637601f..3824f97 100644 --- a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -272,7 +272,7 @@ public static int valuesLength() { return VALUES.length; } - public static ArmorStandPose random() { + public static ArmorStandPose randomValue() { List poses = Arrays.asList(VALUES); Collections.shuffle(poses); return poses.stream().findAny().orElseThrow(); diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/background.png b/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/background.png rename to Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/equipment.png b/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/equipment.png rename to Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/widgets.png b/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/gui/container/armor_stand/widgets.png rename to Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png From c9f9097745104fe99602a83031315a4791ee9611 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:49:04 +0200 Subject: [PATCH 12/31] minor things from 1.20.1 port --- .../inventory/data/ArmorStandAlignment.java | 7 +++--- .../ArmorStandAlignmentsScreen.java | 2 +- .../mixin/accessor/ArmorStandAccessor.java | 7 ------ .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 ++-- .../resources/assets/statues/lang/en_us.json | 20 ++++++++--------- .../data/ModLanguageProvider.java | 22 +++++++++---------- 6 files changed, 27 insertions(+), 35 deletions(-) rename Common/src/main/java/fuzs/armorstatues/{ => api}/world/inventory/data/ArmorStandAlignment.java (87%) diff --git a/Common/src/main/java/fuzs/armorstatues/world/inventory/data/ArmorStandAlignment.java b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java similarity index 87% rename from Common/src/main/java/fuzs/armorstatues/world/inventory/data/ArmorStandAlignment.java rename to Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java index 003799b..25b59a7 100644 --- a/Common/src/main/java/fuzs/armorstatues/world/inventory/data/ArmorStandAlignment.java +++ b/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java @@ -1,7 +1,6 @@ -package fuzs.armorstatues.world.inventory.data; +package fuzs.armorstatues.api.world.inventory.data; -import fuzs.armorstatues.ArmorStatues; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; +import fuzs.armorstatues.api.StatuesApi; import net.minecraft.core.Rotations; import net.minecraft.world.phys.Vec3; @@ -34,7 +33,7 @@ public String toString() { } public String getTranslationKey() { - return ArmorStatues.MOD_ID + ".screen.alignments." + this.name; + return StatuesApi.MOD_ID + ".screen.alignments." + this.name; } public String getDescriptionsKey() { diff --git a/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index f331b57..f60ff1d 100644 --- a/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -5,7 +5,7 @@ import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandPositionScreen; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; -import fuzs.armorstatues.world.inventory.data.ArmorStandAlignment; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; import fuzs.armorstatues.init.ModRegistry; diff --git a/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java b/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java index 0e68716..45e2b2e 100644 --- a/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java +++ b/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java @@ -2,7 +2,6 @@ import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; @@ -26,10 +25,4 @@ public interface ArmorStandAccessor { @Invoker void callReadPose(CompoundTag compound); - - @Invoker - void callBrokenByAnything(DamageSource damageSource); - - @Invoker - void callCauseDamage(DamageSource damageSource, float amount); } diff --git a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index b70f701..ba6e082 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-26T11:55:08.810043 Languages: en_us -6ff61f102004fe4c28571748e7db2fa8ee588cd7 assets/statues/lang/en_us.json +// 1.19.2 2023-07-27T12:48:23.744062 Languages: en_us +d04e0f1fd3fc55a1ca05d332b79edacf16759019 assets/statues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/statues/lang/en_us.json b/Forge/src/generated/resources/assets/statues/lang/en_us.json index cca5f81..6304896 100644 --- a/Forge/src/generated/resources/assets/statues/lang/en_us.json +++ b/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -3,16 +3,16 @@ "armorstatues.dataSync.failure.noPermission": "No Permission", "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", "armorstatues.dataSync.finished": "Finished sending queued armor stand data", - "armorstatues.screen.alignments.block": "Align Block on Surface", - "armorstatues.screen.alignments.block.description": "Align an armor stand placed on a surface so that a block held by it appears on the surface.", - "armorstatues.screen.alignments.itemFlat": "Align Item Flat On Surface", - "armorstatues.screen.alignments.itemFlat.description": "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface.", - "armorstatues.screen.alignments.itemFloating": "Align Item On Surface", - "armorstatues.screen.alignments.itemFloating.description": "Align an armor stand placed on a surface so that an item held by it appears upright on the surface.", - "armorstatues.screen.alignments.tool": "Align Tool Flat On Surface", - "armorstatues.screen.alignments.tool.description": "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface.", "item.minecraft.armor_stand.description": "Use [%s] + [%s] with an empty hand to open configuration screen.", "statues.screen.aligned": "Aligned!", + "statues.screen.alignments.block": "Align Block on Surface", + "statues.screen.alignments.block.description": "Align an armor stand placed on a surface so that a block held by it appears on the surface.", + "statues.screen.alignments.itemFlat": "Align Item Flat On Surface", + "statues.screen.alignments.itemFlat.description": "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface.", + "statues.screen.alignments.itemFloating": "Align Item On Surface", + "statues.screen.alignments.itemFloating.description": "Align an armor stand placed on a surface so that an item held by it appears upright on the surface.", + "statues.screen.alignments.tool": "Align Tool Flat On Surface", + "statues.screen.alignments.tool.description": "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface.", "statues.screen.applied": "Applied!", "statues.screen.centered": "Align Centered", "statues.screen.centered.description": "Align an armor stand in the center of the block position it is placed on.", @@ -71,8 +71,8 @@ "statues.screen.rotations.pose.rightLeg": "Right Leg", "statues.screen.rotations.randomize": "Randomize", "statues.screen.rotations.reset": "Reset", - "statues.screen.rotations.tip1": "Hold the Shift or Alt key to lock sliders to a single axis!", - "statues.screen.rotations.tip2": "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking.", + "statues.screen.rotations.tip1": "Hold any [§dShift§r] or [§dAlt§r] key to lock sliders to a single axis!", + "statues.screen.rotations.tip2": "Use arrow keys to move sliders more precisely! Focus a slider first by clicking.", "statues.screen.rotations.unlimited": "Unlimited Rotations", "statues.screen.rotations.x": "X: %s", "statues.screen.rotations.y": "Y: %s", diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index a714cbe..707719f 100644 --- a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -8,7 +8,7 @@ import fuzs.armorstatues.api.world.inventory.data.*; import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; -import fuzs.armorstatues.world.inventory.data.ArmorStandAlignment; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; import net.minecraft.data.DataGenerator; import net.minecraftforge.common.data.LanguageProvider; @@ -26,14 +26,6 @@ protected void addTranslations() { this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); - this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block on Surface"); - this.add(ArmorStandAlignment.BLOCK.getDescriptionsKey(), "Align an armor stand placed on a surface so that a block held by it appears on the surface."); - this.add(ArmorStandAlignment.FLOATING_ITEM.getTranslationKey(), "Align Item On Surface"); - this.add(ArmorStandAlignment.FLOATING_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that an item held by it appears upright on the surface."); - this.add(ArmorStandAlignment.FLAT_ITEM.getTranslationKey(), "Align Item Flat On Surface"); - this.add(ArmorStandAlignment.FLAT_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface."); - this.add(ArmorStandAlignment.TOOL.getTranslationKey(), "Align Tool Flat On Surface"); - this.add(ArmorStandAlignment.TOOL.getDescriptionsKey(), "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface."); // Statues Api this.add(ClientProxy.OPEN_SCREEN_TRANSLATION_KEY, "Use [%s] + [%s] with an empty hand to open configuration screen."); this.add(ArmorStandPose.POSE_SOURCE_TRANSLATION_KEY, "By %s"); @@ -105,8 +97,8 @@ protected void addTranslations() { this.add(PosePartMutator.AXIS_X_TRANSLATION_KEY, "X: %s"); this.add(PosePartMutator.AXIS_Y_TRANSLATION_KEY, "Y: %s"); this.add(PosePartMutator.AXIS_Z_TRANSLATION_KEY, "Z: %s"); - this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 1, "Hold the Shift or Alt key to lock sliders to a single axis!"); - this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 2, "Use the arrow keys to move sliders more precisely! Focus a slider first by clicking."); + this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 1, "Hold any [§dShift§r] or [§dAlt§r] key to lock sliders to a single axis!"); + this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 2, "Use arrow keys to move sliders more precisely! Focus a slider first by clicking."); this.add(ArmorStandRotationsScreen.RESET_TRANSLATION_KEY, "Reset"); this.add(ArmorStandRotationsScreen.RANDOMIZE_TRANSLATION_KEY, "Randomize"); this.add(ArmorStandRotationsScreen.LIMITED_TRANSLATION_KEY, "Limited Rotations"); @@ -118,6 +110,14 @@ protected void addTranslations() { this.add(AbstractArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand in the center of the block position it is placed on."); this.add(AbstractArmorStandPositionScreen.CORNERED_TRANSLATION_KEY, "Align Cornered"); this.add(AbstractArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand at the corner of the block position it is placed on."); + this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block on Surface"); + this.add(ArmorStandAlignment.BLOCK.getDescriptionsKey(), "Align an armor stand placed on a surface so that a block held by it appears on the surface."); + this.add(ArmorStandAlignment.FLOATING_ITEM.getTranslationKey(), "Align Item On Surface"); + this.add(ArmorStandAlignment.FLOATING_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that an item held by it appears upright on the surface."); + this.add(ArmorStandAlignment.FLAT_ITEM.getTranslationKey(), "Align Item Flat On Surface"); + this.add(ArmorStandAlignment.FLAT_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface."); + this.add(ArmorStandAlignment.TOOL.getTranslationKey(), "Align Tool Flat On Surface"); + this.add(ArmorStandAlignment.TOOL.getDescriptionsKey(), "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface."); this.add(AbstractArmorStandScreen.APPLIED_TRANSLATION_KEY, "Applied!"); this.add(AbstractArmorStandScreen.ALIGNED_TRANSLATION_KEY, "Aligned!"); this.add(AbstractArmorStandScreen.CREDITS_TRANSLATION_KEY, "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); From 402cb75b9e3545c7bc2877c03a921f446285cd91 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 27 Jul 2023 17:50:03 +0200 Subject: [PATCH 13/31] setup 1.19.2 --- .gitattributes | 2 - .github/ISSUE_TEMPLATE/bug.yml | 6 +- .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/ISSUE_TEMPLATE/crash.yml | 6 +- .github/ISSUE_TEMPLATE/suggestion.yml | 2 +- .gitignore | 12 +- .idea/gradle.xml | 44 ++ 1.18/.idea/scopes/Fabric_sources.xml | 3 + 1.18/.idea/scopes/Forge_sources.xml | 3 + 1.18/CHANGELOG.md | 9 + 1.18/Common/build.gradle | 11 + .../main/java/fuzs/examplemod/ExampleMod.java | 16 + .../examplemod/client/ExampleModClient.java | 7 + .../resources/examplemod.common.mixins.json | 15 + 1.18/Common/src/main/resources/mod_banner.png | Bin 0 -> 17858 bytes 1.18/Common/src/main/resources/mod_logo.png | Bin 0 -> 6537 bytes 1.18/Common/src/main/resources/pack.mcmeta | 8 + 1.18/Fabric/build.gradle | 29 ++ .../fuzs/examplemod/ExampleModFabric.java | 12 + .../client/ExampleModFabricClient.java | 13 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../resources/examplemod.fabric.mixins.json | 15 + .../Fabric/src/main/resources/fabric.mod.json | 45 +++ 1.18/Forge/build.gradle | 28 ++ .../java/fuzs/examplemod/ExampleModForge.java | 25 ++ .../client/ExampleModForgeClient.java | 17 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../src/main/resources/META-INF/mods.toml | 40 ++ .../resources/examplemod.forge.mixins.json | 15 + 1.18/build.gradle | 12 + 1.18/gradle.properties | 37 ++ 1.18/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle}/wrapper/gradle-wrapper.properties | 3 +- gradlew => 1.18/gradlew | 18 +- gradlew.bat => 1.18/gradlew.bat | 15 +- 1.18/settings.gradle | 23 ++ 1.19/.idea/scopes/Fabric_sources.xml | 3 + 1.19/.idea/scopes/Forge_sources.xml | 3 + CHANGELOG.md => 1.19/CHANGELOG.md | 0 1.19/Common/build.gradle | 11 + .../java/fuzs/armorstatues/ArmorStatues.java | 0 .../fuzs/armorstatues/api/StatuesApi.java | 0 .../api/client/StatuesApiClient.java | 0 .../gui/components/BoxedSliderButton.java | 0 .../gui/components/LiveSliderButton.java | 0 .../gui/components/NewTextureButton.java | 0 .../components/NewTextureSliderButton.java | 0 .../gui/components/NewTextureTickButton.java | 0 .../client/gui/components/TickBoxButton.java | 0 .../api/client/gui/components/TickButton.java | 0 .../client/gui/components/TickingButton.java | 0 .../gui/components/UnboundedSliderButton.java | 0 .../gui/components/VerticalSliderButton.java | 0 .../AbstractArmorStandPositionScreen.java | 0 .../armorstand/AbstractArmorStandScreen.java | 0 .../armorstand/ArmorStandEquipmentScreen.java | 0 .../ArmorStandInInventoryRenderer.java | 0 .../armorstand/ArmorStandPosesScreen.java | 0 .../armorstand/ArmorStandPositionScreen.java | 0 .../armorstand/ArmorStandRotationsScreen.java | 0 .../screens/armorstand/ArmorStandScreen.java | 0 .../armorstand/ArmorStandScreenFactory.java | 0 .../armorstand/ArmorStandStyleScreen.java | 0 .../armorstand/ArmorStandTickBoxScreen.java | 0 .../armorstand/ArmorStandWidgetsScreen.java | 0 .../api/helper/ArmorStandInteractHelper.java | 0 .../client/C2SArmorStandNameMessage.java | 0 .../client/C2SArmorStandPoseMessage.java | 0 .../client/C2SArmorStandPositionMessage.java | 0 .../client/C2SArmorStandRotationMessage.java | 0 .../client/C2SArmorStandStyleMessage.java | 0 .../network/client/data/DataSyncHandler.java | 0 .../client/data/NetworkDataSyncHandler.java | 0 .../armorstatues/api/proxy/ClientProxy.java | 0 .../fuzs/armorstatues/api/proxy/Proxy.java | 0 .../armorstatues/api/proxy/ServerProxy.java | 0 .../decoration/ArmorStandDataProvider.java | 0 .../api/world/inventory/ArmorStandHolder.java | 0 .../api/world/inventory/ArmorStandMenu.java | 0 .../inventory/data/ArmorStandAlignment.java | 0 .../world/inventory/data/ArmorStandPose.java | 0 .../inventory/data/ArmorStandScreenType.java | 0 .../inventory/data/ArmorStandStyleOption.java | 0 .../data/ArmorStandStyleOptions.java | 0 .../world/inventory/data/PosePartMutator.java | 0 .../client/ArmorStatuesClient.java | 0 .../ArmorStandAlignmentsScreen.java | 0 .../handler/ArmorStandTooltipHandler.java | 0 .../armorstatues/config/ClientConfig.java | 0 .../armorstatues/core/CommonAbstractions.java | 0 .../fuzs/armorstatues/core/ModServices.java | 0 .../handler/ArmorStandInteractHandler.java | 0 .../handler/DataSyncTickHandler.java | 0 .../fuzs/armorstatues/init/ModRegistry.java | 0 .../mixin/accessor/ArmorStandAccessor.java | 0 .../accessor/SimpleContainerAccessor.java | 0 .../armorstatues/network/S2CPingMessage.java | 0 .../client/data/CommandDataSyncHandler.java | 0 .../data/VanillaTweaksDataSyncHandler.java | 0 .../fuzs/armorstatues/proxy/ClientProxy.java | 0 .../java/fuzs/armorstatues/proxy/Proxy.java | 0 .../fuzs/armorstatues/proxy/ServerProxy.java | 0 .../resources/armorstatues.common.mixins.json | 0 .../Common}/src/main/resources/mod_banner.png | Bin .../Common}/src/main/resources/mod_logo.png | Bin 1.19/Common/src/main/resources/pack.mcmeta | 8 + 1.19/Fabric/build.gradle | 29 ++ .../fuzs/armorstatues/ArmorStatuesFabric.java | 0 .../client/ArmorStatuesFabricClient.java | 0 .../armorstatues/core/FabricAbstractions.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../fuzs.armorstatues.core.CommonAbstractions | 0 .../src/main/resources/fabric.mod.json | 8 +- 1.19/Forge/build.gradle | 29 ++ .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 +- .../resources/assets/statues/lang/en_us.json | 0 .../fuzs/armorstatues/ArmorStatuesForge.java | 0 .../client/ArmorStatuesForgeClient.java | 0 .../armorstatues/core/ForgeAbstractions.java | 0 .../data/ModLanguageProvider.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 40 ++ .../fuzs.armorstatues.core.CommonAbstractions | 0 .../gui/container/statue/background.png | Bin .../gui/container/statue/equipment.png | Bin .../textures/gui/container/statue/widgets.png | Bin .../textures/item/empty_armor_slot_sword.png | Bin 1.19/build.gradle | 12 + gradle.properties => 1.19/gradle.properties | 32 +- 1.19/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes 1.19/gradle/wrapper/gradle-wrapper.properties | 6 + 1.19/gradlew | 244 +++++++++++ 1.19/gradlew.bat | 92 +++++ 1.19/settings.gradle | 23 ++ 1.20/.idea/scopes/Fabric_sources.xml | 3 + 1.20/.idea/scopes/Forge_sources.xml | 3 + 1.20/CHANGELOG.md | 9 + 1.20/Common/build.gradle | 11 + .../main/java/fuzs/examplemod/ExampleMod.java | 16 + .../examplemod/client/ExampleModClient.java | 7 + .../resources/examplemod.common.mixins.json | 15 + 1.20/Common/src/main/resources/mod_banner.png | Bin 0 -> 17858 bytes 1.20/Common/src/main/resources/mod_logo.png | Bin 0 -> 6537 bytes 1.20/Common/src/main/resources/pack.mcmeta | 8 + 1.20/Fabric/build.gradle | 29 ++ .../fuzs/examplemod/ExampleModFabric.java | 12 + .../client/ExampleModFabricClient.java | 13 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../resources/examplemod.fabric.mixins.json | 15 + .../Fabric/src/main/resources/fabric.mod.json | 45 +++ 1.20/Forge/build.gradle | 28 ++ .../java/fuzs/examplemod/ExampleModForge.java | 31 ++ .../client/ExampleModForgeClient.java | 17 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../src/main/resources/META-INF/mods.toml | 40 ++ .../resources/examplemod.forge.mixins.json | 15 + 1.20/build.gradle | 12 + 1.20/gradle.properties | 37 ++ 1.20/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes 1.20/gradle/wrapper/gradle-wrapper.properties | 6 + 1.20/gradlew | 244 +++++++++++ 1.20/gradlew.bat | 92 +++++ 1.20/settings.gradle | 23 ++ Common/build.gradle | 140 ------- Common/src/main/resources/pack.mcmeta | 6 - Common/src/main/resources/quilt.mod.json | 8 - Fabric/build.gradle | 280 ------------- Forge/build.gradle | 378 ------------------ Forge/src/main/resources/META-INF/mods.toml | 41 -- LICENSE-ASSETS.md | 1 + LICENSE => LICENSE.md | 0 build.gradle | 122 ------ gradle/tasks.gradle | 232 ----------- gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes run/config/modmenu.json | 19 - run/options.txt | 131 ------ settings.gradle | 28 -- 177 files changed, 1904 insertions(+), 1438 deletions(-) delete mode 100644 .gitattributes create mode 100644 .idea/gradle.xml create mode 100644 1.18/.idea/scopes/Fabric_sources.xml create mode 100644 1.18/.idea/scopes/Forge_sources.xml create mode 100644 1.18/CHANGELOG.md create mode 100644 1.18/Common/build.gradle create mode 100644 1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java create mode 100644 1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java create mode 100644 1.18/Common/src/main/resources/examplemod.common.mixins.json create mode 100644 1.18/Common/src/main/resources/mod_banner.png create mode 100644 1.18/Common/src/main/resources/mod_logo.png create mode 100755 1.18/Common/src/main/resources/pack.mcmeta create mode 100644 1.18/Fabric/build.gradle create mode 100644 1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java create mode 100644 1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java create mode 100644 1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json create mode 100644 1.18/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.18/Forge/build.gradle create mode 100644 1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java create mode 100644 1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java create mode 100644 1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.18/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.18/Forge/src/main/resources/examplemod.forge.mixins.json create mode 100644 1.18/build.gradle create mode 100755 1.18/gradle.properties create mode 100644 1.18/gradle/wrapper/gradle-wrapper.jar rename {gradle => 1.18/gradle}/wrapper/gradle-wrapper.properties (84%) rename gradlew => 1.18/gradlew (93%) rename gradlew.bat => 1.18/gradlew.bat (89%) create mode 100644 1.18/settings.gradle create mode 100644 1.19/.idea/scopes/Fabric_sources.xml create mode 100644 1.19/.idea/scopes/Forge_sources.xml rename CHANGELOG.md => 1.19/CHANGELOG.md (100%) create mode 100644 1.19/Common/build.gradle rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/ArmorStatues.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/StatuesApi.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/config/ClientConfig.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/core/ModServices.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/init/ModRegistry.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/proxy/Proxy.java (100%) rename {Common => 1.19/Common}/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java (100%) rename {Common => 1.19/Common}/src/main/resources/armorstatues.common.mixins.json (100%) rename {Common => 1.19/Common}/src/main/resources/mod_banner.png (100%) rename {Common => 1.19/Common}/src/main/resources/mod_logo.png (100%) create mode 100755 1.19/Common/src/main/resources/pack.mcmeta create mode 100644 1.19/Fabric/build.gradle rename {Fabric => 1.19/Fabric}/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java (100%) rename {Fabric => 1.19/Fabric}/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java (100%) rename {Fabric => 1.19/Fabric}/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java (100%) rename {Fabric => 1.19/Fabric}/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java (100%) rename {Fabric => 1.19/Fabric}/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions (100%) rename {Fabric => 1.19/Fabric}/src/main/resources/fabric.mod.json (88%) create mode 100644 1.19/Forge/build.gradle rename {Forge => 1.19/Forge}/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 (57%) rename {Forge => 1.19/Forge}/src/generated/resources/assets/statues/lang/en_us.json (100%) rename {Forge => 1.19/Forge}/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java (100%) rename {Forge => 1.19/Forge}/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java (100%) rename {Forge => 1.19/Forge}/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java (100%) rename {Forge => 1.19/Forge}/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java (100%) rename {Forge => 1.19/Forge}/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java (100%) create mode 100644 1.19/Forge/src/main/resources/META-INF/mods.toml rename {Forge => 1.19/Forge}/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions (100%) rename {Forge => 1.19/Forge}/src/main/resources/assets/statues/textures/gui/container/statue/background.png (100%) rename {Forge => 1.19/Forge}/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png (100%) rename {Forge => 1.19/Forge}/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png (100%) rename {Forge => 1.19/Forge}/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png (100%) create mode 100644 1.19/build.gradle rename gradle.properties => 1.19/gradle.properties (66%) create mode 100644 1.19/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.19/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.19/gradlew create mode 100644 1.19/gradlew.bat create mode 100644 1.19/settings.gradle create mode 100644 1.20/.idea/scopes/Fabric_sources.xml create mode 100644 1.20/.idea/scopes/Forge_sources.xml create mode 100644 1.20/CHANGELOG.md create mode 100644 1.20/Common/build.gradle create mode 100644 1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java create mode 100644 1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java create mode 100644 1.20/Common/src/main/resources/examplemod.common.mixins.json create mode 100644 1.20/Common/src/main/resources/mod_banner.png create mode 100644 1.20/Common/src/main/resources/mod_logo.png create mode 100755 1.20/Common/src/main/resources/pack.mcmeta create mode 100644 1.20/Fabric/build.gradle create mode 100644 1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java create mode 100644 1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java create mode 100644 1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.20/Fabric/src/main/resources/examplemod.fabric.mixins.json create mode 100644 1.20/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.20/Forge/build.gradle create mode 100644 1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java create mode 100644 1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java create mode 100644 1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.20/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.20/Forge/src/main/resources/examplemod.forge.mixins.json create mode 100644 1.20/build.gradle create mode 100755 1.20/gradle.properties create mode 100644 1.20/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.20/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.20/gradlew create mode 100644 1.20/gradlew.bat create mode 100644 1.20/settings.gradle delete mode 100644 Common/build.gradle delete mode 100755 Common/src/main/resources/pack.mcmeta delete mode 100644 Common/src/main/resources/quilt.mod.json delete mode 100644 Fabric/build.gradle delete mode 100644 Forge/build.gradle delete mode 100644 Forge/src/main/resources/META-INF/mods.toml create mode 100644 LICENSE-ASSETS.md rename LICENSE => LICENSE.md (100%) delete mode 100644 build.gradle delete mode 100644 gradle/tasks.gradle delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 run/config/modmenu.json delete mode 100644 run/options.txt delete mode 100644 settings.gradle diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 629f0ed..7726363 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -1,6 +1,6 @@ name: Bug Report description: >- - Please use this template when you have encountered a bug in this mod. + 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]: ' labels: ["bug"] assignees: @@ -27,7 +27,7 @@ body: attributes: label: Minecraft Version (Required) description: What is the Minecraft version you are playing with? - placeholder: ex. 1.19 + placeholder: ex. 1.20.1 validations: required: true - type: input @@ -35,7 +35,7 @@ body: attributes: label: Mod Version (Required) description: What version of the mod are you playing with? - placeholder: ex. v4.0.0 + placeholder: ex. v8.0.0 validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7f79bf6..e0133b0 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 - url: https://discord.gg/8ZmhaPPbjE - about: "Please ask questions on the Luna Pixel Studios Discord (in #fuzs-projects) or contact me directly on Discord at Fuzs#0212." \ No newline at end of file + url: https://lunapixel.studio/discord + about: "Please ask questions on the Luna Pixel Studios Discord in #fuzs-projects." \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 690bc86..5ca6180 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -1,6 +1,6 @@ name: Crash Report description: >- - Please use this template when this mod has caused your game to crash. + 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"] assignees: @@ -27,7 +27,7 @@ body: attributes: label: Minecraft Version (Required) description: What is the Minecraft version you are playing with? - placeholder: ex. 1.19 + placeholder: ex. 1.20.1 validations: required: true - type: input @@ -35,7 +35,7 @@ body: attributes: label: Mod Version (Required) description: What version of the mod are you playing with? - placeholder: ex. v4.0.0 + placeholder: ex. v8.0.0 validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml index b4d3720..0eb9a33 100644 --- a/.github/ISSUE_TEMPLATE/suggestion.yml +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -1,6 +1,6 @@ name: Suggestion description: >- - Please use this template when you want to suggest a feature. + 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]: ' labels: ["enhancement"] assignees: diff --git a/.gitignore b/.gitignore index 29fed19..223cbb5 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,9 @@ classes *.ipr *.iws *.iml -.idea/* -!.idea/scopes +**/.idea/* +!**/.idea/scopes +!.idea/gradle.xml ### NetBeans ### nbproject/private/ @@ -59,14 +60,9 @@ gradle-app.setting .gradletasknamecache ### Other ### +run .DS_Store *.txt -!run -run/* -!run/options.txt -!run/config -run/config/* -!run/config/modmenu.json # Log file *.log diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..311bce0 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,44 @@ + + + + + + + \ No newline at end of file diff --git a/1.18/.idea/scopes/Fabric_sources.xml b/1.18/.idea/scopes/Fabric_sources.xml new file mode 100644 index 0000000..0448412 --- /dev/null +++ b/1.18/.idea/scopes/Fabric_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.18/.idea/scopes/Forge_sources.xml b/1.18/.idea/scopes/Forge_sources.xml new file mode 100644 index 0000000..7b5f24d --- /dev/null +++ b/1.18/.idea/scopes/Forge_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.18/CHANGELOG.md b/1.18/CHANGELOG.md new file mode 100644 index 0000000..916e567 --- /dev/null +++ b/1.18/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]. + +## [v3.0.0-1.18.2] - 2023-06-25 +- Ported to Minecraft 1.18.2 + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.18/Common/build.gradle b/1.18/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.18/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.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.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java new file mode 100644 index 0000000..45113b2 --- /dev/null +++ b/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java @@ -0,0 +1,16 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExampleMod implements ModConstructor { + public static final String MOD_ID = "examplemod"; + public static final String MOD_NAME = "Example Mod"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java new file mode 100644 index 0000000..e1afacc --- /dev/null +++ b/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java @@ -0,0 +1,7 @@ +package fuzs.examplemod.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; + +public class ExampleModClient implements ClientModConstructor { + +} diff --git a/1.18/Common/src/main/resources/examplemod.common.mixins.json b/1.18/Common/src/main/resources/examplemod.common.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.18/Common/src/main/resources/examplemod.common.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.18/Common/src/main/resources/mod_banner.png b/1.18/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..bda5a0f63968a9c20cc144359547c6d8bb1e893b GIT binary patch literal 17858 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 literal 0 HcmV?d00001 diff --git a/1.18/Common/src/main/resources/mod_logo.png b/1.18/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..98c247e46e4c250202abe7f66209dd16464ade34 GIT binary patch literal 6537 zcmV;48FuE0P)pOk{gJ(ID36A2T30nlM=2{R95XH@ zkcd!;aY}b)I%ZimPCP6(G#ff(GBR5&wUkGQXE}FRH$hTtI%6(KbT?8@Ey0~buZcX9 zZ#F+rYe!i%Z%i#MRwg1m9i?wLhFLf@DjQ-%9!oVFDkd8n926BA4Qf9vB_kOj9Th7p zByyBakXk~IQ#CkPD_3YZOKB}+ol0$_RbP}yZgDnbi9}3%I&-2|ScybgcRE~?Lsg1C zW|&BBs!dXaJ!qv!YottdvQv4tR(`=*jKpknu2FojW^k-dcCu5|mM`uT=$>S9(5*#!e)5fT0hIkYt5(pOsJ5@*X^z)*|?WwJ+@$To9 zw9Tc-?XS=9M^{-lMpjN*YI~EY?eUTa{8J)xJd7_nnqN10Kb5?j(MQJw6=>IrQQ`pV59V{#9@$=c`>?A`Y zxvGlg=jOM@%q%!WRA*?$;rK36FqOUPZH#X%Ml`s(xJFJJG9jdFj9)z{aPm6K0zON4u8&%mC^=KmQR8WSWBEmJBcL>>JoQ%cg5Y^x4XOBarawwd(DJEQDnom^Xa^mP%s5Nc{{5orqkrV$Vc)onI_lZ zk+@7>R_~goWOBKAD9g#DsjGh()&$jn9B&PwBN=Lq0}q2R$zMQ)rp=;muCA_G2mA!# z$4}C_ySl3D#U?a|-k+6)uFV#hxwQczKYiwCrip>I9N?`c^!{wL>>8Api=f^uXeB`M zWugLQ%lYYEx;SoLT$X|UJZ+QBQH1`ySFP0>r99!MXqq0NX{tvb=w)n=HXj20>FmSi zWrVhN+8ri1*(jA+dY~JidvXt-_OBsyx%sKBVQRQ-q1x%R%}c>a?F<3#ek@e^sGJA8 zyoOs34$7ZW7r(dXFLYKIhT*=d+ZrVd(=mge%7zU zWg~~>UrL@=In+wNmOo<5t|m;G@wS<5GgqtCmV$OgbNXP=ESAexx9q}Wz7y!cl(|~9Ua#-iM-)v2cz^~P+g+Zbc%G(t3g*5a46C7a4?-_DK5X3b zV6uodFL)U<$8pfr;jr25Acx%%eVZ_3xD|@FTJa?-O;w1V42?qx7YQ<#nSZt7UNJnX1g-6FULfWu(!S*AKpT_>#uK|-d!F-g|8p$ zyBmb6KiHr!1Yp9?vOK0ORKbE5Q13Se~a?A~q(9VaSXc8cs~51A)Nzp3}+TCWoMJ8wYRjk{u3~ zO;HqZ8znbkM3*Z#-NG#X=wM@FSewB~30JOS*BeM@JZSXV$+GN%bM zbHI=lhs~jAr5I6R!375gyWQaT+QPcSv!1hO&w4yJg>zS@9tRBhHu~<`hJ2#jLWTB) z>Qb#6xI<4m91eIwVP_1BN5k{HvCIH_Qa5pg?77aAE~nE{rhs0~JwHKqjiVQBE?5u3 z8UUF!)fI&AJ4NY{${8XQ?K$AXkHg$7;UJ#-oD2!b%hNYi=Mla@E?_Z=Q+N?1g zR(I?WsH$jiSVYn3bo+cHjm!1LW8zF|{(f{K6xv%)Oih6cumo^o6BXv<6Beo7=D4aL z2s;kwscGSo)9nT`5{ZxlR;$JG9vU}Rg^AGK(>KEj>_XB~T#9G12+jTaKDmXI4s#_d zKt^W6B@s|xgoIf1SarE?0QRVAG_-dS;B*g;OYbrxX#By3+_&&J+FD_lE58f#g6avo zV?Njuk~UBp0Bl>1qxBbMiHyBUsj86Od$SIAkAN|1faB?O<~%AqaP=Q_uF5dyLecy4 z^XiP~BY6Wmpp4Sp=wR=%4$lItX7|>gCEleWaH#dhl9c%)haU7Db`f3Lu5nx_8jaq^ zjU(jYKzSUD;KxCDvKyZ`qc?`ai8zqhmLzyc|C3s=0DKBcP)Rh%C#1Z=evMtfDt2Nd%2!BolaJxDc!;7fWc*p)W;cfD#TQS- zN7koa6wJd8(&{V-a#3Unpzqy3+#-AYmMifOWis+>`y?s&`6YxD8-t;5_~<8+XD=;y z3!7_vJTOC1uFY>ZQ}gYfRnMX;dx_XL{`}qD-~REVEGm0X{I{EnGHTrk7cejL{2*A+ zEY9o&$s>`>ukaRLN{lsQd@n;~eMY}DS3P$~M=T$GclUP`b)OcJP08#$97Urr(H_<3!^ zL%WnIt9;>4^v$iv!1Od;|2}I5Dt7NuF%5#=RAHZebe_PY@xP|`#bJ2h;68uOvim@7#@=;Q!7r)qwh~e~w3NnGjFp>N1 zCBATYpIWUZuER%K-A{VGkas(2PhYz+y%oyOkHJ=dGVI!yo2$;fbH_FB85Lwe9&yEf zKWLV9TGcK->fCTRPpc_ovB(=?dR2>FCyq<{3AQt7Hd$he&u6tK!%I{mQo%t!yCH%( z4%>^>=oE$f9~3^=U#OHQ%FFfIiZYbEZJ+Yyy?C_a^!RdmBtlw^N4bv?!U2UfNKdudl%_zS;QU-eoY$pNIkzM)84u}0v_^t|@jj#=wwabrHe!sI!g zsXdqmKA3SR=iWbla8U9oT7VaERwu)LC(aA0_HfmKy1F;sXgX3Kg-a_mYb=YmvZr!? zVv#@dp3QG;Zf+*@gazYi?V1>_JyY9!o zLE4SgfLRO#gPUHJYRVPvj#1r_fKJ0~AQ))|yl4fRcRbxm;V8vq}3 z4=!T@`jS@U-A-)k^Tlx&Fg^t4`cvU6t+Dh|vhR0Yaz^K?zZa}vI*Bgz;tKaPC z?CRpW7p?xO2A&Sv!z;GulGjr+SxfPPO<&<4L{}Q<5u)$D7;G^~J#^Z1PwECE- zi@?-8?W)8P5`UT^jrq;Q#dymE=R~cpq-02RsLD!yjzw_WN*kilmm7+V^+%5$0ZVeM zn}^q3^g_q}1pF>wvcBXo<^Z>{FFm=kr;<)3I>YpkXh zOb?#M;hPcC=g`OiCJ=5?3@^^dGPFsjoYgYG$rDH$XuyY!$B!F%wxg`9Y-FgH>&JLBp8hLg5lku`A#`wZ zaxMiP^~N$Pejlg87&`2LHJTEQ2Bosw2#*dTVmP{`$>_r{fcsx*0vVO2f$e_O47jb$ zjx&<&C)tj>tOzE1D>nMPBJ8EXQ0t;r`?*-0ZFb^Dza*f-jl!J*d=rCDGz50O0z3*g z8!juVm{a*IK0eGOhD*5Y8cOG7!0IIUo9ThANT?t`20Meh!caloN1tVFb`jiXnVp@r zIKp9Dm|XrK_BJQE=j(**2E4P?^SC{n9w|V(Bm5c%2LUHb(IocQo?Hs`uFTm*&#`KD z7DJX}Sd9xH2PZ8n({MqC;iT?P#C^q;1iyd1?|O9fu}m|;pa7@M)jbO;3i&YT^Kl~B zg5eHuSUonT4y&YQvy@|Ie2mmYVADE|Oj8{G7wwrIm>!4#9vSGvkr_;d?=KETv$!yS z2Oo;A_`rv#QL1Z(tTOcbKA?@~SZV2%}E{KL>!u zSS^OhoNm`(qTv|pnfF|-%kS+|RT9`GhQk3|u>qdJclkm}Y4kg2l@ZaSb zHm3--jRg>;^1y)yg=1qem}3NZmt>PqIlf>8y=u~8Q}4VGfQu1?T%vydxs4OUfq+7x zkSI@_IH6Q311*5ffc?9|!noipsVFm%C0^*{_m(hO7x3;hZjBwEJI;t+$nEf8#JV5?0bfl1QSV=PidVdhog zAmEP9Y>U7n{1}t~IfxthOY)U>(U|cD7R-@CYm#D?$Ngh5kmXniX zr6|{vc&-k~DLKRVii}1B@7A2u>57c)^+=T*-xg1H4f*d^4xQAo+4NMUS#eu*ZS2_s z9GWbNxbdPxkqw64w+{6hj7EK_{;=Wn>380F z`!|q(G%NqF)?8xRIJ+=hdxz{`Br90dE>1EOjH6T@q=@1aVN_$(F;jaczKkzG9CHbj z%r2@_sjC)sQzWEzgVIG>{r{p(5Ie^^o32tyqCh1pgpCVrsH(`4WqE;>Mc*@?*q}g4 z2wC)zYy(Dq=3Hjxo8t+KEcaMmXmXj#2TjVKVI6Q|{?s72ETvnk?6f?5hysHyR5&Pl z{n(K|wBc&d9}I^>d?d>4rDt_NxOQA+L*a0MEm6Q~YwfQx*7aE3&g%@#ZEaA0T!lXs z(9MIi7qD#5+pZizx;onZLdX}3M}|j6M~KlYS4Kxi5;2L7#pCgaLY#*)1bpGEa>3#< zmS3huZ561_eoqClkXEClMGvIst}9#*&dpGMP}pTMCKTg#5_kc`;!1RI%{G zX^3%L=;%1pJvWyYRj(-ObnTZe!QB24I(uk{6{7*TA`n9q;Sm;oqhBfPeUN`Fd36CR z01KUo4=`{24@Z$(`VLsTy1O}Ujzy|{J|)?R_@WZ=d+&F2cRSLo7!JV<8HoGBQM4J= zdn}o(DTfI~J`!n=Zw@dxS{_XC|MKTIAok)g0YnOl>cyjO(xCr>KR7gWrmKtNFl(cj zLnH%ySQHgAl8mrx=DK%6USeEkYw^%KA}}E~p@#@vfI_OmLoEb@LurQtnK(~VJ}oPX zljs|skMW^NmL+qwos(p)Dpl{bDVY*&KxZ9de)3da*7(uT!XV%QQtb;N(@{}O+t1g5 z8M4VRq7DV3tTwHfu^p7~x>>Pb8(GHMk};vP4mbZHHwe?y(}Qho)6;PtPEn+Tq*iN( zHeW?GLk3$kI*I>qC<%y?Taw6J2W20ZSKJ=66`gfB*=4yTK}<-Yz$9yj4uh|~)T1Vy z$g-@~VMqL=CNoOCr_Ljhrx={NYP;}ZWnNz(^PnUN0`kk+S2MSrP7Ei&elM9R-GD_> z$g6147&S3=q~SY&eX3D|xPV zV=_TJ7spES13mU66!_)*_GJAhd18{n}`xnSKX?-?xn^$ig{5kX&q=}M}C!3U9B-S*?u#< z*zM?edU80@O6FBNNW>}67AIK&<_x_Sv-zwUkF(cXQw#D^W536uDHkDlHFdceL2rLLlTpgJLrz>QSuCV( zsR8df@`7Ho&1SOMY<-;u6zV23z?du9*<;*poZZ}fggQN5MSpYoogL(`8z7ghH7~<3 zG-FV_5SvUUTc2iyMven6i^-Zj=H2rtLv9({ezynee4b0QL7grb^bSGKwE~MmXRnHx z0Y4K#$jeTN}!1zCQ5w#o)$Ge`Oc;{VeXT8EUA8uBFynH$2S7i~+;KdHQ`2lMXKU6sB+r&p vxYMG>rZrVwd$ZEIeYUt&qc{uae};bm+U`)~9h?8j00000NkvXXu0mjfr5A3W literal 0 HcmV?d00001 diff --git a/1.18/Common/src/main/resources/pack.mcmeta b/1.18/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..19bfab2 --- /dev/null +++ b/1.18/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} + } +} diff --git a/1.18/Fabric/build.gradle b/1.18/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.18/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // 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())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java new file mode 100644 index 0000000..124b062 --- /dev/null +++ b/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java @@ -0,0 +1,12 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.fabricmc.api.ModInitializer; + +public class ExampleModFabric implements ModInitializer { + + @Override + public void onInitialize() { + ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); + } +} diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java new file mode 100644 index 0000000..7b55517 --- /dev/null +++ b/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java @@ -0,0 +1,13 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import net.fabricmc.api.ClientModInitializer; + +public class ExampleModFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); + } +} diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..6d413e8 --- /dev/null +++ b/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.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.18/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.18/Fabric/src/main/resources/fabric.mod.json b/1.18/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..07fc00c --- /dev/null +++ b/1.18/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,45 @@ +{ + "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}" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.18/Forge/build.gradle b/1.18/Forge/build.gradle new file mode 100644 index 0000000..dec494a --- /dev/null +++ b/1.18/Forge/build.gradle @@ -0,0 +1,28 @@ +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()) + + // 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.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java new file mode 100644 index 0000000..18d3c6f --- /dev/null +++ b/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java @@ -0,0 +1,25 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraft.data.DataGenerator; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; + +@Mod(ExampleMod.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ExampleModForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + } +} diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java new file mode 100644 index 0000000..d6502ba --- /dev/null +++ b/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +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 = ExampleMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ExampleModForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); + } +} diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..af281eb --- /dev/null +++ b/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.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.18/Forge/src/main/resources/META-INF/mods.toml b/1.18/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.18/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.18/Forge/src/main/resources/examplemod.forge.mixins.json b/1.18/Forge/src/main/resources/examplemod.forge.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.18/Forge/src/main/resources/examplemod.forge.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.18/build.gradle b/1.18/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.18/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.18/gradle.properties b/1.18/gradle.properties new file mode 100755 index 0000000..02bba8d --- /dev/null +++ b/1.18/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=examplemod +modName=Example Mod +modVersion=3.0.0 +modAuthor=Fuzs +modDescription=Example description. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/examplemod +modIssueUrl=https://github.com/Fuzss/examplemod/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/examplemod.json +modMavenGroup=fuzs.examplemod +# "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=0 +projectModrinthId=0 + +dependenciesVersionCatalog=1.18.2-v6 +#dependenciesPuzzlesLibVersion=3.0.0 +#dependenciesMinPuzzlesLibVersion=3.0.0 +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.18/gradle/wrapper/gradle-wrapper.jar b/1.18/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/gradle/wrapper/gradle-wrapper.properties b/1.18/gradle/wrapper/gradle-wrapper.properties similarity index 84% rename from gradle/wrapper/gradle-wrapper.properties rename to 1.18/gradle/wrapper/gradle-wrapper.properties index 41dfb87..f398c33 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/1.18/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/1.18/gradlew similarity index 93% rename from gradlew rename to 1.18/gradlew index 1b6c787..65dcd68 100755 --- a/gradlew +++ b/1.18/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# 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/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# 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"' @@ -143,12 +143,16 @@ fi 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 @@ -205,6 +209,12 @@ set -- \ 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. diff --git a/gradlew.bat b/1.18/gradlew.bat similarity index 89% rename from gradlew.bat rename to 1.18/gradlew.bat index 107acd3..93e3f59 100644 --- a/gradlew.bat +++ b/1.18/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +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! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +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 diff --git a/1.18/settings.gradle b/1.18/settings.gradle new file mode 100644 index 0000000..bf7e2e5 --- /dev/null +++ b/1.18/settings.gradle @@ -0,0 +1,23 @@ +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/' + } + } +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/settings.gradle' diff --git a/1.19/.idea/scopes/Fabric_sources.xml b/1.19/.idea/scopes/Fabric_sources.xml new file mode 100644 index 0000000..0448412 --- /dev/null +++ b/1.19/.idea/scopes/Fabric_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.19/.idea/scopes/Forge_sources.xml b/1.19/.idea/scopes/Forge_sources.xml new file mode 100644 index 0000000..7b5f24d --- /dev/null +++ b/1.19/.idea/scopes/Forge_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/CHANGELOG.md b/1.19/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to 1.19/CHANGELOG.md diff --git a/1.19/Common/build.gradle b/1.19/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.19/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.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/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.19/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/ArmorStatues.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java diff --git a/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java diff --git a/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java diff --git a/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java diff --git a/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java diff --git a/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java b/1.19/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java diff --git a/Common/src/main/java/fuzs/armorstatues/core/ModServices.java b/1.19/Common/src/main/java/fuzs/armorstatues/core/ModServices.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/core/ModServices.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/core/ModServices.java diff --git a/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java diff --git a/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java b/1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java diff --git a/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java b/1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java diff --git a/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java diff --git a/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java diff --git a/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.19/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java diff --git a/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.19/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java diff --git a/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.19/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java similarity index 100% rename from Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java diff --git a/Common/src/main/resources/armorstatues.common.mixins.json b/1.19/Common/src/main/resources/armorstatues.common.mixins.json similarity index 100% rename from Common/src/main/resources/armorstatues.common.mixins.json rename to 1.19/Common/src/main/resources/armorstatues.common.mixins.json diff --git a/Common/src/main/resources/mod_banner.png b/1.19/Common/src/main/resources/mod_banner.png similarity index 100% rename from Common/src/main/resources/mod_banner.png rename to 1.19/Common/src/main/resources/mod_banner.png diff --git a/Common/src/main/resources/mod_logo.png b/1.19/Common/src/main/resources/mod_logo.png similarity index 100% rename from Common/src/main/resources/mod_logo.png rename to 1.19/Common/src/main/resources/mod_logo.png diff --git a/1.19/Common/src/main/resources/pack.mcmeta b/1.19/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..19bfab2 --- /dev/null +++ b/1.19/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} + } +} diff --git a/1.19/Fabric/build.gradle b/1.19/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.19/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // 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())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/1.19/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java similarity index 100% rename from Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java rename to 1.19/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java diff --git a/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java similarity index 100% rename from Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java rename to 1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java diff --git a/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java b/1.19/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java similarity index 100% rename from Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java rename to 1.19/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java diff --git a/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java b/1.19/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java similarity index 100% rename from Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java rename to 1.19/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java diff --git a/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions b/1.19/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions similarity index 100% rename from Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions rename to 1.19/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions diff --git a/Fabric/src/main/resources/fabric.mod.json b/1.19/Fabric/src/main/resources/fabric.mod.json similarity index 88% rename from Fabric/src/main/resources/fabric.mod.json rename to 1.19/Fabric/src/main/resources/fabric.mod.json index e370de7..c0c6cfa 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/1.19/Fabric/src/main/resources/fabric.mod.json @@ -5,19 +5,22 @@ "name": "${modName}", "description": "${modDescription}", + "authors": [ "${modAuthor}" ], + "contact": { "homepage": "${modPageUrl}", "issues": "${modIssueUrl}", "sources": "${modPageUrl}" }, - "license": "MPL-2", + "license": "${modLicense}", "icon": "mod_logo.png", "environment": "${modFabricEnvironment}", + "entrypoints": { "main": [ "${mainEntryPoint}" @@ -26,6 +29,7 @@ "${clientEntryPoint}" ] }, + "mixins": [ "${modId}.common.mixins.json" ], @@ -34,7 +38,7 @@ "fabricloader": ">=${minFabricVersion}", "fabric-api": ">=${minFabricApiVersion}", "puzzleslib": ">=${minPuzzlesVersion}", - "minecraft": ">=${minMinecraftVersion} <${nextMinecraftVersion}", + "minecraft": "${minecraftVersion}", "java": ">=17" } } diff --git a/1.19/Forge/build.gradle b/1.19/Forge/build.gradle new file mode 100644 index 0000000..fc4b4de --- /dev/null +++ b/1.19/Forge/build.gradle @@ -0,0 +1,29 @@ +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()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.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/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 similarity index 57% rename from Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 rename to 1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index ba6e082..6a58d4b 100644 --- a/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-27T12:48:23.744062 Languages: en_us +// 1.19.2 2023-07-27T17:46:25.105531 Languages: en_us d04e0f1fd3fc55a1ca05d332b79edacf16759019 assets/statues/lang/en_us.json diff --git a/Forge/src/generated/resources/assets/statues/lang/en_us.json b/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json similarity index 100% rename from Forge/src/generated/resources/assets/statues/lang/en_us.json rename to 1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json diff --git a/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.19/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java similarity index 100% rename from Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java rename to 1.19/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java diff --git a/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java similarity index 100% rename from Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java rename to 1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java diff --git a/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java b/1.19/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java similarity index 100% rename from Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java rename to 1.19/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java diff --git a/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java similarity index 100% rename from Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java rename to 1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java diff --git a/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java b/1.19/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java similarity index 100% rename from Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java rename to 1.19/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java diff --git a/1.19/Forge/src/main/resources/META-INF/mods.toml b/1.19/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.19/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/Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions b/1.19/Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions similarity index 100% rename from Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions rename to 1.19/Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png b/1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png rename to 1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png b/1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png rename to 1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png diff --git a/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png b/1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png rename to 1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png diff --git a/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png b/1.19/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png similarity index 100% rename from Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png rename to 1.19/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png diff --git a/1.19/build.gradle b/1.19/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.19/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/gradle.properties b/1.19/gradle.properties similarity index 66% rename from gradle.properties rename to 1.19/gradle.properties index 337d04d..69215ce 100755 --- a/gradle.properties +++ b/1.19/gradle.properties @@ -3,32 +3,15 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false org.gradle.parallel=true - -# Common Project -minecraftVersion=1.19.2 -minMinecraftVersion=1.19.2 -parchmentMappingsVersion=2022.08.14 -puzzlesVersion=4.4.4 -minPuzzlesVersion=4.4.0 -packFormat=9 copyBuildJar=true -# Forge Project -forgeVersion=1.19.2-43.2.0 -minForgeVersion=43.2.0 - -# Fabric Project -fabricVersion=0.14.9 -minFabricVersion=0.14.9 -fabricApiVersion=0.60.0+1.19.2 -minFabricApiVersion=0.60.0 - # Mod Attributes modId=armorstatues modName=Armor Statues modVersion=4.0.6 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. +modLicense=MPL-2.0 modSourceUrl=https://github.com/Fuzss/armorstatues modIssueUrl=https://github.com/Fuzss/armorstatues/issues modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/armorstatues.json @@ -40,6 +23,15 @@ modFabricEnvironment=* # Mod Publishing projectReleaseType=release -projectGameVersions=1.19.2 -projectCurseId=682566 +projectCurseForgeId=682566 projectModrinthId=bbGCtEvb + +dependenciesVersionCatalog=1.19.2-v11 +#dependenciesPuzzlesLibVersion=4.0.0 +#dependenciesMinPuzzlesLibVersion=4.0.0 +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.19/gradle/wrapper/gradle-wrapper.jar b/1.19/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.19/gradle/wrapper/gradle-wrapper.properties b/1.19/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..f398c33 --- /dev/null +++ b/1.19/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/1.19/gradlew b/1.19/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.19/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.19/gradlew.bat b/1.19/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.19/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.19/settings.gradle b/1.19/settings.gradle new file mode 100644 index 0000000..bf7e2e5 --- /dev/null +++ b/1.19/settings.gradle @@ -0,0 +1,23 @@ +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/' + } + } +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/settings.gradle' diff --git a/1.20/.idea/scopes/Fabric_sources.xml b/1.20/.idea/scopes/Fabric_sources.xml new file mode 100644 index 0000000..0448412 --- /dev/null +++ b/1.20/.idea/scopes/Fabric_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.20/.idea/scopes/Forge_sources.xml b/1.20/.idea/scopes/Forge_sources.xml new file mode 100644 index 0000000..7b5f24d --- /dev/null +++ b/1.20/.idea/scopes/Forge_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md new file mode 100644 index 0000000..c7f9a93 --- /dev/null +++ b/1.20/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/Common/build.gradle b/1.20/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.20/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.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/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java new file mode 100644 index 0000000..45113b2 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java @@ -0,0 +1,16 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExampleMod implements ModConstructor { + public static final String MOD_ID = "examplemod"; + public static final String MOD_NAME = "Example Mod"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java new file mode 100644 index 0000000..e1afacc --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java @@ -0,0 +1,7 @@ +package fuzs.examplemod.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; + +public class ExampleModClient implements ClientModConstructor { + +} diff --git a/1.20/Common/src/main/resources/examplemod.common.mixins.json b/1.20/Common/src/main/resources/examplemod.common.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.20/Common/src/main/resources/examplemod.common.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20/Common/src/main/resources/mod_banner.png b/1.20/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..bda5a0f63968a9c20cc144359547c6d8bb1e893b GIT binary patch literal 17858 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 literal 0 HcmV?d00001 diff --git a/1.20/Common/src/main/resources/mod_logo.png b/1.20/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..98c247e46e4c250202abe7f66209dd16464ade34 GIT binary patch literal 6537 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 literal 0 HcmV?d00001 diff --git a/1.20/Common/src/main/resources/pack.mcmeta b/1.20/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..19bfab2 --- /dev/null +++ b/1.20/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} + } +} diff --git a/1.20/Fabric/build.gradle b/1.20/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.20/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // 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())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java new file mode 100644 index 0000000..124b062 --- /dev/null +++ b/1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java @@ -0,0 +1,12 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.fabricmc.api.ModInitializer; + +public class ExampleModFabric implements ModInitializer { + + @Override + public void onInitialize() { + ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); + } +} diff --git a/1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java new file mode 100644 index 0000000..7b55517 --- /dev/null +++ b/1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java @@ -0,0 +1,13 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import net.fabricmc.api.ClientModInitializer; + +public class ExampleModFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); + } +} diff --git a/1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..6d413e8 --- /dev/null +++ b/1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.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/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.20/Fabric/src/main/resources/examplemod.fabric.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.20/Fabric/src/main/resources/examplemod.fabric.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20/Fabric/src/main/resources/fabric.mod.json b/1.20/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..07fc00c --- /dev/null +++ b/1.20/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,45 @@ +{ + "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}" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.20/Forge/build.gradle b/1.20/Forge/build.gradle new file mode 100644 index 0000000..dec494a --- /dev/null +++ b/1.20/Forge/build.gradle @@ -0,0 +1,28 @@ +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()) + + // 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/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java new file mode 100644 index 0000000..730ddd3 --- /dev/null +++ b/1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java @@ -0,0 +1,31 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +import java.util.concurrent.CompletableFuture; + +@Mod(ExampleMod.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ExampleModForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final PackOutput packOutput = dataGenerator.getPackOutput(); + final CompletableFuture lookupProvider = evt.getLookupProvider(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + } +} diff --git a/1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java new file mode 100644 index 0000000..d6502ba --- /dev/null +++ b/1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +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 = ExampleMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ExampleModForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); + } +} diff --git a/1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..af281eb --- /dev/null +++ b/1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.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/Forge/src/main/resources/META-INF/mods.toml b/1.20/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.20/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/Forge/src/main/resources/examplemod.forge.mixins.json b/1.20/Forge/src/main/resources/examplemod.forge.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.20/Forge/src/main/resources/examplemod.forge.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20/build.gradle b/1.20/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.20/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/gradle.properties b/1.20/gradle.properties new file mode 100755 index 0000000..ac98db0 --- /dev/null +++ b/1.20/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=examplemod +modName=Example Mod +modVersion=8.0.0 +modAuthor=Fuzs +modDescription=Example description. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/examplemod +modIssueUrl=https://github.com/Fuzss/examplemod/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/examplemod.json +modMavenGroup=fuzs.examplemod +# "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=0 +projectModrinthId=0 + +dependenciesVersionCatalog=1.20.1-v7 +#dependenciesPuzzlesLibVersion=8.0.6 +#dependenciesMinPuzzlesLibVersion=8.0.6 +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/gradle/wrapper/gradle-wrapper.jar b/1.20/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/gradle/wrapper/gradle-wrapper.properties b/1.20/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37aef8d --- /dev/null +++ b/1.20/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/gradlew b/1.20/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.20/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/gradlew.bat b/1.20/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.20/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/settings.gradle b/1.20/settings.gradle new file mode 100644 index 0000000..bf7e2e5 --- /dev/null +++ b/1.20/settings.gradle @@ -0,0 +1,23 @@ +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/' + } + } +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/settings.gradle' diff --git a/Common/build.gradle b/Common/build.gradle deleted file mode 100644 index 1ea86ea..0000000 --- a/Common/build.gradle +++ /dev/null @@ -1,140 +0,0 @@ -plugins { - id 'org.quiltmc.loom' version '0.12.+' -} - -archivesBaseName = rootProject.name -version = "v${modVersion}-${minecraftVersion}-Common" -group = modMavenGroup - -dependencies { - // Minecraft - minecraft "com.mojang:minecraft:${minecraftVersion}" - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") - } - - // Mixin Dependencies - implementation 'org.ow2.asm:asm-tree:9.2' - implementation 'org.ow2.asm:asm-commons:9.2' - implementation 'org.ow2.asm:asm-util:9.2' - implementation 'org.spongepowered:mixin:0.8.5' - - // Config Dependencies - implementation 'com.electronwill.night-config:core:3.6.5' - implementation 'com.electronwill.night-config:toml:3.6.5' - - // Puzzles Lib - modImplementation "fuzs.puzzleslib:puzzleslib-common:${puzzlesVersion}" -} - -loom { - mixin { - // not sure if this is necessary for common... - defaultRefmapName = "${modId}.refmap.json" - // fix for java.lang.NoClassDefFoundError: org/objectweb/asm/tree/MethodNode - useLegacyMixinAp = false - } - - // this should hopeful prevent an empty run directory being generated in common during initial project setup - runs { - client { - client() - setConfigName("Common Client") - ideConfigGenerated(false) - runDir("../run") - } - server { - server() - setConfigName("Common Server") - ideConfigGenerated(false) - runDir("../run") - } - } -} - -processResources { - duplicatesStrategy DuplicatesStrategy.INCLUDE - - // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modGroup", project.group - inputs.property "modDescription", "${modDescription}" - inputs.property "packFormat", "${packFormat}" - - // replace stuff in fabric.mod.json and pack.mcmeta - filesMatching ('quilt.mod.json') { - expand ( - 'modId': "${modId}", - 'modVersion': "${modVersion}", - 'modGroup': project.group - ) - } - - // replace stuff in pack.mcmeta - filesMatching ('pack.mcmeta') { - expand ( - 'modDescription': "${modDescription}", - "packFormat": "${packFormat}" - ) - } -} - -publishing { - publications { - mavenJava (MavenPublication) { - artifactId = "${modId}-common" - version = modVersion - from components.java - pom { - name = "${modName} [Common]" - description = "${modDescription}" - url = "${modSourceUrl}" - scm { - url = "${modSourceUrl}" - connection = "${modSourceUrl}".replace("https", "scm:git:git").concat(".git") - developerConnection = "${modSourceUrl}".replace("https://github.com/", "scm:git:git@github.com:").concat(".git") - } - issueManagement { - system = 'github' - url = "${modIssueUrl}" - } - licenses { - license { - name = 'MPL-2' - url = 'https://www.mozilla.org/en-US/MPL/2.0/' - } - } - developers { - developer { - id = "${modAuthor}".toLowerCase() - name = "${modAuthor}" - } - } - } - afterEvaluate { - // exclude certain dependencies when publishing to maven - // from https://stackoverflow.com/a/50121790 - pom.withXml { - asNode().dependencies.dependency.each { dep -> - // use this approach to make excluding dependencies from Curse Maven more convenient - if ([].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { - assert dep.parent().remove(dep) - } - } - } - } - } - } - repositories { - maven { - name = 'FuzsModResources' - url "file://" + project.hasProperty('modResources') ? "${project.findProperty('modResources')}/maven" : System.getenv('local_maven') - } - } -} - -signing { - sign publishing.publications.mavenJava -} diff --git a/Common/src/main/resources/pack.mcmeta b/Common/src/main/resources/pack.mcmeta deleted file mode 100755 index 6221806..0000000 --- a/Common/src/main/resources/pack.mcmeta +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pack": { - "description": "${modDescription}", - "pack_format": ${packFormat} - } -} diff --git a/Common/src/main/resources/quilt.mod.json b/Common/src/main/resources/quilt.mod.json deleted file mode 100644 index 878577d..0000000 --- a/Common/src/main/resources/quilt.mod.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "schema_version": 1, - "quilt_loader": { - "group": "${modGroup}", - "id": "${modId}", - "version": "${modVersion}" - } -} diff --git a/Fabric/build.gradle b/Fabric/build.gradle deleted file mode 100644 index 5d7ca7c..0000000 --- a/Fabric/build.gradle +++ /dev/null @@ -1,280 +0,0 @@ -plugins { - id 'fabric-loom' version '0.12-SNAPSHOT' - id 'io.github.juuxel.loom-quiltflower' version '1.7.1' - // this depends on an older version of guava, which loom is incompatible with, so make sure to apply this plugin after loom - // haven't found a proper way to manage plugin dependencies otherwise - id 'me.hypherionmc.cursegradle' version '2.+' - // cannot apply this in the base build.gradle as it'll be the same for all subprojects, only one configuration will work - id 'com.modrinth.minotaur' version '2.+' -} - -archivesBaseName = rootProject.name -version = "v${modVersion}-${minecraftVersion}-Fabric" -group = modMavenGroup - -repositories { - maven { - name = "Modmuss" - url = "https://maven.modmuss50.me/" - } - maven { - name = 'Terraformers' - url = "https://maven.terraformersmc.com/" - } - maven { - name = 'Ladysnake Mods' - url = 'https://maven.ladysnake.org/releases' - } - maven { - name = "jamieswhiteshirt" - url = "https://maven.jamieswhiteshirt.com/libs-release/" - } -} - -dependencies { - // Include Common Project - compileOnly project(":Common") - - // Minecraft - minecraft "com.mojang:minecraft:${minecraftVersion}" - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") - } - - // Fabric - modImplementation "net.fabricmc:fabric-loader:${fabricVersion}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${fabricApiVersion}" - - // Forge Configs - modImplementation "net.minecraftforge:forgeconfigapiport-fabric:4.2.6" - - // Quality of Life Mods - modRuntimeOnly "com.terraformersmc:modmenu:4.0.6" - modRuntimeOnly "curse.maven:tooltipfix-411557:3820437" - - // Puzzles Lib - modImplementation "fuzs.puzzleslib:puzzleslib-fabric:${puzzlesVersion}" -} - -loom { - mixin.defaultRefmapName = "${modId}.refmap.json" - - runs { - client { - client() - setConfigName("Fabric Client") - ideConfigGenerated(true) - runDir("../run") - vmArg '-Dmixin.debug.export=true' - } - server { - server() - setConfigName("Fabric Server") - ideConfigGenerated(true) - runDir("../run") - vmArg '-Dmixin.debug.export=true' - } - } -} - -processResources { - from(project(":Common").sourceSets.main.resources) { - // we need to have this in common so that in a non-production environment the common jar is correctly deobfuscated - exclude("quilt.mod.json") - } - from(project(":Forge").file('src/generated/resources')) { - exclude('.cache/') - } - // Forge's data gen doesn't work with assets placed in the common project, so we place them in Forge and include them here - from(project(":Forge").sourceSets.main.resources) { - include("assets/") - include("data/") - } - - duplicatesStrategy DuplicatesStrategy.INCLUDE - - // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modName", "${modName}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modDescription", "${modDescription}" - inputs.property "modGroup", project.group - inputs.property "modPageUrl", "${modSourceUrl}" - inputs.property "modIssueUrl", "${modIssueUrl}" - inputs.property "modAuthor", "${modAuthor}" - inputs.property "minFabricVersion", "${minFabricVersion}" - inputs.property "minFabricApiVersion", "${minFabricApiVersion}" - inputs.property "minMinecraftVersion", "${minMinecraftVersion}" - inputs.property "nextMinecraftVersion", rootProject.getNextVersion("${minMinecraftVersion}") - inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" - inputs.property "packFormat", "${packFormat}" - inputs.property "mainEntryPoint", "${project.group}.${rootProject.name}Fabric" - inputs.property "clientEntryPoint", "${project.group}.client.${rootProject.name}FabricClient" - inputs.property "modFabricEnvironment", "${modFabricEnvironment}" - - // replace stuff in fabric.mod.json and pack.mcmeta - filesMatching ('fabric.mod.json') { - expand ( - 'modId': "${modId}", - 'modName': "${modName}", - 'modVersion': "${modVersion}", - 'modDescription': "${modDescription}", - 'modGroup': project.group, - 'modPageUrl': "${modSourceUrl}", - 'modIssueUrl': "${modIssueUrl}", - 'modAuthor': "${modAuthor}", - 'minFabricVersion': "${minFabricVersion}", - 'minFabricApiVersion': "${minFabricApiVersion}", - 'minMinecraftVersion': "${minMinecraftVersion}", - "nextMinecraftVersion": rootProject.getNextVersion("${minMinecraftVersion}"), - "minPuzzlesVersion": "${minPuzzlesVersion}", - "mainEntryPoint": "${project.group}.${rootProject.name}Fabric", - "clientEntryPoint": "${project.group}.client.${rootProject.name}FabricClient", - "modFabricEnvironment": "${modFabricEnvironment}" - ) - } - - filesMatching ('pack.mcmeta') { - expand ( - 'modDescription': "${modDescription}", - "packFormat": "${packFormat}" - ) - } -} - -compileJava { - source project(":Common").sourceSets.main.allSource -} - -sourcesJar { - from project(":Common").sourceSets.main.allJava -} - -javadoc { - source project(":Common").sourceSets.main.allJava -} - -publishing { - publications { - mavenJava (MavenPublication) { - artifactId = "${modId}-fabric" - version = modVersion - from components.java - pom { - name = "${modName} [Fabric]" - description = "${modDescription}" - url = "${modSourceUrl}" - scm { - url = "${modSourceUrl}" - connection = "${modSourceUrl}".replace("https", "scm:git:git").concat(".git") - developerConnection = "${modSourceUrl}".replace("https://github.com/", "scm:git:git@github.com:").concat(".git") - } - issueManagement { - system = 'github' - url = "${modIssueUrl}" - } - licenses { - license { - name = 'MPL-2' - url = 'https://www.mozilla.org/en-US/MPL/2.0/' - } - } - developers { - developer { - id = "${modAuthor}".toLowerCase() - name = "${modAuthor}" - } - } - } - afterEvaluate { - // exclude certain dependencies when publishing to maven - // from https://stackoverflow.com/a/50121790 - pom.withXml { - asNode().dependencies.dependency.each { dep -> - // use this approach to make excluding dependencies from Curse Maven more convenient - if (["curse.maven:", "com.terraformersmc:modmenu"].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { - assert dep.parent().remove(dep) - } - } - } - } - } - } - repositories { - maven { - name = 'FuzsModResources' - url "file://" + project.hasProperty('modResources') ? "${project.findProperty('modResources')}/maven" : System.getenv('local_maven') - } - } -} - -signing { - sign publishing.publications.mavenJava -} - -curseforge { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } - apiKey = project.hasProperty('curseApiToken') ? project.findProperty('curseApiToken') : '' - project { - id = projectCurseId - changelogType = 'markdown' - changelog = file('../CHANGELOG.md') - releaseType = projectReleaseType - addGameVersion 'Fabric' - projectGameVersions.split(",").each { - addGameVersion it.trim() - } - mainArtifact(remapJar) { - displayName = "[FABRIC] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" - relations { - requiredDependency 'fabric-api' - requiredDependency 'forge-config-api-port-fabric' - requiredDependency 'puzzles-lib' - } - } - addArtifact sourcesJar - } - options { -// debug = true - javaVersionAutoDetect = false - forgeGradleIntegration = false - } -} - -modrinth { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } - token = project.hasProperty('modrinthApiToken') ? project.findProperty('modrinthApiToken') : '' - projectId = projectModrinthId - versionNumber = project.version - versionName = "[FABRIC] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" - changelog = file('../CHANGELOG.md').text - versionType = projectReleaseType - uploadFile = remapJar // This is the java jar task - projectGameVersions.split(",").each { - gameVersions.add it.trim() - } - loaders.add 'fabric' - additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") - dependencies { - required.project 'fabric-api' - required.project 'forge-config-api-port' - required.project 'puzzles-lib' - } -// debugMode = true -} - -import groovy.json.* - -task copyJarToDir(type: Copy) { - onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } - if (project.findProperty('copyBuildJar').toBoolean()) { - from remapJar - into project.findProperty('buildJarOutputDir') - // add build number to be able to distinguish jars when testing thorough official launcher - // build number is stored in global gradle.properties - rename { fileName -> fileName.replace("v${modVersion}", "v${modVersion}.${uniqueBuildNumber}") } - } -} - -build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber diff --git a/Forge/build.gradle b/Forge/build.gradle deleted file mode 100644 index 44fd0cd..0000000 --- a/Forge/build.gradle +++ /dev/null @@ -1,378 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { url = 'https://maven.minecraftforge.net' } - maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } - } - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true - classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' - classpath group: 'org.parchmentmc', name: 'librarian', version: '1.+' - } -} - -plugins { - id 'me.hypherionmc.cursegradle' version '2.+' - // cannot apply this in the base build.gradle as it'll be the same for all subprojects, only one configuration will work - id 'com.modrinth.minotaur' version '2.+' -} - -apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'eclipse' -apply plugin: 'org.spongepowered.mixin' -apply plugin: 'org.parchmentmc.librarian.forgegradle' - -archivesBaseName = rootProject.name -version = "v${modVersion}-${minecraftVersion}-Forge" -group = modMavenGroup - -minecraft { - mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${minecraftVersion}" -// mappings channel: 'official', version: "${minecraftVersion}" - - runs { - client { - workingDirectory project.file('../run') - jvmArgs '-Xms1G', '-Xmx4G' - property 'fml.earlyprogresswindow', 'false' - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - arg "-mixin.config=${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - arg "-mixin.config=${modId}.forge.mixins.json" - } - ideaModule "${rootProject.name}.${project.name}.main" - taskName 'Client' - property 'terminal.ansi', 'true' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'mixin.debug.export', 'true' - mods { - modClientRun { - source sourceSets.main - source project(":Common").sourceSets.main - } - } - } - - server { - workingDirectory project.file('../run') - jvmArgs '-Xms1G', '-Xmx4G' - arg 'nogui' - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - arg "-mixin.config=${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - arg "-mixin.config=${modId}.forge.mixins.json" - } - ideaModule "${rootProject.name}.${project.name}.main" - taskName 'Server' - property 'terminal.ansi', 'true' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'mixin.debug.export', 'true' - mods { - modServerRun { - source sourceSets.main - source project(":Common").sourceSets.main - } - } - } - - data { - workingDirectory project.file('../run') - jvmArgs '-Xms1G', '-Xmx4G' - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - arg "-mixin.config=${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - arg "-mixin.config=${modId}.forge.mixins.json" - } - args '--mod', modId, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') - ideaModule "${rootProject.name}.${project.name}.main" - taskName 'Data' - property 'terminal.ansi', 'true' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'mixin.debug.export', 'true' - mods { - modDataRun { - source sourceSets.main - source project(":Common").sourceSets.main - } - } - } - } -} - -dependencies { - // Include Common Project - compileOnly project(":Common") - - // Minecraft - minecraft "net.minecraftforge:forge:${forgeVersion}" - annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' - - // Quality of Life Mods - runtimeOnly fg.deobf("curse.maven:catalogue-459701:3873264") - runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:4.2.0") -// runtimeOnly fg.deobf("curse.maven:configmenusforge-544048:3822820") -// runtimeOnly fg.deobf("curse.maven:configured-457570:3903908") - - // Puzzles Lib - implementation fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${puzzlesVersion}") -} - -mixin { - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists() || project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - add project(":Common").sourceSets.main, "${modId}.refmap.json" - } - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - config "${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - config "${modId}.forge.mixins.json" - } -} - -processResources { - from(project(":Common").sourceSets.main.resources) { - // we need to have this in common so that in a non-production environment the common jar is correctly deobfuscated - exclude("quilt.mod.json") - } - from(file('src/generated/resources')) { - exclude('.cache/') - } - - duplicatesStrategy DuplicatesStrategy.INCLUDE - - // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modName", "${modName}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modDescription", "${modDescription}" - inputs.property "modGroup", project.group - inputs.property "modPageUrl", "${modSourceUrl}" - inputs.property "modUpdateUrl", "${modUpdateUrl}" - inputs.property "modIssueUrl", "${modIssueUrl}" - inputs.property "modAuthor", "${modAuthor}" - inputs.property "minFMLVersion", "${minForgeVersion}".replaceAll("\\..*", "") - inputs.property "minForgeVersion", "${minForgeVersion}" - inputs.property "minMinecraftVersion", "${minMinecraftVersion}" - inputs.property "nextMinecraftVersion", rootProject.getNextVersion("${minMinecraftVersion}") - inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" - inputs.property "packFormat", "${packFormat}" - inputs.property "modForgeDisplayTest", "${modForgeDisplayTest}" - - // replace stuff in mods.toml and pack.mcmeta - filesMatching ('META-INF/mods.toml') { - expand ( - 'modId': "${modId}", - 'modName': "${modName}", - 'modVersion': "${modVersion}", - 'modDescription': "${modDescription}", - 'modGroup': project.group, - 'modPageUrl': "${modSourceUrl}", - 'modUpdateUrl': "${modUpdateUrl}", - 'modIssueUrl': "${modIssueUrl}", - 'modAuthor': "${modAuthor}", - 'minFMLVersion': "${minForgeVersion}".replaceAll("\\..*", ""), - 'minForgeVersion': "${minForgeVersion}", - 'minMinecraftVersion': "${minMinecraftVersion}", - 'nextMinecraftVersion': rootProject.getNextVersion("${minMinecraftVersion}"), - 'minPuzzlesVersion': "${minPuzzlesVersion}", - 'modForgeDisplayTest': "${modForgeDisplayTest}" - ) - } - - filesMatching ('pack.mcmeta') { - expand ( - 'modDescription': "${modDescription}", - "packFormat": "${packFormat}" - ) - } -} - -compileJava { - source project(":Common").sourceSets.main.allSource -} - -sourcesJar { - from project(":Common").sourceSets.main.allJava -} - -javadoc { - source project(":Common").sourceSets.main.allJava -} - -// important: the task may not run before 'compileJava', otherwise overridden/shadowed fields and methods in mixin classes will not be reobfuscated -jar.finalizedBy("configureReobfTaskForReobfJar") -jar.finalizedBy('reobfJar') - -publishing { - publications { - mavenJava (MavenPublication) { - artifactId = "${modId}-forge" - version = modVersion - from components.java - // strip Forge dependency from POM - fg.component(it) - pom { - name = "${modName} [Forge]" - description = "${modDescription}" - url = "${modSourceUrl}" - scm { - url = "${modSourceUrl}" - connection = "${modSourceUrl}".replace("https", "scm:git:git").concat(".git") - developerConnection = "${modSourceUrl}".replace("https://github.com/", "scm:git:git@github.com:").concat(".git") - } - issueManagement { - system = 'github' - url = "${modIssueUrl}" - } - licenses { - license { - name = 'MPL-2' - url = 'https://www.mozilla.org/en-US/MPL/2.0/' - } - } - developers { - developer { - id = "${modAuthor}".toLowerCase() - name = "${modAuthor}" - } - } - } - afterEvaluate { - // exclude certain dependencies when publishing to maven - // from https://stackoverflow.com/a/50121790 - pom.withXml { - asNode().dependencies.dependency.each { dep -> - // use this approach to make excluding dependencies from Curse Maven more convenient - if (["curse.maven:", "fuzs.bettermodsbutton:bettermodsbutton-forge"].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { - assert dep.parent().remove(dep) - } - } - } - } - } - } - repositories { - maven { - name = 'FuzsModResources' - url "file://" + project.hasProperty('modResources') ? "${project.findProperty('modResources')}/maven" : System.getenv('local_maven') - } - } -} - -signing { - sign publishing.publications.mavenJava -} - -task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: jar) { - onlyIf { project.hasProperty('keyStore') } - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = outputFile = jar.archivePath -} - -jar.finalizedBy 'signJar' -signJar.mustRunAfter 'reobfJar' - -curseforge { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } - apiKey = project.hasProperty('curseApiToken') ? project.findProperty('curseApiToken') : '' - project { - id = projectCurseId - changelogType = 'markdown' - changelog = file('../CHANGELOG.md') - releaseType = projectReleaseType - addGameVersion 'Forge' - projectGameVersions.split(",").each { - addGameVersion it.trim() - } - mainArtifact(jar) { - displayName = "[FORGE] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" - relations { - requiredDependency 'puzzles-lib' - } - } - addArtifact sourcesJar - } - options { -// debug = true - javaVersionAutoDetect = false - forgeGradleIntegration = false - } -} - -modrinth { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } - token = project.hasProperty('modrinthApiToken') ? project.findProperty('modrinthApiToken') : '' - projectId = projectModrinthId - versionNumber = project.version - versionName = "[FORGE] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" - changelog = file('../CHANGELOG.md').text - versionType = projectReleaseType - uploadFile = jar // This is the java jar task - projectGameVersions.split(",").each { - gameVersions.add it.trim() - } - loaders.add 'forge' - additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") - dependencies { - required.project 'puzzles-lib' - } -// debugMode = true -} - -import groovy.json.* - -task copyJarToDir(type: Copy) { - onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } - if (project.findProperty('copyBuildJar').toBoolean()) { - // shortcut for jar.outputs.files - from jar - into project.findProperty('buildJarOutputDir') - // add build number to be able to distinguish jars when testing thorough official launcher - // build number is stored in global gradle.properties - rename { fileName -> fileName.replace("v${modVersion}", "v${modVersion}.${uniqueBuildNumber}") } - } -} - -task refreshUpdateJson { - onlyIf { project.hasProperty('modResources') } - doLast { - def updateFile = file(project.findProperty('modResources').concat(File.separator).concat('update').concat(File.separator).concat("${modId}").concat('.json')) - def updateJson - if (updateFile.exists() && updateFile.canRead()) { - updateJson = new JsonSlurper().parseText(updateFile.text) - "${projectGameVersions}".replaceAll(" ", "").split(",").each { version -> - updateJson['promos']["${version}-latest"] = "${modVersion}" - // alpha and beta releases will contain 'a' or 'b' char respectively, don't update recommended for those - if ("${modVersion}".matches("[^a-zA-Z]+")) { - updateJson['promos']["${version}-recommended"] = "${modVersion}" - } - } - } else { - def builder = new JsonBuilder() - updateJson = builder { - homepage "${modSourceUrl}" - promos { "${projectGameVersions}".replaceAll(" ", "").split(",").each { version -> - "${version}-latest" "${modVersion}" - // alpha and beta releases will contain 'a' or 'b' char respectively, don't update recommended for those - if ("${modVersion}".matches("[^a-zA-Z]+")) { - "${version}-recommended" "${modVersion}" - } - } } - } - } - def output = new JsonOutput() - updateFile.write(output.prettyPrint(output.toJson(updateJson))) - } -} - -build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber -[tasks.modrinth, tasks.curseforge].each {it.finalizedBy project.tasks.refreshUpdateJson} diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml deleted file mode 100644 index 5e945cb..0000000 --- a/Forge/src/main/resources/META-INF/mods.toml +++ /dev/null @@ -1,41 +0,0 @@ -modLoader="javafml" -loaderVersion="[${minFMLVersion},)" -license="MPL-2" -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="[${minMinecraftVersion},${nextMinecraftVersion})" - ordering="NONE" - side="BOTH" - -[[dependencies.${modId}]] - modId="puzzleslib" - mandatory=true - versionRange="[${minPuzzlesVersion},)" - ordering="NONE" - side="BOTH" - -[modproperties.${modId}] - catalogueImageIcon="mod_logo.png" - configuredBackground="minecraft:textures/block/coarse_dirt.png" diff --git a/LICENSE-ASSETS.md b/LICENSE-ASSETS.md new file mode 100644 index 0000000..79fd8f1 --- /dev/null +++ b/LICENSE-ASSETS.md @@ -0,0 +1 @@ +Copyright (c) 2023 @heyitsfuzs. All Rights Reserved. \ No newline at end of file diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 91d8eae..0000000 --- a/build.gradle +++ /dev/null @@ -1,122 +0,0 @@ -apply from: './gradle/tasks.gradle' - -subprojects { - apply plugin: 'java' - apply plugin: 'java-library' - apply plugin: 'maven-publish' - apply plugin: 'signing' - - java.toolchain.languageVersion = JavaLanguageVersion.of(17) - java.withSourcesJar() - java.withJavadocJar() - // silence missing javadoc comments, we just don't care - javadoc.options.addStringOption('Xdoclint:none', '-quiet') - - repositories { - mavenCentral() - mavenLocal() - maven { - name = 'Sponge / Mixin' - url = 'https://repo.spongepowered.org/repository/maven-public/' - } - maven { - name = 'Jared' - url = 'https://maven.blamejared.com/' - } - maven { - name = 'Jitpack' - url = 'https://jitpack.io' - } - maven { - name = 'Shedaniel' - url = 'https://maven.shedaniel.me/' - } - maven { - name = 'Parchment' - url = 'https://maven.parchmentmc.org' - } - maven { - name = 'Curse Maven' - url = 'https://cursemaven.com' - } - maven { - name = "Fuzs Mod Resources" - url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" - } - maven { - name = "Progwml6 maven" - url = "https://dvs1.progwml6.com/files/maven/" - } - maven { - name = "ModMaven" - url = "https://modmaven.dev" - } - flatDir { - dirs 'libs' - } - } - - tasks.withType(JavaCompile).configureEach { - // ensure that the encoding is set to UTF-8, no matter what the system default is - // this fixes some edge cases with special characters not displaying correctly - // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html - // If Javadoc is generated, this must be specified in that task too. - options.encoding = 'UTF-8' - options.release = 17 - } - - tasks.withType(Jar).configureEach { - from rootProject.file("LICENSE") - from rootProject.file("CHANGELOG.md") - manifest { - attributes([ - "Specification-Title" : modName, - 'Specification-Version' : modVersion, - "Specification-Vendor" : modAuthor, - 'Implementation-Title' : modName, - 'Implementation-Version' : modVersion, - 'Implementation-Vendor' : modAuthor, - 'Implementation-Timestamp' : new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - 'Implementation-Timestamp-Milli' : System.currentTimeMillis(), - 'Implementation-URL' : modSourceUrl, - 'Built-On-Java' : "${System.getProperty('java.vm.version')} (${System.getProperty('java.vm.vendor')})", - 'Built-On-Minecraft' : minecraftVersion - ]) - } - group 'jar' - } - - tasks.withType(GenerateModuleMetadata) { - // Disables Gradle's custom module metadata from being published to maven. The - // metadata includes mapped dependencies which are not reasonably consumable by - // other mod developers. - enabled = false - } -} - -import groovy.json.* -import java.util.regex.Pattern - -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) - -task incrementBuildNumber { - onlyIf { project.hasProperty('uniqueBuildNumber') } - doLast { - def propertiesName = 'gradle.properties' - // build number is stored in global gradle.properties - def propertiesFile = new File(project.gradle.gradleUserHomeDir, propertiesName) - if (!propertiesFile.canRead()) { throw new FileNotFoundException("Could not read file ".concat(propertiesName)) } - def buildNumberMatcher = Pattern.compile("uniqueBuildNumber=(\\d+)").matcher(propertiesFile.getText()) - buildNumberMatcher.find() - def versionCode = Integer.parseInt(buildNumberMatcher.group(1)) - def propertiesContent = buildNumberMatcher.replaceAll("uniqueBuildNumber=" + ++versionCode) - propertiesFile.write(propertiesContent) - } -} - -def static getNextVersion(String puzzlesVersion) { - def puzzlesVersionMatcher = Pattern.compile("(\\d+\\.\\d+)").matcher(puzzlesVersion) - puzzlesVersionMatcher.find() - def currentVersion = puzzlesVersionMatcher.group(1) - return currentVersion.substring(0, currentVersion.indexOf(".") + 1).concat(String.valueOf(Integer.parseInt(currentVersion.substring(currentVersion.indexOf(".") + 1, currentVersion.size())) + 1)) -} diff --git a/gradle/tasks.gradle b/gradle/tasks.gradle deleted file mode 100644 index dbd3dc0..0000000 --- a/gradle/tasks.gradle +++ /dev/null @@ -1,232 +0,0 @@ -task forgeClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean' - ] -} - -task fabricClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean' - ] -} - -task allClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean' - ] -} - -task forgeBuild(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:build' - ] -} - -task fabricBuild(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:build' - ] -} - -task allBuild(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Common:build', - ':Forge:build', - ':Fabric:build' - ] -} - -task commonPublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Common:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task forgePublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task fabricPublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task allPublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Common:publishMavenJavaPublicationToFuzsModResourcesRepository', - ':Forge:publishMavenJavaPublicationToFuzsModResourcesRepository', - ':Fabric:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task forgeUploadCurseForge(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:curseforge' - ] -} - -task fabricUploadCurseForge(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:curseforge' - ] -} - -task allUploadCurseForge(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Forge:curseforge', - ':Fabric:curseforge' - ] -} - -task forgeUploadModrinth(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:modrinth' - ] -} - -task fabricUploadModrinth(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:modrinth' - ] -} - -task allUploadModrinth(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Forge:modrinth', - ':Fabric:modrinth' - ] -} - -task forgeUploadEverywhere(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:curseforge', - ':Forge:modrinth' - ] -} - -task fabricUploadEverywhere(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:curseforge', - ':Fabric:modrinth' - ] -} - -task allUploadEverywhere(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Forge:curseforge', - ':Forge:modrinth', - ':Fabric:curseforge', - ':Fabric:modrinth' - ] -} - -task commonGenSources(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:genSourcesWithQuiltflower' - ] -} - -task forgeGenRuns(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:genIntellijRuns' - ] -} - -task fabricGenSources(type: GradleBuild) { - group = '_main' - tasks = [ - ':Fabric:genSourcesWithQuiltflower' - ] -} - -task forgeClient(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:runClient' - ] -} - -task fabricClient(type: GradleBuild) { - group = '_main' - tasks = [ - ':Fabric:runClient' - ] -} - -task forgeServer(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:runServer' - ] -} - -task fabricServer(type: GradleBuild) { - group = '_main' - tasks = [ - ':Fabric:runServer' - ] -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/run/config/modmenu.json b/run/config/modmenu.json deleted file mode 100644 index c9e0984..0000000 --- a/run/config/modmenu.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "sorting": "ascending", - "count_libraries": true, - "compact_list": false, - "count_children": true, - "mods_button_style": "classic", - "count_hidden_mods": true, - "mod_count_location": "title_screen_and_mods_button", - "hide_mod_links": false, - "show_libraries": false, - "hide_mod_license": false, - "hide_badges": false, - "hide_mod_credits": false, - "easter_eggs": true, - "modify_title_screen": true, - "modify_game_menu": true, - "hide_config_buttons": false, - "hidden_mods": [] -} \ No newline at end of file diff --git a/run/options.txt b/run/options.txt deleted file mode 100644 index 108a267..0000000 --- a/run/options.txt +++ /dev/null @@ -1,131 +0,0 @@ -version:3120 -autoJump:false -autoSuggestions:true -chatColors:true -chatLinks:true -chatLinksPrompt:true -enableVsync:true -entityShadows:true -forceUnicodeFont:false -discrete_mouse_scroll:false -invertYMouse:false -realmsNotifications:true -reducedDebugInfo:false -showSubtitles:false -directionalAudio:false -touchscreen:false -fullscreen:false -bobView:true -toggleCrouch:false -toggleSprint:false -darkMojangStudiosBackground:false -hideLightningFlashes:false -mouseSensitivity:0.5 -fov:0.0 -screenEffectScale:1.0 -fovEffectScale:1.0 -darknessEffectScale:1.0 -gamma:0.5 -renderDistance:12 -simulationDistance:12 -entityDistanceScaling:1.0 -guiScale:0 -particles:0 -maxFps:120 -graphicsMode:1 -ao:2 -prioritizeChunkUpdates:0 -biomeBlendRadius:2 -renderClouds:"true" -resourcePacks:["Fabric Mods"] -incompatibleResourcePacks:[] -lastServer: -lang:en_us -soundDevice:"" -chatVisibility:0 -chatOpacity:1.0 -chatLineSpacing:0.0 -textBackgroundOpacity:0.5 -backgroundForChatOnly:true -hideServerAddress:false -advancedItemTooltips:false -pauseOnLostFocus:true -overrideWidth:0 -overrideHeight:0 -heldItemTooltips:true -chatHeightFocused:1.0 -chatDelay:0.0 -chatHeightUnfocused:0.4375 -chatScale:1.0 -chatWidth:1.0 -mipmapLevels:4 -useNativeTransport:true -mainHand:"right" -attackIndicator:1 -narrator:0 -tutorialStep:none -mouseWheelSensitivity:1.0 -rawMouseInput:true -glDebugVerbosity:1 -skipMultiplayerWarning:true -skipRealms32bitWarning:false -hideMatchedNames:true -joinedFirstServer:true -hideBundleTutorial:false -syncChunkWrites:false -showAutosaveIndicator:true -allowServerListing:true -chatPreview:1 -onlyShowSecureChat:false -key_key.attack:key.mouse.left -key_key.use:key.mouse.right -key_key.forward:key.keyboard.w -key_key.left:key.keyboard.a -key_key.back:key.keyboard.s -key_key.right:key.keyboard.d -key_key.jump:key.keyboard.space -key_key.sneak:key.keyboard.left.shift -key_key.sprint:key.keyboard.left.control -key_key.drop:key.keyboard.q -key_key.inventory:key.keyboard.e -key_key.chat:key.keyboard.t -key_key.playerlist:key.keyboard.tab -key_key.pickItem:key.mouse.middle -key_key.command:key.keyboard.slash -key_key.socialInteractions:key.keyboard.p -key_key.screenshot:key.keyboard.f2 -key_key.togglePerspective:key.keyboard.f5 -key_key.smoothCamera:key.keyboard.unknown -key_key.fullscreen:key.keyboard.f11 -key_key.spectatorOutlines:key.keyboard.unknown -key_key.swapOffhand:key.keyboard.f -key_key.saveToolbarActivator:key.keyboard.c -key_key.loadToolbarActivator:key.keyboard.x -key_key.advancements:key.keyboard.l -key_key.hotbar.1:key.keyboard.1 -key_key.hotbar.2:key.keyboard.2 -key_key.hotbar.3:key.keyboard.3 -key_key.hotbar.4:key.keyboard.4 -key_key.hotbar.5:key.keyboard.5 -key_key.hotbar.6:key.keyboard.6 -key_key.hotbar.7:key.keyboard.7 -key_key.hotbar.8:key.keyboard.8 -key_key.hotbar.9:key.keyboard.9 -key_key.modmenu.open_menu:key.keyboard.unknown -soundCategory_master:0.5032789 -soundCategory_music:0.0 -soundCategory_record:1.0 -soundCategory_weather:0.15838194 -soundCategory_block:1.0 -soundCategory_hostile:1.0 -soundCategory_neutral:1.0 -soundCategory_player:1.0 -soundCategory_ambient:1.0 -soundCategory_voice:1.0 -modelPart_cape:true -modelPart_jacket:true -modelPart_left_sleeve:true -modelPart_right_sleeve:true -modelPart_left_pants_leg:true -modelPart_right_pants_leg:true -modelPart_hat:true diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 429f534..0000000 --- a/settings.gradle +++ /dev/null @@ -1,28 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'Sponge Snapshots' - url = 'https://repo.spongepowered.org/repository/maven-public/' - } - maven { - name = 'Quilt (Release)' - url = 'https://maven.quiltmc.org/repository/release' - } - maven { - name = 'Quilt (Snapshot)' - url = 'https://maven.quiltmc.org/repository/snapshot' - } - maven { - name = 'QuiltFlower' - url = 'https://server.bbkr.space/artifactory/libs-release/' - } - } -} - -rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}" -include("Common", "Fabric", "Forge") From 18f58ed0f888f2b97fe1123cb91ebd780031eef6 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 27 Jul 2023 18:22:54 +0200 Subject: [PATCH 14/31] 1.20 port --- 1.20/CHANGELOG.md | 2 +- 1.20/Common/build.gradle | 5 + .../java/fuzs/armorstatues/ArmorStatues.java | 41 ++++ .../client/ArmorStatuesClient.java | 43 ++++ .../ArmorStandAlignmentsScreen.java | 107 +++++++++ .../handler/ArmorStandTooltipHandler.java | 25 ++ .../client/handler/DataSyncTickHandler.java | 28 +++ .../armorstatues/config/ClientConfig.java | 10 + .../handler/ArmorStandInteractHandler.java | 51 ++++ .../fuzs/armorstatues/init/ModRegistry.java | 31 +++ .../armorstatues/network/S2CPingMessage.java | 30 +++ .../client/data/CommandDataSyncHandler.java | 207 ++++++++++++++++ .../data/VanillaTweaksDataSyncHandler.java | 227 ++++++++++++++++++ .../fuzs/armorstatues/proxy/ClientProxy.java | 46 ++++ .../java/fuzs/armorstatues/proxy/Proxy.java | 11 + .../fuzs/armorstatues/proxy/ServerProxy.java | 12 + .../main/java/fuzs/examplemod/ExampleMod.java | 16 -- .../examplemod/client/ExampleModClient.java | 7 - .../resources/examplemod.common.mixins.json | 15 -- 1.20/Common/src/main/resources/mod_banner.png | Bin 17858 -> 15383 bytes 1.20/Common/src/main/resources/mod_logo.png | Bin 6537 -> 9380 bytes 1.20/Fabric/build.gradle | 5 + .../fuzs/armorstatues/ArmorStatuesFabric.java | 12 + .../client/ArmorStatuesFabricClient.java | 13 + .../fuzs/examplemod/ExampleModFabric.java | 12 - .../client/ExampleModFabricClient.java | 13 - .../mixin/ModMixinConfigPlugin.java | 47 ---- .../resources/examplemod.fabric.mixins.json | 15 -- .../Fabric/src/main/resources/fabric.mod.json | 2 - 1.20/Forge/build.gradle | 10 + .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 + .../assets/armorstatues/lang/en_us.json | 7 + .../fuzs/armorstatues/ArmorStatuesForge.java | 23 ++ .../client/ArmorStatuesForgeClient.java | 51 ++++ .../data/ModLanguageProvider.java | 23 ++ .../java/fuzs/examplemod/ExampleModForge.java | 31 --- .../client/ExampleModForgeClient.java | 17 -- .../mixin/ModMixinConfigPlugin.java | 47 ---- .../resources/examplemod.forge.mixins.json | 15 -- 1.20/gradle.properties | 27 ++- 40 files changed, 1035 insertions(+), 251 deletions(-) create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java delete mode 100644 1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java delete mode 100644 1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java delete mode 100644 1.20/Common/src/main/resources/examplemod.common.mixins.json create mode 100644 1.20/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java create mode 100644 1.20/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java delete mode 100644 1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java delete mode 100644 1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java delete mode 100644 1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java delete mode 100644 1.20/Fabric/src/main/resources/examplemod.fabric.mixins.json create mode 100644 1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 create mode 100644 1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json create mode 100644 1.20/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java create mode 100644 1.20/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java create mode 100644 1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java delete mode 100644 1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java delete mode 100644 1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java delete mode 100644 1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java delete mode 100644 1.20/Forge/src/main/resources/examplemod.forge.mixins.json diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index c7f9a93..2f76460 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,7 +3,7 @@ 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 +## [v8.0.0-1.20.1] - 2023-07-27 - Ported to Minecraft 1.20.1 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.20/Common/build.gradle b/1.20/Common/build.gradle index 949b426..2434c15 100644 --- a/1.20/Common/build.gradle +++ b/1.20/Common/build.gradle @@ -3,6 +3,11 @@ apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/co dependencies { // Puzzles Lib modApi libs.puzzleslib.common + + // Puzzles Api + api(libs.puzzlesapi.common) { + exclude group: "fuzs.puzzleslib" + } } // @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.20/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java new file mode 100644 index 0000000..041fd20 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -0,0 +1,41 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.S2CPingMessage; +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerEvents; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import fuzs.puzzleslib.api.network.v2.MessageDirection; +import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArmorStatues implements ModConstructor { + public static final String MOD_ID = "armorstatues"; + public static final String MOD_NAME = "Armor Statues"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID, true, true); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class); + + @Override + public void onConstructMod() { + ModRegistry.touch(); + registerMessages(); + registerHandlers(); + } + + private static void registerMessages() { + NETWORK.register(S2CPingMessage.class, S2CPingMessage::new, MessageDirection.TO_CLIENT); + } + + private static void registerHandlers() { + // high priority so we run before the Quark mod + PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); + PlayerEvents.LOGGED_IN.register(ArmorStandInteractHandler::onLoggedIn); + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java new file mode 100644 index 0000000..fbddc76 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -0,0 +1,43 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; +import fuzs.armorstatues.client.handler.DataSyncTickHandler; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreenFactory; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandMenu; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.event.v1.ClientPlayerEvents; +import fuzs.puzzleslib.api.client.event.v1.ClientTickEvents; +import fuzs.puzzleslib.api.client.event.v1.ItemTooltipCallback; +import fuzs.puzzleslib.api.client.event.v1.ScreenEvents; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +public class ArmorStatuesClient implements ClientModConstructor { + + @Override + public void onConstructMod() { + registerHandlers(); + } + + private static void registerHandlers() { + ItemTooltipCallback.EVENT.register(ArmorStandTooltipHandler::onItemTooltip); + ClientTickEvents.END.register(DataSyncTickHandler::onEndClientTick); + ScreenEvents.remove(Screen.class).register(DataSyncTickHandler::onRemove); + ClientPlayerEvents.LOGGED_IN.register(ArmorStandInteractHandler::onLoggedIn); + } + + @SuppressWarnings("Convert2MethodRef") + @Override + public void onClientSetup() { + // compiler doesn't like method reference :( + MenuScreens.register(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), (ArmorStandMenu menu, Inventory inventory, Component component) -> { + return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); + }); + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java new file mode 100644 index 0000000..0028996 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -0,0 +1,107 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzlesapi.api.client.statues.v1.gui.components.TickButton; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.AbstractArmorStandPositionScreen; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOptions; +import net.minecraft.Util; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +import java.util.List; + +public class ArmorStandAlignmentsScreen extends AbstractArmorStandPositionScreen { + + public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(new PositionAlignWidget()); + for (ArmorStandAlignment alignment : ArmorStandAlignment.values()) { + widgets.add(new AlignmentWidget(alignment)); + } + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.ALIGNMENTS_SCREEN_TYPE; + } + + private class AlignmentWidget extends AbstractPositionScreenWidget { + private final ArmorStandAlignment alignment; + + public AlignmentWidget(ArmorStandAlignment alignment) { + super(Component.empty()); + this.alignment = alignment; + } + + @Override + protected boolean shouldTick() { + return true; + } + + @Override + public void init(int posX, int posY) { + super.init(posX, posY); + this.children.add(Util.make(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { + ArmorStand armorStand = ArmorStandAlignmentsScreen.this.holder.getArmorStand(); + DataSyncHandler dataSyncHandler = ArmorStandAlignmentsScreen.this.dataSyncHandler; + if (!armorStand.isInvisible()) { + dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); + } + if (!armorStand.isNoGravity()) { + dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); + } + dataSyncHandler.sendPose(this.alignment.getPose(), false); + Vec3 alignmentOffset = this.alignment.getAlignmentOffset(armorStand.isSmall()); + Vec3 newPosition = getLocalPosition(armorStand, alignmentOffset); + dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z(), false); + dataSyncHandler.finalizeCurrentOperation(); + })), widget -> { + widget.setTooltip(Tooltip.create(Component.translatable(this.alignment.getDescriptionsKey()))); + })); + } + + /** + * Copied from {@link net.minecraft.commands.arguments.coordinates.LocalCoordinates#getPosition(CommandSourceStack)}. + */ + private static Vec3 getLocalPosition(Entity entity, Vec3 offset) { + Vec2 vec2 = entity.getRotationVector(); + Vec3 vec3 = entity.position(); + float f = Mth.cos((vec2.y + 90.0F) * 0.017453292F); + float g = Mth.sin((vec2.y + 90.0F) * 0.017453292F); + float h = Mth.cos(-vec2.x * 0.017453292F); + float i = Mth.sin(-vec2.x * 0.017453292F); + float j = Mth.cos((-vec2.x + 90.0F) * 0.017453292F); + float k = Mth.sin((-vec2.x + 90.0F) * 0.017453292F); + Vec3 vec32 = new Vec3(f * h, i, g * h); + Vec3 vec33 = new Vec3(f * j, k, g * j); + Vec3 vec34 = vec32.cross(vec33).scale(-1.0); + double d = vec32.x * offset.z() + vec33.x * offset.y() + vec34.x * offset.x(); + double e = vec32.y * offset.z() + vec33.y * offset.y() + vec34.y * offset.x(); + double l = vec32.z * offset.z() + vec33.z * offset.y() + vec34.z * offset.x(); + return new Vec3(vec3.x + d, vec3.y + e, vec3.z + l); + } + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java new file mode 100644 index 0000000..929250d --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -0,0 +1,25 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.puzzlesapi.api.statues.v1.helper.ArmorStandInteractHelper; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ArmorStandTooltipHandler { + + public static void onItemTooltip(ItemStack stack, @Nullable Player player, List lines, TooltipFlag context) { + if (stack.is(Items.ARMOR_STAND)) { + Component component = ArmorStandInteractHelper.getArmorStandHoverText(); + if (context.isAdvanced()) { + lines.add(lines.size() - (stack.hasTag() ? 2 : 1), component); + } else { + lines.add(component); + } + } + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java new file mode 100644 index 0000000..32bf170 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -0,0 +1,28 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreen; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +public class DataSyncTickHandler { + @Nullable + private static DataSyncHandler dataSyncHandler; + + public static void onRemove(Screen screen) { + if (screen instanceof ArmorStandScreen armorStandScreen && armorStandScreen.getDataSyncHandler().shouldContinueTicking()) { + dataSyncHandler = armorStandScreen.getDataSyncHandler(); + } + } + + public static void onEndClientTick(Minecraft minecraft) { + if (!(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (dataSyncHandler.shouldContinueTicking()) { + dataSyncHandler.tick(); + } else { + dataSyncHandler = null; + } + } + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java new file mode 100644 index 0000000..14fcfee --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -0,0 +1,10 @@ +package fuzs.armorstatues.config; + +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.AbstractArmorStandScreen; +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; + +public class ClientConfig implements ConfigCore { + @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) + public boolean useVanillaTweaksTriggers = false; +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java new file mode 100644 index 0000000..517095a --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.handler; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.S2CPingMessage; +import fuzs.armorstatues.proxy.Proxy; +import fuzs.puzzlesapi.api.statues.v1.helper.ArmorStandInteractHelper; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.Connection; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class ArmorStandInteractHandler { + private static boolean presentServerside; + + public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { + if (!player.isSpectator() && target.getType() == EntityType.ARMOR_STAND) { + EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get(), ModRegistry.ARMOR_STAND_DATA_PROVIDER); + if (result.isInterrupt() && level.isClientSide && !presentServerside) { + Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); + // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen + // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here + player.swing(interactionHand); + return EventResultHolder.interrupt(InteractionResult.FAIL); + } + return result; + } + return EventResultHolder.pass(); + } + + public static void onLoggedIn(ServerPlayer player) { + ArmorStatues.NETWORK.sendTo(new S2CPingMessage(), player); + } + + public static void onLoggedIn(LocalPlayer player, MultiPlayerGameMode multiPlayerGameMode, Connection connection) { + presentServerside = false; + } + + public static void setPresentServerside() { + presentServerside = true; + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java new file mode 100644 index 0000000..06bf4cd --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -0,0 +1,31 @@ +package fuzs.armorstatues.init; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzlesapi.api.statues.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandMenu; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.puzzleslib.api.init.v2.RegistryManager; +import fuzs.puzzleslib.api.init.v2.RegistryReference; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.instant(ArmorStatues.MOD_ID); + public static final RegistryReference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuType("armor_stand", () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + }); + + public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); + public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandScreenType.EQUIPMENT}; + } + }; + + public static void touch() { + + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java new file mode 100644 index 0000000..f2d0bbe --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java @@ -0,0 +1,30 @@ +package fuzs.armorstatues.network; + +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.network.v2.MessageV2; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; + +public class S2CPingMessage implements MessageV2 { + + @Override + public void write(FriendlyByteBuf buf) { + + } + + @Override + public void read(FriendlyByteBuf buf) { + + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CPingMessage message, Player player, Object gameInstance) { + ArmorStandInteractHandler.setPresentServerside(); + } + }; + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java new file mode 100644 index 0000000..c51faae --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -0,0 +1,207 @@ +package fuzs.armorstatues.network.client.data; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandPose; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOption; +import net.minecraft.ChatFormatting; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.function.BiPredicate; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class CommandDataSyncHandler implements DataSyncHandler { + public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; + private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); + + @Nullable + private static ArmorStand queueArmorStand; + private static int itemDequeuedTicks; + protected final LocalPlayer player; + private final ArmorStandHolder holder; + protected ArmorStandPose lastSyncedPose; + + public CommandDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + this.holder = holder; + this.lastSyncedPose = ArmorStandPose.fromEntity(this.holder.getArmorStand()); + this.player = player; + } + + @Override + public ArmorStandHolder getArmorStandHolder() { + return this.holder; + } + + @Override + public void sendName(String name) { + if (!this.testPermissionLevel()) return; + DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); + CompoundTag tag = new CompoundTag(); + tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); + this.enqueueEntityData(tag); + this.finalizeCurrentOperation(); + } + + @Override + public final void sendPose(ArmorStandPose pose) { + this.sendPose(pose, true); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.testPermissionLevel()) return; + pose.applyToEntity(this.getArmorStand()); + // split this into multiple chat messages as the client chat field has a very low character limit + this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + if (finalize) this.finalizeCurrentOperation(); + } + + private void sendPosePart(BiPredicate dataWriter, ArmorStandPose lastSyncedPose) { + CompoundTag tag = new CompoundTag(); + if (dataWriter.test(tag, lastSyncedPose)) { + CompoundTag tagToSend = new CompoundTag(); + tagToSend.put("Pose", tag); + this.enqueueEntityData(tagToSend); + } + } + + @Override + public final void sendPosition(double posX, double posY, double posZ) { + this.sendPosition(posX, posY, posZ, true); + + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.testPermissionLevel()) return; + ListTag listTag = new ListTag(); + listTag.add(DoubleTag.valueOf(posX)); + listTag.add(DoubleTag.valueOf(posY)); + listTag.add(DoubleTag.valueOf(posZ)); + CompoundTag tag = new CompoundTag(); + tag.put("Pos", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendRotation(float rotation) { + this.sendRotation(rotation, true); + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.testPermissionLevel()) return; + ListTag listTag = new ListTag(); + listTag.add(FloatTag.valueOf(rotation)); + CompoundTag tag = new CompoundTag(); + tag.put("Rotation", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + this.sendStyleOption(styleOption, value, true); + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.testPermissionLevel()) return; + styleOption.setOption(this.getArmorStand(), value); + CompoundTag tag = new CompoundTag(); + styleOption.toTag(tag, value); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public ArmorStandScreenType[] tabs() { + return Stream.of(this.getArmorStandHolder().getDataProvider().getScreenTypes()).filter(Predicate.not(ArmorStandScreenType::requiresServer)).toArray(ArmorStandScreenType[]::new); + } + + @Override + public boolean supportsScreenType(ArmorStandScreenType screenType) { + return !screenType.requiresServer(); + } + + @Override + public void tick() { + if (itemDequeuedTicks > 0) itemDequeuedTicks--; + if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { + if (queueArmorStand.isAlive()) { + this.player.connection.sendCommand(CLIENT_COMMAND_QUEUE.poll()); + } else { + CLIENT_COMMAND_QUEUE.clear(); + } + itemDequeuedTicks = this.getDequeueDelayTicks(); + } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { + this.sendDisplayMessage(Component.translatable(FINISHED_TRANSLATION_KEY), false); + } + } + + protected int getDequeueDelayTicks() { + return 5; + } + + @Override + public boolean shouldContinueTicking() { + return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; + } + + private boolean testPermissionLevel() { + if (!this.player.hasPermissions(2)) { + this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); + return false; + } + return true; + } + + protected boolean enqueueClientCommand(String clientCommand) { + if (CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = null; + } else if (queueArmorStand != null) { + this.sendFailureMessage(Component.translatable(NOT_FINISHED_TRANSLATION_KEY)); + return false; + } + CLIENT_COMMAND_QUEUE.offer(clientCommand); + return true; + } + + @Override + public void finalizeCurrentOperation() { + if (!CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = this.getArmorStand(); + } + } + + protected void sendFailureMessage(Component component) { + this.sendDisplayMessage(Component.translatable(FAILURE_TRANSLATION_KEY, component), true); + } + + protected void sendDisplayMessage(Component component, boolean failure) { + this.player.displayClientMessage(Component.empty().append(component).withStyle(failure ? ChatFormatting.RED : ChatFormatting.GREEN), false); + } + + private void enqueueEntityData(CompoundTag tag) { + this.enqueueClientCommand("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString())); + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java new file mode 100644 index 0000000..21798c4 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -0,0 +1,227 @@ +package fuzs.armorstatues.network.client.data; + +import com.google.common.collect.ImmutableSortedMap; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandPose; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOption; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOptions; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.Rotations; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.NavigableMap; + +public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { + public static final int SHOW_BASE_PLATE_YES = 1; + public static final int SHOW_BASE_PLATE_NO = 2; + public static final int SHOW_ARMS_YES = 3; + public static final int SHOW_ARMS_NO = 4; + public static final int SMALL_STAND_YES = 5; + public static final int SMALL_STAND_NO = 6; + public static final int APPLY_GRAVITY_YES = 7; + public static final int APPLY_GRAVITY_NO = 8; + public static final int STAND_VISIBLE_YES = 9; + public static final int STAND_VISIBLE_NO = 10; + public static final int DISPLAY_NAME_YES = 11; + public static final int DISPLAY_NAME_NO = 12; + public static final int NUDGE_POSITION_X8_NEGATIVE = 40; + public static final int NUDGE_POSITION_X3_NEGATIVE = 101; + public static final int NUDGE_POSITION_X1_NEGATIVE = 102; + public static final int NUDGE_POSITION_X1_POSITIVE = 103; + public static final int NUDGE_POSITION_X3_POSITIVE = 104; + public static final int NUDGE_POSITION_X8_POSITIVE = 43; + public static final int NUDGE_POSITION_Y8_NEGATIVE = 44; + public static final int NUDGE_POSITION_Y3_NEGATIVE = 105; + public static final int NUDGE_POSITION_Y1_NEGATIVE = 106; + public static final int NUDGE_POSITION_Y1_POSITIVE = 107; + public static final int NUDGE_POSITION_Y3_POSITIVE = 108; + public static final int NUDGE_POSITION_Y8_POSITIVE = 47; + public static final int NUDGE_POSITION_Z8_NEGATIVE = 48; + public static final int NUDGE_POSITION_Z3_NEGATIVE = 109; + public static final int NUDGE_POSITION_Z1_NEGATIVE = 110; + public static final int NUDGE_POSITION_Z1_POSITIVE = 111; + public static final int NUDGE_POSITION_Z3_POSITIVE = 112; + public static final int NUDGE_POSITION_Z8_POSITIVE = 51; + public static final int ADJUST_ROTATION_ANGLE_STEP_45 = 120; + public static final int ADJUST_ROTATION_ANGLE_STEP_15 = 121; + public static final int ADJUST_ROTATION_ANGLE_STEP_5 = 122; + public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; + public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; + public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; + public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; + public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; + public static final int POSE_ADJUSTMENT_HEAD_Y_POSITIVE = 63; + public static final int POSE_ADJUSTMENT_HEAD_Z_NEGATIVE = 64; + public static final int POSE_ADJUSTMENT_HEAD_Z_POSITIVE = 65; + public static final int POSE_ADJUSTMENT_BODY_X_NEGATIVE = 67; + public static final int POSE_ADJUSTMENT_BODY_X_POSITIVE = 66; + public static final int POSE_ADJUSTMENT_BODY_Y_NEGATIVE = 68; + public static final int POSE_ADJUSTMENT_BODY_Y_POSITIVE = 69; + public static final int POSE_ADJUSTMENT_BODY_Z_NEGATIVE = 70; + public static final int POSE_ADJUSTMENT_BODY_Z_POSITIVE = 71; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE = 72; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE = 73; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE = 74; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE = 75; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE = 77; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE = 76; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE = 78; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE = 79; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE = 81; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE = 80; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE = 82; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE = 83; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE = 84; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE = 85; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE = 87; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE = 86; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE = 89; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE = 88; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE = 90; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE = 91; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE = 92; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE = 93; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; + private static final int MAX_INCREMENTAL_OPERATIONS = 12; + private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_LEG = new int[]{POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE}; + private static final NavigableMap NUDGE_POSITIONS_X_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_X3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_X8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_X_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_X3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_X8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_POSITIVE); + private static final NavigableMap ADJUST_ROTATION_ANGLE_STEPS = ImmutableSortedMap.of(1.0F, ADJUST_ROTATION_ANGLE_STEP_1, 5.0F, ADJUST_ROTATION_ANGLE_STEP_5, 15.0F, ADJUST_ROTATION_ANGLE_STEP_15, 45.0F, ADJUST_ROTATION_ANGLE_STEP_45); + + public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + super(holder, player); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + $1: + { + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD)) + break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY)) + break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM)) + break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM)) + break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG)) + break $1; + if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG)) + break $1; + } + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean tryApplyPoseIncrements(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + if (newPose == null || oldPose.equals(newPose)) return true; + if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) + return false; + if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) + return false; + if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) + return false; + return true; + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); + if (finalize) this.finalizeCurrentOperation(); + } + + private void applyPositionIncrements(double oldValue, double newValue, NavigableMap positiveNudgePositions, NavigableMap negativeNudgePositions) { + double value = newValue - oldValue; + double signum = Math.signum(value); + value = Math.abs(value); + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = (signum == -1.0F ? negativeNudgePositions : positiveNudgePositions).floorEntry(value); + if (entry != null) { + value -= entry.getKey(); + if (!this.enqueueTriggerValue(entry.getValue())) { + return; + } + } else { + break; + } + } + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean applyIncrementsFromSteps(float oldValue, float newValue, int triggerValueNegative, int triggerValuePositive) { + float value = newValue - oldValue; + float signum = Math.signum(value); + value = Math.abs(value); + float lastIncrement = 0.0F; + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = ADJUST_ROTATION_ANGLE_STEPS.floorEntry(value); + if (entry != null) { + float currentIncrement = entry.getKey(); + value -= currentIncrement; + if (currentIncrement != lastIncrement) { + lastIncrement = currentIncrement; + if (!this.enqueueTriggerValue(entry.getValue())) { + return false; + } + } + if (!this.enqueueTriggerValue(signum == -1.0F ? triggerValuePositive : triggerValueNegative)) { + return false; + } + } else { + break; + } + } + return true; + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + int triggerValue; + if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { + triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; + } else if (styleOption == ArmorStandStyleOptions.SHOW_ARMS) { + triggerValue = value ? SHOW_ARMS_YES : SHOW_ARMS_NO; + } else if (styleOption == ArmorStandStyleOptions.SMALL) { + triggerValue = value ? SMALL_STAND_YES : SMALL_STAND_NO; + } else if (styleOption == ArmorStandStyleOptions.INVISIBLE) { + triggerValue = value ? STAND_VISIBLE_NO : STAND_VISIBLE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_BASE_PLATE) { + triggerValue = value ? SHOW_BASE_PLATE_NO : SHOW_BASE_PLATE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_GRAVITY) { + triggerValue = value ? APPLY_GRAVITY_NO : APPLY_GRAVITY_YES; + } else { + super.sendStyleOption(styleOption, value, finalize); + return; + } + this.enqueueTriggerValue(triggerValue); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + protected int getDequeueDelayTicks() { + return 20; + } + + private boolean enqueueTriggerValue(int triggerValue) { + return this.enqueueClientCommand("trigger as_trigger set %s".formatted(triggerValue)); + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java new file mode 100644 index 0000000..38e9040 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -0,0 +1,46 @@ +package fuzs.armorstatues.proxy; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreenFactory; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ClientProxy extends ServerProxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + ArmorStandHolder holder = new ArmorStandHolder() { + + @Override + public ArmorStand getArmorStand() { + return armorStand; + } + + @Override + public ArmorStandDataProvider getDataProvider() { + return ModRegistry.ARMOR_STAND_DATA_PROVIDER; + } + }; + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(holder, (LocalPlayer) player)); + Minecraft minecraft = Minecraft.getInstance(); + minecraft.setScreen(screen); + } + + private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + if (!player.hasPermissions(2) && ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + return new VanillaTweaksDataSyncHandler(holder, player); + } else { + return new CommandDataSyncHandler(holder, player); + } + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.20/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java new file mode 100644 index 0000000..1f5ae83 --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java @@ -0,0 +1,11 @@ +package fuzs.armorstatues.proxy; + +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public interface Proxy { + Proxy INSTANCE = ModLoaderEnvironment.INSTANCE.isClient() ? new ClientProxy() : new ServerProxy(); + + void openArmorStandScreen(ArmorStand armorStand, Player player); +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java new file mode 100644 index 0000000..81856ec --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java @@ -0,0 +1,12 @@ +package fuzs.armorstatues.proxy; + +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ServerProxy implements Proxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + + } +} diff --git a/1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java deleted file mode 100644 index 45113b2..0000000 --- a/1.20/Common/src/main/java/fuzs/examplemod/ExampleMod.java +++ /dev/null @@ -1,16 +0,0 @@ -package fuzs.examplemod; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import net.minecraft.resources.ResourceLocation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ExampleMod implements ModConstructor { - public static final String MOD_ID = "examplemod"; - public static final String MOD_NAME = "Example Mod"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - - public static ResourceLocation id(String path) { - return new ResourceLocation(MOD_ID, path); - } -} diff --git a/1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java deleted file mode 100644 index e1afacc..0000000 --- a/1.20/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java +++ /dev/null @@ -1,7 +0,0 @@ -package fuzs.examplemod.client; - -import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; - -public class ExampleModClient implements ClientModConstructor { - -} diff --git a/1.20/Common/src/main/resources/examplemod.common.mixins.json b/1.20/Common/src/main/resources/examplemod.common.mixins.json deleted file mode 100644 index ec8895e..0000000 --- a/1.20/Common/src/main/resources/examplemod.common.mixins.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "package": "fuzs.examplemod.mixin", - "refmap": "examplemod.refmap.json", - "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", - "mixins": [ - ], - "client": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/1.20/Common/src/main/resources/mod_banner.png b/1.20/Common/src/main/resources/mod_banner.png index bda5a0f63968a9c20cc144359547c6d8bb1e893b..62a46106e75f6f8cfd477182314002fec637c712 100644 GIT binary patch literal 15383 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 diff --git a/1.20/Common/src/main/resources/mod_logo.png b/1.20/Common/src/main/resources/mod_logo.png index 98c247e46e4c250202abe7f66209dd16464ade34..869766bc4501f6aeda2fe5e7826e13b8e7645b3b 100644 GIT binary patch literal 9380 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 diff --git a/1.20/Fabric/build.gradle b/1.20/Fabric/build.gradle index cd8b641..56fc5da 100644 --- a/1.20/Fabric/build.gradle +++ b/1.20/Fabric/build.gradle @@ -9,6 +9,11 @@ dependencies { // Puzzles Lib modApi libs.puzzleslib.fabric + // Puzzles Api + modApi(include(libs.puzzlesapi.fabric.get())) { + exclude group: "fuzs.puzzleslib" + } + // Cardinal Components // modApi(include(libs.cardinalcomponentsbase.fabric.get())) // modApi(include(libs.cardinalcomponentsentity.fabric.get())) diff --git a/1.20/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/1.20/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java new file mode 100644 index 0000000..65493b3 --- /dev/null +++ b/1.20/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java @@ -0,0 +1,12 @@ +package fuzs.armorstatues; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.fabricmc.api.ModInitializer; + +public class ArmorStatuesFabric implements ModInitializer { + + @Override + public void onInitialize() { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + } +} diff --git a/1.20/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/1.20/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java new file mode 100644 index 0000000..ee3baac --- /dev/null +++ b/1.20/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java @@ -0,0 +1,13 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import net.fabricmc.api.ClientModInitializer; + +public class ArmorStatuesFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); + } +} diff --git a/1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java deleted file mode 100644 index 124b062..0000000 --- a/1.20/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java +++ /dev/null @@ -1,12 +0,0 @@ -package fuzs.examplemod; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import net.fabricmc.api.ModInitializer; - -public class ExampleModFabric implements ModInitializer { - - @Override - public void onInitialize() { - ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); - } -} diff --git a/1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java deleted file mode 100644 index 7b55517..0000000 --- a/1.20/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java +++ /dev/null @@ -1,13 +0,0 @@ -package fuzs.examplemod.client; - -import fuzs.examplemod.ExampleMod; -import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; -import net.fabricmc.api.ClientModInitializer; - -public class ExampleModFabricClient implements ClientModInitializer { - - @Override - public void onInitializeClient() { - ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); - } -} diff --git a/1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index 6d413e8..0000000 --- a/1.20/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.examplemod.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/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.20/Fabric/src/main/resources/examplemod.fabric.mixins.json deleted file mode 100644 index ec8895e..0000000 --- a/1.20/Fabric/src/main/resources/examplemod.fabric.mixins.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "package": "fuzs.examplemod.mixin", - "refmap": "examplemod.refmap.json", - "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", - "mixins": [ - ], - "client": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/1.20/Fabric/src/main/resources/fabric.mod.json b/1.20/Fabric/src/main/resources/fabric.mod.json index 07fc00c..1fb00d5 100644 --- a/1.20/Fabric/src/main/resources/fabric.mod.json +++ b/1.20/Fabric/src/main/resources/fabric.mod.json @@ -31,8 +31,6 @@ }, "mixins": [ - "${modId}.common.mixins.json", - "${modId}.fabric.mixins.json" ], "depends": { diff --git a/1.20/Forge/build.gradle b/1.20/Forge/build.gradle index dec494a..29049d3 100644 --- a/1.20/Forge/build.gradle +++ b/1.20/Forge/build.gradle @@ -6,10 +6,20 @@ dependencies { // Puzzles Lib api fg.deobf(libs.puzzleslib.forge.get()) + // Puzzles Api + api(fg.deobf(libs.puzzlesapi.forge.get())) { + transitive = false + } + jarJar(fg.deobf(libs.puzzlesapi.forge.get()) { + jarJar.ranged(it, "[${libs.versions.puzzlesapi.get()},)") + transitive = false + }) + // Quality of Life Mods versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { runtimeOnly fg.deobf(it.get()) } +// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.get()}") versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { runtimeOnly fg.deobf(it.get()) } diff --git a/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 new file mode 100644 index 0000000..74d892b --- /dev/null +++ b/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -0,0 +1,2 @@ +// 1.20.1 2023-07-27T18:19:44.79768 Languages: en_us +0631eade65589ccf2216571b521d4f32b3e2b8d6 assets/armorstatues/lang/en_us.json diff --git a/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json new file mode 100644 index 0000000..2cd376b --- /dev/null +++ b/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -0,0 +1,7 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.finished": "Finished sending queued armor stand data", + "puzzlesapi.screen.type.alignments": "Alignments" +} \ No newline at end of file diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.20/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java new file mode 100644 index 0000000..346a4a5 --- /dev/null +++ b/1.20/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java @@ -0,0 +1,23 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.data.ModLanguageProvider; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(ArmorStatues.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ArmorStatuesForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + evt.getGenerator().addProvider(true, new ModLanguageProvider(evt, ArmorStatues.MOD_ID)); + } +} diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.20/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java new file mode 100644 index 0000000..c50ecce --- /dev/null +++ b/1.20/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ArmorStatuesForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); + registerHandlers(); + } + + private static void registerHandlers() { + MinecraftForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { + + Minecraft minecraft = Minecraft.getInstance(); + if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { + + EntityHitResult hitResult = (EntityHitResult) minecraft.hitResult; + Entity entity = hitResult.getEntity(); + if (minecraft.level.getWorldBorder().isWithinBounds(entity.blockPosition())) { + + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work + if (result.filter(t -> t == InteractionResult.FAIL).isInterrupt()) { + evt.setSwingHand(false); + evt.setCanceled(true); + } + } + } + }); + } +} diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java new file mode 100644 index 0000000..10070eb --- /dev/null +++ b/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -0,0 +1,23 @@ +package fuzs.armorstatues.data; + +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.puzzleslib.api.data.v1.AbstractLanguageProvider; +import net.minecraftforge.data.event.GatherDataEvent; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(GatherDataEvent evt, String modId) { + super(evt, modId); + } + + @Override + protected void addTranslations() { + // Armor Statues + this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); + this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + } +} diff --git a/1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java deleted file mode 100644 index 730ddd3..0000000 --- a/1.20/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java +++ /dev/null @@ -1,31 +0,0 @@ -package fuzs.examplemod; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import net.minecraft.core.HolderLookup; -import net.minecraft.data.DataGenerator; -import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -import java.util.concurrent.CompletableFuture; - -@Mod(ExampleMod.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -public class ExampleModForge { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); - } - - @SubscribeEvent - public static void onGatherData(final GatherDataEvent evt) { - final DataGenerator dataGenerator = evt.getGenerator(); - final PackOutput packOutput = dataGenerator.getPackOutput(); - final CompletableFuture lookupProvider = evt.getLookupProvider(); - final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); - } -} diff --git a/1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java deleted file mode 100644 index d6502ba..0000000 --- a/1.20/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java +++ /dev/null @@ -1,17 +0,0 @@ -package fuzs.examplemod.client; - -import fuzs.examplemod.ExampleMod; -import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; -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 = ExampleMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class ExampleModForgeClient { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); - } -} diff --git a/1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index af281eb..0000000 --- a/1.20/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.examplemod.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/Forge/src/main/resources/examplemod.forge.mixins.json b/1.20/Forge/src/main/resources/examplemod.forge.mixins.json deleted file mode 100644 index ec8895e..0000000 --- a/1.20/Forge/src/main/resources/examplemod.forge.mixins.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "package": "fuzs.examplemod.mixin", - "refmap": "examplemod.refmap.json", - "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", - "mixins": [ - ], - "client": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/1.20/gradle.properties b/1.20/gradle.properties index ac98db0..402447b 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -6,29 +6,30 @@ org.gradle.parallel=true copyBuildJar=true # Mod Attributes -modId=examplemod -modName=Example Mod +modId=armorstatues +modName=Armor Statues modVersion=8.0.0 modAuthor=Fuzs -modDescription=Example description. +modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 -modSourceUrl=https://github.com/Fuzss/examplemod -modIssueUrl=https://github.com/Fuzss/examplemod/issues -modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/examplemod.json -modMavenGroup=fuzs.examplemod +modSourceUrl=https://github.com/Fuzss/armorstatues +modIssueUrl=https://github.com/Fuzss/armorstatues/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/armorstatues.json +modMavenGroup=fuzs.armorstatues # "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 +modForgeDisplayTest=IGNORE_ALL_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=0 -projectModrinthId=0 +projectCurseForgeId=682566 +projectModrinthId=bbGCtEvb -dependenciesVersionCatalog=1.20.1-v7 -#dependenciesPuzzlesLibVersion=8.0.6 -#dependenciesMinPuzzlesLibVersion=8.0.6 +dependenciesVersionCatalog=1.20.1-v11 +dependenciesPuzzlesLibVersion=8.0.13 +dependenciesMinPuzzlesLibVersion=8.0.13 +dependenciesPuzzlesApi=8.1.1 dependenciesRequiredForgeCurseForge=puzzles-lib dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib dependenciesRequiredForgeModrinth=puzzles-lib From fdfa8148dd325828b82f0589bf9a5cce1e64df07 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:14:17 +0200 Subject: [PATCH 15/31] better vanilla tweaks integration --- 1.19/CHANGELOG.md | 6 + .../client/gui/components/TickBoxButton.java | 25 +-- .../AbstractArmorStandPositionScreen.java | 52 ------ .../armorstand/AbstractArmorStandScreen.java | 12 +- .../armorstand/ArmorStandButtonsScreen.java | 84 +++++++++ .../armorstand/ArmorStandEquipmentScreen.java | 10 +- .../armorstand/ArmorStandPosesScreen.java | 8 +- .../armorstand/ArmorStandPositionScreen.java | 19 +- .../armorstand/ArmorStandRotationsScreen.java | 16 +- .../armorstand/ArmorStandScreenFactory.java | 2 +- .../armorstand/ArmorStandStyleScreen.java | 8 +- .../armorstand/ArmorStandWidgetsScreen.java | 35 ++-- .../network/client/data/DataSyncHandler.java | 56 +++++- .../client/data/NetworkDataSyncHandler.java | 6 - .../world/inventory/data/ArmorStandPose.java | 109 ++++++----- .../inventory/data/ArmorStandStyleOption.java | 2 - .../data/ArmorStandStyleOptions.java | 6 +- .../client/ArmorStatuesClient.java | 4 +- .../ArmorStandAlignmentsScreen.java | 88 ++------- .../ArmorStandVanillaTweaksScreen.java | 75 ++++++++ .../handler/DataSyncTickHandler.java | 4 +- .../armorstatues/config/ClientConfig.java | 3 + .../fuzs/armorstatues/init/ModRegistry.java | 1 + .../client/data/CommandDataSyncHandler.java | 45 +++-- .../data/VanillaTweaksDataSyncHandler.java | 159 ++++++++++++++-- .../client/ArmorStatuesFabricClient.java | 2 +- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../resources/assets/statues/lang/en_us.json | 24 ++- .../client/ArmorStatuesForgeClient.java | 2 +- .../data/ModLanguageProvider.java | 42 +++-- 1.19/gradle.properties | 2 +- 1.20/CHANGELOG.md | 6 + .../client/ArmorStatuesClient.java | 2 + .../ArmorStandAlignmentsScreen.java | 87 ++------- .../ArmorStandVanillaTweaksScreen.java | 75 ++++++++ .../client/handler/DataSyncTickHandler.java | 2 +- .../armorstatues/config/ClientConfig.java | 3 + .../fuzs/armorstatues/init/ModRegistry.java | 1 + .../client/data/CommandDataSyncHandler.java | 48 +++-- .../data/VanillaTweaksDataSyncHandler.java | 176 +++++++++++++++--- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../assets/armorstatues/lang/en_us.json | 17 +- .../data/ModLanguageProvider.java | 16 ++ 1.20/gradle.properties | 4 +- 44 files changed, 923 insertions(+), 429 deletions(-) delete mode 100644 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java create mode 100644 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java create mode 100644 1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java rename 1.19/Common/src/main/java/fuzs/armorstatues/{ => client}/handler/DataSyncTickHandler.java (84%) create mode 100644 1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java diff --git a/1.19/CHANGELOG.md b/1.19/CHANGELOG.md index f0c6550..76d52f3 100644 --- a/1.19/CHANGELOG.md +++ b/1.19/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.7-1.19.2] - 2023-07-28 +### Added +- Added a new tab that only shows when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack offering Vanilla Tweaks exclusive toggles +### Changed +- Optimized some actions during editing to be performed much quicker when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack + ## [v4.0.6-1.19.2] - 2023-07-26 ### Fixed - Fixed an issue where new rotations set on the rotations screen wouldn't save if the sliders were moved using the arrow keys diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java index c2c1a03..0e780bc 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java @@ -8,32 +8,19 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.components.Button; -import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; +import java.util.function.BooleanSupplier; + public class TickBoxButton extends Button { private final int textMargin; - private boolean selected; - - public TickBoxButton(int posX, int posY, boolean selected, OnPress onPress, OnTooltip onTooltip) { - this(posX, posY, 0, 0, CommonComponents.EMPTY, selected, onPress, onTooltip); - } + private final BooleanSupplier supplier; - public TickBoxButton(int posX, int posY, int textMargin, int textWidth, Component component, boolean selected, OnPress onPress, OnTooltip onTooltip) { + public TickBoxButton(int posX, int posY, int textMargin, int textWidth, Component component, BooleanSupplier supplier, OnPress onPress, OnTooltip onTooltip) { super(posX, posY, 20 + textMargin + textWidth, 20, component, onPress, onTooltip); this.textMargin = textMargin; - this.selected = selected; - } - - @Override - public void onPress() { - this.selected = !this.selected; - super.onPress(); - } - - public boolean isSelected() { - return this.selected; + this.supplier = supplier; } @Override @@ -47,7 +34,7 @@ public void renderButton(PoseStack poseStack, int mouseX, int mouseY, float part RenderSystem.defaultBlendFunc(); RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); blit(poseStack, this.x + 2, this.y + 2, 196.0F, this.isHoveredOrFocused() ? 16.0F : 0.0F, 16, 16, 256, 256); - if (this.selected) { + if (this.supplier.getAsBoolean()) { blit(poseStack, this.x + 2, this.y + 2, 196.0F, 32.0F + (this.isHoveredOrFocused() ? 16.0F : 0.0F), 16, 16, 256, 256); } final int textColor = this.active ? (this.isHoveredOrFocused() ? ChatFormatting.YELLOW.getColor() : 16777215) : 10526880; diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java deleted file mode 100644 index a3ccbff..0000000 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandPositionScreen.java +++ /dev/null @@ -1,52 +0,0 @@ -package fuzs.armorstatues.api.client.gui.screens.armorstand; - -import fuzs.armorstatues.api.StatuesApi; -import fuzs.armorstatues.api.client.gui.components.TickButton; -import fuzs.armorstatues.api.network.client.data.DataSyncHandler; -import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.phys.Vec3; - -import java.util.EnumSet; - -public abstract class AbstractArmorStandPositionScreen extends ArmorStandWidgetsScreen { - public static final String CENTERED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.centered"; - public static final String CENTERED_DESCRIPTION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.centered.description"; - public static final String CORNERED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.cornered"; - public static final String CORNERED_DESCRIPTION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.cornered.description"; - - public AbstractArmorStandPositionScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { - super(holder, inventory, component, dataSyncHandler); - } - - protected class PositionAlignWidget extends AbstractPositionScreenWidget { - - public PositionAlignWidget() { - super(Component.empty()); - } - - @Override - protected boolean shouldTick() { - return true; - } - - @Override - public void init(int posX, int posY) { - super.init(posX, posY); - this.children.add(AbstractArmorStandPositionScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, Component.translatable(CENTERED_TRANSLATION_KEY), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { - Vec3 newPosition = AbstractArmorStandPositionScreen.this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); - AbstractArmorStandPositionScreen.this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); - }, (button, poseStack, mouseX, mouseY) -> { - AbstractArmorStandPositionScreen.this.renderTooltip(poseStack, AbstractArmorStandPositionScreen.this.font.split(Component.translatable(CENTERED_DESCRIPTION_TRANSLATION_KEY), 175), mouseX, mouseY); - }))); - this.children.add(AbstractArmorStandPositionScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, Component.translatable(CORNERED_TRANSLATION_KEY), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { - Vec3 newPosition = AbstractArmorStandPositionScreen.this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); - AbstractArmorStandPositionScreen.this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); - }, (button, poseStack, mouseX, mouseY) -> { - AbstractArmorStandPositionScreen.this.renderTooltip(poseStack, AbstractArmorStandPositionScreen.this.font.split(Component.translatable(CORNERED_DESCRIPTION_TRANSLATION_KEY), 175), mouseX, mouseY); - }))); - } - } -} diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java index 6b90ccc..aba9bad 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java @@ -38,8 +38,6 @@ public abstract class AbstractArmorStandScreen extends Screen implements MenuAccess, ArmorStandScreen { public static final String VANILLA_TWEAKS_HOMEPAGE = "https://vanillatweaks.net/"; public static final String CREDITS_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.credits"; - public static final String APPLIED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.applied"; - public static final String ALIGNED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.aligned"; private static final ResourceLocation ARMOR_STAND_BACKGROUND_LOCATION = StatuesApi.id("textures/gui/container/statue/background.png"); private static final ResourceLocation ARMOR_STAND_WIDGETS_LOCATION = StatuesApi.id("textures/gui/container/statue/widgets.png"); private static final ResourceLocation ARMOR_STAND_EQUIPMENT_LOCATION = StatuesApi.id("textures/gui/container/statue/equipment.png"); @@ -165,7 +163,7 @@ protected void addVanillaTweaksCreditsButton() { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0) { - if (!this.disableMenuRendering() && handleTabClicked((int) mouseX, (int) mouseY, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs())) { + if (!this.disableMenuRendering() && handleTabClicked((int) mouseX, (int) mouseY, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.getScreenTypes())) { return true; } } @@ -180,7 +178,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic this.renderBg(poseStack, partialTick, mouseX, mouseY); super.render(poseStack, mouseX, mouseY, partialTick); if (!this.disableMenuRendering()) { - findHoveredTab(this.leftPos, this.topPos, this.imageHeight, mouseX, mouseY, this.dataSyncHandler.tabs()).ifPresent(hoveredTab -> { + findHoveredTab(this.leftPos, this.topPos, this.imageHeight, mouseX, mouseY, this.dataSyncHandler.getScreenTypes()).ifPresent(hoveredTab -> { this.renderTooltip(poseStack, Component.translatable(hoveredTab.getTranslationKey()), mouseX, mouseY); }); } @@ -194,7 +192,7 @@ protected void renderBg(PoseStack poseStack, float partialTick, int mouseX, int RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.setShaderTexture(0, getArmorStandBackgroundLocation()); this.blit(poseStack, this.leftPos, this.topPos, 0, 0, this.imageWidth, this.imageHeight); - drawTabs(poseStack, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); + drawTabs(poseStack, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.getScreenTypes()); this.renderEntityInInventory(poseStack); } } @@ -235,7 +233,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { } else if (this.minecraft.options.keyInventory.matches(keyCode, scanCode)) { this.onClose(); return true; - } else if (handleHotbarKeyPressed(keyCode, scanCode, this, this.dataSyncHandler.tabs())) { + } else if (handleHotbarKeyPressed(keyCode, scanCode, this, this.dataSyncHandler.getScreenTypes())) { return true; } return false; @@ -258,7 +256,7 @@ public boolean mouseScrolled(double mouseX, double mouseY, double delta) { if (super.mouseScrolled(mouseX, mouseY, delta)) { return true; } else { - return handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); + return handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.getScreenTypes()); } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java new file mode 100644 index 0000000..486e9cb --- /dev/null +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java @@ -0,0 +1,84 @@ +package fuzs.armorstatues.api.client.gui.screens.armorstand; + +import fuzs.armorstatues.api.client.gui.components.TickButton; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; +import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; +import net.minecraft.client.gui.components.Button; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +public abstract class ArmorStandButtonsScreen extends ArmorStandWidgetsScreen { + + public ArmorStandButtonsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + protected class SingleButtonWidget extends AbstractArmorStandWidget { + private final Component title; + private final Component description; + private final Component clickedTitle; + private final Button.OnPress onPress; + + public SingleButtonWidget(Component title, Component description, Component clickedTitle, Button.OnPress onPress) { + this.title = title; + this.description = description; + this.clickedTitle = clickedTitle; + this.onPress = onPress; + } + + @Override + protected boolean shouldTick() { + return true; + } + + @Override + public void init(int posX, int posY) { + super.init(posX, posY); + this.children.add(ArmorStandButtonsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, this.title, this.clickedTitle, this.onPress, (button, poseStack, mouseX, mouseY) -> { + ArmorStandButtonsScreen.this.renderTooltip(poseStack, ArmorStandButtonsScreen.this.font.split(this.description, 175), mouseX, mouseY); + }))); + } + } + + protected class DoubleButtonWidget extends AbstractArmorStandWidget { + private final Component titleLeft; + private final Component titleRight; + private final Component descriptionLeft; + private final Component descriptionRight; + private final Component clickedTitleLeft; + private final Component clickedTitleRight; + private final Button.OnPress onPressLeft; + private final Button.OnPress onPressRight; + + public DoubleButtonWidget(Component titleLeft, Component titleRight, Component descriptionLeft, Component descriptionRight, Component clickedTitle, Button.OnPress onPressLeft, Button.OnPress onPressRight) { + this(titleLeft, titleRight, descriptionLeft, descriptionRight, clickedTitle, clickedTitle, onPressLeft, onPressRight); + } + + public DoubleButtonWidget(Component titleLeft, Component titleRight, Component descriptionLeft, Component descriptionRight, Component clickedTitleLeft, Component clickedTitleRight, Button.OnPress onPressLeft, Button.OnPress onPressRight) { + this.titleLeft = titleLeft; + this.titleRight = titleRight; + this.descriptionLeft = descriptionLeft; + this.descriptionRight = descriptionRight; + this.clickedTitleLeft = clickedTitleLeft; + this.clickedTitleRight = clickedTitleRight; + this.onPressLeft = onPressLeft; + this.onPressRight = onPressRight; + } + + @Override + protected boolean shouldTick() { + return true; + } + + @Override + public void init(int posX, int posY) { + super.init(posX, posY); + this.children.add(ArmorStandButtonsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 94, 20, this.titleLeft, this.clickedTitleLeft, this.onPressLeft, (button, poseStack, mouseX, mouseY) -> { + ArmorStandButtonsScreen.this.renderTooltip(poseStack, ArmorStandButtonsScreen.this.font.split(this.descriptionLeft, 175), mouseX, mouseY); + }))); + this.children.add(ArmorStandButtonsScreen.this.addRenderableWidget(new TickButton(posX + 100, posY + 1, 94, 20, this.titleRight, this.clickedTitleRight, this.onPressRight, (button, poseStack, mouseX, mouseY) -> { + ArmorStandButtonsScreen.this.renderTooltip(poseStack, ArmorStandButtonsScreen.this.font.split(this.descriptionRight, 175), mouseX, mouseY); + }))); + } + } +} diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java index a93433f..a52d43b 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java @@ -72,7 +72,7 @@ protected void init() { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0) { - if (AbstractArmorStandScreen.handleTabClicked((int) mouseX, (int) mouseY, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs())) { + if (AbstractArmorStandScreen.handleTabClicked((int) mouseX, (int) mouseY, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.getScreenTypes())) { return true; } } @@ -84,7 +84,7 @@ public boolean mouseScrolled(double mouseX, double mouseY, double delta) { if (super.mouseScrolled(mouseX, mouseY, delta)) { return true; } - return AbstractArmorStandScreen.handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); + return AbstractArmorStandScreen.handleMouseScrolled((int) mouseX, (int) mouseY, delta, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.getScreenTypes()); } @Override @@ -94,7 +94,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic super.render(poseStack, mouseX, mouseY, partialTick); this.renderTooltip(poseStack, mouseX, mouseY); if (this.menu.getCarried().isEmpty()) { - AbstractArmorStandScreen.findHoveredTab(this.leftPos, this.topPos, this.imageHeight, mouseX, mouseY, this.dataSyncHandler.tabs()).ifPresent(hoveredTab -> { + AbstractArmorStandScreen.findHoveredTab(this.leftPos, this.topPos, this.imageHeight, mouseX, mouseY, this.dataSyncHandler.getScreenTypes()).ifPresent(hoveredTab -> { this.renderTooltip(poseStack, Component.translatable(hoveredTab.getTranslationKey()), mouseX, mouseY); }); } @@ -114,7 +114,7 @@ protected void renderBg(PoseStack poseStack, float pPartialTick, int pX, int pY) this.blit(poseStack, this.leftPos + slot.x - 1, this.topPos + slot.y - 1, 210, 0, 18, 18); } } - AbstractArmorStandScreen.drawTabs(poseStack, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.tabs()); + AbstractArmorStandScreen.drawTabs(poseStack, this.leftPos, this.topPos, this.imageHeight, this, this.dataSyncHandler.getScreenTypes()); this.renderArmorStandInInventory(this.leftPos + 104, this.topPos + 84, 30, (float) (this.leftPos + 104 - 10) - this.mouseX, (float) (this.topPos + 84 - 44) - this.mouseY); } @@ -129,7 +129,7 @@ protected void renderLabels(PoseStack poseStack, int mouseX, int mouseY) { @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - ArmorStandScreenType[] tabs = this.dataSyncHandler.tabs(); + ArmorStandScreenType[] tabs = this.dataSyncHandler.getScreenTypes(); if (this.menu.getCarried().isEmpty() && this.hoveredSlot == null) { AbstractArmorStandScreen.handleHotbarKeyPressed(keyCode, scanCode, this, tabs); } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java index c5a610f..124431e 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java @@ -2,6 +2,7 @@ import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; @@ -20,6 +21,7 @@ import java.util.Optional; public class ArmorStandPosesScreen extends AbstractArmorStandScreen { + public static final String POSE_SOURCE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.pose.by"; private static final int POSES_PER_PAGE = 4; private static int firstPoseIndex; @@ -52,9 +54,9 @@ protected void init() { if (translationKey != null) { Component component = Component.translatable(translationKey); List lines = Lists.newArrayList(component); - String source = pose.getSource(); - if (!StringUtil.isNullOrEmpty(source)) { - lines.add(Component.translatable(ArmorStandPose.POSE_SOURCE_TRANSLATION_KEY, source).withStyle(ChatFormatting.GRAY)); + String sourceType = pose.getSourceType().getDisplayName(); + if (!StringUtil.isNullOrEmpty(sourceType)) { + lines.add(Component.translatable(POSE_SOURCE_TRANSLATION_KEY, sourceType).withStyle(ChatFormatting.GRAY)); } this.renderTooltip(poseStack, lines, Optional.empty(), mouseX, mouseY); } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java index dd45781..ebefce1 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java @@ -32,7 +32,7 @@ import java.util.function.DoubleSupplier; import java.util.stream.Collectors; -public class ArmorStandPositionScreen extends AbstractArmorStandPositionScreen { +public class ArmorStandPositionScreen extends ArmorStandButtonsScreen { public static final String ROTATION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.rotation"; public static final String POSITION_X_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.x"; public static final String POSITION_Y_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.y"; @@ -43,6 +43,11 @@ public class ArmorStandPositionScreen extends AbstractArmorStandPositionScreen { public static final String BLOCKS_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.blocks"; public static final String DEGREES_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.degrees"; public static final String MOVE_BY_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.position.moveBy"; + public static final String CENTERED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.centered"; + public static final String CENTERED_DESCRIPTION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.centered.description"; + public static final String CORNERED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.cornered"; + public static final String CORNERED_DESCRIPTION_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.cornered.description"; + public static final String ALIGNED_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.aligned"; private static final DecimalFormat BLOCK_INCREMENT_FORMAT = Util.make(new DecimalFormat("#.####"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); }); @@ -67,7 +72,7 @@ public void removed() { } @Override - protected List buildWidgets(ArmorStand armorStand) { + protected List buildWidgets(ArmorStand armorStand) { // only move server-side to prevent rubber banding return Lists.newArrayList( new RotationWidget(Component.translatable(ROTATION_TRANSLATION_KEY), armorStand::getYRot, this.dataSyncHandler::sendRotation), @@ -101,7 +106,7 @@ private static int getBlockPixelIncrement(double increment) { return (int) Math.round(increment * 16.0); } - protected class RotationWidget extends AbstractPositionScreenWidget { + protected class RotationWidget extends AbstractArmorStandWidget { protected final DoubleSupplier currentValue; protected final Consumer newValue; private final double snapInterval; @@ -201,7 +206,7 @@ public void clearDirty() { } } - private class PositionIncrementWidget extends AbstractPositionScreenWidget { + private class PositionIncrementWidget extends AbstractArmorStandWidget { public PositionIncrementWidget() { super(Component.translatable(MOVE_BY_TRANSLATION_KEY)); @@ -236,12 +241,12 @@ private void setActiveIncrement(AbstractWidget source, double increment) { } @Override - public boolean alwaysVisible(@Nullable PositionScreenWidget activeWidget) { + public boolean alwaysVisible(@Nullable ArmorStandWidgetsScreen.ArmorStandWidget activeWidget) { return !(activeWidget instanceof RotationWidget); } } - private class PositionComponentWidget extends AbstractPositionScreenWidget { + private class PositionComponentWidget extends AbstractArmorStandWidget { private final DoubleSupplier currentValue; private final DoubleConsumer newValue; @@ -309,7 +314,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic } @Override - public boolean alwaysVisible(@Nullable PositionScreenWidget activeWidget) { + public boolean alwaysVisible(@Nullable ArmorStandWidgetsScreen.ArmorStandWidget activeWidget) { return activeWidget instanceof PositionIncrementWidget || super.alwaysVisible(activeWidget); } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java index 98605c8..09de06e 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java @@ -113,7 +113,6 @@ public void playDownSound(SoundManager handler) { }, (button, poseStack, mouseX, mouseY) -> { this.renderTooltip(poseStack, Component.translatable(MIRROR_TRANSLATION_KEY), mouseX, mouseY); })); - ArmorStand armorStand = this.holder.getArmorStand(); PosePartMutator[] values = this.holder.getDataProvider().getPosePartMutators(); ArmorStandPose.checkMutatorsSize(values); for (int i = 0; i < values.length; i++) { @@ -151,10 +150,10 @@ public boolean isDirty() { public void clearDirty() { if (this.isDirty()) { this.dirty = false; - ArmorStandRotationsScreen.this.dataSyncHandler.sendPose(ArmorStandRotationsScreen.this.currentPose); + ArmorStandRotationsScreen.this.setCurrentPose(ArmorStandRotationsScreen.this.currentPose); } } - }).active = isPosePartMutatorActive(mutator, armorStand); + }).active = isPosePartMutatorActive(mutator, this.holder.getArmorStand()); this.addRenderableWidget(new VerticalSliderButton(this.leftPos + 6 + i % 2 * 183, this.topPos + 7 + i / 2 * 60, () -> mutator.getNormalizedRotationsAtAxis(2, this.currentPose, clampRotations), (button, poseStack, mouseX, mouseY) -> { List lines = Lists.newArrayList(); lines.add(Component.translatable(mutator.getTranslationKey())); @@ -185,10 +184,10 @@ public boolean isDirty() { public void clearDirty() { if (this.isDirty()) { this.dirty = false; - ArmorStandRotationsScreen.this.dataSyncHandler.sendPose(ArmorStandRotationsScreen.this.currentPose); + ArmorStandRotationsScreen.this.setCurrentPose(ArmorStandRotationsScreen.this.currentPose); } } - }).active = isPosePartMutatorActive(mutator, armorStand); + }).active = isPosePartMutatorActive(mutator, this.holder.getArmorStand()); this.toggleLockButtons(); } } @@ -233,9 +232,10 @@ public ArmorStandScreenType getScreenType() { return ArmorStandScreenType.ROTATIONS; } - private void setCurrentPose(ArmorStandPose currentPose) { - this.currentPose = currentPose; - this.dataSyncHandler.sendPose(this.currentPose); + private void setCurrentPose(ArmorStandPose pose) { + this.dataSyncHandler.sendPose(pose); + ArmorStandPose lastSyncedPose = this.dataSyncHandler.getLastSyncedPose(); + this.currentPose = lastSyncedPose != null ? lastSyncedPose : pose; this.refreshLiveButtons(); } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java index 5b20719..24c60c7 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java @@ -36,7 +36,7 @@ static & ArmorStandScreen> T crea } static & ArmorStandScreen> T createLastScreenType(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { - Set screenTypes = Sets.newHashSet(dataSyncHandler.getArmorStandHolder().getDataProvider().getScreenTypes()); + Set screenTypes = Sets.newHashSet(dataSyncHandler.getScreenTypes()); Optional lastScreenType = Optional.ofNullable(AbstractArmorStandScreen.lastScreenType).filter(screenTypes::contains).filter(dataSyncHandler::supportsScreenType); ArmorStandScreenType screenType = lastScreenType.orElse(dataSyncHandler.getArmorStandHolder().getDataProvider().getDefaultScreenType()); return createScreenType(screenType, holder, inventory, component, dataSyncHandler); diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java index b9ca213..9faabcc 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java @@ -1,6 +1,7 @@ package fuzs.armorstatues.api.client.gui.screens.armorstand; import com.mojang.blaze3d.vertex.PoseStack; +import fuzs.armorstatues.api.StatuesApi; import fuzs.armorstatues.api.client.gui.components.TickBoxButton; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; @@ -16,6 +17,7 @@ import java.util.stream.Stream; public class ArmorStandStyleScreen extends ArmorStandTickBoxScreen { + public static final String TEXT_BOX_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.style.name"; public ArmorStandStyleScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); @@ -30,8 +32,8 @@ protected ArmorStandStyleOption[] getAllTickBoxValues() { @Override protected AbstractWidget makeTickBoxWidget(ArmorStand armorStand, int buttonStartY, int index, ArmorStandStyleOption option) { - return new TickBoxButton(this.leftPos + 96, this.topPos + buttonStartY + index * 22, 6, 76, Component.translatable(option.getTranslationKey()), option.getOption(armorStand), (Button button) -> { - this.dataSyncHandler.sendStyleOption(option, ((TickBoxButton) button).isSelected()); + return new TickBoxButton(this.leftPos + 96, this.topPos + buttonStartY + index * 22, 6, 76, Component.translatable(option.getTranslationKey()), () -> option.getOption(armorStand), (Button button) -> { + this.dataSyncHandler.sendStyleOption(option, !option.getOption(armorStand)); }, (Button button, PoseStack poseStack, int mouseX, int mouseY) -> { this.renderTooltip(poseStack, this.minecraft.font.split(Component.translatable(option.getDescriptionKey()), 175), mouseX, mouseY); }); @@ -54,7 +56,7 @@ protected String getNameDefaultValue() { @Override protected Component getNameComponent() { - return Component.translatable(ArmorStandStyleOption.TEXT_BOX_TRANSLATION_KEY); + return Component.translatable(TEXT_BOX_TRANSLATION_KEY); } @Override diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java index 7fbb450..6ec56ab 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java @@ -8,6 +8,7 @@ import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; @@ -17,21 +18,21 @@ import java.util.List; public abstract class ArmorStandWidgetsScreen extends AbstractArmorStandScreen { - protected final List widgets; + protected final List widgets; @Nullable - private PositionScreenWidget activeWidget; + private ArmorStandWidgetsScreen.ArmorStandWidget activeWidget; public ArmorStandWidgetsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); this.widgets = ImmutableList.copyOf(this.buildWidgets(holder.getArmorStand())); } - protected abstract List buildWidgets(ArmorStand armorStand); + protected abstract List buildWidgets(ArmorStand armorStand); - private Collection getActivePositionComponentWidgets() { + private Collection getActivePositionComponentWidgets() { if (this.activeWidget != null) { - List activeWidgets = Lists.newArrayList(this.activeWidget); - for (PositionScreenWidget widget : this.widgets) { + List activeWidgets = Lists.newArrayList(this.activeWidget); + for (ArmorStandWidget widget : this.widgets) { if (widget.alwaysVisible(this.activeWidget)) activeWidgets.add(widget); } return activeWidgets; @@ -39,7 +40,7 @@ private Collection getActivePositionComponentWidgets() { return this.widgets; } - protected void setActiveWidget(PositionScreenWidget widget) { + protected void setActiveWidget(ArmorStandWidget widget) { if (this.activeWidget == widget) { this.toggleMenuRendering(false); this.activeWidget = null; @@ -62,7 +63,7 @@ protected boolean disableMenuRendering() { @Override protected void toggleMenuRendering(boolean disableMenuRendering) { super.toggleMenuRendering(disableMenuRendering); - for (PositionScreenWidget widget : this.widgets) { + for (ArmorStandWidget widget : this.widgets) { widget.setVisible(!disableMenuRendering || widget.alwaysVisible(this.activeWidget)); } } @@ -70,7 +71,7 @@ protected void toggleMenuRendering(boolean disableMenuRendering) { @Override public void tick() { super.tick(); - this.getActivePositionComponentWidgets().forEach(PositionScreenWidget::tick); + this.getActivePositionComponentWidgets().forEach(ArmorStandWidget::tick); } @Override @@ -89,12 +90,12 @@ protected int getWidgetRenderOffset() { @Override protected void renderBg(PoseStack poseStack, float partialTick, int mouseX, int mouseY) { super.renderBg(poseStack, partialTick, mouseX, mouseY); - for (PositionScreenWidget widget : this.getActivePositionComponentWidgets()) { + for (ArmorStandWidget widget : this.getActivePositionComponentWidgets()) { widget.render(poseStack, mouseX, mouseY, partialTick); } } - protected interface PositionScreenWidget { + protected interface ArmorStandWidget { void tick(); @@ -106,16 +107,20 @@ protected interface PositionScreenWidget { void render(PoseStack poseStack, int mouseX, int mouseY, float partialTick); - boolean alwaysVisible(@Nullable PositionScreenWidget activeWidget); + boolean alwaysVisible(@Nullable ArmorStandWidgetsScreen.ArmorStandWidget activeWidget); } - protected abstract class AbstractPositionScreenWidget implements PositionScreenWidget { + protected abstract class AbstractArmorStandWidget implements ArmorStandWidget { protected final Component title; protected int posX; protected int posY; protected List children; - protected AbstractPositionScreenWidget(Component title) { + protected AbstractArmorStandWidget() { + this(CommonComponents.EMPTY); + } + + protected AbstractArmorStandWidget(Component title) { this.title = title; } @@ -161,7 +166,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTic } @Override - public boolean alwaysVisible(@Nullable PositionScreenWidget activeWidget) { + public boolean alwaysVisible(@Nullable ArmorStandWidgetsScreen.ArmorStandWidget activeWidget) { return activeWidget == this; } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java index e9d4d11..f8cf925 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java @@ -1,13 +1,19 @@ package fuzs.armorstatues.api.network.client.data; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; +import fuzs.armorstatues.api.world.inventory.data.*; import net.minecraft.SharedConstants; +import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +import java.util.stream.Stream; public interface DataSyncHandler { @@ -25,6 +31,11 @@ default void sendPose(ArmorStandPose pose, boolean finalize) { this.sendPose(pose); } + @Nullable + default ArmorStandPose getLastSyncedPose() { + return null; + } + void sendPosition(double posX, double posY, double posZ); default void sendPosition(double posX, double posY, double posZ, boolean finalize) { @@ -43,7 +54,44 @@ default void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, b this.sendStyleOption(styleOption, value); } - ArmorStandScreenType[] tabs(); + default void sendAlignment(ArmorStandAlignment alignment) { + if (!this.getArmorStand().isInvisible()) { + this.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); + } + if (!this.getArmorStand().isNoGravity()) { + this.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); + } + this.sendPose(alignment.getPose(), false); + Vec3 alignmentOffset = alignment.getAlignmentOffset(this.getArmorStand().isSmall()); + Vec3 newPosition = getLocalPosition(this.getArmorStand(), alignmentOffset); + this.sendPosition(newPosition.x(), newPosition.y(), newPosition.z(), false); + this.finalizeCurrentOperation(); + } + + /** + * Copied from {@link net.minecraft.commands.arguments.coordinates.LocalCoordinates#getPosition(CommandSourceStack)}. + */ + private static Vec3 getLocalPosition(Entity entity, Vec3 offset) { + Vec2 vec2 = entity.getRotationVector(); + Vec3 vec3 = entity.position(); + float f = Mth.cos((vec2.y + 90.0F) * 0.017453292F); + float g = Mth.sin((vec2.y + 90.0F) * 0.017453292F); + float h = Mth.cos(-vec2.x * 0.017453292F); + float i = Mth.sin(-vec2.x * 0.017453292F); + float j = Mth.cos((-vec2.x + 90.0F) * 0.017453292F); + float k = Mth.sin((-vec2.x + 90.0F) * 0.017453292F); + Vec3 vec32 = new Vec3(f * h, i, g * h); + Vec3 vec33 = new Vec3(f * j, k, g * j); + Vec3 vec34 = vec32.cross(vec33).scale(-1.0); + double d = vec32.x * offset.z() + vec33.x * offset.y() + vec34.x * offset.x(); + double e = vec32.y * offset.z() + vec33.y * offset.y() + vec34.y * offset.x(); + double l = vec32.z * offset.z() + vec33.z * offset.y() + vec34.z * offset.x(); + return new Vec3(vec3.x + d, vec3.y + e, vec3.z + l); + } + + default ArmorStandScreenType[] getScreenTypes() { + return Stream.of(this.getArmorStandHolder().getDataProvider().getScreenTypes()).filter(this::supportsScreenType).toArray(ArmorStandScreenType[]::new); + } default boolean supportsScreenType(ArmorStandScreenType screenType) { return true; diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java index 320dab2..2c8c9d0 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java @@ -4,7 +4,6 @@ import fuzs.armorstatues.api.network.client.*; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; import net.minecraft.nbt.CompoundTag; @@ -49,9 +48,4 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { styleOption.setOption(this.getArmorStand(), value); StatuesApi.NETWORK.sendToServer(new C2SArmorStandStyleMessage(styleOption, value)); } - - @Override - public ArmorStandScreenType[] tabs() { - return this.getArmorStandHolder().getDataProvider().getScreenTypes(); - } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java index 3824f97..83aa1e2 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java @@ -16,50 +16,47 @@ import java.util.Locale; public class ArmorStandPose { - public static final String POSE_SOURCE_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.pose.by"; - private static final String MINECRAFT_SOURCE = "Minecraft"; - private static final String VANILLA_TWEAKS_SOURCE = "Vanilla Tweaks"; private static final Rotations ZERO_ROTATIONS = new Rotations(0.0F, 0.0F, 0.0F); public static final double DEGREES_SNAP_INTERVAL = 0.125; public static final DecimalFormat ROTATION_FORMAT = Util.make(new DecimalFormat("#.##"), (decimalFormat) -> { decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); }); - public static final ArmorStandPose EMPTY = new ArmorStandPose(null, null); - public static final ArmorStandPose ATHENA = new ArmorStandPose("athena", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(-5.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-3.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-60.0F, 20.0F, -10.0F)).withRightLegPose(new Rotations(3.0F, 3.0F, 3.0F)); - public static final ArmorStandPose BRANDISH = new ArmorStandPose("brandish", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, -2.0F)).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(20.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 50.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); - public static final ArmorStandPose CANCAN = new ArmorStandPose("cancan", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 22.0F, 0.0F)).withHeadPose(new Rotations(-5.0F, 18.0F, 0.0F)).withLeftArmPose(new Rotations(8.0F, 0.0F, -114.0F)).withLeftLegPose(new Rotations(-111.0F, 55.0F, 0.0F)).withRightArmPose(new Rotations(0.0F, 84.0F, 111.0F)).withRightLegPose(new Rotations(0.0F, 23.0F, -13.0F)); - public static final ArmorStandPose DEFAULT = new ArmorStandPose("default", MINECRAFT_SOURCE).withLeftArmPose(new Rotations(-10.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-15.0F, 0.0F, 10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); - public static final ArmorStandPose ENTERTAIN = new ArmorStandPose("entertain", MINECRAFT_SOURCE).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); - public static final ArmorStandPose HERO = new ArmorStandPose("hero", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 8.0F, 0.0F)).withHeadPose(new Rotations(-4.0F, 67.0F, 0.0F)).withLeftArmPose(new Rotations(16.0F, 32.0F, -8.0F)).withLeftLegPose(new Rotations(0.0F, -75.0F, -8.0F)).withRightArmPose(new Rotations(-99.0F, 63.0F, 0.0F)).withRightLegPose(new Rotations(4.0F, 63.0F, 8.0F)); - public static final ArmorStandPose HONOR = new ArmorStandPose("honor", MINECRAFT_SOURCE).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)); - public static final ArmorStandPose RIPOSTE = new ArmorStandPose("riposte", MINECRAFT_SOURCE).withHeadPose(new Rotations(16.0F, 20.0F, 0.0F)).withLeftArmPose(new Rotations(4.0F, 8.0F, 237.0F)).withLeftLegPose(new Rotations(-14.0F, -18.0F, -16.0F)).withRightArmPose(new Rotations(246.0F, 0.0F, 89.0F)).withRightLegPose(new Rotations(8.0F, 20.0F, 4.0F)); - public static final ArmorStandPose SALUTE = new ArmorStandPose("salute", MINECRAFT_SOURCE).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-70.0F, -40.0F, 0.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); - public static final ArmorStandPose SOLEMN = new ArmorStandPose("solemn", MINECRAFT_SOURCE).withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-30.0F, 15.0F, 15.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-60.0F, -20.0F, -10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)); - public static final ArmorStandPose ZOMBIE = new ArmorStandPose("zombie", MINECRAFT_SOURCE).withHeadPose(new Rotations(-10.0F, 0.0F, -5.0F)).withLeftArmPose(new Rotations(-105.0F, 0.0F, 0.0F)).withLeftLegPose(new Rotations(7.0F, 0.0F, 0.0F)).withRightArmPose(new Rotations(-100.0F, 0.0F, 0.0F)).withRightLegPose(new Rotations(-46.0F, 0.0F, 0.0F)); - public static final ArmorStandPose WALKING = new ArmorStandPose("walking", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(20.0f,0.0f,10.0f)).withLeftArmPose(new Rotations(-20.0f,0.0f,-10.0f)).withRightLegPose(new Rotations(-20.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(20.0f,0.0f,0.0f)); - public static final ArmorStandPose RUNNING = new ArmorStandPose("running", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(-40.0f,0.0f,10.0f)).withLeftArmPose(new Rotations(40.0f,0.0f,-10.0f)).withRightLegPose(new Rotations(40.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(-40.0f,0.0f,0.0f)); - public static final ArmorStandPose POINTING = new ArmorStandPose("pointing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(0.0f,20.0f,0.0f)).withRightArmPose(new Rotations(-90.0f,18.0f,0.0f)).withLeftArmPose(new Rotations(0.0f,0.0f,-10.0f)); - public static final ArmorStandPose BLOCKING = new ArmorStandPose("blocking", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(-20.0f,-20.0f,0.0f)).withLeftArmPose(new Rotations(-50.0f,50.0f,0.0f)).withRightLegPose(new Rotations(-20.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(20.0f,0.0f,0.0f)); - public static final ArmorStandPose LUNGEING = new ArmorStandPose("lungeing", VANILLA_TWEAKS_SOURCE).withBodyPose(new Rotations(15.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-60.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(10.0f,0.0f,-10.0f)).withRightLegPose(new Rotations(-15.0f,0.0f,0.0f)).withLeftLegPose(new Rotations(30.0f,0.0f,0.0f)); - public static final ArmorStandPose WINNING = new ArmorStandPose("winning", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-15.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-120.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(10.0f,0.0f,-10.0f)).withLeftLegPose(new Rotations(15.0f,0.0f,0.0f)); - public static final ArmorStandPose SITTING = new ArmorStandPose("sitting", VANILLA_TWEAKS_SOURCE).withRightArmPose(new Rotations(-80.0f,20.0f,0.0f)).withLeftArmPose(new Rotations(-80.0f,-20.0f,0.0f)).withRightLegPose(new Rotations(-90.0f,10.0f,0.0f)).withLeftLegPose(new Rotations(-90.0f,-10.0f,0.0f)); - public static final ArmorStandPose ARABESQUE = new ArmorStandPose("arabesque", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-15.0f,0.0f,0.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-140.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(70.0f,0.0f,-10.0f)).withLeftLegPose(new Rotations(75.0f,0.0f,0.0f)); - public static final ArmorStandPose CUPID = new ArmorStandPose("cupid", VANILLA_TWEAKS_SOURCE).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-90.0f,-10.0f,0.0f)).withLeftArmPose(new Rotations(-75.0f,0.0f,10.0f)).withLeftLegPose(new Rotations(75.0f,0.0f,0.0f)); - public static final ArmorStandPose CONFIDENT = new ArmorStandPose("confident", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-10.0f,20.0f,0.0f)).withBodyPose(new Rotations(-2.0f,0.0f,0.0f)).withRightArmPose(new Rotations(5.0f,0.0f,0.0f)).withLeftArmPose(new Rotations(5.0f,0.0f,0.0f)).withRightLegPose(new Rotations(16.0f,2.0f,10.0f)).withLeftLegPose(new Rotations(0.0f,-10.0f,-4.0f)); - public static final ArmorStandPose DEATH = new ArmorStandPose("death", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-85.0f,0.0f,0.0f)).withBodyPose(new Rotations(-90.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-90.0f,10.0f,0.0f)).withLeftArmPose(new Rotations(-90.0f,-10.0f,0.0f)); - public static final ArmorStandPose FACEPALM = new ArmorStandPose("facepalm", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(45.0f,-4.0f,1.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(18.0f,-14.0f,0.0f)).withLeftArmPose(new Rotations(-72.0f,24.0f,47.0f)).withRightLegPose(new Rotations(25.0f,-2.0f,0.0f)).withLeftLegPose(new Rotations(-4.0f,-6.0f,-2.0f)); - public static final ArmorStandPose LAZING = new ArmorStandPose("lazing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(14.0f,-12.0f,6.0f)).withBodyPose(new Rotations(5.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-40.0f,20.0f,0.0f)).withLeftArmPose(new Rotations(-4.0f,-20.0f,-10.0f)).withRightLegPose(new Rotations(-88.0f,71.0f,0.0f)).withLeftLegPose(new Rotations(-88.0f,46.0f,0.0f)); - public static final ArmorStandPose CONFUSED = new ArmorStandPose("confused", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(0.0f,30.0f,0f)).withBodyPose(new Rotations(0.0f,13.0f,0.0f)).withRightArmPose(new Rotations(-22.0f,31.0f,10.0f)).withLeftArmPose(new Rotations(145.0f,22.0f,-49.0f)).withRightLegPose(new Rotations(6.0f,-20.0f,0.0f)).withLeftLegPose(new Rotations(-6.0f,0.0f,0.0f)); - public static final ArmorStandPose FORMAL = new ArmorStandPose("formal", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(4.0f,0.0f,0.0f)).withBodyPose(new Rotations(4.0f,0.0f,0.0f)).withRightArmPose(new Rotations(30.0f,22.0f,-20.0f)).withLeftArmPose(new Rotations(30.0f,-20.0f,21.0f)).withRightLegPose(new Rotations(0.0f,0.0f,5.0f)).withLeftLegPose(new Rotations(0.0f,0.0f,-5.0f)); - public static final ArmorStandPose SAD = new ArmorStandPose("sad", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(63.0f,0.0f,0.0f)).withBodyPose(new Rotations(10.0f,0.0f,0.0f)).withRightArmPose(new Rotations(-5.0f,0.0f,5.0f)).withLeftArmPose(new Rotations(-5.0f,0.0f,-5.0f)).withRightLegPose(new Rotations(-5.0f,-10.0f,5.0f)).withLeftLegPose(new Rotations(-5.0f,16.0f,-5.0f)); - public static final ArmorStandPose JOYOUS = new ArmorStandPose("joyous", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-11.0f,0.0f,0.0f)).withBodyPose(new Rotations(-4.0f,0.0f,0.0f)).withRightArmPose(new Rotations(0.0f,0.0f,100.0f)).withLeftArmPose(new Rotations(0.0f,0.0f,-100.0f)).withRightLegPose(new Rotations(-8.0f,0.0f,60.0f)).withLeftLegPose(new Rotations(-8.0f,0.0f,-60.0f)); - public static final ArmorStandPose STARGAZING = new ArmorStandPose("stargazing", VANILLA_TWEAKS_SOURCE).withHeadPose(new Rotations(-22.0f,25.0f,0.0f)).withBodyPose(new Rotations(-4.0f,10.0f,0.0f)).withRightArmPose(new Rotations(-153.0f,34.0f,-3.0f)).withLeftArmPose(new Rotations(4.0f,18.0f,0.0f)).withRightLegPose(new Rotations(-4.0f,17.0f,2.0f)).withLeftLegPose(new Rotations(6.0f,24.0f,0.0f)); + public static final ArmorStandPose EMPTY = new ArmorStandPose(null).withSourceType(SourceType.EMPTY); + public static final ArmorStandPose ATHENA = new ArmorStandPose("athena").withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(-5.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-3.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-60.0F, 20.0F, -10.0F)).withRightLegPose(new Rotations(3.0F, 3.0F, 3.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose BRANDISH = new ArmorStandPose("brandish").withBodyPose(new Rotations(0.0F, 0.0F, -2.0F)).withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(20.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 50.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose CANCAN = new ArmorStandPose("cancan").withBodyPose(new Rotations(0.0F, 22.0F, 0.0F)).withHeadPose(new Rotations(-5.0F, 18.0F, 0.0F)).withLeftArmPose(new Rotations(8.0F, 0.0F, -114.0F)).withLeftLegPose(new Rotations(-111.0F, 55.0F, 0.0F)).withRightArmPose(new Rotations(0.0F, 84.0F, 111.0F)).withRightLegPose(new Rotations(0.0F, 23.0F, -13.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose DEFAULT = new ArmorStandPose("default").withLeftArmPose(new Rotations(-10.0F, 0.0F, -10.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-15.0F, 0.0F, 10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose ENTERTAIN = new ArmorStandPose("entertain").withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose HERO = new ArmorStandPose("hero").withBodyPose(new Rotations(0.0F, 8.0F, 0.0F)).withHeadPose(new Rotations(-4.0F, 67.0F, 0.0F)).withLeftArmPose(new Rotations(16.0F, 32.0F, -8.0F)).withLeftLegPose(new Rotations(0.0F, -75.0F, -8.0F)).withRightArmPose(new Rotations(-99.0F, 63.0F, 0.0F)).withRightLegPose(new Rotations(4.0F, 63.0F, 8.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose HONOR = new ArmorStandPose("honor").withHeadPose(new Rotations(-15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-110.0F, 35.0F, 0.0F)).withLeftLegPose(new Rotations(5.0F, -3.0F, -3.0F)).withRightArmPose(new Rotations(-110.0F, -35.0F, 0.0F)).withRightLegPose(new Rotations(-5.0F, 3.0F, 3.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose RIPOSTE = new ArmorStandPose("riposte").withHeadPose(new Rotations(16.0F, 20.0F, 0.0F)).withLeftArmPose(new Rotations(4.0F, 8.0F, 237.0F)).withLeftLegPose(new Rotations(-14.0F, -18.0F, -16.0F)).withRightArmPose(new Rotations(246.0F, 0.0F, 89.0F)).withRightLegPose(new Rotations(8.0F, 20.0F, 4.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose SALUTE = new ArmorStandPose("salute").withLeftArmPose(new Rotations(10.0F, 0.0F, -5.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-70.0F, -40.0F, 0.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose SOLEMN = new ArmorStandPose("solemn").withBodyPose(new Rotations(0.0F, 0.0F, 2.0F)).withHeadPose(new Rotations(15.0F, 0.0F, 0.0F)).withLeftArmPose(new Rotations(-30.0F, 15.0F, 15.0F)).withLeftLegPose(new Rotations(-1.0F, 0.0F, -1.0F)).withRightArmPose(new Rotations(-60.0F, -20.0F, -10.0F)).withRightLegPose(new Rotations(1.0F, 0.0F, 1.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose ZOMBIE = new ArmorStandPose("zombie").withHeadPose(new Rotations(-10.0F, 0.0F, -5.0F)).withLeftArmPose(new Rotations(-105.0F, 0.0F, 0.0F)).withLeftLegPose(new Rotations(7.0F, 0.0F, 0.0F)).withRightArmPose(new Rotations(-100.0F, 0.0F, 0.0F)).withRightLegPose(new Rotations(-46.0F, 0.0F, 0.0F)).withSourceType(SourceType.MINECRAFT); + public static final ArmorStandPose WALKING = new ArmorStandPose("walking").withRightArmPose(new Rotations(20.0F,0.0F,10.0F)).withLeftArmPose(new Rotations(-20.0F,0.0F,-10.0F)).withRightLegPose(new Rotations(-20.0F,0.0F,0.0F)).withLeftLegPose(new Rotations(20.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose RUNNING = new ArmorStandPose("running").withRightArmPose(new Rotations(-40.0F,0.0F,10.0F)).withLeftArmPose(new Rotations(40.0F,0.0F,-10.0F)).withRightLegPose(new Rotations(40.0F,0.0F,0.0F)).withLeftLegPose(new Rotations(-40.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose POINTING = new ArmorStandPose("pointing").withHeadPose(new Rotations(0.0F,20.0F,0.0F)).withRightArmPose(new Rotations(-90.0F,18.0F,0.0F)).withLeftArmPose(new Rotations(0.0F,0.0F,-10.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose BLOCKING = new ArmorStandPose("blocking").withRightArmPose(new Rotations(-20.0F,-20.0F,0.0F)).withLeftArmPose(new Rotations(-50.0F,50.0F,0.0F)).withRightLegPose(new Rotations(-20.0F,0.0F,0.0F)).withLeftLegPose(new Rotations(20.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose LUNGEING = new ArmorStandPose("lungeing").withBodyPose(new Rotations(15.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-60.0F,-10.0F,0.0F)).withLeftArmPose(new Rotations(10.0F,0.0F,-10.0F)).withRightLegPose(new Rotations(-15.0F,0.0F,0.0F)).withLeftLegPose(new Rotations(30.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose WINNING = new ArmorStandPose("winning").withHeadPose(new Rotations(-15.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-120.0F,-10.0F,0.0F)).withLeftArmPose(new Rotations(10.0F,0.0F,-10.0F)).withLeftLegPose(new Rotations(15.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose SITTING = new ArmorStandPose("sitting").withRightArmPose(new Rotations(-80.0F,20.0F,0.0F)).withLeftArmPose(new Rotations(-80.0F,-20.0F,0.0F)).withRightLegPose(new Rotations(-90.0F,10.0F,0.0F)).withLeftLegPose(new Rotations(-90.0F,-10.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose ARABESQUE = new ArmorStandPose("arabesque").withHeadPose(new Rotations(-15.0F,0.0F,0.0F)).withBodyPose(new Rotations(10.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-140.0F,-10.0F,0.0F)).withLeftArmPose(new Rotations(70.0F,0.0F,-10.0F)).withLeftLegPose(new Rotations(75.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose CUPID = new ArmorStandPose("cupid").withBodyPose(new Rotations(10.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-90.0F,-10.0F,0.0F)).withLeftArmPose(new Rotations(-75.0F,0.0F,10.0F)).withLeftLegPose(new Rotations(75.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose CONFIDENT = new ArmorStandPose("confident").withHeadPose(new Rotations(-10.0F,20.0F,0.0F)).withBodyPose(new Rotations(-2.0F,0.0F,0.0F)).withRightArmPose(new Rotations(5.0F,0.0F,0.0F)).withLeftArmPose(new Rotations(5.0F,0.0F,0.0F)).withRightLegPose(new Rotations(16.0F,2.0F,10.0F)).withLeftLegPose(new Rotations(0.0F,-10.0F,-4.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose DEATH = new ArmorStandPose("death").withHeadPose(new Rotations(-85.0F,0.0F,0.0F)).withBodyPose(new Rotations(-90.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-90.0F,10.0F,0.0F)).withLeftArmPose(new Rotations(-90.0F,-10.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose FACEPALM = new ArmorStandPose("facepalm").withHeadPose(new Rotations(45.0F,-4.0F,1.0F)).withBodyPose(new Rotations(10.0F,0.0F,0.0F)).withRightArmPose(new Rotations(18.0F,-14.0F,0.0F)).withLeftArmPose(new Rotations(-72.0F,24.0F,47.0F)).withRightLegPose(new Rotations(25.0F,-2.0F,0.0F)).withLeftLegPose(new Rotations(-4.0F,-6.0F,-2.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose LAZING = new ArmorStandPose("lazing").withHeadPose(new Rotations(14.0F,-12.0F,6.0F)).withBodyPose(new Rotations(5.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-40.0F,20.0F,0.0F)).withLeftArmPose(new Rotations(-4.0F,-20.0F,-10.0F)).withRightLegPose(new Rotations(-88.0F,71.0F,0.0F)).withLeftLegPose(new Rotations(-88.0F,46.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose CONFUSED = new ArmorStandPose("confused").withHeadPose(new Rotations(0.0F,30.0F,0f)).withBodyPose(new Rotations(0.0F,13.0F,0.0F)).withRightArmPose(new Rotations(-22.0F,31.0F,10.0F)).withLeftArmPose(new Rotations(145.0F,22.0F,-49.0F)).withRightLegPose(new Rotations(6.0F,-20.0F,0.0F)).withLeftLegPose(new Rotations(-6.0F,0.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose FORMAL = new ArmorStandPose("formal").withHeadPose(new Rotations(4.0F,0.0F,0.0F)).withBodyPose(new Rotations(4.0F,0.0F,0.0F)).withRightArmPose(new Rotations(30.0F,22.0F,-20.0F)).withLeftArmPose(new Rotations(30.0F,-20.0F,21.0F)).withRightLegPose(new Rotations(0.0F,0.0F,5.0F)).withLeftLegPose(new Rotations(0.0F,0.0F,-5.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose SAD = new ArmorStandPose("sad").withHeadPose(new Rotations(63.0F,0.0F,0.0F)).withBodyPose(new Rotations(10.0F,0.0F,0.0F)).withRightArmPose(new Rotations(-5.0F,0.0F,5.0F)).withLeftArmPose(new Rotations(-5.0F,0.0F,-5.0F)).withRightLegPose(new Rotations(-5.0F,-10.0F,5.0F)).withLeftLegPose(new Rotations(-5.0F,16.0F,-5.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose JOYOUS = new ArmorStandPose("joyous").withHeadPose(new Rotations(-11.0F,0.0F,0.0F)).withBodyPose(new Rotations(-4.0F,0.0F,0.0F)).withRightArmPose(new Rotations(0.0F,0.0F,100.0F)).withLeftArmPose(new Rotations(0.0F,0.0F,-100.0F)).withRightLegPose(new Rotations(-8.0F,0.0F,60.0F)).withLeftLegPose(new Rotations(-8.0F,0.0F,-60.0F)).withSourceType(SourceType.VANILLA_TWEAKS); + public static final ArmorStandPose STARGAZING = new ArmorStandPose("stargazing").withHeadPose(new Rotations(-22.0F,25.0F,0.0F)).withBodyPose(new Rotations(-4.0F,10.0F,0.0F)).withRightArmPose(new Rotations(-153.0F,34.0F,-3.0F)).withLeftArmPose(new Rotations(4.0F,18.0F,0.0F)).withRightLegPose(new Rotations(-4.0F,17.0F,2.0F)).withLeftLegPose(new Rotations(6.0F,24.0F,0.0F)).withSourceType(SourceType.VANILLA_TWEAKS); private static final ArmorStandPose[] VALUES = {DEFAULT, SOLEMN, ATHENA, BRANDISH, HONOR, ENTERTAIN, SALUTE, HERO, RIPOSTE, ZOMBIE, CANCAN, WALKING, RUNNING, POINTING, BLOCKING, LUNGEING, WINNING, SITTING, ARABESQUE, CUPID, CONFIDENT, DEATH, FACEPALM, LAZING, CONFUSED, FORMAL, SAD, JOYOUS, STARGAZING}; @Nullable private final String name; @Nullable - private final String source; + private final SourceType sourceType; @Nullable private final Rotations headPose; @Nullable @@ -73,13 +70,13 @@ public class ArmorStandPose { @Nullable private final Rotations rightLegPose; - private ArmorStandPose(@Nullable String name, @Nullable String source) { - this(name, source, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS); + private ArmorStandPose(@Nullable String name) { + this(name, null, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS, ZERO_ROTATIONS); } - private ArmorStandPose(@Nullable String name, @Nullable String source, @Nullable Rotations headPose, @Nullable Rotations bodyPose, @Nullable Rotations leftArmPose, @Nullable Rotations rightArmPose, @Nullable Rotations leftLegPose, @Nullable Rotations rightLegPose) { + private ArmorStandPose(@Nullable String name, @Nullable SourceType sourceType, @Nullable Rotations headPose, @Nullable Rotations bodyPose, @Nullable Rotations leftArmPose, @Nullable Rotations rightArmPose, @Nullable Rotations leftLegPose, @Nullable Rotations rightLegPose) { this.name = name; - this.source = source; + this.sourceType = sourceType; this.headPose = headPose; this.bodyPose = bodyPose; this.leftArmPose = leftArmPose; @@ -101,9 +98,8 @@ public String getTranslationKey() { return this.name != null ? StatuesApi.MOD_ID + ".screen.pose." + this.name : null; } - @Nullable - public String getSource() { - return this.source; + public SourceType getSourceType() { + return this.sourceType != null ? this.sourceType : SourceType.TRANSIENT; } public Rotations getHeadPose() { @@ -161,31 +157,35 @@ public Rotations getNullableRightLegPose() { } public ArmorStandPose withHeadPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.source, rotation, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, null, rotation, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withBodyPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.source, this.headPose, rotation, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, null, this.headPose, rotation, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withLeftArmPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, rotation, this.rightArmPose, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, null, this.headPose, this.bodyPose, rotation, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withRightArmPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, this.leftArmPose, rotation, this.leftLegPose, this.rightLegPose); + return new ArmorStandPose(this.name, null, this.headPose, this.bodyPose, this.leftArmPose, rotation, this.leftLegPose, this.rightLegPose); } public ArmorStandPose withLeftLegPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, rotation, this.rightLegPose); + return new ArmorStandPose(this.name, null, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, rotation, this.rightLegPose); } public ArmorStandPose withRightLegPose(Rotations rotation) { - return new ArmorStandPose(this.name, this.source, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, rotation); + return new ArmorStandPose(this.name, null, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, rotation); + } + + public ArmorStandPose withSourceType(SourceType sourceType) { + return new ArmorStandPose(this.name, sourceType, this.headPose, this.bodyPose, this.leftArmPose, this.rightArmPose, this.leftLegPose, this.rightLegPose); } public ArmorStandPose mirror() { - return new ArmorStandPose(this.name, this.source, mirrorRotations(this.headPose), mirrorRotations(this.bodyPose), mirrorRotations(this.rightArmPose), mirrorRotations(this.leftArmPose), mirrorRotations(this.rightLegPose), mirrorRotations(this.leftLegPose)); + return new ArmorStandPose(this.name, SourceType.MIRRORED, mirrorRotations(this.headPose), mirrorRotations(this.bodyPose), mirrorRotations(this.rightArmPose), mirrorRotations(this.leftArmPose), mirrorRotations(this.rightLegPose), mirrorRotations(this.leftLegPose)); } @Nullable @@ -194,7 +194,7 @@ private static Rotations mirrorRotations(@Nullable Rotations rotations) { } public ArmorStandPose copyAndFillFrom(ArmorStandPose fillFrom) { - return new ArmorStandPose(this.name, this.source, this.headPose != null ? this.headPose : fillFrom.headPose, this.bodyPose != null ? this.bodyPose : fillFrom.bodyPose, this.leftArmPose != null ? this.leftArmPose : fillFrom.leftArmPose, this.rightArmPose != null ? this.rightArmPose : fillFrom.rightArmPose, this.leftLegPose != null ? this.leftLegPose : fillFrom.leftLegPose, this.rightLegPose != null ? this.rightLegPose : fillFrom.rightLegPose); + return new ArmorStandPose(this.name, this.sourceType, this.headPose != null ? this.headPose : fillFrom.headPose, this.bodyPose != null ? this.bodyPose : fillFrom.bodyPose, this.leftArmPose != null ? this.leftArmPose : fillFrom.leftArmPose, this.rightArmPose != null ? this.rightArmPose : fillFrom.rightArmPose, this.leftLegPose != null ? this.leftLegPose : fillFrom.leftLegPose, this.rightLegPose != null ? this.rightLegPose : fillFrom.rightLegPose); } public void applyToEntity(ArmorStand armorStand) { @@ -295,4 +295,15 @@ public static double snapValue(double value, double snapInterval) { } return value; } + + public enum SourceType { + MINECRAFT, VANILLA_TWEAKS, TRANSIENT, EMPTY, MIRRORED; + + @Nullable + public String getDisplayName() { + if (this == MINECRAFT) return "Minecraft"; + if (this == VANILLA_TWEAKS) return "Vanilla Tweaks"; + return null; + } + } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java index da5829a..3014552 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java @@ -11,8 +11,6 @@ import java.util.Objects; public interface ArmorStandStyleOption { - String TEXT_BOX_TRANSLATION_KEY = StatuesApi.MOD_ID + ".screen.style.name"; - int ARMOR_STAND_ALL_SLOTS_DISABLED = 4144959; BiMap OPTIONS_REGISTRY = HashBiMap.create(); String getName(); diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java index 8dd6b2a..7c30070 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java @@ -18,9 +18,11 @@ public enum ArmorStandStyleOptions implements ArmorStandStyleOption { NO_GRAVITY("noGravity", Entity::setNoGravity, Entity::isNoGravity), SEALED("sealed", (armorStand, setting) -> { armorStand.setInvulnerable(setting); - ((ArmorStandAccessor) armorStand).setDisabledSlots(setting ? ArmorStandStyleOption.ARMOR_STAND_ALL_SLOTS_DISABLED : 0); + ((ArmorStandAccessor) armorStand).setDisabledSlots(setting ? ArmorStandStyleOptions.ARMOR_STAND_ALL_SLOTS_DISABLED : 0); }, Entity::isInvulnerable); + public static final int ARMOR_STAND_ALL_SLOTS_DISABLED = 4144959; + private final String name; private final BiConsumer newValue; private final Function currentValue; @@ -59,7 +61,7 @@ public void toTag(CompoundTag tag, boolean currentValue) { }; tag.putBoolean(dataKey, currentValue); if (this == ArmorStandStyleOptions.SEALED) { - tag.putInt("DisabledSlots", currentValue ? ArmorStandStyleOption.ARMOR_STAND_ALL_SLOTS_DISABLED : 0); + tag.putInt("DisabledSlots", currentValue ? ARMOR_STAND_ALL_SLOTS_DISABLED : 0); } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index bdb9a83..9025709 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -1,8 +1,9 @@ package fuzs.armorstatues.client; -import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreenFactory; import fuzs.armorstatues.api.world.inventory.ArmorStandMenu; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; import fuzs.armorstatues.init.ModRegistry; import fuzs.puzzleslib.client.core.ClientModConstructor; import net.minecraft.network.chat.Component; @@ -13,6 +14,7 @@ public class ArmorStatuesClient implements ClientModConstructor { @Override public void onClientSetup() { ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); } @Override diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index f60ff1d..da3832b 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -1,37 +1,42 @@ package fuzs.armorstatues.client.gui.screens.armorstand; import com.google.common.collect.Lists; -import fuzs.armorstatues.api.client.gui.components.TickButton; -import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandPositionScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandButtonsScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandPositionScreen; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; import fuzs.armorstatues.init.ModRegistry; -import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; +import java.util.EnumSet; import java.util.List; -public class ArmorStandAlignmentsScreen extends AbstractArmorStandPositionScreen { +public class ArmorStandAlignmentsScreen extends ArmorStandButtonsScreen { public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); } @Override - protected List buildWidgets(ArmorStand armorStand) { - List widgets = Lists.newArrayList(new PositionAlignWidget()); + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new DoubleButtonWidget(Component.translatable(ArmorStandPositionScreen.CENTERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + })); for (ArmorStandAlignment alignment : ArmorStandAlignment.values()) { - widgets.add(new AlignmentWidget(alignment)); + widgets.add(new SingleButtonWidget(Component.translatable(alignment.getTranslationKey()), Component.translatable(alignment.getDescriptionsKey()), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendAlignment(alignment); + })); } return widgets; } @@ -46,63 +51,4 @@ protected void init() { public ArmorStandScreenType getScreenType() { return ModRegistry.ALIGNMENTS_SCREEN_TYPE; } - - private class AlignmentWidget extends AbstractPositionScreenWidget { - private final ArmorStandAlignment alignment; - - public AlignmentWidget(ArmorStandAlignment alignment) { - super(Component.empty()); - this.alignment = alignment; - } - - @Override - protected boolean shouldTick() { - return true; - } - - @Override - public void init(int posX, int posY) { - super.init(posX, posY); - this.children.add(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { - ArmorStand armorStand = ArmorStandAlignmentsScreen.this.holder.getArmorStand(); - DataSyncHandler dataSyncHandler = ArmorStandAlignmentsScreen.this.dataSyncHandler; - if (!armorStand.isInvisible()) { - dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); - } - if (!armorStand.isNoGravity()) { - dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); - } - dataSyncHandler.sendPose(this.alignment.getPose(), false); - Vec3 alignmentOffset = this.alignment.getAlignmentOffset(armorStand.isSmall()); - Vec3 newPosition = getLocalPosition(armorStand, alignmentOffset); - dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z(), false); - dataSyncHandler.finalizeCurrentOperation(); - }, (button, poseStack, mouseX, mouseY) -> { - Component component = Component.translatable(this.alignment.getDescriptionsKey()); - List lines = ArmorStandAlignmentsScreen.this.font.split(component, 175); - ArmorStandAlignmentsScreen.this.renderTooltip(poseStack, lines, mouseX, mouseY); - }))); - } - - /** - * Copied from {@link net.minecraft.commands.arguments.coordinates.LocalCoordinates#getPosition(CommandSourceStack)}. - */ - private static Vec3 getLocalPosition(Entity entity, Vec3 offset) { - Vec2 vec2 = entity.getRotationVector(); - Vec3 vec3 = entity.position(); - float f = Mth.cos((vec2.y + 90.0F) * 0.017453292F); - float g = Mth.sin((vec2.y + 90.0F) * 0.017453292F); - float h = Mth.cos(-vec2.x * 0.017453292F); - float i = Mth.sin(-vec2.x * 0.017453292F); - float j = Mth.cos((-vec2.x + 90.0F) * 0.017453292F); - float k = Mth.sin((-vec2.x + 90.0F) * 0.017453292F); - Vec3 vec32 = new Vec3(f * h, i, g * h); - Vec3 vec33 = new Vec3(f * j, k, g * j); - Vec3 vec34 = vec32.cross(vec33).scale(-1.0); - double d = vec32.x * offset.z() + vec33.x * offset.y() + vec34.x * offset.x(); - double e = vec32.y * offset.z() + vec33.y * offset.y() + vec34.y * offset.x(); - double l = vec32.z * offset.z() + vec33.z * offset.y() + vec34.z * offset.x(); - return new Vec3(vec3.x + d, vec3.y + e, vec3.z + l); - } - } } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java new file mode 100644 index 0000000..88dff11 --- /dev/null +++ b/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java @@ -0,0 +1,75 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandButtonsScreen; +import fuzs.armorstatues.api.network.client.data.DataSyncHandler; +import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; + +import java.util.List; + +public class ArmorStandVanillaTweaksScreen extends ArmorStandButtonsScreen { + public static final String TRIGGER_SENT_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.triggerSent"; + public static final String CHECK_TARGET_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget"; + public static final String CHECK_TARGET_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget.description"; + public static final String LOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock"; + public static final String LOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock.description"; + public static final String UNLOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock"; + public static final String UNLOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock.description"; + public static final String TOOL_RACK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack"; + public static final String TOOL_RACK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack.description"; + public static final String SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand"; + public static final String SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand.description"; + public static final String SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead"; + public static final String SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead.description"; + + public ArmorStandVanillaTweaksScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + public VanillaTweaksDataSyncHandler getDataSyncHandler() { + return (VanillaTweaksDataSyncHandler) super.getDataSyncHandler(); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new SingleButtonWidget(Component.translatable(CHECK_TARGET_TRANSLATION_KEY), Component.translatable(CHECK_TARGET_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.CHECK_TARGET); + this.onClose(); + })); + widgets.add(new DoubleButtonWidget(Component.translatable(LOCK_TRANSLATION_KEY), Component.translatable(UNLOCK_TRANSLATION_KEY), Component.translatable(LOCK_DESCRIPTION_KEY), Component.translatable(UNLOCK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_LOCK); + }, button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_UNLOCK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(TOOL_RACK_TRANSLATION_KEY), Component.translatable(TOOL_RACK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.AUTO_ALIGNMENT_TOOL_RACK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_OFFHAND); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_HEAD); + })); + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE; + } +} diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java similarity index 84% rename from 1.19/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java rename to 1.19/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java index 82c56f0..e534fa6 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/handler/DataSyncTickHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -1,4 +1,4 @@ -package fuzs.armorstatues.handler; +package fuzs.armorstatues.client.handler; import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreen; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; @@ -17,7 +17,7 @@ public static void onScreenClose(Screen screen) { } public static void onClientTickEnd(Minecraft minecraft) { - if (!(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (minecraft.player != null && !(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { if (dataSyncHandler.shouldContinueTicking()) { dataSyncHandler.tick(); } else { diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java index 9c22d51..32e7897 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -7,4 +7,7 @@ public class ClientConfig implements ConfigCore { @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) public boolean useVanillaTweaksTriggers = false; + @Config(description = "The delay in ticks for sending queued client commands for editing armor stands to the server. Increase this values if commands are sent too quickly and the server fails to process all of them.") + @Config.IntRange(min = 20) + public int clientCommandDelay = 20; } diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index dec00cf..47ff5c5 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -24,6 +24,7 @@ public ArmorStandScreenType[] getScreenTypes() { } }; public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); + public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", new ItemStack(Items.WRITTEN_BOOK)); public static void touch() { diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index d82aab7..0c94e9d 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -3,6 +3,7 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; +import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; import fuzs.armorstatues.api.world.inventory.data.ArmorStandScreenType; import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; @@ -19,11 +20,10 @@ import java.util.ArrayDeque; import java.util.Queue; import java.util.function.BiPredicate; -import java.util.function.Predicate; -import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; @@ -50,7 +50,7 @@ public ArmorStandHolder getArmorStandHolder() { @Override public void sendName(String name) { - if (!this.testPermissionLevel()) return; + if (!this.isEditingAllowed()) return; DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); CompoundTag tag = new CompoundTag(); tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); @@ -65,12 +65,12 @@ public final void sendPose(ArmorStandPose pose) { @Override public void sendPose(ArmorStandPose pose, boolean finalize) { - if (!this.testPermissionLevel()) return; - pose.applyToEntity(this.getArmorStand()); + if (!this.isEditingAllowed()) return; // split this into multiple chat messages as the client chat field has a very low character limit this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); if (finalize) this.finalizeCurrentOperation(); } @@ -84,6 +84,11 @@ private void sendPosePart(BiPredicate dataWriter, A } } + @Override + public @Nullable ArmorStandPose getLastSyncedPose() { + return this.lastSyncedPose; + } + @Override public final void sendPosition(double posX, double posY, double posZ) { this.sendPosition(posX, posY, posZ, true); @@ -92,7 +97,7 @@ public final void sendPosition(double posX, double posY, double posZ) { @Override public void sendPosition(double posX, double posY, double posZ, boolean finalize) { - if (!this.testPermissionLevel()) return; + if (!this.isEditingAllowed()) return; ListTag listTag = new ListTag(); listTag.add(DoubleTag.valueOf(posX)); listTag.add(DoubleTag.valueOf(posY)); @@ -110,7 +115,7 @@ public final void sendRotation(float rotation) { @Override public void sendRotation(float rotation, boolean finalize) { - if (!this.testPermissionLevel()) return; + if (!this.isEditingAllowed()) return; ListTag listTag = new ListTag(); listTag.add(FloatTag.valueOf(rotation)); CompoundTag tag = new CompoundTag(); @@ -126,17 +131,18 @@ public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean val @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { - if (!this.testPermissionLevel()) return; - styleOption.setOption(this.getArmorStand(), value); + if (!this.isEditingAllowed()) return; CompoundTag tag = new CompoundTag(); styleOption.toTag(tag, value); this.enqueueEntityData(tag); + styleOption.setOption(this.getArmorStand(), value); if (finalize) this.finalizeCurrentOperation(); } @Override - public ArmorStandScreenType[] tabs() { - return Stream.of(this.getArmorStandHolder().getDataProvider().getScreenTypes()).filter(Predicate.not(ArmorStandScreenType::requiresServer)).toArray(ArmorStandScreenType[]::new); + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.super.sendAlignment(alignment); } @Override @@ -148,7 +154,7 @@ public boolean supportsScreenType(ArmorStandScreenType screenType) { public void tick() { if (itemDequeuedTicks > 0) itemDequeuedTicks--; if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { - if (queueArmorStand.isAlive()) { + if (this.testArmorStand(queueArmorStand)) { this.player.commandSigned(CLIENT_COMMAND_QUEUE.poll(), null); } else { CLIENT_COMMAND_QUEUE.clear(); @@ -168,14 +174,25 @@ public boolean shouldContinueTicking() { return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; } - private boolean testPermissionLevel() { - if (!this.player.hasPermissions(2)) { + protected boolean isEditingAllowed() { + return this.isEditingAllowed(true); + } + + protected final boolean isEditingAllowed(boolean testPermissionLevel) { + if (testPermissionLevel && !this.player.hasPermissions(2)) { this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); return false; + } else if (queueArmorStand != null && !this.testArmorStand(queueArmorStand)) { + this.sendFailureMessage(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)); + return false; } return true; } + protected boolean testArmorStand(ArmorStand armorStand) { + return armorStand.isAlive(); + } + protected boolean enqueueClientCommand(String clientCommand) { if (CLIENT_COMMAND_QUEUE.isEmpty()) { queueArmorStand = null; diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java index 412b0b0..1d74aef 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -1,19 +1,34 @@ package fuzs.armorstatues.network.client.data; import com.google.common.collect.ImmutableSortedMap; +import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandPose; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOption; -import fuzs.armorstatues.api.world.inventory.data.ArmorStandStyleOptions; +import fuzs.armorstatues.api.world.inventory.data.*; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Rotations; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.NavigableMap; +import java.util.function.Function; +import java.util.stream.Stream; public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { private static final int MAX_INCREMENTAL_OPERATIONS = 12; + public static final int CHECK_TARGET = 999; + public static final int SWAP_SLOTS_MAINHAND_AND_OFFHAND = 161; + public static final int SWAP_SLOTS_MAINHAND_AND_HEAD = 162; + public static final int MIRROR_ARMS_LEFT_TO_RIGHT = 131; + public static final int MIRROR_ARMS_RIGHT_TO_LEFT = 132; + public static final int MIRROR_LEGS_LEFT_TO_RIGHT = 133; + public static final int MIRROR_LEGS_RIGHT_TO_LEFT = 134; + public static final int UTILITIES_LOCK = 1000; + public static final int UTILITIES_UNLOCK = 1001; + public static final int MIRROR_AND_FLIP_FLIP = 135; public static final int SHOW_BASE_PLATE_YES = 1; public static final int SHOW_BASE_PLATE_NO = 2; public static final int SHOW_ARMS_YES = 3; @@ -50,6 +65,31 @@ public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + public static final int POSE_PRESETS_ATTENTION = 20; + public static final int POSE_PRESETS_WALKING = 21; + public static final int POSE_PRESETS_RUNNING = 22; + public static final int POSE_PRESETS_POINTING = 23; + public static final int POSE_PRESETS_BLOCKING = 24; + public static final int POSE_PRESETS_LUNGEING = 25; + public static final int POSE_PRESETS_WINNING = 26; + public static final int POSE_PRESETS_SITTING = 27; + public static final int POSE_PRESETS_ARABESQUE = 28; + public static final int POSE_PRESETS_CUPID = 29; + public static final int POSE_PRESETS_CONFIDENT = 30; + public static final int POSE_PRESETS_SALUTE = 31; + public static final int POSE_PRESETS_DEATH = 32; + public static final int POSE_PRESETS_FACEPALM = 33; + public static final int POSE_PRESETS_LAZING = 34; + public static final int POSE_PRESETS_CONFUSED = 35; + public static final int POSE_PRESETS_FORMAL = 36; + public static final int POSE_PRESETS_SAD = 37; + public static final int POSE_PRESETS_JOYOUS = 38; + public static final int POSE_PRESETS_STARGAZING = 39; + public static final int AUTO_ALIGNMENT_BLOCK_ON_SURFACE = 151; + public static final int AUTO_ALIGNMENT_ITEM_ON_SURFACE = 152; + public static final int AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE = 153; + public static final int AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE = 154; + public static final int AUTO_ALIGNMENT_TOOL_RACK = 155; public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; @@ -106,19 +146,69 @@ public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) @Override public void sendPose(ArmorStandPose pose, boolean finalize) { - $1: { - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG)) break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG)) break $1; + if (!this.isEditingAllowed()) return; + int triggerValue = this.getTriggerValueFromPose(pose); + if (triggerValue != -1) { + if (this.enqueueTriggerValue(triggerValue)) { + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + } + } else { + this.tryApplyAllPoseParts(pose); } - this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); if (finalize) this.finalizeCurrentOperation(); } - private boolean tryApplyPoseIncrements(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + private int getTriggerValueFromPose(ArmorStandPose pose) { + if (pose.getSourceType() == ArmorStandPose.SourceType.EMPTY) return POSE_PRESETS_ATTENTION; + if (pose.getSourceType() == ArmorStandPose.SourceType.MIRRORED) return MIRROR_AND_FLIP_FLIP; + if (pose.getSourceType() != ArmorStandPose.SourceType.VANILLA_TWEAKS) return -1; + if (pose == ArmorStandPose.WALKING) return POSE_PRESETS_WALKING; + if (pose == ArmorStandPose.RUNNING) return POSE_PRESETS_RUNNING; + if (pose == ArmorStandPose.POINTING) return POSE_PRESETS_POINTING; + if (pose == ArmorStandPose.BLOCKING) return POSE_PRESETS_BLOCKING; + if (pose == ArmorStandPose.LUNGEING) return POSE_PRESETS_LUNGEING; + if (pose == ArmorStandPose.WINNING) return POSE_PRESETS_WINNING; + if (pose == ArmorStandPose.SITTING) return POSE_PRESETS_SITTING; + if (pose == ArmorStandPose.ARABESQUE) return POSE_PRESETS_ARABESQUE; + if (pose == ArmorStandPose.CUPID) return POSE_PRESETS_CUPID; + if (pose == ArmorStandPose.CONFIDENT) return POSE_PRESETS_CONFIDENT; + if (pose == ArmorStandPose.SALUTE) return POSE_PRESETS_SALUTE; + if (pose == ArmorStandPose.DEATH) return POSE_PRESETS_DEATH; + if (pose == ArmorStandPose.FACEPALM) return POSE_PRESETS_FACEPALM; + if (pose == ArmorStandPose.LAZING) return POSE_PRESETS_LAZING; + if (pose == ArmorStandPose.CONFUSED) return POSE_PRESETS_CONFUSED; + if (pose == ArmorStandPose.FORMAL) return POSE_PRESETS_FORMAL; + if (pose == ArmorStandPose.SAD) return POSE_PRESETS_SAD; + if (pose == ArmorStandPose.JOYOUS) return POSE_PRESETS_JOYOUS; + if (pose == ArmorStandPose.STARGAZING) return POSE_PRESETS_STARGAZING; + return -1; + } + + private void tryApplyAllPoseParts(ArmorStandPose pose) { + if (!this.tryApplyPosePart(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD, this.lastSyncedPose::withHeadPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY, this.lastSyncedPose::withBodyPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM, this.lastSyncedPose::withRightArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM, this.lastSyncedPose::withLeftArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG, this.lastSyncedPose::withRightLegPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG, this.lastSyncedPose::withLeftLegPose)) + return; + } + + private boolean tryApplyPosePart(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment, Function function) { + if (this.tryApplyPoseAdjustment(oldPose, newPose, poseAdjustment)) { + this.lastSyncedPose = function.apply(newPose != null ? newPose : oldPose); + return true; + } else { + return false; + } + } + + private boolean tryApplyPoseAdjustment(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { if (newPose == null || oldPose.equals(newPose)) return true; if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; @@ -128,6 +218,7 @@ private boolean tryApplyPoseIncrements(Rotations oldPose, @Nullable Rotations ne @Override public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); @@ -153,6 +244,7 @@ private void applyPositionIncrements(double oldValue, double newValue, Navigable @Override public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); if (finalize) this.finalizeCurrentOperation(); } @@ -185,6 +277,7 @@ private boolean applyIncrementsFromSteps(float oldValue, float newValue, int tri @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; int triggerValue; if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; @@ -202,13 +295,51 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, bo super.sendStyleOption(styleOption, value, finalize); return; } - this.enqueueTriggerValue(triggerValue); + if (this.sendSingleTriggerValue(triggerValue, finalize)) { + styleOption.setOption(this.getArmorStand(), value); + } + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + int triggerValue = switch (alignment) { + case BLOCK -> AUTO_ALIGNMENT_BLOCK_ON_SURFACE; + case FLOATING_ITEM -> AUTO_ALIGNMENT_ITEM_ON_SURFACE; + case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; + case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; + }; + this.sendSingleTriggerValue(triggerValue); + } + + public boolean sendSingleTriggerValue(int triggerValue) { + return this.sendSingleTriggerValue(triggerValue, true); + } + + private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { + boolean result = this.enqueueTriggerValue(triggerValue); if (finalize) this.finalizeCurrentOperation(); + return result; + } + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return Stream.concat(Stream.of(super.getScreenTypes()), Stream.of(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE)).toArray(ArmorStandScreenType[]::new); + } + + @Override + protected boolean isEditingAllowed() { + return this.isEditingAllowed(false); + } + + @Override + protected boolean testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand) && this.player.distanceToSqr(armorStand) <= 9.0; } @Override protected int getDequeueDelayTicks() { - return 20; + return ArmorStatues.CONFIG.get(ClientConfig.class).clientCommandDelay; } private boolean enqueueTriggerValue(int triggerValue) { diff --git a/1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java index e147d61..6005d3e 100644 --- a/1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java +++ b/1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java @@ -5,7 +5,7 @@ import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandScreen; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; -import fuzs.armorstatues.handler.DataSyncTickHandler; +import fuzs.armorstatues.client.handler.DataSyncTickHandler; import fuzs.puzzleslib.client.core.ClientCoreServices; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; diff --git a/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 6a58d4b..405c45a 100644 --- a/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-27T17:46:25.105531 Languages: en_us -d04e0f1fd3fc55a1ca05d332b79edacf16759019 assets/statues/lang/en_us.json +// 1.19.2 2023-07-28T17:01:47.941569 Languages: en_us +1c053f5d519b333ba71fd8183b6632650d7dc6e2 assets/statues/lang/en_us.json diff --git a/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json b/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json index 6304896..f42838f 100644 --- a/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json +++ b/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -1,11 +1,25 @@ { "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "Out Of Range", "armorstatues.dataSync.failure.noPermission": "No Permission", "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", "armorstatues.dataSync.finished": "Finished sending queued armor stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", "item.minecraft.armor_stand.description": "Use [%s] + [%s] with an empty hand to open configuration screen.", "statues.screen.aligned": "Aligned!", - "statues.screen.alignments.block": "Align Block on Surface", + "statues.screen.alignments.block": "Align Block On Surface", "statues.screen.alignments.block.description": "Align an armor stand placed on a surface so that a block held by it appears on the surface.", "statues.screen.alignments.itemFlat": "Align Item Flat On Surface", "statues.screen.alignments.itemFlat.description": "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface.", @@ -13,7 +27,6 @@ "statues.screen.alignments.itemFloating.description": "Align an armor stand placed on a surface so that an item held by it appears upright on the surface.", "statues.screen.alignments.tool": "Align Tool Flat On Surface", "statues.screen.alignments.tool.description": "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface.", - "statues.screen.applied": "Applied!", "statues.screen.centered": "Align Centered", "statues.screen.centered.description": "Align an armor stand in the center of the block position it is placed on.", "statues.screen.cornered": "Align Cornered", @@ -71,8 +84,8 @@ "statues.screen.rotations.pose.rightLeg": "Right Leg", "statues.screen.rotations.randomize": "Randomize", "statues.screen.rotations.reset": "Reset", - "statues.screen.rotations.tip1": "Hold any [§dShift§r] or [§dAlt§r] key to lock sliders to a single axis!", - "statues.screen.rotations.tip2": "Use arrow keys to move sliders more precisely! Focus a slider first by clicking.", + "statues.screen.rotations.tip1": "Hold any [§dShift§r] or [§dAlt§r] key to lock two-dimensional sliders to a single axis while dragging!", + "statues.screen.rotations.tip2": "Use arrow keys to move sliders with greater precision than when dragging! Focus a slider first by clicking.", "statues.screen.rotations.unlimited": "Unlimited Rotations", "statues.screen.rotations.x": "X: %s", "statues.screen.rotations.y": "Y: %s", @@ -97,5 +110,6 @@ "statues.screen.type.poses": "Poses", "statues.screen.type.position": "Position", "statues.screen.type.rotations": "Rotations", - "statues.screen.type.style": "Style" + "statues.screen.type.style": "Style", + "statues.screen.type.vanillaTweaks": "Vanilla Tweaks" } \ No newline at end of file diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java index d96d8a1..c537aee 100644 --- a/1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java +++ b/1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java @@ -3,8 +3,8 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.client.StatuesApiClient; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; +import fuzs.armorstatues.client.handler.DataSyncTickHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; -import fuzs.armorstatues.handler.DataSyncTickHandler; import fuzs.puzzleslib.client.core.ClientCoreServices; import net.minecraft.client.Minecraft; import net.minecraft.world.InteractionResult; diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index 707719f..ac44c44 100644 --- a/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -1,11 +1,9 @@ package fuzs.armorstatues.data; -import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandPositionScreen; -import fuzs.armorstatues.api.client.gui.screens.armorstand.AbstractArmorStandScreen; -import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandPositionScreen; -import fuzs.armorstatues.api.client.gui.screens.armorstand.ArmorStandRotationsScreen; +import fuzs.armorstatues.api.client.gui.screens.armorstand.*; import fuzs.armorstatues.api.proxy.ClientProxy; import fuzs.armorstatues.api.world.inventory.data.*; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; import fuzs.armorstatues.api.world.inventory.data.ArmorStandAlignment; @@ -23,12 +21,27 @@ protected void addTranslations() { // Armor Statues this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "Out Of Range"); this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + this.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + this.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu."); + this.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + this.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); // Statues Api this.add(ClientProxy.OPEN_SCREEN_TRANSLATION_KEY, "Use [%s] + [%s] with an empty hand to open configuration screen."); - this.add(ArmorStandPose.POSE_SOURCE_TRANSLATION_KEY, "By %s"); + this.add(ArmorStandPosesScreen.POSE_SOURCE_TRANSLATION_KEY, "By %s"); this.add(ArmorStandPose.ATHENA.getTranslationKey(), "Athena"); this.add(ArmorStandPose.BRANDISH.getTranslationKey(), "Brandish"); this.add(ArmorStandPose.CANCAN.getTranslationKey(), "Cancan"); @@ -63,7 +76,7 @@ protected void addTranslations() { this.add(ArmorStandScreenType.STYLE.getTranslationKey(), "Style"); this.add(ArmorStandScreenType.POSES.getTranslationKey(), "Poses"); this.add(ArmorStandScreenType.POSITION.getTranslationKey(), "Position"); - this.add(ArmorStandStyleOption.TEXT_BOX_TRANSLATION_KEY, "Set a name to display above the entity if enabled."); + this.add(ArmorStandStyleScreen.TEXT_BOX_TRANSLATION_KEY, "Set a name to display above the entity if enabled."); this.add(ArmorStandStyleOptions.SHOW_ARMS.getTranslationKey(), "Show Arms"); this.add(ArmorStandStyleOptions.SHOW_ARMS.getDescriptionKey(), "Shows the statue's arms, so it may hold items in both hands."); this.add(ArmorStandStyleOptions.SMALL.getTranslationKey(), "Small"); @@ -88,6 +101,11 @@ protected void addTranslations() { this.add(ArmorStandPositionScreen.MOVE_BY_TRANSLATION_KEY, "Move By:"); this.add(ArmorStandPositionScreen.PIXELS_TRANSLATION_KEY, "%s Pixel(s)"); this.add(ArmorStandPositionScreen.BLOCKS_TRANSLATION_KEY, "%s Block(s)"); + this.add(ArmorStandPositionScreen.CENTERED_TRANSLATION_KEY, "Align Centered"); + this.add(ArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand in the center of the block position it is placed on."); + this.add(ArmorStandPositionScreen.CORNERED_TRANSLATION_KEY, "Align Cornered"); + this.add(ArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand at the corner of the block position it is placed on."); + this.add(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY, "Aligned!"); this.add(PosePartMutator.HEAD.getTranslationKey(), "Head"); this.add(PosePartMutator.BODY.getTranslationKey(), "Body"); this.add(PosePartMutator.LEFT_ARM.getTranslationKey(), "Left Arm"); @@ -97,8 +115,8 @@ protected void addTranslations() { this.add(PosePartMutator.AXIS_X_TRANSLATION_KEY, "X: %s"); this.add(PosePartMutator.AXIS_Y_TRANSLATION_KEY, "Y: %s"); this.add(PosePartMutator.AXIS_Z_TRANSLATION_KEY, "Z: %s"); - this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 1, "Hold any [§dShift§r] or [§dAlt§r] key to lock sliders to a single axis!"); - this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 2, "Use arrow keys to move sliders more precisely! Focus a slider first by clicking."); + this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 1, "Hold any [§dShift§r] or [§dAlt§r] key to lock two-dimensional sliders to a single axis while dragging!"); + this.add(ArmorStandRotationsScreen.TIP_TRANSLATION_KEY + 2, "Use arrow keys to move sliders with greater precision than when dragging! Focus a slider first by clicking."); this.add(ArmorStandRotationsScreen.RESET_TRANSLATION_KEY, "Reset"); this.add(ArmorStandRotationsScreen.RANDOMIZE_TRANSLATION_KEY, "Randomize"); this.add(ArmorStandRotationsScreen.LIMITED_TRANSLATION_KEY, "Limited Rotations"); @@ -106,11 +124,7 @@ protected void addTranslations() { this.add(ArmorStandRotationsScreen.COPY_TRANSLATION_KEY, "Copy"); this.add(ArmorStandRotationsScreen.PASTE_TRANSLATION_KEY, "Paste"); this.add(ArmorStandRotationsScreen.MIRROR_TRANSLATION_KEY, "Mirror"); - this.add(AbstractArmorStandPositionScreen.CENTERED_TRANSLATION_KEY, "Align Centered"); - this.add(AbstractArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand in the center of the block position it is placed on."); - this.add(AbstractArmorStandPositionScreen.CORNERED_TRANSLATION_KEY, "Align Cornered"); - this.add(AbstractArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY, "Align an armor stand at the corner of the block position it is placed on."); - this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block on Surface"); + this.add(ArmorStandAlignment.BLOCK.getTranslationKey(), "Align Block On Surface"); this.add(ArmorStandAlignment.BLOCK.getDescriptionsKey(), "Align an armor stand placed on a surface so that a block held by it appears on the surface."); this.add(ArmorStandAlignment.FLOATING_ITEM.getTranslationKey(), "Align Item On Surface"); this.add(ArmorStandAlignment.FLOATING_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that an item held by it appears upright on the surface."); @@ -118,8 +132,6 @@ protected void addTranslations() { this.add(ArmorStandAlignment.FLAT_ITEM.getDescriptionsKey(), "Align an armor stand placed on a surface so that a non-tool item held by it appears flat on the surface."); this.add(ArmorStandAlignment.TOOL.getTranslationKey(), "Align Tool Flat On Surface"); this.add(ArmorStandAlignment.TOOL.getDescriptionsKey(), "Align an armor stand placed on a surface so that a tool held by it appears flat on the surface."); - this.add(AbstractArmorStandScreen.APPLIED_TRANSLATION_KEY, "Applied!"); - this.add(AbstractArmorStandScreen.ALIGNED_TRANSLATION_KEY, "Aligned!"); this.add(AbstractArmorStandScreen.CREDITS_TRANSLATION_KEY, "Some content on this page originates from the Vanilla Tweaks \"Armor Statues\" data pack. Click this button to go to their website!"); } } diff --git a/1.19/gradle.properties b/1.19/gradle.properties index 69215ce..6835197 100755 --- a/1.19/gradle.properties +++ b/1.19/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.6 +modVersion=4.0.7 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index 2f76460..48dedc3 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.1-1.20.1] - 2023-07-28 +### Added +- Added a new tab that only shows when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack offering Vanilla Tweaks exclusive toggles +### Changed +- Optimized some actions during editing to be performed much quicker when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack + ## [v8.0.0-1.20.1] - 2023-07-27 - Ported to Minecraft 1.20.1 diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index fbddc76..42de006 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -1,6 +1,7 @@ package fuzs.armorstatues.client; import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.client.handler.DataSyncTickHandler; import fuzs.armorstatues.handler.ArmorStandInteractHandler; @@ -39,5 +40,6 @@ public void onClientSetup() { return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); }); ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); } } diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index 0028996..da972b8 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -2,37 +2,41 @@ import com.google.common.collect.Lists; import fuzs.armorstatues.init.ModRegistry; -import fuzs.puzzlesapi.api.client.statues.v1.gui.components.TickButton; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.AbstractArmorStandPositionScreen; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandButtonsScreen; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandPositionScreen; import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOptions; -import net.minecraft.Util; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; +import java.util.EnumSet; import java.util.List; -public class ArmorStandAlignmentsScreen extends AbstractArmorStandPositionScreen { +public class ArmorStandAlignmentsScreen extends ArmorStandButtonsScreen { public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { super(holder, inventory, component, dataSyncHandler); } @Override - protected List buildWidgets(ArmorStand armorStand) { - List widgets = Lists.newArrayList(new PositionAlignWidget()); + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new DoubleButtonWidget(Component.translatable(ArmorStandPositionScreen.CENTERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + })); for (ArmorStandAlignment alignment : ArmorStandAlignment.values()) { - widgets.add(new AlignmentWidget(alignment)); + widgets.add(new SingleButtonWidget(Component.translatable(alignment.getTranslationKey()), Component.translatable(alignment.getDescriptionsKey()), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendAlignment(alignment); + })); } return widgets; } @@ -47,61 +51,4 @@ protected void init() { public ArmorStandScreenType getScreenType() { return ModRegistry.ALIGNMENTS_SCREEN_TYPE; } - - private class AlignmentWidget extends AbstractPositionScreenWidget { - private final ArmorStandAlignment alignment; - - public AlignmentWidget(ArmorStandAlignment alignment) { - super(Component.empty()); - this.alignment = alignment; - } - - @Override - protected boolean shouldTick() { - return true; - } - - @Override - public void init(int posX, int posY) { - super.init(posX, posY); - this.children.add(Util.make(ArmorStandAlignmentsScreen.this.addRenderableWidget(new TickButton(posX, posY + 1, 194, 20, Component.translatable(this.alignment.getTranslationKey()), Component.translatable(ALIGNED_TRANSLATION_KEY), button -> { - ArmorStand armorStand = ArmorStandAlignmentsScreen.this.holder.getArmorStand(); - DataSyncHandler dataSyncHandler = ArmorStandAlignmentsScreen.this.dataSyncHandler; - if (!armorStand.isInvisible()) { - dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.INVISIBLE, true, false); - } - if (!armorStand.isNoGravity()) { - dataSyncHandler.sendStyleOption(ArmorStandStyleOptions.NO_GRAVITY, true, false); - } - dataSyncHandler.sendPose(this.alignment.getPose(), false); - Vec3 alignmentOffset = this.alignment.getAlignmentOffset(armorStand.isSmall()); - Vec3 newPosition = getLocalPosition(armorStand, alignmentOffset); - dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z(), false); - dataSyncHandler.finalizeCurrentOperation(); - })), widget -> { - widget.setTooltip(Tooltip.create(Component.translatable(this.alignment.getDescriptionsKey()))); - })); - } - - /** - * Copied from {@link net.minecraft.commands.arguments.coordinates.LocalCoordinates#getPosition(CommandSourceStack)}. - */ - private static Vec3 getLocalPosition(Entity entity, Vec3 offset) { - Vec2 vec2 = entity.getRotationVector(); - Vec3 vec3 = entity.position(); - float f = Mth.cos((vec2.y + 90.0F) * 0.017453292F); - float g = Mth.sin((vec2.y + 90.0F) * 0.017453292F); - float h = Mth.cos(-vec2.x * 0.017453292F); - float i = Mth.sin(-vec2.x * 0.017453292F); - float j = Mth.cos((-vec2.x + 90.0F) * 0.017453292F); - float k = Mth.sin((-vec2.x + 90.0F) * 0.017453292F); - Vec3 vec32 = new Vec3(f * h, i, g * h); - Vec3 vec33 = new Vec3(f * j, k, g * j); - Vec3 vec34 = vec32.cross(vec33).scale(-1.0); - double d = vec32.x * offset.z() + vec33.x * offset.y() + vec34.x * offset.x(); - double e = vec32.y * offset.z() + vec33.y * offset.y() + vec34.y * offset.x(); - double l = vec32.z * offset.z() + vec33.z * offset.y() + vec34.z * offset.x(); - return new Vec3(vec3.x + d, vec3.y + e, vec3.z + l); - } - } } diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java new file mode 100644 index 0000000..ed09c7d --- /dev/null +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java @@ -0,0 +1,75 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandButtonsScreen; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; + +import java.util.List; + +public class ArmorStandVanillaTweaksScreen extends ArmorStandButtonsScreen { + public static final String TRIGGER_SENT_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.triggerSent"; + public static final String CHECK_TARGET_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget"; + public static final String CHECK_TARGET_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget.description"; + public static final String LOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock"; + public static final String LOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock.description"; + public static final String UNLOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock"; + public static final String UNLOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock.description"; + public static final String TOOL_RACK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack"; + public static final String TOOL_RACK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack.description"; + public static final String SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand"; + public static final String SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand.description"; + public static final String SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead"; + public static final String SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead.description"; + + public ArmorStandVanillaTweaksScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + public VanillaTweaksDataSyncHandler getDataSyncHandler() { + return (VanillaTweaksDataSyncHandler) super.getDataSyncHandler(); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new SingleButtonWidget(Component.translatable(CHECK_TARGET_TRANSLATION_KEY), Component.translatable(CHECK_TARGET_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.CHECK_TARGET); + this.onClose(); + })); + widgets.add(new DoubleButtonWidget(Component.translatable(LOCK_TRANSLATION_KEY), Component.translatable(UNLOCK_TRANSLATION_KEY), Component.translatable(LOCK_DESCRIPTION_KEY), Component.translatable(UNLOCK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_LOCK); + }, button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_UNLOCK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(TOOL_RACK_TRANSLATION_KEY), Component.translatable(TOOL_RACK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.AUTO_ALIGNMENT_TOOL_RACK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_OFFHAND); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_HEAD); + })); + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE; + } +} diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java index 32bf170..91ccdad 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -17,7 +17,7 @@ public static void onRemove(Screen screen) { } public static void onEndClientTick(Minecraft minecraft) { - if (!(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (minecraft.player != null && !(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { if (dataSyncHandler.shouldContinueTicking()) { dataSyncHandler.tick(); } else { diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java index 14fcfee..d6978d9 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -7,4 +7,7 @@ public class ClientConfig implements ConfigCore { @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) public boolean useVanillaTweaksTriggers = false; + @Config(description = "The delay in ticks for sending queued client commands for editing armor stands to the server. Increase this values if commands are sent too quickly and the server fails to process all of them.") + @Config.IntRange(min = 20) + public int clientCommandDelay = 20; } diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index 06bf4cd..cd5e925 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -17,6 +17,7 @@ public class ModRegistry { }); public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); + public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", new ItemStack(Items.WRITTEN_BOOK)); public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { @Override diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index c51faae..e5e3d0d 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -3,6 +3,7 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandPose; import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOption; @@ -19,11 +20,10 @@ import java.util.ArrayDeque; import java.util.Queue; import java.util.function.BiPredicate; -import java.util.function.Predicate; -import java.util.stream.Stream; public class CommandDataSyncHandler implements DataSyncHandler { public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; @@ -32,8 +32,9 @@ public class CommandDataSyncHandler implements DataSyncHandler { @Nullable private static ArmorStand queueArmorStand; private static int itemDequeuedTicks; - protected final LocalPlayer player; + private final ArmorStandHolder holder; + protected final LocalPlayer player; protected ArmorStandPose lastSyncedPose; public CommandDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { @@ -49,7 +50,7 @@ public ArmorStandHolder getArmorStandHolder() { @Override public void sendName(String name) { - if (!this.testPermissionLevel()) return; + if (!this.isEditingAllowed()) return; DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); CompoundTag tag = new CompoundTag(); tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); @@ -64,12 +65,12 @@ public final void sendPose(ArmorStandPose pose) { @Override public void sendPose(ArmorStandPose pose, boolean finalize) { - if (!this.testPermissionLevel()) return; - pose.applyToEntity(this.getArmorStand()); + if (!this.isEditingAllowed()) return; // split this into multiple chat messages as the client chat field has a very low character limit this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); if (finalize) this.finalizeCurrentOperation(); } @@ -83,6 +84,11 @@ private void sendPosePart(BiPredicate dataWriter, A } } + @Override + public @Nullable ArmorStandPose getLastSyncedPose() { + return this.lastSyncedPose; + } + @Override public final void sendPosition(double posX, double posY, double posZ) { this.sendPosition(posX, posY, posZ, true); @@ -91,7 +97,7 @@ public final void sendPosition(double posX, double posY, double posZ) { @Override public void sendPosition(double posX, double posY, double posZ, boolean finalize) { - if (!this.testPermissionLevel()) return; + if (!this.isEditingAllowed()) return; ListTag listTag = new ListTag(); listTag.add(DoubleTag.valueOf(posX)); listTag.add(DoubleTag.valueOf(posY)); @@ -109,7 +115,7 @@ public final void sendRotation(float rotation) { @Override public void sendRotation(float rotation, boolean finalize) { - if (!this.testPermissionLevel()) return; + if (!this.isEditingAllowed()) return; ListTag listTag = new ListTag(); listTag.add(FloatTag.valueOf(rotation)); CompoundTag tag = new CompoundTag(); @@ -125,17 +131,18 @@ public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean val @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { - if (!this.testPermissionLevel()) return; - styleOption.setOption(this.getArmorStand(), value); + if (!this.isEditingAllowed()) return; CompoundTag tag = new CompoundTag(); styleOption.toTag(tag, value); this.enqueueEntityData(tag); + styleOption.setOption(this.getArmorStand(), value); if (finalize) this.finalizeCurrentOperation(); } @Override - public ArmorStandScreenType[] tabs() { - return Stream.of(this.getArmorStandHolder().getDataProvider().getScreenTypes()).filter(Predicate.not(ArmorStandScreenType::requiresServer)).toArray(ArmorStandScreenType[]::new); + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.super.sendAlignment(alignment); } @Override @@ -147,7 +154,7 @@ public boolean supportsScreenType(ArmorStandScreenType screenType) { public void tick() { if (itemDequeuedTicks > 0) itemDequeuedTicks--; if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { - if (queueArmorStand.isAlive()) { + if (this.testArmorStand(queueArmorStand)) { this.player.connection.sendCommand(CLIENT_COMMAND_QUEUE.poll()); } else { CLIENT_COMMAND_QUEUE.clear(); @@ -167,14 +174,25 @@ public boolean shouldContinueTicking() { return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; } - private boolean testPermissionLevel() { - if (!this.player.hasPermissions(2)) { + protected boolean isEditingAllowed() { + return this.isEditingAllowed(true); + } + + protected final boolean isEditingAllowed(boolean testPermissionLevel) { + if (testPermissionLevel && !this.player.hasPermissions(2)) { this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); return false; + } else if (queueArmorStand != null && !this.testArmorStand(queueArmorStand)) { + this.sendFailureMessage(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)); + return false; } return true; } + protected boolean testArmorStand(ArmorStand armorStand) { + return armorStand.isAlive(); + } + protected boolean enqueueClientCommand(String clientCommand) { if (CLIENT_COMMAND_QUEUE.isEmpty()) { queueArmorStand = null; diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java index 21798c4..7420260 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -1,18 +1,33 @@ package fuzs.armorstatues.network.client.data; import com.google.common.collect.ImmutableSortedMap; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandPose; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOption; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOptions; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.*; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Rotations; +import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.NavigableMap; +import java.util.function.Function; +import java.util.stream.Stream; public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { + private static final int MAX_INCREMENTAL_OPERATIONS = 12; + public static final int CHECK_TARGET = 999; + public static final int SWAP_SLOTS_MAINHAND_AND_OFFHAND = 161; + public static final int SWAP_SLOTS_MAINHAND_AND_HEAD = 162; + public static final int MIRROR_ARMS_LEFT_TO_RIGHT = 131; + public static final int MIRROR_ARMS_RIGHT_TO_LEFT = 132; + public static final int MIRROR_LEGS_LEFT_TO_RIGHT = 133; + public static final int MIRROR_LEGS_RIGHT_TO_LEFT = 134; + public static final int UTILITIES_LOCK = 1000; + public static final int UTILITIES_UNLOCK = 1001; + public static final int MIRROR_AND_FLIP_FLIP = 135; public static final int SHOW_BASE_PLATE_YES = 1; public static final int SHOW_BASE_PLATE_NO = 2; public static final int SHOW_ARMS_YES = 3; @@ -49,6 +64,31 @@ public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + public static final int POSE_PRESETS_ATTENTION = 20; + public static final int POSE_PRESETS_WALKING = 21; + public static final int POSE_PRESETS_RUNNING = 22; + public static final int POSE_PRESETS_POINTING = 23; + public static final int POSE_PRESETS_BLOCKING = 24; + public static final int POSE_PRESETS_LUNGEING = 25; + public static final int POSE_PRESETS_WINNING = 26; + public static final int POSE_PRESETS_SITTING = 27; + public static final int POSE_PRESETS_ARABESQUE = 28; + public static final int POSE_PRESETS_CUPID = 29; + public static final int POSE_PRESETS_CONFIDENT = 30; + public static final int POSE_PRESETS_SALUTE = 31; + public static final int POSE_PRESETS_DEATH = 32; + public static final int POSE_PRESETS_FACEPALM = 33; + public static final int POSE_PRESETS_LAZING = 34; + public static final int POSE_PRESETS_CONFUSED = 35; + public static final int POSE_PRESETS_FORMAL = 36; + public static final int POSE_PRESETS_SAD = 37; + public static final int POSE_PRESETS_JOYOUS = 38; + public static final int POSE_PRESETS_STARGAZING = 39; + public static final int AUTO_ALIGNMENT_BLOCK_ON_SURFACE = 151; + public static final int AUTO_ALIGNMENT_ITEM_ON_SURFACE = 152; + public static final int AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE = 153; + public static final int AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE = 154; + public static final int AUTO_ALIGNMENT_TOOL_RACK = 155; public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; @@ -85,7 +125,6 @@ public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE = 93; public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; - private static final int MAX_INCREMENTAL_OPERATIONS = 12; private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE}; @@ -106,38 +145,79 @@ public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) @Override public void sendPose(ArmorStandPose pose, boolean finalize) { - $1: - { - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD)) - break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY)) - break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM)) - break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM)) - break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG)) - break $1; - if (!this.tryApplyPoseIncrements(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG)) - break $1; + if (!this.isEditingAllowed()) return; + int triggerValue = this.getTriggerValueFromPose(pose); + if (triggerValue != -1) { + if (this.enqueueTriggerValue(triggerValue)) { + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + } + } else { + this.tryApplyAllPoseParts(pose); } - this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); if (finalize) this.finalizeCurrentOperation(); } - private boolean tryApplyPoseIncrements(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { - if (newPose == null || oldPose.equals(newPose)) return true; - if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) - return false; - if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) - return false; - if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) + private int getTriggerValueFromPose(ArmorStandPose pose) { + if (pose.getSourceType() == ArmorStandPose.SourceType.EMPTY) return POSE_PRESETS_ATTENTION; + if (pose.getSourceType() == ArmorStandPose.SourceType.MIRRORED) return MIRROR_AND_FLIP_FLIP; + if (pose.getSourceType() != ArmorStandPose.SourceType.VANILLA_TWEAKS) return -1; + if (pose == ArmorStandPose.WALKING) return POSE_PRESETS_WALKING; + if (pose == ArmorStandPose.RUNNING) return POSE_PRESETS_RUNNING; + if (pose == ArmorStandPose.POINTING) return POSE_PRESETS_POINTING; + if (pose == ArmorStandPose.BLOCKING) return POSE_PRESETS_BLOCKING; + if (pose == ArmorStandPose.LUNGEING) return POSE_PRESETS_LUNGEING; + if (pose == ArmorStandPose.WINNING) return POSE_PRESETS_WINNING; + if (pose == ArmorStandPose.SITTING) return POSE_PRESETS_SITTING; + if (pose == ArmorStandPose.ARABESQUE) return POSE_PRESETS_ARABESQUE; + if (pose == ArmorStandPose.CUPID) return POSE_PRESETS_CUPID; + if (pose == ArmorStandPose.CONFIDENT) return POSE_PRESETS_CONFIDENT; + if (pose == ArmorStandPose.SALUTE) return POSE_PRESETS_SALUTE; + if (pose == ArmorStandPose.DEATH) return POSE_PRESETS_DEATH; + if (pose == ArmorStandPose.FACEPALM) return POSE_PRESETS_FACEPALM; + if (pose == ArmorStandPose.LAZING) return POSE_PRESETS_LAZING; + if (pose == ArmorStandPose.CONFUSED) return POSE_PRESETS_CONFUSED; + if (pose == ArmorStandPose.FORMAL) return POSE_PRESETS_FORMAL; + if (pose == ArmorStandPose.SAD) return POSE_PRESETS_SAD; + if (pose == ArmorStandPose.JOYOUS) return POSE_PRESETS_JOYOUS; + if (pose == ArmorStandPose.STARGAZING) return POSE_PRESETS_STARGAZING; + return -1; + } + + private void tryApplyAllPoseParts(ArmorStandPose pose) { + if (!this.tryApplyPosePart(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD, this.lastSyncedPose::withHeadPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY, this.lastSyncedPose::withBodyPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM, this.lastSyncedPose::withRightArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM, this.lastSyncedPose::withLeftArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG, this.lastSyncedPose::withRightLegPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG, this.lastSyncedPose::withLeftLegPose)) + return; + } + + private boolean tryApplyPosePart(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment, Function function) { + if (this.tryApplyPoseAdjustment(oldPose, newPose, poseAdjustment)) { + this.lastSyncedPose = function.apply(newPose != null ? newPose : oldPose); + return true; + } else { return false; + } + } + + private boolean tryApplyPoseAdjustment(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + if (newPose == null || oldPose.equals(newPose)) return true; + if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) return false; return true; } @Override public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); @@ -163,6 +243,7 @@ private void applyPositionIncrements(double oldValue, double newValue, Navigable @Override public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); if (finalize) this.finalizeCurrentOperation(); } @@ -195,6 +276,7 @@ private boolean applyIncrementsFromSteps(float oldValue, float newValue, int tri @Override public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; int triggerValue; if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; @@ -212,13 +294,51 @@ public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, bo super.sendStyleOption(styleOption, value, finalize); return; } - this.enqueueTriggerValue(triggerValue); + if (this.sendSingleTriggerValue(triggerValue, finalize)) { + styleOption.setOption(this.getArmorStand(), value); + } + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + int triggerValue = switch (alignment) { + case BLOCK -> AUTO_ALIGNMENT_BLOCK_ON_SURFACE; + case FLOATING_ITEM -> AUTO_ALIGNMENT_ITEM_ON_SURFACE; + case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; + case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; + }; + this.sendSingleTriggerValue(triggerValue); + } + + public boolean sendSingleTriggerValue(int triggerValue) { + return this.sendSingleTriggerValue(triggerValue, true); + } + + private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { + boolean result = this.enqueueTriggerValue(triggerValue); if (finalize) this.finalizeCurrentOperation(); + return result; + } + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return Stream.concat(Stream.of(super.getScreenTypes()), Stream.of(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE)).toArray(ArmorStandScreenType[]::new); + } + + @Override + protected boolean isEditingAllowed() { + return this.isEditingAllowed(false); + } + + @Override + protected boolean testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand) && this.player.distanceToSqr(armorStand) <= 9.0; } @Override protected int getDequeueDelayTicks() { - return 20; + return ArmorStatues.CONFIG.get(ClientConfig.class).clientCommandDelay; } private boolean enqueueTriggerValue(int triggerValue) { diff --git a/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 74d892b..610349b 100644 --- a/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.20.1 2023-07-27T18:19:44.79768 Languages: en_us -0631eade65589ccf2216571b521d4f32b3e2b8d6 assets/armorstatues/lang/en_us.json +// 1.20.1 2023-07-28T17:02:23.622753 Languages: en_us +a9a0748cdc8850668db99c9fe600f6dc7cb836f5 assets/armorstatues/lang/en_us.json diff --git a/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json index 2cd376b..3747440 100644 --- a/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json +++ b/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -1,7 +1,22 @@ { "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "Out Of Range", "armorstatues.dataSync.failure.noPermission": "No Permission", "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", "armorstatues.dataSync.finished": "Finished sending queued armor stand data", - "puzzlesapi.screen.type.alignments": "Alignments" + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", + "puzzlesapi.screen.type.alignments": "Alignments", + "puzzlesapi.screen.type.vanillaTweaks": "Vanilla Tweaks" } \ No newline at end of file diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index 10070eb..51744dc 100644 --- a/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -1,5 +1,6 @@ package fuzs.armorstatues.data; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; import fuzs.puzzleslib.api.data.v1.AbstractLanguageProvider; @@ -16,8 +17,23 @@ protected void addTranslations() { // Armor Statues this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "Out Of Range"); this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + this.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + this.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu."); + this.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + this.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); } } diff --git a/1.20/gradle.properties b/1.20/gradle.properties index 402447b..ec1326f 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=8.0.0 +modVersion=8.0.1 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -29,7 +29,7 @@ projectModrinthId=bbGCtEvb dependenciesVersionCatalog=1.20.1-v11 dependenciesPuzzlesLibVersion=8.0.13 dependenciesMinPuzzlesLibVersion=8.0.13 -dependenciesPuzzlesApi=8.1.1 +dependenciesPuzzlesApi=8.1.2 dependenciesRequiredForgeCurseForge=puzzles-lib dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib dependenciesRequiredForgeModrinth=puzzles-lib From 3ff26564fa1f48c903c1fbe339aaf0a232e3d9b0 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:37:19 +0200 Subject: [PATCH 16/31] vanilla tweaks fixes --- 1.19/CHANGELOG.md | 4 ++++ .../client/data/CommandDataSyncHandler.java | 14 ++++++------ .../data/VanillaTweaksDataSyncHandler.java | 21 +++++++++++++----- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 ++-- .../resources/assets/statues/lang/en_us.json | 3 ++- .../data/ModLanguageProvider.java | 3 ++- 1.19/gradle.properties | 2 +- 1.20/CHANGELOG.md | 4 ++++ .../client/data/CommandDataSyncHandler.java | 14 ++++++------ .../data/VanillaTweaksDataSyncHandler.java | 22 ++++++++++++++----- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 ++-- .../assets/armorstatues/lang/en_us.json | 3 ++- .../data/ModLanguageProvider.java | 3 ++- 1.20/gradle.properties | 2 +- 14 files changed, 69 insertions(+), 34 deletions(-) diff --git a/1.19/CHANGELOG.md b/1.19/CHANGELOG.md index 76d52f3..1e7e251 100644 --- a/1.19/CHANGELOG.md +++ b/1.19/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v4.0.8-1.19.2] - 2023-07-29 +### Fixed +- Fixed an issue with always receiving an incorrect error message when trying to edit an armor stand on a server with the Vanilla Tweaks data pack installed + ## [v4.0.7-1.19.2] - 2023-07-28 ### Added - Added a new tab that only shows when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack offering Vanilla Tweaks exclusive toggles diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 0c94e9d..bfb8821 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -1,5 +1,7 @@ package fuzs.armorstatues.network.client.data; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.network.client.data.DataSyncHandler; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; @@ -24,6 +26,7 @@ public class CommandDataSyncHandler implements DataSyncHandler { public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; + public static final String OUT_OF_RANGE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.outOfRange"; public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; @@ -154,7 +157,7 @@ public boolean supportsScreenType(ArmorStandScreenType screenType) { public void tick() { if (itemDequeuedTicks > 0) itemDequeuedTicks--; if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { - if (this.testArmorStand(queueArmorStand)) { + if (this.testArmorStand(queueArmorStand).right().isPresent()) { this.player.commandSigned(CLIENT_COMMAND_QUEUE.poll(), null); } else { CLIENT_COMMAND_QUEUE.clear(); @@ -182,15 +185,12 @@ protected final boolean isEditingAllowed(boolean testPermissionLevel) { if (testPermissionLevel && !this.player.hasPermissions(2)) { this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); return false; - } else if (queueArmorStand != null && !this.testArmorStand(queueArmorStand)) { - this.sendFailureMessage(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)); - return false; } - return true; + return this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); } - protected boolean testArmorStand(ArmorStand armorStand) { - return armorStand.isAlive(); + protected Either testArmorStand(ArmorStand armorStand) { + return !armorStand.isAlive() ? Either.left(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)) : Either.right(Unit.INSTANCE); } protected boolean enqueueClientCommand(String clientCommand) { diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java index 1d74aef..592d7d6 100644 --- a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -1,6 +1,8 @@ package fuzs.armorstatues.network.client.data; import com.google.common.collect.ImmutableSortedMap; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.api.world.inventory.ArmorStandHolder; import fuzs.armorstatues.api.world.inventory.data.*; @@ -14,6 +16,7 @@ import java.util.Map; import java.util.NavigableMap; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; @@ -151,6 +154,7 @@ public void sendPose(ArmorStandPose pose, boolean finalize) { if (triggerValue != -1) { if (this.enqueueTriggerValue(triggerValue)) { this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); } } else { this.tryApplyAllPoseParts(pose); @@ -309,11 +313,12 @@ public void sendAlignment(ArmorStandAlignment alignment) { case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; }; - this.sendSingleTriggerValue(triggerValue); + this.sendSingleTriggerValue(triggerValue, true); } - public boolean sendSingleTriggerValue(int triggerValue) { - return this.sendSingleTriggerValue(triggerValue, true); + public void sendSingleTriggerValue(int triggerValue) { + if (!this.isEditingAllowed()) return; + this.sendSingleTriggerValue(triggerValue, true); } private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { @@ -333,8 +338,14 @@ protected boolean isEditingAllowed() { } @Override - protected boolean testArmorStand(ArmorStand armorStand) { - return super.testArmorStand(armorStand) && this.player.distanceToSqr(armorStand) <= 9.0; + protected Either testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand).>map(Optional::of, $ -> { + if (this.player.distanceToSqr(armorStand) < 9.0) { + return Optional.empty(); + } else { + return Optional.of(Component.translatable(OUT_OF_RANGE_TRANSLATION_KEY)); + } + }).>map(Either::left).orElse(Either.right(Unit.INSTANCE)); } @Override diff --git a/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 405c45a..525b2ea 100644 --- a/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.19.2 2023-07-28T17:01:47.941569 Languages: en_us -1c053f5d519b333ba71fd8183b6632650d7dc6e2 assets/statues/lang/en_us.json +// 1.19.2 2023-07-29T15:17:53.05358 Languages: en_us +4471aca48f8c14711835624b702c98ab8f90b317 assets/statues/lang/en_us.json diff --git a/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json b/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json index f42838f..f3b0b60 100644 --- a/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json +++ b/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json @@ -1,8 +1,9 @@ { "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", - "armorstatues.dataSync.failure.noArmorStand": "Out Of Range", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", "armorstatues.dataSync.failure.noPermission": "No Permission", "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", "armorstatues.dataSync.finished": "Finished sending queued armor stand data", "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index ac44c44..91e0ee1 100644 --- a/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -21,7 +21,8 @@ protected void addTranslations() { // Armor Statues this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); - this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "Out Of Range"); + this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + this.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); diff --git a/1.19/gradle.properties b/1.19/gradle.properties index 6835197..c0873ca 100755 --- a/1.19/gradle.properties +++ b/1.19/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=4.0.7 +modVersion=4.0.8 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index 48dedc3..12cad8f 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.2-1.20.1] - 2023-07-29 +### Fixed +- Fixed an issue with always receiving an incorrect error message when trying to edit an armor stand on a server with the Vanilla Tweaks data pack installed + ## [v8.0.1-1.20.1] - 2023-07-28 ### Added - Added a new tab that only shows when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack offering Vanilla Tweaks exclusive toggles diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index e5e3d0d..4bcd9af 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -1,5 +1,7 @@ package fuzs.armorstatues.network.client.data; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; import fuzs.armorstatues.ArmorStatues; import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; @@ -24,6 +26,7 @@ public class CommandDataSyncHandler implements DataSyncHandler { public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; + public static final String OUT_OF_RANGE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.outOfRange"; public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; @@ -154,7 +157,7 @@ public boolean supportsScreenType(ArmorStandScreenType screenType) { public void tick() { if (itemDequeuedTicks > 0) itemDequeuedTicks--; if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { - if (this.testArmorStand(queueArmorStand)) { + if (this.testArmorStand(queueArmorStand).right().isPresent()) { this.player.connection.sendCommand(CLIENT_COMMAND_QUEUE.poll()); } else { CLIENT_COMMAND_QUEUE.clear(); @@ -182,15 +185,12 @@ protected final boolean isEditingAllowed(boolean testPermissionLevel) { if (testPermissionLevel && !this.player.hasPermissions(2)) { this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); return false; - } else if (queueArmorStand != null && !this.testArmorStand(queueArmorStand)) { - this.sendFailureMessage(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)); - return false; } - return true; + return this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); } - protected boolean testArmorStand(ArmorStand armorStand) { - return armorStand.isAlive(); + protected Either testArmorStand(ArmorStand armorStand) { + return !armorStand.isAlive() ? Either.left(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)) : Either.right(Unit.INSTANCE); } protected boolean enqueueClientCommand(String clientCommand) { diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java index 7420260..e573f08 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -1,6 +1,8 @@ package fuzs.armorstatues.network.client.data; import com.google.common.collect.ImmutableSortedMap; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.config.ClientConfig; import fuzs.armorstatues.init.ModRegistry; @@ -8,11 +10,13 @@ import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.*; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Rotations; +import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.NavigableMap; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; @@ -150,6 +154,7 @@ public void sendPose(ArmorStandPose pose, boolean finalize) { if (triggerValue != -1) { if (this.enqueueTriggerValue(triggerValue)) { this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); } } else { this.tryApplyAllPoseParts(pose); @@ -308,11 +313,12 @@ public void sendAlignment(ArmorStandAlignment alignment) { case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; }; - this.sendSingleTriggerValue(triggerValue); + this.sendSingleTriggerValue(triggerValue, true); } - public boolean sendSingleTriggerValue(int triggerValue) { - return this.sendSingleTriggerValue(triggerValue, true); + public void sendSingleTriggerValue(int triggerValue) { + if (!this.isEditingAllowed()) return; + this.sendSingleTriggerValue(triggerValue, true); } private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { @@ -332,8 +338,14 @@ protected boolean isEditingAllowed() { } @Override - protected boolean testArmorStand(ArmorStand armorStand) { - return super.testArmorStand(armorStand) && this.player.distanceToSqr(armorStand) <= 9.0; + protected Either testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand).>map(Optional::of, $ -> { + if (this.player.distanceToSqr(armorStand) < 9.0) { + return Optional.empty(); + } else { + return Optional.of(Component.translatable(OUT_OF_RANGE_TRANSLATION_KEY)); + } + }).>map(Either::left).orElse(Either.right(Unit.INSTANCE)); } @Override diff --git a/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 610349b..8e2c24f 100644 --- a/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.20.1 2023-07-28T17:02:23.622753 Languages: en_us -a9a0748cdc8850668db99c9fe600f6dc7cb836f5 assets/armorstatues/lang/en_us.json +// 1.20.1 2023-07-29T15:02:23.443069 Languages: en_us +9ecbeccea1af534ecf344346c3f5cecde17fd977 assets/armorstatues/lang/en_us.json diff --git a/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json index 3747440..e392806 100644 --- a/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json +++ b/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -1,8 +1,9 @@ { "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", - "armorstatues.dataSync.failure.noArmorStand": "Out Of Range", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", "armorstatues.dataSync.failure.noPermission": "No Permission", "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", "armorstatues.dataSync.finished": "Finished sending queued armor stand data", "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java index 51744dc..53b29c2 100644 --- a/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ b/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -17,7 +17,8 @@ protected void addTranslations() { // Armor Statues this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); - this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "Out Of Range"); + this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + this.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); diff --git a/1.20/gradle.properties b/1.20/gradle.properties index ec1326f..f45be4b 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=8.0.1 +modVersion=8.0.2 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 From 28b0e555a4d7c6113b37dec65391babc301694e5 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:54:19 +0200 Subject: [PATCH 17/31] fix forge crash when mod is missing on server --- 1.20/CHANGELOG.md | 4 ++++ .../armorstatues/handler/ArmorStandInteractHandler.java | 8 ++++++-- 1.20/gradle.properties | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index 12cad8f..7710300 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.3-1.20.1] - 2023-08-16 +### Fixed +- Fixed a crash trying to interact with an armor stand when playing on a Forge server that does not have Armor Statues installed (Forge only) + ## [v8.0.2-1.20.1] - 2023-07-29 ### Fixed - Fixed an issue with always receiving an incorrect error message when trying to edit an armor stand on a server with the Vanilla Tweaks data pack installed diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index 517095a..bc152dc 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -16,6 +16,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -24,8 +25,11 @@ public class ArmorStandInteractHandler { public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { if (!player.isSpectator() && target.getType() == EntityType.ARMOR_STAND) { - EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, ModRegistry.ARMOR_STAND_MENU_TYPE.get(), ModRegistry.ARMOR_STAND_DATA_PROVIDER); - if (result.isInterrupt() && level.isClientSide && !presentServerside) { + boolean clientsideOnly = level.isClientSide && !presentServerside; + // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients + MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.get(); + EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, menuType, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + if (result.isInterrupt() && clientsideOnly) { Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here diff --git a/1.20/gradle.properties b/1.20/gradle.properties index f45be4b..1725db6 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=8.0.2 +modVersion=8.0.3 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 From 522490f1253f151a9f144f315aeb6d42d0f1c1bd Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sun, 3 Dec 2023 22:33:26 +0100 Subject: [PATCH 18/31] update puzzlesapi --- 1.20/CHANGELOG.md | 4 ++++ 1.20/Fabric/src/main/resources/fabric.mod.json | 1 + 1.20/Forge/src/main/resources/META-INF/mods.toml | 7 +++++++ 1.20/gradle.properties | 10 +++++----- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index 7710300..1444eb7 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.4-1.20.1] - 2023-12-03 +### Changed +- Updated to Puzzles Api v8.1.4 + ## [v8.0.3-1.20.1] - 2023-08-16 ### Fixed - Fixed a crash trying to interact with an armor stand when playing on a Forge server that does not have Armor Statues installed (Forge only) diff --git a/1.20/Fabric/src/main/resources/fabric.mod.json b/1.20/Fabric/src/main/resources/fabric.mod.json index 1fb00d5..d1caf67 100644 --- a/1.20/Fabric/src/main/resources/fabric.mod.json +++ b/1.20/Fabric/src/main/resources/fabric.mod.json @@ -37,6 +37,7 @@ "fabricloader": ">=${minFabricVersion}", "fabric-api": ">=${minFabricApiVersion}", "puzzleslib": ">=${minPuzzlesVersion}", + "puzzlesapi": "*", "minecraft": "${minecraftVersion}", "java": ">=17" } diff --git a/1.20/Forge/src/main/resources/META-INF/mods.toml b/1.20/Forge/src/main/resources/META-INF/mods.toml index e15b638..fac0264 100644 --- a/1.20/Forge/src/main/resources/META-INF/mods.toml +++ b/1.20/Forge/src/main/resources/META-INF/mods.toml @@ -36,5 +36,12 @@ versionRange = "[${minPuzzlesVersion},)" ordering = "NONE" side = "BOTH" +[[dependencies.${ modId }]] +modId = "puzzlesapi" +mandatory = true +versionRange = "*" +ordering = "NONE" +side = "BOTH" + [modproperties.${ modId }] catalogueImageIcon = "mod_logo.png" diff --git a/1.20/gradle.properties b/1.20/gradle.properties index 1725db6..65c8675 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=8.0.3 +modVersion=8.0.4 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -26,10 +26,10 @@ projectReleaseType=release projectCurseForgeId=682566 projectModrinthId=bbGCtEvb -dependenciesVersionCatalog=1.20.1-v11 -dependenciesPuzzlesLibVersion=8.0.13 -dependenciesMinPuzzlesLibVersion=8.0.13 -dependenciesPuzzlesApi=8.1.2 +dependenciesVersionCatalog=1.20.1-v25 +dependenciesPuzzlesLibVersion=8.1.11 +dependenciesMinPuzzlesLibVersion=8.1.11 +dependenciesPuzzlesApi=8.1.4 dependenciesRequiredForgeCurseForge=puzzles-lib dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib dependenciesRequiredForgeModrinth=puzzles-lib From f68fd94592a24621f824774ac05b2c270af5487d Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sun, 3 Dec 2023 22:51:46 +0100 Subject: [PATCH 19/31] misc bugfixes --- 1.20/CHANGELOG.md | 6 ++++++ .../main/java/fuzs/armorstatues/config/ClientConfig.java | 2 ++ .../armorstatues/handler/ArmorStandInteractHandler.java | 2 +- .../network/client/data/CommandDataSyncHandler.java | 5 +++-- 1.20/gradle.properties | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index 1444eb7..dc05013 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.5-1.20.1] - 2023-12-03 +### Changed +- Client side permissions check can now be disabled in the config +### Fixed +- Armor stand menu can no longer open in adventure mode + ## [v8.0.4-1.20.1] - 2023-12-03 ### Changed - Updated to Puzzles Api v8.1.4 diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java index d6978d9..6e2a684 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -7,6 +7,8 @@ public class ClientConfig implements ConfigCore { @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) public boolean useVanillaTweaksTriggers = false; + @Config(description = "Do not check if the client has the necessary permission level for executing the '/data' command when trying to edit an armor stand. Useful when the current server is using custom permissions handling.") + public boolean overrideClientPermissionsCheck = false; @Config(description = "The delay in ticks for sending queued client commands for editing armor stands to the server. Increase this values if commands are sent too quickly and the server fails to process all of them.") @Config.IntRange(min = 20) public int clientCommandDelay = 20; diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index bc152dc..7e4f965 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -24,7 +24,7 @@ public class ArmorStandInteractHandler { private static boolean presentServerside; public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { - if (!player.isSpectator() && target.getType() == EntityType.ARMOR_STAND) { + if (player.getAbilities().mayBuild && target.getType() == EntityType.ARMOR_STAND) { boolean clientsideOnly = level.isClientSide && !presentServerside; // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.get(); diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 4bcd9af..145ec94 100644 --- a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -3,6 +3,7 @@ import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Unit; import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; @@ -178,7 +179,7 @@ public boolean shouldContinueTicking() { } protected boolean isEditingAllowed() { - return this.isEditingAllowed(true); + return this.isEditingAllowed(!ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck); } protected final boolean isEditingAllowed(boolean testPermissionLevel) { @@ -186,7 +187,7 @@ protected final boolean isEditingAllowed(boolean testPermissionLevel) { this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); return false; } - return this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); + return this.player.getAbilities().mayBuild && this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); } protected Either testArmorStand(ArmorStand armorStand) { diff --git a/1.20/gradle.properties b/1.20/gradle.properties index 65c8675..f4ac86b 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=8.0.4 +modVersion=8.0.5 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 From 6768905b11259c361387f438a3715871d45e088f Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:11:31 +0100 Subject: [PATCH 20/31] 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 +- .gitignore | 2 - .idea/gradle.xml | 44 --- .idea/scopes/Fabric_sources.xml | 3 - .idea/scopes/Forge_sources.xml | 3 - {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 1.18/.idea/scopes/Fabric_sources.xml | 3 - 1.18/.idea/scopes/Forge_sources.xml | 3 - {1.19 => 1.19.2}/CHANGELOG.md | 0 {1.19 => 1.19.2}/Common/build.gradle | 0 .../java/fuzs/armorstatues/ArmorStatues.java | 0 .../fuzs/armorstatues/api/StatuesApi.java | 0 .../api/client/StatuesApiClient.java | 0 .../gui/components/BoxedSliderButton.java | 0 .../gui/components/LiveSliderButton.java | 0 .../gui/components/NewTextureButton.java | 0 .../components/NewTextureSliderButton.java | 0 .../gui/components/NewTextureTickButton.java | 0 .../client/gui/components/TickBoxButton.java | 0 .../api/client/gui/components/TickButton.java | 0 .../client/gui/components/TickingButton.java | 0 .../gui/components/UnboundedSliderButton.java | 0 .../gui/components/VerticalSliderButton.java | 0 .../armorstand/AbstractArmorStandScreen.java | 0 .../armorstand/ArmorStandButtonsScreen.java | 0 .../armorstand/ArmorStandEquipmentScreen.java | 0 .../ArmorStandInInventoryRenderer.java | 0 .../armorstand/ArmorStandPosesScreen.java | 0 .../armorstand/ArmorStandPositionScreen.java | 0 .../armorstand/ArmorStandRotationsScreen.java | 0 .../screens/armorstand/ArmorStandScreen.java | 0 .../armorstand/ArmorStandScreenFactory.java | 0 .../armorstand/ArmorStandStyleScreen.java | 0 .../armorstand/ArmorStandTickBoxScreen.java | 0 .../armorstand/ArmorStandWidgetsScreen.java | 0 .../api/helper/ArmorStandInteractHelper.java | 0 .../client/C2SArmorStandNameMessage.java | 0 .../client/C2SArmorStandPoseMessage.java | 0 .../client/C2SArmorStandPositionMessage.java | 0 .../client/C2SArmorStandRotationMessage.java | 0 .../client/C2SArmorStandStyleMessage.java | 0 .../network/client/data/DataSyncHandler.java | 0 .../client/data/NetworkDataSyncHandler.java | 0 .../armorstatues/api/proxy/ClientProxy.java | 0 .../fuzs/armorstatues/api/proxy/Proxy.java | 0 .../armorstatues/api/proxy/ServerProxy.java | 0 .../decoration/ArmorStandDataProvider.java | 0 .../api/world/inventory/ArmorStandHolder.java | 0 .../api/world/inventory/ArmorStandMenu.java | 0 .../inventory/data/ArmorStandAlignment.java | 0 .../world/inventory/data/ArmorStandPose.java | 0 .../inventory/data/ArmorStandScreenType.java | 0 .../inventory/data/ArmorStandStyleOption.java | 0 .../data/ArmorStandStyleOptions.java | 0 .../world/inventory/data/PosePartMutator.java | 0 .../client/ArmorStatuesClient.java | 0 .../ArmorStandAlignmentsScreen.java | 0 .../ArmorStandVanillaTweaksScreen.java | 0 .../handler/ArmorStandTooltipHandler.java | 0 .../client/handler/DataSyncTickHandler.java | 0 .../armorstatues/config/ClientConfig.java | 0 .../armorstatues/core/CommonAbstractions.java | 0 .../fuzs/armorstatues/core/ModServices.java | 0 .../handler/ArmorStandInteractHandler.java | 0 .../fuzs/armorstatues/init/ModRegistry.java | 0 .../mixin/accessor/ArmorStandAccessor.java | 0 .../accessor/SimpleContainerAccessor.java | 0 .../armorstatues/network/S2CPingMessage.java | 0 .../client/data/CommandDataSyncHandler.java | 0 .../data/VanillaTweaksDataSyncHandler.java | 0 .../fuzs/armorstatues/proxy/ClientProxy.java | 0 .../java/fuzs/armorstatues/proxy/Proxy.java | 0 .../fuzs/armorstatues/proxy/ServerProxy.java | 0 .../resources/armorstatues.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/armorstatues/ArmorStatuesFabric.java | 0 .../client/ArmorStatuesFabricClient.java | 0 .../armorstatues/core/FabricAbstractions.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../fuzs.armorstatues.core.CommonAbstractions | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.19 => 1.19.2}/Forge/build.gradle | 0 .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 0 .../resources/assets/statues/lang/en_us.json | 0 .../fuzs/armorstatues/ArmorStatuesForge.java | 0 .../client/ArmorStatuesForgeClient.java | 0 .../armorstatues/core/ForgeAbstractions.java | 0 .../data/ModLanguageProvider.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 .../fuzs.armorstatues.core.CommonAbstractions | 0 .../gui/container/statue/background.png | Bin .../gui/container/statue/equipment.png | Bin .../textures/gui/container/statue/widgets.png | Bin .../textures/item/empty_armor_slot_sword.png | Bin {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 1.19/.idea/scopes/Fabric_sources.xml | 3 - 1.19/.idea/scopes/Forge_sources.xml | 3 - {1.20 => 1.20.1}/CHANGELOG.md | 0 {1.20 => 1.20.1}/Common/build.gradle | 0 .../java/fuzs/armorstatues/ArmorStatues.java | 0 .../client/ArmorStatuesClient.java | 0 .../ArmorStandAlignmentsScreen.java | 0 .../ArmorStandVanillaTweaksScreen.java | 0 .../handler/ArmorStandTooltipHandler.java | 0 .../client/handler/DataSyncTickHandler.java | 0 .../armorstatues/config/ClientConfig.java | 0 .../handler/ArmorStandInteractHandler.java | 0 .../fuzs/armorstatues/init/ModRegistry.java | 0 .../armorstatues/network/S2CPingMessage.java | 0 .../client/data/CommandDataSyncHandler.java | 0 .../data/VanillaTweaksDataSyncHandler.java | 0 .../fuzs/armorstatues/proxy/ClientProxy.java | 0 .../java/fuzs/armorstatues/proxy/Proxy.java | 0 .../fuzs/armorstatues/proxy/ServerProxy.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 {1.20 => 1.20.1}/Fabric/build.gradle | 0 .../fuzs/armorstatues/ArmorStatuesFabric.java | 0 .../client/ArmorStatuesFabricClient.java | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.20 => 1.20.1}/Forge/build.gradle | 0 .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 0 .../assets/armorstatues/lang/en_us.json | 0 .../fuzs/armorstatues/ArmorStatuesForge.java | 0 .../client/ArmorStatuesForgeClient.java | 0 .../data/ModLanguageProvider.java | 0 .../src/main/resources/META-INF/mods.toml | 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 | 33 ++ 1.20.4/Common/build.gradle | 16 + .../java/fuzs/armorstatues/ArmorStatues.java | 41 ++ .../client/ArmorStatuesClient.java | 45 +++ .../ArmorStandAlignmentsScreen.java | 54 +++ .../ArmorStandVanillaTweaksScreen.java | 75 ++++ .../handler/ArmorStandTooltipHandler.java | 25 ++ .../client/handler/DataSyncTickHandler.java | 28 ++ .../armorstatues/config/ClientConfig.java | 15 + .../handler/ArmorStandInteractHandler.java | 55 +++ .../fuzs/armorstatues/init/ModRegistry.java | 32 ++ .../armorstatues/network/S2CPingMessage.java | 30 ++ .../client/data/CommandDataSyncHandler.java | 226 +++++++++++ .../data/VanillaTweaksDataSyncHandler.java | 359 ++++++++++++++++++ .../fuzs/armorstatues/proxy/ClientProxy.java | 46 +++ .../java/fuzs/armorstatues/proxy/Proxy.java | 11 + .../fuzs/armorstatues/proxy/ServerProxy.java | 12 + .../Common/src/main/resources/mod_banner.png | Bin 0 -> 15383 bytes 1.20.4/Common/src/main/resources/mod_logo.png | Bin 0 -> 9380 bytes 1.20.4/Common/src/main/resources/pack.mcmeta | 8 + 1.20.4/Fabric/build.gradle | 34 ++ .../fuzs/armorstatues/ArmorStatuesFabric.java | 12 + .../client/ArmorStatuesFabricClient.java | 13 + .../Fabric/src/main/resources/fabric.mod.json | 44 +++ 1.20.4/Forge/build.gradle | 38 ++ .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 + .../assets/armorstatues/lang/en_us.json | 23 ++ .../fuzs/armorstatues/ArmorStatuesForge.java | 23 ++ .../client/ArmorStatuesForgeClient.java | 51 +++ .../data/ModLanguageProvider.java | 40 ++ .../src/main/resources/META-INF/mods.toml | 47 +++ 1.20.4/NeoForge/build.gradle | 38 ++ .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 + .../assets/armorstatues/lang/en_us.json | 23 ++ .../fuzs/armorstatues/ArmorStatuesForge.java | 23 ++ .../client/ArmorStatuesForgeClient.java | 51 +++ .../data/ModLanguageProvider.java | 40 ++ .../src/main/resources/META-INF/mods.toml | 47 +++ 1.20.4/build.gradle | 12 + 1.20.4/gradle.properties | 38 ++ 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 | 23 ++ 1.20/.idea/scopes/Fabric_sources.xml | 3 - 1.20/.idea/scopes/Forge_sources.xml | 3 - LICENSE-ASSETS.md | 2 +- 222 files changed, 2173 insertions(+), 106 deletions(-) delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/scopes/Fabric_sources.xml delete mode 100644 .idea/scopes/Forge_sources.xml 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%) delete mode 100644 1.18/.idea/scopes/Fabric_sources.xml delete mode 100644 1.18/.idea/scopes/Forge_sources.xml 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/armorstatues/ArmorStatues.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/core/ModServices.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/armorstatues.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/armorstatues/ArmorStatuesFabric.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions (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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 (100%) rename {1.19 => 1.19.2}/Forge/src/generated/resources/assets/statues/lang/en_us.json (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/armorstatues/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/META-INF/services/fuzs.armorstatues.core.CommonAbstractions (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png (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%) delete mode 100644 1.19/.idea/scopes/Fabric_sources.xml delete mode 100644 1.19/.idea/scopes/Forge_sources.xml 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/armorstatues/ArmorStatues.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.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}/Fabric/build.gradle (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.20 => 1.20.1}/Forge/build.gradle (100%) rename {1.20 => 1.20.1}/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 (100%) rename {1.20 => 1.20.1}/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/resources/META-INF/mods.toml (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/armorstatues/ArmorStatues.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.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/Fabric/build.gradle create mode 100644 1.20.4/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java create mode 100644 1.20.4/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 create mode 100644 1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json create mode 100644 1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 create mode 100644 1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.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..a8afb2c 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: Minimal Setup (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..c91c5ae 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: Minimal Setup + 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/.gitignore b/.gitignore index 223cbb5..0360158 100644 --- a/.gitignore +++ b/.gitignore @@ -33,8 +33,6 @@ classes *.iws *.iml **/.idea/* -!**/.idea/scopes -!.idea/gradle.xml ### NetBeans ### nbproject/private/ 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/.idea/scopes/Fabric_sources.xml deleted file mode 100644 index 0448412..0000000 --- a/.idea/scopes/Fabric_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/scopes/Forge_sources.xml b/.idea/scopes/Forge_sources.xml deleted file mode 100644 index 7b5f24d..0000000 --- a/.idea/scopes/Forge_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file 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.18/.idea/scopes/Fabric_sources.xml deleted file mode 100644 index 0448412..0000000 --- a/1.18/.idea/scopes/Fabric_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/1.18/.idea/scopes/Forge_sources.xml b/1.18/.idea/scopes/Forge_sources.xml deleted file mode 100644 index 7b5f24d..0000000 --- a/1.18/.idea/scopes/Forge_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file 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/armorstatues/ArmorStatues.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/StatuesApi.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/StatuesApiClient.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/BoxedSliderButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/LiveSliderButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureSliderButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/NewTextureTickButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickBoxButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/TickingButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/UnboundedSliderButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/components/VerticalSliderButton.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/AbstractArmorStandScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandButtonsScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandEquipmentScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandInInventoryRenderer.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPosesScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandPositionScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandRotationsScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandScreenFactory.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandStyleScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandTickBoxScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/client/gui/screens/armorstand/ArmorStandWidgetsScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/helper/ArmorStandInteractHelper.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandNameMessage.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPoseMessage.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandPositionMessage.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandRotationMessage.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/C2SArmorStandStyleMessage.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/data/DataSyncHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/network/client/data/NetworkDataSyncHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/proxy/ClientProxy.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/proxy/Proxy.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/proxy/ServerProxy.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/entity/decoration/ArmorStandDataProvider.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandHolder.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/ArmorStandMenu.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandAlignment.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandPose.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandScreenType.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOption.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/ArmorStandStyleOptions.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/api/world/inventory/data/PosePartMutator.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/core/CommonAbstractions.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/core/ModServices.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/core/ModServices.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/core/ModServices.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/core/ModServices.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/mixin/accessor/ArmorStandAccessor.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/mixin/accessor/SimpleContainerAccessor.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java diff --git a/1.19/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.19.2/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java rename to 1.19.2/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java diff --git a/1.19/Common/src/main/resources/armorstatues.common.mixins.json b/1.19.2/Common/src/main/resources/armorstatues.common.mixins.json similarity index 100% rename from 1.19/Common/src/main/resources/armorstatues.common.mixins.json rename to 1.19.2/Common/src/main/resources/armorstatues.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/armorstatues/ArmorStatuesFabric.java b/1.19.2/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java rename to 1.19.2/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java diff --git a/1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/1.19.2/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java rename to 1.19.2/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java diff --git a/1.19/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java b/1.19.2/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java rename to 1.19.2/Fabric/src/main/java/fuzs/armorstatues/core/FabricAbstractions.java diff --git a/1.19/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java b/1.19.2/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java rename to 1.19.2/Fabric/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java diff --git a/1.19/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions b/1.19.2/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions similarity index 100% rename from 1.19/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions rename to 1.19.2/Fabric/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions 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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.19.2/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 similarity index 100% rename from 1.19/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 rename to 1.19.2/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 diff --git a/1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json b/1.19.2/Forge/src/generated/resources/assets/statues/lang/en_us.json similarity index 100% rename from 1.19/Forge/src/generated/resources/assets/statues/lang/en_us.json rename to 1.19.2/Forge/src/generated/resources/assets/statues/lang/en_us.json diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.19.2/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java rename to 1.19.2/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.19.2/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java rename to 1.19.2/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java b/1.19.2/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java rename to 1.19.2/Forge/src/main/java/fuzs/armorstatues/core/ForgeAbstractions.java diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.19.2/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java rename to 1.19.2/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java diff --git a/1.19/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java b/1.19.2/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/armorstatues/mixin/ModMixinConfigPlugin.java rename to 1.19.2/Forge/src/main/java/fuzs/armorstatues/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/META-INF/services/fuzs.armorstatues.core.CommonAbstractions b/1.19.2/Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions similarity index 100% rename from 1.19/Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions rename to 1.19.2/Forge/src/main/resources/META-INF/services/fuzs.armorstatues.core.CommonAbstractions diff --git a/1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png b/1.19.2/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png similarity index 100% rename from 1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png rename to 1.19.2/Forge/src/main/resources/assets/statues/textures/gui/container/statue/background.png diff --git a/1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png b/1.19.2/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png similarity index 100% rename from 1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png rename to 1.19.2/Forge/src/main/resources/assets/statues/textures/gui/container/statue/equipment.png diff --git a/1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png b/1.19.2/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png similarity index 100% rename from 1.19/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png rename to 1.19.2/Forge/src/main/resources/assets/statues/textures/gui/container/statue/widgets.png diff --git a/1.19/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png b/1.19.2/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png similarity index 100% rename from 1.19/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png rename to 1.19.2/Forge/src/main/resources/assets/statues/textures/item/empty_armor_slot_sword.png 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.19/.idea/scopes/Fabric_sources.xml deleted file mode 100644 index 0448412..0000000 --- a/1.19/.idea/scopes/Fabric_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/1.19/.idea/scopes/Forge_sources.xml b/1.19/.idea/scopes/Forge_sources.xml deleted file mode 100644 index 7b5f24d..0000000 --- a/1.19/.idea/scopes/Forge_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file 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/armorstatues/ArmorStatues.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java diff --git a/1.20/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java rename to 1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.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/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/armorstatues/ArmorStatuesFabric.java b/1.20.1/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java rename to 1.20.1/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java diff --git a/1.20/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/1.20.1/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java rename to 1.20.1/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java 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/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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20.1/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 similarity index 100% rename from 1.20/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 rename to 1.20.1/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 diff --git a/1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20.1/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json similarity index 100% rename from 1.20/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json rename to 1.20.1/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.20.1/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java rename to 1.20.1/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.20.1/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java rename to 1.20.1/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java diff --git a/1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20.1/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java rename to 1.20.1/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.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/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..dc05013 --- /dev/null +++ b/1.20.4/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog]. + +## [v8.0.5-1.20.1] - 2023-12-03 +### Changed +- Client side permissions check can now be disabled in the config +### Fixed +- Armor stand menu can no longer open in adventure mode + +## [v8.0.4-1.20.1] - 2023-12-03 +### Changed +- Updated to Puzzles Api v8.1.4 + +## [v8.0.3-1.20.1] - 2023-08-16 +### Fixed +- Fixed a crash trying to interact with an armor stand when playing on a Forge server that does not have Armor Statues installed (Forge only) + +## [v8.0.2-1.20.1] - 2023-07-29 +### Fixed +- Fixed an issue with always receiving an incorrect error message when trying to edit an armor stand on a server with the Vanilla Tweaks data pack installed + +## [v8.0.1-1.20.1] - 2023-07-28 +### Added +- Added a new tab that only shows when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack offering Vanilla Tweaks exclusive toggles +### Changed +- Optimized some actions during editing to be performed much quicker when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack + +## [v8.0.0-1.20.1] - 2023-07-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..2434c15 --- /dev/null +++ b/1.20.4/Common/build.gradle @@ -0,0 +1,16 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common + + // Puzzles Api + api(libs.puzzlesapi.common) { + exclude group: "fuzs.puzzleslib" + } +} + +// @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/armorstatues/ArmorStatues.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java new file mode 100644 index 0000000..041fd20 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -0,0 +1,41 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.S2CPingMessage; +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerEvents; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import fuzs.puzzleslib.api.network.v2.MessageDirection; +import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArmorStatues implements ModConstructor { + public static final String MOD_ID = "armorstatues"; + public static final String MOD_NAME = "Armor Statues"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID, true, true); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class); + + @Override + public void onConstructMod() { + ModRegistry.touch(); + registerMessages(); + registerHandlers(); + } + + private static void registerMessages() { + NETWORK.register(S2CPingMessage.class, S2CPingMessage::new, MessageDirection.TO_CLIENT); + } + + private static void registerHandlers() { + // high priority so we run before the Quark mod + PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); + PlayerEvents.LOGGED_IN.register(ArmorStandInteractHandler::onLoggedIn); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java new file mode 100644 index 0000000..42de006 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -0,0 +1,45 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; +import fuzs.armorstatues.client.handler.DataSyncTickHandler; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreenFactory; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandMenu; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.event.v1.ClientPlayerEvents; +import fuzs.puzzleslib.api.client.event.v1.ClientTickEvents; +import fuzs.puzzleslib.api.client.event.v1.ItemTooltipCallback; +import fuzs.puzzleslib.api.client.event.v1.ScreenEvents; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +public class ArmorStatuesClient implements ClientModConstructor { + + @Override + public void onConstructMod() { + registerHandlers(); + } + + private static void registerHandlers() { + ItemTooltipCallback.EVENT.register(ArmorStandTooltipHandler::onItemTooltip); + ClientTickEvents.END.register(DataSyncTickHandler::onEndClientTick); + ScreenEvents.remove(Screen.class).register(DataSyncTickHandler::onRemove); + ClientPlayerEvents.LOGGED_IN.register(ArmorStandInteractHandler::onLoggedIn); + } + + @SuppressWarnings("Convert2MethodRef") + @Override + public void onClientSetup() { + // compiler doesn't like method reference :( + MenuScreens.register(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), (ArmorStandMenu menu, Inventory inventory, Component component) -> { + return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); + }); + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java new file mode 100644 index 0000000..da972b8 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -0,0 +1,54 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandButtonsScreen; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandPositionScreen; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.phys.Vec3; + +import java.util.EnumSet; +import java.util.List; + +public class ArmorStandAlignmentsScreen extends ArmorStandButtonsScreen { + + public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new DoubleButtonWidget(Component.translatable(ArmorStandPositionScreen.CENTERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + })); + for (ArmorStandAlignment alignment : ArmorStandAlignment.values()) { + widgets.add(new SingleButtonWidget(Component.translatable(alignment.getTranslationKey()), Component.translatable(alignment.getDescriptionsKey()), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendAlignment(alignment); + })); + } + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.ALIGNMENTS_SCREEN_TYPE; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java new file mode 100644 index 0000000..ed09c7d --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java @@ -0,0 +1,75 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandButtonsScreen; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; + +import java.util.List; + +public class ArmorStandVanillaTweaksScreen extends ArmorStandButtonsScreen { + public static final String TRIGGER_SENT_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.triggerSent"; + public static final String CHECK_TARGET_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget"; + public static final String CHECK_TARGET_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget.description"; + public static final String LOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock"; + public static final String LOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock.description"; + public static final String UNLOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock"; + public static final String UNLOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock.description"; + public static final String TOOL_RACK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack"; + public static final String TOOL_RACK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack.description"; + public static final String SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand"; + public static final String SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand.description"; + public static final String SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead"; + public static final String SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead.description"; + + public ArmorStandVanillaTweaksScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + public VanillaTweaksDataSyncHandler getDataSyncHandler() { + return (VanillaTweaksDataSyncHandler) super.getDataSyncHandler(); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new SingleButtonWidget(Component.translatable(CHECK_TARGET_TRANSLATION_KEY), Component.translatable(CHECK_TARGET_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.CHECK_TARGET); + this.onClose(); + })); + widgets.add(new DoubleButtonWidget(Component.translatable(LOCK_TRANSLATION_KEY), Component.translatable(UNLOCK_TRANSLATION_KEY), Component.translatable(LOCK_DESCRIPTION_KEY), Component.translatable(UNLOCK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_LOCK); + }, button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_UNLOCK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(TOOL_RACK_TRANSLATION_KEY), Component.translatable(TOOL_RACK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.AUTO_ALIGNMENT_TOOL_RACK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_OFFHAND); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_HEAD); + })); + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java new file mode 100644 index 0000000..929250d --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -0,0 +1,25 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.puzzlesapi.api.statues.v1.helper.ArmorStandInteractHelper; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ArmorStandTooltipHandler { + + public static void onItemTooltip(ItemStack stack, @Nullable Player player, List lines, TooltipFlag context) { + if (stack.is(Items.ARMOR_STAND)) { + Component component = ArmorStandInteractHelper.getArmorStandHoverText(); + if (context.isAdvanced()) { + lines.add(lines.size() - (stack.hasTag() ? 2 : 1), component); + } else { + lines.add(component); + } + } + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java new file mode 100644 index 0000000..91ccdad --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -0,0 +1,28 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreen; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +public class DataSyncTickHandler { + @Nullable + private static DataSyncHandler dataSyncHandler; + + public static void onRemove(Screen screen) { + if (screen instanceof ArmorStandScreen armorStandScreen && armorStandScreen.getDataSyncHandler().shouldContinueTicking()) { + dataSyncHandler = armorStandScreen.getDataSyncHandler(); + } + } + + public static void onEndClientTick(Minecraft minecraft) { + if (minecraft.player != null && !(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (dataSyncHandler.shouldContinueTicking()) { + dataSyncHandler.tick(); + } else { + dataSyncHandler = null; + } + } + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java new file mode 100644 index 0000000..6e2a684 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -0,0 +1,15 @@ +package fuzs.armorstatues.config; + +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.AbstractArmorStandScreen; +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; + +public class ClientConfig implements ConfigCore { + @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) + public boolean useVanillaTweaksTriggers = false; + @Config(description = "Do not check if the client has the necessary permission level for executing the '/data' command when trying to edit an armor stand. Useful when the current server is using custom permissions handling.") + public boolean overrideClientPermissionsCheck = false; + @Config(description = "The delay in ticks for sending queued client commands for editing armor stands to the server. Increase this values if commands are sent too quickly and the server fails to process all of them.") + @Config.IntRange(min = 20) + public int clientCommandDelay = 20; +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java new file mode 100644 index 0000000..7e4f965 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -0,0 +1,55 @@ +package fuzs.armorstatues.handler; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.S2CPingMessage; +import fuzs.armorstatues.proxy.Proxy; +import fuzs.puzzlesapi.api.statues.v1.helper.ArmorStandInteractHelper; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.Connection; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class ArmorStandInteractHandler { + private static boolean presentServerside; + + public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { + if (player.getAbilities().mayBuild && target.getType() == EntityType.ARMOR_STAND) { + boolean clientsideOnly = level.isClientSide && !presentServerside; + // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients + MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.get(); + EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, menuType, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + if (result.isInterrupt() && clientsideOnly) { + Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); + // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen + // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here + player.swing(interactionHand); + return EventResultHolder.interrupt(InteractionResult.FAIL); + } + return result; + } + return EventResultHolder.pass(); + } + + public static void onLoggedIn(ServerPlayer player) { + ArmorStatues.NETWORK.sendTo(new S2CPingMessage(), player); + } + + public static void onLoggedIn(LocalPlayer player, MultiPlayerGameMode multiPlayerGameMode, Connection connection) { + presentServerside = false; + } + + public static void setPresentServerside() { + presentServerside = true; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java new file mode 100644 index 0000000..cd5e925 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -0,0 +1,32 @@ +package fuzs.armorstatues.init; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzlesapi.api.statues.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandMenu; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.puzzleslib.api.init.v2.RegistryManager; +import fuzs.puzzleslib.api.init.v2.RegistryReference; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.instant(ArmorStatues.MOD_ID); + public static final RegistryReference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuType("armor_stand", () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + }); + + public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); + public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", new ItemStack(Items.WRITTEN_BOOK)); + public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandScreenType.EQUIPMENT}; + } + }; + + public static void touch() { + + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java new file mode 100644 index 0000000..f2d0bbe --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java @@ -0,0 +1,30 @@ +package fuzs.armorstatues.network; + +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.network.v2.MessageV2; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; + +public class S2CPingMessage implements MessageV2 { + + @Override + public void write(FriendlyByteBuf buf) { + + } + + @Override + public void read(FriendlyByteBuf buf) { + + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CPingMessage message, Player player, Object gameInstance) { + ArmorStandInteractHandler.setPresentServerside(); + } + }; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java new file mode 100644 index 0000000..145ec94 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -0,0 +1,226 @@ +package fuzs.armorstatues.network.client.data; + +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandPose; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOption; +import net.minecraft.ChatFormatting; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.function.BiPredicate; + +public class CommandDataSyncHandler implements DataSyncHandler { + public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; + public static final String OUT_OF_RANGE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.outOfRange"; + public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; + private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); + + @Nullable + private static ArmorStand queueArmorStand; + private static int itemDequeuedTicks; + + private final ArmorStandHolder holder; + protected final LocalPlayer player; + protected ArmorStandPose lastSyncedPose; + + public CommandDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + this.holder = holder; + this.lastSyncedPose = ArmorStandPose.fromEntity(this.holder.getArmorStand()); + this.player = player; + } + + @Override + public ArmorStandHolder getArmorStandHolder() { + return this.holder; + } + + @Override + public void sendName(String name) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); + CompoundTag tag = new CompoundTag(); + tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); + this.enqueueEntityData(tag); + this.finalizeCurrentOperation(); + } + + @Override + public final void sendPose(ArmorStandPose pose) { + this.sendPose(pose, true); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.isEditingAllowed()) return; + // split this into multiple chat messages as the client chat field has a very low character limit + this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + if (finalize) this.finalizeCurrentOperation(); + } + + private void sendPosePart(BiPredicate dataWriter, ArmorStandPose lastSyncedPose) { + CompoundTag tag = new CompoundTag(); + if (dataWriter.test(tag, lastSyncedPose)) { + CompoundTag tagToSend = new CompoundTag(); + tagToSend.put("Pose", tag); + this.enqueueEntityData(tagToSend); + } + } + + @Override + public @Nullable ArmorStandPose getLastSyncedPose() { + return this.lastSyncedPose; + } + + @Override + public final void sendPosition(double posX, double posY, double posZ) { + this.sendPosition(posX, posY, posZ, true); + + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; + ListTag listTag = new ListTag(); + listTag.add(DoubleTag.valueOf(posX)); + listTag.add(DoubleTag.valueOf(posY)); + listTag.add(DoubleTag.valueOf(posZ)); + CompoundTag tag = new CompoundTag(); + tag.put("Pos", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendRotation(float rotation) { + this.sendRotation(rotation, true); + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; + ListTag listTag = new ListTag(); + listTag.add(FloatTag.valueOf(rotation)); + CompoundTag tag = new CompoundTag(); + tag.put("Rotation", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + this.sendStyleOption(styleOption, value, true); + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; + CompoundTag tag = new CompoundTag(); + styleOption.toTag(tag, value); + this.enqueueEntityData(tag); + styleOption.setOption(this.getArmorStand(), value); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.super.sendAlignment(alignment); + } + + @Override + public boolean supportsScreenType(ArmorStandScreenType screenType) { + return !screenType.requiresServer(); + } + + @Override + public void tick() { + if (itemDequeuedTicks > 0) itemDequeuedTicks--; + if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { + if (this.testArmorStand(queueArmorStand).right().isPresent()) { + this.player.connection.sendCommand(CLIENT_COMMAND_QUEUE.poll()); + } else { + CLIENT_COMMAND_QUEUE.clear(); + } + itemDequeuedTicks = this.getDequeueDelayTicks(); + } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { + this.sendDisplayMessage(Component.translatable(FINISHED_TRANSLATION_KEY), false); + } + } + + protected int getDequeueDelayTicks() { + return 5; + } + + @Override + public boolean shouldContinueTicking() { + return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; + } + + protected boolean isEditingAllowed() { + return this.isEditingAllowed(!ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck); + } + + protected final boolean isEditingAllowed(boolean testPermissionLevel) { + if (testPermissionLevel && !this.player.hasPermissions(2)) { + this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); + return false; + } + return this.player.getAbilities().mayBuild && this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); + } + + protected Either testArmorStand(ArmorStand armorStand) { + return !armorStand.isAlive() ? Either.left(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)) : Either.right(Unit.INSTANCE); + } + + protected boolean enqueueClientCommand(String clientCommand) { + if (CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = null; + } else if (queueArmorStand != null) { + this.sendFailureMessage(Component.translatable(NOT_FINISHED_TRANSLATION_KEY)); + return false; + } + CLIENT_COMMAND_QUEUE.offer(clientCommand); + return true; + } + + @Override + public void finalizeCurrentOperation() { + if (!CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = this.getArmorStand(); + } + } + + protected void sendFailureMessage(Component component) { + this.sendDisplayMessage(Component.translatable(FAILURE_TRANSLATION_KEY, component), true); + } + + protected void sendDisplayMessage(Component component, boolean failure) { + this.player.displayClientMessage(Component.empty().append(component).withStyle(failure ? ChatFormatting.RED : ChatFormatting.GREEN), false); + } + + private void enqueueEntityData(CompoundTag tag) { + this.enqueueClientCommand("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString())); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java new file mode 100644 index 0000000..e573f08 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -0,0 +1,359 @@ +package fuzs.armorstatues.network.client.data; + +import com.google.common.collect.ImmutableSortedMap; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.*; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.Rotations; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.NavigableMap; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { + private static final int MAX_INCREMENTAL_OPERATIONS = 12; + public static final int CHECK_TARGET = 999; + public static final int SWAP_SLOTS_MAINHAND_AND_OFFHAND = 161; + public static final int SWAP_SLOTS_MAINHAND_AND_HEAD = 162; + public static final int MIRROR_ARMS_LEFT_TO_RIGHT = 131; + public static final int MIRROR_ARMS_RIGHT_TO_LEFT = 132; + public static final int MIRROR_LEGS_LEFT_TO_RIGHT = 133; + public static final int MIRROR_LEGS_RIGHT_TO_LEFT = 134; + public static final int UTILITIES_LOCK = 1000; + public static final int UTILITIES_UNLOCK = 1001; + public static final int MIRROR_AND_FLIP_FLIP = 135; + public static final int SHOW_BASE_PLATE_YES = 1; + public static final int SHOW_BASE_PLATE_NO = 2; + public static final int SHOW_ARMS_YES = 3; + public static final int SHOW_ARMS_NO = 4; + public static final int SMALL_STAND_YES = 5; + public static final int SMALL_STAND_NO = 6; + public static final int APPLY_GRAVITY_YES = 7; + public static final int APPLY_GRAVITY_NO = 8; + public static final int STAND_VISIBLE_YES = 9; + public static final int STAND_VISIBLE_NO = 10; + public static final int DISPLAY_NAME_YES = 11; + public static final int DISPLAY_NAME_NO = 12; + public static final int NUDGE_POSITION_X8_NEGATIVE = 40; + public static final int NUDGE_POSITION_X3_NEGATIVE = 101; + public static final int NUDGE_POSITION_X1_NEGATIVE = 102; + public static final int NUDGE_POSITION_X1_POSITIVE = 103; + public static final int NUDGE_POSITION_X3_POSITIVE = 104; + public static final int NUDGE_POSITION_X8_POSITIVE = 43; + public static final int NUDGE_POSITION_Y8_NEGATIVE = 44; + public static final int NUDGE_POSITION_Y3_NEGATIVE = 105; + public static final int NUDGE_POSITION_Y1_NEGATIVE = 106; + public static final int NUDGE_POSITION_Y1_POSITIVE = 107; + public static final int NUDGE_POSITION_Y3_POSITIVE = 108; + public static final int NUDGE_POSITION_Y8_POSITIVE = 47; + public static final int NUDGE_POSITION_Z8_NEGATIVE = 48; + public static final int NUDGE_POSITION_Z3_NEGATIVE = 109; + public static final int NUDGE_POSITION_Z1_NEGATIVE = 110; + public static final int NUDGE_POSITION_Z1_POSITIVE = 111; + public static final int NUDGE_POSITION_Z3_POSITIVE = 112; + public static final int NUDGE_POSITION_Z8_POSITIVE = 51; + public static final int ADJUST_ROTATION_ANGLE_STEP_45 = 120; + public static final int ADJUST_ROTATION_ANGLE_STEP_15 = 121; + public static final int ADJUST_ROTATION_ANGLE_STEP_5 = 122; + public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; + public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; + public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + public static final int POSE_PRESETS_ATTENTION = 20; + public static final int POSE_PRESETS_WALKING = 21; + public static final int POSE_PRESETS_RUNNING = 22; + public static final int POSE_PRESETS_POINTING = 23; + public static final int POSE_PRESETS_BLOCKING = 24; + public static final int POSE_PRESETS_LUNGEING = 25; + public static final int POSE_PRESETS_WINNING = 26; + public static final int POSE_PRESETS_SITTING = 27; + public static final int POSE_PRESETS_ARABESQUE = 28; + public static final int POSE_PRESETS_CUPID = 29; + public static final int POSE_PRESETS_CONFIDENT = 30; + public static final int POSE_PRESETS_SALUTE = 31; + public static final int POSE_PRESETS_DEATH = 32; + public static final int POSE_PRESETS_FACEPALM = 33; + public static final int POSE_PRESETS_LAZING = 34; + public static final int POSE_PRESETS_CONFUSED = 35; + public static final int POSE_PRESETS_FORMAL = 36; + public static final int POSE_PRESETS_SAD = 37; + public static final int POSE_PRESETS_JOYOUS = 38; + public static final int POSE_PRESETS_STARGAZING = 39; + public static final int AUTO_ALIGNMENT_BLOCK_ON_SURFACE = 151; + public static final int AUTO_ALIGNMENT_ITEM_ON_SURFACE = 152; + public static final int AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE = 153; + public static final int AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE = 154; + public static final int AUTO_ALIGNMENT_TOOL_RACK = 155; + public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; + public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; + public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; + public static final int POSE_ADJUSTMENT_HEAD_Y_POSITIVE = 63; + public static final int POSE_ADJUSTMENT_HEAD_Z_NEGATIVE = 64; + public static final int POSE_ADJUSTMENT_HEAD_Z_POSITIVE = 65; + public static final int POSE_ADJUSTMENT_BODY_X_NEGATIVE = 67; + public static final int POSE_ADJUSTMENT_BODY_X_POSITIVE = 66; + public static final int POSE_ADJUSTMENT_BODY_Y_NEGATIVE = 68; + public static final int POSE_ADJUSTMENT_BODY_Y_POSITIVE = 69; + public static final int POSE_ADJUSTMENT_BODY_Z_NEGATIVE = 70; + public static final int POSE_ADJUSTMENT_BODY_Z_POSITIVE = 71; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE = 72; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE = 73; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE = 74; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE = 75; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE = 77; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE = 76; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE = 78; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE = 79; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE = 81; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE = 80; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE = 82; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE = 83; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE = 84; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE = 85; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE = 87; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE = 86; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE = 89; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE = 88; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE = 90; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE = 91; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE = 92; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE = 93; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; + private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_LEG = new int[]{POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE}; + private static final NavigableMap NUDGE_POSITIONS_X_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_X3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_X8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_X_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_X3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_X8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_POSITIVE); + private static final NavigableMap ADJUST_ROTATION_ANGLE_STEPS = ImmutableSortedMap.of(1.0F, ADJUST_ROTATION_ANGLE_STEP_1, 5.0F, ADJUST_ROTATION_ANGLE_STEP_5, 15.0F, ADJUST_ROTATION_ANGLE_STEP_15, 45.0F, ADJUST_ROTATION_ANGLE_STEP_45); + + public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + super(holder, player); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.isEditingAllowed()) return; + int triggerValue = this.getTriggerValueFromPose(pose); + if (triggerValue != -1) { + if (this.enqueueTriggerValue(triggerValue)) { + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); + } + } else { + this.tryApplyAllPoseParts(pose); + } + if (finalize) this.finalizeCurrentOperation(); + } + + private int getTriggerValueFromPose(ArmorStandPose pose) { + if (pose.getSourceType() == ArmorStandPose.SourceType.EMPTY) return POSE_PRESETS_ATTENTION; + if (pose.getSourceType() == ArmorStandPose.SourceType.MIRRORED) return MIRROR_AND_FLIP_FLIP; + if (pose.getSourceType() != ArmorStandPose.SourceType.VANILLA_TWEAKS) return -1; + if (pose == ArmorStandPose.WALKING) return POSE_PRESETS_WALKING; + if (pose == ArmorStandPose.RUNNING) return POSE_PRESETS_RUNNING; + if (pose == ArmorStandPose.POINTING) return POSE_PRESETS_POINTING; + if (pose == ArmorStandPose.BLOCKING) return POSE_PRESETS_BLOCKING; + if (pose == ArmorStandPose.LUNGEING) return POSE_PRESETS_LUNGEING; + if (pose == ArmorStandPose.WINNING) return POSE_PRESETS_WINNING; + if (pose == ArmorStandPose.SITTING) return POSE_PRESETS_SITTING; + if (pose == ArmorStandPose.ARABESQUE) return POSE_PRESETS_ARABESQUE; + if (pose == ArmorStandPose.CUPID) return POSE_PRESETS_CUPID; + if (pose == ArmorStandPose.CONFIDENT) return POSE_PRESETS_CONFIDENT; + if (pose == ArmorStandPose.SALUTE) return POSE_PRESETS_SALUTE; + if (pose == ArmorStandPose.DEATH) return POSE_PRESETS_DEATH; + if (pose == ArmorStandPose.FACEPALM) return POSE_PRESETS_FACEPALM; + if (pose == ArmorStandPose.LAZING) return POSE_PRESETS_LAZING; + if (pose == ArmorStandPose.CONFUSED) return POSE_PRESETS_CONFUSED; + if (pose == ArmorStandPose.FORMAL) return POSE_PRESETS_FORMAL; + if (pose == ArmorStandPose.SAD) return POSE_PRESETS_SAD; + if (pose == ArmorStandPose.JOYOUS) return POSE_PRESETS_JOYOUS; + if (pose == ArmorStandPose.STARGAZING) return POSE_PRESETS_STARGAZING; + return -1; + } + + private void tryApplyAllPoseParts(ArmorStandPose pose) { + if (!this.tryApplyPosePart(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD, this.lastSyncedPose::withHeadPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY, this.lastSyncedPose::withBodyPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM, this.lastSyncedPose::withRightArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM, this.lastSyncedPose::withLeftArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG, this.lastSyncedPose::withRightLegPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG, this.lastSyncedPose::withLeftLegPose)) + return; + } + + private boolean tryApplyPosePart(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment, Function function) { + if (this.tryApplyPoseAdjustment(oldPose, newPose, poseAdjustment)) { + this.lastSyncedPose = function.apply(newPose != null ? newPose : oldPose); + return true; + } else { + return false; + } + } + + private boolean tryApplyPoseAdjustment(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + if (newPose == null || oldPose.equals(newPose)) return true; + if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) return false; + return true; + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; + this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); + if (finalize) this.finalizeCurrentOperation(); + } + + private void applyPositionIncrements(double oldValue, double newValue, NavigableMap positiveNudgePositions, NavigableMap negativeNudgePositions) { + double value = newValue - oldValue; + double signum = Math.signum(value); + value = Math.abs(value); + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = (signum == -1.0F ? negativeNudgePositions : positiveNudgePositions).floorEntry(value); + if (entry != null) { + value -= entry.getKey(); + if (!this.enqueueTriggerValue(entry.getValue())) { + return; + } + } else { + break; + } + } + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; + this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean applyIncrementsFromSteps(float oldValue, float newValue, int triggerValueNegative, int triggerValuePositive) { + float value = newValue - oldValue; + float signum = Math.signum(value); + value = Math.abs(value); + float lastIncrement = 0.0F; + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = ADJUST_ROTATION_ANGLE_STEPS.floorEntry(value); + if (entry != null) { + float currentIncrement = entry.getKey(); + value -= currentIncrement; + if (currentIncrement != lastIncrement) { + lastIncrement = currentIncrement; + if (!this.enqueueTriggerValue(entry.getValue())) { + return false; + } + } + if (!this.enqueueTriggerValue(signum == -1.0F ? triggerValuePositive : triggerValueNegative)) { + return false; + } + } else { + break; + } + } + return true; + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; + int triggerValue; + if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { + triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; + } else if (styleOption == ArmorStandStyleOptions.SHOW_ARMS) { + triggerValue = value ? SHOW_ARMS_YES : SHOW_ARMS_NO; + } else if (styleOption == ArmorStandStyleOptions.SMALL) { + triggerValue = value ? SMALL_STAND_YES : SMALL_STAND_NO; + } else if (styleOption == ArmorStandStyleOptions.INVISIBLE) { + triggerValue = value ? STAND_VISIBLE_NO : STAND_VISIBLE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_BASE_PLATE) { + triggerValue = value ? SHOW_BASE_PLATE_NO : SHOW_BASE_PLATE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_GRAVITY) { + triggerValue = value ? APPLY_GRAVITY_NO : APPLY_GRAVITY_YES; + } else { + super.sendStyleOption(styleOption, value, finalize); + return; + } + if (this.sendSingleTriggerValue(triggerValue, finalize)) { + styleOption.setOption(this.getArmorStand(), value); + } + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + int triggerValue = switch (alignment) { + case BLOCK -> AUTO_ALIGNMENT_BLOCK_ON_SURFACE; + case FLOATING_ITEM -> AUTO_ALIGNMENT_ITEM_ON_SURFACE; + case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; + case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; + }; + this.sendSingleTriggerValue(triggerValue, true); + } + + public void sendSingleTriggerValue(int triggerValue) { + if (!this.isEditingAllowed()) return; + this.sendSingleTriggerValue(triggerValue, true); + } + + private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { + boolean result = this.enqueueTriggerValue(triggerValue); + if (finalize) this.finalizeCurrentOperation(); + return result; + } + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return Stream.concat(Stream.of(super.getScreenTypes()), Stream.of(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE)).toArray(ArmorStandScreenType[]::new); + } + + @Override + protected boolean isEditingAllowed() { + return this.isEditingAllowed(false); + } + + @Override + protected Either testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand).>map(Optional::of, $ -> { + if (this.player.distanceToSqr(armorStand) < 9.0) { + return Optional.empty(); + } else { + return Optional.of(Component.translatable(OUT_OF_RANGE_TRANSLATION_KEY)); + } + }).>map(Either::left).orElse(Either.right(Unit.INSTANCE)); + } + + @Override + protected int getDequeueDelayTicks() { + return ArmorStatues.CONFIG.get(ClientConfig.class).clientCommandDelay; + } + + private boolean enqueueTriggerValue(int triggerValue) { + return this.enqueueClientCommand("trigger as_trigger set %s".formatted(triggerValue)); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java new file mode 100644 index 0000000..38e9040 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -0,0 +1,46 @@ +package fuzs.armorstatues.proxy; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreenFactory; +import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.puzzlesapi.api.statues.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ClientProxy extends ServerProxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + ArmorStandHolder holder = new ArmorStandHolder() { + + @Override + public ArmorStand getArmorStand() { + return armorStand; + } + + @Override + public ArmorStandDataProvider getDataProvider() { + return ModRegistry.ARMOR_STAND_DATA_PROVIDER; + } + }; + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(holder, (LocalPlayer) player)); + Minecraft minecraft = Minecraft.getInstance(); + minecraft.setScreen(screen); + } + + private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + if (!player.hasPermissions(2) && ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + return new VanillaTweaksDataSyncHandler(holder, player); + } else { + return new CommandDataSyncHandler(holder, player); + } + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java new file mode 100644 index 0000000..1f5ae83 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java @@ -0,0 +1,11 @@ +package fuzs.armorstatues.proxy; + +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public interface Proxy { + Proxy INSTANCE = ModLoaderEnvironment.INSTANCE.isClient() ? new ClientProxy() : new ServerProxy(); + + void openArmorStandScreen(ArmorStand armorStand, Player player); +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java new file mode 100644 index 0000000..81856ec --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java @@ -0,0 +1,12 @@ +package fuzs.armorstatues.proxy; + +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ServerProxy implements Proxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + + } +} 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..62a46106e75f6f8cfd477182314002fec637c712 GIT binary patch literal 15383 zcmV+yJm|xTP)BpxwyDNLPCm)iezkIpoM79t~eVV z7?qWkH8e0EBp)m-DkdKr9v>XX$H!AsQ70rH&(F^&EGdSDhLUqqx1nOosx=xM6(A@i zJUu%jDkT&f4j3C4A{`fVaBPcsZp5ooYiC-Mn3A%zuoM&vla6$AgLD-f4zsJ5S9di- zS}ZFnCptPeA|4wfBON0oAt@srDJCK-D5D>XGSI5#slIXFB$IzB)@KS4l3Lqbzi zQoOsn#Kgn5xwyKvwUm^Tg@uKPhlZ@HtBZ<+Cf1+Eios?$jH3H z#ULpby2HO5BNQGe6n07_6ciH+3kw1P0SE^K4-gLw2?7xf04*W_Ttxw8OaN(403{g( zY*7Fk6aqpq01pokIVl5DJp^)A0Crgbdt3m4UI#xg08BXmN;U*}jfyEZG+9Cfm#3>S zLOwP~L{)NYe_#NKnW+~X5QAa@Wl0Lmm<`gM4T@$6rFsjSa|*MC48V^LlWhp*`67zcpP|E4A7Sv z#Eux9aTCjv8Ow0vs zBX>w6fKMb$Ef^CI3_W66vc1QWvCDCiuy&}^YkZ8+!L5jde59nLoSd9VNJpodlc|(z zn3U3R#>Vd5;@|D=?(XgG?(X^S z^84=n_4@ws?#u1`{{H>_{rma;{r>*`@yEx;$M;j)0020qNkl!%5C&j^ zaRek8h!+-7p;S%U6IP`j`u;CuNYdrnF`#r5gu-_)%=jP6vgfRP#sbdydSXM&Y(!BM zFZQ_$w{sx80e~c21mHGqQv{oM32S9cb+|Of8i-+L6 zF&FusrdD=sCuL`_z8;>P{o(RqP=6#mCYvuwF4D^H^YM;SS@xoP#jpyY|KV%gr;*lT zRA?-fYggDL$To30#XRu69^>m*A>N2TR_*P%ZQ}|9cv4>;nzzg}?WDu8>Y3E4RCPR~ z7ZEl?Q>ZIA*e$q}nt;yP}W*lp84S%4Ere(iV8?qUHfP)oMI(SSBcQ4oJ~ z&R(F~^D8U!^EhytmSr`Y%@sbUPa`;ck8=Nh>+AM|&T3V09rp;Q1+@A2*^lXJ=<8iW&{_x^a!G>c*b|b^G=dxh+E;IK9>!JYN2lt^SU(x{{S&ZDnQ+Sk%lwL5YHZT2>T&Ovte!q0tHrrxP+i?>cnK@iSJ>7VjR=oiIIw6FT&oow2T^NmogjFIs|!|4 z6?7h>D>R%=}`EYZ}0XY7EX>S`PxgD(qL)I{Wj?5MgxRk8vW3ai!% z16IA2mSLrmmCC&W7PJuJ+SQe%vDPvxET3L1EG+!>;OOmsEPEi$wH=#G{5mVY+KQxH z6_AtF2!-`{V_9}U(<=2;sm6vCj2!v%?E1PQDe6(6La3}TU^T`K6xA`P3RV*t?oV_C zUO`F~R$x-)t)>+r4XIR>X3454tz=qqPFQQ@xCy$s zXZ6`9H><3q(sWX7)vUMT2OhZ|01CKxg+-w}d9}<$4#a zB2bxDj74D`5SmucG8sJdpkF*QvK_n93RKlr{w1s;>VQfiYIDm+2n$*>(i#&Nd`ecF zJLR%MD%QglbtOy?va+NbTjg*ntPC)&DqJR#RhG6oJRj1U29ZaVn46q5G^{uSnX0w$ zGoH3PJWgTovdN0diA#*mIHr|jvxk?O15Yq}+I@#8R z-n=jhE3^6xRtOo)&x66@u+&uB6tIl4GO!}bOFd?(#_{mY(fP&2#krA-LE@q(LWv$? z9BQp<_Lyj$97Ei}qif6hvZ-FVVhyX*lOtfwnH>5-VFfb{`(D zmvV^kir9@4ku-_5m61xTk>kcRS4ra-VxG-{xGMTS)yWhe53>XeoUV-=&MkTGrH8a+^2eNIj?EJId^vJx;B#iXhLQ|n&u*rLiQ{EPQitvA=gw40_oO_5Gfog6Dm$P*{jRyv&`)wYPDVmC9Sq$h)!6*(aQHm#Vag6f`i|2{725>y;bMOeG? zR|sdb-Sy2Rx2f~ug`9||WL3I&!-~f%9Rb8o7pM#?q{b?1 zfg0;Uh?)vsy$WWlM+34NP+pwfy-Qf!13%1a%Zbw^gi66vRhDr)5+KNL|4Pga4#e`@oWrbLb6);s}49q)7-U@#Z!;wPdo8`n} zs`s@57D8693RZWKGhlrTE8Bw=>v?YM+B}P=#gPQIt0>6#IAFmn1XX4=ZsD_q z)DBabSdz{HRfeUhTFmm6i2K1-z>S|OT>A@xET z5q~1eB};bGTn`khVQqy}X-TWv^)IacEpu`LtYT&HQCWd%Vd2)?+#I@~X_a2ls`nqq z_hEF(4Nu$`w&_HI#GXfIKG+J0@CYml{?h=I3aR0)V|8Got$4u7njjxBmT?8??Wk=_ z&}Lgw1uFzr1+04|E{sD=f8Pi}QNcEU{`tQOYb>qWoJ=gU`hMXSW#Q~>kXa4DBdy&2 z;F4C7%Kw|oIP$(QQ^ov$afYleK?NSaWc5Er&1J=LBMQS=Ws_YX%p!y=J06mK_lafo zD9G;7r4_nu(VmXP2sGGE4|bbmF%Tw^C-3W)KxJ)nPF+=vP3Fg(I(4d4h4`#eT|}%1 zln}ou9PH>{-$#W5yvm&(1UV)${g0}#NNj!(D+?CDh0W?k{}XjX>&R=#pdr&&hH@OZ z_=vEC{(5kbl|f~*;;7bZ&MFqHkWR_ifh$VFq+n%SP^LT>mAy<6OIBCcI8{%6A|+zq zD5PyZ^0jL0G&(SGVfnnlGKq9S5rw>_D2UrS?tE9i=p6}*FRS`ORH)xi!&2$Jl+Efp ziWS+55#_feb>t2W61o8eV16{B^^R<7|KoW*E4tHf1>8R&EYKWUostTQH@;zEN ztEekefIdXpXVuVV_3rp{l{udcOJE`%n9}tem3Wa^v;gkqsfl1^qXMBL!{2dEB$1sf zR-^}qPoD5+$uq2eEVf80P6Vs*INeCqZjo-%?QXZngyo?sNLyIxO6jVKY29=+VVAcX zrRDpLmNznS&(m%?=(X4lYr1MzZLzBZn1aHs^#wN-a8wG`9~>5HXt5GCJ`0wlKr)*e zASWF*EWrvh-+YN@BDDN90$T>sX;L;TGYDp4n73KcS~!Wf#b7|FgrX=4n=VzV-570A zRgai-POS@CFqP8PE_zMh)l9m#8_aHQDY*1ah4-V4_I*$L(;{!R&v@(Y-YqcMA}giX zHQm?(m3V>Mp$ zG+?WY3c`-GsNQf!3YA8)IQeN4zej*uFeSuWobt8Xn*vNzR( zMe6z7kBpSa!W)Z~D0kE!@g3>y_>jc<0ILu}Cvo=^+$UZ7C@-tgXO;6b34%qH-#fnF zBp9lp(3O1W(~?kKO;>(^LQ34CnKDKZ-=)aGC!KldPdjp(QQl%JVMCb=uq#wj2f?I; z93ZBCviuCFQo<{}+U4>_B`W#%yZfM_I0_b_QA=bkDmQZv6++n?ydXi^d-2M%S@lLe z?e)h%i<~6Xmo*6D3QMwb#Qojz`@8fP44<6m>dNe9Mqfstg2da*CbO<`uQ9a3S=jO# zqm#*|%p*~WH2yc6UZJMr24lf;9AL6sqCvuB8<&!RS6;r-e((sb?kbws}1u#+*MT{$0@HRv%ne?TKa5)KykgtH0uoVErBzMF|RBm78;R zgcHp%X%bA~EP5`2K^)H_!AIj69q`*QZxSnEgA_wLpA;1{`1tW<_BoyvU_&?fGb_7y zrpu_;H<2fHGWA1-w^fSAUB<;a2BYT*?%b*rkaTx*m)9eS78I`NuadHuBN_@sWhuI| zLQSJBQ!Tpq2dx`m_5JIt*mYL^YpndO!wM5tO{r$}h`Rl=EI?&bd6kV5jbRktL9r2G zAIB;9IG~nO$T%MwR-X&GKhwj$B0@i*aIkgzBxny$CdLOZ;Mxq*lrOixGh#1Qkzv1mNpC{Dy{r& zBVp-u_3W|=qUwyQ8hTfCr;vPxIj9Ot9Qi^PP|U(Sf$JsDLp=Ie=BPEcmvSG$Lm*_8 z7?B;XM=<)Ig6<5Q2}NXlL*)@_Uf3{Al4*s0!B1fK$AB7&kPC4pLkJO4!1*po((3St z^J?CPwac6Bov&;hGwQTpxvWT6SuNaFov(`X z1Rn=BwH{TyewwD0$5ERkP2-2?35tGDrQlQ%XcMq9LanhqtXWNq4Sr&czXFv{c38wv z6kWVdD8lCv=?FFB#SpI39Q~4`eJuJZXjXbc(CtbgydDKqci>;7URE@}4oxg8os?|) zA}uz_sj>*EB_z$_?z}u6%X_*rrj*?`TQDRuBfa<=lx*%2)Q$O}6D_|9jV~i_= z5IHtQz^Y1g#OkB0_f=YRlrne7C(Cv_xHwOmTv)_P74A~r8TPGZWnU|)*sW@zb)d~x z4OTTG7u9uEG+0;03AZ0Z< zA**VIE=DrVDz&UAvbv8~+MWU*(|tBtrK=bJz5*yo39KkI7oL}=CVF`2C{*3sTY9(& zP6HM|LRQa8PU`AdfwRzJBz<6TyJc{(39Bi6Uj4>l#hip?5M7yASwr*rzbpjjc4a}V z>^uAs?1$I%KoFpn8%#8z@BkKnNRwLWI9pril1;Uf_V4$|YTO@`70$mNu@X7jVFZ+t zA~USgbGL71=k(2pEV8lt^wS$2&L~9+L7TQpa1q7kzDL38Eq(pc0CylegoWN*5o)sn zD0U2;eY1m$8GPH8J~&!(e&g(~D3nSItImc^L~T-YC1`3qxmc)E7xmVWU^%S5;&Y~V zPfzOoRmAYP^uj|{EQpLs-m^~ED~(-nxuvns%xyU0ej(oQ$uWL6WGq|H;I%XLWWjHLorK( zZCk9tN|j5^>PLHG$wkEom5}?_CHL|mp=io{`hbOQ7Cxa`Du-CG4V*VC-io&%j#|n+ zr7Dl)zOxdp?Kqy4XPQ?}2dq>rzyUj_?v;AANFuRRoqaGI{{^jvTiwd05u0np-YHMXYYPW@YD4jp}dG&80VTVhg~m*sw!F znspXfTqzo0*AcK_cf}(TupwxAHHg=GR%j&Gsj0HdE<1KrVW;U~CU^1!Arge`t%sem zW1l3_d<%DVoi4{dU!U@$osUug#@AtR-x!6hQ?;4&F*x|oSMQP83Rp;Ul2Qtg#MCA! zB5rW?-(#=FrrDBuS7cZot-0E!({>VE`4?6iFa*duAxdW5mjG z#K->Tt{zM#zxkq$ z^@Vj>Wk3m9SPNI*93HvO6j)^mmgr4abUH4%@jV#IDz&3SSur{*t41zpDa)?mKn{S% z_Y8P$2NWxa66#q%OsE;q19#uT&wGyR!a5mT1yjqr78?T4NHw76nBVeD>J^Nms|s^X z!QF9y02gLNckuls(A-Sv$<}A8vT`XlXOU_9D!BSN^~I1WrNzTlR|!of?VD5JFfo(9 z^lMLeLndXFR?;lcS*DC0Xej{H`kEe^@Szn%qZR=*(sL`z9?hbw0oQ)uTrDnygQ_hB zT1z!!X2iWiY)N5sqyf*Fi+Qxl831JZ#{OGb&Q))NbUN8#iN5krJnepWQno%p@}Y~b zxLVb{^$JrKUMiV|s%-Xtd>~=1S)s_)*z`Ndg^tv@>qeM`)SP_+hw_TuVnp&C& zCM)NABnhZ2M3=|_$kzD@#O8z9eT#@YtElqm{Qeta=0tguK40xTH|q$Y+)^2YqAuan z_~hl+hc9285MFU;4Z?X3e1DFuuIqDyA>GEHu3|{%axD#a%3A8uvH_sUC@6B`UH$3^ zvfRQ|AOR?aj;8Lb%G_Y=oJEwQXth~IiNY@pMs8g_`eJnT8`Ppqpg1pu1kdV$wyQ1m_SqYy%)!Rb!mIk>N^=&NS{>1MNZ_2#>St8mT{ zt_f);qbOVzE(%v=Zdavzax|VH-Pa8yk4IO3|8I1~1g?X!4h_n_7v}W~>$W_gvJhQ+ z4v?OlthoBn^6J&W)8UYH0Km==QHUzD&UHweMOmSl^SMz4p4z%@=;_t*z~SNUpUdFt zmNASqxcs)yaUF#y^y|!mBZ#bZT{^GA8OG9;!?|*o!J8C-w<>U_s=GH2QHAOab55ZQ zhN$a~**g{^yWQ2LJH7&!xGPRGe2sbE;z8*O3q>h&FIiaHu)@-!bh3`Z#nr;qE9)wp ztCzyu!o|fjaDIM%F*1Zl;tV+LRDlbGaAu*4^9zjJy5jJ|_=ED!y87`u=c>}^7*j#1 z&}h;35+7QK!r;-hS#Yi+4z{^kBoak603`l=Y=yo3f4a<{H)kQ%RAo4tCU%@$&k4zq>$gJU17JHjCqaFl;ZEmA z_8a?`*MH8Il}aqVVCl{JRj3u+qL5L_je*>_H3VI!VUVR$+ zXSJbOsi}X==SX5kS%h6m+4Z6^7LwV;DqF0Tvw8;P^Tn+aX3=qpTma44nLgY8X<2Qq zSw#yZsaS=-kgHe;Xoe%#!wn1KiQI~tTxtsnPAMMCFreu*bfbydUUW~qdtFvKvFfeG zw9J8ItfI?~(F?F-l!~@UtdCY+TG&EfZ!FjnbU;@jj+@Mp;)!PU%Cg%0d%jh(3US9z z22<$ffq#L+ao1%zG9@FyvW;T$ipfp^4Wc$qU(1xv#2gOv?`8^or&Pmwc+aph(hHWp z{!}a0l`ML)FG^mj@L7(e6DzVt#g!OUA7W|QhLjMdN+R%#Le-&;!%;8h+^~9Cv)VpC zKRDQ~S&d6rr&O#W?kPwEAfU>lR{0W7+xLS3DdX?rBs;hSdYj z>hf~U>bbdcS66_k?5k#{zNCtuRs~R`6RS@-qgfBPObJP)#*W1uhe3a(|K&4>VZ&^sn9#%;6*H?#_hUS;v(BD?4hhTi1!D zS>6BCu-bU~R9mqSl`)b2@o~mF zP6I(0rn=@jBq}-z=;?@{MM8jRt_cM#Pe6GRToiB)2OW6N8{{U!kutk+aa&lo$?kc5 z_d--qGj_5&u}JQ#^6$(fjwa(-d#sqO+pKov>TT~C(oXItrPUrKrP6l8O6F|7Sik%q z%p`-ZK|$Gd!IL1YZl#Q))5Tt6mQMKa)89?5J{%qSTwPu43Aupb$waUA0Gt=3N&sm{ z&c-7&?g4*xG6-EH2&3a}%Zi*Wp|w>xE6NoubU7bjv+DP{+}}P2whasE;Xrs$8IP9v zbiUAD8Nrxvy1^n&0w^1Rrm$=WZMz6;ST3jqcxvl0=TQXo<&*$P0dAJ^$>+hJHdn9S zP_Bj)VkC5!VK>W=%WCW3T$Lf!{E~Buv=Bux`IKj8BUZFXORHi{{)3V0x~zou+5lsq z$t;MrjZbArQ3+(rGaUAfan#!1QCGCL_|@JL^c(kU7Z7YJO5>a{D2&QkE}hwc#$;X_ zPu&!jxs@djev}t>=^so;w!(@iDuS>Ovs~GrtMvP~FGML4XOjsRYkt!HT_6e=YWS|fz+v!@rK;XvKa1gdtss(!jqU)-AxAwLSVGYJ{0 zE6*K)As{w3?qn7O6kYSm)u=Z5uGfugM-T`f3;@Tz_V%_`ugrIipj*RH8E?7Mu1g$Oi{}YY2cHPFHJOsaU@a}vd~C_>L(UsrjDsK6`FK?TG@(a=6PF%pGMKx zClCI2m5FVfC|6INw(Fiqlg!A&3*tvWChe~5VOO5}W9{nH>b0JBH8Z&-8v#rTsetm; zRo$8zA*{(tshT3l>X%LWlaROga6M3SrBSZ#H>$_L?zM^kOD-#9LSZT)kWv|2LSOKe zyp(EJxr-$W0&b#JSe;g3h&jnTkI5~hN72~TE5o*{-*Owr%GHZj$8|G1dGLX_5nwgt zY%-x(*`hyOy9!d1JP)+1Fv0d6DX{LOZ0E~asY{C7XbN;V_)`?HUn8j!*@0@)PJk>$Wq^zJObkFMN*pR?6vz4;ZUCcQ z`--MWIhLNq@*<2<_Lj&ok|377KV2wlBjud5O6w|vS4Y&I5)P30;N;}iI) z>ngMpC1ZAFsPkC6BC!c?-9zn)nlM&nm2UvggA)>56%Ho0sIj<;^ER~flO&d!arNwx zD@FZz3)(kwTu$bLRg9rX!pBu8@ub(|cIoJ&7t{SV9HE3aGYpr5QuJ~tI=?{-}d5i?u> zGJdSIz7`# z!%m+ld~UMHan5F@ckY~yLfad9dz(A@KR5q-ZCts;FG9`y*)`M}i|v=t_3WqIwrlh4 zhwS3wEUjPyo9(W0H89!i4%*AY>W3x^)onVS&aj;k5fT-SYLG()Yd3>231>OK7&&*{ zCW0soQ_;{-ASAjJJOEuR+aM(HMnnOmG@!(t1uuc*oKZHH&935*wJoJV5Xp~_Zkx## zk=7c~Y~sz0Hy{O8TFzN}&e;_t%GdpK^YQ$i+3{#*6F0x6!Bz>@D|U(|LAfG2c_HWn44Lcw_<5_xdKY4Ofhq`APg^I5(!nMRZ(7s;O}WdYgy@W_&fPfX)tu5-b_;l|E0t zzZSK7I|H3gF&?Pu^A=%^s!rf>#ruJ|SBU*X+^Q<@%*dh#gIKeQ(SnlNWtA55Qa#y0 z=>m8^B<+LCIA&~7#Jfkg!={B)#4B2EjP5sw%h7oeVrOGuYy zKLMK0bFb>SwktDPTRfb}&9W!Y*eP1NHvvx1vMKcQ30Y-0c+5HH(QwX+%CItI)rJe8 z5>AVDwoG;#Q5Q~FpjYltRNsSZzVIz`;6-)=hP=9JyjfZ8bHLa!WAwSAx*Z8*h)3H+ zoxm#x>#T2XMx1tj1hX%e6$Cg1W{gHe8k!+kl?iXo$_^E@m(izs9Y+UG$365?9q)tr_qoO^~h#@0=whKCIMm zL?Jael^ zp%P56BH7Q?j#|h4Cv8v=3_&R0fh|)t4$3ak5MPCu?PD!;4#~5wu7mRrx$Pz4!g<6 zKJ&1zsA`7bs2ePx%dW(t#Xl_30gx`KylK<)IMe8VBK&(G_i8Df+*FL~L*kGoG(I=# zL!lZ~p9|*Ik*umUvF)U4BbCeP=!t|w2ZWgZh)y#au}Hf{0GMGgn$WgkaYa3%uZuB{ z8-;Q?T$-l@%xN}Mu*O)-B`FpdqAobKl|cS#7E34O(u0a_DVME-BL!jDn2CchZBZw zqiK$XI;l9XhY6ie#10cdJ2i~O(g%=I?v)CMC%8?J?Gy&Xd9)oUD+D+46hrXBJ-1@1)qdZ2mBHMpqm~vg%F5lKeE}Fo3j*5u+rlF{l zqjS5O#5ti2M&+0e=i)o{1`X%qnK0CndVN3f;h2B(>iNVgm7&Ck#Abh-aAd;jaa98b zTzC#35_={bAuMRQTyA$?N^tP8_1zG~WO~ro*IvRF0V2QC0NMOC>&&aw4c3Fdn7`0X zxt2^HY9aD;2LmY<*C=Y}OLZaDa8Qos%H<6yHo)DenZ>fIE`ij;*E5U(T?cC8`Pi^N zELiF}AQ^Ve73P(u%|8AZ;u$Fad>h|a%aKuxOngWzL9m$V#3`jm6W3p5AhF$QwccVr z#@>&$%M=7e)#c@KGMH{{b2T2Y&R%6Ks~-j%_|20f_h7Xy!MubL{QTQ* zzd0$vk2)va&C&@4e^IJdyZ4fJ8tL$4xt`VSR=3Z0@aISU!Q^W9`9GdNhq*UjehDKt z4`FWkHs!pJvo){i<2YCDmHcAo%1h6vQ1@Al{?Uvacsyg>yV{nh&jC{nQlHm7fFBR} zKz1&94*&S5a)K#gs&!7U7j{YB%r~3R6?EYQoERyU_^gyRX^P9qv}~%;3RMfa6c$Fi zaUTfBkh0p;Ry_28hXw0l6LpnZII3=KN{(r01-(n^s0!(XwI2B7vvbf=GnL%I#{Gk% zf4_S-aa}c6&NF7ecni)Gp#fM$dHk5ITHZplU-I)r!YVh$@Xrq^HPSLR?&u~+-U?_G zN)R{f@LA!LXAg&?u%;7&5;<|Wwz~Q6YZNP{!dD4)Y_j5^2XvS=TS>59t*jFt7T(Q` zXs~dh6^uTBw_`eZ2Ue%j~h0m~*1V{;0 z9?R||cg?l@!EF~3t@$ z30i6Xj2KrEPVkl~AnR*C;x!PcICR0{4M9nsDwp2kRy6y?g~bo4IPQ&Feg8dLoxKnK zu&kBTRjsbSc2idz@q!p@VrW;XE6h||j*77@P?e<1%Mz^hwI8DuMc-x71&gR9OH!Fu zZtMWnpg$PM@Rz|L+gmJebsE8gNU>UK4k`%PXkn|hPQYyO5;1+pg9yYmor<=UFckyK zmh!Tyc`JS#f?D(l3$5&BthQ(7khNgTI)x(8^O~HP6a%oEYOccS zZxC6iW|kIE5uso$s)gf3Qj=eP2f^7d1F(t!i4!ynt)igWXhMQ$iq+e*v$J2rnCbsr zJjqyr11ENht=i+Ltq!EYb%jhq`O3- zDzK8f0>SFdPS)yhS8}MbdjNISM59In6oTMUkyY&DI625Ps|H%N(5n0hhVi7Vq8REG z<419^l^h6L)v;Hgvy)1?U9X83-z<^i2q^T`$n3~c=MZRlv1AfpLMpK``#^auJ3}o> z1*$e<&9_R-{(gQi>Gvl(83#}dnesUnqCR*toH7k?qEHJ7hEHv&1xd>|+Dy~J+I%azo6RNxwWBsK< zP>WdUFB+`e8dDWxiQ3EEz7w}vo*CD5*ov37xmEy$ALozB3dc(j9z**+T*}H{JqZYg zP01<>lySSbu8@fT2g<64Ry4=gV44LcsbOttRapwnQ;CbE%mxvJ0;?|6>Rc;rH?o21 z_*i2VQjt}i?hC1BkMgr$XrH~|2LOPx-+X^jtC*}n3jdO%4e=#7W1X#-01m*LV+G*@ zQC7C4-hI8IfRf$y{3T3*QR4>`ID1}}LWy8uWhJquVO7&s4`72mWhGeoj7GLiZK}o1 z<|0dA9f1*Rhi9z2sif)(0T#1rrmbkAIwwj;e#d7krdrG@P*%8aq5Eq+))%d8hn^2JJSP2tRjsOg;j=9Mxlwzw<$40G}Xa!UQ4F3nX#41?O zicQ5T@CyS<*Rl#SR;s&5<}gvgY%Mq1eL>NrG)IK?K z5*BK3|G+^kh+##|yXM+dTrxZf0P&f~st<7e`I(ZKbRn zT#=$yU#wyed?44fg6#QYCrNw(+24P$@901~5;WvX0jUbDu=(N7udM3y_)slVR91Y$ zs$O-pMd7FDnR_N`?-iCU*DZ5jNwhMxRg&DhySj4w&NM5TQ7a{tEvl^3R4heBR$E(K zSKJ4-B5dSbqGBuH(N@x1%zq{VY51{r*x$b(tFOOy#YR~%04pqFMLUmCe|NjygZ2o! z1br^8Dz{(cx0S>i@&m4#+F;@!mUQQpVl32Bt0hLP?%ZCvm25JVu(Guh$0(_S1&}iX z3(2^yj&)t(tVY*~+EELaKu@fQ3aaJftzPV3l%G8-?|;5AaFa4htXlJvvl@^U{X0;> zMjn2cRYR02S_u}tBbY1nxin)5k1@)zuwjo+c@Tw)fI%}~l6p=I; zj8#$PK(Q(2D-NXyKl{n8l}}gYO;mwejgdB_vRG-d>sVPSD|(1O=p)rlTa}-F`0(^% z<8pG-RvhLELsbsL>Q*LJb;wv;gYuoCge7}Q-Q-V1EY~h1v%WuD{dDD%+j55mSeS~2 z5-KwvfrULU6qZz#vaNND6tYOsV#2dRXSpr0h`g? zS!=(#{mBXz7GpgCERkZWA}i6#XO`7*csPh@J8%G4M5SME(fFv|qRm!q<9hX^Tz&{6 zR)6rcl}A?I!d9NqTl_L>Md6n^TSAq)Y*BE{<4(c&&Ne%>2l(3rOvFsA^|hZtSwU{C z-no1C?gI!|fz&#tcxzC!iqRxsMTOrvzr@#DQ1H2xPRnolj(n$%AA#rGc<_1q)TU4AvQJ zq_HH%eAEBeI!8MVgHQm5yS88fIV7XOro>)ZlP0TI&OV3_VZ8LoTNB-GJum~-E?HyZ zcLSXK5N;!5OiQxFOLIagy+>PX)+qnN7>i6A`C)^WmQ%7G>)tr zZ)aRK@7k7;JWalB(k#mfAyf#){|yrk=fkiJqym5%%iUoq57h`OGV86yR5DSFlS(a`R^aZCHwqwY0LSsHTa9d4zgzLPA2dwY79`Y?+vqk%)1L zc2AU&jFN*?jdw3BEGoIVxuThqbYo6@WIMgRy}7uym1r0?Gbu4GFT}&cNH;W;fIL-F zO=wtAZA>%M($Oj@CcnVHB_<(MTxCmER69LI4Gj%5B>+h^0z@(ZKrR42EdVVc0RaI3 z5e)zh2?GTJ015>GIx7GT4-zF90}~Sx-J%!xxfTDz7qo^BW=jUnnGWr-5+fub>8%vx zsTAU;7O8p_ZBYl{rV+@K7Isz(8xsLdIsjNg1C(qHnQ{vvA|B+Z8I5BV)SDTBUkFk@ z0o9ut-J%%Wp&A7Q0|N*PTtxwrZ3AOV0mY9QZBhZulN=KZ0exNogku4VX9lc{P`ZU0 za#jF%S^#!g0K$tMRz)g&Tm?%x0I_-?dt3m|l_6$gTZ2+AD@bw0$C~bRwZ_BBpU6Gan6mQx|`Lf1YY0mSZDoMi!%L zD4J#?j$9)}Eew%fC45UKUqBI+UnoyA785iwV?7^Qc_YWDk@A)P7NU*JUl!U92*xfEj2ba8yp%YH8fLHQ#naB9UdMSDJCHzB27+C z5h*4rG%QI;Nemnt4kaQuI5tB>LnS9BRaR9yMMe`XD$khN&;S4-Vo5|nRCr#5)912; zAPj&}-v9lm_PV{^UgsttMh3k5{o5UtV=^*!bX_sd`5nuk9Maf;8JB>J=G_is*p6%b zOAkWY#FUvDAZ^Q`47y`*(iJ<}7%^-Q7($T4OO6=`1PJ9^C>gL6r1K7p95Evr200MY z;iHaSZe$cO5R#VAK*&K1QsiDSED>;sQ2>BAJ~+!^9ED951OWgsl=gjjN4%NzFw%q1A!h*v_R@D40flc1bhNYsAr7Bwrn9mSG62^54VFz--C zmWj|&sr_%*GxhH3Hk-|Y!4eD&1q$gEfdd%_UqGo&`w$W-Hnum4g^V0ZDQE?SRLYOz zKm{J}pvbWTVKF0INr1rQG!6lbbk>oStV7s3LnIl6nAbvp8Vej0NfHopq!=^|Y@xup zJBKpWp$;R=!lBd>vo2u|7)9yc_oIfkP+e9pP*v93)#~cxs%-vO>QnaL4ofmfvHg5) znkQTDdTQFXZJMz^f5)A%z8}ZdHo|R9^V+sQi!PViH6x8u>|aK){o}iCeA>pcHh?Fw zNj!E!niPNHPp*j*5)#5UDR26A>2`Kzx6}WAM$2y50fkkhk*KstNU$L7bIx_Zw5X3% zCA|>m=X1}!zFe0pilV5hx>QAK6#1(CpudzKGzxxaNd})(6vL=gD)mOAvD|EyUm>kl ztNr@*J&EB2c%}4R#@St2H!aJyZ3l5(kFvVzQvyo(lz`)NJj8Wf2f=48(=?+fj*~SZ zQb@sEA{}gymDgW&TJ447MaJhpZVVGwWB`42$jLa}JUvP`PsS8;IovM5cyP#ytQ8^k&NUc!C1N1oR^x2r>})=(I*u^vR1HO`3foCk<9Quu z9m~aB929Pb4(<>7eM#921J8;hK**5}ha)(sQ`v!(B;)cDRiF}V@cwywD>u)rw&uD* zsTh3!wZw6gDik$}_EKsxTI^9R2IB!KHn~%rNF-d5H7G{gOTYu7RMuxVh;;n@bYp&Z z2Np(n`T}xaqhNEbB*`mjOuixvB$NgRwthzfpSYCFb3#>Xb9`5c@ zwz-t*!XeA?d8NHxE;pNbC-D8FyjtuAUZPgyTxhX$6ae~DiWEJ9qfd@*=KV9NpemsM@%0nhKG`Je8L1VD-6Z2?Y#tcz#raP7+?q zlLL&wWYX{Y`=h|4f90ypXBg=^rH~=BX{~sQXhV-D(s*Uyxk&fTCn(WXT*Yk~c@811s zV}7q%J~1-cn)2#FXz4Xpa1y%h$r$OnaiLXG>6o6JOnPs2ci|X`9XL#SN;|Ss_l6=N zNVP5R2a<*1UdCdABj2874WpnQuZsD>*WqEVFb?GI)JkRQ|zWfO;e}@(8rE ziFEV>%)@ZFW_hj&2d2=qb`Snc4%GiE#}OQ91czR4fB5j@U*5l;Z(S)?07kDH*fF|* z+aTy>cJ2@e92p##mR@Kl`PidlifNgSdz-$ygSZ~mgRbIHryd;auEjARdacrWa(upP z2mg(AAR;kteagaWDlx=)ytUhdemhh?yjo7f?X} z*&W9DD$^>hE2Kn>Q+6PUh7EkQz1(@-sw7_6B}e9YVXsf=W#2j`a3JImPhrP&GVc0B zu;hslZR!USV(stCA*|3!r{Gv=2os4Ctmq}BzT8lR6QCRjZi&kQQJAqqJgdimgkL+H z-jp1@P#&3OO&mWziO}k`ErP&dbndV2;Q)gi2{|lCQVpA@9_Ng{baW}~NDJjapTa;t z@hwqw#Bd;av3N=|5P1E8lAq5ka_Dd%aGVw#C?b@xX}duv9sSJrGwzMA90_7#!ufXX zSUwdBj+5#1gu)<*22{@;LL@EAz$V5~@ zxT)b5gHH}1q=Ylhu-@?0K><+_#IqwI;8-s>wpvD&Pgk$FIxx>(0KXsu+px%p=&PU1mR^H z^k0Aw(i~7Z{Yk!L4%Ffs*Kp|un*5F4;K@^W{7}<$Py%#bMNgzJ*s?2eZKSEbI<*znVIg}qnr!SY`ondZi%E#|NsoL7A-a7E@uH5WQa6xuSuRX^% zHd%1A8M%+933aIDD310=_qIRgS}|?p@BI!nT8kY2y^WgF=C!&q@z)~Q*q;NdVINuf z@YyKL*s4ButQvf5XXR$4&d09TUKBlT813}f>g76`-X@&FBcM)CJH)P9QS!-+SZZMr zBe&3bbXGTGXM0*{4~kajKkS9e=AZ8^DudNBvxtuZ_>5*8>jfO!`r{8xA8@h`9{lOY zwXKcq08bx2HhQ|nZV)W6qs}%`aMUj!^G^2Oc~xMaLq zl8f&)!AB|h0DzCLzwYg|`Z)OG*MFMP<>?<77zlWq2Qb>Z9L;?vFbjZ;gLAO69h3fc zZ%=!GYOJf15&}Fp5KuY>OpR1~j%U1D1h+FU;m<5wQ_J^*kII5d@PSXrv8u;E%qpio zz{byh7VPN@^aoCO)uH}Ce}8{K^9}bCLHC{r0P7UlPBH=-cq14YWrvA26bgq!5vpo( zfE4w>MA9Hw^fKIFl)+`Y6fW*5AC(!^*hh8MLqbl zmOBHOcq4RROq7O!SP>YJSUNZqHDWPsnD7qYNfMhQW+#5vKDef18zuX5&GS)-ec<=0 z)yHA*@lVpo$T0kj$Gs$u#oajIe>6;p;zh4$~VJKs?1LL($96lxf*Iw)+ zx4g8pJUhF*q%_;~fw4t>WP**;hY!E=`Y(l3VotZj`xu5BoHs_GzsoIZU#+ya}yghQ@q-5{;e|$Xu!jZS$dh2kFd-|U- zW@bo$Ze3I`F>RA(>Cg;45Qw~O8fV>eMo1HEGo+C5r_Y?Pw>&2+D=D)2*djj4vNNfT zBS!|4GYb<>ai)toeufBV&*H;WWD&yh5 zc@~FmU$FG09V2C>C8gL$h3TW}(Bs0Kvh3Y?r@_aO(|^m^7S36)Fwgjjuo#ISu-RBRE`i3?m3#Pet8ITvdemPmok=cYYuVH*xpHh%kG%xBDiUAbl1dH9l+ z(Myf&_&9Rp^sZlwE)p!;mML+^lZ(snlhh0w*3U0Vv*+;GO2_f>@$ncD&&_g6=a(U_ zB7~fddElTbD(ST7*Si+6a8A5^53cEOV*z-vaCdIb?mT$*lhJz&8=*en_j3C53wb~O zi}bcSDZ6Y}oG z;5WBZf3^Meets@_I-8x*+e>`V?^FCR{`uWm^%qyxFf=_$Vp35^ytK-Un?!;Vh?mtw zEM`PW*~%<>|6l1a#u}w=pV>pzNL;xR{NPbda1bNdaG(OdK`>H24t$rFnU_zHS24JL z^%`JF)si?~z3!7C09h3}t`c%Xy10hphR>Lsi)q)fx;Be$B$t3#u#|NBU=Tx9$=KDK z=-<8%B7(u1&nwEw!(H$}j8xtE)whM;(g%gx_qmPBo12@Lud5maAgjLjFB5V@Fv%76 z;x!yMST!8d*>$X5yMWY$dt=jz$*AI6y-cWEy-vsm|G@{Q4+K8S=(djf03)B@2RtVK zAC6wX3D{Uw-4K9)4+wx8!VO9;vKKdTTpe_%s*hX86E-h!T0&X9X~m@GQ`{Sby46)e zHb=j=`Y0#g^4U8+4(;42|LQX&8&QC+sydEyx*|t0VyfVX&SB!?g%BBG2kYx=I4uTA z!pZ9~pAO?GK&?YjOa+?J9w_a6W0K2m7kR>U z7O}L9LXXKj;uXT@q*|Rw3bG4!!GwdaugIa-7y3QcTXhV{k?>R4k%n6v3Nl|mavC`5 zJbvwSQA0$k5sl4-Bw;9`alqybjaM0@$L7eo_?VC+1rcLL9K{VR>&R(YB_g9IW!ZZw z0Ob1vfW&ajNFio~B;;aUE*H-u7Y565smK$;Ay&c>#o=?yv1APCQNkn`AwYt`n&mu1 z=*YQ@gk_zu82pnQi;t=rP7fK09T*|q!T5Z>xDr+4K1_636cmV>?jyMxwIinjF%(MN z(r}Fe=P(RRaRvvaIGHTMyNZ^}Q3XqkN5oN;9 zD0V)SE`(X;mH`M!oDfeCrZUlI`)HALp~n$CZN5*dklf^Hwc>3p(qzp&OE}s0(*#Ym`RqU1V3==8gwE={2$!1PhuX!9DOkt)xDJ_P&8ei~)ki zzE0iS*O&&;Nrd*!<`z=g=SE)70HJiE$BV{2khce1qCG;21B%)>Ku68K5p}qa3KS>$ z#4j?WSt=#Dt-b83yhxWL^?Q z2}SxK>F+cYXLlc&$V@^l5O0`v9oM1(t1zTXgZa->9~f20ePSdK=pRnm7#i19RpaLS zVB6Z?sn#lDkZtbA32eOsfRPhj=wa4>ej~y>Na`L{7G@wnB(V1lYfdk%6(SI!Z%<^1 zc2%hm=t-?J`bl|eUs+XEb*Mo~+pOZ{G))&B{Y37H%R)`iPZF;l#$mXB3BB>=-xZ1= zLLz+e>MMUlHd4`iOSgMTNw?4gilu9h3>j z-vp_2*G`e*ozBLj$x=;bZ|7$1+3^AYAM#1tl!=LjiG{O%Ra1F1KZChVk@a8%mP%*h`%Ta9Ewwo{d$B%y2!%9*+uTF z*RoRQqpBKks0L|adO_+w4>)I2b)o(bvlEMuEXoQh&*6cQp>yPzMECaX+a4v!g7`nh zMcbT>B#}_4i?(3gAOON40z=bpQFdz%mo84cAFRwap9l3){QS0L^HbQ~!&uQY*O%Xo zE@Qszb`0(-;*!gl&pX!_AucA-cg4l`Xu+cNq`2q@+$ECuBN0CluiNLL5-TP;G=B<2 zUzYxGI*a%yAU+;^_~4Dd9K61=c8P#)2_xD0P41w~Tw~=r`h8{AF8aI>Z2b1a4<8&V z{QAOL`j*gMpOaO81&ddgT=)0BlyQ;pRU}@;@iO;ZNl5_@6q3=qMJ4&@%KGNh`RnVV zl(x%UyJENGbR+sk0r()#Pq7Wap~Ab|MmqQ}%X2;xFJpQW!E2{{a~=I=lZ@Vmk~%Vh=HgmVoV;LvtjDO0JL(=?>hY`6B&0-XRg_A!MB4B7o{jC4qJ0k#kpmx|@jJZVm!r#f%GN7yUj00EeGY z4xy>C2^|eG5VB2YwO3d2+c&DX*L9*dJnjd*p5OO_UeG^2SwPUir5#f)D@bRyXIX%F zc(5jOf)2$r6c}Hzk)5pR%5E;*rlWt<(v`a0vn$ms6Lf?@N8p~jLExVsAEh1jgyRm@ zBg;_--!aPi38Uo>G-Rd5f%=pu%Esj zv-KDRmgT$PXxk#Rr+2zu`25(ftkoL8P=;9TlHas!Q5OfIWXxN_yZMZaT&(1@6O-ML$)FGo|b?-BFr0*Ahxq~#Q zgE6RsKr{BNXnS7Un-=qgqYlH6*ZFMd!1+GRpi@Z@VxXco%Tm(eCLAYe2kSfhjgFhv zY)mpF4?&5&dA30WF2f1@wxMsYNBtmKjrt#}gZ&S)ER8w~$A#OAu8Vt-aNNvE*#G#M zLRz;|iR9}TI>pUPB7sQU))GhUe>gPrM|8y7DLO9t7CM}S5q8ar?kVt|W?t6{7{h?PyqY*1!T7Oe|ukD2dma5YyPE z4oGM1UGxjU7Ut&N9ReckZgW=_+h&00kieI#gXPN53mj0i}k~mM8xA zR({lVXgb|=@Oyf~zQF(WZEm}58(SC_4<#q$&=hIvV8J_*!b7{gZ*&_Vz3D|#6x&AL zAeVjuze=7b=tYGVNPt>FiWc?-0lE<24Q|5%2v}u-{%Z{>C61LJ@ZoMgt(moEjlKS> zLK?b606M1(LL8_c++1}bZO`NS;Z86ZJZ`Gy1oMHT{+QL$TI_!DNn^zC(WvkAI zLh4!&)-^az6^AciJW5{ zL6=JH23?UbA0_>eEHa&2=D4`5e5qxm{gYpzlTh;zFMWDQ^V-cEeKHtMEHGJL77-60 zV_uYPFOu`phcr!9Ysv?*?4W37p01UYnVmBRx%jQpyp$ez0XP`st?z*&9*w3(Ge~a7 zG)Hd`hP_)vBBmn@t~L{n{nr1&7K@Fgz$AN)yP2cMumgd7SEXJWgalIlx&A*u_BC+G zcytiEpUm?cEyb=)Y3KPj2lt){X6u0=m@UUGK#0Rn`Bn+b{LP!c5s)q-DU$>CH?;A9 zzrirK;dl^2#RIdMtwo1mc+hgxpfs)zp?nra6;%;&(9V2_Qa=l!ePC=kyks~`h=V}j zvrrtYotwfO@L7O^Z5F#ZOiIbdXK}_L;K;y%i|;uwqWn+Ak$TQ>;OO4g?-Aegd)y~b zLgc8xz~k^4!**YUrTfT*pygl?aA*Mz@$(ANcwU!C-L9sAV?Z2|LCmB-h?|+J-QpAn z2VYBHGXgWbgQoG5>DCbB`l;smK_0E6b?4@cboz81pnoq5!dTT|upeeAIDFCX3*A?R z-h_87F?4XSb}%T80q$qa^FBUo+)@2^kDxj9C~0j;x`u|!5A!tyUt_}&reRsEz>$}H z*>zJb&3w`838}g>=5Q!^%r6U>oeZc`__`Ub91zC*e2%Zh;;VV<1(Ioy`dV1cAaD@K z?bBJ9)de`Jyr?%bmziew#kY@x;J8|<|Et4=Q>eZWFhQ7FV{m8+#07`Y)mdrv@%kTg^k8v=A7BIwE@Ttp zct1b?@wjVPO&RmDEeHI_9FdFb3g-n|`LUS^)w(*#Z1t*V^aZglO)G+~vx}rzJ zrkqZ}aXz0fPEJB;DhwSQL7J7(Y&lyt{%jnO>$@Xv3$Iys5IWVBj)6DnsXAskld&y5 zip)bYEGJgkAYf5}*$*5Ct*P*w`*3 z8BcB3Q11r#DkjVUJ-}j$NuM^MKaPc%u&I!}h{~2SUn~~g?8Ubj`_T;p806psM^HpF zYy$iDnd9my#I`kf!Aa!ft7IJ8mWcV8fNxXYBweZH0aBAr&7q7fdpZ~n5RyTA!zI>Y zaeTc0;@Pv;doCMLB{<4D2n(EqRSpgYK})@y@r!}a2vm_uJpl*Dd%}~*COAAv((j9G zegm$T4ho1esrDIS8k3J<(d}lhfdOpB@Y5Qp85Y1O3jFm!qENU=W^~b7sI%I?*m+KxHJqZSnn(&}3%CKG$ z$Eu@1ZvK0hmk)4+y5m@;a99FA4Id@YW8KGb#e^*j*aO!{#>%E(bNXgrz zN~~3b0}-e?uU;_;IEuVd`vDfB0ZS1|;o!m-5HM^ z!;1MLrTZMQp(NoB17Z^13~ft71L63n6)hNbegOwUa(i8^sx>OgI-*hrLVy&j(z9*D zZLc)bwwVL+KbJI}*b$KBdb*f069v&$J7css9G8ZLIA&|&c=?h+&W@ryLc+|dyaGmn z;L!GzzGZPGSF$YGJoljcIG%2*kB`bA?HCvYLS%eMT9P&_03mz(D#CL5!~a!_{gE5EN>z;f2h>dYA$j;4nGSO%H4H;(RRC`s%&Co>BCp eyqew78|xoesj$^wqzKCZ0000=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "puzzlesapi": "*", + "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..29049d3 --- /dev/null +++ b/1.20.4/Forge/build.gradle @@ -0,0 +1,38 @@ +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()) + + // Puzzles Api + api(fg.deobf(libs.puzzlesapi.forge.get())) { + transitive = false + } + jarJar(fg.deobf(libs.puzzlesapi.forge.get()) { + jarJar.ranged(it, "[${libs.versions.puzzlesapi.get()},)") + transitive = false + }) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20.4/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 new file mode 100644 index 0000000..8e2c24f --- /dev/null +++ b/1.20.4/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -0,0 +1,2 @@ +// 1.20.1 2023-07-29T15:02:23.443069 Languages: en_us +9ecbeccea1af534ecf344346c3f5cecde17fd977 assets/armorstatues/lang/en_us.json diff --git a/1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json new file mode 100644 index 0000000..e392806 --- /dev/null +++ b/1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armor stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", + "puzzlesapi.screen.type.alignments": "Alignments", + "puzzlesapi.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java new file mode 100644 index 0000000..346a4a5 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java @@ -0,0 +1,23 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.data.ModLanguageProvider; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(ArmorStatues.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ArmorStatuesForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + evt.getGenerator().addProvider(true, new ModLanguageProvider(evt, ArmorStatues.MOD_ID)); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java new file mode 100644 index 0000000..c50ecce --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ArmorStatuesForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); + registerHandlers(); + } + + private static void registerHandlers() { + MinecraftForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { + + Minecraft minecraft = Minecraft.getInstance(); + if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { + + EntityHitResult hitResult = (EntityHitResult) minecraft.hitResult; + Entity entity = hitResult.getEntity(); + if (minecraft.level.getWorldBorder().isWithinBounds(entity.blockPosition())) { + + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work + if (result.filter(t -> t == InteractionResult.FAIL).isInterrupt()) { + evt.setSwingHand(false); + evt.setCanceled(true); + } + } + } + }); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java new file mode 100644 index 0000000..53b29c2 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -0,0 +1,40 @@ +package fuzs.armorstatues.data; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.puzzleslib.api.data.v1.AbstractLanguageProvider; +import net.minecraftforge.data.event.GatherDataEvent; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(GatherDataEvent evt, String modId) { + super(evt, modId); + } + + @Override + protected void addTranslations() { + // Armor Statues + this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + this.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); + this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); + this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + this.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + this.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu."); + this.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + this.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); + } +} 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..fac0264 --- /dev/null +++ b/1.20.4/Forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,47 @@ +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" + +[[dependencies.${ modId }]] +modId = "puzzlesapi" +mandatory = true +versionRange = "*" +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..29049d3 --- /dev/null +++ b/1.20.4/NeoForge/build.gradle @@ -0,0 +1,38 @@ +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()) + + // Puzzles Api + api(fg.deobf(libs.puzzlesapi.forge.get())) { + transitive = false + } + jarJar(fg.deobf(libs.puzzlesapi.forge.get()) { + jarJar.ranged(it, "[${libs.versions.puzzlesapi.get()},)") + transitive = false + }) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20.4/NeoForge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 new file mode 100644 index 0000000..8e2c24f --- /dev/null +++ b/1.20.4/NeoForge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -0,0 +1,2 @@ +// 1.20.1 2023-07-29T15:02:23.443069 Languages: en_us +9ecbeccea1af534ecf344346c3f5cecde17fd977 assets/armorstatues/lang/en_us.json diff --git a/1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json new file mode 100644 index 0000000..e392806 --- /dev/null +++ b/1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armor stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", + "puzzlesapi.screen.type.alignments": "Alignments", + "puzzlesapi.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java new file mode 100644 index 0000000..346a4a5 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java @@ -0,0 +1,23 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.data.ModLanguageProvider; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(ArmorStatues.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ArmorStatuesForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + evt.getGenerator().addProvider(true, new ModLanguageProvider(evt, ArmorStatues.MOD_ID)); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java new file mode 100644 index 0000000..c50ecce --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ArmorStatuesForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); + registerHandlers(); + } + + private static void registerHandlers() { + MinecraftForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { + + Minecraft minecraft = Minecraft.getInstance(); + if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { + + EntityHitResult hitResult = (EntityHitResult) minecraft.hitResult; + Entity entity = hitResult.getEntity(); + if (minecraft.level.getWorldBorder().isWithinBounds(entity.blockPosition())) { + + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work + if (result.filter(t -> t == InteractionResult.FAIL).isInterrupt()) { + evt.setSwingHand(false); + evt.setCanceled(true); + } + } + } + }); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java new file mode 100644 index 0000000..53b29c2 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java @@ -0,0 +1,40 @@ +package fuzs.armorstatues.data; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.puzzleslib.api.data.v1.AbstractLanguageProvider; +import net.minecraftforge.data.event.GatherDataEvent; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(GatherDataEvent evt, String modId) { + super(evt, modId); + } + + @Override + protected void addTranslations() { + // Armor Statues + this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + this.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); + this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); + this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + this.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + this.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu."); + this.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + this.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + this.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); + } +} 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..fac0264 --- /dev/null +++ b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,47 @@ +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" + +[[dependencies.${ modId }]] +modId = "puzzlesapi" +mandatory = true +versionRange = "*" +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..f4ac86b --- /dev/null +++ b/1.20.4/gradle.properties @@ -0,0 +1,38 @@ +# 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=armorstatues +modName=Armor Statues +modVersion=8.0.5 +modAuthor=Fuzs +modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/armorstatues +modIssueUrl=https://github.com/Fuzss/armorstatues/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/armorstatues.json +modMavenGroup=fuzs.armorstatues +# "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=IGNORE_ALL_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=682566 +projectModrinthId=bbGCtEvb + +dependenciesVersionCatalog=1.20.1-v25 +dependenciesPuzzlesLibVersion=8.1.11 +dependenciesMinPuzzlesLibVersion=8.1.11 +dependenciesPuzzlesApi=8.1.4 +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 zcmb6AV{~QRwml9f72CFLyJFk6ZKq;e729@pY}>YNR8p1vbMJH7ubt# zZR`2@zJD1Ad^Oa6Hk1{VlN1wGR-u;_dyt)+kddaNpM#U8qn@6eX;fldWZ6BspQIa= zoRXcQk)#ENJ`XiXJuK3q0$`Ap92QXrW00Yv7NOrc-8ljOOOIcj{J&cR{W`aIGXJ-` z`ez%Mf7qBi8JgIb{-35Oe>Zh^GIVe-b^5nULQhxRDZa)^4+98@`hUJe{J%R>|LYHA z4K3~Hjcp8_owGF{d~lZVKJ;kc48^OQ+`_2migWY?JqgW&))70RgSB6KY9+&wm<*8 z_{<;(c;5H|u}3{Y>y_<0Z59a)MIGK7wRMX0Nvo>feeJs+U?bt-++E8bu7 zh#_cwz0(4#RaT@xy14c7d<92q-Dd}Dt<*RS+$r0a^=LGCM{ny?rMFjhgxIG4>Hc~r zC$L?-FW0FZ((8@dsowXlQq}ja%DM{z&0kia*w7B*PQ`gLvPGS7M}$T&EPl8mew3In z0U$u}+bk?Vei{E$6dAYI8Tsze6A5wah?d(+fyP_5t4ytRXNktK&*JB!hRl07G62m_ zAt1nj(37{1p~L|m(Bsz3vE*usD`78QTgYIk zQ6BF14KLzsJTCqx&E!h>XP4)bya|{*G7&T$^hR0(bOWjUs2p0uw7xEjbz1FNSBCDb@^NIA z$qaq^0it^(#pFEmuGVS4&-r4(7HLmtT%_~Xhr-k8yp0`$N|y>#$Ao#zibzGi*UKzi zhaV#@e1{2@1Vn2iq}4J{1-ox;7K(-;Sk{3G2_EtV-D<)^Pk-G<6-vP{W}Yd>GLL zuOVrmN@KlD4f5sVMTs7c{ATcIGrv4@2umVI$r!xI8a?GN(R;?32n0NS(g@B8S00-=zzLn z%^Agl9eV(q&8UrK^~&$}{S(6-nEXnI8%|hoQ47P?I0Kd=woZ-pH==;jEg+QOfMSq~ zOu>&DkHsc{?o&M5`jyJBWbfoPBv9Y#70qvoHbZXOj*qRM(CQV=uX5KN+b>SQf-~a8 ziZg}@&XHHXkAUqr)Q{y`jNd7`1F8nm6}n}+_She>KO`VNlnu(&??!(i#$mKOpWpi1 z#WfWxi3L)bNRodhPM~~?!5{TrrBY_+nD?CIUupkwAPGz-P;QYc-DcUoCe`w(7)}|S zRvN)9ru8b)MoullmASwsgKQo1U6nsVAvo8iKnbaWydto4y?#-|kP^%e6m@L`88KyDrLH`=EDx*6>?r5~7Iv~I zr__%SximG(izLKSnbTlXa-ksH@R6rvBrBavt4)>o3$dgztLt4W=!3=O(*w7I+pHY2(P0QbTma+g#dXoD7N#?FaXNQ^I0*;jzvjM}%=+km`YtC%O#Alm| zqgORKSqk!#^~6whtLQASqiJ7*nq?38OJ3$u=Tp%Y`x^eYJtOqTzVkJ60b2t>TzdQ{I}!lEBxm}JSy7sy8DpDb zIqdT%PKf&Zy--T^c-;%mbDCxLrMWTVLW}c=DP2>Td74)-mLl|70)8hU??(2)I@Zyo z2i`q5oyA!!(2xV~gahuKl&L(@_3SP012#x(7P!1}6vNFFK5f*A1xF({JwxSFwA|TM z&1z}!*mZKcUA-v4QzLz&5wS$7=5{M@RAlx@RkJaA4nWVqsuuaW(eDh^LNPPkmM~Al zwxCe@*-^4!ky#iNv2NIIU$CS+UW%ziW0q@6HN3{eCYOUe;2P)C*M`Bt{~-mC%T3%# zEaf)lATO1;uF33x>Hr~YD0Ju*Syi!Jz+x3myVvU^-O>C*lFCKS&=Tuz@>&o?68aF& zBv<^ziPywPu#;WSlTkzdZ9`GWe7D8h<1-v0M*R@oYgS5jlPbgHcx)n2*+!+VcGlYh?;9Ngkg% z=MPD+`pXryN1T|%I7c?ZPLb3bqWr7 zU4bfG1y+?!bw)5Iq#8IqWN@G=Ru%Thxf)#=yL>^wZXSCC8we@>$hu=yrU;2=7>h;5 zvj_pYgKg2lKvNggl1ALnsz2IlcvL;q79buN5T3IhXuJvy@^crqWpB-5NOm{7UVfxmPJ>`?;Tn@qHzF+W!5W{8Z&ZAnDOquw6r4$bv*jM#5lc%3v|c~^ zdqo4LuxzkKhK4Q+JTK8tR_|i6O(x#N2N0Fy5)!_trK&cn9odQu#Vlh1K~7q|rE z61#!ZPZ+G&Y7hqmY;`{XeDbQexC2@oFWY)Nzg@lL3GeEVRxWQlx@0?Zt`PcP0iq@6 zLgc)p&s$;*K_;q0L(mQ8mKqOJSrq$aQYO-Hbssf3P=wC6CvTVHudzJH-Jgm&foBSy zx0=qu$w477lIHk);XhaUR!R-tQOZ;tjLXFH6;%0)8^IAc*MO>Q;J={We(0OHaogG0 zE_C@bXic&m?F7slFAB~x|n#>a^@u8lu;=!sqE*?vq zu4`(x!Jb4F#&3+jQ|ygldPjyYn#uCjNWR)%M3(L!?3C`miKT;~iv_)dll>Q6b+I&c zrlB04k&>mSYLR7-k{Od+lARt~3}Bv!LWY4>igJl!L5@;V21H6dNHIGr+qV551e@yL z`*SdKGPE^yF?FJ|`#L)RQ?LJ;8+={+|Cl<$*ZF@j^?$H%V;jqVqt#2B0yVr}Nry5R z5D?S9n+qB_yEqvdy9nFc+8WxK$XME$3ftSceLb+L(_id5MMc*hSrC;E1SaZYow%jh zPgo#1PKjE+1QB`Of|aNmX?}3TP;y6~0iN}TKi3b+yvGk;)X&i3mTnf9M zuv3qvhErosfZ%Pb-Q>|BEm5(j-RV6Zf^$icM=sC-5^6MnAvcE9xzH@FwnDeG0YU{J zi~Fq?=bi0;Ir=hfOJu8PxC)qjYW~cv^+74Hs#GmU%Cw6?3LUUHh|Yab`spoqh8F@_ zm4bCyiXPx-Cp4!JpI~w!ShPfJOXsy>f*|$@P8L8(oeh#~w z-2a4IOeckn6}_TQ+rgl_gLArS3|Ml(i<`*Lqv6rWh$(Z5ycTYD#Z*&-5mpa}a_zHt z6E`Ty-^L9RK-M*mN5AasoBhc|XWZ7=YRQSvG)3$v zgr&U_X`Ny0)IOZtX}e$wNUzTpD%iF7Rgf?nWoG2J@PsS-qK4OD!kJ?UfO+1|F*|Bo z1KU`qDA^;$0*4mUJ#{EPOm7)t#EdX=Yx1R2T&xlzzThfRC7eq@pX&%MO&2AZVO%zw zS;A{HtJiL=rfXDigS=NcWL-s>Rbv|=)7eDoOVnVI>DI_8x>{E>msC$kXsS}z?R6*x zi(yO`$WN)_F1$=18cbA^5|f`pZA+9DG_Zu8uW?rA9IxUXx^QCAp3Gk1MSdq zBZv;_$W>*-zLL)F>Vn`}ti1k!%6{Q=g!g1J*`KONL#)M{ZC*%QzsNRaL|uJcGB7jD zTbUe%T(_x`UtlM!Ntp&-qu!v|mPZGcJw$mdnanY3Uo>5{oiFOjDr!ZznKz}iWT#x& z?*#;H$`M0VC|a~1u_<(}WD>ogx(EvF6A6S8l0%9U<( zH||OBbh8Tnzz*#bV8&$d#AZNF$xF9F2{_B`^(zWNC}af(V~J+EZAbeC2%hjKz3V1C zj#%d%Gf(uyQ@0Y6CcP^CWkq`n+YR^W0`_qkDw333O<0FoO9()vP^!tZ{`0zsNQx~E zb&BcBU>GTP2svE2Tmd;~73mj!_*V8uL?ZLbx}{^l9+yvR5fas+w&0EpA?_g?i9@A$j*?LnmctPDQG|zJ`=EF}Vx8aMD^LrtMvpNIR*|RHA`ctK*sbG= zjN7Q)(|dGpC}$+nt~bupuKSyaiU}Ws{?Tha@$q}cJ;tvH>+MuPih+B4d$Zbq9$Y*U z)iA(-dK?Ov@uCDq48Zm%%t5uw1GrnxDm7*ITGCEF!2UjA`BqPRiUR`yNq^zz|A3wU zG(8DAnY-GW+PR2&7@In{Sla(XnMz5Rk^*5u4UvCiDQs@hvZXoiziv{6*i?fihVI|( zPrY8SOcOIh9-AzyJ*wF4hq%ojB&Abrf;4kX@^-p$mmhr}xxn#fVU?ydmD=21&S)s*v*^3E96(K1}J$6bi8pyUr-IU)p zcwa$&EAF$0Aj?4OYPcOwb-#qB=kCEDIV8%^0oa567_u6`9+XRhKaBup z2gwj*m#(}=5m24fBB#9cC?A$4CCBj7kanaYM&v754(b%Vl!gg&N)ZN_gO0mv(jM0# z>FC|FHi=FGlEt6Hk6H3!Yc|7+q{&t%(>3n#>#yx@*aS+bw)(2!WK#M0AUD~wID>yG z?&{p66jLvP1;!T7^^*_9F322wJB*O%TY2oek=sA%AUQT75VQ_iY9`H;ZNKFQELpZd z$~M`wm^Y>lZ8+F0_WCJ0T2td`bM+b`)h3YOV%&@o{C#|t&7haQfq#uJJP;81|2e+$ z|K#e~YTE87s+e0zCE2X$df`o$`8tQhmO?nqO?lOuTJ%GDv&-m_kP9X<5GCo1=?+LY z?!O^AUrRb~3F!k=H7Aae5W0V1{KlgH379eAPTwq=2+MlNcJ6NM+4ztXFTwI)g+)&Q7G4H%KH_(}1rq%+eIJ*3$?WwnZxPZ;EC=@`QS@|-I zyl+NYh&G>k%}GL}1;ap8buvF>x^yfR*d+4Vkg7S!aQ++_oNx6hLz6kKWi>pjWGO5k zlUZ45MbA=v(xf>Oeqhg8ctl56y{;uDG?A9Ga5aEzZB80BW6vo2Bz&O-}WAq>(PaV;*SX0=xXgI_SJ< zYR&5HyeY%IW}I>yKu^?W2$~S!pw?)wd4(#6;V|dVoa}13Oiz5Hs6zA zgICc;aoUt$>AjDmr0nCzeCReTuvdD1{NzD1wr*q@QqVW*Wi1zn;Yw1dSwLvTUwg#7 zpp~Czra7U~nSZZTjieZxiu~=}!xgV68(!UmQz@#w9#$0Vf@y%!{uN~w^~U_d_Aa&r zt2l>)H8-+gA;3xBk?ZV2Cq!L71;-tb%7A0FWziYwMT|#s_Ze_B>orZQWqDOZuT{|@ zX04D%y&8u@>bur&*<2??1KnaA7M%%gXV@C3YjipS4|cQH68OSYxC`P#ncvtB%gnEI z%fxRuH=d{L70?vHMi>~_lhJ@MC^u#H66=tx?8{HG;G2j$9@}ZDYUuTetwpvuqy}vW)kDmj^a|A%z(xs7yY2mU0#X2$un&MCirr|7 z%m?8+9aekm0x5hvBQ2J+>XeAdel$cy>J<6R3}*O^j{ObSk_Ucv$8a3_WPTd5I4HRT z(PKP5!{l*{lk_19@&{5C>TRV8_D~v*StN~Pm*(qRP+`1N12y{#w_fsXrtSt={0hJw zQ(PyWgA;;tBBDql#^2J(pnuv;fPn(H>^d<6BlI%00ylJZ?Evkh%=j2n+|VqTM~EUh zTx|IY)W;3{%x(O{X|$PS&x0?z#S2q-kW&G}7#D?p7!Q4V&NtA_DbF~v?cz6_l+t8e zoh1`dk;P-%$m(Ud?wnoZn0R=Ka$`tnZ|yQ-FN!?!9Wmb^b(R!s#b)oj9hs3$p%XX9DgQcZJE7B_dz0OEF6C zx|%jlqj0WG5K4`cVw!19doNY+(;SrR_txAlXxf#C`uz5H6#0D>SzG*t9!Fn|^8Z8; z1w$uiQzufUzvPCHXhGma>+O327SitsB1?Rn6|^F198AOx}! zfXg22Lm0x%=gRvXXx%WU2&R!p_{_1H^R`+fRO2LT%;He@yiekCz3%coJ=8+Xbc$mN zJ;J7*ED|yKWDK3CrD?v#VFj|l-cTgtn&lL`@;sMYaM1;d)VUHa1KSB5(I54sBErYp z>~4Jz41?Vt{`o7T`j=Se{-kgJBJG^MTJ}hT00H%U)pY-dy!M|6$v+-d(CkZH5wmo1 zc2RaU`p3_IJ^hf{g&c|^;)k3zXC0kF1>rUljSxd}Af$!@@R1fJWa4g5vF?S?8rg=Z z4_I!$dap>3l+o|fyYy(sX}f@Br4~%&&#Z~bEca!nMKV zgQSCVC!zw^j<61!7#T!RxC6KdoMNONcM5^Q;<#~K!Q?-#6SE16F*dZ;qv=`5 z(kF|n!QIVd*6BqRR8b8H>d~N@ab+1+{3dDVPVAo>{mAB#m&jX{usKkCg^a9Fef`tR z?M79j7hH*;iC$XM)#IVm&tUoDv!(#f=XsTA$)(ZE37!iu3Gkih5~^Vlx#<(M25gr@ zOkSw4{l}6xI(b0Gy#ywglot$GnF)P<FQt~9ge1>qp8Q^k;_Dm1X@Tc^{CwYb4v_ld}k5I$&u}avIDQ-D(_EP zhgdc{)5r_iTFiZ;Q)5Uq=U73lW%uYN=JLo#OS;B0B=;j>APk?|!t{f3grv0nv}Z%` zM%XJk^#R69iNm&*^0SV0s9&>cl1BroIw*t3R0()^ldAsq)kWcI=>~4!6fM#0!K%TS ziZH=H%7-f=#-2G_XmF$~Wl~Um%^9%AeNSk)*`RDl##y+s)$V`oDlnK@{y+#LNUJp1^(e89sed@BB z^W)sHm;A^9*RgQ;f(~MHK~bJRvzezWGr#@jYAlXIrCk_iiUfC_FBWyvKj2mBF=FI;9|?0_~=E<)qnjLg9k*Qd!_ zl}VuSJB%#M>`iZm*1U^SP1}rkkI};91IRpZw%Hb$tKmr6&H5~m?A7?+uFOSnf)j14 zJCYLOYdaRu>zO%5d+VeXa-Ai7{7Z}iTn%yyz7hsmo7E|{ z@+g9cBcI-MT~2f@WrY0dpaC=v{*lDPBDX}OXtJ|niu$xyit;tyX5N&3pgmCxq>7TP zcOb9%(TyvOSxtw%Y2+O&jg39&YuOtgzn`uk{INC}^Na_-V;63b#+*@NOBnU{lG5TS zbC+N-qt)u26lggGPcdrTn@m+m>bcrh?sG4b(BrtdIKq3W<%?WuQtEW0Z)#?c_Lzqj*DlZ zVUpEV3~mG#DN$I#JJp3xc8`9ex)1%Il7xKwrpJt)qtpq}DXqI=5~~N}N?0g*YwETZ z(NKJO5kzh?Os`BQ7HYaTl>sXVr!b8>(Wd&PU*3ivSn{;q`|@n*J~-3tbm;4WK>j3&}AEZ*`_!gJ3F4w~4{{PyLZklDqWo|X}D zbZU_{2E6^VTCg#+6yJt{QUhu}uMITs@sRwH0z5OqM>taO^(_+w1c ztQ?gvVPj<_F_=(ISaB~qML59HT;#c9x(;0vkCi2#Zp`;_r@+8QOV1Ey2RWm6{*J&9 zG(Dt$zF^7qYpo9Ne}ce5re^j|rvDo*DQ&1Be#Fvo#?m4mfFrNZb1#D4f`Lf(t_Fib zwxL3lx(Zp(XVRjo_ocElY#yS$LHb6yl;9;Ycm1|5y_praEcGUZxLhS%7?b&es2skI z9l!O)b%D=cXBa@v9;64f^Q9IV$xOkl;%cG6WLQ`_a7I`woHbEX&?6NJ9Yn&z+#^#! zc8;5=jt~Unn7!cQa$=a7xSp}zuz#Lc#Q3-e7*i`Xk5tx_+^M~!DlyBOwVEq3c(?`@ zZ_3qlTN{eHOwvNTCLOHjwg0%niFYm({LEfAieI+k;U2&uTD4J;Zg#s`k?lxyJN<$mK6>j?J4eOM@T*o?&l@LFG$Gs5f4R*p*V1RkTdCfv9KUfa< z{k;#JfA3XA5NQJziGd%DchDR*Dkld&t;6i9e2t7{hQPIG_uDXN1q0T;IFCmCcua-e z`o#=uS2_en206(TuB4g-!#=rziBTs%(-b1N%(Bl}ea#xKK9zzZGCo@<*i1ZoETjeC zJ)ll{$mpX7Eldxnjb1&cB6S=7v@EDCsmIOBWc$p^W*;C0i^Hc{q(_iaWtE{0qbLjxWlqBe%Y|A z>I|4)(5mx3VtwRBrano|P))JWybOHUyOY67zRst259tx;l(hbY@%Z`v8Pz^0Sw$?= zwSd^HLyL+$l&R+TDnbV_u+h{Z>n$)PMf*YGQ}1Df@Nr{#Gr+@|gKlnv?`s1rm^$1+ zic`WeKSH?{+E}0^#T<&@P;dFf;P5zCbuCOijADb}n^{k=>mBehDD6PtCrn5ZBhh2L zjF$TbzvnwT#AzGEG_Rg>W1NS{PxmL9Mf69*?YDeB*pK!&2PQ7!u6eJEHk5e(H~cnG zZQ?X_rtws!;Tod88j=aMaylLNJbgDoyzlBv0g{2VYRXObL=pn!n8+s1s2uTwtZc

YH!Z*ZaR%>WTVy8-(^h5J^1%NZ$@&_ZQ)3AeHlhL~=X9=fKPzFbZ;~cS**=W-LF1 z5F82SZ zG8QZAet|10U*jK*GVOA(iULStsUDMjhT$g5MRIc4b8)5q_a?ma-G+@xyNDk{pR*YH zjCXynm-fV`*;}%3=+zMj**wlCo6a{}*?;`*j%fU`t+3Korws%dsCXAANKkmVby*eJ z6`2%GB{+&`g2;snG`LM9S~>#^G|nZ|JMnWLgSmJ4!kB->uAEF0sVn6km@s=#_=d)y zzld%;gJY>ypQuE z!wgqqTSPxaUPoG%FQ()1hz(VHN@5sfnE68of>9BgGsQP|9$7j zGqN{nxZx4CD6ICwmXSv6&RD<-etQmbyTHIXn!Q+0{18=!p))>To8df$nCjycnW07Q zsma_}$tY#Xc&?#OK}-N`wPm)+2|&)9=9>YOXQYfaCI*cV1=TUl5({a@1wn#V?y0Yn z(3;3-@(QF|0PA}|w4hBWQbTItc$(^snj$36kz{pOx*f`l7V8`rZK}82pPRuy zxwE=~MlCwOLRC`y%q8SMh>3BUCjxLa;v{pFSdAc7m*7!}dtH`MuMLB)QC4B^Uh2_? zApl6z_VHU}=MAA9*g4v-P=7~3?Lu#ig)cRe90>@B?>})@X*+v&yT6FvUsO=p#n8p{ zFA6xNarPy0qJDO1BPBYk4~~LP0ykPV ztoz$i+QC%Ch%t}|i^(Rb9?$(@ijUc@w=3F1AM}OgFo1b89KzF6qJO~W52U_;R_MsB zfAC29BNUXpl!w&!dT^Zq<__Hr#w6q%qS1CJ#5Wrb*)2P1%h*DmZ?br)*)~$^TExX1 zL&{>xnM*sh=@IY)i?u5@;;k6+MLjx%m(qwDF3?K3p>-4c2fe(cIpKq#Lc~;#I#Wwz zywZ!^&|9#G7PM6tpgwA@3ev@Ev_w`ZZRs#VS4}<^>tfP*(uqLL65uSi9H!Gqd59C&=LSDo{;#@Isg3caF1X+4T}sL2B+Q zK*kO0?4F7%8mx3di$B~b&*t7y|{x%2BUg4kLFXt`FK;Vi(FIJ+!H zW;mjBrfZdNT>&dDfc4m$^f@k)mum{DioeYYJ|XKQynXl-IDs~1c(`w{*ih0-y_=t$ zaMDwAz>^CC;p*Iw+Hm}%6$GN49<(rembdFvb!ZyayLoqR*KBLc^OIA*t8CXur+_e0 z3`|y|!T>7+jdny7x@JHtV0CP1jI^)9){!s#{C>BcNc5#*hioZ>OfDv)&PAM!PTjS+ zy1gRZirf>YoGpgprd?M1k<;=SShCMn406J>>iRVnw9QxsR|_j5U{Ixr;X5n$ih+-=X0fo(Oga zB=uer9jc=mYY=tV-tAe@_d-{aj`oYS%CP@V3m6Y{)mZ5}b1wV<9{~$`qR9 zEzXo|ok?1fS?zneLA@_C(BAjE_Bv7Dl2s?=_?E9zO5R^TBg8Be~fpG?$9I; zDWLH9R9##?>ISN8s2^wj3B?qJxrSSlC6YB}Yee{D3Ex8@QFLZ&zPx-?0>;Cafcb-! zlGLr)wisd=C(F#4-0@~P-C&s%C}GvBhb^tTiL4Y_dsv@O;S56@?@t<)AXpqHx9V;3 zgB!NXwp`=%h9!L9dBn6R0M<~;(g*nvI`A@&K!B`CU3^FpRWvRi@Iom>LK!hEh8VjX z_dSw5nh-f#zIUDkKMq|BL+IO}HYJjMo=#_srx8cRAbu9bvr&WxggWvxbS_Ix|B}DE zk!*;&k#1BcinaD-w#E+PR_k8I_YOYNkoxw5!g&3WKx4{_Y6T&EV>NrnN9W*@OH+niSC0nd z#x*dm=f2Zm?6qhY3}Kurxl@}d(~ z<}?Mw+>%y3T{!i3d1%ig*`oIYK|Vi@8Z~*vxY%Od-N0+xqtJ*KGrqo*9GQ14WluUn z+%c+og=f0s6Mcf%r1Be#e}&>1n!!ZxnWZ`7@F9ymfVkuFL;m6M5t%6OrnK#*lofS{ z=2;WPobvGCu{(gy8|Mn(9}NV99Feps6r*6s&bg(5aNw$eE ztbYsrm0yS`UIJ?Kv-EpZT#76g76*hVNg)L#Hr7Q@L4sqHI;+q5P&H{GBo1$PYkr@z zFeVdcS?N1klRoBt4>fMnygNrDL!3e)k3`TXoa3#F#0SFP(Xx^cc)#e2+&z9F=6{qk z%33-*f6=+W@baq){!d_;ouVthV1PREX^ykCjD|%WUMnNA2GbA#329aEihLk~0!!}k z)SIEXz(;0lemIO{|JdO{6d|-9LePs~$}6vZ>`xYCD(ODG;OuwOe3jeN;|G$~ml%r* z%{@<9qDf8Vsw581v9y+)I4&te!6ZDJMYrQ*g4_xj!~pUu#er`@_bJ34Ioez)^055M$)LfC|i*2*3E zLB<`5*H#&~R*VLYlNMCXl~=9%o0IYJ$bY+|m-0OJ-}6c@3m<~C;;S~#@j-p?DBdr<><3Y92rW-kc2C$zhqwyq09;dc5;BAR#PPpZxqo-@e_s9*O`?w5 zMnLUs(2c-zw9Pl!2c#+9lFpmTR>P;SA#Id;+fo|g{*n&gLi}7`K)(=tcK|?qR4qNT z%aEsSCL0j9DN$j8g(a+{Z-qPMG&O)H0Y9!c*d?aN0tC&GqC+`%(IFY$ll~!_%<2pX zuD`w_l)*LTG%Qq3ZSDE)#dt-xp<+n=3&lPPzo}r2u~>f8)mbcdN6*r)_AaTYq%Scv zEdwzZw&6Ls8S~RTvMEfX{t@L4PtDi{o;|LyG>rc~Um3;x)rOOGL^Bmp0$TbvPgnwE zJEmZ>ktIfiJzdW5i{OSWZuQWd13tz#czek~&*?iZkVlLkgxyiy^M~|JH(?IB-*o6% zZT8+svJzcVjcE0UEkL_5$kNmdrkOl3-`eO#TwpTnj?xB}AlV2`ks_Ua9(sJ+ok|%b z=2n2rgF}hvVRHJLA@9TK4h#pLzw?A8u31&qbr~KA9;CS7aRf$^f1BZ5fsH2W8z}FU zC}Yq76IR%%g|4aNF9BLx6!^RMhv|JYtoZW&!7uOskGSGL+}_>L$@Jg2Vzugq-NJW7 zzD$7QK7cftU1z*Fxd@}wcK$n6mje}=C|W)tm?*V<<{;?8V9hdoi2NRm#~v^#bhwlc z5J5{cSRAUztxc6NH>Nwm4yR{(T>0x9%%VeU&<&n6^vFvZ{>V3RYJ_kC9zN(M(` zp?1PHN>f!-aLgvsbIp*oTZv4yWsXM2Q=C}>t7V(iX*N8{aoWphUJ^(n3k`pncUt&` ze+sYjo)>>=I?>X}1B*ZrxYu`|WD0J&RIb~ zPA_~u)?&`}JPwc1tu=OlKlJ3f!9HXa)KMb|2%^~;)fL>ZtycHQg`j1Vd^nu^XexYkcae@su zOhxk8ws&Eid_KAm_<}65zbgGNzwshR#yv&rQ8Ae<9;S^S}Dsk zubzo?l{0koX8~q*{uA%)wqy*Vqh4>_Os7PPh-maB1|eT-4 zK>*v3q}TBk1QlOF!113XOn(Kzzb5o4Dz@?q3aEb9%X5m{xV6yT{;*rnLCoI~BO&SM zXf=CHLI>kaSsRP2B{z_MgbD;R_yLnd>^1g`l;uXBw7|)+Q_<_rO!!VaU-O+j`u%zO z1>-N8OlHDJlAqi2#z@2yM|Dsc$(nc>%ZpuR&>}r(i^+qO+sKfg(Ggj9vL%hB6 zJ$8an-DbmKBK6u6oG7&-c0&QD#?JuDYKvL5pWXG{ztpq3BWF)e|7aF-(91xvKt047 zvR{G@KVKz$0qPNXK*gt*%qL-boz-*E;7LJXSyj3f$7;%5wj)2p8gvX}9o_u}A*Q|7 z)hjs?k`8EOxv1zahjg2PQDz5pYF3*Cr{%iUW3J+JU3P+l?n%CwV;`noa#3l@vd#6N zc#KD2J;5(Wd1BP)`!IM;L|(d9m*L8QP|M7W#S7SUF3O$GFnWvSZOwC_Aq~5!=1X+s z6;_M++j0F|x;HU6kufX-Ciy|du;T%2@hASD9(Z)OSVMsJg+=7SNTAjV<8MYN-zX5U zVp~|N&{|#Z)c6p?BEBBexg4Q((kcFwE`_U>ZQotiVrS-BAHKQLr87lpmwMCF_Co1M z`tQI{{7xotiN%Q~q{=Mj5*$!{aE4vi6aE$cyHJC@VvmemE4l_v1`b{)H4v7=l5+lm^ ztGs>1gnN(Vl+%VuwB+|4{bvdhCBRxGj3ady^ zLxL@AIA>h@eP|H41@b}u4R`s4yf9a2K!wGcGkzUe?!21Dk)%N6l+#MP&}B0%1Ar*~ zE^88}(mff~iKMPaF+UEp5xn(gavK(^9pvsUQT8V;v!iJt|7@&w+_va`(s_57#t?i6 zh$p!4?BzS9fZm+ui`276|I307lA-rKW$-y^lK#=>N|<-#?WPPNs86Iugsa&n{x%*2 zzL_%$#TmshCw&Yo$Ol?^|hy{=LYEUb|bMMY`n@#(~oegs-nF){0ppwee|b{ca)OXzS~01a%cg&^ zp;}mI0ir3zapNB)5%nF>Sd~gR1dBI!tDL z&m24z9sE%CEv*SZh1PT6+O`%|SG>x74(!d!2xNOt#C5@I6MnY%ij6rK3Y+%d7tr3&<^4XU-Npx{^`_e z9$-|@$t`}A`UqS&T?cd@-+-#V7n7tiZU!)tD8cFo4Sz=u65?f#7Yj}MDFu#RH_GUQ z{_-pKVEMAQ7ljrJ5Wxg4*0;h~vPUI+Ce(?={CTI&(RyX&GVY4XHs>Asxcp%B+Y9rK z5L$q94t+r3=M*~seA3BO$<0%^iaEb2K=c7((dIW$ggxdvnC$_gq~UWy?wljgA0Dwd`ZsyqOC>)UCn-qU5@~!f znAWKSZeKRaq#L$3W21fDCMXS;$X(C*YgL7zi8E|grQg%Jq8>YTqC#2~ys%Wnxu&;ZG<`uZ1L<53jf2yxYR3f0>a;%=$SYI@zUE*g7f)a{QH^<3F?%({Gg)yx^zsdJ3^J2 z#(!C3qmwx77*3#3asBA(jsL`86|OLB)j?`0hQIh>v;c2A@|$Yg>*f+iMatg8w#SmM z<;Y?!$L--h9vH+DL|Wr3lnfggMk*kyGH^8P48or4m%K^H-v~`cBteWvnN9port02u zF;120HE2WUDi@8?&Oha6$sB20(XPd3LhaT~dRR2_+)INDTPUQ9(-370t6a!rLKHkIA`#d-#WUcqK%pMcTs6iS2nD?hln+F-cQPUtTz2bZ zq+K`wtc1;ex_iz9?S4)>Fkb~bj0^VV?|`qe7W02H)BiibE9=_N8=(5hQK7;(`v7E5Mi3o? z>J_)L`z(m(27_&+89P?DU|6f9J*~Ih#6FWawk`HU1bPWfdF?02aY!YSo_!v$`&W znzH~kY)ll^F07=UNo|h;ZG2aJ<5W~o7?*${(XZ9zP0tTCg5h-dNPIM=*x@KO>a|Bk zO13Cbnbn7+_Kj=EEMJh4{DW<))H!3)vcn?_%WgRy=FpIkVW>NuV`knP`VjT78dqzT z>~ay~f!F?`key$EWbp$+w$8gR1RHR}>wA8|l9rl7jsT+>sQLqs{aITUW{US&p{Y)O zRojdm|7yoA_U+`FkQkS?$4$uf&S52kOuUaJT9lP@LEqjKDM)iqp9aKNlkpMyJ76eb zAa%9G{YUTXa4c|UE>?CCv(x1X3ebjXuL&9Dun1WTlw@Wltn3zTareM)uOKs$5>0tR zDA~&tM~J~-YXA<)&H(ud)JyFm+d<97d8WBr+H?6Jn&^Ib0<{6ov- ze@q`#Y%KpD?(k{if5-M(fO3PpK{Wjqh)7h+ojH ztb=h&vmy0tn$eA8_368TlF^DKg>BeFtU%3|k~3lZAp(C$&Qjo9lR<#rK{nVn$)r*y z#58_+t=UJm7tp|@#7}6M*o;vn7wM?8Srtc z3ZFlKRDYc^HqI!O9Z*OZZ8yo-3ie9i8C%KDYCfE?`rjrf(b&xBXub!54yaZY2hFi2w2asEOiO8;Hru4~KsqQZMrs+OhO8WMX zFN0=EvME`WfQ85bmsnPFp|RU;GP^&Ik#HV(iR1B}8apb9W9)Nv#LwpED~%w67o;r! zVzm@zGjsl)loBy6p>F(G+#*b|7BzZbV#E0Pi`02uAC}D%6d12TzOD19-9bhZZT*GS zqY|zxCTWn+8*JlL3QH&eLZ}incJzgX>>i1dhff}DJ=qL{d?yv@k33UhC!}#hC#31H zOTNv5e*ozksj`4q5H+75O70w4PoA3B5Ea*iGSqA=v)}LifPOuD$ss*^W}=9kq4qqd z6dqHmy_IGzq?j;UzFJ*gI5)6qLqdUL;G&E*;lnAS+ZV1nO%OdoXqw(I+*2-nuWjwM-<|XD541^5&!u2 z1XflFJp(`^D|ZUECbaoqT5$#MJ=c23KYpBjGknPZ7boYRxpuaO`!D6C_Al?T$<47T zFd@QT%860pwLnUwer$BspTO9l1H`fknMR|GC?@1Wn`HscOe4mf{KbVio zahne0&hJd0UL#{Xyz=&h@oc>E4r*T|PHuNtK6D279q!2amh%r#@HjaN_LT4j>{&2I z?07K#*aaZ?lNT6<8o85cjZoT~?=J&Xd35I%JJom{P=jj?HQ5yfvIR8bd~#7P^m%B-szS{v<)7i?#at=WA+}?r zwMlc-iZv$GT};AP4k2nL70=Q-(+L_CYUN{V?dnvG-Av+%)JxfwF4-r^Z$BTwbT!Jh zG0YXK4e8t`3~){5Qf6U(Ha0WKCKl^zlqhqHj~F}DoPV#yHqLu+ZWlv2zH29J6}4amZ3+-WZkR7(m{qEG%%57G!Yf&!Gu~FDeSYmNEkhi5nw@#6=Bt& zOKT!UWVY-FFyq1u2c~BJ4F`39K7Vw!1U;aKZw)2U8hAb&7ho|FyEyP~D<31{_L>RrCU>eEk-0)TBt5sS5?;NwAdRzRj5qRSD?J6 ze9ueq%TA*pgwYflmo`=FnGj2r_u2!HkhE5ZbR_Xf=F2QW@QTLD5n4h(?xrbOwNp5` zXMEtm`m52{0^27@=9VLt&GI;nR9S)p(4e+bAO=e4E;qprIhhclMO&7^ThphY9HEko z#WfDFKKCcf%Bi^umN({q(avHrnTyPH{o=sXBOIltHE?Q65y_At<9DsN*xWP|Q=<|R z{JfV?B5dM9gsXTN%%j;xCp{UuHuYF;5=k|>Q=;q zU<3AEYawUG;=%!Igjp!FIAtJvoo!*J^+!oT%VI4{P=XlbYZl;Dc467Nr*3j zJtyn|g{onj!_vl)yv)Xv#}(r)@25OHW#|eN&q7_S4i2xPA<*uY9vU_R7f};uqRgVb zM%<_N3ys%M;#TU_tQa#6I1<+7Bc+f%mqHQ}A@(y^+Up5Q*W~bvS9(21FGQRCosvIX zhmsjD^OyOpae*TKs=O?(_YFjSkO`=CJIb*yJ)Pts1egl@dX6-YI1qb?AqGtIOir&u zyn>qxbJhhJi9SjK+$knTBy-A)$@EfzOj~@>s$M$|cT5V!#+|X`aLR_gGYmNuLMVH4 z(K_Tn;i+fR28M~qv4XWqRg~+18Xb?!sQ=Dy)oRa)Jkl{?pa?66h$YxD)C{F%EfZt| z^qWFB2S_M=Ryrj$a?D<|>-Qa5Y6RzJ$6Yp`FOy6p2lZSjk%$9guVsv$OOT*6V$%TH zMO}a=JR(1*u`MN8jTn|OD!84_h${A)_eFRoH7WTCCue9X73nbD282V`VzTH$ckVaC zalu%ek#pHxAx=0migDNXwcfbK3TwB7@T7wx2 zGV7rS+2g9eIT9>uWfao+lW2Qi9L^EBu#IZSYl0Q~A^KYbQKwNU(YO4Xa1XH_>ml1v z#qS;P!3Lt%2|U^=++T`A!;V-!I%upi?<#h~h!X`p7eP!{+2{7DM0$yxi9gBfm^W?M zD1c)%I7N>CG6250NW54T%HoCo^ud#`;flZg_4ciWuj4a884oWUYV(#VW`zO1T~m(_ zkayymAJI)NU9_0b6tX)GU+pQ3K9x=pZ-&{?07oeb1R7T4RjYYbfG^>3Y>=?dryJq& zw9VpqkvgVB?&aK}4@m78NQhTqZeF=zUtBkJoz8;6LO<4>wP7{UPEs1tP69;v919I5 zzCqXUhfi~FoK5niVU~hQqAksPsD@_|nwH4avOw67#fb@Z5_OS=$eP%*TrPU%HG<-A z`9)Y3*SAdfiqNTJ2eKj8B;ntdqa@U46)B+odlH)jW;U{A*0sg@z>-?;nN}I=z3nEE@Bf3kh1B zdqT{TWJvb#AT&01hNsBz8v(OwBJSu#9}A6Y!lv|`J#Z3uVK1G`0$J&OH{R?3YVfk% z9P3HGpo<1uy~VRCAe&|c4L!SR{~^0*TbVtqej3ARx(Okl5c>m~|H9ZwKVHc_tCe$hsqA`l&h7qPP5xBgtwu!; zzQyUD<6J!M5fsV-9P?C9P49qnXR+iXt#G_AS2N<6!HZ(eS`|-ndb|y!(0Y({2 z4aF~GO8bHM7s+wnhPz>sa!Z%|!qWk*DGr)azB}j6bLe#FQXV4aO>Eo7{v`0x=%5SY zy&{kY+VLXni6pPJYG_Sa*9hLy-s$79$zAhkF)r?9&?UaNGmY9F$uf>iJ~u@Q;sydU zQaN7B>4B*V;rtl^^pa3nFh$q*c&sx^Um}I)Z)R&oLEoWi3;Yv6za?;7m?fZe>#_mS z-EGInS^#UHdOzCaMRSLh7Mr0}&)WCuw$4&K^lx{;O+?Q1p5PD8znQ~srGrygJ?b~Q5hIPt?Wf2)N?&Dae4%GRcRKL(a-2koctrcvxSslXn-k9cYS|<-KJ#+$Wo>}yKKh*3Q zHsK(4-Jv!9R3*FKmN$Z#^aZcACGrlGjOe^#Z&DfPyS-1bT9OIX~-I-5lN6Y>M}dvivbs2BcbPcaNH%25-xMkT$>*soDJ) z27;};8oCYHSLF0VawZFn8^H;hIN=J457@eoI6s2P87QN6O`q8coa;PN$mRZ>2Vv+! zQj1}Tvp8?>yyd_U>dnhx%q~k*JR`HO=43mB?~xKAW9Z}Vh2b0<(T89%eZ z57kGs@{NUHM>|!+QtqI@vE8hp`IIGc`A9Y{p?c;@a!zJFmdaCJ;JmzOJ8)B1x{yZp zi!U{Wh-h+u6vj`2F+(F6gTv*cRX7MR z9@?>is`MSS1L#?PaW6BWEd#EX4+O1x6WdU~LZaQ^Quow~ybz*aAu{ZMrQ;yQ8g)-qh>x z^}@eFu1u7+3C0|hRMD1{MEn(JOmJ|wYHqGyn*xt-Y~J3j@nY56i)sgNjS4n@Q&p@@^>HQjzNaw#C9=TbwzDtiMr2a^}bX< zZE%HU^|CnS`WYVcs}D)+fP#bW0+Q#l#JC+!`OlhffKUCN8M-*CqS;VQX`If78$as0 z=$@^NFcDpTh~45heE63=x5nmP@4hBaFn(rmTY2Yj{S&k;{4W!0Nu9O5pK30}oxM7{ z>l4cKb~9D?N#u_AleD<~8XD@23sY^rt&fN%Q0L=Ti2bV#px`RhM$}h*Yg-iC4A+rI zV~@yY7!1}-@onsZ)@0tUM23cN-rXrZYWF#!V-&>vds8rP+w0t{?~Q zT^LN*lW==+_ifPb+-yMh9JhfcYiXo_zWa`ObRP9_En3P))Qyu0qPJ3*hiFSu>Vt-j z<*HWbiP2#BK@nt<g|pe3 zfBKS@i;ISkorx@cOIx9}p^d8Gis%$)))%ByVYU^KG#eE+j1p;^(Y1ndHnV&YuQZm~ zj;f+mf>0ru!N`)_p@Ls<& z`t+JDx7}R568Q|8`4A}G@t8Wc?SOXunyW5C-AWoB@P>r}uwFY*=?=!K@J(!t@#xOuPXhFS@FTf6-7|%k;nw2%Z+iHl219Ho1!bv(Ee0|ao!Rs%Jl0@3suGrOsb_@VM;(xzrf^Cbd;CK3b%a|ih-fG)`Rd00O74=sQYW~Ve z#fl!*(fo~SIQ5-Sl?1@o7-E*|SK|hoVEKzxeg!$KmQLSTN=5N`rYeh$AH&x}JMR+5dq|~FUy&Oj%QIy;HNr;V*7cQC+ka>LAwdU)?ubI@W z={eg%A&7D**SIj$cu=CN%vN^(_JeIHMUyejCrO%C3MhOcVL~Niu;8WYoN}YVhb+=- zR}M3p|H0`E2Id99y#03r`8$s0t*iD>`^7EPm1~guC)L~uW#O~>I85Q3Nj8(sG<@T| zL^e~XQt9O0AXQ^zkMdgzk5bdYttP~nf-<831zulL>>ghTFii$lg3^80t8Gb*x1w5| zN{kZuv`^8Fj=t(T*46M=S$6xY@0~AvWaGOYOBTl0?}KTkplmGn-*P(X=o-v^48OY} zi11-+Y}y)fdy_tI;*W(>#qzvgQZ52t!nrGsJEy!c86TKIN(n|!&ucCduG$XaIapI z{(Z9gZANsI={A=5Aorgq2H25Dd}H5@-5=j=s{f`%^>6b5qkm_2|3g>r-^amf=B_xV zXg*>aqxXZ6=VUI4$})ypDMy$IKkgJ;V>077T9o#OhpFhKtHP_4mnjS5QCgGe<;~Xe zt<2ZhL7?JL6Mi|U_w?;?@4OD@=4EB2op_s)N-ehm#7`zSU#7itU$#%^ncqjc`9HCG zfj;O1T+*oTkzRi-6NN`oS3w3$7ZB37L>PcN$C$L^qqHfiYO4_>0_qCw0r@FEMj=>}}%q_`d#pUT;c?=gI zqTGpiY4Z;Q(B~#hXIVBFbi#dO=cOdmOqD0|An?7nMdrm2^C>yw*dQ=#lf8)@DvXK; z$MXp}QZgnE!&L73x0LZX_bCdD4lRY$$^?9dt1RwCng{lIpbb%Ej%yOh{@76yEyb}K zXZy%^656Sk3BLKbalcc>Dt5iDzo^tj2!wnDL(X;urJfpkWrab!frFSC6Q7m zuoqN!(t=L&+Ov&~9mz(yEB`MK%RPXS>26Ww5(F;aZ zR@tPAw~=q2ioOiynxgBqE&3-R-@6yCo0*mE;#I^c!=g~HyyjGA6}|<(0EseKDTM4w z94YnCO^VYIUY@}x8kr;;El-cFHVO<$6;-UdmUB|J8R*Wf$a37gVgYT|w5^KkYe=(i zMkA$%7;^a*$V+}e%S~&*^^O;AX9NLt@cIPc*v!lKZ)(zahAsUj%PJot19ErFU=Uk( z9Hw;Lb`V+BzVpMu;TGB9}y~ff)^mbEmF?g{{7_0SR zPgp*n)l{?>7-Ji;eWG{ln$)Bro+UJAQo6W2-23d@SI=HiFV3hR2OUcAq_9q~ye)o@ zq8WZvhg`H(?1AUZ-NM%_Cuj}eb{4wOCnqs^E1G9U4HKjqaw@4dsXWP#$wx^}XPZ0F zywsJ0aJHA>AHc^q#nhQjD3!KDFT6FaDioJ#HsZU7Wo?8WH19TJ%OMDz$XH5J4Cjdt z@crE;#JNG`&1H8ekB(R4?QiiZ55kztsx}pQti}gG0&8`dP=d(8aCLOExd*Sw^WL`Q zHvZ(u`5A58h?+G&GVsA;pQNNPFI)U@O`#~RjaG(6Y<=gKT2?1 z*pCUGU)f??VlyP64P@uT`qh?L03ZQyLOBn?EKwH+IG{XvTh5|NldaSV_n~DK&F1aa znq~C_lCQHMfW6xib%a2m!h&%J)aXb{%-0!HCcW|kzaoSwPMhJ6$KL|F~Sx(tctbwfkgV;#KZlEmJN5&l5XF9eD;Kqb<| z>os)CqC^qF8$be|v;)LY{Gh@c0?a??k7M7&9CH+-B)t&T$xeSzCs30sf8O-+I#rq} z&kZj5&i>UyK9lDjI<*TLZ3USVwwpiE5x8<|{Db z3`HX3+Tt>1hg?+uY{^wC$|Tb7ud@3*Ub?=2xgztgv6OOz0G z-4VRyIChHfegUak^-)-P;VZY@FT64#xyo=+jG<48n2%wcx`ze6yd51(!NclmN=$*kY=#uu#>=yAU-u4I9Bt0n_6ta?&9jN+tM_5_3RH);I zxTN4n$EhvKH%TmOh5mq|?Cx$m>$Ed?H7hUEiRW^lnW+}ZoN#;}aAuy_n189qe1Juk z6;QeZ!gdMAEx4Na;{O*j$3F3e?FLAYuJ2iuMbWf8Ub6(nDo?zI5VNhN@ib6Yw_4P)GY^0M7TJwat z2S*2AcP}e0tibZ@k&htTD&yxT9QRG0CEq$;obfgV^&6YVX9B9|VJf`1aS_#Xk>DFo zwhk?~)>XlP5(u~UW0hP7dWZuCuN4QM24Td&j^7~)WQ6YeCg)njG*ri}tTcG-NxX}p zNB>kcxd5ipW@tN3=6r@Jgm#rgrK*dXA!gxy6fAvP7$)8)Vc~PPQ|`( zPy|bG1sUz958-!zW^j(8ILV%QC@x`~PDFczboZqWjvSU<9O3!TQ&xYi%?Y0AiVBLV z%R?#1L#G&xw*RZPsrwF?)B5+MSM(b$L;GLnRsSU!_$N;6pD97~H}`c>0F`&E_FCNE z_)Q*EA1%mOp`z>+h&aqlLKUD9*w?D>stDeBRdR*AS9)u;ABm7w1}eE|>YH>YtMyBR z^e%rPeZzBx_hj?zhJVNRM_PX(O9N#^ngmIJ0W@A)PRUV7#2D!#3vyd}ADuLry;jdn zSsTsHfQ@6`lH z^GWQf?ANJS>bBO-_obBL$Apvakhr1e5}l3axEgcNWRN$4S6ByH+viK#CnC1|6Xqj& z*_i7cullAJKy9GBAkIxUIzsmN=M|(4*WfBhePPHp?55xfF}yjeBld7+A7cQPX8PE-|Pe_xqboE;2AJb5ifrEfr86k&F0+y!r`-urW}OXSkfz2;E``UTrGSt^B)7&#RSLTQitk=mmPKUKP`uGQ4)vp_^$^U`2Jjq zeul!ptEpa%aJo0S(504oXPGdWM7dAA9=o9s4-{>z*pP zJ31L#|L?YR;^%+>YRJrLrFC=5vc;0{hcxDKF z!ntmgO>rVDaGmRpMI7-+mv(j~;s_LARvcpkXj|{GHu1c<1 zKI)#7RE~Dizu1lG>p-PcY2jX#)!oJlBA$LHnTUWX=lu``E)vhf9h4tYL-juZ`e|Kb z=F?C;Ou)h^cxB;M-8@$ZSH0jkVD>x-XS$ePV1vlU8&CG))4NgU(=XFH=Jb1IB7dBysS+94}Y>sjS(&YcJwhn zifzA|g$D5rW89vkJSv()I+Th4R&C$g-!CB30xkh%aw4po3$@DK2fW>}enE2YPt&{C~j}`>RYICK{ zYAPfZ&%`R}u6MYo<>d`^O#Q(dM{3>T^%J{Vu;lr#Utg4x9!Z9J%iXs(j+dn&SS1_2 zzxGtMnu^`d%K4Xq4Ms-ErG3_7n?c(3T!?rvyW=G<7_XKDv*ox`zN*^BVwUoqh{D7o zdEiq;Zp6}k_mCIAVTUcMdH|fo%L#qkN19X$%b1#Oko|u4!M*oRqdBa3z98{H#g=d%5X&D#NXhLh`nUjxi8@3oo(AgeItdJ zIrt9ieHI1GiwHiU4Cba-*nK@eHI4uj^LVmVIntU@Gwf^t6i3{;SfLMCs#L;s;P4s5oqd^}8Uil!NssP>?!K z07nAH>819U=^4H6l-Dhy`^Q6DV^}B9^aR0B%4AH=D&+dowt9N}zCK+xHnXb-tsKaV6kjf;Wdp#uIZ_QsI4ralE>MWP@%_5eN=MApv92( z09SSB#%eE|2atm9P~X2W2F-zJD+#{q9@1}L2fF|Lzu@1CAJq*d6gA8*Jjb;<+Asih zctE|7hdr5&b-hRhVe}PN z$0G{~;pz1yhkbwuLkfbvnX=<7?b(1PhxAmefKn$VS6Sv)t-UypwhEs3?*E=(pc%Dlul1V~OdWvdf z{WBX?lhfO_g$$X~hm^Bhl@U0t<|beYgT)2L_C(z@B^-63c9Ak2*Aa)iOMylfl|qyNQdO#yoJ?m2FOkhZ1ou@G%+^m z#!#(gTv8nx^34(HddDp|dcFl@&eh+&FFJc@^FL3fV2?u&9Wt|Yp3&MS)e+ez0g~Ys zY7d0n^)+ z0@K^GJTLN?XAV(0F6e>o>HCGJU5(8WsSFErs0FsO=O1u$=T~xx7HYK{7C>-IGB8U+ z&G^Vy>uY}Bq7HX-X`U^nNh+11GjG-)N1l_tG<^4Tu4+4X9KO9IrdH+eXGk|G6Tc(U zU~g7BoO!{elBk>;uN-`rGQP-7qIf9lQhj-=_~0Qyszu>s$s0FrJatSylv!ol&{29~ z7S4fv&-UBOF&cR@xpuW*{x9$R;c_ALt?{+dI&HoBKG-!EY{yE=>aWhlmNhHlCXc(B zuA-zI*?Z9ohO$i8s*SEIHzVvyEF$65b5m=H*fQ)hi*rX8 zKlPqjD*Ix1tPzfR_Z3bO^n32iQ#vhjWDwj6g@4S?_2GyjiGdZZRs3MLM zTfl0_Dsn=CvL`zRey?yi)&4TpF&skAi|)+`N-wrB_%I_Osi~)9`X+`Z^03whrnP7f z?T`*4Id`J@1x#T~L(h5^5z%Cok~U|&g&GpCF%E4sB#i3xAe>6>24%Kuu=)=HRS;Pu2wghgTFa zHqm#sa{7-~{w_039gH0vrOm&KPMiPmuPRpAQTm5fkPTZVT&9eKuu%Riu%-oMQl2X6 z{Bnx`3ro^Z$}rVzvUZsk9T)pX|4%sY+j0i)If_z-9;a^vr1YN>=D(I7PX){_JTJ&T zPS6~9iDT{TFPn}%H=QS!Tc$I9FPgI<0R7?Mu`{FTP~rRq(0ITmP1yrJdy|m;nWmDelF-V^y7*UEVvbxNv0sHR?Q=PVYRuZinR(;RjVAG zm&qlSYvaiIbVEqBwyDaJ8LVmiCi{6ESF4pO?U&7pk&CASm6vuB;n-RauPFzdr!C%1 z8pjdSUts7EbA4Kg(01zK!ZU<-|d zU&jWswHnSLIg&mTR;!=-=~z(#!UsXt%NJR|^teM8kG@8Qg_0^6Jqfn&(eENtP8D7K zvnll3Y%7yh1Ai~0+l6dAG|lEGe~Oa+3hO>K2}{ulO?Vf*R{o2feaRBolc;SJg)HXHn4qtzomq^EM zb)JygZ=_4@I_T=Xu$_;!Q`pv6l)4E%bV%37)RAba{sa4T*cs%C!zK?T8(cPTqE`bJ zrBWY`04q&+On`qH^KrAQT7SD2j@C>aH7E8=9U*VZPN-(x>2a++w7R$!sHH+wlze2X)<<=zC_JJvTdY7h&Jum?s?VRV)JU`T;vjdi7N-V)_QCBzI zcWqZT{RI4(lYU~W0N}tdOY@dYO8Rx5d7DF1Ba5*U7l$_Er$cO)R4dV zE#ss{Dl`s#!*MdLfGP>?q2@GSNboVP!9ZcHBZhQZ>TJ85(=-_i4jdX5A-|^UT}~W{CO^Lt4r;<1ps@s|K7A z90@6x1583&fobrg9-@p&`Gh+*&61N!$v2He2fi9pk9W2?6|)ng7Y~pJT3=g~DjTcYWjY9gtZ5hk*1Qf!y2$ot@0St$@r8|9^GMWEE>iB~etL zXYxn#Rvc`DV&y93@U$Z91md1qVtGY*M(=uCc}@STDOry@58JNx`bUH}EIb(n6I}i? zSYJOZ2>B6&Payu+@V!gxb;)_zh-{~qtgVwQ-V;vK7e0^Ag_$3+g+{xSVudVOY_p-R z$sXhpFSk7je2lk5)7Y2;Z847E1<;5?;z(I)55YFtgF!J;NT|eVi}q^*2sM}zyM{+s zD0phl+J>k1E7cZEGmP?1-3~RE;R$q(I5}m?MX8xi?6@0f#rD8Cjkpv1GmL5HVbTnM zAQ&4-rbkpdaoLp~?ZoW>^+t0t1t%GO2B;ZD4?{qeP+qsjOm{1%!oy1OfmX?_POQJ4 zGwvChl|uE;{zGoO?9B_m{c8p(-;_yq?b^jA({}iQG35?7H7`1cm`BGyfuq7z1s~T| zm88HpS{z54T{jxC=>kZ=Z#8G@uya3tt0$xST5V$-V<;6MA66VFg}`LLU8L=q3DmkU z)P^X8pg`ndMY*>gr{6~ur^Q@Z8LNQf*6wkP03K<|M*+cDc#XKZ`Z0$1FkI-IDRw#| za52W4MyHlDABs~AQu7Duebjgc}02W;1jgBx&I@TMDXU`LJutQ?@r%1z`W zlB8G-U$q37G1ob>Er8j0$q@OU3IwG#8HsvJM#)j=Y%~#zY`jaG%5;!(kY3*a^t>(qf6>I zpAJpF%;FQ?BhDSsVG27tQEG*CmWhl4)Ngp%}D?U0!nb1=)1M==^B)^$8Li$boCY$S4U;G^A!?24nSYHra{< zSNapX#G+0BTac|xh`w&}K!);$sA3ay%^a2f?+^*9Ev8ONilfwYUaDTMvhqz2Ue2<81uuB71 zAl|VEOy%GQ7zxAJ&;V^h6HOrAzF=q!s4x)Mdlmp{WWI=gZRk(;4)saI0cpWJw$2TJcyc2hWG=|v^1CAkKYp;s_QmU?A;Yj!VQ1m-ugzkaJA(wQ_ zah00eSuJg<5Nd#OWWE?|GrmWr+{-PpE_Dbqs&2`BI=<%ggbwK^8VcGiwC-6x`x|ZY z1&{Vj*XIF2$-2Lx?KC3UNRT z&=j7p1B(akO5G)SjxXOjEzujDS{s?%o*k{Ntu4*X z;2D|UsC@9Wwk5%)wzTrR`qJX!c1zDZXG>-Q<3Z)7@=8Y?HAlj_ZgbvOJ4hPlcH#Iw z!M-f`OSHF~R5U`p(3*JY=kgBZ{Gk;0;bqEu%A;P6uvlZ0;BAry`VUoN(*M9NJ z%CU2_w<0(mSOqG;LS4@`p(3*Z7jC|Khm5-i>FcYr87};_J9)XKlE}(|HSfnA(I3)I zfxNYZhs#E6k5W(z9TI2)qGY&++K@Z?bd;H%B@^!>e2Wi@gLk)wC)T93gTxdRPU7uh z)`$-m(G2I5AuK52aj!fMJR|d^H?0X~+4xSpw zqNRtq5r8hic*{eAwUT<=gI5uXLg)o5mg4XnO^T+Rd+{l)<$Aqp{+RxhNYuX^45W0k z5$t%+7R;dX$`s6CYQYcims>5bNt+k&l_t%C9D-6sYVm%Y8SRC#kgRh*%2kqMg2ewb zp_X*$NFU%#$PuQ@ULP>h9Xw`cJ>J-ma8lU`n*9PcWFpE%x0^}(DvOVe2jz@ z0^2QOi0~t!ov?jI{#bw~`Aj5ymQW@eruRg`ZNJ5IT5_5AHbQ?|C>_7rwREf2e2x&L zlV8xdOkp_*+wdaqE?6bmdrFfaGepcj=0AI<+c=Tg^WB9BhFx?SvwoVdTEm&zPy@Vs zPs2mVPiw1n_h?Xi6!+w)ypsFXXuM>gIY(J+1N6r!sJ{+r1%BzRF20!D;bN>L^?O8n z(5|x2p^Q6X`!pm3!MMFET5`nJXn>tK`fFAj5Eo&t6;F>TU_4G93YGyzvF2_fB& zfE8(dq?R@@&Wh8~%G~rDt1+e)96O5)by_%;G~Zv`TpmZ)vY@BkAan*zEy(s`*{-@U z;$WPjoNx~m?`6Z;^O=K3SBL3LrIxfU{&g)edERkPQZK!mVYU-zHuV0ENDq^e<-?^U zGyRcrPDZZw*wxK(1SPUR$0t0Wc^*u_gb*>qEOP102FX|`^U%n*7z=wM@pOmYa6Z=-)T%!{tAFELY2`dTl3$&w! z7sgKXCTU(h3+8)H#Qov19%85Xo+oQh?C-q0zaM_X2twSCz|j_u!te3J2zLV#Ut_q7 zl+5LGx#{I`(9FzE$0==km|?%m?g~HB#BSz2vHynf1x14mEX^~pej*dhzD|6gMgOJ_ z8F_<>&OIz;`NSqrel?HI-K(|ypxwz}NtX!CF3&T(CkuYOnKS&%lUSU44KsgS`L>!w zl{MoT4`t=+p8>@88)Ea%*hOIkxt#b4RfrwRMr91UF_Ic~kV;|+dRW0a8Vl725+gsvtHr5 z>?3fai&9NmU|3;-nAu8OB|<(-2Kfub4MX&1i}dDd=R~Dk=U-Vr=@&lfEIYU~xtHHO z4TKt=wze`qm=69lD)sOOkZ;$9=0B#*g@X6xPM-%zG*rCXkN%eRDEUp$gAaEd29t&T zRTAg##Sk+TAYaa(LyTD__zL3?Z+45^+1o}(&f<~lQ*-z7`Um^>v@PKqOunTE#OyKFY^q&L^fqZgplhXQ>P3?BMaq6%rO5hfsiln7TppJ z>nG9|2MmL|lShn4-yz0qH>+o;Fe`V!-e*R0M|q~31B=EC$(bQZTW^!PrHCPE4i|>e zyAFK!@P}u>@hqwf%<#uv*jen5xEL|v!VQEK!F`SIz_H8emZfn#Hg}}@SuqPv+gJ@- zf3a`DT_Q#)DnHv+XVXX`H}At zmQwW2K`t@(k%ULJrBe6ln9|W8+3B*pJ#-^9P?21%mOk(W1{t#h?|j0ZrRi_dwGh#*eBd?fy(UBXWqAt5I@L3=@QdaiK`B_NQ$ zLXzm{0#6zh2^M zfu>HFK^d`&v|x&xxa&M|pr))A4)gFw<_X@eN`B1X%C^a{$39fq`(mOG!~22h)DYut z(?MONP1>xp4@dIN^rxtMp&a^yeGc8gmcajyuXhgaB;3}vFCQFa!pTDht9ld9`&ql`2&(dwNl5FZqedD^BP zf5K1`(_&i7x-&rD=^zkFD87idQrk(Y?E;-j^DMCht`A8Qa5J-46@G_*Y3J+&l{$}*QCATEc9zuzaQGHR8B;y*>eWuv)E##?Ba3w= zZ|v(l{EB`XzD#|ncVm#Wy?#Nzm3bS1!FJ70e{DGe$EgNDg7<_ic^mJSh&Xc|aTwCrTv;XkW~UlS&G%KyLklCn}F^i(YP(f z{cqH%5q9ND_S;l$HRP$Q@`D=F*_1$CXIA5X@|V&Vir$NQ$vCx!b&LGCR<-2y)m%HI zxeeyQIjiWcf4uD9+FP+EJ`&$oJ%$R(#w~GjqP|aTQj#d(;l#rq$vcM&Y4ZQ_i{Kpx z?k2BtoKb?+1-EVmG^ne-W%8+y?i#J5N5g8f^qpH5(ZZp7$u+?I9GB+&MREX?TmVV$ zA}Ps=^CkD^sD9N;tNtN!a>@D^&940cTETu*DUZlJO*z7BBy`Rl;$-D@8$6PFq@tz0 z=_2JMmq-JRSvx`;!XM|kO!|DENI-5ke8WR*Zj#vy#Nf1;mW-{6>_sCO8?sVWOKDM| zR(iaZrBrzlRatUzp_Y|2nOXnY2G%WLGXCo9*)th_RnXvXV=q;WNAimI98!A54|$&OCCG%$4m{%E&o?S|Qx<4K~YGmM1CS!vZAzLN%d znbZsw6ql=XkiwSbNofNeA42q8#LH6Rk(u@z172O#6K>Sb{#`t#GUgpd{2;D(9@I_9 zwsY(6Go7RmOThs2rM3|Z#Vbs}CHPLgBK6gE8;XkJQDx~p5wJ?XkE(0<^hwnt6;$~R zXCAzMfK@`myzdkkpv*ZbarVwCi&{-O#rswrb-#x4zRkxfVCq;mJLic|*C92T?0CYv z)FCqY$xA(QZmggPocZqQj0Rc?=Afna`@fpSn)&nSqtI}?;cLphqEF3F9^OZfW9@HDunc^2{_H)1D9(O}4e zJMi_4(&$CD{Jf5&u|7#Iq*F~)l!8pAzNrX^<&wfEu~}Ipslzx=g^ff2?B9SnV=!$ zv&K0`hMN6BVIusHNX-lr`#K?OG1S*S4rCQaI3ea(!gCl7YjxJ3YQ)7-b&N*D8k><*x|47s3; z4f~WTWuk|Qd*d*DICV}Vb0YSzFZp5|%s4}@jvtTfm&`|(jNpajge zD}@CMaUBs+b?Yu6&c#18=TxzMCLE76#Dy=DLiq_a_knQX4Uxk$&@3ORoBFK_&a>`QKaWu^)Hzrqz{5)?h3B_`4AOn{fG9k zEwnjQb>8XRq!k?rmCd6E**1cY#b9yczN4mD%GLCeRk}{TmR1*!dTNzY;(f!B0yVuk zSjRyf;9i@2>bdGSZJ=FNrnxOExb075;gB z*7&YR|4ZraFO#45-4h%8z8U}jdt?83AmU3)Ln#m3GT!@hYdzqqDrkeHW zU#R`Z8RHq996HR=mC}SRGtsz07;-C-!n*ALpwwBe~loM)YqMH)Um$sH0RbTTzxFd)h1=-w5Yl3k|3nQ zZG>=_yZ7Lsn=b8_MZI+LSHLGYSSCc?ht~7cv#39>Moz6AS}5 zus?xge0PGdFd2FpXgIscWOyG}oxATgd$yl0Ugf_&J_vwt`)XWx!p*gE_cWU(tUTnz zQS}!bMxJyi3KWh^W9m zxLcy``V@EfJzYjK@$e7Yk=q!kL8cd3E-zpc*wwvGJ62O!V;N zFG7Y?sJ+^a%H1;rdDZRu2JmGn6<&ERKes=Pwx)GG-nt73&M78+>SOy!^#=gvLB)2H zjv!J0O`-zft|0Jv$3k5wScY)XB+9leZgR5%3~HtZA=bCg7=Dn+F}>2lf;!*1+vBtf z9jhmqlH=t5XW{0MC7Y~O7jaju&2`p!ZDLGlgnd~%+EJ%A#pIByi-+EOmoLVoK&ow8 zTDjB%0hxhiRv+O3c2*y00rMA=)s|3-ev7emcbT43#izku7dvaDXy1IMV0ahjB9yzi z9C9fN+I2Mzt1*{`a6B?+PdWHiJ5fH}rb2t>q)~3RfCxmyK^y5jN7Pn(9DFh61GO%p zuBErj=m|bDn_L8SINU)Z&@K*AgGz+SUYO_RUeJt=E0M+eh&kqK;%Y1psBNU<4-s9# ziHFr7QP6Ew=-2CdfA#Bf|EsctH;<&=Hsd>)Ma8NvHB$cpVY@}TV!UN}3?9o@CS5kw zx%nXo%y|r5`YOWoZi#hE(3+rNKLZ2g5^(%Z99nSVt$2TeU2zD%$Q(=$Y;%@QyT5Rq zRI#b><}zztscQaTiFbsu2+%O~sd`L+oKYy5nkF4Co6p88i0pmJN9In`zg*Q;&u#uK zj#>lsuWWH14-2iG z&4w{6QN8h$(MWPNu84w1m{Qg0I31ra?jdyea*I~Xk(+A5bz{x%7+IL}vFDUI-Rf{! zE^&Dau9QxA2~)M98b42(D6Q}2PUum0%g>B?JS?o~VrP+Go2&c-7hIf7(@o1*7k$zS zy@o5MEe8DoX$Ie(%SZByyf9Xf9n8xkoX}s6RiO1sg*kAV^6EAAz$>*x^OmIy!*?1k zG+UQ|aIWDEl%)#;k{>-(w9UE7oKM#2AvQud}sby=D7$l6{$}SE8O9WgHM_+ zJ?tHeu@Pi93{AuwVF^)N(B~0?#V*6z;zY)wtgqF7Nx7?YQdD^s+f8T0_;mFV9r<+C z4^NloIJIir%}ptEpDk!z`l+B z5h(k$0bO$VV(i$E@(ngVG^YAjdieHWwMrz6DvNGM*ydHGU#ZG{HG5YGTT&SIqub@) z=U)hR_)Q@#!jck+V`$X5itp9&PGiENo(yT5>4erS<|Rh#mbCA^aO2rw+~zR&2N6XP z5qAf^((HYO2QQQu2j9fSF)#rRAwpbp+o=X>au|J5^|S@(vqun`du;1_h-jxJU-%v| z_#Q!izX;$3%BBE8Exh3ojXC?$Rr6>dqXlxIGF?_uY^Z#INySnWam=5dV`v_un`=G*{f$51(G`PfGDBJNJfg1NRT2&6E^sG%z8wZyv|Yuj z%#)h~7jGEI^U&-1KvyxIbHt2%zb|fa(H0~Qwk7ED&KqA~VpFtQETD^AmmBo54RUhi z=^Xv>^3L^O8~HO`J_!mg4l1g?lLNL$*oc}}QDeh!w@;zex zHglJ-w>6cqx3_lvZ_R#`^19smw-*WwsavG~LZUP@suUGz;~@Cj9E@nbfdH{iqCg>! zD7hy1?>dr^ynOw|2(VHK-*e%fvU0AoKxsmReM7Uy{qqUVvrYc5Z#FK&Z*XwMNJ$TJ zW1T**U1Vfvq1411ol1R?nE)y%NpR?4lVjqZL`J}EWT0m7r>U{2BYRVVzAQamN#wiT zu*A`FGaD=fz|{ahqurK^jCapFS^2e>!6hSQTh87V=OjzVZ}ShM3vHX+5IY{f^_uFp zIpKBGq)ildb_?#fzJWy)MLn#ov|SvVOA&2|y;{s;Ym4#as?M^K}L_g zDkd`3GR+CuH0_$s*Lm6j)6@N;L7Vo@R=W3~a<#VxAmM&W33LiEioyyVpsrtMBbON+ zX^#%iKHM;ueExK@|t3fX`R+vO(C zucU#Xf>OjSH0Kd%521=Sz%5Y!O(ug(?gRH@K>IUayFU~ntx`Wdm27dB-2s@)J=jf_ zjI-o;hKnjQ|Lg~GKX!*OHB69xvuDU zuG-H48~inKa)^r539a{F)OS`*4GShX>%BR)LU~a-|6+sx&FYsrS1}_b)xSNOzH|Kv zq>+1-cSc0`99EsUz(XWcoRO)|shn>TqKoQBHE)w8i8K`*Xy6(ls%WN_#d}YC^)NJ; zzl8!Zduz^Gg8*f0tCWnLEzw6k5Fv!QWC1x4)3r}+x~@#O8_)0>lP-@3(kFwLl%%Mz(TpATVnL5Pl2Gahw45QXI~>Hrw))CcEs@PP?}4^zkM$ z@(?H6^`Jl?A=(&Ue;W0`*a8&fR7vde@^q^AzX^H#gd~96`Ay^_A%?;?@q@t7l7iGn zWms#2J|To4;o1?3g3L!K_chdtmbEg~>U>$5{WO@Ip~YE&H($(^X6y_OBuNHkd0wu= z4rXGy#-@vZ?>M<_gpE8+W-{#ZJeAfgE#yIDSS?M?K(oY@A|FaS3P;OjMNOG% zGWyZWS(}LJCPaGi9=5b%sq$i!6x@o(G}wwfpI5|yJe24d_V}cT1{^(Qe$KEMZ;>I@ zuE6ee%FLgem>CKEN8SeY)fpK#>*lGcH~71)T4p|9jWT;vwM@N!gL}nCW=Oi6+_>K2 zl4sWXeM1U}RETA~hp=o3tCk+?Zwl#*QA>Wwd|FlUF0)U;rEGPD1s0Syluo zfW9L(F>q9li8YKwKXZrp*t)N9E;?&Hdbm-AZp2BcDTHO6q=tzVkZsozEIXjIH`tm} zo2-UleNm*Lj7zgvhBph_|1IggkSuW~S(9ueZEfao8BuzqlF(a+pRivTv(Zb zXFaHwcuovdM#d+!rjV7F<^VW&@}=5|xj!OUF)s0zh|8yzC)7!9CZB+TLnycoGBsDF z$u&j={5c(4A$iik;x6_S96Krw8--+9pGY+*oSVTIuq;$z8*)W8B~rMX_(U6uM}!Gc`T;WfEKwI84%)-e7j}>NA(O_)3Vn9 zjXxY1Fnx3Fx%CFpUHVu0xjvxgZv}F9@!vC!lD|05#ew3eJ}@!V&urwRKH`1f{0e^o zWvM1S@NbI6pHdzm33pza_q;#?s%J*$4>10uYi4l%5qi|j5qh+D=oqSJR=7QwkQh>>c$|uJ#Z@lK6PMHs@ zyvnnoOSkGQkYz#g>||xN&1fV)aJb*y--Y`UQV~lt!u8yTUG59ns1l7u>CX2F>9fl; zB)zH3z^XHmSU{F_jlvESvaNL&nj^;j)29~1LcTYw>(6}>bt0hiRooqm0@qTj%A&P9 zKmexPwyXG@Rs1i+8>AJ;=?&7RHC7Mn%nO>@+l?Qj~+lD376O2rp)>tlVHn8MKq zwop1KRLhUjZ|+6ecGIAftSPT*3i94=QzYCi_ay+5J&O(%^IsqZ!$w-^bmd7ds$^!q z;AkC;5mTAU>l0S$6NSyG30Ej?KPq@#T)^x#x?@U~fl2m$Ffk)s6u|iPr!)-j0BlA7p3E*A|My8S#KH;8i-IQq7Q*F4*ZVPe<{^SWz_ zr?!6cS+@|C#-P~d#=W1n7acn8_pg#W-lcyf+41zwR+BU6`jUkP^`*wgX)FxEaXzoi z8)?FE*97Yqz|b@fR1(r{QD363t260rQ(F||dt9^xABi+{C*_HL9Zt5T;fq|#*b}=K zo5yj_cZB(oydMAL&X(W6yKf>ui?!%(HhiHJ83EA|#k0hQ!gpVd( zVSqRR&ado+v4BP9mzamKtSsV<|0U-Fe2HP5{{x&K>NxWLIT+D^7md{%>D1Z-5lwS~ z6Q<1`Hfc+0G{4-84o-6dr@)>5;oTt|P6jt9%a43^wGCslQtONH)7QXJEYa!c~39 zWJpTL@bMYhtem1de>svLvOUa*DL7+Ah0(_~2|ng`!Z!qiN}6xL;F}<%M8qWv&52-Y zG*1A&ZKlp~{UFV%Hb_*Re({93f7W*jJZMV-Yn|<+l3SPN+%GuPl=+tSZxxr%?6SEc zntb0~hcK691wwxlQz_jSY+V_h+0o`X!Vm{;qYK$n?6ib1G{q>a%UejzOfk6q<=8oM z6Izkn2%JA2E)aRZbel(M#gI45(Fo^O=F=W26RA8Qb0X;m(IPD{^Wd|Q;#jgBg}e( z+zY(c!4nxoIWAE4H*_ReTm|0crMv8#RLSDwAv<+|fsaqT)3}g=|0_CJgxKZo7MhUiYc8Dy7B~kohCQ$O6~l#1*#v4iWZ=7AoNuXkkVVrnARx?ZW^4-%1I8 zEdG1%?@|KmyQ}tploH>5@&8Cp{`)CxVQOss&x|Z7@gGL3=tCVNDG!N9`&;N$gu^MDk|`rRm=lhnXAJ5v1T)WTz)qvz|Dw zR?{}W4VB(O6#9%o9Z^kFZZV*PDTAWqkQ8TH!rti8QIcR&>zcg3qG}&A( zwH^K8=`1C1lRfhrX{IvNn9R9!$UMC%k(;;VH%`S0h_on|Gh6qDSH&#}*m-u{;p~WB zF$_I~xx!RxVrxNQdr@3T>{F#^D{@N9OYC9LsV62F_Z1KYQ5yk*C5WQ4&q}Kz(I{9UWWf?LIcCZicB1EO_FUH*a9QKS(4IR%#D5DTi_@M}Q_-4)J4d zz@!vR0}5MPAOK(#uL+$7XOcP$5SS#*EK9Rt6XN%}HB7@`8S^gNRk!HLv(CvCjX4o= z>9scPwWbE!F8T=@x9^;s-OF2!eO(!gL9$-AmzUiDnu&QS4If5ea2T070n1-IyNhck z9$J8b!he3@q5qB-cQ;5ymVIXXn46kK0sqKZV+3s3^mac=3~BrCW})WNrrRs1KtMmg zLzwXYC?@_H#s3W4D$W0rh%WL|G<1$$uYdptPbxy0ke!c%v#x9I=2?S)YVkg1X$W^cB!i>B{e9wXlm8AcCT8|verIZQngj>{%W%~W0J%N`Q($h z^u3}p|HyHk?(ls7?R`a&&-q@R<94fI30;ImG3jARzFz<(!K|o9@lqB@Va+on`X2G) zegCM8$vvJ$kUwXlM8df|r^GQXr~2q*Zepf&Mc%kgWGTf;=Wx%7e{&KId-{G}r22lI zmq%L6Y-M*T$xf8 z#kWOBg2TF1cwcd{<$B)AZmD%h-a6>j z%I=|#ir#iEkj3t4UhHy)cRB$3-K12y!qH^1Z%g*-t;RK z6%Mjb*?GGROZSHSRVY1Ip=U_V%(GNfjnUkhk>q%&h!xjFvh69W8Mzg)7?UM=8VHS* zx|)6Ew!>6-`!L+uS+f0xLQC^brt2b(8Y9|5j=2pxHHlbdSN*J1pz(#O%z*W-5WSf# z6EW5Nh&r<;$<3o1b013?U$#Y!jXY)*QiGFt|M58sO45TBGPiHl4PKqZhJ|VRX=AOO zsFz-=3$~g#t4Ji9c;GFS9L~}~bzgCqnYuJ-60AMDdN7HZt8_$~Of{oXaD3HVn9zkH z`>#xQNe=YpWTq_LcOoy}R`L<_4il7w4)QH4rl?AUk%?fH##I>`1_mnp&=$-%SutYT zs}sSNMWo;(a&D()U$~PG0MvZ#1lmsF&^P4l_oN#_NORD-GSmR{h_NbJ^ZdY#R9#qW zKAC%V*?y~}V1Zh#d|-z1Z8sy5A+}*cOq$xk@Pn&{QffzG-9ReyPeEhqF%~Z3@|r(s z3(wA&)dV~fELW*&*=!~l9M=7wq8xE(<@)BjjN8bUiS8@N9E{wi+Dd!V1AtT;Nl}9> zTz`2ge2Jn#Dlg1kC%oFlOe<>?jYC`Asr^%i4hH;S`*qZTPRan2a9Kjj=0aq{iVi2Z z87PZt$d(LAm_{92kl+2Z%k3KGV;~gsp;C>k?gMYZrVIzaI|0D+fka9G_4v>N96*8T zI(C8bj?A7l%V&U?H_IpSeCvf7@y1e?b>G7cN382GVO0qAMQ93(T*<*9c_;%P1}x2l zi8S$s<=e_8ww%DaBAf4oIQ7}U7_48$eYpo}Fb+F|K|43IAPR1y9xbqPPg6er{I7xj|=>-c%pGBRLn1~=5KbAb1mJAx=z(loN!w{49VkEthF>*OX z)=gqXyZB5%5lIWYPWh~{!5pSt43-)-@L@x=pmiuKP-3Cwq8qSxGNwaTT4->BWEjxk zUjr)z7WrBZB5u3iV>Y_>*i~*!vRYL)iAh5hMqNzVq1eeq=&d9Ye!26jks{f~6Ru&c zg$D;^4ui#kC`rSxx`fP!zZ^6&qSneQzZRq0F*V4QvKYKB<9FC%t#)Tik%Zq*G*IOW z3*`2!4d)!3oH>GxVcXlorJDt+JnH)p{~olYBPq|>_V@8=l#(f*diW=L+%>rfWCcPQ z#H^ksQt15Z5Uc4ODq8_JwD5^H&OGqyH6E@MabJQO>s`?bqgA6}J_QpytW{2jH#eCN z8k7y*TFZ2lj2B|1CB(@QZedFfPhX|IQbKMI;$YK>9Zla0fsU7}an6(kP;sXpBWLR` zJ#z_kk!`JJC7h(1J!+G)gL2WB2&0*~Q!%s??}GH?=`hU@03xOwU} z6s7?tGySLz!%(MwxQRiF)2(vR2wQX`YB}u&I-S+RR)LQcyH407#-{*pWLJJR?X|5 zsAl2k{&0N-?JArn@)9YTo-5+gl}R~XkbZM*5AOjPrcikpE3P?p0oN^?H+5+n)}Qxe z*RQ!-eu0RxPyF8B=}xnseNpQMXFU$d^=(G%kUd&|!BHSm7bXoGR$WA+%yjuA{|S>u z?9N6JDhS+ui~rd?wY_t7`p)|qKIMM>6jz%$jv4hc_YUDjF6-%5muq|SNuoji2)|qK zNY5+oWMe+5vu{I*grk6xlVk;(J)uuy13G`VDbj(~Vz9lA)_;$aj?=-cmd#h~N0mn{ z9EIS_d4C=L3H;Pl^;vcpb&-B+)8vt%#?gn5z>#;G{1L&8u8cXJYADMUsm9>%*%)&F zsi&I{Y=VUsV82+)hdNgDWh^M7^hMs|TA0M269^|RIGfdX1MetV2z`Ycb&_Mn4iRI! zeI6O}O9mOhN6pzfs5IfMz#Gxl`C{(111okA8M4gijgb~5s7QTyh84zUiZZ^sr1^ps z1GO`$eOS@k@XP^OVH|8)n}Wx)fKHoGwL&5;W?qEf5Jdsd!3hf7L`%QNwN0gGBm^2= z@WI+qJMJG1w2AS9d@Dt$sj_P$+S2kh7+M72^SfcdBjQEtWQ5?PT&a~G9hOo6CtS>h zoghqoR;sk{X)`ZK-M|lu{M}0>Mrs^ZW@ngC?c$26_vYKDBK^n7sFiod_xV#XcPL!^ zRPyqD{w^9u{oA3y73IW0 zH;%xop$r(Q=bq=JaLT%myEKD_2&?L@s6TzsUwE#g^OkiU6{lN)(7I?%a;_%r5_^@d zS-Z)Q-2o|~?F~f`sHlhNhiZk;!CW;3Ma6{xPlBjJx8PXc!Oq{uTo$p*tyH~ka`g<` z;3?wLhLg5pfL)2bYZTd)jP%f+N7|vIi?c491#Kv57sE3fQh(ScM?+ucH2M>9Rqj?H zY^d!KezBk6rQ|p{^RNn2dRt(9)VN_j#O!3TV`AGl-@jbbBAW$!3S$LXS0xNMr}S%f z%K9x%MRp(D2uO90(0||EOzFc6DaLm((mCe9Hy2 z-59y8V)5(K^{B0>YZUyNaQD5$3q41j-eX))x+REv|TIckJ+g#DstadNn_l~%*RBSss_jV3XS&>yNBc8H2jo(lwcLz-PuYp< z7>)~}zl$Ts0+RFxnYj7-UMpmFcw_H zYrsXM>8icD)@Iauiu_(Y#~Iyl)|pj@kHkWvg2N$kGG(W>Y)nfNn%z2xvTLwk1O2GQ zb^5KAW?c%5;VM4RWBy}`JVCBFOGQWoA9|+bgn7^fY3tSk1MSZccs9&Fy6{8F>_K@? zK(z=zgmq1R#jGE^eGV`<`>SP9SEBx!_-Ao|VZq6)-rUpd^<2GgVN&uHiM{0zA9kI( z<1^1%*uE$?4mXV@?W8}fvnBOpfwCo^?(a0E402!pZi&Kd5pp$oV%2Ofx<}YC-1mynB3X|BzWC_ufrmaH1F&VrU&Gs+5>uixj*OJ*f=gs9VR8k^7HRR$Ns|DYBc*Slz>hGK5B1}U+}#j0{ohGC zE80>WClD5FP+nUS?1qa}ENOPb2`P4ccI<9j;k?hqEe|^#jE4gguHYz-$_BCovNqIb zMUrsU;Fq%n$Ku_wB{Ny>%(B&x9$pr=Anti@#U%DgKX|HzC^=21<5Fn6EKc#~g!Mcj zJrI(gW+aK+3BWVFPWEF*ntHX5;aabHqRgU-Nr2t++%JRPP7-6$XS|M8o&YSgf3a9A zLW*tSJxoe1?#T4EocApa*+1kUIgy7oA%Ig9n@)AdY%)p_FWgF-Kxx{6vta)2X1O5y z#+%KQlxETmcIz@64y`mrSk2Z17~}k1n{=>d#$AVMbp>_60Jc&$ILCg-DTN~kM8)#o$M#Fk~<10{bQ>_@gU2uZE z*eN~mqqQC*wh{CI(!xvRQ^{jyUcvE~8N)S0bMA^SK@v;b7|xUOi63X~3Qc>2UNSD1) z7moi9K3QN_iW5KmKH>1ijU41PO>BvA6f1;kL)6io%^r>?YQ#+bB;)Rzad5;{XAJGeAT#FnDV0$w2>v|JeFIB zZ>8vmz?WVs78PuCDiHfb@D0Yi;2#%){*#?bY4dpta6dSjquGLcOw?Z{nxg98mN^4* zj&^!WMUQ_zFp+}B|G0vcNsk8(2u9(LAPk5ogKt%zgQ4^1#UCd;`-W#X8v{YyQ_m9g z8`jydw>>@1J{Q*q#5^cHVA~xR9LR3Hl@^bx)`IBKmj+Gmye36;xwL0>sS|mV+$~%b zC;2wEm&Ht3#6P|2Y0XQ+5t-aI)jn{o%&ZHWvjzEtSojFgXxNKO^e(RmM`gsJ4GrR8 zKhBtBoRjnH`mD$kT;-8ttq|iw?*`7iTF_AX<^Qe3=h8L^tqz$w$#Z@Z$`C579Jeeu ztr0z~HEazU&htfG@`HW!201!N(70hCd{%~@Wv)G*uKnJZ8>hFx`9LnYs;T>8p!`5T zx#aXXU?}B{QTV_Ux(EMzDhl-a^y^f5tRU;xnOQoN)pThr4M>-HU)As8nQ34-0*sab&z<2ye-D_3m&Q`KJJ|ZEZbaDrE%j>yQ(LM#N845j zNYrP)@)md;&r5|;JA?<~l^<=F1VRGFM93c=6@MJ`tDO_7E7Ru zW{ShCijJ?yHl63Go)-YlOW2n3W*x%w||iw(Cy>@dBJHdQl){bBVg{wmRt{#oXb9kaWqe{bJPmGE$$ z_0=cmD9dVzh<8&oyM8rK9F^bufW$Bj2cFhw&f*oKKyu$H{PI=Aqe^NL6B=dkMEAk& zE3y&F=x;e|!7kMn%(UX>G!OE$Y$@UyME#d;#d+WLmm@W@y!sboiIox^DZPB|EN<>7 z57xm5YWlFUGyF|{<*;b&Cqm+|DC8{rB9R@2EFHGL^NX*l#AcDpw6}bCmhY7!(Gv{s zm^eYNvzyJLQA#GhmL*oSt^Uulb5&ZYBuGJTC>Vm9yGaZ=Vd--pMUoDRaV_^3hE9b*Pby#Ubl65U!VBm7sV}coY)m zn1Ag^jPPLT93J{wpK%>8TnkNp;=a@;`sA7{Q}JmmS1bEK5=d@hQEWl;k$9M-PYX~S zayGm;P(Wwk23}JR7XM~kNqba`6!Z+Wt2|5K>g_j3ajhR>+;HF?88GBN!P; zr6sQ8YYpn%r^gbi8yYK7qx6U5^Tf<|VfcR$jCo`$VMVh_&(9w@O?|o3eRHq*e*#P z8-==G)D?vB3Zo~b-dkx8lg0^=gn`9FUy?ZzAfWQd>>@cyqF!sHQ_S&@$r&tTB~Lxq zAjAZTK~?J{A|L3)8K>S{`Qf%131B>?<~t=w!D{;olQ>#31R#{go`a9DOy+H*q5t+; z^*Ka!r@#8tk?~tQbylaG-$n#wP2VzIm3vjrZjcmTL zl`{6mhBhMKbSWoGqi;g3z1@G0q!ib`(Zz_o8HG_*vr8U5G|vhZn26h`f~bO&)RY0; zw(CWk*a_{ji_=O9U}66lI` zCm32)SEcAo5)5k>{<8DLI@Zz)*R29BB!^wF;WZRF9sAi39BGObmZzg?$lUn6w1rYPHSB^L4^AN zLObEaUh7TXpt6)hWck#6AZV(2`lze<`urGFre|>LUF+j5;9z%=K@&BPXCM)P$>;Xc z!tRA4j0grcS%E!urO^lsH-Ey*XY4m&9lK(;gJOyKk*#l!y7$BaBC)xHc|3i~e^bpR zz5E-=BX_5n8|<6hLj(W67{mWk@Bfc){NGAX z5-O3SP^38wjh6dCEDLB#0((3`g4rl}@I(&E8V2yDB=wYhSxlxB4&!sRy>NTh#cVvv z=HyRrf9dVK&3lyXel+#=R6^hf`;lF$COPUYG)Bq4`#>p z@u%=$28dn8+?|u94l6)-ay7Z!8l*6?m}*!>#KuZ1rF??R@Zd zrRXSfn3}tyD+Z0WOeFnKEZi^!az>x zDgDtgv>Hk-xS~pZRq`cTQD(f=kMx3Mfm2AVxtR(u^#Ndd6xli@n1(c6QUgznNTseV z_AV-qpfQ0#ZIFIccG-|a+&{gSAgtYJ{5g!ane(6mLAs5z?>ajC?=-`a5p8%b*r*mOk}?)zMfus$+W~k z{Tmz9p5$wsX1@q`aNMukq-jREu;;A6?LA(kpRut+jX?Tt?}4HGQr}7>+8z4miohO2 zU4fQ?Y8ggl%cj&>+M+)TTjn8(?^%`~!oAt#ri8gIbzIig$y#d7o##077fM9sCu%N9 zOIsq4vyox6`itu*j{eOD<$gTZd-$JuyM^cM>{?v<8# zS1yN%R0zRy&>+D*Gv-&S80?JF+Y|c^^IJWDnfy06MI2{NFO-x4JXsb@3Qp;EnL!a{ zJwKwV@mO zYVGvNmeJ!;+ce+@j@oo-+`DaPJX|h@7@4BD`QEdP?NKkYzdIa3KrZt%VUSsR+{b+| zk?dSd#9NnVl?&Y$A{-OtZ>wk%mWVF5)bf`)AA2{EFapIS4jil69Xan>*J^6Juou&`oJx|7-&|@8z?$ z2V#jm!UHstCE*qM{OGtqYY8q+x%SL6&aGY!a>@d=_G~^0;+7dY9P`oJ*)67*9Kx*O zKitC5V3g5;&L-fa37?eN=;V_c^L-ph_uKv5)Q`&!Z!RPlDWA2{J%a2q@_*?-cn@bH zIt)+mA@HaJj2RV+-MNc#y#Vji*N~m!ZyrYyg-7UK4PYK4F7Y$3Y%@Lk6iPp=I96N> z!;ih(KtZMB23*v{`5cJ}^4D*P!k1&OfU&1%borv_q|7jfaV7fL+wwx8Zp*b}B_O>NRSeJeM zpvw3M`=vSYjFYQ11kx1xqOnJ@degPh&SyXnWz-l719EiW17Yo?c~Bh~;R$MOl+jzV zM1yTq-1**x-=AVR;p0;IPi`#=E!G5qIT>EFE`Bn<7o*8!aVd7?(CZT=U9^Gi3rmWUQG z0|GaP9s$^4t_oLCs!fInyCoB(d?=tZ%%Bb2Y+X&7gvQ6~C4kU%e$W_H;-%XSM;&*HYYnLI z>%{5x_RtSUC~PI4C0H^>O%FixKYVubA>#72wexd}Cgwuw5ZYTvcN2ywVP(dO=5975 zCjo)mOa2Bo&ucEsaq8wi1{h*brT(H=XrTOy*P>?0%VV1QDr09X+Je!T)JT`02?gjX zT@B8}h|;4lH35Guq2gKZT?ags-~Ts~S=poPnQ_T1*?U|{$jaur_PjQ6WmF_(XLFG)d#|iiBC=&B zp}1eOQvQ!3UpL?K`=8hAzMkv#a^COr`J8i}d!BPX&*xp-LL#qse~mOtxI-}{yPRNV zJNTL1{7A55F~K>0e&Os%MwQ~?n1>QV=j!8o_`^-&*E|Q-L9DNr%#6sw8kQVE3E|*}$aAoO$@27ei1w=+zU%?AA!;mf#!%IV*w_D=u516!Kz1F0-WnyVB`I6F1Pc3r1=0iT<_(pCyk>@22z1$w$@M>7AIuk6+ zRG&MFVQ_7>5DLoR5HeOa$?2SA(v2u!#8;5I(ss%=x9U#R zU62n~&)22RTTsp${}6C&$+l&0skFVX%ACgc$(iQ#DVRRz!`Y+b>E?;ib(TH#6Wa=} zs(q_;SA|fhyEo7Ix%rAY9j=Ul^Rzd`3ABf+yO@~h@Rh=wo`?;8PdHE1AUo34r7izy znAr`;VavQueSu7bD5r^nXTERcW(P-{2SOSfF1x0cW1Nczvj0}@!!upORN1%_-b2bh zGt#zokJz&SveJRzlUK4DruxR(YuHEAmB%F}buU`*pAzJ7Mbgs4sg;H@&6x*wxvGm6 z>KH@ilsvvdl@CGfm4T+$agodrB=md8ygG!|O=r@FY>S_zX%*)mqf?XBX*chhQ9uPP z-(T(24)})vWD*{bQM5_hy3CD8C>anuNtCXMkG7T?Yew^>=PK!~Hlr0{-0h0cNAJ8> zRMzLFz7aJv)Yh)_s)^L&L*nDV@qfeg>_<`z1z(?s}}3tE4h|7_taB> zPfmmOCFZ8%>`gyf1@|7t3;e~mwBRCDDw(Rrt>@O}obs#1?!W((+9>d$b7t!{&wR!P ziQbn0@j=&sw={`s##Uc@uS^(tbShjtsk=qrU1LW0lu}BplIfzv{fwxNsSaG~b|ryo zTQ}YXfp6o?^sSHW>s~m;l@h6wFbIPw{Z(IqO1u){{hEZgrTdF0o$n;hYIm`h5ejym zWt^w~#8p1J)FtfY6LvGmNQ~#n>4#mN4B^ zjrQk)Zt%k}GBRD>l`<~og6N_{6HYKDtsAtd%y?KbXCQR(sW8O(v_)kwYMz|(OW zsFz6A1^abSklOl`wLC-KYI8x=oMD^qZBs}}JVW@YY|3&k&IZ_n2Ia@5WiK>buV!E- zOsYcS4dFPE7vzj%_?5i2!XY`TiPd*jy>#C`i^XG8h?f35`=)s`0EhQBN!+YrXbpt( z-bwg_Jen`w<+6&B`hldU%rr&Xdgtze>rKuJ61AI12ja-eDZZX-+u1H>Sa|7pCine9 z&MEhmT7nq`P!pPK>l?I8cjuPpN<7(hqH~beChC*YMR+p;;@6#0j2k$=onUM`IXW3> z`dtX8`|@P|Ep-_0>)@&7@aLeg$jOd4G`eIW=^dQQ*^cgKeWAsSHOY?WEOsrtnG|^yeQ3lSd`pKAR}kzgIiEk@OvQb>DS*pGidh`E=BHYepHXbV)SV6pE2dx6 zkND~nK}2qjDVX3Z`H;2~lUvar>zT7u%x8LZa&rp7YH@n@GqQ65Cv+pkxI1OU6(g`b z?>)NcE7>j@p>V0mFk-5Rpi`W}oQ!tUU&Yn8m0OWYFj|~`?aVFOx;e`M)Q!YSokY)3 zV6l-;hK6?j=mp2#1e5cCn7P6n_7)n^+MdRw@5pvkOA>|&B8`QZ32|ynqaf}Kcdro= zzQchCYM0^)7$;m2iZnMbE$!}hwk&AVvN`iX3A9mB&`*BDmLV-m`OMvd`sJ?;%U`p~ zmwow{y6sPbcZNQPZ#GQS0&mzy?s%>_p>ZM|sCXVAUlST;rQ-3#Iu!-bpFSV4g7?-l zGfX>Z#hR+i;9B};^CO@7<<#MGFeY)SC&;a{!` zf;yaQo%{bjSa8KT~@?O$cK z(DGnm7w>cG1hH#*J%X}%Y%~+nLT*{aP08@l&Nu}>!-j|!8lSqt_xUNF+Y}SQmupyb zPua2PI;@1YaIsRF*knA^rJv84Tc=7?J2}!1kMfHSO$d$+PK*u?OI%=P7;`PHxMB0k zau~T0Wk)rPEGJ$NiXW~kfPA#m%Sr|7=$tHelF9A6rFLa$^g{6)8GSW*6}#~Zb^qk% zg=pLwC!SkY+&Gne((9`TCy`i`a#eCS{A2yMi>J>p*NS*!V~aAgK;wnSOHPULqzyj- z-q4BPXqXn))iRnMF*WZj17wUYjC!h43tI7uScHLf1|WJfA7^5O9`%lH>ga`cmpiz( zs|I8nTUD4?d{CQ-vwD!2uwGU_Ts&{1_mvqY`@A{j^b?n&WbPhb418NY1*Otz19`1w zc9rn?0e_*En&8?OWii89x+jaqRVzlL!QUCg^qU&+WERycV&1+fcsJ%ExEPjiQWRTU zCJpu*1dXyvrJJcH`+OKn7;q`X#@Gmy3U?5ZAV~mXjQhBJOCMw>o@2kznF>*?qOW;D z6!GTcM)P-OY-R`Yd>FeX%UyL%dY%~#^Yl!c42;**WqdGtGwTfB9{2mf2h@#M8YyY+!Q(4}X^+V#r zcZXYE$-hJyYzq%>$)k8vSQU` zIpxU*yy~naYp=IocRp5no^PeFROluibl( zmaKkWgSWZHn(`V_&?hM{%xl3TBWCcr59WlX6Q{j45)`A^-kUv4!qM=OdcwpsGB)l} z&-_U+8S8bQ!RDc&Y3~?w5NwLNstoUYqPYs(y+lj!HFqIZ7FA>WsxAE7vB=20K zn_&y{2)Uaw4b^NCFNhJXd&XrhA4E~zD7Ue7X^f98=&5!wn_r=6qAwDkd>g#2+*ahd zaV|_P_8e%jiHh7W;cl(d=&-r-C}_Ov?bts8s^rKUWQ|XkuW!ToSwe}Z{4|kl+q&&W zn%iW48c5*ft#*m)+xSps+j(B5bPh&u0&m6=@WgwBf_QfJJzg2Qdz89HwcV`5kZ#5z zw;W&H8>5R(>KRwvd0gh30wJHA>|2N(im;~wy1HTv_}Ue%qb)>5qL^$hIyPvoT(nk_<`7F;#nS8;q!cqKspvBc<%xMsQj*h|>`Z)F6LDxue@to))OIbs2X+zY2L9#2UNrR^)?c8&PFc?j*&Q-r|C%7a$)ZRQ->#|?rEj&M4spQfNt;J^ntwf(d+q;tt)C`d{*|t)czD4x-qw{Chm0vuKp8axqy5`Yz z1756|;JX1q(lEieR=uT;%havqflgv+`5i!Z`R}(JNV~&`x}I9Lmm;aB7Bnc^UC?>W zu)(J7@fs}pL=Y-4aLq&Z*lO$e^0(bOW z3gWbcvb^gjEfhV=6Lgu2aX{(zjq|NH*fSgm&kBj?6dFqD2MWk5@eHt@_&^ZTX$b?o}S<9BGaCZIm6Hz)Qkruacn!qv*>La|#%j*XFp(*;&v3h4 zcjPbZWzv|cOypb@XDnd}g%(@f7A>w2Nseo|{KdeVQu)mN=W=Q`N?ID%J_SXUr0Rl# z3X;tO*^?41^%c!H;ia@hX``kWS3TR|CJ4_9j-?l6RjC=n?}r&sr>m%58&~?$JJV6{ zDq5h#m4S_BPiibQQaPGg6LIHVCc`9w3^3ZVWP$n>p7 z5dIEH-W9e;$Id8>9?wh%WnWf>4^1U<%vn=<4oNFhVl9zVk+jn;WtQUQ)ZeEjKYy8C z3g#tIb28thR1nZdKrN}(r zJdy-Y3Rvr5D3D|msZbmE;FLePbiM0ZjwTIQQHk)8G+sB$iwmEa2kQv&9Vs9m#$_8j zNKz}(x$Wc(M)a9H-Pn?5(Lk-CmOS(&+EVLOfsiq>e3ru6P?Lp>FOwPt>0o=j8UyF^ zO{(vf#MGx^y~WaOKnt%I78s}60(O#jFx0^47^Ikh$QTar(Dg$c=0KR|rRD|6s zz?tEX0_=(Hm0jWl;QOu!-k)mV?^i(Etl=Lg-{ z0G}CBprLX60zgAUz-fS^&m#o;erEC5TU+mn_Wj(zL$zqMo!e`D>s7X&;E zFz}}}puI+c%xq0uTpWS3RBlIS2jH0)W(9FU1>6PLcj|6O>=y)l`*%P`6K4}U2p}a0 zvInj%$AmqzkNLy%azH|_f7x$lYxSG=-;7BViUN(&0HPUobDixM1RVBzWhv8LokKI2 zjDwvWu=S~8We)+K{oMd-_cuXNO&+{eUaA8Ope3MxME0?PD+0a)99N>WZ66*;sn(N++hjPyz5z0RC{- z$pcSs{|)~a_h?w)y}42A6fg|nRnYUjMaBqg=68&_K%h3eboQ=%i083nfIVZZ04qOp%d*)*hNJA_foPjiW z$1r8ZZiRSvJT3zhK>iR@8_+TTJ!tlNLdL`e0=yjzv3Ie80h#wSfS3$>DB!!@JHxNd z0Mvd0Vqq!zfDy$?goY+|h!e(n3{J2;Ag=b)eLq{F0W*O?j&@|882U5?hUVIw_v3aV8tMn`8jPa5pSxzaZe{z}z|}$zM$o=3-mQ0Zgd?ZtaI> zQVHP1W3v1lbw>|?z@2MO(Ex!5KybKQ@+JRAg1>nzpP-!@3!th3rV=o?eiZ~fQRWy_ zfA!U9^bUL+z_$VJI=ic;{epla<&J@W-QMPZm^kTQ8a^2TX^TDpza*^tOu!WZ=T!PT z+0lJ*HuRnNGobNk0PbPT?i;^h{&0u+-fejISNv#9&j~Ep2;dYspntgzwR6<$@0dTQ z!qLe3Ztc=Ozy!btCcx!G$U7FlBRe}-L(E|RpH%_gt4m_LJllX3!iRYJEPvxcJ>C76 zfBy0_zKaYn{3yG6@;}S&+BeJk5X}$Kchp<Ea-=>VDg&zi*8xM0-ya!{ zcDN@>%H#vMwugU&1KN9pqA6-?Q8N@Dz?VlJ3IDfz#i#_RxgQS*>K+|Q@bek+s7#Qk z(5NZ-4xs&$j)X=@(1(hLn)vPj&pP>Nyu)emQ1MW6)g0hqXa5oJ_slh@(5MMS4xnG= z{0aK#F@_p=e}FdAa3tEl!|+j?h8h`t0CvCmNU%dOwEq<+jmm-=n|r|G^7QX4N4o(v zPU!%%w(Cet)Zev3QA?;TMm_aEK!5(~Nc6pJlp|sQP@z%JI}f0_`u+rc`1Df^j0G&s 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..bf7e2e5 --- /dev/null +++ b/1.20.4/settings.gradle @@ -0,0 +1,23 @@ +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/' + } + } +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/settings.gradle' 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 diff --git a/LICENSE-ASSETS.md b/LICENSE-ASSETS.md index 79fd8f1..9a3157a 100644 --- a/LICENSE-ASSETS.md +++ b/LICENSE-ASSETS.md @@ -1 +1 @@ -Copyright (c) 2023 @heyitsfuzs. All Rights Reserved. \ No newline at end of file +Copyright (c) 2024 @heyitsfuzs. All Rights Reserved. From 67498ea12b5c14d45190f2e992909923188150ac Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 10 Feb 2024 01:24:39 +0100 Subject: [PATCH 21/31] full 1.20.4 port --- 1.20.4/CHANGELOG.md | 34 +++------------- 1.20.4/Common/build.gradle | 13 +++--- .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../assets/armorstatues/lang/en_us.json | 8 ++-- .../java/fuzs/armorstatues/ArmorStatues.java | 11 ----- .../client/ArmorStatuesClient.java | 25 ++++++------ .../ArmorStandAlignmentsScreen.java | 12 +++--- .../ArmorStandVanillaTweaksScreen.java | 8 ++-- .../handler/ArmorStandTooltipHandler.java | 9 +++-- .../client/handler/DataSyncTickHandler.java | 4 +- .../armorstatues/config/ClientConfig.java | 2 +- .../data/client/ModLanguageProvider.java | 39 ++++++++++++++++++ .../handler/ArmorStandInteractHandler.java | 25 ++---------- .../fuzs/armorstatues/init/ModRegistry.java | 18 ++++----- .../armorstatues/network/S2CPingMessage.java | 30 -------------- .../client/data/CommandDataSyncHandler.java | 12 +++--- .../data/VanillaTweaksDataSyncHandler.java | 4 +- .../fuzs/armorstatues/proxy/ClientProxy.java | 8 ++-- .../fuzs/armorstatues/proxy/ServerProxy.java | 2 +- .../main/resources/architectury.common.json | 3 ++ .../main/resources/armorstatues.accesswidener | 1 + .../src/main/resources/common.mixins.json | 13 ++++++ 1.20.4/Common/src/main/resources/pack.mcmeta | 4 +- 1.20.4/Fabric/build.gradle | 28 ++----------- .../{ => fabric}/ArmorStatuesFabric.java | 3 +- .../client/ArmorStatuesFabricClient.java | 3 +- .../src/main/resources/fabric.mixins.json | 14 +++++++ .../Fabric/src/main/resources/fabric.mod.json | 6 ++- 1.20.4/Forge/build.gradle | 37 ++--------------- 1.20.4/Forge/gradle.properties | 1 + .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 - .../fuzs/armorstatues/ArmorStatuesForge.java | 23 ----------- .../data/ModLanguageProvider.java | 40 ------------------- .../forge}/ArmorStatuesForge.java | 10 +---- .../client/ArmorStatuesForgeClient.java | 3 +- .../src/main/resources/META-INF/mods.toml | 16 +++++++- .../src/main/resources/forge.mixins.json | 14 +++++++ 1.20.4/NeoForge/build.gradle | 37 ++--------------- 1.20.4/NeoForge/gradle.properties | 1 + .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 2 - .../assets/armorstatues/lang/en_us.json | 23 ----------- .../data/ModLanguageProvider.java | 40 ------------------- .../neoforge/ArmorStatuesNeoForge.java | 20 ++++++++++ .../client/ArmorStatuesNeoForgeClient.java} | 21 +++++----- .../src/main/resources/META-INF/mods.toml | 18 +++++++-- .../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 | 24 ++++------- 50 files changed, 285 insertions(+), 445 deletions(-) create mode 100644 1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 rename 1.20.4/{Forge => Common}/src/generated/resources/assets/armorstatues/lang/en_us.json (83%) create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java delete mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java create mode 100644 1.20.4/Common/src/main/resources/architectury.common.json create mode 100644 1.20.4/Common/src/main/resources/armorstatues.accesswidener create mode 100644 1.20.4/Common/src/main/resources/common.mixins.json rename 1.20.4/Fabric/src/main/java/fuzs/armorstatues/{ => fabric}/ArmorStatuesFabric.java (79%) rename 1.20.4/Fabric/src/main/java/fuzs/armorstatues/{ => fabric}/client/ArmorStatuesFabricClient.java (79%) create mode 100644 1.20.4/Fabric/src/main/resources/fabric.mixins.json create mode 100644 1.20.4/Forge/gradle.properties delete mode 100644 1.20.4/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 delete mode 100644 1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java delete mode 100644 1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java rename 1.20.4/{NeoForge/src/main/java/fuzs/armorstatues => Forge/src/main/java/fuzs/armorstatues/forge}/ArmorStatuesForge.java (61%) rename 1.20.4/Forge/src/main/java/fuzs/armorstatues/{ => forge}/client/ArmorStatuesForgeClient.java (96%) 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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 delete mode 100644 1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json delete mode 100644 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java rename 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/{client/ArmorStatuesForgeClient.java => neoforge/client/ArmorStatuesNeoForgeClient.java} (76%) 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 dc05013..72b0350 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -1,33 +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.5-1.20.1] - 2023-12-03 -### Changed -- Client side permissions check can now be disabled in the config -### Fixed -- Armor stand menu can no longer open in adventure mode - -## [v8.0.4-1.20.1] - 2023-12-03 -### Changed -- Updated to Puzzles Api v8.1.4 - -## [v8.0.3-1.20.1] - 2023-08-16 -### Fixed -- Fixed a crash trying to interact with an armor stand when playing on a Forge server that does not have Armor Statues installed (Forge only) - -## [v8.0.2-1.20.1] - 2023-07-29 -### Fixed -- Fixed an issue with always receiving an incorrect error message when trying to edit an armor stand on a server with the Vanilla Tweaks data pack installed - -## [v8.0.1-1.20.1] - 2023-07-28 -### Added -- Added a new tab that only shows when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack offering Vanilla Tweaks exclusive toggles -### Changed -- Optimized some actions during editing to be performed much quicker when Armor Statues is being used in conjunction with the Vanilla Tweaks data pack - -## [v8.0.0-1.20.1] - 2023-07-27 -- Ported to Minecraft 1.20.1 - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +## [v20.4.0-1.20.4] - 2024-02-10 +- Port to Minecraft 1.20.4 +- Port to NeoForge diff --git a/1.20.4/Common/build.gradle b/1.20.4/Common/build.gradle index 2434c15..4971f9a 100644 --- a/1.20.4/Common/build.gradle +++ b/1.20.4/Common/build.gradle @@ -1,16 +1,13 @@ -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 - // Puzzles Api - api(libs.puzzlesapi.common) { - exclude group: "fuzs.puzzleslib" - } + // Statue Menus + modApi libs.statuemenus.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..95dc085 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.20.4 2024-02-10T01:11:18.844688 Language (en_us) +3b837616894d5f092cf8c1f8e4658d723dbc0320 assets/armorstatues/lang/en_us.json diff --git a/1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_us.json similarity index 83% rename from 1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json rename to 1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_us.json index e392806..1235c24 100644 --- a/1.20.4/Forge/src/generated/resources/assets/armorstatues/lang/en_us.json +++ b/1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -6,9 +6,9 @@ "armorstatues.dataSync.failure.outOfRange": "Out Of Range", "armorstatues.dataSync.finished": "Finished sending queued armor stand data", "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", - "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armor stand which opened builder menu.", "armorstatues.screen.vanillaTweaks.lock": "Lock", - "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using builder menu and disables interaction with the equipment slots.", "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", @@ -18,6 +18,6 @@ "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", "armorstatues.screen.vanillaTweaks.unlock": "Unlock", "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", - "puzzlesapi.screen.type.alignments": "Alignments", - "puzzlesapi.screen.type.vanillaTweaks": "Vanilla Tweaks" + "statuemenus.screen.type.alignments": "Alignments", + "statuemenus.screen.type.vanillaTweaks": "Vanilla Tweaks" } \ No newline at end of file diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java index 041fd20..4e42e41 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -3,14 +3,10 @@ import fuzs.armorstatues.config.ClientConfig; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.armorstatues.init.ModRegistry; -import fuzs.armorstatues.network.S2CPingMessage; import fuzs.puzzleslib.api.config.v3.ConfigHolder; import fuzs.puzzleslib.api.core.v1.ModConstructor; import fuzs.puzzleslib.api.event.v1.core.EventPhase; -import fuzs.puzzleslib.api.event.v1.entity.player.PlayerEvents; import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; -import fuzs.puzzleslib.api.network.v2.MessageDirection; -import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,23 +15,16 @@ public class ArmorStatues implements ModConstructor { public static final String MOD_NAME = "Armor Statues"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID, true, true); public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).client(ClientConfig.class); @Override public void onConstructMod() { ModRegistry.touch(); - registerMessages(); registerHandlers(); } - private static void registerMessages() { - NETWORK.register(S2CPingMessage.class, S2CPingMessage::new, MessageDirection.TO_CLIENT); - } - private static void registerHandlers() { // high priority so we run before the Quark mod PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); - PlayerEvents.LOGGED_IN.register(ArmorStandInteractHandler::onLoggedIn); } } diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index 42de006..644997c 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -4,16 +4,14 @@ import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; import fuzs.armorstatues.client.handler.DataSyncTickHandler; -import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.armorstatues.init.ModRegistry; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreenFactory; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandMenu; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; -import fuzs.puzzleslib.api.client.event.v1.ClientPlayerEvents; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; import fuzs.puzzleslib.api.client.event.v1.ClientTickEvents; -import fuzs.puzzleslib.api.client.event.v1.ItemTooltipCallback; -import fuzs.puzzleslib.api.client.event.v1.ScreenEvents; -import net.minecraft.client.gui.screens.MenuScreens; +import fuzs.puzzleslib.api.client.event.v1.gui.ItemTooltipCallback; +import fuzs.puzzleslib.api.client.event.v1.gui.ScreenEvents; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; @@ -29,17 +27,20 @@ private static void registerHandlers() { ItemTooltipCallback.EVENT.register(ArmorStandTooltipHandler::onItemTooltip); ClientTickEvents.END.register(DataSyncTickHandler::onEndClientTick); ScreenEvents.remove(Screen.class).register(DataSyncTickHandler::onRemove); - ClientPlayerEvents.LOGGED_IN.register(ArmorStandInteractHandler::onLoggedIn); } - @SuppressWarnings("Convert2MethodRef") @Override public void onClientSetup() { + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); + } + + @SuppressWarnings("Convert2MethodRef") + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { // compiler doesn't like method reference :( - MenuScreens.register(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), (ArmorStandMenu menu, Inventory inventory, Component component) -> { + context.registerMenuScreen(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), (ArmorStandMenu menu, Inventory inventory, Component component) -> { return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); }); - ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); - ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); } } diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java index da972b8..df01829 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -2,12 +2,12 @@ import com.google.common.collect.Lists; import fuzs.armorstatues.init.ModRegistry; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandButtonsScreen; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandPositionScreen; -import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandButtonsScreen; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandPositionScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java index ed09c7d..f52054d 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java @@ -4,10 +4,10 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandButtonsScreen; -import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandButtonsScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Inventory; diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java index 929250d..29864c3 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -1,6 +1,7 @@ package fuzs.armorstatues.client.handler; -import fuzs.puzzlesapi.api.statues.v1.helper.ArmorStandInteractHelper; +import fuzs.puzzleslib.api.core.v1.Proxy; +import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -14,11 +15,11 @@ public class ArmorStandTooltipHandler { public static void onItemTooltip(ItemStack stack, @Nullable Player player, List lines, TooltipFlag context) { if (stack.is(Items.ARMOR_STAND)) { - Component component = ArmorStandInteractHelper.getArmorStandHoverText(); + List components = Proxy.INSTANCE.splitTooltipLines(ArmorStandInteractHelper.getArmorStandHoverText()); if (context.isAdvanced()) { - lines.add(lines.size() - (stack.hasTag() ? 2 : 1), component); + lines.addAll(lines.size() - (stack.hasTag() ? 2 : 1), components); } else { - lines.add(component); + lines.addAll(components); } } } diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java index 91ccdad..822390a 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -1,7 +1,7 @@ package fuzs.armorstatues.client.handler; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreen; -import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.Nullable; diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java index 6e2a684..137797d 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -1,8 +1,8 @@ package fuzs.armorstatues.config; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.AbstractArmorStandScreen; import fuzs.puzzleslib.api.config.v3.Config; import fuzs.puzzleslib.api.config.v3.ConfigCore; +import fuzs.statuemenus.api.v1.client.gui.screens.AbstractArmorStandScreen; public class ClientConfig implements ConfigCore { @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..44c0b50 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java @@ -0,0 +1,39 @@ +package fuzs.armorstatues.data.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + builder.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + builder.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + builder.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); + builder.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + builder.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); + builder.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + builder.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + builder.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + builder.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + builder.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armor stand which opened builder menu."); + builder.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + builder.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using builder menu and disables interaction with the equipment slots."); + builder.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + builder.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + builder.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + builder.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index 7e4f965..39f282a 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -2,14 +2,10 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.init.ModRegistry; -import fuzs.armorstatues.network.S2CPingMessage; import fuzs.armorstatues.proxy.Proxy; -import fuzs.puzzlesapi.api.statues.v1.helper.ArmorStandInteractHelper; +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; -import net.minecraft.client.multiplayer.MultiPlayerGameMode; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.network.Connection; -import net.minecraft.server.level.ServerPlayer; +import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.Entity; @@ -21,13 +17,12 @@ import net.minecraft.world.phys.Vec3; public class ArmorStandInteractHandler { - private static boolean presentServerside; public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { if (player.getAbilities().mayBuild && target.getType() == EntityType.ARMOR_STAND) { - boolean clientsideOnly = level.isClientSide && !presentServerside; + boolean clientsideOnly = level.isClientSide && !ModLoaderEnvironment.INSTANCE.isModPresentServerside(ArmorStatues.MOD_ID); // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients - MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.get(); + MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.value(); EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, menuType, ModRegistry.ARMOR_STAND_DATA_PROVIDER); if (result.isInterrupt() && clientsideOnly) { Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); @@ -40,16 +35,4 @@ public static EventResultHolder onUseEntityAt(Player player, } return EventResultHolder.pass(); } - - public static void onLoggedIn(ServerPlayer player) { - ArmorStatues.NETWORK.sendTo(new S2CPingMessage(), player); - } - - public static void onLoggedIn(LocalPlayer player, MultiPlayerGameMode multiPlayerGameMode, Connection connection) { - presentServerside = false; - } - - public static void setPresentServerside() { - presentServerside = true; - } } diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index cd5e925..c296189 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -1,19 +1,19 @@ package fuzs.armorstatues.init; import fuzs.armorstatues.ArmorStatues; -import fuzs.puzzlesapi.api.statues.v1.world.entity.decoration.ArmorStandDataProvider; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandMenu; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; -import fuzs.puzzleslib.api.init.v2.RegistryManager; -import fuzs.puzzleslib.api.init.v2.RegistryReference; +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; +import fuzs.statuemenus.api.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.core.Holder; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; public class ModRegistry { - static final RegistryManager REGISTRY = RegistryManager.instant(ArmorStatues.MOD_ID); - public static final RegistryReference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuType("armor_stand", () -> (containerId, inventory, data) -> { - return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.get(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + static final RegistryManager REGISTRY = RegistryManager.from(ArmorStatues.MOD_ID); + public static final Holder.Reference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuType("armor_stand", () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); }); public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); @@ -27,6 +27,6 @@ public ArmorStandScreenType[] getScreenTypes() { }; public static void touch() { - + // NO-OP } } diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java deleted file mode 100644 index f2d0bbe..0000000 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/S2CPingMessage.java +++ /dev/null @@ -1,30 +0,0 @@ -package fuzs.armorstatues.network; - -import fuzs.armorstatues.handler.ArmorStandInteractHandler; -import fuzs.puzzleslib.api.network.v2.MessageV2; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.world.entity.player.Player; - -public class S2CPingMessage implements MessageV2 { - - @Override - public void write(FriendlyByteBuf buf) { - - } - - @Override - public void read(FriendlyByteBuf buf) { - - } - - @Override - public MessageHandler makeHandler() { - return new MessageHandler<>() { - - @Override - public void handle(S2CPingMessage message, Player player, Object gameInstance) { - ArmorStandInteractHandler.setPresentServerside(); - } - }; - } -} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 145ec94..3d8b59a 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -4,12 +4,12 @@ import com.mojang.datafixers.util.Unit; import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.config.ClientConfig; -import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandAlignment; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandPose; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandScreenType; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.ArmorStandStyleOption; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandPose; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandStyleOption; import net.minecraft.ChatFormatting; import net.minecraft.client.player.LocalPlayer; import net.minecraft.nbt.CompoundTag; diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java index e573f08..dbdc639 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -6,8 +6,8 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.config.ClientConfig; import fuzs.armorstatues.init.ModRegistry; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.data.*; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.*; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.Rotations; import net.minecraft.network.chat.Component; diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java index 38e9040..554fba9 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -5,10 +5,10 @@ import fuzs.armorstatues.init.ModRegistry; import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; -import fuzs.puzzlesapi.api.client.statues.v1.gui.screens.armorstand.ArmorStandScreenFactory; -import fuzs.puzzlesapi.api.statues.v1.network.client.data.DataSyncHandler; -import fuzs.puzzlesapi.api.statues.v1.world.entity.decoration.ArmorStandDataProvider; -import fuzs.puzzlesapi.api.statues.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.player.LocalPlayer; diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java index 81856ec..f41e246 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java @@ -7,6 +7,6 @@ public class ServerProxy implements Proxy { @Override public void openArmorStandScreen(ArmorStand armorStand, Player player) { - + // NO-OP } } 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..4cfa289 --- /dev/null +++ b/1.20.4/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "armorstatues.accesswidener" +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/armorstatues.accesswidener b/1.20.4/Common/src/main/resources/armorstatues.accesswidener new file mode 100644 index 0000000..236e6b1 --- /dev/null +++ b/1.20.4/Common/src/main/resources/armorstatues.accesswidener @@ -0,0 +1 @@ +accessWidener v2 named 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/Fabric/build.gradle b/1.20.4/Fabric/build.gradle index 56fc5da..ac4ba5e 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 @@ -9,26 +7,6 @@ dependencies { // Puzzles Lib modApi libs.puzzleslib.fabric - // Puzzles Api - modApi(include(libs.puzzlesapi.fabric.get())) { - exclude group: "fuzs.puzzleslib" - } - - // 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())) - - // Quality of Life Mods - versionCatalog.findLibrary("modmenu.fabric").ifPresent { - modLocalRuntime(it) - } - versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { - modLocalRuntime(it) - } + // Statue Menus + modApi(include(libs.statuemenus.fabric.get())) } diff --git a/1.20.4/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java b/1.20.4/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java similarity index 79% rename from 1.20.4/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java rename to 1.20.4/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java index 65493b3..822cef4 100644 --- a/1.20.4/Fabric/src/main/java/fuzs/armorstatues/ArmorStatuesFabric.java +++ b/1.20.4/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java @@ -1,5 +1,6 @@ -package fuzs.armorstatues; +package fuzs.armorstatues.fabric; +import fuzs.armorstatues.ArmorStatues; import fuzs.puzzleslib.api.core.v1.ModConstructor; import net.fabricmc.api.ModInitializer; diff --git a/1.20.4/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java b/1.20.4/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java similarity index 79% rename from 1.20.4/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java rename to 1.20.4/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java index ee3baac..2414106 100644 --- a/1.20.4/Fabric/src/main/java/fuzs/armorstatues/client/ArmorStatuesFabricClient.java +++ b/1.20.4/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java @@ -1,6 +1,7 @@ -package fuzs.armorstatues.client; +package fuzs.armorstatues.fabric.client; import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.client.ArmorStatuesClient; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import net.fabricmc.api.ClientModInitializer; 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 d1caf67..d67e512 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}", @@ -31,13 +31,15 @@ }, "mixins": [ + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" ], "depends": { "fabricloader": ">=${minFabricVersion}", "fabric-api": ">=${minFabricApiVersion}", "puzzleslib": ">=${minPuzzlesVersion}", - "puzzlesapi": "*", + "statuemenus": "*", "minecraft": "${minecraftVersion}", "java": ">=17" } diff --git a/1.20.4/Forge/build.gradle b/1.20.4/Forge/build.gradle index 29049d3..a0ed80c 100644 --- a/1.20.4/Forge/build.gradle +++ b/1.20.4/Forge/build.gradle @@ -1,38 +1,9 @@ -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()) - - // Puzzles Api - api(fg.deobf(libs.puzzlesapi.forge.get())) { - transitive = false - } - jarJar(fg.deobf(libs.puzzlesapi.forge.get()) { - jarJar.ranged(it, "[${libs.versions.puzzlesapi.get()},)") - transitive = false - }) + modApi libs.puzzleslib.forge - // Quality of Life Mods - versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } -// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.get()}") - versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } + // Statue Menus + modApi(include(libs.statuemenus.forge.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/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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20.4/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 deleted file mode 100644 index 8e2c24f..0000000 --- a/1.20.4/Forge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2023-07-29T15:02:23.443069 Languages: en_us -9ecbeccea1af534ecf344346c3f5cecde17fd977 assets/armorstatues/lang/en_us.json diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java deleted file mode 100644 index 346a4a5..0000000 --- a/1.20.4/Forge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java +++ /dev/null @@ -1,23 +0,0 @@ -package fuzs.armorstatues; - -import fuzs.armorstatues.data.ModLanguageProvider; -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -@Mod(ArmorStatues.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -public class ArmorStatuesForge { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); - } - - @SubscribeEvent - public static void onGatherData(final GatherDataEvent evt) { - evt.getGenerator().addProvider(true, new ModLanguageProvider(evt, ArmorStatues.MOD_ID)); - } -} diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java deleted file mode 100644 index 53b29c2..0000000 --- a/1.20.4/Forge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -package fuzs.armorstatues.data; - -import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; -import fuzs.armorstatues.init.ModRegistry; -import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; -import fuzs.puzzleslib.api.data.v1.AbstractLanguageProvider; -import net.minecraftforge.data.event.GatherDataEvent; - -public class ModLanguageProvider extends AbstractLanguageProvider { - - public ModLanguageProvider(GatherDataEvent evt, String modId) { - super(evt, modId); - } - - @Override - protected void addTranslations() { - // Armor Statues - this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); - this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); - this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); - this.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); - this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); - this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); - this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); - this.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); - this.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); - this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); - this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu."); - this.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); - this.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots."); - this.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); - this.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); - this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); - this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/ArmorStatuesForge.java similarity index 61% rename from 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java rename to 1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/ArmorStatuesForge.java index 346a4a5..e4cb244 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/ArmorStatuesForge.java +++ b/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/ArmorStatuesForge.java @@ -1,8 +1,7 @@ -package fuzs.armorstatues; +package fuzs.armorstatues.forge; -import fuzs.armorstatues.data.ModLanguageProvider; +import fuzs.armorstatues.ArmorStatues; import fuzs.puzzleslib.api.core.v1.ModConstructor; -import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; @@ -15,9 +14,4 @@ public class ArmorStatuesForge { public static void onConstructMod(final FMLConstructModEvent evt) { ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); } - - @SubscribeEvent - public static void onGatherData(final GatherDataEvent evt) { - evt.getGenerator().addProvider(true, new ModLanguageProvider(evt, ArmorStatues.MOD_ID)); - } } diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java similarity index 96% rename from 1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java rename to 1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java index c50ecce..01aa112 100644 --- a/1.20.4/Forge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java +++ b/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java @@ -1,6 +1,7 @@ -package fuzs.armorstatues.client; +package fuzs.armorstatues.forge.client; import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.client.ArmorStatuesClient; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; 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 fac0264..3095160 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,20 +26,31 @@ 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" [[dependencies.${ modId }]] -modId = "puzzlesapi" +modId = "statuemenus" mandatory = true +type = "required" versionRange = "*" 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 29049d3..07725b4 100644 --- a/1.20.4/NeoForge/build.gradle +++ b/1.20.4/NeoForge/build.gradle @@ -1,38 +1,9 @@ -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()) - - // Puzzles Api - api(fg.deobf(libs.puzzlesapi.forge.get())) { - transitive = false - } - jarJar(fg.deobf(libs.puzzlesapi.forge.get()) { - jarJar.ranged(it, "[${libs.versions.puzzlesapi.get()},)") - transitive = false - }) + modApi libs.puzzleslib.neoforge - // Quality of Life Mods - versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } -// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.get()}") - versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } + // Statue Menus + modApi(include(libs.statuemenus.neoforge.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/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/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/1.20.4/NeoForge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 deleted file mode 100644 index 8e2c24f..0000000 --- a/1.20.4/NeoForge/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2023-07-29T15:02:23.443069 Languages: en_us -9ecbeccea1af534ecf344346c3f5cecde17fd977 assets/armorstatues/lang/en_us.json diff --git a/1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json deleted file mode 100644 index e392806..0000000 --- a/1.20.4/NeoForge/src/generated/resources/assets/armorstatues/lang/en_us.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", - "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", - "armorstatues.dataSync.failure.noPermission": "No Permission", - "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", - "armorstatues.dataSync.failure.outOfRange": "Out Of Range", - "armorstatues.dataSync.finished": "Finished sending queued armor stand data", - "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", - "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu.", - "armorstatues.screen.vanillaTweaks.lock": "Lock", - "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots.", - "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", - "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", - "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", - "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", - "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", - "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", - "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", - "armorstatues.screen.vanillaTweaks.unlock": "Unlock", - "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", - "puzzlesapi.screen.type.alignments": "Alignments", - "puzzlesapi.screen.type.vanillaTweaks": "Vanilla Tweaks" -} \ No newline at end of file diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java deleted file mode 100644 index 53b29c2..0000000 --- a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/data/ModLanguageProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -package fuzs.armorstatues.data; - -import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; -import fuzs.armorstatues.init.ModRegistry; -import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; -import fuzs.puzzleslib.api.data.v1.AbstractLanguageProvider; -import net.minecraftforge.data.event.GatherDataEvent; - -public class ModLanguageProvider extends AbstractLanguageProvider { - - public ModLanguageProvider(GatherDataEvent evt, String modId) { - super(evt, modId); - } - - @Override - protected void addTranslations() { - // Armor Statues - this.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); - this.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); - this.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); - this.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); - this.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); - this.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); - this.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); - this.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); - this.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); - this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); - this.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armor stand which opened this menu."); - this.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); - this.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using this menu and disables interaction with the equipment slots."); - this.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); - this.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); - this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); - this.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); - this.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java new file mode 100644 index 0000000..8557403 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java @@ -0,0 +1,20 @@ +package fuzs.armorstatues.neoforge; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.data.client.ModLanguageProvider; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(ArmorStatues.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ArmorStatuesNeoForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + DataProviderHelper.registerDataProviders(ArmorStatues.MOD_ID, ModLanguageProvider::new); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java similarity index 76% rename from 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java rename to 1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java index c50ecce..2d76a66 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/client/ArmorStatuesForgeClient.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java @@ -1,6 +1,7 @@ -package fuzs.armorstatues.client; +package fuzs.armorstatues.neoforge.client; import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.client.ArmorStatuesClient; import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; @@ -10,15 +11,15 @@ import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.InputEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +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; +import net.neoforged.neoforge.client.event.InputEvent; +import net.neoforged.neoforge.common.NeoForge; @Mod.EventBusSubscriber(modid = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class ArmorStatuesForgeClient { +public class ArmorStatuesNeoForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { @@ -27,7 +28,7 @@ public static void onConstructMod(final FMLConstructModEvent evt) { } private static void registerHandlers() { - MinecraftForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { + NeoForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { Minecraft minecraft = Minecraft.getInstance(); if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { @@ -40,7 +41,7 @@ private static void registerHandlers() { EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work - if (result.filter(t -> t == InteractionResult.FAIL).isInterrupt()) { + if (result.filter(interactionResult -> interactionResult == InteractionResult.FAIL).isInterrupt()) { evt.setSwingHand(false); evt.setCanceled(true); } 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 fac0264..432ab6c 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,13 +40,15 @@ side = "BOTH" [[dependencies.${ modId }]] modId = "puzzleslib" mandatory = true +type = "required" versionRange = "[${minPuzzlesVersion},)" ordering = "NONE" side = "BOTH" [[dependencies.${ modId }]] -modId = "puzzlesapi" +modId = "statuemenus" mandatory = true +type = "required" versionRange = "*" 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 f4ac86b..b63344f 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=armorstatues modName=Armor Statues -modVersion=8.0.5 +modVersion=20.4.0 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -21,18 +18,26 @@ modForgeDisplayTest=IGNORE_ALL_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-v23 +dependenciesPuzzlesLibVersion=20.4.21 +dependenciesMinPuzzlesLibVersion=20.4.21 + # Mod Publishing projectReleaseType=release projectCurseForgeId=682566 projectModrinthId=bbGCtEvb -dependenciesVersionCatalog=1.20.1-v25 -dependenciesPuzzlesLibVersion=8.1.11 -dependenciesMinPuzzlesLibVersion=8.1.11 -dependenciesPuzzlesApi=8.1.4 -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 -#dependenciesEmbeddedFabricModrinth=cardinal-components-api +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 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 bf7e2e5..e401f79 100644 --- a/1.20.4/settings.gradle +++ b/1.20.4/settings.gradle @@ -1,23 +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/" } } } -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/settings.gradle' +include("Common", "Fabric", "NeoForge", "Forge") + +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From d9d679f80026fc6b95eee587df760865b4257925 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 16 Mar 2024 22:15:15 +0100 Subject: [PATCH 22/31] fix removing equipment on servers without mod --- 1.20.4/CHANGELOG.md | 6 +++ .../java/fuzs/armorstatues/ArmorStatues.java | 7 ++-- .../client/ArmorStatuesClient.java | 9 ++++- .../client/handler/ClientInteractHandler.java | 39 +++++++++++++++++++ .../handler/ArmorStandInteractHandler.java | 5 +++ .../forge/client/ArmorStatuesForgeClient.java | 34 ---------------- .../neoforge/ArmorStatuesNeoForge.java | 3 -- .../client/ArmorStatuesNeoForgeClient.java | 37 ++---------------- 1.20.4/gradle.properties | 8 ++-- 9 files changed, 68 insertions(+), 80 deletions(-) create mode 100644 1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index 72b0350..ec91fce 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -4,6 +4,12 @@ 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-03-16 +### Changed +- Bump bundled Statue Menus mod to v20.4.2 +### Fixed +- Fix equipment changing when opening the armor stand menu on dedicated servers without the mod on Fabric + ## [v20.4.0-1.20.4] - 2024-02-10 - Port to Minecraft 1.20.4 - Port to NeoForge diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java index 4e42e41..8ac4dac 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -20,11 +20,12 @@ public class ArmorStatues implements ModConstructor { @Override public void onConstructMod() { ModRegistry.touch(); - registerHandlers(); + registerEventHandlers(); } - private static void registerHandlers() { - // high priority so we run before the Quark mod + private static void registerEventHandlers() { + // high priority, so we run before other mods that add armor stand interactions + // we require empty hand + shift, so those other mods can still run their behaviors when those conditions are not met PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); } } diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java index 644997c..2b4043c 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -3,13 +3,16 @@ import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; +import fuzs.armorstatues.client.handler.ClientInteractHandler; import fuzs.armorstatues.client.handler.DataSyncTickHandler; import fuzs.armorstatues.init.ModRegistry; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; import fuzs.puzzleslib.api.client.event.v1.ClientTickEvents; +import fuzs.puzzleslib.api.client.event.v1.entity.player.InteractionInputEvents; import fuzs.puzzleslib.api.client.event.v1.gui.ItemTooltipCallback; import fuzs.puzzleslib.api.client.event.v1.gui.ScreenEvents; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; import net.minecraft.client.gui.screens.Screen; @@ -20,13 +23,15 @@ public class ArmorStatuesClient implements ClientModConstructor { @Override public void onConstructMod() { - registerHandlers(); + registerEventHandlers(); } - private static void registerHandlers() { + private static void registerEventHandlers() { ItemTooltipCallback.EVENT.register(ArmorStandTooltipHandler::onItemTooltip); ClientTickEvents.END.register(DataSyncTickHandler::onEndClientTick); ScreenEvents.remove(Screen.class).register(DataSyncTickHandler::onRemove); + // event phase must match PlayerInteractEvents#USE_ENTITY_AT as both are implemented using the same event on Fabric + InteractionInputEvents.USE.register(EventPhase.BEFORE, ClientInteractHandler::onUseInteraction); } @Override diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java new file mode 100644 index 0000000..22b26d2 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java @@ -0,0 +1,39 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.event.v1.core.EventResult; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class ClientInteractHandler { + + public static EventResult onUseInteraction(Minecraft minecraft, LocalPlayer player, InteractionHand interactionHand, HitResult hitResult) { + + if (hitResult.getType() == HitResult.Type.ENTITY) { + + Entity entity = ((EntityHitResult) hitResult).getEntity(); + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, + minecraft.level, + interactionHand, + entity, + hitVector + ); + + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + if (result.filter(interactionResult -> interactionResult == InteractionResult.FAIL).isInterrupt()) { + + return EventResult.INTERRUPT; + } + } + + return EventResult.PASS; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java index 39f282a..2dd8af0 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -19,20 +19,25 @@ public class ArmorStandInteractHandler { public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { + if (player.getAbilities().mayBuild && target.getType() == EntityType.ARMOR_STAND) { + boolean clientsideOnly = level.isClientSide && !ModLoaderEnvironment.INSTANCE.isModPresentServerside(ArmorStatues.MOD_ID); // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.value(); EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, menuType, ModRegistry.ARMOR_STAND_DATA_PROVIDER); if (result.isInterrupt() && clientsideOnly) { + Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here player.swing(interactionHand); return EventResultHolder.interrupt(InteractionResult.FAIL); } + return result; } + return EventResultHolder.pass(); } } diff --git a/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java index 01aa112..c263dd4 100644 --- a/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java +++ b/1.20.4/Forge/src/main/java/fuzs/armorstatues/forge/client/ArmorStatuesForgeClient.java @@ -2,18 +2,8 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.client.ArmorStatuesClient; -import fuzs.armorstatues.handler.ArmorStandInteractHandler; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; -import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.InputEvent; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; @@ -24,29 +14,5 @@ public class ArmorStatuesForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); - registerHandlers(); - } - - private static void registerHandlers() { - MinecraftForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { - - Minecraft minecraft = Minecraft.getInstance(); - if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { - - EntityHitResult hitResult = (EntityHitResult) minecraft.hitResult; - Entity entity = hitResult.getEntity(); - if (minecraft.level.getWorldBorder().isWithinBounds(entity.blockPosition())) { - - Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); - EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); - // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact - // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work - if (result.filter(t -> t == InteractionResult.FAIL).isInterrupt()) { - evt.setSwingHand(false); - evt.setCanceled(true); - } - } - } - }); } } diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java index 8557403..1dd837f 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java @@ -1,9 +1,7 @@ package fuzs.armorstatues.neoforge; import fuzs.armorstatues.ArmorStatues; -import fuzs.armorstatues.data.client.ModLanguageProvider; import fuzs.puzzleslib.api.core.v1.ModConstructor; -import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; @@ -15,6 +13,5 @@ public class ArmorStatuesNeoForge { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); - DataProviderHelper.registerDataProviders(ArmorStatues.MOD_ID, ModLanguageProvider::new); } } diff --git a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java index 2d76a66..dde7adc 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java @@ -2,21 +2,13 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.armorstatues.client.ArmorStatuesClient; -import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.data.client.ModLanguageProvider; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; -import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; -import net.minecraft.client.Minecraft; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; 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; -import net.neoforged.neoforge.client.event.InputEvent; -import net.neoforged.neoforge.common.NeoForge; @Mod.EventBusSubscriber(modid = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ArmorStatuesNeoForgeClient { @@ -24,29 +16,6 @@ public class ArmorStatuesNeoForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); - registerHandlers(); - } - - private static void registerHandlers() { - NeoForge.EVENT_BUS.addListener((final InputEvent.InteractionKeyMappingTriggered evt) -> { - - Minecraft minecraft = Minecraft.getInstance(); - if (evt.isUseItem() && minecraft.hitResult != null && minecraft.hitResult.getType() == HitResult.Type.ENTITY) { - - EntityHitResult hitResult = (EntityHitResult) minecraft.hitResult; - Entity entity = hitResult.getEntity(); - if (minecraft.level.getWorldBorder().isWithinBounds(entity.blockPosition())) { - - Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); - EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, minecraft.level, evt.getHand(), entity, hitVector); - // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact - // only Fabric sending the packet is simple prevented by returning InteractionResult.FAIL from ArmorStandInteractHandler::onUseEntityAt, on Forge this approach seems to work - if (result.filter(interactionResult -> interactionResult == InteractionResult.FAIL).isInterrupt()) { - evt.setSwingHand(false); - evt.setCanceled(true); - } - } - } - }); + DataProviderHelper.registerDataProviders(ArmorStatues.MOD_ID, ModLanguageProvider::new); } } diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index b63344f..037b2c9 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=20.4.0 +modVersion=20.4.1 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -19,9 +19,9 @@ modForgeDisplayTest=IGNORE_ALL_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.20.4-v23 -dependenciesPuzzlesLibVersion=20.4.21 -dependenciesMinPuzzlesLibVersion=20.4.21 +dependenciesVersionCatalog=1.20.4-v35 +#dependenciesPuzzlesLibVersion=20.4.21 +#dependenciesMinPuzzlesLibVersion=20.4.21 # Mod Publishing projectReleaseType=release From 5d99a10765c8d3d7a0d65679b667b58ad14456f2 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sun, 7 Apr 2024 08:48:08 +0200 Subject: [PATCH 23/31] allow forcing Vanilla Tweaks command handler --- 1.20.1/CHANGELOG.md | 4 ++++ .../main/java/fuzs/armorstatues/proxy/ClientProxy.java | 9 +++++++-- 1.20.1/gradle.properties | 2 +- 1.20.4/CHANGELOG.md | 4 ++++ .../main/java/fuzs/armorstatues/proxy/ClientProxy.java | 9 +++++++-- 1.20.4/gradle.properties | 2 +- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/1.20.1/CHANGELOG.md b/1.20.1/CHANGELOG.md index dc05013..1e48d5c 100644 --- a/1.20.1/CHANGELOG.md +++ b/1.20.1/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.6-1.20.1] - 2024-04-07 +### Changed +- Allow `override_client_permissions_check` config option to also force enabling of the Vanilla Tweaks triggers command handler + ## [v8.0.5-1.20.1] - 2023-12-03 ### Changed - Client side permissions check can now be disabled in the config diff --git a/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java index 38e9040..3cf5225 100644 --- a/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java +++ b/1.20.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -31,13 +31,18 @@ public ArmorStandDataProvider getDataProvider() { return ModRegistry.ARMOR_STAND_DATA_PROVIDER; } }; - Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(holder, (LocalPlayer) player)); + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, + player.getInventory(), + armorStand.getDisplayName(), + createDataSyncHandler(holder, (LocalPlayer) player) + ); Minecraft minecraft = Minecraft.getInstance(); minecraft.setScreen(screen); } private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { - if (!player.hasPermissions(2) && ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + if ((!player.hasPermissions(2) || ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck) && + ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { return new VanillaTweaksDataSyncHandler(holder, player); } else { return new CommandDataSyncHandler(holder, player); diff --git a/1.20.1/gradle.properties b/1.20.1/gradle.properties index f4ac86b..38d6730 100755 --- a/1.20.1/gradle.properties +++ b/1.20.1/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=8.0.5 +modVersion=8.0.6 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index ec91fce..f07319e 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-04-07 +### Changed +- Allow `override_client_permissions_check` config option to also force enabling of the Vanilla Tweaks triggers command handler + ## [v20.4.1-1.20.4] - 2024-03-16 ### Changed - Bump bundled Statue Menus mod to v20.4.2 diff --git a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java index 554fba9..3689876 100644 --- a/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java +++ b/1.20.4/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -31,13 +31,18 @@ public ArmorStandDataProvider getDataProvider() { return ModRegistry.ARMOR_STAND_DATA_PROVIDER; } }; - Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, player.getInventory(), armorStand.getDisplayName(), createDataSyncHandler(holder, (LocalPlayer) player)); + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, + player.getInventory(), + armorStand.getDisplayName(), + createDataSyncHandler(holder, (LocalPlayer) player) + ); Minecraft minecraft = Minecraft.getInstance(); minecraft.setScreen(screen); } private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { - if (!player.hasPermissions(2) && ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + if ((!player.hasPermissions(2) || ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck) && + ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { return new VanillaTweaksDataSyncHandler(holder, player); } else { return new CommandDataSyncHandler(holder, player); diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index 037b2c9..00a426e 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=20.4.1 +modVersion=20.4.2 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 From 6f9f2867ce90cc1a1e20f62118a957f71b2bb0f6 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 11 Jul 2024 14:27:56 +0200 Subject: [PATCH 24/31] prepare 1.21 port --- 1.21/CHANGELOG.md | 19 + 1.21/Common/build.gradle | 13 + .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../assets/armorstatues/lang/en_us.json | 23 ++ .../java/fuzs/armorstatues/ArmorStatues.java | 31 ++ .../client/ArmorStatuesClient.java | 51 +++ .../ArmorStandAlignmentsScreen.java | 54 +++ .../ArmorStandVanillaTweaksScreen.java | 75 ++++ .../handler/ArmorStandTooltipHandler.java | 26 ++ .../client/handler/ClientInteractHandler.java | 39 ++ .../client/handler/DataSyncTickHandler.java | 28 ++ .../armorstatues/config/ClientConfig.java | 15 + .../data/client/ModLanguageProvider.java | 39 ++ .../handler/ArmorStandInteractHandler.java | 43 +++ .../fuzs/armorstatues/init/ModRegistry.java | 32 ++ .../client/data/CommandDataSyncHandler.java | 226 +++++++++++ .../data/VanillaTweaksDataSyncHandler.java | 359 ++++++++++++++++++ .../fuzs/armorstatues/proxy/ClientProxy.java | 51 +++ .../java/fuzs/armorstatues/proxy/Proxy.java | 11 + .../fuzs/armorstatues/proxy/ServerProxy.java | 12 + .../main/resources/architectury.common.json | 3 + .../main/resources/armorstatues.accesswidener | 1 + .../src/main/resources/common.mixins.json | 13 + 1.21/Common/src/main/resources/mod_banner.png | Bin 0 -> 15383 bytes 1.21/Common/src/main/resources/mod_logo.png | Bin 0 -> 9380 bytes 1.21/Common/src/main/resources/pack.mcmeta | 6 + 1.21/Fabric/build.gradle | 12 + .../fabric/ArmorStatuesFabric.java | 13 + .../client/ArmorStatuesFabricClient.java | 14 + .../src/main/resources/fabric.mixins.json | 14 + .../Fabric/src/main/resources/fabric.mod.json | 46 +++ 1.21/NeoForge/build.gradle | 9 + 1.21/NeoForge/gradle.properties | 1 + .../neoforge/ArmorStatuesNeoForge.java | 17 + .../client/ArmorStatuesNeoForgeClient.java | 21 + .../src/main/resources/META-INF/mods.toml | 57 +++ .../src/main/resources/neoforge.mixins.json | 13 + 1.21/build.gradle | 9 + 1.21/gradle.properties | 43 +++ 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 | 13 + 44 files changed, 1796 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/assets/armorstatues/lang/en_us.json create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java create mode 100644 1.21/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java create mode 100644 1.21/Common/src/main/resources/architectury.common.json create mode 100644 1.21/Common/src/main/resources/armorstatues.accesswidener 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/Fabric/build.gradle create mode 100644 1.21/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java create mode 100644 1.21/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.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/armorstatues/neoforge/ArmorStatuesNeoForge.java create mode 100644 1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java create mode 100644 1.21/NeoForge/src/main/resources/META-INF/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..f07319e --- /dev/null +++ b/1.21/CHANGELOG.md @@ -0,0 +1,19 @@ +# 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). + +## [v20.4.2-1.20.4] - 2024-04-07 +### Changed +- Allow `override_client_permissions_check` config option to also force enabling of the Vanilla Tweaks triggers command handler + +## [v20.4.1-1.20.4] - 2024-03-16 +### Changed +- Bump bundled Statue Menus mod to v20.4.2 +### Fixed +- Fix equipment changing when opening the armor stand menu on dedicated servers without the mod on Fabric + +## [v20.4.0-1.20.4] - 2024-02-10 +- Port to Minecraft 1.20.4 +- Port to NeoForge diff --git a/1.21/Common/build.gradle b/1.21/Common/build.gradle new file mode 100644 index 0000000..4971f9a --- /dev/null +++ b/1.21/Common/build.gradle @@ -0,0 +1,13 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/common.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common + + // Statue Menus + modApi libs.statuemenus.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..95dc085 --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.20.4 2024-02-10T01:11:18.844688 Language (en_us) +3b837616894d5f092cf8c1f8e4658d723dbc0320 assets/armorstatues/lang/en_us.json diff --git a/1.21/Common/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.21/Common/src/generated/resources/assets/armorstatues/lang/en_us.json new file mode 100644 index 0000000..1235c24 --- /dev/null +++ b/1.21/Common/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armor stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armor stand which opened builder menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using builder menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", + "statuemenus.screen.type.alignments": "Alignments", + "statuemenus.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java new file mode 100644 index 0000000..8ac4dac --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -0,0 +1,31 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArmorStatues implements ModConstructor { + public static final String MOD_ID = "armorstatues"; + public static final String MOD_NAME = "Armor Statues"; + 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(); + registerEventHandlers(); + } + + private static void registerEventHandlers() { + // high priority, so we run before other mods that add armor stand interactions + // we require empty hand + shift, so those other mods can still run their behaviors when those conditions are not met + PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java new file mode 100644 index 0000000..2b4043c --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; +import fuzs.armorstatues.client.handler.ClientInteractHandler; +import fuzs.armorstatues.client.handler.DataSyncTickHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; +import fuzs.puzzleslib.api.client.event.v1.ClientTickEvents; +import fuzs.puzzleslib.api.client.event.v1.entity.player.InteractionInputEvents; +import fuzs.puzzleslib.api.client.event.v1.gui.ItemTooltipCallback; +import fuzs.puzzleslib.api.client.event.v1.gui.ScreenEvents; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +public class ArmorStatuesClient implements ClientModConstructor { + + @Override + public void onConstructMod() { + registerEventHandlers(); + } + + private static void registerEventHandlers() { + ItemTooltipCallback.EVENT.register(ArmorStandTooltipHandler::onItemTooltip); + ClientTickEvents.END.register(DataSyncTickHandler::onEndClientTick); + ScreenEvents.remove(Screen.class).register(DataSyncTickHandler::onRemove); + // event phase must match PlayerInteractEvents#USE_ENTITY_AT as both are implemented using the same event on Fabric + InteractionInputEvents.USE.register(EventPhase.BEFORE, ClientInteractHandler::onUseInteraction); + } + + @Override + public void onClientSetup() { + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); + } + + @SuppressWarnings("Convert2MethodRef") + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { + // compiler doesn't like method reference :( + context.registerMenuScreen(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), (ArmorStandMenu menu, Inventory inventory, Component component) -> { + return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); + }); + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java new file mode 100644 index 0000000..df01829 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -0,0 +1,54 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandButtonsScreen; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandPositionScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.phys.Vec3; + +import java.util.EnumSet; +import java.util.List; + +public class ArmorStandAlignmentsScreen extends ArmorStandButtonsScreen { + + public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new DoubleButtonWidget(Component.translatable(ArmorStandPositionScreen.CENTERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + })); + for (ArmorStandAlignment alignment : ArmorStandAlignment.values()) { + widgets.add(new SingleButtonWidget(Component.translatable(alignment.getTranslationKey()), Component.translatable(alignment.getDescriptionsKey()), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendAlignment(alignment); + })); + } + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.ALIGNMENTS_SCREEN_TYPE; + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java new file mode 100644 index 0000000..f52054d --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java @@ -0,0 +1,75 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandButtonsScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; + +import java.util.List; + +public class ArmorStandVanillaTweaksScreen extends ArmorStandButtonsScreen { + public static final String TRIGGER_SENT_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.triggerSent"; + public static final String CHECK_TARGET_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget"; + public static final String CHECK_TARGET_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget.description"; + public static final String LOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock"; + public static final String LOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock.description"; + public static final String UNLOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock"; + public static final String UNLOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock.description"; + public static final String TOOL_RACK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack"; + public static final String TOOL_RACK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack.description"; + public static final String SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand"; + public static final String SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand.description"; + public static final String SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead"; + public static final String SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead.description"; + + public ArmorStandVanillaTweaksScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + public VanillaTweaksDataSyncHandler getDataSyncHandler() { + return (VanillaTweaksDataSyncHandler) super.getDataSyncHandler(); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new SingleButtonWidget(Component.translatable(CHECK_TARGET_TRANSLATION_KEY), Component.translatable(CHECK_TARGET_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.CHECK_TARGET); + this.onClose(); + })); + widgets.add(new DoubleButtonWidget(Component.translatable(LOCK_TRANSLATION_KEY), Component.translatable(UNLOCK_TRANSLATION_KEY), Component.translatable(LOCK_DESCRIPTION_KEY), Component.translatable(UNLOCK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_LOCK); + }, button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_UNLOCK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(TOOL_RACK_TRANSLATION_KEY), Component.translatable(TOOL_RACK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.AUTO_ALIGNMENT_TOOL_RACK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_OFFHAND); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_HEAD); + })); + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE; + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java new file mode 100644 index 0000000..29864c3 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -0,0 +1,26 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.puzzleslib.api.core.v1.Proxy; +import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ArmorStandTooltipHandler { + + public static void onItemTooltip(ItemStack stack, @Nullable Player player, List lines, TooltipFlag context) { + if (stack.is(Items.ARMOR_STAND)) { + List components = Proxy.INSTANCE.splitTooltipLines(ArmorStandInteractHelper.getArmorStandHoverText()); + if (context.isAdvanced()) { + lines.addAll(lines.size() - (stack.hasTag() ? 2 : 1), components); + } else { + lines.addAll(components); + } + } + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java new file mode 100644 index 0000000..22b26d2 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java @@ -0,0 +1,39 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.event.v1.core.EventResult; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class ClientInteractHandler { + + public static EventResult onUseInteraction(Minecraft minecraft, LocalPlayer player, InteractionHand interactionHand, HitResult hitResult) { + + if (hitResult.getType() == HitResult.Type.ENTITY) { + + Entity entity = ((EntityHitResult) hitResult).getEntity(); + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, + minecraft.level, + interactionHand, + entity, + hitVector + ); + + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + if (result.filter(interactionResult -> interactionResult == InteractionResult.FAIL).isInterrupt()) { + + return EventResult.INTERRUPT; + } + } + + return EventResult.PASS; + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java new file mode 100644 index 0000000..822390a --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -0,0 +1,28 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +public class DataSyncTickHandler { + @Nullable + private static DataSyncHandler dataSyncHandler; + + public static void onRemove(Screen screen) { + if (screen instanceof ArmorStandScreen armorStandScreen && armorStandScreen.getDataSyncHandler().shouldContinueTicking()) { + dataSyncHandler = armorStandScreen.getDataSyncHandler(); + } + } + + public static void onEndClientTick(Minecraft minecraft) { + if (minecraft.player != null && !(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (dataSyncHandler.shouldContinueTicking()) { + dataSyncHandler.tick(); + } else { + dataSyncHandler = null; + } + } + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.21/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java new file mode 100644 index 0000000..137797d --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -0,0 +1,15 @@ +package fuzs.armorstatues.config; + +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; +import fuzs.statuemenus.api.v1.client.gui.screens.AbstractArmorStandScreen; + +public class ClientConfig implements ConfigCore { + @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) + public boolean useVanillaTweaksTriggers = false; + @Config(description = "Do not check if the client has the necessary permission level for executing the '/data' command when trying to edit an armor stand. Useful when the current server is using custom permissions handling.") + public boolean overrideClientPermissionsCheck = false; + @Config(description = "The delay in ticks for sending queued client commands for editing armor stands to the server. Increase this values if commands are sent too quickly and the server fails to process all of them.") + @Config.IntRange(min = 20) + public int clientCommandDelay = 20; +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java b/1.21/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..44c0b50 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java @@ -0,0 +1,39 @@ +package fuzs.armorstatues.data.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + builder.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + builder.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + builder.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); + builder.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + builder.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); + builder.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + builder.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + builder.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + builder.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + builder.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armor stand which opened builder menu."); + builder.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + builder.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using builder menu and disables interaction with the equipment slots."); + builder.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + builder.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + builder.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + builder.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java new file mode 100644 index 0000000..2dd8af0 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -0,0 +1,43 @@ +package fuzs.armorstatues.handler; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.proxy.Proxy; +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class ArmorStandInteractHandler { + + public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { + + if (player.getAbilities().mayBuild && target.getType() == EntityType.ARMOR_STAND) { + + boolean clientsideOnly = level.isClientSide && !ModLoaderEnvironment.INSTANCE.isModPresentServerside(ArmorStatues.MOD_ID); + // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients + MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.value(); + EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, menuType, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + if (result.isInterrupt() && clientsideOnly) { + + Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); + // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen + // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here + player.swing(interactionHand); + return EventResultHolder.interrupt(InteractionResult.FAIL); + } + + return result; + } + + return EventResultHolder.pass(); + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java new file mode 100644 index 0000000..c296189 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -0,0 +1,32 @@ +package fuzs.armorstatues.init; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; +import fuzs.statuemenus.api.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.core.Holder; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.from(ArmorStatues.MOD_ID); + public static final Holder.Reference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuType("armor_stand", () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + }); + + public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); + public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", new ItemStack(Items.WRITTEN_BOOK)); + public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandScreenType.EQUIPMENT}; + } + }; + + public static void touch() { + // NO-OP + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java new file mode 100644 index 0000000..3d8b59a --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -0,0 +1,226 @@ +package fuzs.armorstatues.network.client.data; + +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandPose; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandStyleOption; +import net.minecraft.ChatFormatting; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.function.BiPredicate; + +public class CommandDataSyncHandler implements DataSyncHandler { + public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; + public static final String OUT_OF_RANGE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.outOfRange"; + public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; + private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); + + @Nullable + private static ArmorStand queueArmorStand; + private static int itemDequeuedTicks; + + private final ArmorStandHolder holder; + protected final LocalPlayer player; + protected ArmorStandPose lastSyncedPose; + + public CommandDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + this.holder = holder; + this.lastSyncedPose = ArmorStandPose.fromEntity(this.holder.getArmorStand()); + this.player = player; + } + + @Override + public ArmorStandHolder getArmorStandHolder() { + return this.holder; + } + + @Override + public void sendName(String name) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); + CompoundTag tag = new CompoundTag(); + tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); + this.enqueueEntityData(tag); + this.finalizeCurrentOperation(); + } + + @Override + public final void sendPose(ArmorStandPose pose) { + this.sendPose(pose, true); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.isEditingAllowed()) return; + // split this into multiple chat messages as the client chat field has a very low character limit + this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + if (finalize) this.finalizeCurrentOperation(); + } + + private void sendPosePart(BiPredicate dataWriter, ArmorStandPose lastSyncedPose) { + CompoundTag tag = new CompoundTag(); + if (dataWriter.test(tag, lastSyncedPose)) { + CompoundTag tagToSend = new CompoundTag(); + tagToSend.put("Pose", tag); + this.enqueueEntityData(tagToSend); + } + } + + @Override + public @Nullable ArmorStandPose getLastSyncedPose() { + return this.lastSyncedPose; + } + + @Override + public final void sendPosition(double posX, double posY, double posZ) { + this.sendPosition(posX, posY, posZ, true); + + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; + ListTag listTag = new ListTag(); + listTag.add(DoubleTag.valueOf(posX)); + listTag.add(DoubleTag.valueOf(posY)); + listTag.add(DoubleTag.valueOf(posZ)); + CompoundTag tag = new CompoundTag(); + tag.put("Pos", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendRotation(float rotation) { + this.sendRotation(rotation, true); + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; + ListTag listTag = new ListTag(); + listTag.add(FloatTag.valueOf(rotation)); + CompoundTag tag = new CompoundTag(); + tag.put("Rotation", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + this.sendStyleOption(styleOption, value, true); + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; + CompoundTag tag = new CompoundTag(); + styleOption.toTag(tag, value); + this.enqueueEntityData(tag); + styleOption.setOption(this.getArmorStand(), value); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.super.sendAlignment(alignment); + } + + @Override + public boolean supportsScreenType(ArmorStandScreenType screenType) { + return !screenType.requiresServer(); + } + + @Override + public void tick() { + if (itemDequeuedTicks > 0) itemDequeuedTicks--; + if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { + if (this.testArmorStand(queueArmorStand).right().isPresent()) { + this.player.connection.sendCommand(CLIENT_COMMAND_QUEUE.poll()); + } else { + CLIENT_COMMAND_QUEUE.clear(); + } + itemDequeuedTicks = this.getDequeueDelayTicks(); + } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { + this.sendDisplayMessage(Component.translatable(FINISHED_TRANSLATION_KEY), false); + } + } + + protected int getDequeueDelayTicks() { + return 5; + } + + @Override + public boolean shouldContinueTicking() { + return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; + } + + protected boolean isEditingAllowed() { + return this.isEditingAllowed(!ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck); + } + + protected final boolean isEditingAllowed(boolean testPermissionLevel) { + if (testPermissionLevel && !this.player.hasPermissions(2)) { + this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); + return false; + } + return this.player.getAbilities().mayBuild && this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); + } + + protected Either testArmorStand(ArmorStand armorStand) { + return !armorStand.isAlive() ? Either.left(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)) : Either.right(Unit.INSTANCE); + } + + protected boolean enqueueClientCommand(String clientCommand) { + if (CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = null; + } else if (queueArmorStand != null) { + this.sendFailureMessage(Component.translatable(NOT_FINISHED_TRANSLATION_KEY)); + return false; + } + CLIENT_COMMAND_QUEUE.offer(clientCommand); + return true; + } + + @Override + public void finalizeCurrentOperation() { + if (!CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = this.getArmorStand(); + } + } + + protected void sendFailureMessage(Component component) { + this.sendDisplayMessage(Component.translatable(FAILURE_TRANSLATION_KEY, component), true); + } + + protected void sendDisplayMessage(Component component, boolean failure) { + this.player.displayClientMessage(Component.empty().append(component).withStyle(failure ? ChatFormatting.RED : ChatFormatting.GREEN), false); + } + + private void enqueueEntityData(CompoundTag tag) { + this.enqueueClientCommand("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString())); + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java new file mode 100644 index 0000000..dbdc639 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -0,0 +1,359 @@ +package fuzs.armorstatues.network.client.data; + +import com.google.common.collect.ImmutableSortedMap; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.*; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.Rotations; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.NavigableMap; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { + private static final int MAX_INCREMENTAL_OPERATIONS = 12; + public static final int CHECK_TARGET = 999; + public static final int SWAP_SLOTS_MAINHAND_AND_OFFHAND = 161; + public static final int SWAP_SLOTS_MAINHAND_AND_HEAD = 162; + public static final int MIRROR_ARMS_LEFT_TO_RIGHT = 131; + public static final int MIRROR_ARMS_RIGHT_TO_LEFT = 132; + public static final int MIRROR_LEGS_LEFT_TO_RIGHT = 133; + public static final int MIRROR_LEGS_RIGHT_TO_LEFT = 134; + public static final int UTILITIES_LOCK = 1000; + public static final int UTILITIES_UNLOCK = 1001; + public static final int MIRROR_AND_FLIP_FLIP = 135; + public static final int SHOW_BASE_PLATE_YES = 1; + public static final int SHOW_BASE_PLATE_NO = 2; + public static final int SHOW_ARMS_YES = 3; + public static final int SHOW_ARMS_NO = 4; + public static final int SMALL_STAND_YES = 5; + public static final int SMALL_STAND_NO = 6; + public static final int APPLY_GRAVITY_YES = 7; + public static final int APPLY_GRAVITY_NO = 8; + public static final int STAND_VISIBLE_YES = 9; + public static final int STAND_VISIBLE_NO = 10; + public static final int DISPLAY_NAME_YES = 11; + public static final int DISPLAY_NAME_NO = 12; + public static final int NUDGE_POSITION_X8_NEGATIVE = 40; + public static final int NUDGE_POSITION_X3_NEGATIVE = 101; + public static final int NUDGE_POSITION_X1_NEGATIVE = 102; + public static final int NUDGE_POSITION_X1_POSITIVE = 103; + public static final int NUDGE_POSITION_X3_POSITIVE = 104; + public static final int NUDGE_POSITION_X8_POSITIVE = 43; + public static final int NUDGE_POSITION_Y8_NEGATIVE = 44; + public static final int NUDGE_POSITION_Y3_NEGATIVE = 105; + public static final int NUDGE_POSITION_Y1_NEGATIVE = 106; + public static final int NUDGE_POSITION_Y1_POSITIVE = 107; + public static final int NUDGE_POSITION_Y3_POSITIVE = 108; + public static final int NUDGE_POSITION_Y8_POSITIVE = 47; + public static final int NUDGE_POSITION_Z8_NEGATIVE = 48; + public static final int NUDGE_POSITION_Z3_NEGATIVE = 109; + public static final int NUDGE_POSITION_Z1_NEGATIVE = 110; + public static final int NUDGE_POSITION_Z1_POSITIVE = 111; + public static final int NUDGE_POSITION_Z3_POSITIVE = 112; + public static final int NUDGE_POSITION_Z8_POSITIVE = 51; + public static final int ADJUST_ROTATION_ANGLE_STEP_45 = 120; + public static final int ADJUST_ROTATION_ANGLE_STEP_15 = 121; + public static final int ADJUST_ROTATION_ANGLE_STEP_5 = 122; + public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; + public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; + public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + public static final int POSE_PRESETS_ATTENTION = 20; + public static final int POSE_PRESETS_WALKING = 21; + public static final int POSE_PRESETS_RUNNING = 22; + public static final int POSE_PRESETS_POINTING = 23; + public static final int POSE_PRESETS_BLOCKING = 24; + public static final int POSE_PRESETS_LUNGEING = 25; + public static final int POSE_PRESETS_WINNING = 26; + public static final int POSE_PRESETS_SITTING = 27; + public static final int POSE_PRESETS_ARABESQUE = 28; + public static final int POSE_PRESETS_CUPID = 29; + public static final int POSE_PRESETS_CONFIDENT = 30; + public static final int POSE_PRESETS_SALUTE = 31; + public static final int POSE_PRESETS_DEATH = 32; + public static final int POSE_PRESETS_FACEPALM = 33; + public static final int POSE_PRESETS_LAZING = 34; + public static final int POSE_PRESETS_CONFUSED = 35; + public static final int POSE_PRESETS_FORMAL = 36; + public static final int POSE_PRESETS_SAD = 37; + public static final int POSE_PRESETS_JOYOUS = 38; + public static final int POSE_PRESETS_STARGAZING = 39; + public static final int AUTO_ALIGNMENT_BLOCK_ON_SURFACE = 151; + public static final int AUTO_ALIGNMENT_ITEM_ON_SURFACE = 152; + public static final int AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE = 153; + public static final int AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE = 154; + public static final int AUTO_ALIGNMENT_TOOL_RACK = 155; + public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; + public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; + public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; + public static final int POSE_ADJUSTMENT_HEAD_Y_POSITIVE = 63; + public static final int POSE_ADJUSTMENT_HEAD_Z_NEGATIVE = 64; + public static final int POSE_ADJUSTMENT_HEAD_Z_POSITIVE = 65; + public static final int POSE_ADJUSTMENT_BODY_X_NEGATIVE = 67; + public static final int POSE_ADJUSTMENT_BODY_X_POSITIVE = 66; + public static final int POSE_ADJUSTMENT_BODY_Y_NEGATIVE = 68; + public static final int POSE_ADJUSTMENT_BODY_Y_POSITIVE = 69; + public static final int POSE_ADJUSTMENT_BODY_Z_NEGATIVE = 70; + public static final int POSE_ADJUSTMENT_BODY_Z_POSITIVE = 71; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE = 72; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE = 73; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE = 74; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE = 75; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE = 77; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE = 76; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE = 78; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE = 79; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE = 81; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE = 80; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE = 82; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE = 83; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE = 84; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE = 85; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE = 87; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE = 86; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE = 89; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE = 88; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE = 90; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE = 91; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE = 92; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE = 93; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; + private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_LEG = new int[]{POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE}; + private static final NavigableMap NUDGE_POSITIONS_X_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_X3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_X8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_X_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_X3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_X8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_POSITIVE); + private static final NavigableMap ADJUST_ROTATION_ANGLE_STEPS = ImmutableSortedMap.of(1.0F, ADJUST_ROTATION_ANGLE_STEP_1, 5.0F, ADJUST_ROTATION_ANGLE_STEP_5, 15.0F, ADJUST_ROTATION_ANGLE_STEP_15, 45.0F, ADJUST_ROTATION_ANGLE_STEP_45); + + public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + super(holder, player); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.isEditingAllowed()) return; + int triggerValue = this.getTriggerValueFromPose(pose); + if (triggerValue != -1) { + if (this.enqueueTriggerValue(triggerValue)) { + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); + } + } else { + this.tryApplyAllPoseParts(pose); + } + if (finalize) this.finalizeCurrentOperation(); + } + + private int getTriggerValueFromPose(ArmorStandPose pose) { + if (pose.getSourceType() == ArmorStandPose.SourceType.EMPTY) return POSE_PRESETS_ATTENTION; + if (pose.getSourceType() == ArmorStandPose.SourceType.MIRRORED) return MIRROR_AND_FLIP_FLIP; + if (pose.getSourceType() != ArmorStandPose.SourceType.VANILLA_TWEAKS) return -1; + if (pose == ArmorStandPose.WALKING) return POSE_PRESETS_WALKING; + if (pose == ArmorStandPose.RUNNING) return POSE_PRESETS_RUNNING; + if (pose == ArmorStandPose.POINTING) return POSE_PRESETS_POINTING; + if (pose == ArmorStandPose.BLOCKING) return POSE_PRESETS_BLOCKING; + if (pose == ArmorStandPose.LUNGEING) return POSE_PRESETS_LUNGEING; + if (pose == ArmorStandPose.WINNING) return POSE_PRESETS_WINNING; + if (pose == ArmorStandPose.SITTING) return POSE_PRESETS_SITTING; + if (pose == ArmorStandPose.ARABESQUE) return POSE_PRESETS_ARABESQUE; + if (pose == ArmorStandPose.CUPID) return POSE_PRESETS_CUPID; + if (pose == ArmorStandPose.CONFIDENT) return POSE_PRESETS_CONFIDENT; + if (pose == ArmorStandPose.SALUTE) return POSE_PRESETS_SALUTE; + if (pose == ArmorStandPose.DEATH) return POSE_PRESETS_DEATH; + if (pose == ArmorStandPose.FACEPALM) return POSE_PRESETS_FACEPALM; + if (pose == ArmorStandPose.LAZING) return POSE_PRESETS_LAZING; + if (pose == ArmorStandPose.CONFUSED) return POSE_PRESETS_CONFUSED; + if (pose == ArmorStandPose.FORMAL) return POSE_PRESETS_FORMAL; + if (pose == ArmorStandPose.SAD) return POSE_PRESETS_SAD; + if (pose == ArmorStandPose.JOYOUS) return POSE_PRESETS_JOYOUS; + if (pose == ArmorStandPose.STARGAZING) return POSE_PRESETS_STARGAZING; + return -1; + } + + private void tryApplyAllPoseParts(ArmorStandPose pose) { + if (!this.tryApplyPosePart(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD, this.lastSyncedPose::withHeadPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY, this.lastSyncedPose::withBodyPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM, this.lastSyncedPose::withRightArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM, this.lastSyncedPose::withLeftArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG, this.lastSyncedPose::withRightLegPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG, this.lastSyncedPose::withLeftLegPose)) + return; + } + + private boolean tryApplyPosePart(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment, Function function) { + if (this.tryApplyPoseAdjustment(oldPose, newPose, poseAdjustment)) { + this.lastSyncedPose = function.apply(newPose != null ? newPose : oldPose); + return true; + } else { + return false; + } + } + + private boolean tryApplyPoseAdjustment(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + if (newPose == null || oldPose.equals(newPose)) return true; + if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) return false; + return true; + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; + this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); + if (finalize) this.finalizeCurrentOperation(); + } + + private void applyPositionIncrements(double oldValue, double newValue, NavigableMap positiveNudgePositions, NavigableMap negativeNudgePositions) { + double value = newValue - oldValue; + double signum = Math.signum(value); + value = Math.abs(value); + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = (signum == -1.0F ? negativeNudgePositions : positiveNudgePositions).floorEntry(value); + if (entry != null) { + value -= entry.getKey(); + if (!this.enqueueTriggerValue(entry.getValue())) { + return; + } + } else { + break; + } + } + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; + this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean applyIncrementsFromSteps(float oldValue, float newValue, int triggerValueNegative, int triggerValuePositive) { + float value = newValue - oldValue; + float signum = Math.signum(value); + value = Math.abs(value); + float lastIncrement = 0.0F; + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = ADJUST_ROTATION_ANGLE_STEPS.floorEntry(value); + if (entry != null) { + float currentIncrement = entry.getKey(); + value -= currentIncrement; + if (currentIncrement != lastIncrement) { + lastIncrement = currentIncrement; + if (!this.enqueueTriggerValue(entry.getValue())) { + return false; + } + } + if (!this.enqueueTriggerValue(signum == -1.0F ? triggerValuePositive : triggerValueNegative)) { + return false; + } + } else { + break; + } + } + return true; + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; + int triggerValue; + if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { + triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; + } else if (styleOption == ArmorStandStyleOptions.SHOW_ARMS) { + triggerValue = value ? SHOW_ARMS_YES : SHOW_ARMS_NO; + } else if (styleOption == ArmorStandStyleOptions.SMALL) { + triggerValue = value ? SMALL_STAND_YES : SMALL_STAND_NO; + } else if (styleOption == ArmorStandStyleOptions.INVISIBLE) { + triggerValue = value ? STAND_VISIBLE_NO : STAND_VISIBLE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_BASE_PLATE) { + triggerValue = value ? SHOW_BASE_PLATE_NO : SHOW_BASE_PLATE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_GRAVITY) { + triggerValue = value ? APPLY_GRAVITY_NO : APPLY_GRAVITY_YES; + } else { + super.sendStyleOption(styleOption, value, finalize); + return; + } + if (this.sendSingleTriggerValue(triggerValue, finalize)) { + styleOption.setOption(this.getArmorStand(), value); + } + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + int triggerValue = switch (alignment) { + case BLOCK -> AUTO_ALIGNMENT_BLOCK_ON_SURFACE; + case FLOATING_ITEM -> AUTO_ALIGNMENT_ITEM_ON_SURFACE; + case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; + case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; + }; + this.sendSingleTriggerValue(triggerValue, true); + } + + public void sendSingleTriggerValue(int triggerValue) { + if (!this.isEditingAllowed()) return; + this.sendSingleTriggerValue(triggerValue, true); + } + + private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { + boolean result = this.enqueueTriggerValue(triggerValue); + if (finalize) this.finalizeCurrentOperation(); + return result; + } + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return Stream.concat(Stream.of(super.getScreenTypes()), Stream.of(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE)).toArray(ArmorStandScreenType[]::new); + } + + @Override + protected boolean isEditingAllowed() { + return this.isEditingAllowed(false); + } + + @Override + protected Either testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand).>map(Optional::of, $ -> { + if (this.player.distanceToSqr(armorStand) < 9.0) { + return Optional.empty(); + } else { + return Optional.of(Component.translatable(OUT_OF_RANGE_TRANSLATION_KEY)); + } + }).>map(Either::left).orElse(Either.right(Unit.INSTANCE)); + } + + @Override + protected int getDequeueDelayTicks() { + return ArmorStatues.CONFIG.get(ClientConfig.class).clientCommandDelay; + } + + private boolean enqueueTriggerValue(int triggerValue) { + return this.enqueueClientCommand("trigger as_trigger set %s".formatted(triggerValue)); + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java new file mode 100644 index 0000000..3689876 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.proxy; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ClientProxy extends ServerProxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + ArmorStandHolder holder = new ArmorStandHolder() { + + @Override + public ArmorStand getArmorStand() { + return armorStand; + } + + @Override + public ArmorStandDataProvider getDataProvider() { + return ModRegistry.ARMOR_STAND_DATA_PROVIDER; + } + }; + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, + player.getInventory(), + armorStand.getDisplayName(), + createDataSyncHandler(holder, (LocalPlayer) player) + ); + Minecraft minecraft = Minecraft.getInstance(); + minecraft.setScreen(screen); + } + + private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + if ((!player.hasPermissions(2) || ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck) && + ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + return new VanillaTweaksDataSyncHandler(holder, player); + } else { + return new CommandDataSyncHandler(holder, player); + } + } +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.21/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java new file mode 100644 index 0000000..1f5ae83 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java @@ -0,0 +1,11 @@ +package fuzs.armorstatues.proxy; + +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public interface Proxy { + Proxy INSTANCE = ModLoaderEnvironment.INSTANCE.isClient() ? new ClientProxy() : new ServerProxy(); + + void openArmorStandScreen(ArmorStand armorStand, Player player); +} diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java new file mode 100644 index 0000000..f41e246 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java @@ -0,0 +1,12 @@ +package fuzs.armorstatues.proxy; + +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ServerProxy implements Proxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + // NO-OP + } +} 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..4cfa289 --- /dev/null +++ b/1.21/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "armorstatues.accesswidener" +} \ No newline at end of file diff --git a/1.21/Common/src/main/resources/armorstatues.accesswidener b/1.21/Common/src/main/resources/armorstatues.accesswidener new file mode 100644 index 0000000..236e6b1 --- /dev/null +++ b/1.21/Common/src/main/resources/armorstatues.accesswidener @@ -0,0 +1 @@ +accessWidener v2 named 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..62a46106e75f6f8cfd477182314002fec637c712 GIT binary patch literal 15383 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 eyqew78|xoesj$^wqzKCZ0000=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "statuemenus": "*", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.21/NeoForge/build.gradle b/1.21/NeoForge/build.gradle new file mode 100644 index 0000000..07725b4 --- /dev/null +++ b/1.21/NeoForge/build.gradle @@ -0,0 +1,9 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/neoforge.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.neoforge + + // Statue Menus + modApi(include(libs.statuemenus.neoforge.get())) +} 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/armorstatues/neoforge/ArmorStatuesNeoForge.java b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java new file mode 100644 index 0000000..1dd837f --- /dev/null +++ b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java @@ -0,0 +1,17 @@ +package fuzs.armorstatues.neoforge; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(ArmorStatues.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ArmorStatuesNeoForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + } +} diff --git a/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java new file mode 100644 index 0000000..dde7adc --- /dev/null +++ b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java @@ -0,0 +1,21 @@ +package fuzs.armorstatues.neoforge.client; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.client.ArmorStatuesClient; +import fuzs.armorstatues.data.client.ModLanguageProvider; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +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 = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ArmorStatuesNeoForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); + DataProviderHelper.registerDataProviders(ArmorStatues.MOD_ID, ModLanguageProvider::new); + } +} diff --git a/1.21/NeoForge/src/main/resources/META-INF/mods.toml b/1.21/NeoForge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..432ab6c --- /dev/null +++ b/1.21/NeoForge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,57 @@ +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" + +[[dependencies.${ modId }]] +modId = "statuemenus" +mandatory = true +type = "required" +versionRange = "*" +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..2417d2e --- /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/v2/main.gradle" diff --git a/1.21/gradle.properties b/1.21/gradle.properties new file mode 100755 index 0000000..00a426e --- /dev/null +++ b/1.21/gradle.properties @@ -0,0 +1,43 @@ +org.gradle.jvmargs=-Xmx4G +org.gradle.daemon=false +copyBuildJar=true + +# Mod Attributes +modId=armorstatues +modName=Armor Statues +modVersion=20.4.2 +modAuthor=Fuzs +modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/armorstatues +modIssueUrl=https://github.com/Fuzss/armorstatues/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/armorstatues.json +modMavenGroup=fuzs.armorstatues +# "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=IGNORE_ALL_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-v35 +#dependenciesPuzzlesLibVersion=20.4.21 +#dependenciesMinPuzzlesLibVersion=20.4.21 + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=682566 +projectModrinthId=bbGCtEvb + +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 + +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..3499ded --- /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.5-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..e401f79 --- /dev/null +++ b/1.21/settings.gradle @@ -0,0 +1,13 @@ +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", "Fabric", "NeoForge", "Forge") + +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From 1ecdfc2210142e4463c6a5b10c7572b6cddf8322 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 11 Jul 2024 23:32:00 +0200 Subject: [PATCH 25/31] full 1.21 port --- 1.21/CHANGELOG.md | 16 ++------- 1.21/Common/build.gradle | 2 +- .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 +- .../java/fuzs/armorstatues/ArmorStatues.java | 6 ++++ .../handler/ArmorStandTooltipHandler.java | 9 ++--- .../fuzs/armorstatues/init/ModRegistry.java | 33 +++++++++++++++---- .../client/data/CommandDataSyncHandler.java | 2 +- 1.21/Fabric/build.gradle | 2 +- 1.21/NeoForge/build.gradle | 2 +- .../neoforge/ArmorStatuesNeoForge.java | 6 +--- .../client/ArmorStatuesNeoForgeClient.java | 7 ++-- .../{mods.toml => neoforge.mods.toml} | 0 1.21/build.gradle | 2 +- 1.21/gradle.properties | 10 +++--- 1.21/gradle/wrapper/gradle-wrapper.properties | 2 +- 1.21/settings.gradle | 5 ++- 16 files changed, 60 insertions(+), 46 deletions(-) rename 1.21/NeoForge/src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (100%) diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index f07319e..b38a8dd 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,16 +4,6 @@ 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-04-07 -### Changed -- Allow `override_client_permissions_check` config option to also force enabling of the Vanilla Tweaks triggers command handler - -## [v20.4.1-1.20.4] - 2024-03-16 -### Changed -- Bump bundled Statue Menus mod to v20.4.2 -### Fixed -- Fix equipment changing when opening the armor stand menu on dedicated servers without the mod on Fabric - -## [v20.4.0-1.20.4] - 2024-02-10 -- Port to Minecraft 1.20.4 -- Port to NeoForge +## [v21.0.0-1.21] - 2024-07-11 +- Port to Minecraft 1.21 +- Forge is no longer supported in favor of NeoForge diff --git a/1.21/Common/build.gradle b/1.21/Common/build.gradle index 4971f9a..1a985e0 100644 --- a/1.21/Common/build.gradle +++ b/1.21/Common/build.gradle @@ -1,4 +1,4 @@ -apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/common.gradle" +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/common.gradle" dependencies { // Puzzles Lib diff --git a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 index 95dc085..bd386df 100644 --- a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 +++ b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -1,2 +1,2 @@ -// 1.20.4 2024-02-10T01:11:18.844688 Language (en_us) +// 1.21 2024-07-11T14:39:10.467599 Language (en_us) 3b837616894d5f092cf8c1f8e4658d723dbc0320 assets/armorstatues/lang/en_us.json diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java index 8ac4dac..70c87b4 100644 --- a/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java +++ b/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -5,8 +5,10 @@ import fuzs.armorstatues.init.ModRegistry; 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.core.EventPhase; import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import net.minecraft.resources.ResourceLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,4 +30,8 @@ private static void registerEventHandlers() { // we require empty hand + shift, so those other mods can still run their behaviors when those conditions are not met PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); } + + public static ResourceLocation id(String path) { + return ResourceLocationHelper.fromNamespaceAndPath(MOD_ID, path); + } } diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java index 29864c3..a7c16e7 100644 --- a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java +++ b/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -4,6 +4,7 @@ import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; @@ -13,11 +14,11 @@ public class ArmorStandTooltipHandler { - public static void onItemTooltip(ItemStack stack, @Nullable Player player, List lines, TooltipFlag context) { - if (stack.is(Items.ARMOR_STAND)) { + public static void onItemTooltip(ItemStack itemStack, List lines, Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag tooltipFlag) { + if (itemStack.is(Items.ARMOR_STAND)) { List components = Proxy.INSTANCE.splitTooltipLines(ArmorStandInteractHelper.getArmorStandHoverText()); - if (context.isAdvanced()) { - lines.addAll(lines.size() - (stack.hasTag() ? 2 : 1), components); + if (tooltipFlag.isAdvanced()) { + lines.addAll(lines.size() - (!itemStack.getComponents().isEmpty() ? 2 : 1), components); } else { lines.addAll(components); } diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index c296189..a9aba22 100644 --- a/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -11,18 +11,37 @@ import net.minecraft.world.item.Items; public class ModRegistry { - static final RegistryManager REGISTRY = RegistryManager.from(ArmorStatues.MOD_ID); - public static final Holder.Reference> ARMOR_STAND_MENU_TYPE = REGISTRY.registerExtendedMenuType("armor_stand", () -> (containerId, inventory, data) -> { - return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), containerId, inventory, data, ModRegistry.ARMOR_STAND_DATA_PROVIDER); - }); + static final RegistryManager REGISTRIES = RegistryManager.from(ArmorStatues.MOD_ID); + public static final Holder.Reference> ARMOR_STAND_MENU_TYPE = REGISTRIES.registerExtendedMenuType( + "armor_stand", + () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), + containerId, + inventory, + data, + ModRegistry.ARMOR_STAND_DATA_PROVIDER + ); + } + ); - public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", new ItemStack(Items.DIAMOND_PICKAXE)); - public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", new ItemStack(Items.WRITTEN_BOOK)); + public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", + new ItemStack(Items.DIAMOND_PICKAXE) + ); + public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", + new ItemStack(Items.WRITTEN_BOOK) + ); public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { @Override public ArmorStandScreenType[] getScreenTypes() { - return new ArmorStandScreenType[]{ArmorStandScreenType.ROTATIONS, ArmorStandScreenType.POSES, ArmorStandScreenType.STYLE, ArmorStandScreenType.POSITION, ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandScreenType.EQUIPMENT}; + return new ArmorStandScreenType[]{ + ArmorStandScreenType.ROTATIONS, + ArmorStandScreenType.POSES, + ArmorStandScreenType.STYLE, + ArmorStandScreenType.POSITION, + ModRegistry.ALIGNMENTS_SCREEN_TYPE, + ArmorStandScreenType.EQUIPMENT + }; } }; diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java index 3d8b59a..d52bc76 100644 --- a/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java +++ b/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -57,7 +57,7 @@ public void sendName(String name) { if (!this.isEditingAllowed()) return; DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); CompoundTag tag = new CompoundTag(); - tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name))); + tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name), this.player.registryAccess())); this.enqueueEntityData(tag); this.finalizeCurrentOperation(); } diff --git a/1.21/Fabric/build.gradle b/1.21/Fabric/build.gradle index ac4ba5e..8ab06f6 100644 --- a/1.21/Fabric/build.gradle +++ b/1.21/Fabric/build.gradle @@ -1,4 +1,4 @@ -apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/fabric.gradle" +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/fabric.gradle" dependencies { // Fabric Api diff --git a/1.21/NeoForge/build.gradle b/1.21/NeoForge/build.gradle index 07725b4..97e8395 100644 --- a/1.21/NeoForge/build.gradle +++ b/1.21/NeoForge/build.gradle @@ -1,4 +1,4 @@ -apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/neoforge.gradle" +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/neoforge.gradle" dependencies { // Puzzles Lib diff --git a/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java index 1dd837f..9f37d35 100644 --- a/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java +++ b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java @@ -2,16 +2,12 @@ import fuzs.armorstatues.ArmorStatues; import fuzs.puzzleslib.api.core.v1.ModConstructor; -import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.Mod; -import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; @Mod(ArmorStatues.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class ArmorStatuesNeoForge { - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { + public ArmorStatuesNeoForge() { ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); } } diff --git a/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java index dde7adc..53de799 100644 --- a/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java +++ b/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java @@ -6,15 +6,12 @@ import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; 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 = ArmorStatues.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@Mod(value = ArmorStatues.MOD_ID, dist = Dist.CLIENT) public class ArmorStatuesNeoForgeClient { - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { + public ArmorStatuesNeoForgeClient() { ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); DataProviderHelper.registerDataProviders(ArmorStatues.MOD_ID, ModLanguageProvider::new); } diff --git a/1.21/NeoForge/src/main/resources/META-INF/mods.toml b/1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml similarity index 100% rename from 1.21/NeoForge/src/main/resources/META-INF/mods.toml rename to 1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml diff --git a/1.21/build.gradle b/1.21/build.gradle index 2417d2e..dea2bca 100644 --- a/1.21/build.gradle +++ b/1.21/build.gradle @@ -6,4 +6,4 @@ plugins { alias libs.plugins.minotaur apply false } -apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/main.gradle" +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 index 00a426e..58a7e1b 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=20.4.2 +modVersion=21.0.0 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -19,15 +19,16 @@ modForgeDisplayTest=IGNORE_ALL_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.20.4-v35 -#dependenciesPuzzlesLibVersion=20.4.21 -#dependenciesMinPuzzlesLibVersion=20.4.21 +dependenciesVersionCatalog=1.21-v13 +#dependenciesPuzzlesLibVersion=21.0.8 +#dependenciesMinPuzzlesLibVersion=21.0.8 # Mod Publishing projectReleaseType=release projectCurseForgeId=682566 projectModrinthId=bbGCtEvb +# Required Dependencies dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib dependenciesRequiredNeoForgeCurseForge=puzzles-lib dependenciesRequiredForgeCurseForge=forge-config-api-port-fabric, puzzles-lib @@ -35,6 +36,7 @@ dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-li dependenciesRequiredNeoForgeModrinth=puzzles-lib dependenciesRequiredForgeModrinth=forge-config-api-port, puzzles-lib +# Optional Dependencies dependenciesOptionalFabricCurseForge=config-menus-forge dependenciesOptionalNeoForgeCurseForge=config-menus-forge dependenciesOptionalForgeCurseForge=config-menus-forge diff --git a/1.21/gradle/wrapper/gradle-wrapper.properties b/1.21/gradle/wrapper/gradle-wrapper.properties index 3499ded..2617362 100644 --- a/1.21/gradle/wrapper/gradle-wrapper.properties +++ b/1.21/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +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/settings.gradle b/1.21/settings.gradle index e401f79..5cfe5eb 100644 --- a/1.21/settings.gradle +++ b/1.21/settings.gradle @@ -8,6 +8,9 @@ pluginManagement { } } -include("Common", "Fabric", "NeoForge", "Forge") +include "Common" +include "Fabric" +include "NeoForge" +//include "Forge" apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From 5bcdad2eeaa71c3f7f3a761d46527e31b5210251 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:06:57 +0200 Subject: [PATCH 26/31] bump statue menus library --- 1.21/CHANGELOG.md | 4 ++++ 1.21/gradle.properties | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index b38a8dd..3db075a 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-08-22 +### Changed +- Bump bundled Statue Menus library to v21.0.2 to add a workaround for a crash on servers without Armor Statues when the OwoLib mod is installed + ## [v21.0.0-1.21] - 2024-07-11 - Port to Minecraft 1.21 - Forge is no longer supported in favor of NeoForge diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 58a7e1b..9555e1b 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=21.0.0 +modVersion=21.0.1 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -19,7 +19,7 @@ modForgeDisplayTest=IGNORE_ALL_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.21-v13 +dependenciesVersionCatalog=1.21-v27 #dependenciesPuzzlesLibVersion=21.0.8 #dependenciesMinPuzzlesLibVersion=21.0.8 From 8a6ad175b286d937c75feae24e4da7255b21b6ab Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 18 Sep 2024 00:36:02 +0200 Subject: [PATCH 27/31] full 1.21.1 port --- 1.21.1/CHANGELOG.md | 8 ++++++++ {1.21 => 1.21.1}/Common/build.gradle | 0 .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 0 .../resources/assets/armorstatues/lang/en_us.json | 0 .../main/java/fuzs/armorstatues/ArmorStatues.java | 0 .../armorstatues/client/ArmorStatuesClient.java | 0 .../armorstand/ArmorStandAlignmentsScreen.java | 0 .../armorstand/ArmorStandVanillaTweaksScreen.java | 0 .../client/handler/ArmorStandTooltipHandler.java | 0 .../client/handler/ClientInteractHandler.java | 0 .../client/handler/DataSyncTickHandler.java | 0 .../fuzs/armorstatues/config/ClientConfig.java | 0 .../data/client/ModLanguageProvider.java | 0 .../handler/ArmorStandInteractHandler.java | 0 .../java/fuzs/armorstatues/init/ModRegistry.java | 0 .../client/data/CommandDataSyncHandler.java | 0 .../client/data/VanillaTweaksDataSyncHandler.java | 0 .../java/fuzs/armorstatues/proxy/ClientProxy.java | 0 .../main/java/fuzs/armorstatues/proxy/Proxy.java | 0 .../java/fuzs/armorstatues/proxy/ServerProxy.java | 0 .../src/main/resources/architectury.common.json | 0 .../src/main/resources/armorstatues.accesswidener | 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 {1.21 => 1.21.1}/Fabric/build.gradle | 0 .../armorstatues/fabric/ArmorStatuesFabric.java | 0 .../fabric/client/ArmorStatuesFabricClient.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/ArmorStatuesNeoForge.java | 0 .../client/ArmorStatuesNeoForgeClient.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 | 8 ++++---- {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 1.21/CHANGELOG.md | 13 ------------- 45 files changed, 12 insertions(+), 17 deletions(-) create mode 100644 1.21.1/CHANGELOG.md 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/assets/armorstatues/lang/en_us.json (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java (100%) rename {1.21 => 1.21.1}/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.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/armorstatues.accesswidener (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}/Fabric/build.gradle (100%) rename {1.21 => 1.21.1}/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java (100%) rename {1.21 => 1.21.1}/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.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/armorstatues/neoforge/ArmorStatuesNeoForge.java (100%) rename {1.21 => 1.21.1}/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.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 (92%) 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%) delete mode 100644 1.21/CHANGELOG.md diff --git a/1.21.1/CHANGELOG.md b/1.21.1/CHANGELOG.md new file mode 100644 index 0000000..e8a7c35 --- /dev/null +++ b/1.21.1/CHANGELOG.md @@ -0,0 +1,8 @@ +# 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.1.0-1.21.1] - 2024-09-17 +- Port to Minecraft 1.21.1 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/assets/armorstatues/lang/en_us.json b/1.21.1/Common/src/generated/resources/assets/armorstatues/lang/en_us.json similarity index 100% rename from 1.21/Common/src/generated/resources/assets/armorstatues/lang/en_us.json rename to 1.21.1/Common/src/generated/resources/assets/armorstatues/lang/en_us.json diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java diff --git a/1.21/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.21.1/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java similarity index 100% rename from 1.21/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java rename to 1.21.1/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.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/armorstatues.accesswidener b/1.21.1/Common/src/main/resources/armorstatues.accesswidener similarity index 100% rename from 1.21/Common/src/main/resources/armorstatues.accesswidener rename to 1.21.1/Common/src/main/resources/armorstatues.accesswidener 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/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/armorstatues/fabric/ArmorStatuesFabric.java b/1.21.1/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java similarity index 100% rename from 1.21/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java rename to 1.21.1/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java diff --git a/1.21/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java b/1.21.1/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java similarity index 100% rename from 1.21/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java rename to 1.21.1/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.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/armorstatues/neoforge/ArmorStatuesNeoForge.java b/1.21.1/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java similarity index 100% rename from 1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java rename to 1.21.1/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java diff --git a/1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java b/1.21.1/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java similarity index 100% rename from 1.21/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java rename to 1.21.1/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.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 92% rename from 1.21/gradle.properties rename to 1.21.1/gradle.properties index 9555e1b..c5b4b8e 100755 --- a/1.21/gradle.properties +++ b/1.21.1/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=21.0.1 +modVersion=21.1.0 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -19,9 +19,9 @@ modForgeDisplayTest=IGNORE_ALL_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.21-v27 -#dependenciesPuzzlesLibVersion=21.0.8 -#dependenciesMinPuzzlesLibVersion=21.0.8 +dependenciesVersionCatalog=1.21.1-v6 +dependenciesPuzzlesLibVersion=21.1.8 +dependenciesMinPuzzlesLibVersion=21.1.8 # Mod Publishing projectReleaseType=release 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 diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md deleted file mode 100644 index 3db075a..0000000 --- a/1.21/CHANGELOG.md +++ /dev/null @@ -1,13 +0,0 @@ -# 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.1-1.21] - 2024-08-22 -### Changed -- Bump bundled Statue Menus library to v21.0.2 to add a workaround for a crash on servers without Armor Statues when the OwoLib mod is installed - -## [v21.0.0-1.21] - 2024-07-11 -- Port to Minecraft 1.21 -- Forge is no longer supported in favor of NeoForge From d4b7a41070af4a41a8d1de64306ead2c72981d3a Mon Sep 17 00:00:00 2001 From: Matthew McDermott Date: Thu, 5 Dec 2024 12:51:49 +1300 Subject: [PATCH 28/31] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 0360158..c098fbd 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ nbactions.xml build .gradle +### VSCode ### +.vscode + # Ignore Gradle GUI config gradle-app.setting From 0bd416d183f9eb37f84c7f1020f9309898c59510 Mon Sep 17 00:00:00 2001 From: Matthew McDermott Date: Thu, 5 Dec 2024 12:58:37 +1300 Subject: [PATCH 29/31] Added en_nz --- .../resources/assets/statues/lang/en_nz.json | 116 ++++++++++++++++++ .../assets/armorstatues/lang/en_nz.json | 23 ++++ .../assets/armorstatues/lang/en_nz.json | 23 ++++ .../assets/armorstatues/lang/en_nz.json | 23 ++++ 4 files changed, 185 insertions(+) create mode 100644 1.19.2/Forge/src/generated/resources/assets/statues/lang/en_nz.json create mode 100644 1.20.1/Forge/src/generated/resources/assets/armorstatues/lang/en_nz.json create mode 100644 1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json create mode 100644 1.21.1/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json diff --git a/1.19.2/Forge/src/generated/resources/assets/statues/lang/en_nz.json b/1.19.2/Forge/src/generated/resources/assets/statues/lang/en_nz.json new file mode 100644 index 0000000..97ff84a --- /dev/null +++ b/1.19.2/Forge/src/generated/resources/assets/statues/lang/en_nz.json @@ -0,0 +1,116 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armour stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armour Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armour stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armour Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armour stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armour stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armour stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armour stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armour stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armour stand reverts any adjustments made via a previous lock action.", + "item.minecraft.armor_stand.description": "Use [%s] + [%s] with an empty hand to open configuration screen.", + "statues.screen.aligned": "Aligned!", + "statues.screen.alignments.block": "Align Block On Surface", + "statues.screen.alignments.block.description": "Align an armour stand placed on a surface so that a block held by it appears on the surface.", + "statues.screen.alignments.itemFlat": "Align Item Flat On Surface", + "statues.screen.alignments.itemFlat.description": "Align an armour stand placed on a surface so that a non-tool item held by it appears flat on the surface.", + "statues.screen.alignments.itemFloating": "Align Item On Surface", + "statues.screen.alignments.itemFloating.description": "Align an armour stand placed on a surface so that an item held by it appears upright on the surface.", + "statues.screen.alignments.tool": "Align Tool Flat On Surface", + "statues.screen.alignments.tool.description": "Align an armour stand placed on a surface so that a tool held by it appears flat on the surface.", + "statues.screen.centered": "Align Centred", + "statues.screen.centered.description": "Align an armour stand in the center of the block position it is placed on.", + "statues.screen.cornered": "Align Cornered", + "statues.screen.cornered.description": "Align an armour stand at the corner of the block position it is placed on.", + "statues.screen.credits": "Some content on this page originates from the Vanilla Tweaks \"Armour Statues\" data pack. Click this button to go to their website!", + "statues.screen.pose.arabesque": "Arabesque", + "statues.screen.pose.athena": "Athena", + "statues.screen.pose.blocking": "Blocking", + "statues.screen.pose.brandish": "Brandish", + "statues.screen.pose.by": "By %s", + "statues.screen.pose.cancan": "Cancan", + "statues.screen.pose.confident": "Confident", + "statues.screen.pose.confused": "Confused", + "statues.screen.pose.cupid": "Cupid", + "statues.screen.pose.death": "Death", + "statues.screen.pose.default": "Default", + "statues.screen.pose.entertain": "Entertain", + "statues.screen.pose.facepalm": "Facepalm", + "statues.screen.pose.formal": "Formal", + "statues.screen.pose.hero": "Hero", + "statues.screen.pose.honor": "Honour", + "statues.screen.pose.joyous": "Joyous", + "statues.screen.pose.lazing": "Lazing", + "statues.screen.pose.lungeing": "Lunging", + "statues.screen.pose.pointing": "Pointing", + "statues.screen.pose.riposte": "Riposte", + "statues.screen.pose.running": "Running", + "statues.screen.pose.sad": "Sad", + "statues.screen.pose.salute": "Salute", + "statues.screen.pose.sitting": "Sitting", + "statues.screen.pose.solemn": "Solemn", + "statues.screen.pose.stargazing": "Stargazing", + "statues.screen.pose.walking": "Walking", + "statues.screen.pose.winning": "Winning", + "statues.screen.pose.zombie": "Zombie", + "statues.screen.position.blocks": "%s Block(s)", + "statues.screen.position.decrement": "Decrement by %s", + "statues.screen.position.degrees": "%s°", + "statues.screen.position.increment": "Increment by %s", + "statues.screen.position.moveBy": "Move By:", + "statues.screen.position.pixels": "%s Pixel(s)", + "statues.screen.position.rotation": "Rotation:", + "statues.screen.position.x": "X-Position:", + "statues.screen.position.y": "Y-Position:", + "statues.screen.position.z": "Z-Position:", + "statues.screen.rotations.copy": "Copy", + "statues.screen.rotations.limited": "Limited Rotations", + "statues.screen.rotations.mirror": "Mirror", + "statues.screen.rotations.paste": "Paste", + "statues.screen.rotations.pose.body": "Body", + "statues.screen.rotations.pose.head": "Head", + "statues.screen.rotations.pose.leftArm": "Left Arm", + "statues.screen.rotations.pose.leftLeg": "Left Leg", + "statues.screen.rotations.pose.rightArm": "Right Arm", + "statues.screen.rotations.pose.rightLeg": "Right Leg", + "statues.screen.rotations.randomize": "Randomize", + "statues.screen.rotations.reset": "Reset", + "statues.screen.rotations.tip1": "Hold any [§dShift§r] or [§dAlt§r] key to lock two-dimensional sliders to a single axis while dragging!", + "statues.screen.rotations.tip2": "Use arrow keys to move sliders with greater precision than when dragging! Focus a slider first by clicking.", + "statues.screen.rotations.unlimited": "Unlimited Rotations", + "statues.screen.rotations.x": "X: %s", + "statues.screen.rotations.y": "Y: %s", + "statues.screen.rotations.z": "Z: %s", + "statues.screen.style.invisible": "Invisible", + "statues.screen.style.invisible.description": "Makes the statue itself invisible, but still shows all equipped items.", + "statues.screen.style.name": "Set a name to display above the entity if enabled.", + "statues.screen.style.noBasePlate": "No Base Plate", + "statues.screen.style.noBasePlate.description": "Hide the stone base plate at the statue's feet.", + "statues.screen.style.noGravity": "No Gravity", + "statues.screen.style.noGravity.description": "Prevents the statue from falling down, so it may float freely.", + "statues.screen.style.sealed": "Sealed", + "statues.screen.style.sealed.description": "The statue can no longer be broken, equipment cannot be changed. Disallows opening this menu in survival mode.", + "statues.screen.style.showArms": "Show Arms", + "statues.screen.style.showArms.description": "Shows the statue's arms, so it may hold items in both hands.", + "statues.screen.style.showName": "Show Name", + "statues.screen.style.showName.description": "Render the statue's name tag above it's head.", + "statues.screen.style.small": "Small", + "statues.screen.style.small.description": "Makes the statue half it's size like a baby mob.", + "statues.screen.type.alignments": "Alignments", + "statues.screen.type.equipment": "Equipment", + "statues.screen.type.poses": "Poses", + "statues.screen.type.position": "Position", + "statues.screen.type.rotations": "Rotations", + "statues.screen.type.style": "Style", + "statues.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.20.1/Forge/src/generated/resources/assets/armorstatues/lang/en_nz.json b/1.20.1/Forge/src/generated/resources/assets/armorstatues/lang/en_nz.json new file mode 100644 index 0000000..2825c92 --- /dev/null +++ b/1.20.1/Forge/src/generated/resources/assets/armorstatues/lang/en_nz.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armour stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armour Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armour stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armour Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armour stand within three blocks of the player which will be adjusted. Due to how data packs work, this isn't necessarily the armour stand which opened this menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armour stand prevents it from being changed using this menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armour stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armour stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armour stand reverts any adjustments made via a previous lock action.", + "puzzlesapi.screen.type.alignments": "Alignments", + "puzzlesapi.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json b/1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json new file mode 100644 index 0000000..f352c78 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armour stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armour Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armour stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armour Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armour stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armour stand which opened builder menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armour stand prevents it from being changed using builder menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armour stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armour stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armour stand reverts any adjustments made via a previous lock action.", + "statuemenus.screen.type.alignments": "Alignments", + "statuemenus.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.21.1/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json b/1.21.1/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json new file mode 100644 index 0000000..f352c78 --- /dev/null +++ b/1.21.1/Common/src/generated/resources/assets/armorstatues/lang/en_nz.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armour stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armour Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armour stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armour Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armour stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armour stand which opened builder menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armour stand prevents it from being changed using builder menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armour stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armour stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armour stand reverts any adjustments made via a previous lock action.", + "statuemenus.screen.type.alignments": "Alignments", + "statuemenus.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file From b57d43938b7a1def4f04ed8f702282bcebdc964d Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:43:25 +0100 Subject: [PATCH 30/31] prepare 1.21.3 port --- 1.21.3/CHANGELOG.md | 8 + 1.21.3/Common/build.gradle | 13 + .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../assets/armorstatues/lang/en_us.json | 23 ++ .../java/fuzs/armorstatues/ArmorStatues.java | 37 ++ .../client/ArmorStatuesClient.java | 51 +++ .../ArmorStandAlignmentsScreen.java | 54 +++ .../ArmorStandVanillaTweaksScreen.java | 75 ++++ .../handler/ArmorStandTooltipHandler.java | 27 ++ .../client/handler/ClientInteractHandler.java | 39 ++ .../client/handler/DataSyncTickHandler.java | 28 ++ .../armorstatues/config/ClientConfig.java | 15 + .../data/client/ModLanguageProvider.java | 39 ++ .../handler/ArmorStandInteractHandler.java | 43 +++ .../fuzs/armorstatues/init/ModRegistry.java | 51 +++ .../client/data/CommandDataSyncHandler.java | 226 +++++++++++ .../data/VanillaTweaksDataSyncHandler.java | 359 ++++++++++++++++++ .../fuzs/armorstatues/proxy/ClientProxy.java | 51 +++ .../java/fuzs/armorstatues/proxy/Proxy.java | 11 + .../fuzs/armorstatues/proxy/ServerProxy.java | 12 + .../main/resources/architectury.common.json | 3 + .../main/resources/armorstatues.accesswidener | 1 + .../src/main/resources/common.mixins.json | 13 + .../Common/src/main/resources/mod_banner.png | Bin 0 -> 15383 bytes 1.21.3/Common/src/main/resources/mod_logo.png | Bin 0 -> 9380 bytes 1.21.3/Common/src/main/resources/pack.mcmeta | 6 + 1.21.3/Fabric/build.gradle | 12 + .../fabric/ArmorStatuesFabric.java | 13 + .../client/ArmorStatuesFabricClient.java | 14 + .../src/main/resources/fabric.mixins.json | 14 + .../Fabric/src/main/resources/fabric.mod.json | 46 +++ 1.21.3/NeoForge/build.gradle | 9 + 1.21.3/NeoForge/gradle.properties | 1 + .../neoforge/ArmorStatuesNeoForge.java | 13 + .../client/ArmorStatuesNeoForgeClient.java | 18 + .../resources/META-INF/neoforge.mods.toml | 57 +++ .../src/main/resources/neoforge.mixins.json | 13 + 1.21.3/build.gradle | 9 + 1.21.3/gradle.properties | 45 +++ 1.21.3/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + 1.21.3/gradlew | 244 ++++++++++++ 1.21.3/gradlew.bat | 92 +++++ 1.21.3/settings.gradle | 16 + 44 files changed, 1809 insertions(+) create mode 100644 1.21.3/CHANGELOG.md create mode 100644 1.21.3/Common/build.gradle create mode 100644 1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 create mode 100644 1.21.3/Common/src/generated/resources/assets/armorstatues/lang/en_us.json create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java create mode 100644 1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java create mode 100644 1.21.3/Common/src/main/resources/architectury.common.json create mode 100644 1.21.3/Common/src/main/resources/armorstatues.accesswidener create mode 100644 1.21.3/Common/src/main/resources/common.mixins.json create mode 100644 1.21.3/Common/src/main/resources/mod_banner.png create mode 100644 1.21.3/Common/src/main/resources/mod_logo.png create mode 100755 1.21.3/Common/src/main/resources/pack.mcmeta create mode 100644 1.21.3/Fabric/build.gradle create mode 100644 1.21.3/Fabric/src/main/java/fuzs/armorstatues/fabric/ArmorStatuesFabric.java create mode 100644 1.21.3/Fabric/src/main/java/fuzs/armorstatues/fabric/client/ArmorStatuesFabricClient.java create mode 100644 1.21.3/Fabric/src/main/resources/fabric.mixins.json create mode 100644 1.21.3/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.21.3/NeoForge/build.gradle create mode 100644 1.21.3/NeoForge/gradle.properties create mode 100644 1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java create mode 100644 1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java create mode 100644 1.21.3/NeoForge/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 1.21.3/NeoForge/src/main/resources/neoforge.mixins.json create mode 100644 1.21.3/build.gradle create mode 100755 1.21.3/gradle.properties create mode 100644 1.21.3/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.21.3/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.21.3/gradlew create mode 100644 1.21.3/gradlew.bat create mode 100644 1.21.3/settings.gradle diff --git a/1.21.3/CHANGELOG.md b/1.21.3/CHANGELOG.md new file mode 100644 index 0000000..e8a7c35 --- /dev/null +++ b/1.21.3/CHANGELOG.md @@ -0,0 +1,8 @@ +# 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.1.0-1.21.1] - 2024-09-17 +- Port to Minecraft 1.21.1 diff --git a/1.21.3/Common/build.gradle b/1.21.3/Common/build.gradle new file mode 100644 index 0000000..1a985e0 --- /dev/null +++ b/1.21.3/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 + + // Statue Menus + modApi libs.statuemenus.common +} + +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).configureEach { + targetNamespace = "named" +} diff --git a/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 new file mode 100644 index 0000000..bd386df --- /dev/null +++ b/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.21 2024-07-11T14:39:10.467599 Language (en_us) +3b837616894d5f092cf8c1f8e4658d723dbc0320 assets/armorstatues/lang/en_us.json diff --git a/1.21.3/Common/src/generated/resources/assets/armorstatues/lang/en_us.json b/1.21.3/Common/src/generated/resources/assets/armorstatues/lang/en_us.json new file mode 100644 index 0000000..1235c24 --- /dev/null +++ b/1.21.3/Common/src/generated/resources/assets/armorstatues/lang/en_us.json @@ -0,0 +1,23 @@ +{ + "armorstatues.dataSync.failure": "Unable to modify armor stand data: %s", + "armorstatues.dataSync.failure.noArmorStand": "No Valid Armor Stand", + "armorstatues.dataSync.failure.noPermission": "No Permission", + "armorstatues.dataSync.failure.notFinished": "Queue Not Empty", + "armorstatues.dataSync.failure.outOfRange": "Out Of Range", + "armorstatues.dataSync.finished": "Finished sending queued armor stand data", + "armorstatues.screen.vanillaTweaks.checkTarget": "Check Armor Stand Target", + "armorstatues.screen.vanillaTweaks.checkTarget.description": "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armor stand which opened builder menu.", + "armorstatues.screen.vanillaTweaks.lock": "Lock", + "armorstatues.screen.vanillaTweaks.lock.description": "Locking an armor stand prevents it from being changed using builder menu and disables interaction with the equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead": "Swap Mainhand & Helmet", + "armorstatues.screen.vanillaTweaks.swapMainhandAndHead.description": "Swaps items between the main hand and helmet equipment slots.", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand": "Swap Mainhand & Offhand", + "armorstatues.screen.vanillaTweaks.swapMainhandAndOffhand.description": "Swaps items between the main hand and off hand equipment slots.", + "armorstatues.screen.vanillaTweaks.toolRack": "Align Tool As Tool Rack", + "armorstatues.screen.vanillaTweaks.toolRack.description": "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand.", + "armorstatues.screen.vanillaTweaks.triggerSent": "Sent!", + "armorstatues.screen.vanillaTweaks.unlock": "Unlock", + "armorstatues.screen.vanillaTweaks.unlock.description": "Unlocking an armor stand reverts any adjustments made via a previous lock action.", + "statuemenus.screen.type.alignments": "Alignments", + "statuemenus.screen.type.vanillaTweaks": "Vanilla Tweaks" +} \ No newline at end of file diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java new file mode 100644 index 0000000..70c87b4 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -0,0 +1,37 @@ +package fuzs.armorstatues; + +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.armorstatues.init.ModRegistry; +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.core.EventPhase; +import fuzs.puzzleslib.api.event.v1.entity.player.PlayerInteractEvents; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ArmorStatues implements ModConstructor { + public static final String MOD_ID = "armorstatues"; + public static final String MOD_NAME = "Armor Statues"; + 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(); + registerEventHandlers(); + } + + private static void registerEventHandlers() { + // high priority, so we run before other mods that add armor stand interactions + // we require empty hand + shift, so those other mods can still run their behaviors when those conditions are not met + PlayerInteractEvents.USE_ENTITY_AT.register(EventPhase.BEFORE, ArmorStandInteractHandler::onUseEntityAt); + } + + public static ResourceLocation id(String path) { + return ResourceLocationHelper.fromNamespaceAndPath(MOD_ID, path); + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java new file mode 100644 index 0000000..2b4043c --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/ArmorStatuesClient.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandAlignmentsScreen; +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.client.handler.ArmorStandTooltipHandler; +import fuzs.armorstatues.client.handler.ClientInteractHandler; +import fuzs.armorstatues.client.handler.DataSyncTickHandler; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; +import fuzs.puzzleslib.api.client.event.v1.ClientTickEvents; +import fuzs.puzzleslib.api.client.event.v1.entity.player.InteractionInputEvents; +import fuzs.puzzleslib.api.client.event.v1.gui.ItemTooltipCallback; +import fuzs.puzzleslib.api.client.event.v1.gui.ScreenEvents; +import fuzs.puzzleslib.api.event.v1.core.EventPhase; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +public class ArmorStatuesClient implements ClientModConstructor { + + @Override + public void onConstructMod() { + registerEventHandlers(); + } + + private static void registerEventHandlers() { + ItemTooltipCallback.EVENT.register(ArmorStandTooltipHandler::onItemTooltip); + ClientTickEvents.END.register(DataSyncTickHandler::onEndClientTick); + ScreenEvents.remove(Screen.class).register(DataSyncTickHandler::onRemove); + // event phase must match PlayerInteractEvents#USE_ENTITY_AT as both are implemented using the same event on Fabric + InteractionInputEvents.USE.register(EventPhase.BEFORE, ClientInteractHandler::onUseInteraction); + } + + @Override + public void onClientSetup() { + ArmorStandScreenFactory.register(ModRegistry.ALIGNMENTS_SCREEN_TYPE, ArmorStandAlignmentsScreen::new); + ArmorStandScreenFactory.register(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE, ArmorStandVanillaTweaksScreen::new); + } + + @SuppressWarnings("Convert2MethodRef") + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { + // compiler doesn't like method reference :( + context.registerMenuScreen(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), (ArmorStandMenu menu, Inventory inventory, Component component) -> { + return ArmorStandScreenFactory.createLastScreenType(menu, inventory, component); + }); + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java new file mode 100644 index 0000000..df01829 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandAlignmentsScreen.java @@ -0,0 +1,54 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandButtonsScreen; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandPositionScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.phys.Vec3; + +import java.util.EnumSet; +import java.util.List; + +public class ArmorStandAlignmentsScreen extends ArmorStandButtonsScreen { + + public ArmorStandAlignmentsScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new DoubleButtonWidget(Component.translatable(ArmorStandPositionScreen.CENTERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CENTERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.CORNERED_DESCRIPTION_TRANSLATION_KEY), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)).add(0.5, 0.0, 0.5); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + }, button -> { + Vec3 newPosition = this.holder.getArmorStand().position().align(EnumSet.allOf(Direction.Axis.class)); + this.dataSyncHandler.sendPosition(newPosition.x(), newPosition.y(), newPosition.z()); + })); + for (ArmorStandAlignment alignment : ArmorStandAlignment.values()) { + widgets.add(new SingleButtonWidget(Component.translatable(alignment.getTranslationKey()), Component.translatable(alignment.getDescriptionsKey()), Component.translatable(ArmorStandPositionScreen.ALIGNED_TRANSLATION_KEY), button -> { + ArmorStandAlignmentsScreen.this.dataSyncHandler.sendAlignment(alignment); + })); + } + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.ALIGNMENTS_SCREEN_TYPE; + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java new file mode 100644 index 0000000..f52054d --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/gui/screens/armorstand/ArmorStandVanillaTweaksScreen.java @@ -0,0 +1,75 @@ +package fuzs.armorstatues.client.gui.screens.armorstand; + +import com.google.common.collect.Lists; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandButtonsScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Inventory; + +import java.util.List; + +public class ArmorStandVanillaTweaksScreen extends ArmorStandButtonsScreen { + public static final String TRIGGER_SENT_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.triggerSent"; + public static final String CHECK_TARGET_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget"; + public static final String CHECK_TARGET_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.checkTarget.description"; + public static final String LOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock"; + public static final String LOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.lock.description"; + public static final String UNLOCK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock"; + public static final String UNLOCK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.unlock.description"; + public static final String TOOL_RACK_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack"; + public static final String TOOL_RACK_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.toolRack.description"; + public static final String SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand"; + public static final String SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndOffhand.description"; + public static final String SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead"; + public static final String SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY = ArmorStatues.MOD_ID + ".screen.vanillaTweaks.swapMainhandAndHead.description"; + + public ArmorStandVanillaTweaksScreen(ArmorStandHolder holder, Inventory inventory, Component component, DataSyncHandler dataSyncHandler) { + super(holder, inventory, component, dataSyncHandler); + } + + @Override + public VanillaTweaksDataSyncHandler getDataSyncHandler() { + return (VanillaTweaksDataSyncHandler) super.getDataSyncHandler(); + } + + @Override + protected List buildWidgets(ArmorStand armorStand) { + List widgets = Lists.newArrayList(); + widgets.add(new SingleButtonWidget(Component.translatable(CHECK_TARGET_TRANSLATION_KEY), Component.translatable(CHECK_TARGET_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.CHECK_TARGET); + this.onClose(); + })); + widgets.add(new DoubleButtonWidget(Component.translatable(LOCK_TRANSLATION_KEY), Component.translatable(UNLOCK_TRANSLATION_KEY), Component.translatable(LOCK_DESCRIPTION_KEY), Component.translatable(UNLOCK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_LOCK); + }, button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.UTILITIES_UNLOCK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(TOOL_RACK_TRANSLATION_KEY), Component.translatable(TOOL_RACK_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.AUTO_ALIGNMENT_TOOL_RACK); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_OFFHAND); + })); + widgets.add(new SingleButtonWidget(Component.translatable(SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY), Component.translatable(SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY), Component.translatable(TRIGGER_SENT_TRANSLATION_KEY), button -> { + this.getDataSyncHandler().sendSingleTriggerValue(VanillaTweaksDataSyncHandler.SWAP_SLOTS_MAINHAND_AND_HEAD); + })); + return widgets; + } + + @Override + protected void init() { + super.init(); + this.addVanillaTweaksCreditsButton(); + } + + @Override + public ArmorStandScreenType getScreenType() { + return ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE; + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java new file mode 100644 index 0000000..a7c16e7 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ArmorStandTooltipHandler.java @@ -0,0 +1,27 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.puzzleslib.api.core.v1.Proxy; +import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ArmorStandTooltipHandler { + + public static void onItemTooltip(ItemStack itemStack, List lines, Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag tooltipFlag) { + if (itemStack.is(Items.ARMOR_STAND)) { + List components = Proxy.INSTANCE.splitTooltipLines(ArmorStandInteractHelper.getArmorStandHoverText()); + if (tooltipFlag.isAdvanced()) { + lines.addAll(lines.size() - (!itemStack.getComponents().isEmpty() ? 2 : 1), components); + } else { + lines.addAll(components); + } + } + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java new file mode 100644 index 0000000..22b26d2 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/ClientInteractHandler.java @@ -0,0 +1,39 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.armorstatues.handler.ArmorStandInteractHandler; +import fuzs.puzzleslib.api.event.v1.core.EventResult; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class ClientInteractHandler { + + public static EventResult onUseInteraction(Minecraft minecraft, LocalPlayer player, InteractionHand interactionHand, HitResult hitResult) { + + if (hitResult.getType() == HitResult.Type.ENTITY) { + + Entity entity = ((EntityHitResult) hitResult).getEntity(); + Vec3 hitVector = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + EventResultHolder result = ArmorStandInteractHandler.onUseEntityAt(minecraft.player, + minecraft.level, + interactionHand, + entity, + hitVector + ); + + // if InteractionResult.FAIL is returned the mod is missing server-side, and we open the menu client-side without sending a packet to the server, so the server does not try to interact + if (result.filter(interactionResult -> interactionResult == InteractionResult.FAIL).isInterrupt()) { + + return EventResult.INTERRUPT; + } + } + + return EventResult.PASS; + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java new file mode 100644 index 0000000..822390a --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/client/handler/DataSyncTickHandler.java @@ -0,0 +1,28 @@ +package fuzs.armorstatues.client.handler; + +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreen; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +public class DataSyncTickHandler { + @Nullable + private static DataSyncHandler dataSyncHandler; + + public static void onRemove(Screen screen) { + if (screen instanceof ArmorStandScreen armorStandScreen && armorStandScreen.getDataSyncHandler().shouldContinueTicking()) { + dataSyncHandler = armorStandScreen.getDataSyncHandler(); + } + } + + public static void onEndClientTick(Minecraft minecraft) { + if (minecraft.player != null && !(minecraft.screen instanceof ArmorStandScreen) && dataSyncHandler != null) { + if (dataSyncHandler.shouldContinueTicking()) { + dataSyncHandler.tick(); + } else { + dataSyncHandler = null; + } + } + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java new file mode 100644 index 0000000..137797d --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/config/ClientConfig.java @@ -0,0 +1,15 @@ +package fuzs.armorstatues.config; + +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; +import fuzs.statuemenus.api.v1.client.gui.screens.AbstractArmorStandScreen; + +public class ClientConfig implements ConfigCore { + @Config(description = {"Allows for using this mod on a server without it (like a vanilla server) when the Vanilla Tweaks Armor Statues data pack is installed without the need for being a server operator.", "Download the Vanilla Tweaks Armor Statues data pack from here: " + AbstractArmorStandScreen.VANILLA_TWEAKS_HOMEPAGE}) + public boolean useVanillaTweaksTriggers = false; + @Config(description = "Do not check if the client has the necessary permission level for executing the '/data' command when trying to edit an armor stand. Useful when the current server is using custom permissions handling.") + public boolean overrideClientPermissionsCheck = false; + @Config(description = "The delay in ticks for sending queued client commands for editing armor stands to the server. Increase this values if commands are sent too quickly and the server fails to process all of them.") + @Config.IntRange(min = 20) + public int clientCommandDelay = 20; +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..44c0b50 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/data/client/ModLanguageProvider.java @@ -0,0 +1,39 @@ +package fuzs.armorstatues.data.client; + +import fuzs.armorstatues.client.gui.screens.armorstand.ArmorStandVanillaTweaksScreen; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(CommandDataSyncHandler.FAILURE_TRANSLATION_KEY, "Unable to modify armor stand data: %s"); + builder.add(CommandDataSyncHandler.NO_PERMISSION_TRANSLATION_KEY, "No Permission"); + builder.add(CommandDataSyncHandler.NO_ARMOR_STAND_TRANSLATION_KEY, "No Valid Armor Stand"); + builder.add(CommandDataSyncHandler.OUT_OF_RANGE_TRANSLATION_KEY, "Out Of Range"); + builder.add(CommandDataSyncHandler.NOT_FINISHED_TRANSLATION_KEY, "Queue Not Empty"); + builder.add(CommandDataSyncHandler.FINISHED_TRANSLATION_KEY, "Finished sending queued armor stand data"); + builder.add(ModRegistry.ALIGNMENTS_SCREEN_TYPE.getTranslationKey(), "Alignments"); + builder.add(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE.getTranslationKey(), "Vanilla Tweaks"); + builder.add(ArmorStandVanillaTweaksScreen.TRIGGER_SENT_TRANSLATION_KEY, "Sent!"); + builder.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_TRANSLATION_KEY, "Check Armor Stand Target"); + builder.add(ArmorStandVanillaTweaksScreen.CHECK_TARGET_DESCRIPTION_KEY, "Highlights the closest armor stand within three blocks of the player which will be adjusted. Due to how data packs work, builder isn't necessarily the armor stand which opened builder menu."); + builder.add(ArmorStandVanillaTweaksScreen.LOCK_TRANSLATION_KEY, "Lock"); + builder.add(ArmorStandVanillaTweaksScreen.LOCK_DESCRIPTION_KEY, "Locking an armor stand prevents it from being changed using builder menu and disables interaction with the equipment slots."); + builder.add(ArmorStandVanillaTweaksScreen.UNLOCK_TRANSLATION_KEY, "Unlock"); + builder.add(ArmorStandVanillaTweaksScreen.UNLOCK_DESCRIPTION_KEY, "Unlocking an armor stand reverts any adjustments made via a previous lock action."); + builder.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_TRANSLATION_KEY, "Align Tool As Tool Rack"); + builder.add(ArmorStandVanillaTweaksScreen.TOOL_RACK_DESCRIPTION_KEY, "Align an armor stand with a tripwire hook on the wall above it so that a tool held by it appears to be hanging up. Also locks the armor stand and disables all slots except the mainhand."); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_TRANSLATION_KEY, "Swap Mainhand & Offhand"); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_OFFHAND_DESCRIPTION_KEY, "Swaps items between the main hand and off hand equipment slots."); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_TRANSLATION_KEY, "Swap Mainhand & Helmet"); + builder.add(ArmorStandVanillaTweaksScreen.SWAP_MAINHAND_AND_HEAD_DESCRIPTION_KEY, "Swaps items between the main hand and helmet equipment slots."); + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java new file mode 100644 index 0000000..2dd8af0 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/handler/ArmorStandInteractHandler.java @@ -0,0 +1,43 @@ +package fuzs.armorstatues.handler; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.proxy.Proxy; +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; +import fuzs.puzzleslib.api.event.v1.core.EventResultHolder; +import fuzs.statuemenus.api.v1.helper.ArmorStandInteractHelper; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class ArmorStandInteractHandler { + + public static EventResultHolder onUseEntityAt(Player player, Level level, InteractionHand interactionHand, Entity target, Vec3 hitVector) { + + if (player.getAbilities().mayBuild && target.getType() == EntityType.ARMOR_STAND) { + + boolean clientsideOnly = level.isClientSide && !ModLoaderEnvironment.INSTANCE.isModPresentServerside(ArmorStatues.MOD_ID); + // the menu won't exist in the registry if the mod is missing serverside since Forge syncs registries to clients + MenuType menuType = clientsideOnly ? null : ModRegistry.ARMOR_STAND_MENU_TYPE.value(); + EventResultHolder result = ArmorStandInteractHelper.tryOpenArmorStatueMenu(player, level, interactionHand, (ArmorStand) target, menuType, ModRegistry.ARMOR_STAND_DATA_PROVIDER); + if (result.isInterrupt() && clientsideOnly) { + + Proxy.INSTANCE.openArmorStandScreen((ArmorStand) target, player); + // required so no packet is sent to server when only installed client-side, so the server doesn't change any equipment when we only want to open the screen + // returning InteractionResult.FAIL will miss out on the player arm swing animation, which we manually play here + player.swing(interactionHand); + return EventResultHolder.interrupt(InteractionResult.FAIL); + } + + return result; + } + + return EventResultHolder.pass(); + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java new file mode 100644 index 0000000..a9aba22 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.init; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; +import fuzs.statuemenus.api.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandMenu; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import net.minecraft.core.Holder; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class ModRegistry { + static final RegistryManager REGISTRIES = RegistryManager.from(ArmorStatues.MOD_ID); + public static final Holder.Reference> ARMOR_STAND_MENU_TYPE = REGISTRIES.registerExtendedMenuType( + "armor_stand", + () -> (containerId, inventory, data) -> { + return ArmorStandMenu.create(ModRegistry.ARMOR_STAND_MENU_TYPE.value(), + containerId, + inventory, + data, + ModRegistry.ARMOR_STAND_DATA_PROVIDER + ); + } + ); + + public static final ArmorStandScreenType ALIGNMENTS_SCREEN_TYPE = new ArmorStandScreenType("alignments", + new ItemStack(Items.DIAMOND_PICKAXE) + ); + public static final ArmorStandScreenType VANILLA_TWEAKS_SCREEN_TYPE = new ArmorStandScreenType("vanillaTweaks", + new ItemStack(Items.WRITTEN_BOOK) + ); + public static final ArmorStandDataProvider ARMOR_STAND_DATA_PROVIDER = new ArmorStandDataProvider() { + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return new ArmorStandScreenType[]{ + ArmorStandScreenType.ROTATIONS, + ArmorStandScreenType.POSES, + ArmorStandScreenType.STYLE, + ArmorStandScreenType.POSITION, + ModRegistry.ALIGNMENTS_SCREEN_TYPE, + ArmorStandScreenType.EQUIPMENT + }; + } + }; + + public static void touch() { + // NO-OP + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java new file mode 100644 index 0000000..d52bc76 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/CommandDataSyncHandler.java @@ -0,0 +1,226 @@ +package fuzs.armorstatues.network.client.data; + +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandAlignment; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandPose; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandScreenType; +import fuzs.statuemenus.api.v1.world.inventory.data.ArmorStandStyleOption; +import net.minecraft.ChatFormatting; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.function.BiPredicate; + +public class CommandDataSyncHandler implements DataSyncHandler { + public static final String NO_PERMISSION_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noPermission"; + public static final String NO_ARMOR_STAND_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.noArmorStand"; + public static final String OUT_OF_RANGE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.outOfRange"; + public static final String NOT_FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure.notFinished"; + public static final String FINISHED_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.finished"; + public static final String FAILURE_TRANSLATION_KEY = ArmorStatues.MOD_ID + ".dataSync.failure"; + private static final Queue CLIENT_COMMAND_QUEUE = new ArrayDeque<>(); + + @Nullable + private static ArmorStand queueArmorStand; + private static int itemDequeuedTicks; + + private final ArmorStandHolder holder; + protected final LocalPlayer player; + protected ArmorStandPose lastSyncedPose; + + public CommandDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + this.holder = holder; + this.lastSyncedPose = ArmorStandPose.fromEntity(this.holder.getArmorStand()); + this.player = player; + } + + @Override + public ArmorStandHolder getArmorStandHolder() { + return this.holder; + } + + @Override + public void sendName(String name) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.setCustomArmorStandName(this.getArmorStand(), name); + CompoundTag tag = new CompoundTag(); + tag.putString("CustomName", Component.Serializer.toJson(Component.literal(name), this.player.registryAccess())); + this.enqueueEntityData(tag); + this.finalizeCurrentOperation(); + } + + @Override + public final void sendPose(ArmorStandPose pose) { + this.sendPose(pose, true); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.isEditingAllowed()) return; + // split this into multiple chat messages as the client chat field has a very low character limit + this.sendPosePart(pose::serializeBodyPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeArmPoses, this.lastSyncedPose); + this.sendPosePart(pose::serializeLegPoses, this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + if (finalize) this.finalizeCurrentOperation(); + } + + private void sendPosePart(BiPredicate dataWriter, ArmorStandPose lastSyncedPose) { + CompoundTag tag = new CompoundTag(); + if (dataWriter.test(tag, lastSyncedPose)) { + CompoundTag tagToSend = new CompoundTag(); + tagToSend.put("Pose", tag); + this.enqueueEntityData(tagToSend); + } + } + + @Override + public @Nullable ArmorStandPose getLastSyncedPose() { + return this.lastSyncedPose; + } + + @Override + public final void sendPosition(double posX, double posY, double posZ) { + this.sendPosition(posX, posY, posZ, true); + + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; + ListTag listTag = new ListTag(); + listTag.add(DoubleTag.valueOf(posX)); + listTag.add(DoubleTag.valueOf(posY)); + listTag.add(DoubleTag.valueOf(posZ)); + CompoundTag tag = new CompoundTag(); + tag.put("Pos", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendRotation(float rotation) { + this.sendRotation(rotation, true); + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; + ListTag listTag = new ListTag(); + listTag.add(FloatTag.valueOf(rotation)); + CompoundTag tag = new CompoundTag(); + tag.put("Rotation", listTag); + this.enqueueEntityData(tag); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public final void sendStyleOption(ArmorStandStyleOption styleOption, boolean value) { + this.sendStyleOption(styleOption, value, true); + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; + CompoundTag tag = new CompoundTag(); + styleOption.toTag(tag, value); + this.enqueueEntityData(tag); + styleOption.setOption(this.getArmorStand(), value); + if (finalize) this.finalizeCurrentOperation(); + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + DataSyncHandler.super.sendAlignment(alignment); + } + + @Override + public boolean supportsScreenType(ArmorStandScreenType screenType) { + return !screenType.requiresServer(); + } + + @Override + public void tick() { + if (itemDequeuedTicks > 0) itemDequeuedTicks--; + if (itemDequeuedTicks == 0 && queueArmorStand != null && !CLIENT_COMMAND_QUEUE.isEmpty()) { + if (this.testArmorStand(queueArmorStand).right().isPresent()) { + this.player.connection.sendCommand(CLIENT_COMMAND_QUEUE.poll()); + } else { + CLIENT_COMMAND_QUEUE.clear(); + } + itemDequeuedTicks = this.getDequeueDelayTicks(); + } else if (itemDequeuedTicks == 1 && CLIENT_COMMAND_QUEUE.isEmpty()) { + this.sendDisplayMessage(Component.translatable(FINISHED_TRANSLATION_KEY), false); + } + } + + protected int getDequeueDelayTicks() { + return 5; + } + + @Override + public boolean shouldContinueTicking() { + return !CLIENT_COMMAND_QUEUE.isEmpty() || itemDequeuedTicks != 0; + } + + protected boolean isEditingAllowed() { + return this.isEditingAllowed(!ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck); + } + + protected final boolean isEditingAllowed(boolean testPermissionLevel) { + if (testPermissionLevel && !this.player.hasPermissions(2)) { + this.sendFailureMessage(Component.translatable(NO_PERMISSION_TRANSLATION_KEY)); + return false; + } + return this.player.getAbilities().mayBuild && this.testArmorStand(this.getArmorStand()).ifLeft(this::sendFailureMessage).right().isPresent(); + } + + protected Either testArmorStand(ArmorStand armorStand) { + return !armorStand.isAlive() ? Either.left(Component.translatable(NO_ARMOR_STAND_TRANSLATION_KEY)) : Either.right(Unit.INSTANCE); + } + + protected boolean enqueueClientCommand(String clientCommand) { + if (CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = null; + } else if (queueArmorStand != null) { + this.sendFailureMessage(Component.translatable(NOT_FINISHED_TRANSLATION_KEY)); + return false; + } + CLIENT_COMMAND_QUEUE.offer(clientCommand); + return true; + } + + @Override + public void finalizeCurrentOperation() { + if (!CLIENT_COMMAND_QUEUE.isEmpty()) { + queueArmorStand = this.getArmorStand(); + } + } + + protected void sendFailureMessage(Component component) { + this.sendDisplayMessage(Component.translatable(FAILURE_TRANSLATION_KEY, component), true); + } + + protected void sendDisplayMessage(Component component, boolean failure) { + this.player.displayClientMessage(Component.empty().append(component).withStyle(failure ? ChatFormatting.RED : ChatFormatting.GREEN), false); + } + + private void enqueueEntityData(CompoundTag tag) { + this.enqueueClientCommand("data merge entity %s %s".formatted(this.getArmorStand().getStringUUID(), tag.getAsString())); + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java new file mode 100644 index 0000000..dbdc639 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/network/client/data/VanillaTweaksDataSyncHandler.java @@ -0,0 +1,359 @@ +package fuzs.armorstatues.network.client.data; + +import com.google.common.collect.ImmutableSortedMap; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Unit; +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import fuzs.statuemenus.api.v1.world.inventory.data.*; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.Rotations; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.NavigableMap; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +public class VanillaTweaksDataSyncHandler extends CommandDataSyncHandler { + private static final int MAX_INCREMENTAL_OPERATIONS = 12; + public static final int CHECK_TARGET = 999; + public static final int SWAP_SLOTS_MAINHAND_AND_OFFHAND = 161; + public static final int SWAP_SLOTS_MAINHAND_AND_HEAD = 162; + public static final int MIRROR_ARMS_LEFT_TO_RIGHT = 131; + public static final int MIRROR_ARMS_RIGHT_TO_LEFT = 132; + public static final int MIRROR_LEGS_LEFT_TO_RIGHT = 133; + public static final int MIRROR_LEGS_RIGHT_TO_LEFT = 134; + public static final int UTILITIES_LOCK = 1000; + public static final int UTILITIES_UNLOCK = 1001; + public static final int MIRROR_AND_FLIP_FLIP = 135; + public static final int SHOW_BASE_PLATE_YES = 1; + public static final int SHOW_BASE_PLATE_NO = 2; + public static final int SHOW_ARMS_YES = 3; + public static final int SHOW_ARMS_NO = 4; + public static final int SMALL_STAND_YES = 5; + public static final int SMALL_STAND_NO = 6; + public static final int APPLY_GRAVITY_YES = 7; + public static final int APPLY_GRAVITY_NO = 8; + public static final int STAND_VISIBLE_YES = 9; + public static final int STAND_VISIBLE_NO = 10; + public static final int DISPLAY_NAME_YES = 11; + public static final int DISPLAY_NAME_NO = 12; + public static final int NUDGE_POSITION_X8_NEGATIVE = 40; + public static final int NUDGE_POSITION_X3_NEGATIVE = 101; + public static final int NUDGE_POSITION_X1_NEGATIVE = 102; + public static final int NUDGE_POSITION_X1_POSITIVE = 103; + public static final int NUDGE_POSITION_X3_POSITIVE = 104; + public static final int NUDGE_POSITION_X8_POSITIVE = 43; + public static final int NUDGE_POSITION_Y8_NEGATIVE = 44; + public static final int NUDGE_POSITION_Y3_NEGATIVE = 105; + public static final int NUDGE_POSITION_Y1_NEGATIVE = 106; + public static final int NUDGE_POSITION_Y1_POSITIVE = 107; + public static final int NUDGE_POSITION_Y3_POSITIVE = 108; + public static final int NUDGE_POSITION_Y8_POSITIVE = 47; + public static final int NUDGE_POSITION_Z8_NEGATIVE = 48; + public static final int NUDGE_POSITION_Z3_NEGATIVE = 109; + public static final int NUDGE_POSITION_Z1_NEGATIVE = 110; + public static final int NUDGE_POSITION_Z1_POSITIVE = 111; + public static final int NUDGE_POSITION_Z3_POSITIVE = 112; + public static final int NUDGE_POSITION_Z8_POSITIVE = 51; + public static final int ADJUST_ROTATION_ANGLE_STEP_45 = 120; + public static final int ADJUST_ROTATION_ANGLE_STEP_15 = 121; + public static final int ADJUST_ROTATION_ANGLE_STEP_5 = 122; + public static final int ADJUST_ROTATION_ANGLE_STEP_1 = 123; + public static final int ADJUST_ROTATION_ROTATE_RIGHT = 56; + public static final int ADJUST_ROTATION_ROTATE_LEFT = 57; + public static final int POSE_PRESETS_ATTENTION = 20; + public static final int POSE_PRESETS_WALKING = 21; + public static final int POSE_PRESETS_RUNNING = 22; + public static final int POSE_PRESETS_POINTING = 23; + public static final int POSE_PRESETS_BLOCKING = 24; + public static final int POSE_PRESETS_LUNGEING = 25; + public static final int POSE_PRESETS_WINNING = 26; + public static final int POSE_PRESETS_SITTING = 27; + public static final int POSE_PRESETS_ARABESQUE = 28; + public static final int POSE_PRESETS_CUPID = 29; + public static final int POSE_PRESETS_CONFIDENT = 30; + public static final int POSE_PRESETS_SALUTE = 31; + public static final int POSE_PRESETS_DEATH = 32; + public static final int POSE_PRESETS_FACEPALM = 33; + public static final int POSE_PRESETS_LAZING = 34; + public static final int POSE_PRESETS_CONFUSED = 35; + public static final int POSE_PRESETS_FORMAL = 36; + public static final int POSE_PRESETS_SAD = 37; + public static final int POSE_PRESETS_JOYOUS = 38; + public static final int POSE_PRESETS_STARGAZING = 39; + public static final int AUTO_ALIGNMENT_BLOCK_ON_SURFACE = 151; + public static final int AUTO_ALIGNMENT_ITEM_ON_SURFACE = 152; + public static final int AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE = 153; + public static final int AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE = 154; + public static final int AUTO_ALIGNMENT_TOOL_RACK = 155; + public static final int POSE_ADJUSTMENT_HEAD_X_NEGATIVE = 60; + public static final int POSE_ADJUSTMENT_HEAD_X_POSITIVE = 61; + public static final int POSE_ADJUSTMENT_HEAD_Y_NEGATIVE = 62; + public static final int POSE_ADJUSTMENT_HEAD_Y_POSITIVE = 63; + public static final int POSE_ADJUSTMENT_HEAD_Z_NEGATIVE = 64; + public static final int POSE_ADJUSTMENT_HEAD_Z_POSITIVE = 65; + public static final int POSE_ADJUSTMENT_BODY_X_NEGATIVE = 67; + public static final int POSE_ADJUSTMENT_BODY_X_POSITIVE = 66; + public static final int POSE_ADJUSTMENT_BODY_Y_NEGATIVE = 68; + public static final int POSE_ADJUSTMENT_BODY_Y_POSITIVE = 69; + public static final int POSE_ADJUSTMENT_BODY_Z_NEGATIVE = 70; + public static final int POSE_ADJUSTMENT_BODY_Z_POSITIVE = 71; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE = 72; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE = 73; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE = 74; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE = 75; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE = 77; + public static final int POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE = 76; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE = 78; + public static final int POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE = 79; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE = 81; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE = 80; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE = 82; + public static final int POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE = 83; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE = 84; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE = 85; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE = 87; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE = 86; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE = 89; + public static final int POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE = 88; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE = 90; + public static final int POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE = 91; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE = 92; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE = 93; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE = 94; + public static final int POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE = 95; + private static final int[] POSE_ADJUSTMENT_HEAD = new int[]{POSE_ADJUSTMENT_HEAD_X_NEGATIVE, POSE_ADJUSTMENT_HEAD_X_POSITIVE, POSE_ADJUSTMENT_HEAD_Y_NEGATIVE, POSE_ADJUSTMENT_HEAD_Y_POSITIVE, POSE_ADJUSTMENT_HEAD_Z_NEGATIVE, POSE_ADJUSTMENT_HEAD_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_BODY = new int[]{POSE_ADJUSTMENT_BODY_X_POSITIVE, POSE_ADJUSTMENT_BODY_X_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_NEGATIVE, POSE_ADJUSTMENT_BODY_Y_POSITIVE, POSE_ADJUSTMENT_BODY_Z_NEGATIVE, POSE_ADJUSTMENT_BODY_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_ARM = new int[]{POSE_ADJUSTMENT_RIGHT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_ARM_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_ARM = new int[]{POSE_ADJUSTMENT_LEFT_ARM_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_X_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_ARM_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_ARM_Z_POSITIVE}; + private static final int[] POSE_ADJUSTMENT_RIGHT_LEG = new int[]{POSE_ADJUSTMENT_RIGHT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_X_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_POSITIVE, POSE_ADJUSTMENT_RIGHT_LEG_Z_NEGATIVE}; + private static final int[] POSE_ADJUSTMENT_LEFT_LEG = new int[]{POSE_ADJUSTMENT_LEFT_LEG_X_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_X_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Y_POSITIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_NEGATIVE, POSE_ADJUSTMENT_LEFT_LEG_Z_POSITIVE}; + private static final NavigableMap NUDGE_POSITIONS_X_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_X3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_X8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_X_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_X1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_X3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_X8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Y_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Y1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Y3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Y8_POSITIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_NEGATIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_NEGATIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_NEGATIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_NEGATIVE); + private static final NavigableMap NUDGE_POSITIONS_Z_POSITIVE = ImmutableSortedMap.of(1.0 / 16.0, NUDGE_POSITION_Z1_POSITIVE, 3.0 / 16.0, NUDGE_POSITION_Z3_POSITIVE, 8.0 / 16.0, NUDGE_POSITION_Z8_POSITIVE); + private static final NavigableMap ADJUST_ROTATION_ANGLE_STEPS = ImmutableSortedMap.of(1.0F, ADJUST_ROTATION_ANGLE_STEP_1, 5.0F, ADJUST_ROTATION_ANGLE_STEP_5, 15.0F, ADJUST_ROTATION_ANGLE_STEP_15, 45.0F, ADJUST_ROTATION_ANGLE_STEP_45); + + public VanillaTweaksDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + super(holder, player); + } + + @Override + public void sendPose(ArmorStandPose pose, boolean finalize) { + if (!this.isEditingAllowed()) return; + int triggerValue = this.getTriggerValueFromPose(pose); + if (triggerValue != -1) { + if (this.enqueueTriggerValue(triggerValue)) { + this.lastSyncedPose = pose.copyAndFillFrom(this.lastSyncedPose); + pose.applyToEntity(this.getArmorStand()); + } + } else { + this.tryApplyAllPoseParts(pose); + } + if (finalize) this.finalizeCurrentOperation(); + } + + private int getTriggerValueFromPose(ArmorStandPose pose) { + if (pose.getSourceType() == ArmorStandPose.SourceType.EMPTY) return POSE_PRESETS_ATTENTION; + if (pose.getSourceType() == ArmorStandPose.SourceType.MIRRORED) return MIRROR_AND_FLIP_FLIP; + if (pose.getSourceType() != ArmorStandPose.SourceType.VANILLA_TWEAKS) return -1; + if (pose == ArmorStandPose.WALKING) return POSE_PRESETS_WALKING; + if (pose == ArmorStandPose.RUNNING) return POSE_PRESETS_RUNNING; + if (pose == ArmorStandPose.POINTING) return POSE_PRESETS_POINTING; + if (pose == ArmorStandPose.BLOCKING) return POSE_PRESETS_BLOCKING; + if (pose == ArmorStandPose.LUNGEING) return POSE_PRESETS_LUNGEING; + if (pose == ArmorStandPose.WINNING) return POSE_PRESETS_WINNING; + if (pose == ArmorStandPose.SITTING) return POSE_PRESETS_SITTING; + if (pose == ArmorStandPose.ARABESQUE) return POSE_PRESETS_ARABESQUE; + if (pose == ArmorStandPose.CUPID) return POSE_PRESETS_CUPID; + if (pose == ArmorStandPose.CONFIDENT) return POSE_PRESETS_CONFIDENT; + if (pose == ArmorStandPose.SALUTE) return POSE_PRESETS_SALUTE; + if (pose == ArmorStandPose.DEATH) return POSE_PRESETS_DEATH; + if (pose == ArmorStandPose.FACEPALM) return POSE_PRESETS_FACEPALM; + if (pose == ArmorStandPose.LAZING) return POSE_PRESETS_LAZING; + if (pose == ArmorStandPose.CONFUSED) return POSE_PRESETS_CONFUSED; + if (pose == ArmorStandPose.FORMAL) return POSE_PRESETS_FORMAL; + if (pose == ArmorStandPose.SAD) return POSE_PRESETS_SAD; + if (pose == ArmorStandPose.JOYOUS) return POSE_PRESETS_JOYOUS; + if (pose == ArmorStandPose.STARGAZING) return POSE_PRESETS_STARGAZING; + return -1; + } + + private void tryApplyAllPoseParts(ArmorStandPose pose) { + if (!this.tryApplyPosePart(this.lastSyncedPose.getHeadPose(), pose.getNullableHeadPose(), POSE_ADJUSTMENT_HEAD, this.lastSyncedPose::withHeadPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getBodyPose(), pose.getNullableBodyPose(), POSE_ADJUSTMENT_BODY, this.lastSyncedPose::withBodyPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightArmPose(), pose.getNullableRightArmPose(), POSE_ADJUSTMENT_RIGHT_ARM, this.lastSyncedPose::withRightArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftArmPose(), pose.getNullableLeftArmPose(), POSE_ADJUSTMENT_LEFT_ARM, this.lastSyncedPose::withLeftArmPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getRightLegPose(), pose.getNullableRightLegPose(), POSE_ADJUSTMENT_RIGHT_LEG, this.lastSyncedPose::withRightLegPose)) + return; + if (!this.tryApplyPosePart(this.lastSyncedPose.getLeftLegPose(), pose.getNullableLeftLegPose(), POSE_ADJUSTMENT_LEFT_LEG, this.lastSyncedPose::withLeftLegPose)) + return; + } + + private boolean tryApplyPosePart(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment, Function function) { + if (this.tryApplyPoseAdjustment(oldPose, newPose, poseAdjustment)) { + this.lastSyncedPose = function.apply(newPose != null ? newPose : oldPose); + return true; + } else { + return false; + } + } + + private boolean tryApplyPoseAdjustment(Rotations oldPose, @Nullable Rotations newPose, int[] poseAdjustment) { + if (newPose == null || oldPose.equals(newPose)) return true; + if (!this.applyIncrementsFromSteps(oldPose.getX(), newPose.getX(), poseAdjustment[0], poseAdjustment[1])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getY(), newPose.getY(), poseAdjustment[2], poseAdjustment[3])) return false; + if (!this.applyIncrementsFromSteps(oldPose.getZ(), newPose.getZ(), poseAdjustment[4], poseAdjustment[5])) return false; + return true; + } + + @Override + public void sendPosition(double posX, double posY, double posZ, boolean finalize) { + if (!this.isEditingAllowed()) return; + this.applyPositionIncrements(this.getArmorStand().getX(), posX, NUDGE_POSITIONS_X_POSITIVE, NUDGE_POSITIONS_X_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getY(), posY, NUDGE_POSITIONS_Y_POSITIVE, NUDGE_POSITIONS_Y_NEGATIVE); + this.applyPositionIncrements(this.getArmorStand().getZ(), posZ, NUDGE_POSITIONS_Z_POSITIVE, NUDGE_POSITIONS_Z_NEGATIVE); + if (finalize) this.finalizeCurrentOperation(); + } + + private void applyPositionIncrements(double oldValue, double newValue, NavigableMap positiveNudgePositions, NavigableMap negativeNudgePositions) { + double value = newValue - oldValue; + double signum = Math.signum(value); + value = Math.abs(value); + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = (signum == -1.0F ? negativeNudgePositions : positiveNudgePositions).floorEntry(value); + if (entry != null) { + value -= entry.getKey(); + if (!this.enqueueTriggerValue(entry.getValue())) { + return; + } + } else { + break; + } + } + } + + @Override + public void sendRotation(float rotation, boolean finalize) { + if (!this.isEditingAllowed()) return; + this.applyIncrementsFromSteps(this.getArmorStand().getYRot(), rotation, ADJUST_ROTATION_ROTATE_RIGHT, ADJUST_ROTATION_ROTATE_LEFT); + if (finalize) this.finalizeCurrentOperation(); + } + + private boolean applyIncrementsFromSteps(float oldValue, float newValue, int triggerValueNegative, int triggerValuePositive) { + float value = newValue - oldValue; + float signum = Math.signum(value); + value = Math.abs(value); + float lastIncrement = 0.0F; + for (int i = 0; i < MAX_INCREMENTAL_OPERATIONS; i++) { + Map.Entry entry = ADJUST_ROTATION_ANGLE_STEPS.floorEntry(value); + if (entry != null) { + float currentIncrement = entry.getKey(); + value -= currentIncrement; + if (currentIncrement != lastIncrement) { + lastIncrement = currentIncrement; + if (!this.enqueueTriggerValue(entry.getValue())) { + return false; + } + } + if (!this.enqueueTriggerValue(signum == -1.0F ? triggerValuePositive : triggerValueNegative)) { + return false; + } + } else { + break; + } + } + return true; + } + + @Override + public void sendStyleOption(ArmorStandStyleOption styleOption, boolean value, boolean finalize) { + if (!this.isEditingAllowed()) return; + int triggerValue; + if (styleOption == ArmorStandStyleOptions.SHOW_NAME) { + triggerValue = value ? DISPLAY_NAME_YES : DISPLAY_NAME_NO; + } else if (styleOption == ArmorStandStyleOptions.SHOW_ARMS) { + triggerValue = value ? SHOW_ARMS_YES : SHOW_ARMS_NO; + } else if (styleOption == ArmorStandStyleOptions.SMALL) { + triggerValue = value ? SMALL_STAND_YES : SMALL_STAND_NO; + } else if (styleOption == ArmorStandStyleOptions.INVISIBLE) { + triggerValue = value ? STAND_VISIBLE_NO : STAND_VISIBLE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_BASE_PLATE) { + triggerValue = value ? SHOW_BASE_PLATE_NO : SHOW_BASE_PLATE_YES; + } else if (styleOption == ArmorStandStyleOptions.NO_GRAVITY) { + triggerValue = value ? APPLY_GRAVITY_NO : APPLY_GRAVITY_YES; + } else { + super.sendStyleOption(styleOption, value, finalize); + return; + } + if (this.sendSingleTriggerValue(triggerValue, finalize)) { + styleOption.setOption(this.getArmorStand(), value); + } + } + + @Override + public void sendAlignment(ArmorStandAlignment alignment) { + if (!this.isEditingAllowed()) return; + int triggerValue = switch (alignment) { + case BLOCK -> AUTO_ALIGNMENT_BLOCK_ON_SURFACE; + case FLOATING_ITEM -> AUTO_ALIGNMENT_ITEM_ON_SURFACE; + case FLAT_ITEM -> AUTO_ALIGNMENT_ITEM_FLAT_ON_SURFACE; + case TOOL -> AUTO_ALIGNMENT_TOOL_FLAT_ON_SURFACE; + }; + this.sendSingleTriggerValue(triggerValue, true); + } + + public void sendSingleTriggerValue(int triggerValue) { + if (!this.isEditingAllowed()) return; + this.sendSingleTriggerValue(triggerValue, true); + } + + private boolean sendSingleTriggerValue(int triggerValue, boolean finalize) { + boolean result = this.enqueueTriggerValue(triggerValue); + if (finalize) this.finalizeCurrentOperation(); + return result; + } + + @Override + public ArmorStandScreenType[] getScreenTypes() { + return Stream.concat(Stream.of(super.getScreenTypes()), Stream.of(ModRegistry.VANILLA_TWEAKS_SCREEN_TYPE)).toArray(ArmorStandScreenType[]::new); + } + + @Override + protected boolean isEditingAllowed() { + return this.isEditingAllowed(false); + } + + @Override + protected Either testArmorStand(ArmorStand armorStand) { + return super.testArmorStand(armorStand).>map(Optional::of, $ -> { + if (this.player.distanceToSqr(armorStand) < 9.0) { + return Optional.empty(); + } else { + return Optional.of(Component.translatable(OUT_OF_RANGE_TRANSLATION_KEY)); + } + }).>map(Either::left).orElse(Either.right(Unit.INSTANCE)); + } + + @Override + protected int getDequeueDelayTicks() { + return ArmorStatues.CONFIG.get(ClientConfig.class).clientCommandDelay; + } + + private boolean enqueueTriggerValue(int triggerValue) { + return this.enqueueClientCommand("trigger as_trigger set %s".formatted(triggerValue)); + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java new file mode 100644 index 0000000..3689876 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ClientProxy.java @@ -0,0 +1,51 @@ +package fuzs.armorstatues.proxy; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.config.ClientConfig; +import fuzs.armorstatues.init.ModRegistry; +import fuzs.armorstatues.network.client.data.CommandDataSyncHandler; +import fuzs.armorstatues.network.client.data.VanillaTweaksDataSyncHandler; +import fuzs.statuemenus.api.v1.client.gui.screens.ArmorStandScreenFactory; +import fuzs.statuemenus.api.v1.network.client.data.DataSyncHandler; +import fuzs.statuemenus.api.v1.world.entity.decoration.ArmorStandDataProvider; +import fuzs.statuemenus.api.v1.world.inventory.ArmorStandHolder; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ClientProxy extends ServerProxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + ArmorStandHolder holder = new ArmorStandHolder() { + + @Override + public ArmorStand getArmorStand() { + return armorStand; + } + + @Override + public ArmorStandDataProvider getDataProvider() { + return ModRegistry.ARMOR_STAND_DATA_PROVIDER; + } + }; + Screen screen = ArmorStandScreenFactory.createLastScreenType(holder, + player.getInventory(), + armorStand.getDisplayName(), + createDataSyncHandler(holder, (LocalPlayer) player) + ); + Minecraft minecraft = Minecraft.getInstance(); + minecraft.setScreen(screen); + } + + private static DataSyncHandler createDataSyncHandler(ArmorStandHolder holder, LocalPlayer player) { + if ((!player.hasPermissions(2) || ArmorStatues.CONFIG.get(ClientConfig.class).overrideClientPermissionsCheck) && + ArmorStatues.CONFIG.get(ClientConfig.class).useVanillaTweaksTriggers) { + return new VanillaTweaksDataSyncHandler(holder, player); + } else { + return new CommandDataSyncHandler(holder, player); + } + } +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java new file mode 100644 index 0000000..1f5ae83 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/Proxy.java @@ -0,0 +1,11 @@ +package fuzs.armorstatues.proxy; + +import fuzs.puzzleslib.api.core.v1.ModLoaderEnvironment; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public interface Proxy { + Proxy INSTANCE = ModLoaderEnvironment.INSTANCE.isClient() ? new ClientProxy() : new ServerProxy(); + + void openArmorStandScreen(ArmorStand armorStand, Player player); +} diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java new file mode 100644 index 0000000..f41e246 --- /dev/null +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/proxy/ServerProxy.java @@ -0,0 +1,12 @@ +package fuzs.armorstatues.proxy; + +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; + +public class ServerProxy implements Proxy { + + @Override + public void openArmorStandScreen(ArmorStand armorStand, Player player) { + // NO-OP + } +} diff --git a/1.21.3/Common/src/main/resources/architectury.common.json b/1.21.3/Common/src/main/resources/architectury.common.json new file mode 100644 index 0000000..4cfa289 --- /dev/null +++ b/1.21.3/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "armorstatues.accesswidener" +} \ No newline at end of file diff --git a/1.21.3/Common/src/main/resources/armorstatues.accesswidener b/1.21.3/Common/src/main/resources/armorstatues.accesswidener new file mode 100644 index 0000000..236e6b1 --- /dev/null +++ b/1.21.3/Common/src/main/resources/armorstatues.accesswidener @@ -0,0 +1 @@ +accessWidener v2 named diff --git a/1.21.3/Common/src/main/resources/common.mixins.json b/1.21.3/Common/src/main/resources/common.mixins.json new file mode 100644 index 0000000..77fc8f4 --- /dev/null +++ b/1.21.3/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.3/Common/src/main/resources/mod_banner.png b/1.21.3/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..62a46106e75f6f8cfd477182314002fec637c712 GIT binary patch literal 15383 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 eyqew78|xoesj$^wqzKCZ0000=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "statuemenus": "*", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.21.3/NeoForge/build.gradle b/1.21.3/NeoForge/build.gradle new file mode 100644 index 0000000..97e8395 --- /dev/null +++ b/1.21.3/NeoForge/build.gradle @@ -0,0 +1,9 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/neoforge.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.neoforge + + // Statue Menus + modApi(include(libs.statuemenus.neoforge.get())) +} diff --git a/1.21.3/NeoForge/gradle.properties b/1.21.3/NeoForge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/1.21.3/NeoForge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java b/1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java new file mode 100644 index 0000000..9f37d35 --- /dev/null +++ b/1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/ArmorStatuesNeoForge.java @@ -0,0 +1,13 @@ +package fuzs.armorstatues.neoforge; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.neoforged.fml.common.Mod; + +@Mod(ArmorStatues.MOD_ID) +public class ArmorStatuesNeoForge { + + public ArmorStatuesNeoForge() { + ModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatues::new); + } +} diff --git a/1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java b/1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java new file mode 100644 index 0000000..53de799 --- /dev/null +++ b/1.21.3/NeoForge/src/main/java/fuzs/armorstatues/neoforge/client/ArmorStatuesNeoForgeClient.java @@ -0,0 +1,18 @@ +package fuzs.armorstatues.neoforge.client; + +import fuzs.armorstatues.ArmorStatues; +import fuzs.armorstatues.client.ArmorStatuesClient; +import fuzs.armorstatues.data.client.ModLanguageProvider; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.common.Mod; + +@Mod(value = ArmorStatues.MOD_ID, dist = Dist.CLIENT) +public class ArmorStatuesNeoForgeClient { + + public ArmorStatuesNeoForgeClient() { + ClientModConstructor.construct(ArmorStatues.MOD_ID, ArmorStatuesClient::new); + DataProviderHelper.registerDataProviders(ArmorStatues.MOD_ID, ModLanguageProvider::new); + } +} diff --git a/1.21.3/NeoForge/src/main/resources/META-INF/neoforge.mods.toml b/1.21.3/NeoForge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..432ab6c --- /dev/null +++ b/1.21.3/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,57 @@ +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" + +[[dependencies.${ modId }]] +modId = "statuemenus" +mandatory = true +type = "required" +versionRange = "*" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.21.3/NeoForge/src/main/resources/neoforge.mixins.json b/1.21.3/NeoForge/src/main/resources/neoforge.mixins.json new file mode 100644 index 0000000..1fb3919 --- /dev/null +++ b/1.21.3/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.3/build.gradle b/1.21.3/build.gradle new file mode 100644 index 0000000..dea2bca --- /dev/null +++ b/1.21.3/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.3/gradle.properties b/1.21.3/gradle.properties new file mode 100755 index 0000000..c5b4b8e --- /dev/null +++ b/1.21.3/gradle.properties @@ -0,0 +1,45 @@ +org.gradle.jvmargs=-Xmx4G +org.gradle.daemon=false +copyBuildJar=true + +# Mod Attributes +modId=armorstatues +modName=Armor Statues +modVersion=21.1.0 +modAuthor=Fuzs +modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/armorstatues +modIssueUrl=https://github.com/Fuzss/armorstatues/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/armorstatues.json +modMavenGroup=fuzs.armorstatues +# "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=IGNORE_ALL_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.1-v6 +dependenciesPuzzlesLibVersion=21.1.8 +dependenciesMinPuzzlesLibVersion=21.1.8 + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=682566 +projectModrinthId=bbGCtEvb + +# 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.3/gradle/wrapper/gradle-wrapper.jar b/1.21.3/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.3/gradle/wrapper/gradle-wrapper.properties b/1.21.3/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2617362 --- /dev/null +++ b/1.21.3/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.3/gradlew b/1.21.3/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.21.3/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.3/gradlew.bat b/1.21.3/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.21.3/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.3/settings.gradle b/1.21.3/settings.gradle new file mode 100644 index 0000000..5cfe5eb --- /dev/null +++ b/1.21.3/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 5829a25dd0396d4d1fe0c588fe798d932ef909cf Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:34:54 +0100 Subject: [PATCH 31/31] full 1.21.3 port --- 1.21.3/CHANGELOG.md | 4 ++-- .../.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 +- .../src/main/java/fuzs/armorstatues/ArmorStatues.java | 2 +- .../src/main/java/fuzs/armorstatues/init/ModRegistry.java | 2 +- 1.21.3/gradle.properties | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/1.21.3/CHANGELOG.md b/1.21.3/CHANGELOG.md index e8a7c35..0248538 100644 --- a/1.21.3/CHANGELOG.md +++ b/1.21.3/CHANGELOG.md @@ -4,5 +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.1.0-1.21.1] - 2024-09-17 -- Port to Minecraft 1.21.1 +## [v21.3.0-1.21.3] - 2024-12-09 +- Port to Minecraft 1.21.3 diff --git a/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 index bd386df..7219911 100644 --- a/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 +++ b/1.21.3/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -1,2 +1,2 @@ -// 1.21 2024-07-11T14:39:10.467599 Language (en_us) +// 1.21.3 2024-12-09T11:45:46.926081 Language (en_us) 3b837616894d5f092cf8c1f8e4658d723dbc0320 assets/armorstatues/lang/en_us.json diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java index 70c87b4..f260170 100644 --- a/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/ArmorStatues.java @@ -21,7 +21,7 @@ public class ArmorStatues implements ModConstructor { @Override public void onConstructMod() { - ModRegistry.touch(); + ModRegistry.bootstrap(); registerEventHandlers(); } diff --git a/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java b/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java index a9aba22..9720ffb 100644 --- a/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java +++ b/1.21.3/Common/src/main/java/fuzs/armorstatues/init/ModRegistry.java @@ -45,7 +45,7 @@ public ArmorStandScreenType[] getScreenTypes() { } }; - public static void touch() { + public static void bootstrap() { // NO-OP } } diff --git a/1.21.3/gradle.properties b/1.21.3/gradle.properties index c5b4b8e..dd2ef35 100755 --- a/1.21.3/gradle.properties +++ b/1.21.3/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=armorstatues modName=Armor Statues -modVersion=21.1.0 +modVersion=21.3.0 modAuthor=Fuzs modDescription=Unlock the full potential of armor stands! Works on vanilla servers, too. modLicense=MPL-2.0 @@ -19,9 +19,9 @@ modForgeDisplayTest=IGNORE_ALL_VERSION modFabricEnvironment=* # Version Catalog -dependenciesVersionCatalog=1.21.1-v6 -dependenciesPuzzlesLibVersion=21.1.8 -dependenciesMinPuzzlesLibVersion=21.1.8 +dependenciesVersionCatalog=1.21.3-v13 +#dependenciesPuzzlesLibVersion=21.3.13 +#dependenciesMinPuzzlesLibVersion=21.3.13 # Mod Publishing projectReleaseType=release