diff --git a/build.gradle.kts b/build.gradle.kts index fe40fc3..269d3b1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,13 +1,3 @@ -plugins { - id("roundalib") version "0.4.0" -} - -repositories { - maven("https://jitpack.io") -} - -dependencies { - implementation("com.github.LlamaLad7:MixinExtras:0.1.1") - annotationProcessor("com.github.LlamaLad7:MixinExtras:0.1.1") - include("com.github.LlamaLad7:MixinExtras:0.1.1") -} +plugins { + id("roundalib") version "0.7.0-SNAPSHOT" +} diff --git a/gradle.properties b/gradle.properties index 89ed86b..6252a41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,13 +1,16 @@ # Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx4G -XX:ActiveProcessorCount=4 +org.gradle.jvmargs=-Xmx8G -XX:ActiveProcessorCount=4 org.gradle.parallel=true # RoundaLib Properties group_id=me.roundaround mod_id=armorstands -mod_version=1.4.0 -minecraft_version=1.20.3 +mod_version=1.5.0 +minecraft_version=1.20.5 yarn_mappings=build.1 -loader_version=0.15.3 -fabric_version=0.91.1 -mod_menu_version=9.0.0 +loader_version=0.15.11 +fabric_version=0.97.8 +roundalib_version=2.0.0 +roundalib_snapshot=true +mod_menu_version=10.0.0-beta.1 +dev_login_version=3.5 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..0ce5b32 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/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 -networkTimeout=10000 -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +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/settings.gradle.kts b/settings.gradle.kts index 9dc8b59..3162ca0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ -pluginManagement { - repositories { - gradlePluginPortal() - maven("https://maven.fabricmc.net/") - maven("https://maven.rnda.dev/releases/") - } -} +pluginManagement { + repositories { + gradlePluginPortal() + maven("https://maven.fabricmc.net/") + maven("https://maven.rnda.dev/snapshots/") + } +} diff --git a/src/main/java/me/roundaround/armorstands/ArmorStandsMod.java b/src/main/java/me/roundaround/armorstands/ArmorStandsMod.java index 6c039a2..9963ab9 100644 --- a/src/main/java/me/roundaround/armorstands/ArmorStandsMod.java +++ b/src/main/java/me/roundaround/armorstands/ArmorStandsMod.java @@ -1,9 +1,10 @@ package me.roundaround.armorstands; -import me.roundaround.armorstands.network.packet.c2s.*; +import me.roundaround.armorstands.network.Networking; import me.roundaround.armorstands.screen.ArmorStandScreenHandler; import me.roundaround.armorstands.server.ArmorStandUsers; import me.roundaround.armorstands.server.command.ArmorStandsCommand; +import me.roundaround.armorstands.server.network.ServerNetworking; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; @@ -16,20 +17,19 @@ public final class ArmorStandsMod implements ModInitializer { public static final String MOD_ID = "armorstands"; public static final Logger LOGGER = LogManager.getLogger(MOD_ID); - public static final ExtendedScreenHandlerType - ARMOR_STAND_SCREEN_HANDLER_TYPE = new ExtendedScreenHandlerType( - ArmorStandScreenHandler::new); + public static final ExtendedScreenHandlerType ARMOR_STAND_SCREEN_HANDLER_TYPE = new ExtendedScreenHandlerType<>( + ArmorStandScreenHandler::new, ArmorStandScreenHandler.Data.PACKET_CODEC); static { - Registry.register( - Registries.SCREEN_HANDLER, - "armorstands:armor_stand", - ARMOR_STAND_SCREEN_HANDLER_TYPE); + Registry.register(Registries.SCREEN_HANDLER, "armorstands:armor_stand", ARMOR_STAND_SCREEN_HANDLER_TYPE); } @Override public void onInitialize() { - registerReceivers(); + Networking.registerS2CPayloads(); + Networking.registerC2SPayloads(); + + ServerNetworking.registerReceivers(); CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { if (environment.dedicated) { @@ -43,18 +43,4 @@ public void onInitialize() { } }); } - - private static void registerReceivers() { - RequestScreenPacket.registerServerReceiver(); - AdjustYawPacket.registerServerReceiver(); - SetYawPacket.registerServerReceiver(); - AdjustPosPacket.registerServerReceiver(); - UtilityActionPacket.registerServerReceiver(); - SetFlagPacket.registerServerReceiver(); - SetPosePacket.registerServerReceiver(); - SetPosePresetPacket.registerServerReceiver(); - AdjustPosePacket.registerServerReceiver(); - UndoPacket.registerServerReceiver(); - PingPacket.registerServerReceiver(); - } } diff --git a/src/main/java/me/roundaround/armorstands/ArmorStandsPreLaunch.java b/src/main/java/me/roundaround/armorstands/ArmorStandsPreLaunch.java deleted file mode 100644 index 2e0a8e6..0000000 --- a/src/main/java/me/roundaround/armorstands/ArmorStandsPreLaunch.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.roundaround.armorstands; - -import com.llamalad7.mixinextras.MixinExtrasBootstrap; -import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; - -public class ArmorStandsPreLaunch implements PreLaunchEntrypoint { - public void onPreLaunch() { - MixinExtrasBootstrap.init(); - } -} diff --git a/src/main/java/me/roundaround/armorstands/client/ArmorStandsClientMod.java b/src/main/java/me/roundaround/armorstands/client/ArmorStandsClientMod.java index bcdd6a8..f0f763d 100644 --- a/src/main/java/me/roundaround/armorstands/client/ArmorStandsClientMod.java +++ b/src/main/java/me/roundaround/armorstands/client/ArmorStandsClientMod.java @@ -1,66 +1,57 @@ -package me.roundaround.armorstands.client; - -import me.roundaround.armorstands.ArmorStandsMod; -import me.roundaround.armorstands.client.gui.screen.*; -import me.roundaround.armorstands.network.packet.s2c.ClientUpdatePacket; -import me.roundaround.armorstands.network.packet.s2c.MessagePacket; -import me.roundaround.armorstands.network.packet.s2c.PongPacket; -import me.roundaround.armorstands.screen.ArmorStandScreenHandler; -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.fabricmc.fabric.api.resource.ResourceManagerHelper; -import net.fabricmc.fabric.api.resource.ResourcePackActivationType; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.gui.screen.ingame.HandledScreens; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - -public class ArmorStandsClientMod implements ClientModInitializer { - public static KeyBinding highlightArmorStandKeyBinding; - - @Override - public void onInitializeClient() { - registerReceivers(); - - highlightArmorStandKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding( - "armorstands.key.highlight_armor_stand", - InputUtil.Type.KEYSYM, - InputUtil.UNKNOWN_KEY.getCode(), - KeyBinding.MISC_CATEGORY)); - - FabricLoader.getInstance().getModContainer(ArmorStandsMod.MOD_ID).ifPresent((container) -> { - ResourceManagerHelper.registerBuiltinResourcePack( - new Identifier(ArmorStandsMod.MOD_ID, "armorstands-dark-ui"), - container, - Text.literal("Armor Stands Dark UI"), - ResourcePackActivationType.NORMAL); - }); - - HandledScreens.register(ArmorStandsMod.ARMOR_STAND_SCREEN_HANDLER_TYPE, - new HandledScreens.Provider() { - @Override - public AbstractArmorStandScreen create( - ArmorStandScreenHandler handler, - PlayerInventory playerInventory, - Text title) { - return switch (handler.getScreenType()) { - case UTILITIES -> new ArmorStandUtilitiesScreen(handler); - case MOVE -> new ArmorStandMoveScreen(handler); - case ROTATE -> new ArmorStandRotateScreen(handler); - case POSE -> new ArmorStandPoseScreen(handler); - case PRESETS -> new ArmorStandPresetsScreen(handler); - case INVENTORY -> new ArmorStandInventoryScreen(handler); - }; - } - }); - } - - private static void registerReceivers() { - ClientUpdatePacket.registerClientReceiver(); - MessagePacket.registerClientReceiver(); - PongPacket.registerClientReceiver(); - } -} +package me.roundaround.armorstands.client; + +import me.roundaround.armorstands.ArmorStandsMod; +import me.roundaround.armorstands.client.gui.screen.*; +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.screen.ArmorStandScreenHandler; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.ResourcePackActivationType; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class ArmorStandsClientMod implements ClientModInitializer { + public static KeyBinding highlightArmorStandKeyBinding; + + @Override + public void onInitializeClient() { + ClientNetworking.registerReceivers(); + + highlightArmorStandKeyBinding = KeyBindingHelper.registerKeyBinding( + new KeyBinding("armorstands.key.highlight_armor_stand", InputUtil.Type.KEYSYM, InputUtil.UNKNOWN_KEY.getCode(), + KeyBinding.MISC_CATEGORY + )); + + FabricLoader.getInstance() + .getModContainer(ArmorStandsMod.MOD_ID) + .ifPresent((container) -> ResourceManagerHelper.registerBuiltinResourcePack( + new Identifier(ArmorStandsMod.MOD_ID, "armorstands-dark-ui"), container, + Text.literal("Armor Stands Dark UI"), ResourcePackActivationType.NORMAL + )); + + HandledScreens.register(ArmorStandsMod.ARMOR_STAND_SCREEN_HANDLER_TYPE, new HandledScreenProvider()); + } + + private static class HandledScreenProvider implements HandledScreens.Provider { + @Override + public AbstractArmorStandScreen create( + ArmorStandScreenHandler handler, PlayerInventory playerInventory, Text title + ) { + return switch (handler.getScreenType()) { + case UTILITIES -> new ArmorStandUtilitiesScreen(handler); + case MOVE -> new ArmorStandMoveScreen(handler); + case ROTATE -> new ArmorStandRotateScreen(handler); + case POSE -> new ArmorStandPoseScreen(handler); + case PRESETS -> new ArmorStandPresetsScreen(handler); + case INVENTORY -> new ArmorStandInventoryScreen(handler); + }; + } + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/screen/AbstractArmorStandScreen.java b/src/main/java/me/roundaround/armorstands/client/gui/screen/AbstractArmorStandScreen.java index bc38bc0..ca0135c 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/screen/AbstractArmorStandScreen.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/screen/AbstractArmorStandScreen.java @@ -9,16 +9,13 @@ import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; import me.roundaround.armorstands.client.gui.widget.LabelWidget; import me.roundaround.armorstands.client.gui.widget.NavigationButtonWidget; +import me.roundaround.armorstands.client.network.ClientNetworking; import me.roundaround.armorstands.mixin.ArmorStandEntityAccessor; import me.roundaround.armorstands.mixin.InGameHudAccessor; import me.roundaround.armorstands.mixin.KeyBindingAccessor; import me.roundaround.armorstands.mixin.MouseAccessor; import me.roundaround.armorstands.network.ScreenType; import me.roundaround.armorstands.network.UtilityAction; -import me.roundaround.armorstands.network.packet.c2s.PingPacket; -import me.roundaround.armorstands.network.packet.c2s.RequestScreenPacket; -import me.roundaround.armorstands.network.packet.c2s.UndoPacket; -import me.roundaround.armorstands.network.packet.c2s.UtilityActionPacket; import me.roundaround.armorstands.screen.ArmorStandScreenHandler; import me.roundaround.armorstands.util.HasArmorStand; import net.minecraft.client.gui.DrawContext; @@ -37,12 +34,14 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Objects; import java.util.Optional; -public abstract class AbstractArmorStandScreen extends HandledScreen - implements HasArmorStand, HasMessageRenderer, PassesEventsThrough { - protected static final Identifier SELECTION_TEXTURE = - new Identifier(ArmorStandsMod.MOD_ID, "textures/gui/selection_frame.png"); +public abstract class AbstractArmorStandScreen extends HandledScreen implements HasArmorStand, + HasMessageRenderer, + PassesEventsThrough { + protected static final Identifier SELECTION_TEXTURE = new Identifier( + ArmorStandsMod.MOD_ID, "textures/gui/selection_frame.png"); protected static final int SCREEN_EDGE_PAD = 4; protected static final int BETWEEN_PAD = 2; @@ -92,11 +91,6 @@ public boolean shouldPassEvents() { return this.passEvents; } - @Override - public boolean shouldPause() { - return false; - } - @Override public void init() { initStart(); @@ -112,11 +106,13 @@ public void init() { @Override protected void handledScreenTick() { + assert this.client != null; + // Block any inputs bound to shift so that this screen gets exclusive use - Arrays.stream(this.client.options.allKeys).filter((key) -> { - return key.matchesKey(GLFW.GLFW_KEY_LEFT_SHIFT, 0) || - key.matchesKey(GLFW.GLFW_KEY_RIGHT_SHIFT, 0); - }).map((key) -> (KeyBindingAccessor) key).forEach(KeyBindingAccessor::invokeReset); + Arrays.stream(this.client.options.allKeys) + .filter((key) -> key.matchesKey(GLFW.GLFW_KEY_LEFT_SHIFT, 0) || key.matchesKey(GLFW.GLFW_KEY_RIGHT_SHIFT, 0)) + .map((key) -> (KeyBindingAccessor) key) + .forEach(KeyBindingAccessor::invokeReset); ((InGameHudAccessor) this.client.inGameHud).invokeUpdateVignetteDarkness(this.client.getCameraEntity()); @@ -125,12 +121,13 @@ protected void handledScreenTick() { @Override public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + assert this.client != null; + int adjustedMouseX = cursorLocked ? -1 : mouseX; int adjustedMouseY = cursorLocked ? -1 : mouseY; RenderSystem.enableBlend(); - ((InGameHudAccessor) this.client.inGameHud).invokeRenderVignetteOverlay(drawContext, - this.client.getCameraEntity()); + ((InGameHudAccessor) this.client.inGameHud).invokeRenderVignetteOverlay(drawContext, this.client.getCameraEntity()); // Render labels before all other widgets so they are rendered on bottom for (LabelWidget label : this.labels) { @@ -182,7 +179,8 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { @Override public boolean mouseDragged( - double mouseX, double mouseY, int button, double deltaX, double deltaY) { + double mouseX, double mouseY, int button, double deltaX, double deltaY + ) { if (this.cursorLocked) { return false; } @@ -218,7 +216,8 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { @Override public boolean mouseScrolled( - double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + double mouseX, double mouseY, double horizontalAmount, double verticalAmount + ) { if (this.cursorLocked) { return false; } @@ -245,6 +244,8 @@ public Optional hoveredElement(double mouseX, double mouseY) { @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + assert this.client != null; + // Allow jump to pass through without pressing buttons if (this.client.options.jumpKey.matchesKey(keyCode, scanCode)) { return false; @@ -285,21 +286,21 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { break; } playClickSound(); - UndoPacket.sendToServer(Screen.hasShiftDown()); + ClientNetworking.sendUndoPacket(Screen.hasShiftDown()); return true; case GLFW.GLFW_KEY_C: if (!this.supportsUndoRedo || !Screen.hasControlDown()) { break; } playClickSound(); - UtilityActionPacket.sendToServer(UtilityAction.COPY); + ClientNetworking.sendUtilityActionPacket(UtilityAction.COPY); return true; case GLFW.GLFW_KEY_V: if (!this.supportsUndoRedo || !Screen.hasControlDown()) { break; } playClickSound(); - UtilityActionPacket.sendToServer(UtilityAction.PASTE); + ClientNetworking.sendUtilityActionPacket(UtilityAction.PASTE); return true; } @@ -327,8 +328,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { @Override public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - if (this.passEvents && - (keyCode == GLFW.GLFW_KEY_LEFT_ALT || keyCode == GLFW.GLFW_KEY_RIGHT_ALT)) { + if (this.passEvents && (keyCode == GLFW.GLFW_KEY_LEFT_ALT || keyCode == GLFW.GLFW_KEY_RIGHT_ALT)) { unlockCursor(); return true; } @@ -337,8 +337,7 @@ public boolean keyReleased(int keyCode, int scanCode, int modifiers) { } public boolean shouldHighlight(Entity entity) { - return ArmorStandsClientMod.highlightArmorStandKeyBinding.isPressed() && - entity == this.armorStand; + return ArmorStandsClientMod.highlightArmorStandKeyBinding.isPressed() && entity == this.armorStand; } public boolean isCursorLocked() { @@ -347,7 +346,7 @@ public boolean isCursorLocked() { public void sendPing() { this.lastPing = System.currentTimeMillis(); - PingPacket.sendToServer(this.client.player); + ClientNetworking.sendPingPacket(Objects.requireNonNull(this.client).player); } public void onPong() { @@ -385,37 +384,23 @@ protected void initUtilityButtons() { } addDrawableChild(new HelpButtonWidget(SCREEN_EDGE_PAD, SCREEN_EDGE_PAD)); - addDrawableChild(new IconButtonWidget(SCREEN_EDGE_PAD + IconButtonWidget.WIDTH + BETWEEN_PAD, - SCREEN_EDGE_PAD, - 14, + addDrawableChild(new IconButtonWidget(SCREEN_EDGE_PAD + IconButtonWidget.WIDTH + BETWEEN_PAD, SCREEN_EDGE_PAD, 14, Text.translatable("armorstands.utility.copy"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.COPY); - })); - addDrawableChild(new IconButtonWidget( - SCREEN_EDGE_PAD + 2 * (IconButtonWidget.WIDTH + BETWEEN_PAD), - SCREEN_EDGE_PAD, - 15, - Text.translatable("armorstands.utility.paste"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.PASTE); - })); - addDrawableChild(new IconButtonWidget( - SCREEN_EDGE_PAD + 3 * (IconButtonWidget.WIDTH + BETWEEN_PAD), - SCREEN_EDGE_PAD, - 17, - Text.translatable("armorstands.utility.undo"), - (button) -> { - UndoPacket.sendToServer(false); - })); - addDrawableChild(new IconButtonWidget( - SCREEN_EDGE_PAD + 4 * (IconButtonWidget.WIDTH + BETWEEN_PAD), - SCREEN_EDGE_PAD, - 18, - Text.translatable("armorstands.utility.redo"), - (button) -> { - UndoPacket.sendToServer(true); - })); + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.COPY) + )); + addDrawableChild( + new IconButtonWidget(SCREEN_EDGE_PAD + 2 * (IconButtonWidget.WIDTH + BETWEEN_PAD), SCREEN_EDGE_PAD, 15, + Text.translatable("armorstands.utility.paste"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.PASTE) + )); + addDrawableChild( + new IconButtonWidget(SCREEN_EDGE_PAD + 3 * (IconButtonWidget.WIDTH + BETWEEN_PAD), SCREEN_EDGE_PAD, 17, + Text.translatable("armorstands.utility.undo"), (button) -> ClientNetworking.sendUndoPacket(false) + )); + addDrawableChild( + new IconButtonWidget(SCREEN_EDGE_PAD + 4 * (IconButtonWidget.WIDTH + BETWEEN_PAD), SCREEN_EDGE_PAD, 18, + Text.translatable("armorstands.utility.redo"), (button) -> ClientNetworking.sendUndoPacket(true) + )); } protected void initLeft() { @@ -424,8 +409,7 @@ protected void initLeft() { protected void initNavigationButtons() { ScreenType[] screenTypes = ScreenType.values(); - int totalWidth = screenTypes.length * NavigationButtonWidget.WIDTH + - (screenTypes.length - 1) * NAV_BUTTON_SPACING; + int totalWidth = screenTypes.length * NavigationButtonWidget.WIDTH + (screenTypes.length - 1) * NAV_BUTTON_SPACING; int x = (width - totalWidth) / 2 - 2 * NAV_BUTTON_SPACING; int y = height - NAV_BUTTON_BOTTOM_PADDING - NavigationButtonWidget.HEIGHT; @@ -464,52 +448,45 @@ protected void renderActivePageButtonHighlight(DrawContext drawContext) { MatrixStack matrixStack = drawContext.getMatrices(); matrixStack.push(); matrixStack.translate(0, 0, 100); - drawContext.drawTexture(SELECTION_TEXTURE, - this.activeButton.getX() - 2, - this.activeButton.getY() - 2, - 0, - 0, - 24, - 24, - 24, - 24); + drawContext.drawTexture(SELECTION_TEXTURE, this.activeButton.getX() - 2, this.activeButton.getY() - 2, 0, 0, 24, 24, + 24, 24 + ); matrixStack.pop(); } protected void playClickSound() { - this.client.getSoundManager() + Objects.requireNonNull(this.client) + .getSoundManager() .play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1f)); } protected void lockCursor() { + assert this.client != null; + this.cursorLocked = true; int x = this.client.getWindow().getWidth() / 2; int y = this.client.getWindow().getHeight() / 2; ((MouseAccessor) this.client.mouse).setX(x); ((MouseAccessor) this.client.mouse).setY(y); - InputUtil.setCursorParameters(this.client.getWindow().getHandle(), - InputUtil.GLFW_CURSOR_DISABLED, - x, - y); + InputUtil.setCursorParameters(this.client.getWindow().getHandle(), InputUtil.GLFW_CURSOR_DISABLED, x, y); } protected void unlockCursor() { + assert this.client != null; + this.cursorLocked = false; int x = this.client.getWindow().getWidth() / 2; int y = this.client.getWindow().getHeight() / 2; ((MouseAccessor) this.client.mouse).setX(x); ((MouseAccessor) this.client.mouse).setY(y); - InputUtil.setCursorParameters(this.client.getWindow().getHandle(), - InputUtil.GLFW_CURSOR_NORMAL, - x, - y); + InputUtil.setCursorParameters(this.client.getWindow().getHandle(), InputUtil.GLFW_CURSOR_NORMAL, x, y); } protected void goToPreviousScreen() { - RequestScreenPacket.sendToServer(this.armorStand, getScreenType().previous()); + ClientNetworking.sendRequestScreenPacket(this.armorStand, getScreenType().previous()); } protected void goToNextScreen() { - RequestScreenPacket.sendToServer(this.armorStand, getScreenType().next()); + ClientNetworking.sendRequestScreenPacket(this.armorStand, getScreenType().next()); } } diff --git a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandMoveScreen.java b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandMoveScreen.java index adf19ce..1f666ca 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandMoveScreen.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandMoveScreen.java @@ -1,318 +1,247 @@ -package me.roundaround.armorstands.client.gui.screen; - -import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; -import me.roundaround.armorstands.client.gui.widget.LabelWidget; -import me.roundaround.armorstands.client.gui.widget.MoveButtonWidget; -import me.roundaround.armorstands.network.ScreenType; -import me.roundaround.armorstands.network.UtilityAction; -import me.roundaround.armorstands.network.packet.c2s.UtilityActionPacket; -import me.roundaround.armorstands.screen.ArmorStandScreenHandler; -import me.roundaround.armorstands.util.MoveMode; -import me.roundaround.armorstands.util.MoveUnits; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.CyclingButtonWidget; -import net.minecraft.entity.Entity; -import net.minecraft.text.Text; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; - -import java.util.ArrayList; -import java.util.HashMap; - -public class ArmorStandMoveScreen extends AbstractArmorStandScreen { - private static final int MINI_BUTTON_WIDTH = 28; - private static final int MINI_BUTTON_HEIGHT = 16; - private static final int BUTTON_WIDTH = 46; - private static final int BUTTON_HEIGHT = 16; - - private final HashMap directionLabels = new HashMap<>(); - private final ArrayList moveButtons = new ArrayList<>(); - - private LabelWidget playerPosLabel; - private LabelWidget playerBlockPosLabel; - private LabelWidget standPosLabel; - private LabelWidget standBlockPosLabel; - private LabelWidget facingLabel; - private CyclingButtonWidget unitsButton; - private MoveMode mode = MoveMode.RELATIVE; - private MoveUnits units = MoveUnits.PIXELS; - - public ArmorStandMoveScreen(ArmorStandScreenHandler handler) { - super(handler, ScreenType.MOVE.getDisplayName()); - this.supportsUndoRedo = true; - } - - @Override - public ScreenType getScreenType() { - return ScreenType.MOVE; - } - - @Override - protected void initStart() { - super.initStart(); - - directionLabels.clear(); - moveButtons.clear(); - } - - @Override - protected void initLeft() { - super.initLeft(); - - initCurrentStatus(); - initSnapButtons(); - } - - private void initCurrentStatus() { - addLabel(LabelWidget.builder(Text.translatable("armorstands.current.player"), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.playerPosLabel = addLabel(LabelWidget.builder(getCurrentPosText(client.player), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 2 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.playerBlockPosLabel = addLabel(LabelWidget.builder(getCurrentBlockPosText(client.player), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 3 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - addLabel(LabelWidget.builder(Text.translatable("armorstands.current.stand"), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 5 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.standPosLabel = addLabel(LabelWidget.builder(getCurrentPosText(this.armorStand), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 6 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.standBlockPosLabel = addLabel(LabelWidget.builder(getCurrentBlockPosText(this.armorStand), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 7 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - } - - private void initSnapButtons() { - addLabel(LabelWidget.builder(Text.translatable("armorstands.move.snap"), - SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 2 * (BUTTON_HEIGHT + BETWEEN_PAD)) - .shiftForPadding() - .justifiedLeft() - .alignedBottom() - .build()); - - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.standing"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.SNAP_STANDING); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.sitting"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.SNAP_SITTING); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.corner"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.SNAP_CORNER); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.center"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.SNAP_CENTER); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.player"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.SNAP_PLAYER); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + 2 * (BUTTON_WIDTH + BETWEEN_PAD), - this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - } - - @Override - protected void initRight() { - super.initRight(); - - int topOfMoveButtons = this.height - SCREEN_EDGE_PAD - 6 * MINI_BUTTON_HEIGHT - 5 * BETWEEN_PAD; - - addDrawableChild(CyclingButtonWidget.builder(MoveMode::getOptionValueText) - .values(MoveMode.values()) - .initially(this.mode) - .build(this.width - SCREEN_EDGE_PAD - 120, - topOfMoveButtons - LabelWidget.HEIGHT_WITH_PADDING - 3 * BETWEEN_PAD - - 2 * MINI_BUTTON_HEIGHT, - 120, - MINI_BUTTON_HEIGHT, - MoveMode.getOptionLabelText(), - (button, mode) -> { - this.mode = mode; - this.units = this.mode.getDefaultUnits(); - - this.facingLabel.setText(getCurrentFacingText(this.mode.equals(MoveMode.LOCAL_TO_STAND) - ? this.armorStand - : client.player)); - this.directionLabels.forEach((direction, label) -> { - label.setText(this.mode.getDirectionText(direction)); - }); - - this.unitsButton.setValue(this.units); - this.moveButtons.forEach((moveButton) -> { - moveButton.setUnits(this.units); - }); - })); - - this.unitsButton = addDrawableChild(CyclingButtonWidget.builder(MoveUnits::getOptionValueText) - .values(MoveUnits.values()) - .initially(this.units) - .build(this.width - SCREEN_EDGE_PAD - 120, - topOfMoveButtons - LabelWidget.HEIGHT_WITH_PADDING - 2 * BETWEEN_PAD - - MINI_BUTTON_HEIGHT, - 120, - MINI_BUTTON_HEIGHT, - MoveUnits.getOptionLabelText(), - (button, units) -> { - this.units = units; - this.moveButtons.forEach((moveButton) -> { - moveButton.setUnits(this.units); - }); - })); - - this.facingLabel = - addLabel(LabelWidget.builder(getCurrentFacingText(this.mode.equals(MoveMode.LOCAL_TO_STAND) - ? this.armorStand - : client.player), this.width - SCREEN_EDGE_PAD, topOfMoveButtons - BETWEEN_PAD) - .shiftForPadding() - .alignedBottom() - .justifiedRight() - .build()); - - Direction[] directions = new Direction[] { - Direction.UP, - Direction.DOWN, - Direction.SOUTH, - Direction.NORTH, - Direction.EAST, - Direction.WEST - }; - for (int i = directions.length - 1; i >= 0; i--) { - addRowOfButtons(directions[directions.length - i - 1], i); - } - } - - private void addRowOfButtons(Direction direction, int index) { - int refX = this.width - SCREEN_EDGE_PAD; - int refY = this.height - SCREEN_EDGE_PAD - MINI_BUTTON_HEIGHT - - index * (BETWEEN_PAD + MINI_BUTTON_HEIGHT); - - directionLabels.put(direction, - addLabel(LabelWidget.builder(this.mode.getDirectionText(direction), - refX - 3 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), - refY + MINI_BUTTON_HEIGHT / 2) - .justifiedRight() - .alignedMiddle() - .shiftForPadding() - .build())); - - moveButtons.add(addDrawableChild(new MoveButtonWidget( - refX - 3 * MINI_BUTTON_WIDTH - 2 * BETWEEN_PAD, - refY, - MINI_BUTTON_WIDTH, - MINI_BUTTON_HEIGHT, - direction, - 1, - this.mode, - this.units))); - - moveButtons.add(addDrawableChild(new MoveButtonWidget( - refX - 2 * MINI_BUTTON_WIDTH - BETWEEN_PAD, - refY, - MINI_BUTTON_WIDTH, - MINI_BUTTON_HEIGHT, - direction, - 2, - this.mode, - this.units))); - - moveButtons.add(addDrawableChild(new MoveButtonWidget(refX - MINI_BUTTON_WIDTH, - refY, - MINI_BUTTON_WIDTH, - MINI_BUTTON_HEIGHT, - direction, - 3, - this.mode, - this.units))); - } - - @Override - public void handledScreenTick() { - super.handledScreenTick(); - - playerPosLabel.setText(getCurrentPosText(client.player)); - playerBlockPosLabel.setText(getCurrentBlockPosText(client.player)); - standPosLabel.setText(getCurrentPosText(this.armorStand)); - standBlockPosLabel.setText(getCurrentBlockPosText(this.armorStand)); - - facingLabel.setText(getCurrentFacingText(this.mode.equals(MoveMode.LOCAL_TO_STAND) - ? this.armorStand - : client.player)); - } - - private Text getCurrentPosText(Entity entity) { - String xStr = String.format("%.2f", entity.getX()); - String yStr = String.format("%.2f", entity.getY()); - String zStr = String.format("%.2f", entity.getZ()); - return Text.translatable("armorstands.current.position", xStr, yStr, zStr); - } - - private Text getCurrentBlockPosText(Entity entity) { - BlockPos pos = entity.getBlockPos(); - return Text.translatable("armorstands.current.block", pos.getX(), pos.getY(), pos.getZ()); - } - - private Text getCurrentFacingText(Entity entity) { - float currentRotation = entity.getYaw(); - Direction currentFacing = Direction.fromRotation(currentRotation); - String towardsI18n = switch (currentFacing) { - case NORTH -> "negZ"; - case SOUTH -> "posZ"; - case WEST -> "negX"; - case EAST -> "posX"; - default -> "posX"; - }; - Text towards = Text.translatable("armorstands.current.facing." + towardsI18n); - return Text.translatable("armorstands.current.facing", currentFacing, towards.getString()); - } -} +package me.roundaround.armorstands.client.gui.screen; + +import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; +import me.roundaround.armorstands.client.gui.widget.LabelWidget; +import me.roundaround.armorstands.client.gui.widget.MoveButtonWidget; +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.network.ScreenType; +import me.roundaround.armorstands.network.UtilityAction; +import me.roundaround.armorstands.screen.ArmorStandScreenHandler; +import me.roundaround.armorstands.util.MoveMode; +import me.roundaround.armorstands.util.MoveUnits; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.CyclingButtonWidget; +import net.minecraft.entity.Entity; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +import java.util.ArrayList; +import java.util.HashMap; + +public class ArmorStandMoveScreen extends AbstractArmorStandScreen { + private static final int MINI_BUTTON_WIDTH = 28; + private static final int MINI_BUTTON_HEIGHT = 16; + private static final int BUTTON_WIDTH = 46; + private static final int BUTTON_HEIGHT = 16; + + private final HashMap directionLabels = new HashMap<>(); + private final ArrayList moveButtons = new ArrayList<>(); + + private LabelWidget playerPosLabel; + private LabelWidget playerBlockPosLabel; + private LabelWidget standPosLabel; + private LabelWidget standBlockPosLabel; + private LabelWidget facingLabel; + private CyclingButtonWidget unitsButton; + private MoveMode mode = MoveMode.RELATIVE; + private MoveUnits units = MoveUnits.PIXELS; + + public ArmorStandMoveScreen(ArmorStandScreenHandler handler) { + super(handler, ScreenType.MOVE.getDisplayName()); + this.supportsUndoRedo = true; + } + + @Override + public ScreenType getScreenType() { + return ScreenType.MOVE; + } + + @Override + protected void initStart() { + super.initStart(); + + directionLabels.clear(); + moveButtons.clear(); + } + + @Override + protected void initLeft() { + super.initLeft(); + + initCurrentStatus(); + initSnapButtons(); + } + + private void initCurrentStatus() { + addLabel(LabelWidget.builder(Text.translatable("armorstands.current.player"), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.playerPosLabel = addLabel(LabelWidget.builder(getCurrentPosText(client.player), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 2 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.playerBlockPosLabel = addLabel(LabelWidget.builder(getCurrentBlockPosText(client.player), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 3 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + addLabel(LabelWidget.builder(Text.translatable("armorstands.current.stand"), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 5 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.standPosLabel = addLabel(LabelWidget.builder(getCurrentPosText(this.armorStand), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 6 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.standBlockPosLabel = addLabel(LabelWidget.builder(getCurrentBlockPosText(this.armorStand), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 7 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + } + + private void initSnapButtons() { + addLabel(LabelWidget.builder(Text.translatable("armorstands.move.snap"), SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 2 * (BUTTON_HEIGHT + BETWEEN_PAD) + ).shiftForPadding().justifiedLeft().alignedBottom().build()); + + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.standing"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.SNAP_STANDING) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.sitting"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.SNAP_SITTING) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, + this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD + ) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.corner"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.SNAP_CORNER) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.center"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.SNAP_CENTER) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.move.snap.player"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.SNAP_PLAYER) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + 2 * (BUTTON_WIDTH + BETWEEN_PAD), this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + } + + @Override + protected void initRight() { + super.initRight(); + + int topOfMoveButtons = this.height - SCREEN_EDGE_PAD - 6 * MINI_BUTTON_HEIGHT - 5 * BETWEEN_PAD; + + addDrawableChild(CyclingButtonWidget.builder(MoveMode::getOptionValueText) + .values(MoveMode.values()) + .initially(this.mode) + .build(this.width - SCREEN_EDGE_PAD - 120, + topOfMoveButtons - LabelWidget.HEIGHT_WITH_PADDING - 3 * BETWEEN_PAD - 2 * MINI_BUTTON_HEIGHT, 120, + MINI_BUTTON_HEIGHT, MoveMode.getOptionLabelText(), (button, mode) -> { + this.mode = mode; + this.units = this.mode.getDefaultUnits(); + + this.facingLabel.setText( + getCurrentFacingText(this.mode.equals(MoveMode.LOCAL_TO_STAND) ? this.armorStand : client.player)); + this.directionLabels.forEach((direction, label) -> { + label.setText(this.mode.getDirectionText(direction)); + }); + + this.unitsButton.setValue(this.units); + this.moveButtons.forEach((moveButton) -> { + moveButton.setUnits(this.units); + }); + } + )); + + this.unitsButton = addDrawableChild(CyclingButtonWidget.builder(MoveUnits::getOptionValueText) + .values(MoveUnits.values()) + .initially(this.units) + .build(this.width - SCREEN_EDGE_PAD - 120, + topOfMoveButtons - LabelWidget.HEIGHT_WITH_PADDING - 2 * BETWEEN_PAD - MINI_BUTTON_HEIGHT, 120, + MINI_BUTTON_HEIGHT, MoveUnits.getOptionLabelText(), (button, units) -> { + this.units = units; + this.moveButtons.forEach((moveButton) -> { + moveButton.setUnits(this.units); + }); + } + )); + + this.facingLabel = addLabel(LabelWidget.builder( + getCurrentFacingText(this.mode.equals(MoveMode.LOCAL_TO_STAND) ? this.armorStand : this.client.player), + this.width - SCREEN_EDGE_PAD, topOfMoveButtons - BETWEEN_PAD + ).shiftForPadding().alignedBottom().justifiedRight().build()); + + Direction[] directions = new Direction[]{ + Direction.UP, Direction.DOWN, Direction.SOUTH, Direction.NORTH, Direction.EAST, Direction.WEST + }; + for (int i = directions.length - 1; i >= 0; i--) { + addRowOfButtons(directions[directions.length - i - 1], i); + } + } + + private void addRowOfButtons(Direction direction, int index) { + int refX = this.width - SCREEN_EDGE_PAD; + int refY = this.height - SCREEN_EDGE_PAD - MINI_BUTTON_HEIGHT - index * (BETWEEN_PAD + MINI_BUTTON_HEIGHT); + + directionLabels.put(direction, addLabel( + LabelWidget.builder(this.mode.getDirectionText(direction), refX - 3 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), + refY + MINI_BUTTON_HEIGHT / 2 + ).justifiedRight().alignedMiddle().shiftForPadding().build())); + + moveButtons.add(addDrawableChild( + new MoveButtonWidget(refX - 3 * MINI_BUTTON_WIDTH - 2 * BETWEEN_PAD, refY, MINI_BUTTON_WIDTH, + MINI_BUTTON_HEIGHT, direction, 1, this.mode, this.units + ))); + + moveButtons.add(addDrawableChild( + new MoveButtonWidget(refX - 2 * MINI_BUTTON_WIDTH - BETWEEN_PAD, refY, MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT, + direction, 2, this.mode, this.units + ))); + + moveButtons.add(addDrawableChild( + new MoveButtonWidget(refX - MINI_BUTTON_WIDTH, refY, MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT, direction, 3, + this.mode, this.units + ))); + } + + @Override + public void handledScreenTick() { + super.handledScreenTick(); + + this.playerPosLabel.setText(getCurrentPosText(this.client.player)); + this.playerBlockPosLabel.setText(getCurrentBlockPosText(this.client.player)); + this.standPosLabel.setText(getCurrentPosText(this.armorStand)); + this.standBlockPosLabel.setText(getCurrentBlockPosText(this.armorStand)); + + this.facingLabel.setText( + getCurrentFacingText(this.mode.equals(MoveMode.LOCAL_TO_STAND) ? this.armorStand : this.client.player)); + } + + private Text getCurrentPosText(Entity entity) { + String xStr = String.format("%.2f", entity.getX()); + String yStr = String.format("%.2f", entity.getY()); + String zStr = String.format("%.2f", entity.getZ()); + return Text.translatable("armorstands.current.position", xStr, yStr, zStr); + } + + private Text getCurrentBlockPosText(Entity entity) { + BlockPos pos = entity.getBlockPos(); + return Text.translatable("armorstands.current.block", pos.getX(), pos.getY(), pos.getZ()); + } + + private Text getCurrentFacingText(Entity entity) { + float currentRotation = entity.getYaw(); + Direction currentFacing = Direction.fromRotation(currentRotation); + String towardsI18n = switch (currentFacing) { + case NORTH -> "negZ"; + case SOUTH -> "posZ"; + case WEST -> "negX"; + default -> "posX"; + }; + Text towards = Text.translatable("armorstands.current.facing." + towardsI18n); + return Text.translatable("armorstands.current.facing", currentFacing.toString(), towards.getString()); + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandPoseScreen.java b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandPoseScreen.java index 9db6fb2..688184f 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandPoseScreen.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandPoseScreen.java @@ -1,327 +1,297 @@ -package me.roundaround.armorstands.client.gui.screen; - -import com.mojang.blaze3d.systems.RenderSystem; -import me.roundaround.armorstands.client.gui.widget.AdjustPoseSliderWidget; -import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; -import me.roundaround.armorstands.client.gui.widget.LabelWidget; -import me.roundaround.armorstands.network.EulerAngleParameter; -import me.roundaround.armorstands.network.PosePart; -import me.roundaround.armorstands.network.ScreenType; -import me.roundaround.armorstands.network.packet.c2s.SetPosePacket; -import me.roundaround.armorstands.screen.ArmorStandScreenHandler; -import me.roundaround.armorstands.util.Pose; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.CyclingButtonWidget; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.text.Text; - -public class ArmorStandPoseScreen extends AbstractArmorStandScreen { - private static final int CONTROL_WIDTH = 100; - private static final int SLIDER_HEIGHT = 16; - private static final int BUTTON_HEIGHT = 16; - private static final int BUTTON_WIDTH = 16; - private static final int ROW_PAD = 6; - private static final int PART_PAD_VERTICAL = 10; - private static final int PART_PAD_HORIZONTAL = 4; - - private PosePart posePart = PosePart.HEAD; - private IconButtonWidget activePosePartButton; - - private LabelWidget posePartLabel; - private AdjustPoseSliderWidget pitchSlider; - private AdjustPoseSliderWidget yawSlider; - private AdjustPoseSliderWidget rollSlider; - - public ArmorStandPoseScreen(ArmorStandScreenHandler handler) { - super(handler, ScreenType.POSE.getDisplayName()); - this.supportsUndoRedo = true; - } - - public void onArmorStandPoseChanged(ArmorStandEntity armorStand, PosePart part) { - if (this.pitchSlider == null || this.yawSlider == null || this.rollSlider == null) { - return; - } - - if (armorStand.getId() != this.armorStand.getId() || part != this.posePart) { - return; - } - - this.pitchSlider.refresh(); - this.yawSlider.refresh(); - this.rollSlider.refresh(); - } - - @Override - public ScreenType getScreenType() { - return ScreenType.POSE; - } - - @Override - protected void initLeft() { - super.initLeft(); - - int offset = (CONTROL_WIDTH - 3 * IconButtonWidget.WIDTH - 2 * PART_PAD_HORIZONTAL) / 2; - - IconButtonWidget headButton = new IconButtonWidget( - offset + SCREEN_EDGE_PAD + IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL, - this.height - SCREEN_EDGE_PAD - 3 * IconButtonWidget.HEIGHT - 2 * PART_PAD_VERTICAL - - PART_PAD_VERTICAL - BUTTON_HEIGHT, - 6, - PosePart.HEAD.getDisplayName(), - (button) -> { - setActivePosePart(PosePart.HEAD); - this.activePosePartButton.active = true; - this.activePosePartButton = (IconButtonWidget) button; - this.activePosePartButton.active = false; - }); - headButton.active = false; - this.activePosePartButton = headButton; - addDrawableChild(headButton); - - IconButtonWidget rightArmButton = new IconButtonWidget(offset + SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 2 * IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - - PART_PAD_VERTICAL - BUTTON_HEIGHT, - 8, - PosePart.RIGHT_ARM.getDisplayName(), - (button) -> { - setActivePosePart(PosePart.RIGHT_ARM); - this.activePosePartButton.active = true; - this.activePosePartButton = (IconButtonWidget) button; - this.activePosePartButton.active = false; - }); - addDrawableChild(rightArmButton); - - IconButtonWidget bodyButton = new IconButtonWidget( - offset + SCREEN_EDGE_PAD + IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL, - this.height - SCREEN_EDGE_PAD - 2 * IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - - PART_PAD_VERTICAL - BUTTON_HEIGHT, - 7, - PosePart.BODY.getDisplayName(), - (button) -> { - setActivePosePart(PosePart.BODY); - this.activePosePartButton.active = true; - this.activePosePartButton = (IconButtonWidget) button; - this.activePosePartButton.active = false; - }); - addDrawableChild(bodyButton); - - IconButtonWidget leftArmButton = new IconButtonWidget( - offset + SCREEN_EDGE_PAD + 2 * IconButtonWidget.WIDTH + 2 * PART_PAD_HORIZONTAL, - this.height - SCREEN_EDGE_PAD - 2 * IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - - PART_PAD_VERTICAL - BUTTON_HEIGHT, - 9, - PosePart.LEFT_ARM.getDisplayName(), - (button) -> { - setActivePosePart(PosePart.LEFT_ARM); - this.activePosePartButton.active = true; - this.activePosePartButton = (IconButtonWidget) button; - this.activePosePartButton.active = false; - }); - addDrawableChild(leftArmButton); - - IconButtonWidget rightLegButton = new IconButtonWidget( - offset + SCREEN_EDGE_PAD + (IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL) / 2, - this.height - SCREEN_EDGE_PAD - IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - BUTTON_HEIGHT, - 11, - PosePart.RIGHT_LEG.getDisplayName(), - (button) -> { - setActivePosePart(PosePart.RIGHT_LEG); - this.activePosePartButton.active = true; - this.activePosePartButton = (IconButtonWidget) button; - this.activePosePartButton.active = false; - }); - addDrawableChild(rightLegButton); - - IconButtonWidget leftLegButton = new IconButtonWidget( - offset + SCREEN_EDGE_PAD + (IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL) / 2 + - IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL, - this.height - SCREEN_EDGE_PAD - IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - BUTTON_HEIGHT, - 10, - PosePart.LEFT_LEG.getDisplayName(), - (button) -> { - setActivePosePart(PosePart.LEFT_LEG); - this.activePosePartButton.active = true; - this.activePosePartButton = (IconButtonWidget) button; - this.activePosePartButton.active = false; - }); - addDrawableChild(leftLegButton); - - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.pose.mirror"), - (button) -> { - SetPosePacket.sendToServer(new Pose(this.armorStand).mirror()); - - this.pitchSlider.refresh(); - this.yawSlider.refresh(); - this.rollSlider.refresh(); - }) - .size(CONTROL_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - } - - @Override - protected void initRight() { - super.initRight(); - - addDrawableChild(CyclingButtonWidget.builder(SliderRange::getDisplayName) - .initially(SliderRange.FULL) - .values(SliderRange.values()) - .omitKeyText() - .build(this.width - SCREEN_EDGE_PAD - CONTROL_WIDTH, - this.height - SCREEN_EDGE_PAD - 3 * SLIDER_HEIGHT - 3 * BUTTON_HEIGHT - - 3 * BETWEEN_PAD - 3 * ROW_PAD - 2 * LabelWidget.HEIGHT_WITH_PADDING, - CONTROL_WIDTH, - BUTTON_HEIGHT, - Text.translatable("armorstands.pose.range"), - (button, value) -> { - this.pitchSlider.setRange(value.getMin(), value.getMax()); - this.yawSlider.setRange(value.getMin(), value.getMax()); - this.rollSlider.setRange(value.getMin(), value.getMax()); - })); - - this.posePartLabel = addLabel(LabelWidget.builder(Text.translatable("armorstands.pose.editing", - this.posePart.getDisplayName().getString()), - this.width - SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 3 * SLIDER_HEIGHT - 3 * BUTTON_HEIGHT - 4 * BETWEEN_PAD - - 3 * ROW_PAD - 2 * LabelWidget.HEIGHT_WITH_PADDING) - .shiftForPadding() - .alignedBottom() - .justifiedRight() - .build()); - - this.pitchSlider = addAdjustSlider(EulerAngleParameter.PITCH, 2); - this.yawSlider = addAdjustSlider(EulerAngleParameter.YAW, 1); - this.rollSlider = addAdjustSlider(EulerAngleParameter.ROLL, 0); - } - - private AdjustPoseSliderWidget addAdjustSlider(EulerAngleParameter parameter, int index) { - int refRight = this.width - SCREEN_EDGE_PAD; - int refLeft = refRight - CONTROL_WIDTH; - int refY = this.height - SCREEN_EDGE_PAD - SLIDER_HEIGHT - - index * (SLIDER_HEIGHT + BUTTON_HEIGHT + BETWEEN_PAD + ROW_PAD); - - AdjustPoseSliderWidget slider = new AdjustPoseSliderWidget(refLeft, - refY, - CONTROL_WIDTH, - SLIDER_HEIGHT, - this.posePart, - parameter, - this.armorStand); - - addLabel(LabelWidget.builder(parameter.getDisplayName(), refLeft, refY - BETWEEN_PAD) - .alignedBottom() - .justifiedLeft() - .shiftForPadding() - .build()); - addDrawableChild(ButtonWidget.builder(Text.literal("-"), (button) -> slider.decrement()) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(refRight - 3 * BUTTON_WIDTH - 2 * BETWEEN_PAD, refY - BETWEEN_PAD - BUTTON_HEIGHT) - .tooltip(Tooltip.of(Text.translatable("armorstands.pose.subtract"))) - .build()); - addDrawableChild(ButtonWidget.builder(Text.literal("+"), (button) -> slider.increment()) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(refRight - 2 * BUTTON_WIDTH - BETWEEN_PAD, refY - BETWEEN_PAD - BUTTON_HEIGHT) - .tooltip(Tooltip.of(Text.translatable("armorstands.pose.add"))) - .build()); - addDrawableChild(ButtonWidget.builder(Text.literal("0"), (button) -> slider.zero()) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(refRight - BUTTON_WIDTH, refY - BETWEEN_PAD - BUTTON_HEIGHT) - .tooltip(Tooltip.of(Text.translatable("armorstands.pose.zero"))) - .build()); - addDrawableChild(slider); - - return slider; - } - - @Override - public boolean mouseScrolled( - double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - if (this.pitchSlider != null && - this.pitchSlider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { - return true; - } - if (this.yawSlider != null && - this.yawSlider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { - return true; - } - if (this.rollSlider != null && - this.rollSlider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { - return true; - } - return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); - } - - @Override - protected void handledScreenTick() { - super.handledScreenTick(); - - this.pitchSlider.tick(); - this.yawSlider.tick(); - this.rollSlider.tick(); - } - - @Override - protected void renderActivePageButtonHighlight(DrawContext drawContext) { - super.renderActivePageButtonHighlight(drawContext); - - if (this.activePosePartButton == null) { - return; - } - - RenderSystem.setShaderColor(1f, 1f, 1f, 1f); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - - MatrixStack matrixStack = drawContext.getMatrices(); - matrixStack.push(); - matrixStack.translate(0, 0, 100); - drawContext.drawTexture(SELECTION_TEXTURE, - this.activePosePartButton.getX() - 2, - this.activePosePartButton.getY() - 2, - 0, - 0, - 24, - 24, - 24, - 24); - matrixStack.pop(); - } - - private void setActivePosePart(PosePart part) { - this.posePart = part; - this.pitchSlider.setPart(part); - this.yawSlider.setPart(part); - this.rollSlider.setPart(part); - this.posePartLabel.setText(Text.translatable("armorstands.pose.editing", - this.posePart.getDisplayName().getString())); - } - - private static enum SliderRange { - FULL(-180, 180), - HALF(-90, 90), - TIGHT(-35, 35); - - private final int min; - private final int max; - - private SliderRange(int min, int max) { - this.min = min; - this.max = max; - } - - public int getMin() { - return this.min; - } - - public int getMax() { - return this.max; - } - - public Text getDisplayName() { - return Text.translatable("armorstands.pose.range." + this.name().toLowerCase()); - } - } -} +package me.roundaround.armorstands.client.gui.screen; + +import com.mojang.blaze3d.systems.RenderSystem; +import me.roundaround.armorstands.client.gui.widget.AdjustPoseSliderWidget; +import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; +import me.roundaround.armorstands.client.gui.widget.LabelWidget; +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.network.EulerAngleParameter; +import me.roundaround.armorstands.network.PosePart; +import me.roundaround.armorstands.network.ScreenType; +import me.roundaround.armorstands.screen.ArmorStandScreenHandler; +import me.roundaround.armorstands.util.Pose; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.CyclingButtonWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.text.Text; + +public class ArmorStandPoseScreen extends AbstractArmorStandScreen { + private static final int CONTROL_WIDTH = 100; + private static final int SLIDER_HEIGHT = 16; + private static final int BUTTON_HEIGHT = 16; + private static final int BUTTON_WIDTH = 16; + private static final int ROW_PAD = 6; + private static final int PART_PAD_VERTICAL = 10; + private static final int PART_PAD_HORIZONTAL = 4; + + private PosePart posePart = PosePart.HEAD; + private IconButtonWidget activePosePartButton; + + private LabelWidget posePartLabel; + private AdjustPoseSliderWidget pitchSlider; + private AdjustPoseSliderWidget yawSlider; + private AdjustPoseSliderWidget rollSlider; + + public ArmorStandPoseScreen(ArmorStandScreenHandler handler) { + super(handler, ScreenType.POSE.getDisplayName()); + this.supportsUndoRedo = true; + } + + public void onArmorStandPoseChanged(ArmorStandEntity armorStand, PosePart part) { + if (this.pitchSlider == null || this.yawSlider == null || this.rollSlider == null) { + return; + } + + if (armorStand.getId() != this.armorStand.getId() || part != this.posePart) { + return; + } + + this.pitchSlider.refresh(); + this.yawSlider.refresh(); + this.rollSlider.refresh(); + } + + @Override + public ScreenType getScreenType() { + return ScreenType.POSE; + } + + @Override + protected void initLeft() { + super.initLeft(); + + int offset = (CONTROL_WIDTH - 3 * IconButtonWidget.WIDTH - 2 * PART_PAD_HORIZONTAL) / 2; + + IconButtonWidget headButton = new IconButtonWidget( + offset + SCREEN_EDGE_PAD + IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL, + this.height - SCREEN_EDGE_PAD - 3 * IconButtonWidget.HEIGHT - 2 * PART_PAD_VERTICAL - PART_PAD_VERTICAL - + BUTTON_HEIGHT, 6, PosePart.HEAD.getDisplayName(), (button) -> { + setActivePosePart(PosePart.HEAD); + this.activePosePartButton.active = true; + this.activePosePartButton = (IconButtonWidget) button; + this.activePosePartButton.active = false; + } + ); + headButton.active = false; + this.activePosePartButton = headButton; + addDrawableChild(headButton); + + IconButtonWidget rightArmButton = new IconButtonWidget(offset + SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 2 * IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - PART_PAD_VERTICAL - + BUTTON_HEIGHT, 8, PosePart.RIGHT_ARM.getDisplayName(), (button) -> { + setActivePosePart(PosePart.RIGHT_ARM); + this.activePosePartButton.active = true; + this.activePosePartButton = (IconButtonWidget) button; + this.activePosePartButton.active = false; + } + ); + addDrawableChild(rightArmButton); + + IconButtonWidget bodyButton = new IconButtonWidget( + offset + SCREEN_EDGE_PAD + IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL, + this.height - SCREEN_EDGE_PAD - 2 * IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - PART_PAD_VERTICAL - + BUTTON_HEIGHT, 7, PosePart.BODY.getDisplayName(), (button) -> { + setActivePosePart(PosePart.BODY); + this.activePosePartButton.active = true; + this.activePosePartButton = (IconButtonWidget) button; + this.activePosePartButton.active = false; + } + ); + addDrawableChild(bodyButton); + + IconButtonWidget leftArmButton = new IconButtonWidget( + offset + SCREEN_EDGE_PAD + 2 * IconButtonWidget.WIDTH + 2 * PART_PAD_HORIZONTAL, + this.height - SCREEN_EDGE_PAD - 2 * IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - PART_PAD_VERTICAL - + BUTTON_HEIGHT, 9, PosePart.LEFT_ARM.getDisplayName(), (button) -> { + setActivePosePart(PosePart.LEFT_ARM); + this.activePosePartButton.active = true; + this.activePosePartButton = (IconButtonWidget) button; + this.activePosePartButton.active = false; + } + ); + addDrawableChild(leftArmButton); + + IconButtonWidget rightLegButton = new IconButtonWidget( + offset + SCREEN_EDGE_PAD + (IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL) / 2, + this.height - SCREEN_EDGE_PAD - IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - BUTTON_HEIGHT, 11, + PosePart.RIGHT_LEG.getDisplayName(), (button) -> { + setActivePosePart(PosePart.RIGHT_LEG); + this.activePosePartButton.active = true; + this.activePosePartButton = (IconButtonWidget) button; + this.activePosePartButton.active = false; + } + ); + addDrawableChild(rightLegButton); + + IconButtonWidget leftLegButton = new IconButtonWidget( + offset + SCREEN_EDGE_PAD + (IconButtonWidget.WIDTH + PART_PAD_HORIZONTAL) / 2 + IconButtonWidget.WIDTH + + PART_PAD_HORIZONTAL, + this.height - SCREEN_EDGE_PAD - IconButtonWidget.HEIGHT - PART_PAD_VERTICAL - BUTTON_HEIGHT, 10, + PosePart.LEFT_LEG.getDisplayName(), (button) -> { + setActivePosePart(PosePart.LEFT_LEG); + this.activePosePartButton.active = true; + this.activePosePartButton = (IconButtonWidget) button; + this.activePosePartButton.active = false; + } + ); + addDrawableChild(leftLegButton); + + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.pose.mirror"), (button) -> { + ClientNetworking.sendSetPosePacket(new Pose(this.armorStand).mirror()); + + this.pitchSlider.refresh(); + this.yawSlider.refresh(); + this.rollSlider.refresh(); + }) + .size(CONTROL_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + } + + @Override + protected void initRight() { + super.initRight(); + + addDrawableChild(CyclingButtonWidget.builder(SliderRange::getDisplayName) + .initially(SliderRange.FULL) + .values(SliderRange.values()) + .omitKeyText() + .build(this.width - SCREEN_EDGE_PAD - CONTROL_WIDTH, + this.height - SCREEN_EDGE_PAD - 3 * SLIDER_HEIGHT - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD - 3 * ROW_PAD - + 2 * LabelWidget.HEIGHT_WITH_PADDING, CONTROL_WIDTH, BUTTON_HEIGHT, + Text.translatable("armorstands.pose.range"), (button, value) -> { + this.pitchSlider.setRange(value.getMin(), value.getMax()); + this.yawSlider.setRange(value.getMin(), value.getMax()); + this.rollSlider.setRange(value.getMin(), value.getMax()); + } + )); + + this.posePartLabel = addLabel( + LabelWidget.builder(Text.translatable("armorstands.pose.editing", this.posePart.getDisplayName().getString()), + this.width - SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 3 * SLIDER_HEIGHT - 3 * BUTTON_HEIGHT - 4 * BETWEEN_PAD - 3 * ROW_PAD - + 2 * LabelWidget.HEIGHT_WITH_PADDING + ).shiftForPadding().alignedBottom().justifiedRight().build()); + + this.pitchSlider = addAdjustSlider(EulerAngleParameter.PITCH, 2); + this.yawSlider = addAdjustSlider(EulerAngleParameter.YAW, 1); + this.rollSlider = addAdjustSlider(EulerAngleParameter.ROLL, 0); + } + + private AdjustPoseSliderWidget addAdjustSlider(EulerAngleParameter parameter, int index) { + int refRight = this.width - SCREEN_EDGE_PAD; + int refLeft = refRight - CONTROL_WIDTH; + int refY = + this.height - SCREEN_EDGE_PAD - SLIDER_HEIGHT - index * (SLIDER_HEIGHT + BUTTON_HEIGHT + BETWEEN_PAD + ROW_PAD); + + AdjustPoseSliderWidget slider = new AdjustPoseSliderWidget(refLeft, refY, CONTROL_WIDTH, SLIDER_HEIGHT, + this.posePart, parameter, this.armorStand + ); + + addLabel(LabelWidget.builder(parameter.getDisplayName(), refLeft, refY - BETWEEN_PAD) + .alignedBottom() + .justifiedLeft() + .shiftForPadding() + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal("-"), (button) -> slider.decrement()) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(refRight - 3 * BUTTON_WIDTH - 2 * BETWEEN_PAD, refY - BETWEEN_PAD - BUTTON_HEIGHT) + .tooltip(Tooltip.of(Text.translatable("armorstands.pose.subtract"))) + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal("+"), (button) -> slider.increment()) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(refRight - 2 * BUTTON_WIDTH - BETWEEN_PAD, refY - BETWEEN_PAD - BUTTON_HEIGHT) + .tooltip(Tooltip.of(Text.translatable("armorstands.pose.add"))) + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal("0"), (button) -> slider.zero()) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(refRight - BUTTON_WIDTH, refY - BETWEEN_PAD - BUTTON_HEIGHT) + .tooltip(Tooltip.of(Text.translatable("armorstands.pose.zero"))) + .build()); + addDrawableChild(slider); + + return slider; + } + + @Override + public boolean mouseScrolled( + double mouseX, double mouseY, double horizontalAmount, double verticalAmount + ) { + if (this.pitchSlider != null && this.pitchSlider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { + return true; + } + if (this.yawSlider != null && this.yawSlider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { + return true; + } + if (this.rollSlider != null && this.rollSlider.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { + return true; + } + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + + @Override + protected void handledScreenTick() { + super.handledScreenTick(); + + this.pitchSlider.tick(); + this.yawSlider.tick(); + this.rollSlider.tick(); + } + + @Override + protected void renderActivePageButtonHighlight(DrawContext drawContext) { + super.renderActivePageButtonHighlight(drawContext); + + if (this.activePosePartButton == null) { + return; + } + + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + MatrixStack matrixStack = drawContext.getMatrices(); + matrixStack.push(); + matrixStack.translate(0, 0, 100); + drawContext.drawTexture(SELECTION_TEXTURE, this.activePosePartButton.getX() - 2, + this.activePosePartButton.getY() - 2, 0, 0, 24, 24, 24, 24 + ); + matrixStack.pop(); + } + + private void setActivePosePart(PosePart part) { + this.posePart = part; + this.pitchSlider.setPart(part); + this.yawSlider.setPart(part); + this.rollSlider.setPart(part); + this.posePartLabel.setText( + Text.translatable("armorstands.pose.editing", this.posePart.getDisplayName().getString())); + } + + private static enum SliderRange { + FULL(-180, 180), HALF(-90, 90), TIGHT(-35, 35); + + private final int min; + private final int max; + + private SliderRange(int min, int max) { + this.min = min; + this.max = max; + } + + public int getMin() { + return this.min; + } + + public int getMax() { + return this.max; + } + + public Text getDisplayName() { + return Text.translatable("armorstands.pose.range." + this.name().toLowerCase()); + } + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandRotateScreen.java b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandRotateScreen.java index 345ea82..fe60761 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandRotateScreen.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandRotateScreen.java @@ -1,315 +1,272 @@ -package me.roundaround.armorstands.client.gui.screen; - -import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; -import me.roundaround.armorstands.client.gui.widget.LabelWidget; -import me.roundaround.armorstands.client.gui.widget.RotateSliderWidget; -import me.roundaround.armorstands.network.ScreenType; -import me.roundaround.armorstands.network.UtilityAction; -import me.roundaround.armorstands.network.packet.c2s.AdjustYawPacket; -import me.roundaround.armorstands.network.packet.c2s.SetYawPacket; -import me.roundaround.armorstands.network.packet.c2s.UtilityActionPacket; -import me.roundaround.armorstands.screen.ArmorStandScreenHandler; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.entity.Entity; -import net.minecraft.text.Text; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; - -import java.util.Locale; - -public class ArmorStandRotateScreen extends AbstractArmorStandScreen { - private static final int BUTTON_WIDTH = 46; - private static final int BUTTON_HEIGHT = 16; - private static final int DIRECTION_BUTTON_WIDTH = 70; - private static final int MINI_BUTTON_WIDTH = 24; - private static final int MINI_BUTTON_HEIGHT = 16; - private static final int SLIDER_WIDTH = 4 * MINI_BUTTON_WIDTH + 3 * BETWEEN_PAD; - private static final int SLIDER_HEIGHT = 16; - - private LabelWidget playerFacingLabel; - private LabelWidget playerRotationLabel; - private LabelWidget standFacingLabel; - private LabelWidget standRotationLabel; - private RotateSliderWidget rotateSlider; - - public ArmorStandRotateScreen(ArmorStandScreenHandler handler) { - super(handler, ScreenType.ROTATE.getDisplayName()); - this.supportsUndoRedo = true; - } - - @Override - public ScreenType getScreenType() { - return ScreenType.ROTATE; - } - - @Override - protected void initLeft() { - super.initLeft(); - - initCurrentStatus(); - initSnapButtons(); - initFaceButtons(); - } - - private void initCurrentStatus() { - addLabel(LabelWidget.builder(Text.translatable("armorstands.current.player"), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.playerFacingLabel = addLabel(LabelWidget.builder(getCurrentFacingText(client.player), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 2 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.playerRotationLabel = addLabel(LabelWidget.builder(getCurrentRotationText(client.player), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 3 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - addLabel(LabelWidget.builder(Text.translatable("armorstands.current.stand"), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 5 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.standFacingLabel = addLabel(LabelWidget.builder(getCurrentFacingText(this.armorStand), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 6 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - - this.standRotationLabel = addLabel(LabelWidget.builder(getCurrentRotationText(this.armorStand), - SCREEN_EDGE_PAD, - SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 7 * LabelWidget.HEIGHT_WITH_PADDING) - .alignedTop() - .justifiedLeft() - .shiftForPadding() - .build()); - } - - private void initSnapButtons() { - addLabel(LabelWidget.builder(Text.translatable("armorstands.rotate.snap"), - SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 4 * BETWEEN_PAD - - LabelWidget.HEIGHT_WITH_PADDING) - .shiftForPadding() - .justifiedLeft() - .alignedBottom() - .build()); - - addDrawableChild(ButtonWidget.builder(Text.translatable( - "armorstands.rotate.snap." + Direction.SOUTH.getName()), (button) -> { - SetYawPacket.sendToServer(MathHelper.wrapDegrees(Direction.SOUTH.asRotation())); - }) - .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD - - LabelWidget.HEIGHT_WITH_PADDING) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable( - "armorstands.rotate.snap." + Direction.NORTH.getName()), (button) -> { - SetYawPacket.sendToServer(MathHelper.wrapDegrees(Direction.NORTH.asRotation())); - }) - .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + DIRECTION_BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD - - LabelWidget.HEIGHT_WITH_PADDING) - .build()); - - addDrawableChild(ButtonWidget.builder(Text.translatable( - "armorstands.rotate.snap." + Direction.EAST.getName()), (button) -> { - SetYawPacket.sendToServer(MathHelper.wrapDegrees(Direction.EAST.asRotation())); - }) - .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - 2 * BETWEEN_PAD - - LabelWidget.HEIGHT_WITH_PADDING) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable( - "armorstands.rotate.snap." + Direction.WEST.getName()), (button) -> { - SetYawPacket.sendToServer(MathHelper.wrapDegrees(Direction.WEST.asRotation())); - }) - .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + DIRECTION_BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - 2 * BETWEEN_PAD - - LabelWidget.HEIGHT_WITH_PADDING) - .build()); - } - - private void initFaceButtons() { - addLabel(LabelWidget.builder(Text.translatable("armorstands.rotate.face"), - SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT - BETWEEN_PAD) - .shiftForPadding() - .justifiedLeft() - .alignedBottom() - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.face.toward"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.FACE_TOWARD); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.face.away"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.FACE_AWAY); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.face.with"), - (button) -> { - UtilityActionPacket.sendToServer(UtilityAction.FACE_WITH); - }) - .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + 2 * (BUTTON_WIDTH + BETWEEN_PAD), - this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) - .build()); - } - - @Override - protected void initRight() { - super.initRight(); - - addRowOfButtons(RotateDirection.CLOCKWISE, 1); - addRowOfButtons(RotateDirection.COUNTERCLOCKWISE, 0); - - this.rotateSlider = addDrawableChild(new RotateSliderWidget(this, - this.width - SCREEN_EDGE_PAD - SLIDER_WIDTH, - this.height - SCREEN_EDGE_PAD - SLIDER_HEIGHT, - SLIDER_WIDTH, - SLIDER_HEIGHT, - this.armorStand)); - } - - private void addRowOfButtons(RotateDirection direction, int index) { - int refX = this.width - SCREEN_EDGE_PAD - MINI_BUTTON_WIDTH; - int refY = - this.height - SCREEN_EDGE_PAD - SLIDER_HEIGHT - 2 * BETWEEN_PAD - MINI_BUTTON_HEIGHT - - index * (2 * BETWEEN_PAD + MINI_BUTTON_HEIGHT + LabelWidget.HEIGHT_WITH_PADDING); - String modifier = direction.equals(RotateDirection.CLOCKWISE) ? "+" : "-"; - - addLabel(LabelWidget.builder(direction.getLabel(), - this.width - SCREEN_EDGE_PAD, - refY - BETWEEN_PAD).justifiedRight().alignedBottom().shiftForPadding().build()); - addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "1"), (button) -> { - AdjustYawPacket.sendToServer(direction.offset() * 1); - }) - .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) - .position(refX - 3 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), refY) - .build()); - addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "5"), (button) -> { - AdjustYawPacket.sendToServer(direction.offset() * 5); - }) - .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) - .position(refX - 2 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), refY) - .build()); - addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "15"), (button) -> { - AdjustYawPacket.sendToServer(direction.offset() * 15); - }) - .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) - .position(refX - 1 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), refY) - .build()); - addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "45"), (button) -> { - AdjustYawPacket.sendToServer(direction.offset() * 45); - }).size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT).position(refX, refY).build()); - } - - @Override - public void handledScreenTick() { - super.handledScreenTick(); - - this.playerFacingLabel.setText(getCurrentFacingText(this.client.player)); - this.playerRotationLabel.setText(getCurrentRotationText(this.client.player)); - this.standFacingLabel.setText(getCurrentFacingText(this.armorStand)); - this.standRotationLabel.setText(getCurrentRotationText(this.armorStand)); - this.rotateSlider.tick(); - } - - @Override - public void updateYawOnClient(float yaw) { - if (this.rotateSlider != null && this.rotateSlider.isPending(this)) { - return; - } - - super.updateYawOnClient(yaw); - - if (this.rotateSlider != null) { - this.rotateSlider.setAngle(yaw); - } - } - - @Override - public void onPong() { - super.onPong(); - - if (this.rotateSlider != null) { - this.rotateSlider.onPong(); - } - } - - private Text getCurrentFacingText(Entity entity) { - float currentRotation = entity.getYaw(); - Direction currentFacing = Direction.fromRotation(currentRotation); - String towardsI18n = switch (currentFacing) { - case NORTH -> "negZ"; - case SOUTH -> "posZ"; - case WEST -> "negX"; - case EAST -> "posX"; - default -> "posX"; - }; - Text towards = Text.translatable("armorstands.current.facing." + towardsI18n); - return Text.translatable("armorstands.current.facing", currentFacing, towards.getString()); - } - - private Text getCurrentRotationText(Entity entity) { - float currentRotation = entity.getYaw(); - return Text.translatable("armorstands.current.rotation", - String.format(Locale.ROOT, "%.1f", Float.valueOf(MathHelper.wrapDegrees(currentRotation)))); - } - - public static enum RotateDirection { - CLOCKWISE(1, "armorstands.rotate.clockwise"), - COUNTERCLOCKWISE(-1, "armorstands.rotate.counter"); - - private final int offset; - private final Text label; - - private RotateDirection(int offset, String i18n) { - this.offset = offset; - label = Text.translatable(i18n); - } - - public int offset() { - return offset; - } - - public Text getLabel() { - return label; - } - - public String toString() { - return label.getString(); - } - - public RotateDirection getOpposite() { - return this == CLOCKWISE ? COUNTERCLOCKWISE : CLOCKWISE; - } - } -} +package me.roundaround.armorstands.client.gui.screen; + +import me.roundaround.armorstands.client.gui.widget.IconButtonWidget; +import me.roundaround.armorstands.client.gui.widget.LabelWidget; +import me.roundaround.armorstands.client.gui.widget.RotateSliderWidget; +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.network.ScreenType; +import me.roundaround.armorstands.network.UtilityAction; +import me.roundaround.armorstands.screen.ArmorStandScreenHandler; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.entity.Entity; +import net.minecraft.text.Text; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; + +import java.util.Locale; + +public class ArmorStandRotateScreen extends AbstractArmorStandScreen { + private static final int BUTTON_WIDTH = 46; + private static final int BUTTON_HEIGHT = 16; + private static final int DIRECTION_BUTTON_WIDTH = 70; + private static final int MINI_BUTTON_WIDTH = 24; + private static final int MINI_BUTTON_HEIGHT = 16; + private static final int SLIDER_WIDTH = 4 * MINI_BUTTON_WIDTH + 3 * BETWEEN_PAD; + private static final int SLIDER_HEIGHT = 16; + + private LabelWidget playerFacingLabel; + private LabelWidget playerRotationLabel; + private LabelWidget standFacingLabel; + private LabelWidget standRotationLabel; + private RotateSliderWidget rotateSlider; + + public ArmorStandRotateScreen(ArmorStandScreenHandler handler) { + super(handler, ScreenType.ROTATE.getDisplayName()); + this.supportsUndoRedo = true; + } + + @Override + public ScreenType getScreenType() { + return ScreenType.ROTATE; + } + + @Override + protected void initLeft() { + super.initLeft(); + + initCurrentStatus(); + initSnapButtons(); + initFaceButtons(); + } + + private void initCurrentStatus() { + addLabel(LabelWidget.builder(Text.translatable("armorstands.current.player"), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.playerFacingLabel = addLabel(LabelWidget.builder(getCurrentFacingText(this.client.player), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 2 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.playerRotationLabel = addLabel(LabelWidget.builder(getCurrentRotationText(this.client.player), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 3 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + addLabel(LabelWidget.builder(Text.translatable("armorstands.current.stand"), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 5 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.standFacingLabel = addLabel(LabelWidget.builder(getCurrentFacingText(this.armorStand), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 6 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + + this.standRotationLabel = addLabel(LabelWidget.builder(getCurrentRotationText(this.armorStand), SCREEN_EDGE_PAD, + SCREEN_EDGE_PAD + IconButtonWidget.HEIGHT + 7 * LabelWidget.HEIGHT_WITH_PADDING + ).alignedTop().justifiedLeft().shiftForPadding().build()); + } + + private void initSnapButtons() { + addLabel(LabelWidget.builder(Text.translatable("armorstands.rotate.snap"), SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 4 * BETWEEN_PAD - LabelWidget.HEIGHT_WITH_PADDING + ).shiftForPadding().justifiedLeft().alignedBottom().build()); + + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.snap." + Direction.SOUTH.getName()), + (button) -> ClientNetworking.sendSetYawPacket(MathHelper.wrapDegrees(Direction.SOUTH.asRotation())) + ) + .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD - LabelWidget.HEIGHT_WITH_PADDING + ) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.snap." + Direction.NORTH.getName()), + (button) -> ClientNetworking.sendSetYawPacket(MathHelper.wrapDegrees(Direction.NORTH.asRotation())) + ) + .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + DIRECTION_BUTTON_WIDTH + BETWEEN_PAD, + this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD - LabelWidget.HEIGHT_WITH_PADDING + ) + .build()); + + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.snap." + Direction.EAST.getName()), + (button) -> ClientNetworking.sendSetYawPacket(MathHelper.wrapDegrees(Direction.EAST.asRotation())) + ) + .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - 2 * BETWEEN_PAD - LabelWidget.HEIGHT_WITH_PADDING + ) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.snap." + Direction.WEST.getName()), + (button) -> ClientNetworking.sendSetYawPacket(MathHelper.wrapDegrees(Direction.WEST.asRotation())) + ) + .size(DIRECTION_BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + DIRECTION_BUTTON_WIDTH + BETWEEN_PAD, + this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - 2 * BETWEEN_PAD - LabelWidget.HEIGHT_WITH_PADDING + ) + .build()); + } + + private void initFaceButtons() { + addLabel(LabelWidget.builder(Text.translatable("armorstands.rotate.face"), SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT - BETWEEN_PAD + ).shiftForPadding().justifiedLeft().alignedBottom().build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.face.toward"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.FACE_TOWARD) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.face.away"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.FACE_AWAY) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.rotate.face.with"), + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.FACE_WITH) + ) + .size(BUTTON_WIDTH, BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + 2 * (BUTTON_WIDTH + BETWEEN_PAD), this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .build()); + } + + @Override + protected void initRight() { + super.initRight(); + + addRowOfButtons(RotateDirection.CLOCKWISE, 1); + addRowOfButtons(RotateDirection.COUNTERCLOCKWISE, 0); + + this.rotateSlider = addDrawableChild(new RotateSliderWidget(this, this.width - SCREEN_EDGE_PAD - SLIDER_WIDTH, + this.height - SCREEN_EDGE_PAD - SLIDER_HEIGHT, SLIDER_WIDTH, SLIDER_HEIGHT, this.armorStand + )); + } + + private void addRowOfButtons(RotateDirection direction, int index) { + int refX = this.width - SCREEN_EDGE_PAD - MINI_BUTTON_WIDTH; + int refY = this.height - SCREEN_EDGE_PAD - SLIDER_HEIGHT - 2 * BETWEEN_PAD - MINI_BUTTON_HEIGHT - + index * (2 * BETWEEN_PAD + MINI_BUTTON_HEIGHT + LabelWidget.HEIGHT_WITH_PADDING); + String modifier = direction.equals(RotateDirection.CLOCKWISE) ? "+" : "-"; + + addLabel(LabelWidget.builder(direction.getLabel(), this.width - SCREEN_EDGE_PAD, refY - BETWEEN_PAD) + .justifiedRight() + .alignedBottom() + .shiftForPadding() + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "1"), + (button) -> ClientNetworking.sendAdjustYawPacket(direction.offset()) + ) + .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) + .position(refX - 3 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), refY) + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "5"), + (button) -> ClientNetworking.sendAdjustYawPacket(direction.offset() * 5) + ) + .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) + .position(refX - 2 * (BETWEEN_PAD + MINI_BUTTON_WIDTH), refY) + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "15"), + (button) -> ClientNetworking.sendAdjustYawPacket(direction.offset() * 15) + ) + .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) + .position(refX - (BETWEEN_PAD + MINI_BUTTON_WIDTH), refY) + .build()); + addDrawableChild(ButtonWidget.builder(Text.literal(modifier + "45"), + (button) -> ClientNetworking.sendAdjustYawPacket(direction.offset() * 45) + ) + .size(MINI_BUTTON_WIDTH, MINI_BUTTON_HEIGHT) + .position(refX, refY) + .build()); + } + + @Override + public void handledScreenTick() { + super.handledScreenTick(); + + this.playerFacingLabel.setText(getCurrentFacingText(this.client.player)); + this.playerRotationLabel.setText(getCurrentRotationText(this.client.player)); + this.standFacingLabel.setText(getCurrentFacingText(this.armorStand)); + this.standRotationLabel.setText(getCurrentRotationText(this.armorStand)); + this.rotateSlider.tick(); + } + + @Override + public void updateYawOnClient(float yaw) { + if (this.rotateSlider != null && this.rotateSlider.isPending(this)) { + return; + } + + super.updateYawOnClient(yaw); + + if (this.rotateSlider != null) { + this.rotateSlider.setAngle(yaw); + } + } + + @Override + public void onPong() { + super.onPong(); + + if (this.rotateSlider != null) { + this.rotateSlider.onPong(); + } + } + + private Text getCurrentFacingText(Entity entity) { + float currentRotation = entity.getYaw(); + Direction currentFacing = Direction.fromRotation(currentRotation); + String towardsI18n = switch (currentFacing) { + case NORTH -> "negZ"; + case SOUTH -> "posZ"; + case WEST -> "negX"; + case EAST -> "posX"; + default -> "posX"; + }; + Text towards = Text.translatable("armorstands.current.facing." + towardsI18n); + return Text.translatable("armorstands.current.facing", currentFacing.toString(), towards.getString()); + } + + private Text getCurrentRotationText(Entity entity) { + float currentRotation = entity.getYaw(); + return Text.translatable("armorstands.current.rotation", + String.format(Locale.ROOT, "%.1f", MathHelper.wrapDegrees(currentRotation)) + ); + } + + public enum RotateDirection { + CLOCKWISE(1, "armorstands.rotate.clockwise"), COUNTERCLOCKWISE(-1, "armorstands.rotate.counter"); + + private final int offset; + private final Text label; + + RotateDirection(int offset, String i18n) { + this.offset = offset; + label = Text.translatable(i18n); + } + + public int offset() { + return offset; + } + + public Text getLabel() { + return label; + } + + public String toString() { + return label.getString(); + } + + public RotateDirection getOpposite() { + return this == CLOCKWISE ? COUNTERCLOCKWISE : CLOCKWISE; + } + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandUtilitiesScreen.java b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandUtilitiesScreen.java index 1c6a60e..68d7fa5 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandUtilitiesScreen.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/screen/ArmorStandUtilitiesScreen.java @@ -2,10 +2,10 @@ import me.roundaround.armorstands.client.gui.widget.FlagToggleWidget; import me.roundaround.armorstands.client.gui.widget.LabelWidget; +import me.roundaround.armorstands.client.network.ClientNetworking; import me.roundaround.armorstands.network.ArmorStandFlag; import me.roundaround.armorstands.network.ScreenType; import me.roundaround.armorstands.network.UtilityAction; -import me.roundaround.armorstands.network.packet.c2s.UtilityActionPacket; import me.roundaround.armorstands.screen.ArmorStandScreenHandler; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; @@ -45,55 +45,57 @@ protected void initStart() { protected void initLeft() { super.initLeft(); - addLabel(LabelWidget.builder(Text.translatable("armorstands.utility.setup"), - SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD) - .alignedBottom() - .justifiedLeft() - .shiftForPadding() - .build()); + addLabel(LabelWidget.builder(Text.translatable("armorstands.utility.setup"), SCREEN_EDGE_PAD, + this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 3 * BETWEEN_PAD + ).alignedBottom().justifiedLeft().shiftForPadding().build()); addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.utility.prepare"), - (button) -> UtilityActionPacket.sendToServer(UtilityAction.PREPARE)) + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.PREPARE) + ) .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD, - this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 2 * BETWEEN_PAD) + .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 2 * BETWEEN_PAD) .tooltip(Tooltip.of(Text.translatable("armorstands.utility.prepare.tooltip"))) .build()); addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.utility.toolRack"), - (button) -> UtilityActionPacket.sendToServer(UtilityAction.TOOL_RACK)) + (button) -> ClientNetworking.sendUtilityActionPacket(UtilityAction.TOOL_RACK) + ) .size(BUTTON_WIDTH, BUTTON_HEIGHT) .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 2 * BETWEEN_PAD) + this.height - SCREEN_EDGE_PAD - 3 * BUTTON_HEIGHT - 2 * BETWEEN_PAD + ) .tooltip(Tooltip.of(Text.translatable("armorstands.utility.toolRack.tooltip"))) .build()); addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.utility.uprightItem"), - (button) -> UtilityActionPacket.sendToServer(UtilityAction.UPRIGHT_ITEM.forSmall( - ArmorStandFlag.SMALL.getValue(armorStand)))) + (button) -> ClientNetworking.sendUtilityActionPacket( + UtilityAction.UPRIGHT_ITEM.forSmall(ArmorStandFlag.SMALL.getValue(armorStand))) + ) .size(BUTTON_WIDTH, BUTTON_HEIGHT) .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD) .tooltip(Tooltip.of(Text.translatable("armorstands.utility.uprightItem.tooltip"))) .build()); addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.utility.flatItem"), - (button) -> UtilityActionPacket.sendToServer(UtilityAction.FLAT_ITEM.forSmall(ArmorStandFlag.SMALL.getValue( - armorStand)))) + (button) -> ClientNetworking.sendUtilityActionPacket( + UtilityAction.FLAT_ITEM.forSmall(ArmorStandFlag.SMALL.getValue(armorStand))) + ) .size(BUTTON_WIDTH, BUTTON_HEIGHT) .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD) + this.height - SCREEN_EDGE_PAD - 2 * BUTTON_HEIGHT - BETWEEN_PAD + ) .tooltip(Tooltip.of(Text.translatable("armorstands.utility.flatItem.tooltip"))) .build()); addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.utility.block"), - (button) -> UtilityActionPacket.sendToServer(UtilityAction.BLOCK.forSmall(ArmorStandFlag.SMALL.getValue( - armorStand)))) + (button) -> ClientNetworking.sendUtilityActionPacket( + UtilityAction.BLOCK.forSmall(ArmorStandFlag.SMALL.getValue(armorStand))) + ) .size(BUTTON_WIDTH, BUTTON_HEIGHT) .position(SCREEN_EDGE_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) .tooltip(Tooltip.of(Text.translatable("armorstands.utility.block.tooltip"))) .build()); addDrawableChild(ButtonWidget.builder(Text.translatable("armorstands.utility.tool"), - (button) -> UtilityActionPacket.sendToServer(UtilityAction.TOOL.forSmall(ArmorStandFlag.SMALL.getValue( - armorStand)))) + (button) -> ClientNetworking.sendUtilityActionPacket( + UtilityAction.TOOL.forSmall(ArmorStandFlag.SMALL.getValue(armorStand))) + ) .size(BUTTON_WIDTH, BUTTON_HEIGHT) - .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, - this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) + .position(SCREEN_EDGE_PAD + BUTTON_WIDTH + BETWEEN_PAD, this.height - SCREEN_EDGE_PAD - BUTTON_HEIGHT) .tooltip(Tooltip.of(Text.translatable("armorstands.utility.tool.tooltip"))) .build()); } @@ -132,14 +134,9 @@ private void refreshFlags() { private void addFlagToggleWidget(ArmorStandFlag flag, int index) { int xPos = this.width - SCREEN_EDGE_PAD; - int yPos = - this.height - (index + 1) * (SCREEN_EDGE_PAD + FlagToggleWidget.WIDGET_HEIGHT); - - FlagToggleWidget widget = new FlagToggleWidget(this.textRenderer, - flag, - this.currentValues.get(flag), - xPos, - yPos); + int yPos = this.height - (index + 1) * (SCREEN_EDGE_PAD + FlagToggleWidget.WIDGET_HEIGHT); + + FlagToggleWidget widget = new FlagToggleWidget(this.textRenderer, flag, this.currentValues.get(flag), xPos, yPos); addDrawableChild(widget); listeners.put(flag, widget::setValue); diff --git a/src/main/java/me/roundaround/armorstands/client/gui/widget/AdjustPoseSliderWidget.java b/src/main/java/me/roundaround/armorstands/client/gui/widget/AdjustPoseSliderWidget.java index 4cc7760..02ab2b8 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/widget/AdjustPoseSliderWidget.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/widget/AdjustPoseSliderWidget.java @@ -1,181 +1,175 @@ -package me.roundaround.armorstands.client.gui.widget; - -import me.roundaround.armorstands.network.EulerAngleParameter; -import me.roundaround.armorstands.network.PosePart; -import me.roundaround.armorstands.network.packet.c2s.AdjustPosePacket; -import net.minecraft.client.gui.widget.SliderWidget; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.sound.SoundManager; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.sound.SoundEvents; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.glfw.GLFW; - -import java.util.Optional; - -public class AdjustPoseSliderWidget extends SliderWidget { - private final ArmorStandEntity armorStand; - - private PosePart part; - private EulerAngleParameter parameter; - private Optional lastAngle = Optional.empty(); - private int min = -180; - private int max = 180; - private Optional lastScroll = Optional.empty(); - - public AdjustPoseSliderWidget( - int x, - int y, - int width, - int height, - PosePart part, - EulerAngleParameter parameter, - ArmorStandEntity armorStand) { - super(x, y, width, height, Text.empty(), 0); - - this.part = part; - this.parameter = parameter; - this.armorStand = armorStand; - - refresh(); - } - - public void setPart(PosePart part) { - this.part = part; - refresh(); - } - - public void setParameter(EulerAngleParameter parameter) { - this.parameter = parameter; - refresh(); - } - - public void setRange(int min, int max) { - this.min = min; - this.max = max; - refresh(); - } - - public void refresh() { - float armorStandAngle = this.parameter.get(this.part.get(this.armorStand)); - if (this.lastAngle.isPresent() && - Math.abs(armorStandAngle - this.lastAngle.get()) < MathHelper.EPSILON) { - return; - } - - this.lastAngle = Optional.of(armorStandAngle); - setAngle(armorStandAngle); - } - - public void zero() { - setAngle(0); - persistValue(); - } - - public void increment() { - double up = Math.ceil(getAngle()); - if (up - getAngle() < MathHelper.EPSILON) { - up += 1; - } - setAngle((float) up); - persistValue(); - } - - public void decrement() { - double down = Math.floor(getAngle()); - if (getAngle() - down < MathHelper.EPSILON) { - down -= 1; - } - setAngle((float) down); - persistValue(); - } - - public void tick() { - this.lastScroll.ifPresent(lastScroll -> { - if (System.currentTimeMillis() - lastScroll > 500) { - this.lastScroll = Optional.empty(); - persistValue(); - } - }); - } - - @Override - protected void updateMessage() { - setMessage(Text.translatable("armorstands.adjustPose.label", - String.format("%.2f", getAngle()))); - } - - @Override - protected void applyValue() { - this.part.set(this.armorStand, this.parameter, getAngle()); - } - - @Override - public void onRelease(double mouseX, double mouseY) { - super.onRelease(mouseX, mouseY); - - persistValue(); - } - - @Override - public boolean mouseScrolled( - double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - if (isMouseOver(mouseX, mouseY)) { - setAngle(getAngle() + (float) verticalAmount); - applyValue(); - this.lastScroll = Optional.of(System.currentTimeMillis()); - return true; - } - - return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == GLFW.GLFW_KEY_LEFT) { - decrement(); - return true; - } else if (keyCode == GLFW.GLFW_KEY_RIGHT) { - increment(); - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public void playDownSound(SoundManager soundManager) { - soundManager.play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1)); - } - - private float getAngle() { - return valueToAngle(this.value, this.min, this.max); - } - - private void setAngle(float value) { - setValue(angleToValue(value, this.min, this.max)); - } - - private void setValue(double value) { - this.value = MathHelper.clamp(value, 0, 1); - updateMessage(); - } - - private static double angleToValue(float value, int min, int max) { - // Map angle (min-max) to value (0-1) - return (value - min) / (max - min); - } - - private static float valueToAngle(double value, int min, int max) { - // Map value (0-1) to angle (min-max) - return (float) (value * (max - min) + min); - } - - private void persistValue() { - // Cancel any pending scroll updates - this.lastScroll = Optional.empty(); - - AdjustPosePacket.sendToServer(this.part, this.parameter, getAngle()); - } -} +package me.roundaround.armorstands.client.gui.widget; + +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.network.EulerAngleParameter; +import me.roundaround.armorstands.network.PosePart; +import net.minecraft.client.gui.widget.SliderWidget; +import net.minecraft.client.sound.PositionedSoundInstance; +import net.minecraft.client.sound.SoundManager; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +import java.util.Optional; + +public class AdjustPoseSliderWidget extends SliderWidget { + private final ArmorStandEntity armorStand; + + private PosePart part; + private EulerAngleParameter parameter; + private Optional lastAngle = Optional.empty(); + private int min = -180; + private int max = 180; + private Optional lastScroll = Optional.empty(); + + public AdjustPoseSliderWidget( + int x, int y, int width, int height, PosePart part, EulerAngleParameter parameter, ArmorStandEntity armorStand + ) { + super(x, y, width, height, Text.empty(), 0); + + this.part = part; + this.parameter = parameter; + this.armorStand = armorStand; + + refresh(); + } + + public void setPart(PosePart part) { + this.part = part; + refresh(); + } + + public void setParameter(EulerAngleParameter parameter) { + this.parameter = parameter; + refresh(); + } + + public void setRange(int min, int max) { + this.min = min; + this.max = max; + refresh(); + } + + public void refresh() { + float armorStandAngle = this.parameter.get(this.part.get(this.armorStand)); + if (this.lastAngle.isPresent() && Math.abs(armorStandAngle - this.lastAngle.get()) < MathHelper.EPSILON) { + return; + } + + this.lastAngle = Optional.of(armorStandAngle); + setAngle(armorStandAngle); + } + + public void zero() { + setAngle(0); + persistValue(); + } + + public void increment() { + double up = Math.ceil(getAngle()); + if (up - getAngle() < MathHelper.EPSILON) { + up += 1; + } + setAngle((float) up); + persistValue(); + } + + public void decrement() { + double down = Math.floor(getAngle()); + if (getAngle() - down < MathHelper.EPSILON) { + down -= 1; + } + setAngle((float) down); + persistValue(); + } + + public void tick() { + this.lastScroll.ifPresent(lastScroll -> { + if (System.currentTimeMillis() - lastScroll > 500) { + this.lastScroll = Optional.empty(); + persistValue(); + } + }); + } + + @Override + protected void updateMessage() { + setMessage(Text.translatable("armorstands.adjustPose.label", String.format("%.2f", getAngle()))); + } + + @Override + protected void applyValue() { + this.part.set(this.armorStand, this.parameter, getAngle()); + } + + @Override + public void onRelease(double mouseX, double mouseY) { + super.onRelease(mouseX, mouseY); + + persistValue(); + } + + @Override + public boolean mouseScrolled( + double mouseX, double mouseY, double horizontalAmount, double verticalAmount + ) { + if (isMouseOver(mouseX, mouseY)) { + setAngle(getAngle() + (float) verticalAmount); + applyValue(); + this.lastScroll = Optional.of(System.currentTimeMillis()); + return true; + } + + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == GLFW.GLFW_KEY_LEFT) { + decrement(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_RIGHT) { + increment(); + return true; + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public void playDownSound(SoundManager soundManager) { + soundManager.play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1)); + } + + private float getAngle() { + return valueToAngle(this.value, this.min, this.max); + } + + private void setAngle(float value) { + setValue(angleToValue(value, this.min, this.max)); + } + + private void setValue(double value) { + this.value = MathHelper.clamp(value, 0, 1); + updateMessage(); + } + + private static double angleToValue(float value, int min, int max) { + // Map angle (min-max) to value (0-1) + return (value - min) / (max - min); + } + + private static float valueToAngle(double value, int min, int max) { + // Map value (0-1) to angle (min-max) + return (float) (value * (max - min) + min); + } + + private void persistValue() { + // Cancel any pending scroll updates + this.lastScroll = Optional.empty(); + + ClientNetworking.sendAdjustPosePacket(this.part, this.parameter, getAngle()); + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/widget/FlagToggleWidget.java b/src/main/java/me/roundaround/armorstands/client/gui/widget/FlagToggleWidget.java index 81618fd..65a1e58 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/widget/FlagToggleWidget.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/widget/FlagToggleWidget.java @@ -1,8 +1,8 @@ package me.roundaround.armorstands.client.gui.widget; import com.mojang.blaze3d.systems.RenderSystem; +import me.roundaround.armorstands.client.network.ClientNetworking; import me.roundaround.armorstands.network.ArmorStandFlag; -import me.roundaround.armorstands.network.packet.c2s.SetFlagPacket; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; @@ -16,8 +16,7 @@ public class FlagToggleWidget extends PressableWidget { private static final int BAR_WIDTH = 10; private static final Identifier TEXTURE = new Identifier("widget/slider"); private static final Identifier HANDLE_TEXTURE = new Identifier("widget/slider_handle"); - private static final Identifier HANDLE_HIGHLIGHTED_TEXTURE = - new Identifier("widget/slider_handle_highlighted"); + private static final Identifier HANDLE_HIGHLIGHTED_TEXTURE = new Identifier("widget/slider_handle_highlighted"); private final ArmorStandFlag flag; private final boolean inverted; @@ -28,23 +27,29 @@ public class FlagToggleWidget extends PressableWidget { private boolean currentValue = false; public FlagToggleWidget( - TextRenderer textRenderer, ArmorStandFlag flag, boolean initialValue, int x, int y) { + TextRenderer textRenderer, ArmorStandFlag flag, boolean initialValue, int x, int y + ) { super(x, y, 100, WIDGET_HEIGHT, flag.getDisplayName()); this.flag = flag; this.inverted = flag.invertControl(); int valueLabelWidth = 2 * LabelWidget.PADDING + Math.max(textRenderer.getWidth(Text.translatable("armorstands.flagToggle.on")), - textRenderer.getWidth(Text.translatable("armorstands.flagToggle.off"))); - - this.flagLabel = LabelWidget.builder(flag.getDisplayName(), - x - WIDGET_WIDTH - 2 - valueLabelWidth - 2, - y + height / 2).justifiedRight().alignedMiddle().shiftForPadding().build(); - - this.valueLabel = LabelWidget.builder(Text.translatable( - "armorstands.flagToggle." + (initialValue ^ inverted ? "on" : "off")), - x - valueLabelWidth / 2, - y + height / 2).justifiedCenter().alignedMiddle().shiftForPadding().build(); + textRenderer.getWidth(Text.translatable("armorstands.flagToggle.off")) + ); + + this.flagLabel = LabelWidget.builder(flag.getDisplayName(), x - WIDGET_WIDTH - 2 - valueLabelWidth - 2, + y + height / 2 + ) + .justifiedRight() + .alignedMiddle() + .shiftForPadding() + .build(); + + this.valueLabel = LabelWidget.builder( + Text.translatable("armorstands.flagToggle." + (initialValue ^ inverted ? "on" : "off")), + x - valueLabelWidth / 2, y + height / 2 + ).justifiedCenter().alignedMiddle().shiftForPadding().build(); currentValue = initialValue; @@ -54,7 +59,7 @@ public FlagToggleWidget( @Override public void onPress() { - SetFlagPacket.sendToServer(flag, !currentValue); + ClientNetworking.sendSetFlagPacket(flag, !currentValue); } @Override @@ -82,8 +87,7 @@ public void renderWidget(DrawContext drawContext, int mouseX, int mouseY, float public void setValue(boolean newValue) { currentValue = newValue; - valueLabel.setText(Text.translatable( - "armorstands.flagToggle." + (newValue ^ inverted ? "on" : "off"))); + valueLabel.setText(Text.translatable("armorstands.flagToggle." + (newValue ^ inverted ? "on" : "off"))); } private void renderControl(DrawContext drawContext, int mouseX, int mouseY, float delta) { @@ -95,11 +99,7 @@ private void renderControl(DrawContext drawContext, int mouseX, int mouseY, floa RenderSystem.enableDepthTest(); drawContext.drawGuiTexture(TEXTURE, widgetX, widgetY, WIDGET_WIDTH, WIDGET_HEIGHT); - drawContext.drawGuiTexture(getHandleTexture(), - widgetX + offset, - widgetY, - BAR_WIDTH, - WIDGET_HEIGHT); + drawContext.drawGuiTexture(getHandleTexture(), widgetX + offset, widgetY, BAR_WIDTH, WIDGET_HEIGHT); } private boolean isWithinBounds(double mouseX, double mouseY) { diff --git a/src/main/java/me/roundaround/armorstands/client/gui/widget/MoveButtonWidget.java b/src/main/java/me/roundaround/armorstands/client/gui/widget/MoveButtonWidget.java index 9b0303d..06a35a0 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/widget/MoveButtonWidget.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/widget/MoveButtonWidget.java @@ -1,6 +1,6 @@ package me.roundaround.armorstands.client.gui.widget; -import me.roundaround.armorstands.network.packet.c2s.AdjustPosPacket; +import me.roundaround.armorstands.client.network.ClientNetworking; import me.roundaround.armorstands.util.MoveMode; import me.roundaround.armorstands.util.MoveUnits; import net.minecraft.client.gui.widget.ButtonWidget; @@ -15,17 +15,11 @@ public class MoveButtonWidget extends ButtonWidget { private MoveUnits units = MoveUnits.PIXELS; public MoveButtonWidget( - int x, - int y, - int width, - int height, - Direction direction, - int amount, - MoveMode mode, - MoveUnits units) { + int x, int y, int width, int height, Direction direction, int amount, MoveMode mode, MoveUnits units + ) { super(x, y, width, height, getText(amount, units), (rawButton) -> { MoveButtonWidget button = (MoveButtonWidget) rawButton; - AdjustPosPacket.sendToServer(button.direction, button.amount, button.mode, button.units); + ClientNetworking.sendAdjustPosPacket(button.direction, button.amount, button.mode, button.units); }, ButtonWidget.DEFAULT_NARRATION_SUPPLIER); this.direction = direction; diff --git a/src/main/java/me/roundaround/armorstands/client/gui/widget/NavigationButtonWidget.java b/src/main/java/me/roundaround/armorstands/client/gui/widget/NavigationButtonWidget.java index 708245d..d695303 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/widget/NavigationButtonWidget.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/widget/NavigationButtonWidget.java @@ -1,39 +1,40 @@ -package me.roundaround.armorstands.client.gui.widget; - -import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; -import me.roundaround.armorstands.network.ScreenType; -import me.roundaround.armorstands.network.packet.c2s.RequestScreenPacket; - -public class NavigationButtonWidget extends IconButtonWidget { - private final ScreenType screenType; - private final boolean clickable; - - public NavigationButtonWidget( - AbstractArmorStandScreen parent, int x, int y, ScreenType screenType) { - super(x, y, screenType.getUIndex(), screenType.getDisplayName(), (button) -> { - if (parent.getScreenType() == screenType) { - return; - } - - RequestScreenPacket.sendToServer(parent.getArmorStand(), screenType); - }); - - this.screenType = screenType; - this.clickable = parent.getScreenType() != screenType; - this.active = clickable; - } - - public ScreenType getScreenType() { - return this.screenType; - } - - public boolean isMouseOverIgnoreState(double mouseX, double mouseY) { - return mouseX >= this.getX() && mouseY >= this.getY() && mouseX < (this.getX() + this.width) && - mouseY < (this.getY() + this.height); - } - - @Override - public boolean isHovered() { - return this.clickable && super.isHovered(); - } -} +package me.roundaround.armorstands.client.gui.widget; + +import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.network.ScreenType; + +public class NavigationButtonWidget extends IconButtonWidget { + private final ScreenType screenType; + private final boolean clickable; + + public NavigationButtonWidget( + AbstractArmorStandScreen parent, int x, int y, ScreenType screenType + ) { + super(x, y, screenType.getUIndex(), screenType.getDisplayName(), (button) -> { + if (parent.getScreenType() == screenType) { + return; + } + + ClientNetworking.sendRequestScreenPacket(parent.getArmorStand(), screenType); + }); + + this.screenType = screenType; + this.clickable = parent.getScreenType() != screenType; + this.active = clickable; + } + + public ScreenType getScreenType() { + return this.screenType; + } + + public boolean isMouseOverIgnoreState(double mouseX, double mouseY) { + return mouseX >= this.getX() && mouseY >= this.getY() && mouseX < (this.getX() + this.width) && + mouseY < (this.getY() + this.height); + } + + @Override + public boolean isHovered() { + return this.clickable && super.isHovered(); + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/widget/PresetPoseButtonWidget.java b/src/main/java/me/roundaround/armorstands/client/gui/widget/PresetPoseButtonWidget.java index 58a07a1..292777a 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/widget/PresetPoseButtonWidget.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/widget/PresetPoseButtonWidget.java @@ -1,39 +1,39 @@ -package me.roundaround.armorstands.client.gui.widget; - -import me.roundaround.armorstands.network.packet.c2s.SetPosePresetPacket; -import me.roundaround.armorstands.util.PosePreset; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; - -public class PresetPoseButtonWidget extends ButtonWidget { - private PosePreset pose = PosePreset.DEFAULT; - - public PresetPoseButtonWidget( - int x, int y, int width, int height) { - super(x, y, width, height, Text.empty(), (button) -> { - SetPosePresetPacket.sendToServer(((PresetPoseButtonWidget) button).getPose()); - }, ButtonWidget.DEFAULT_NARRATION_SUPPLIER); - - updateMessage(); - } - - public PosePreset getPose() { - return pose; - } - - public void setPose(PosePreset pose) { - this.pose = pose; - updateMessage(); - } - - private void updateMessage() { - MutableText category = - Text.translatable("armorstands.presets.category", pose.getCategory().getDisplayName()); - MutableText source = - Text.translatable("armorstands.presets.source", pose.getSource().getDisplayName()); - setTooltip(Tooltip.of(category.append(Text.literal("\n")).append(source))); - setMessage(this.pose.getDisplayName()); - } -} +package me.roundaround.armorstands.client.gui.widget; + +import me.roundaround.armorstands.client.network.ClientNetworking; +import me.roundaround.armorstands.util.PosePreset; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; + +public class PresetPoseButtonWidget extends ButtonWidget { + private PosePreset pose = PosePreset.DEFAULT; + + public PresetPoseButtonWidget( + int x, int y, int width, int height + ) { + super(x, y, width, height, Text.empty(), + (button) -> ClientNetworking.sendSetPosePresetPacket(((PresetPoseButtonWidget) button).getPose()), + ButtonWidget.DEFAULT_NARRATION_SUPPLIER + ); + + updateMessage(); + } + + public PosePreset getPose() { + return pose; + } + + public void setPose(PosePreset pose) { + this.pose = pose; + updateMessage(); + } + + private void updateMessage() { + MutableText category = Text.translatable("armorstands.presets.category", pose.getCategory().getDisplayName()); + MutableText source = Text.translatable("armorstands.presets.source", pose.getSource().getDisplayName()); + setTooltip(Tooltip.of(category.append(Text.literal("\n")).append(source))); + setMessage(this.pose.getDisplayName()); + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/gui/widget/RotateSliderWidget.java b/src/main/java/me/roundaround/armorstands/client/gui/widget/RotateSliderWidget.java index 145c07c..18e8351 100644 --- a/src/main/java/me/roundaround/armorstands/client/gui/widget/RotateSliderWidget.java +++ b/src/main/java/me/roundaround/armorstands/client/gui/widget/RotateSliderWidget.java @@ -1,198 +1,194 @@ -package me.roundaround.armorstands.client.gui.widget; - -import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; -import me.roundaround.armorstands.network.packet.c2s.SetYawPacket; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.SliderWidget; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.client.sound.SoundManager; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.sound.SoundEvents; -import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.glfw.GLFW; - -import java.util.Optional; - -public class RotateSliderWidget extends SliderWidget { - private final AbstractArmorStandScreen parent; - private final ArmorStandEntity armorStand; - - private Optional lastAngle = Optional.empty(); - private int min = -180; - private int max = 180; - private Optional lastScroll = Optional.empty(); - private boolean isDragging = false; - private boolean pendingDragPing = false; - - public RotateSliderWidget( - AbstractArmorStandScreen parent, - int x, - int y, - int width, - int height, - ArmorStandEntity armorStand) { - super(x, y, width, height, Text.empty(), 0); - - this.parent = parent; - this.armorStand = armorStand; - - refresh(); - } - - public boolean isPending(Screen parent) { - return isDragging() || this.lastScroll.isPresent(); - } - - public void setRange(int min, int max) { - this.min = min; - this.max = max; - refresh(); - } - - public void refresh() { - float armorStandAngle = this.armorStand.getYaw(); - if (this.lastAngle.isPresent() && - Math.abs(armorStandAngle - this.lastAngle.get()) < MathHelper.EPSILON) { - return; - } - - this.lastAngle = Optional.of(armorStandAngle); - setAngle(armorStandAngle); - } - - public void zero() { - setAngle(0); - persistValue(); - } - - public void increment() { - double up = Math.ceil(getAngle()); - if (up - getAngle() < MathHelper.EPSILON) { - up += 1; - } - setAngle((float) up); - persistValue(); - } - - public void decrement() { - double down = Math.floor(getAngle()); - if (getAngle() - down < MathHelper.EPSILON) { - down -= 1; - } - setAngle((float) down); - persistValue(); - } - - public void tick() { - this.lastScroll.ifPresent(lastScroll -> { - if (System.currentTimeMillis() - lastScroll > 500) { - this.lastScroll = Optional.empty(); - persistValue(); - } - }); - } - - public boolean isDragging() { - return this.isDragging || this.pendingDragPing; - } - - public void onPong() { - this.pendingDragPing = false; - } - - @Override - protected void updateMessage() { - setMessage(Text.translatable("armorstands.rotate.label", String.format("%.2f", getAngle()))); - } - - @Override - protected void applyValue() { - this.armorStand.setYaw(getAngle()); - } - - @Override - public void onClick(double mouseX, double mouseY) { - super.onClick(mouseX, mouseY); - - this.isDragging = true; - } - - @Override - public void onRelease(double mouseX, double mouseY) { - super.onRelease(mouseX, mouseY); - - this.isDragging = false; - this.pendingDragPing = true; - this.parent.sendPing(); - - persistValue(); - } - - @Override - public boolean mouseScrolled( - double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { - if (isMouseOver(mouseX, mouseY)) { - setAngle(getAngle() + (float) verticalAmount); - applyValue(); - this.lastScroll = Optional.of(System.currentTimeMillis()); - return true; - } - - return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == GLFW.GLFW_KEY_LEFT) { - decrement(); - return true; - } else if (keyCode == GLFW.GLFW_KEY_RIGHT) { - increment(); - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) { - this.isDragging = true; - super.onDrag(mouseX, mouseY, deltaX, deltaY); - } - - @Override - public void playDownSound(SoundManager soundManager) { - soundManager.play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1)); - } - - private float getAngle() { - return valueToAngle(this.value, this.min, this.max); - } - - public void setAngle(float value) { - setValue(angleToValue(value, this.min, this.max)); - } - - private void setValue(double value) { - this.value = MathHelper.clamp(value, 0, 1); - updateMessage(); - } - - private static double angleToValue(float value, int min, int max) { - // Map angle (min-max) to value (0-1) - return (value - min) / (max - min); - } - - private static float valueToAngle(double value, int min, int max) { - // Map value (0-1) to angle (min-max) - return (float) (value * (max - min) + min); - } - - private void persistValue() { - // Cancel any pending scroll updates - this.lastScroll = Optional.empty(); - - SetYawPacket.sendToServer(getAngle()); - } -} +package me.roundaround.armorstands.client.gui.widget; + +import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; +import me.roundaround.armorstands.client.network.ClientNetworking; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.SliderWidget; +import net.minecraft.client.sound.PositionedSoundInstance; +import net.minecraft.client.sound.SoundManager; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +import java.util.Optional; + +public class RotateSliderWidget extends SliderWidget { + private final AbstractArmorStandScreen parent; + private final ArmorStandEntity armorStand; + + private Optional lastAngle = Optional.empty(); + private int min = -180; + private int max = 180; + private Optional lastScroll = Optional.empty(); + private boolean isDragging = false; + private boolean pendingDragPing = false; + + public RotateSliderWidget( + AbstractArmorStandScreen parent, int x, int y, int width, int height, ArmorStandEntity armorStand + ) { + super(x, y, width, height, Text.empty(), 0); + + this.parent = parent; + this.armorStand = armorStand; + + refresh(); + } + + public boolean isPending(Screen parent) { + return isDragging() || this.lastScroll.isPresent(); + } + + public void setRange(int min, int max) { + this.min = min; + this.max = max; + refresh(); + } + + public void refresh() { + float armorStandAngle = this.armorStand.getYaw(); + if (this.lastAngle.isPresent() && Math.abs(armorStandAngle - this.lastAngle.get()) < MathHelper.EPSILON) { + return; + } + + this.lastAngle = Optional.of(armorStandAngle); + setAngle(armorStandAngle); + } + + public void zero() { + setAngle(0); + persistValue(); + } + + public void increment() { + double up = Math.ceil(getAngle()); + if (up - getAngle() < MathHelper.EPSILON) { + up += 1; + } + setAngle((float) up); + persistValue(); + } + + public void decrement() { + double down = Math.floor(getAngle()); + if (getAngle() - down < MathHelper.EPSILON) { + down -= 1; + } + setAngle((float) down); + persistValue(); + } + + public void tick() { + this.lastScroll.ifPresent(lastScroll -> { + if (System.currentTimeMillis() - lastScroll > 500) { + this.lastScroll = Optional.empty(); + persistValue(); + } + }); + } + + public boolean isDragging() { + return this.isDragging || this.pendingDragPing; + } + + public void onPong() { + this.pendingDragPing = false; + } + + @Override + protected void updateMessage() { + setMessage(Text.translatable("armorstands.rotate.label", String.format("%.2f", getAngle()))); + } + + @Override + protected void applyValue() { + this.armorStand.setYaw(getAngle()); + } + + @Override + public void onClick(double mouseX, double mouseY) { + super.onClick(mouseX, mouseY); + + this.isDragging = true; + } + + @Override + public void onRelease(double mouseX, double mouseY) { + super.onRelease(mouseX, mouseY); + + this.isDragging = false; + this.pendingDragPing = true; + this.parent.sendPing(); + + persistValue(); + } + + @Override + public boolean mouseScrolled( + double mouseX, double mouseY, double horizontalAmount, double verticalAmount + ) { + if (isMouseOver(mouseX, mouseY)) { + setAngle(getAngle() + (float) verticalAmount); + applyValue(); + this.lastScroll = Optional.of(System.currentTimeMillis()); + return true; + } + + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == GLFW.GLFW_KEY_LEFT) { + decrement(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_RIGHT) { + increment(); + return true; + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) { + this.isDragging = true; + super.onDrag(mouseX, mouseY, deltaX, deltaY); + } + + @Override + public void playDownSound(SoundManager soundManager) { + soundManager.play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1)); + } + + private float getAngle() { + return valueToAngle(this.value, this.min, this.max); + } + + public void setAngle(float value) { + setValue(angleToValue(value, this.min, this.max)); + } + + private void setValue(double value) { + this.value = MathHelper.clamp(value, 0, 1); + updateMessage(); + } + + private static double angleToValue(float value, int min, int max) { + // Map angle (min-max) to value (0-1) + return (value - min) / (max - min); + } + + private static float valueToAngle(double value, int min, int max) { + // Map value (0-1) to angle (min-max) + return (float) (value * (max - min) + min); + } + + private void persistValue() { + // Cancel any pending scroll updates + this.lastScroll = Optional.empty(); + + ClientNetworking.sendSetYawPacket(getAngle()); + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/network/ClientNetworking.java b/src/main/java/me/roundaround/armorstands/client/network/ClientNetworking.java new file mode 100644 index 0000000..e57c56d --- /dev/null +++ b/src/main/java/me/roundaround/armorstands/client/network/ClientNetworking.java @@ -0,0 +1,117 @@ +package me.roundaround.armorstands.client.network; + +import me.roundaround.armorstands.client.gui.MessageRenderer; +import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; +import me.roundaround.armorstands.network.*; +import me.roundaround.armorstands.util.*; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; + +public final class ClientNetworking { + private ClientNetworking() { + } + + public static void sendAdjustPosePacket(PosePart part, EulerAngleParameter parameter, float amount) { + ClientPlayNetworking.send(new Networking.AdjustPoseC2S(part, parameter, amount)); + } + + public static void sendAdjustPosPacket(Direction direction, int amount, MoveMode mode, MoveUnits units) { + ClientPlayNetworking.send(new Networking.AdjustPosC2S(direction, amount, mode, units)); + } + + public static void sendAdjustYawPacket(int amount) { + ClientPlayNetworking.send(new Networking.AdjustYawC2S(amount)); + } + + public static void sendPingPacket(ClientPlayerEntity player) { + if (ClientPlayNetworking.canSend(Networking.PingC2S.ID)) { + ClientPlayNetworking.send(new Networking.PingC2S(player.getUuid())); + } + } + + public static void sendRequestScreenPacket(ArmorStandEntity armorStand, ScreenType screenType) { + ClientPlayNetworking.send(new Networking.RequestScreenC2S(armorStand.getId(), screenType)); + } + + public static void sendSetFlagPacket(ArmorStandFlag flag, boolean value) { + ClientPlayNetworking.send(new Networking.SetFlagC2S(flag, value)); + } + + public static void sendSetPosePacket(SavedPose pose) { + sendSetPosePacket(pose.toPose()); + } + + public static void sendSetPosePacket(Pose pose) { + ClientPlayNetworking.send(new Networking.SetPoseC2S(pose)); + } + + public static void sendSetPosePresetPacket(PosePreset pose) { + ClientPlayNetworking.send(new Networking.SetPosePresetC2S(pose)); + } + + public static void sendSetYawPacket(float angle) { + ClientPlayNetworking.send(new Networking.SetYawC2S(angle)); + } + + public static void sendUndoPacket(boolean redo) { + if (ClientPlayNetworking.canSend(Networking.UndoC2S.ID)) { + ClientPlayNetworking.send(new Networking.UndoC2S(redo)); + } + } + + public static void sendUtilityActionPacket(UtilityAction action) { + ClientPlayNetworking.send(new Networking.UtilityActionC2S(action)); + } + + public static void registerReceivers() { + ClientPlayNetworking.registerGlobalReceiver(Networking.ClientUpdateS2C.ID, ClientNetworking::handleClientUpdate); + ClientPlayNetworking.registerGlobalReceiver(Networking.MessageS2C.ID, ClientNetworking::handleMessage); + ClientPlayNetworking.registerGlobalReceiver(Networking.PongS2C.ID, ClientNetworking::handlePong); + } + + private static void handleClientUpdate(Networking.ClientUpdateS2C payload, ClientPlayNetworking.Context context) { + context.client().execute(() -> { + Screen currentScreen = context.client().currentScreen; + if (!(currentScreen instanceof AbstractArmorStandScreen screen)) { + return; + } + + screen.updatePosOnClient(payload.x(), payload.y(), payload.z()); + screen.updateYawOnClient(MathHelper.wrapDegrees(payload.yawFloat())); + screen.updatePitchOnClient(MathHelper.wrapDegrees(payload.pitchFloat())); + screen.updateInvulnerableOnClient(payload.invulnerable()); + screen.updateDisabledSlotsOnClient(payload.disabledSlots()); + }); + } + + private static void handleMessage(Networking.MessageS2C payload, ClientPlayNetworking.Context context) { + context.client().execute(() -> { + Screen currentScreen = context.client().currentScreen; + if (!(currentScreen instanceof AbstractArmorStandScreen screen)) { + return; + } + + MessageRenderer messageRenderer = screen.getMessageRenderer(); + messageRenderer.addMessage( + payload.translatable() ? Text.translatable(payload.message()) : Text.literal(payload.message()), + payload.styled() ? payload.color() : MessageRenderer.BASE_COLOR + ); + }); + } + + private static void handlePong(Networking.PongS2C payload, ClientPlayNetworking.Context context) { + context.client().execute(() -> { + Screen currentScreen = context.client().currentScreen; + if (!(currentScreen instanceof AbstractArmorStandScreen screen)) { + return; + } + + screen.onPong(); + }); + } +} diff --git a/src/main/java/me/roundaround/armorstands/client/util/PoseStorage.java b/src/main/java/me/roundaround/armorstands/client/util/PoseStorage.java index 56c80f0..0c20b2a 100644 --- a/src/main/java/me/roundaround/armorstands/client/util/PoseStorage.java +++ b/src/main/java/me/roundaround/armorstands/client/util/PoseStorage.java @@ -1,102 +1,97 @@ -package me.roundaround.armorstands.client.util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import com.google.common.io.Files; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import me.roundaround.armorstands.util.Pose; -import me.roundaround.armorstands.util.SavedPose; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.util.JsonHelper; - -public class PoseStorage { - private static final File FILE = FabricLoader.getInstance().getGameDir().resolve("armorstandsposes.json").toFile(); - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - - private static HashMap map = new HashMap<>(); - - public static void add(String name, ArmorStandEntity armorStand) { - add(name, new Pose(armorStand)); - } - - public static void add(String name, Pose pose) { - UUID uuid = UUID.randomUUID(); - try { - map.put(uuid, new SavedPose(name, pose)); - save(); - } catch (IOException e) { - map.remove(uuid); - e.printStackTrace(); - } - } - - public static void rename(UUID uuid, String name) { - try { - SavedPose savedPose = map.get(uuid); - if (savedPose == null) { - return; - } - map.put(uuid, new SavedPose(name, savedPose.toPose())); - save(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void remove(UUID uuid) { - try { - map.remove(uuid); - save(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void reload() { - try { - load(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static Map getPoses() { - return Map.copyOf(map); - } - - private static void save() throws IOException { - JsonArray jsonArray = new JsonArray(); - map.values().stream().map(SavedPose::toJson).forEach(jsonArray::add); - try (BufferedWriter bufferedWriter = Files.newWriter(FILE, StandardCharsets.UTF_8);) { - GSON.toJson(jsonArray, bufferedWriter); - } - } - - private static void load() throws IOException { - if (!FILE.exists()) { - return; - } - try (BufferedReader bufferedReader = Files.newReader(FILE, StandardCharsets.UTF_8)) { - map.clear(); - - JsonArray jsonArray = GSON.fromJson(bufferedReader, JsonArray.class); - for (JsonElement jsonElement : jsonArray) { - JsonObject jsonObject = JsonHelper.asObject(jsonElement, "entry"); - map.put(UUID.randomUUID(), SavedPose.fromJson(jsonObject)); - } - } - } -} +package me.roundaround.armorstands.client.util; + +import com.google.common.io.Files; +import com.google.gson.*; +import me.roundaround.armorstands.ArmorStandsMod; +import me.roundaround.armorstands.util.Pose; +import me.roundaround.armorstands.util.SavedPose; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.util.JsonHelper; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PoseStorage { + private static final File FILE = FabricLoader.getInstance().getGameDir().resolve("armorstandsposes.json").toFile(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final HashMap map = new HashMap<>(); + + public static void add(String name, ArmorStandEntity armorStand) { + add(name, new Pose(armorStand)); + } + + public static void add(String name, Pose pose) { + UUID uuid = UUID.randomUUID(); + try { + map.put(uuid, new SavedPose(name, pose)); + save(); + } catch (IOException e) { + map.remove(uuid); + ArmorStandsMod.LOGGER.error(e); + } + } + + public static void rename(UUID uuid, String name) { + try { + SavedPose savedPose = map.get(uuid); + if (savedPose == null) { + return; + } + map.put(uuid, new SavedPose(name, savedPose.toPose())); + save(); + } catch (IOException e) { + ArmorStandsMod.LOGGER.error(e); + } + } + + public static void remove(UUID uuid) { + try { + map.remove(uuid); + save(); + } catch (IOException e) { + ArmorStandsMod.LOGGER.error(e); + } + } + + public static void reload() { + try { + load(); + } catch (IOException e) { + ArmorStandsMod.LOGGER.error(e); + } + } + + public static Map getPoses() { + return Map.copyOf(map); + } + + private static void save() throws IOException { + JsonArray jsonArray = new JsonArray(); + map.values().stream().map(SavedPose::toJson).forEach(jsonArray::add); + try (BufferedWriter bufferedWriter = Files.newWriter(FILE, StandardCharsets.UTF_8);) { + GSON.toJson(jsonArray, bufferedWriter); + } + } + + private static void load() throws IOException { + if (!FILE.exists()) { + return; + } + try (BufferedReader bufferedReader = Files.newReader(FILE, StandardCharsets.UTF_8)) { + map.clear(); + + JsonArray jsonArray = GSON.fromJson(bufferedReader, JsonArray.class); + for (JsonElement jsonElement : jsonArray) { + JsonObject jsonObject = JsonHelper.asObject(jsonElement, "entry"); + map.put(UUID.randomUUID(), SavedPose.fromJson(jsonObject)); + } + } + } +} diff --git a/src/main/java/me/roundaround/armorstands/mixin/InGameHudMixin.java b/src/main/java/me/roundaround/armorstands/mixin/InGameHudMixin.java index f7d5c4c..ac4ecd2 100644 --- a/src/main/java/me/roundaround/armorstands/mixin/InGameHudMixin.java +++ b/src/main/java/me/roundaround/armorstands/mixin/InGameHudMixin.java @@ -4,6 +4,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; +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; @@ -13,6 +14,7 @@ @Mixin(InGameHud.class) public abstract class InGameHudMixin { @Shadow + @Final private MinecraftClient client; @Inject(method = "render", at = @At(value = "HEAD"), cancellable = true) diff --git a/src/main/java/me/roundaround/armorstands/mixin/KeyBindingAccessor.java b/src/main/java/me/roundaround/armorstands/mixin/KeyBindingAccessor.java index f314a7f..9d7443f 100644 --- a/src/main/java/me/roundaround/armorstands/mixin/KeyBindingAccessor.java +++ b/src/main/java/me/roundaround/armorstands/mixin/KeyBindingAccessor.java @@ -1,12 +1,11 @@ package me.roundaround.armorstands.mixin; +import net.minecraft.client.option.KeyBinding; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -import net.minecraft.client.option.KeyBinding; - @Mixin(KeyBinding.class) public interface KeyBindingAccessor { @Invoker("reset") - public void invokeReset(); + void invokeReset(); } diff --git a/src/main/java/me/roundaround/armorstands/mixin/MouseMixin.java b/src/main/java/me/roundaround/armorstands/mixin/MouseMixin.java index ef2c69b..1901629 100644 --- a/src/main/java/me/roundaround/armorstands/mixin/MouseMixin.java +++ b/src/main/java/me/roundaround/armorstands/mixin/MouseMixin.java @@ -1,41 +1,39 @@ -package me.roundaround.armorstands.mixin; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; -import me.roundaround.armorstands.client.gui.screen.PassesEventsThrough; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.Mouse; -import net.minecraft.client.gui.screen.Screen; -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; - -@Mixin(Mouse.class) -public abstract class MouseMixin { - @Shadow - private MinecraftClient client; - - @Inject(method = "isCursorLocked", at = @At(value = "HEAD"), cancellable = true) - public void isCursorLocked(CallbackInfoReturnable info) { - if (client.currentScreen instanceof AbstractArmorStandScreen) { - info.setReturnValue(((AbstractArmorStandScreen) client.currentScreen).isCursorLocked()); - } - } - - @ModifyExpressionValue( - method = "onMouseButton", - at = @At( - value = "FIELD", - target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", - ordinal = 3 - ) - ) - private Screen modifyCurrentScreen(Screen screen) { - return - screen instanceof PassesEventsThrough && ((PassesEventsThrough) screen).shouldPassEvents() - ? null - : screen; - } -} +package me.roundaround.armorstands.mixin; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; +import me.roundaround.armorstands.client.gui.screen.PassesEventsThrough; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Mouse; +import net.minecraft.client.gui.screen.Screen; +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; + +@Mixin(Mouse.class) +public abstract class MouseMixin { + @Shadow + @Final + private MinecraftClient client; + + @Inject(method = "isCursorLocked", at = @At(value = "HEAD"), cancellable = true) + public void isCursorLocked(CallbackInfoReturnable info) { + if (client.currentScreen instanceof AbstractArmorStandScreen) { + info.setReturnValue(((AbstractArmorStandScreen) client.currentScreen).isCursorLocked()); + } + } + + @ModifyExpressionValue( + method = "onMouseButton", at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", + ordinal = 3 + ) + ) + private Screen modifyCurrentScreen(Screen screen) { + return screen instanceof PassesEventsThrough && ((PassesEventsThrough) screen).shouldPassEvents() ? null : screen; + } +} diff --git a/src/main/java/me/roundaround/armorstands/mixin/NameTagItemMixin.java b/src/main/java/me/roundaround/armorstands/mixin/NameTagItemMixin.java index 92908ec..2eb6b84 100644 --- a/src/main/java/me/roundaround/armorstands/mixin/NameTagItemMixin.java +++ b/src/main/java/me/roundaround/armorstands/mixin/NameTagItemMixin.java @@ -1,10 +1,5 @@ package me.roundaround.armorstands.mixin; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - import me.roundaround.armorstands.server.ArmorStandUsers; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.decoration.ArmorStandEntity; @@ -14,16 +9,21 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(NameTagItem.class) public abstract class NameTagItemMixin { - @Inject(method = "useOnEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;setCustomName(Lnet/minecraft/text/Text;)V"), cancellable = true) + @Inject( + method = "useOnEntity", at = @At( + value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;setCustomName(Lnet/minecraft/text/Text;)V" + ) + ) public void useOnEntity( - ItemStack stack, - PlayerEntity player, - LivingEntity entity, - Hand hand, - CallbackInfoReturnable info) { + ItemStack stack, PlayerEntity player, LivingEntity entity, Hand hand, CallbackInfoReturnable info + ) { if (!(player instanceof ServerPlayerEntity) || !ArmorStandUsers.canEditArmorStands(player)) { return; } diff --git a/src/main/java/me/roundaround/armorstands/mixin/ServerPropertiesHandlerMixin.java b/src/main/java/me/roundaround/armorstands/mixin/ServerPropertiesHandlerMixin.java index c1ce51c..3241859 100644 --- a/src/main/java/me/roundaround/armorstands/mixin/ServerPropertiesHandlerMixin.java +++ b/src/main/java/me/roundaround/armorstands/mixin/ServerPropertiesHandlerMixin.java @@ -1,23 +1,22 @@ package me.roundaround.armorstands.mixin; -import java.util.Properties; - -import org.spongepowered.asm.mixin.Mixin; - import me.roundaround.armorstands.server.ServerPropertiesWithArmorStands; import net.minecraft.server.dedicated.AbstractPropertiesHandler; import net.minecraft.server.dedicated.ServerPropertiesHandler; +import org.spongepowered.asm.mixin.Mixin; + +import java.util.Properties; @Mixin(ServerPropertiesHandler.class) -public abstract class ServerPropertiesHandlerMixin - extends AbstractPropertiesHandler - implements ServerPropertiesWithArmorStands { +public abstract class ServerPropertiesHandlerMixin extends AbstractPropertiesHandler implements + ServerPropertiesWithArmorStands { public final boolean enforceArmorStandPermissions = this.parseBoolean("enforce-armor-stand-permissions", true); public ServerPropertiesHandlerMixin(Properties properties) { super(properties); } + @Override public boolean getEnforceArmorStandPermissions() { return enforceArmorStandPermissions; } diff --git a/src/main/java/me/roundaround/armorstands/network/ArmorStandFlag.java b/src/main/java/me/roundaround/armorstands/network/ArmorStandFlag.java index e43a79c..83bfeb4 100644 --- a/src/main/java/me/roundaround/armorstands/network/ArmorStandFlag.java +++ b/src/main/java/me/roundaround/armorstands/network/ArmorStandFlag.java @@ -1,45 +1,61 @@ package me.roundaround.armorstands.network; -import java.util.Arrays; -import java.util.List; - +import io.netty.buffer.ByteBuf; import me.roundaround.armorstands.ArmorStandsMod; import me.roundaround.armorstands.mixin.ArmorStandEntityAccessor; import me.roundaround.armorstands.util.actions.MoveAction; import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.text.Text; +import net.minecraft.util.function.ValueLists; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; +import java.util.Arrays; +import java.util.List; +import java.util.function.IntFunction; + public enum ArmorStandFlag { - HIDE_BASE_PLATE("base", true), - SHOW_ARMS("arms", false), - SMALL("small", false), - NO_GRAVITY("gravity", true), - INVISIBLE("visible", false), - NAME("name", false), - INVULNERABLE("invulnerable", false), - LOCK_INVENTORY("inventory", false), - UNKNOWN("unknown", false); + UNKNOWN(0, "unknown", false), + HIDE_BASE_PLATE(1, "base", true), + SHOW_ARMS(2, "arms", false), + SMALL(3, "small", false), + NO_GRAVITY(4, "gravity", true), + INVISIBLE(5, "visible", false), + NAME(6, "name", false), + INVULNERABLE(7, "invulnerable", false), + LOCK_INVENTORY(8, "inventory", false); + + public static final IntFunction ID_TO_VALUE_FUNCTION = ValueLists.createIdToValueFunction( + ArmorStandFlag::getId, values(), ValueLists.OutOfBoundsHandling.ZERO); + public static final PacketCodec PACKET_CODEC = PacketCodecs.indexed( + ID_TO_VALUE_FUNCTION, ArmorStandFlag::getId); // Magic number from Vanilla Tweaks armor stand data pack. ¯\_(ツ)_/¯ private static final int ALL_SLOTS_DISABLED = 4144959; - private final String id; + private final int id; + private final String name; private final boolean invertControl; - private ArmorStandFlag(String id, boolean invertControl) { + ArmorStandFlag(int id, String name, boolean invertControl) { this.id = id; + this.name = name; this.invertControl = invertControl; } @Override public String toString() { + return this.name; + } + + public int getId() { return this.id; } public Text getDisplayName() { - return Text.translatable("armorstands.flags." + this.id); + return Text.translatable("armorstands.flags." + this.name); } public boolean invertControl() { @@ -49,26 +65,17 @@ public boolean invertControl() { public boolean getValue(ArmorStandEntity armorStand) { ArmorStandEntityAccessor accessor = (ArmorStandEntityAccessor) armorStand; - switch (this) { - case HIDE_BASE_PLATE: - return armorStand.shouldHideBasePlate(); - case SHOW_ARMS: - return armorStand.shouldShowArms(); - case SMALL: - return armorStand.isSmall(); - case NO_GRAVITY: - return armorStand.hasNoGravity(); - case INVISIBLE: - return armorStand.isInvisible(); - case NAME: - return armorStand.isCustomNameVisible(); - case INVULNERABLE: - return armorStand.isInvulnerable(); - case LOCK_INVENTORY: - return accessor.getDisabledSlots() == ALL_SLOTS_DISABLED; - default: - return false; - } + return switch (this) { + case HIDE_BASE_PLATE -> armorStand.shouldHideBasePlate(); + case SHOW_ARMS -> armorStand.shouldShowArms(); + case SMALL -> armorStand.isSmall(); + case NO_GRAVITY -> armorStand.hasNoGravity(); + case INVISIBLE -> armorStand.isInvisible(); + case NAME -> armorStand.isCustomNameVisible(); + case INVULNERABLE -> armorStand.isInvulnerable(); + case LOCK_INVENTORY -> accessor.getDisabledSlots() == ALL_SLOTS_DISABLED; + default -> false; + }; } public void setValue(ArmorStandEntity armorStand, boolean value) { @@ -115,7 +122,7 @@ public void setValue(ArmorStandEntity armorStand, boolean value) { public static ArmorStandFlag fromString(String value) { return Arrays.stream(ArmorStandFlag.values()) - .filter((flag) -> flag.id.equals(value)) + .filter((flag) -> flag.name.equals(value)) .findFirst() .orElseGet(() -> { ArmorStandsMod.LOGGER.warn("Unknown flag id '{}'. Returning UNKNOWN.", value); @@ -124,9 +131,6 @@ public static ArmorStandFlag fromString(String value) { } public static List getFlags() { - return Arrays.asList(values()) - .stream() - .filter((flag) -> flag != UNKNOWN) - .toList(); + return Arrays.stream(values()).filter((flag) -> flag != UNKNOWN).toList(); } } diff --git a/src/main/java/me/roundaround/armorstands/network/EulerAngleParameter.java b/src/main/java/me/roundaround/armorstands/network/EulerAngleParameter.java index cd355a2..4a1e5da 100644 --- a/src/main/java/me/roundaround/armorstands/network/EulerAngleParameter.java +++ b/src/main/java/me/roundaround/armorstands/network/EulerAngleParameter.java @@ -1,60 +1,64 @@ -package me.roundaround.armorstands.network; - -import java.util.Arrays; - -import net.minecraft.text.Text; -import net.minecraft.util.math.EulerAngle; - -public enum EulerAngleParameter { - PITCH("pitch"), - YAW("yaw"), - ROLL("roll"); - - private final String id; - - private EulerAngleParameter(String id) { - this.id = id; - } - - @Override - public String toString() { - return id; - } - - public Text getDisplayName() { - return Text.translatable("armorstands.parameter." + id); - } - - public float get(EulerAngle angle) { - switch (this) { - case PITCH: - return angle.getPitch(); - case YAW: - return angle.getYaw(); - case ROLL: - return angle.getRoll(); - default: - throw new IllegalArgumentException("Unknown parameter: " + this); - } - } - - public EulerAngle set(EulerAngle angle, float value) { - switch (this) { - case PITCH: - return new EulerAngle(value, angle.getYaw(), angle.getRoll()); - case YAW: - return new EulerAngle(angle.getPitch(), value, angle.getRoll()); - case ROLL: - return new EulerAngle(angle.getPitch(), angle.getYaw(), value); - default: - throw new IllegalArgumentException("Unknown parameter: " + this); - } - } - - public static EulerAngleParameter fromString(String string) { - return Arrays.stream(values()) - .filter(parameter -> parameter.id.equals(string)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Unknown parameter: " + string)); - } -} +package me.roundaround.armorstands.network; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.text.Text; +import net.minecraft.util.function.ValueLists; +import net.minecraft.util.math.EulerAngle; + +import java.util.Arrays; +import java.util.function.IntFunction; + +public enum EulerAngleParameter { + PITCH(0, "pitch"), YAW(1, "yaw"), ROLL(2, "roll"); + + public static final IntFunction ID_TO_VALUE_FUNCTION = ValueLists.createIdToValueFunction( + EulerAngleParameter::getId, values(), ValueLists.OutOfBoundsHandling.CLAMP); + public static final PacketCodec PACKET_CODEC = PacketCodecs.indexed( + ID_TO_VALUE_FUNCTION, EulerAngleParameter::getId); + + private final int id; + private final String name; + + EulerAngleParameter(int id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public int getId() { + return this.id; + } + + public Text getDisplayName() { + return Text.translatable("armorstands.parameter." + name); + } + + public float get(EulerAngle angle) { + return switch (this) { + case PITCH -> angle.getPitch(); + case YAW -> angle.getYaw(); + case ROLL -> angle.getRoll(); + }; + } + + public EulerAngle set(EulerAngle angle, float value) { + return switch (this) { + case PITCH -> new EulerAngle(value, angle.getYaw(), angle.getRoll()); + case YAW -> new EulerAngle(angle.getPitch(), value, angle.getRoll()); + case ROLL -> new EulerAngle(angle.getPitch(), angle.getYaw(), value); + }; + } + + public static EulerAngleParameter fromString(String string) { + return Arrays.stream(values()) + .filter(parameter -> parameter.name.equals(string)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown parameter: " + string)); + } +} diff --git a/src/main/java/me/roundaround/armorstands/network/Networking.java b/src/main/java/me/roundaround/armorstands/network/Networking.java new file mode 100644 index 0000000..9016ae6 --- /dev/null +++ b/src/main/java/me/roundaround/armorstands/network/Networking.java @@ -0,0 +1,293 @@ +package me.roundaround.armorstands.network; + +import me.roundaround.armorstands.ArmorStandsMod; +import me.roundaround.armorstands.mixin.ArmorStandEntityAccessor; +import me.roundaround.armorstands.util.MoveMode; +import me.roundaround.armorstands.util.MoveUnits; +import me.roundaround.armorstands.util.Pose; +import me.roundaround.armorstands.util.PosePreset; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; +import net.minecraft.util.Uuids; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.EulerAngle; + +import java.util.UUID; + +public final class Networking { + private Networking() { + } + + public static final Identifier CLIENT_UPDATE_S2C = new Identifier(ArmorStandsMod.MOD_ID, "client_update_s2c"); + public static final Identifier MESSAGE_S2C = new Identifier(ArmorStandsMod.MOD_ID, "message_s2c"); + public static final Identifier PONG_S2C = new Identifier(ArmorStandsMod.MOD_ID, "pong_s2c"); + + public static final Identifier ADJUST_POSE_C2S = new Identifier(ArmorStandsMod.MOD_ID, "adjust_pose_c2s"); + public static final Identifier ADJUST_POS_C2S = new Identifier(ArmorStandsMod.MOD_ID, "adjust_pos_c2s"); + public static final Identifier ADJUST_YAW_C2S = new Identifier(ArmorStandsMod.MOD_ID, "adjust_yaw_c2s"); + public static final Identifier PING_C2S = new Identifier(ArmorStandsMod.MOD_ID, "ping_c2s"); + public static final Identifier REQUEST_SCREEN_C2S = new Identifier(ArmorStandsMod.MOD_ID, "request_screen_c2s"); + public static final Identifier SET_FLAG_C2S = new Identifier(ArmorStandsMod.MOD_ID, "set_flag_c2s"); + public static final Identifier SET_POSE_C2S = new Identifier(ArmorStandsMod.MOD_ID, "set_pose_c2s"); + public static final Identifier SET_POSE_PRESET_C2S = new Identifier(ArmorStandsMod.MOD_ID, "set_pose_preset_c2s"); + public static final Identifier SET_YAW_C2S = new Identifier(ArmorStandsMod.MOD_ID, "set_yaw_c2s"); + public static final Identifier UNDO_C2S = new Identifier(ArmorStandsMod.MOD_ID, "undo_c2s"); + public static final Identifier UTILITY_ACTION_C2S = new Identifier(ArmorStandsMod.MOD_ID, "utility_action_c2s"); + + public static void registerS2CPayloads() { + PayloadTypeRegistry.playS2C().register(ClientUpdateS2C.ID, ClientUpdateS2C.CODEC); + PayloadTypeRegistry.playS2C().register(MessageS2C.ID, MessageS2C.CODEC); + PayloadTypeRegistry.playS2C().register(PongS2C.ID, PongS2C.CODEC); + } + + public static void registerC2SPayloads() { + PayloadTypeRegistry.playC2S().register(AdjustPoseC2S.ID, AdjustPoseC2S.CODEC); + PayloadTypeRegistry.playC2S().register(AdjustPosC2S.ID, AdjustPosC2S.CODEC); + PayloadTypeRegistry.playC2S().register(AdjustYawC2S.ID, AdjustYawC2S.CODEC); + PayloadTypeRegistry.playC2S().register(PingC2S.ID, PingC2S.CODEC); + PayloadTypeRegistry.playC2S().register(RequestScreenC2S.ID, RequestScreenC2S.CODEC); + PayloadTypeRegistry.playC2S().register(SetFlagC2S.ID, SetFlagC2S.CODEC); + PayloadTypeRegistry.playC2S().register(SetPoseC2S.ID, SetPoseC2S.CODEC); + PayloadTypeRegistry.playC2S().register(SetPosePresetC2S.ID, SetPosePresetC2S.CODEC); + PayloadTypeRegistry.playC2S().register(SetYawC2S.ID, SetYawC2S.CODEC); + PayloadTypeRegistry.playC2S().register(UndoC2S.ID, UndoC2S.CODEC); + PayloadTypeRegistry.playC2S().register(UtilityActionC2S.ID, UtilityActionC2S.CODEC); + } + + public record ClientUpdateS2C(double x, double y, double z, byte yaw, byte pitch, boolean invulnerable, + int disabledSlots) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(CLIENT_UPDATE_S2C); + public static final PacketCodec CODEC = PacketCodec.of( + ClientUpdateS2C::write, ClientUpdateS2C::new); + + public ClientUpdateS2C(ArmorStandEntity armorStand) { + this(armorStand.getX(), armorStand.getY(), armorStand.getZ(), (byte) (armorStand.getYaw() * 256 / 360), + (byte) (armorStand.getPitch() * 256 / 360), armorStand.isInvulnerable(), + ((ArmorStandEntityAccessor) armorStand).getDisabledSlots() + ); + } + + private ClientUpdateS2C(PacketByteBuf buf) { + this(buf.readDouble(), buf.readDouble(), buf.readDouble(), buf.readByte(), buf.readByte(), buf.readBoolean(), + buf.readInt() + ); + } + + private void write(PacketByteBuf buf) { + buf.writeDouble(this.x); + buf.writeDouble(this.y); + buf.writeDouble(this.z); + buf.writeByte(this.yaw); + buf.writeByte(this.pitch); + buf.writeBoolean(this.invulnerable); + buf.writeInt(this.disabledSlots); + } + + @Override + public Id getId() { + return ID; + } + + public float yawFloat() { + return this.yaw() * 360f / 256f; + } + + public float pitchFloat() { + return this.pitch() * 360f / 256f; + } + } + + public record MessageS2C(boolean translatable, String message, boolean styled, int color) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(MESSAGE_S2C); + public static final PacketCodec CODEC = PacketCodec.tuple(PacketCodecs.BOOL, + MessageS2C::translatable, PacketCodecs.STRING, MessageS2C::message, PacketCodecs.BOOL, MessageS2C::styled, + PacketCodecs.INTEGER, MessageS2C::color, MessageS2C::new + ); + + public MessageS2C(String message) { + this(true, message); + } + + public MessageS2C(String message, int color) { + this(true, message, color); + } + + public MessageS2C(boolean translatable, String message) { + this(translatable, message, false, -1); + } + + public MessageS2C(boolean translatable, String message, int color) { + this(translatable, message, true, color); + } + + @Override + public Id getId() { + return ID; + } + } + + public record PongS2C(UUID playerUuid) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(PONG_S2C); + public static final PacketCodec CODEC = PacketCodec.tuple( + Uuids.PACKET_CODEC, PongS2C::playerUuid, PongS2C::new); + + @Override + public Id getId() { + return ID; + } + } + + public record AdjustPoseC2S(PosePart part, EulerAngleParameter parameter, float amount) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(ADJUST_POSE_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple(PosePart.PACKET_CODEC, + AdjustPoseC2S::part, EulerAngleParameter.PACKET_CODEC, AdjustPoseC2S::parameter, PacketCodecs.FLOAT, + AdjustPoseC2S::amount, AdjustPoseC2S::new + ); + + @Override + public Id getId() { + return ID; + } + } + + public record AdjustPosC2S(Direction direction, int amount, MoveMode mode, MoveUnits units) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(ADJUST_POS_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple(Direction.PACKET_CODEC, + AdjustPosC2S::direction, PacketCodecs.INTEGER, AdjustPosC2S::amount, MoveMode.PACKET_CODEC, AdjustPosC2S::mode, + MoveUnits.PACKET_CODEC, AdjustPosC2S::units, AdjustPosC2S::new + ); + + @Override + public Id getId() { + return ID; + } + } + + public record AdjustYawC2S(int amount) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(ADJUST_YAW_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.INTEGER, AdjustYawC2S::amount, AdjustYawC2S::new); + + @Override + public Id getId() { + return ID; + } + } + + public record PingC2S(UUID playerUuid) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(PING_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + Uuids.PACKET_CODEC, PingC2S::playerUuid, PingC2S::new); + + @Override + public Id getId() { + return ID; + } + } + + public record RequestScreenC2S(int armorStandId, ScreenType screenType) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(REQUEST_SCREEN_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple(PacketCodecs.INTEGER, + RequestScreenC2S::armorStandId, ScreenType.PACKET_CODEC, RequestScreenC2S::screenType, RequestScreenC2S::new + ); + + @Override + public Id getId() { + return ID; + } + } + + public record SetFlagC2S(ArmorStandFlag flag, boolean value) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(SET_FLAG_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + ArmorStandFlag.PACKET_CODEC, SetFlagC2S::flag, PacketCodecs.BOOL, SetFlagC2S::value, SetFlagC2S::new); + + @Override + public Id getId() { + return ID; + } + } + + public record SetPoseC2S(EulerAngle head, EulerAngle body, EulerAngle rightArm, EulerAngle leftArm, + EulerAngle rightLeg, EulerAngle leftLeg) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(SET_POSE_C2S); + public static final PacketCodec CODEC = PacketCodec.of( + SetPoseC2S::write, SetPoseC2S::new); + + public SetPoseC2S(Pose pose) { + this(pose.getHead(), pose.getBody(), pose.getRightArm(), pose.getLeftArm(), pose.getRightLeg(), + pose.getLeftLeg() + ); + } + + private SetPoseC2S(PacketByteBuf buf) { + this(NetworkHelpers.readEulerAngle(buf), NetworkHelpers.readEulerAngle(buf), NetworkHelpers.readEulerAngle(buf), + NetworkHelpers.readEulerAngle(buf), NetworkHelpers.readEulerAngle(buf), NetworkHelpers.readEulerAngle(buf) + ); + } + + private void write(PacketByteBuf buf) { + NetworkHelpers.writeEulerAngle(buf, head); + NetworkHelpers.writeEulerAngle(buf, body); + NetworkHelpers.writeEulerAngle(buf, rightArm); + NetworkHelpers.writeEulerAngle(buf, leftArm); + NetworkHelpers.writeEulerAngle(buf, rightLeg); + NetworkHelpers.writeEulerAngle(buf, leftLeg); + } + + @Override + public Id getId() { + return ID; + } + } + + public record SetPosePresetC2S(PosePreset pose) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(SET_POSE_PRESET_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + PosePreset.PACKET_CODEC, SetPosePresetC2S::pose, SetPosePresetC2S::new); + + @Override + public Id getId() { + return ID; + } + } + + public record SetYawC2S(float angle) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(SET_YAW_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.FLOAT, SetYawC2S::angle, SetYawC2S::new); + + @Override + public Id getId() { + return ID; + } + } + + public record UndoC2S(boolean redo) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(UNDO_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.BOOL, UndoC2S::redo, UndoC2S::new); + + @Override + public Id getId() { + return ID; + } + } + + public record UtilityActionC2S(UtilityAction action) implements CustomPayload { + public static final CustomPayload.Id ID = new CustomPayload.Id<>(UTILITY_ACTION_C2S); + public static final PacketCodec CODEC = PacketCodec.tuple( + UtilityAction.PACKET_CODEC, UtilityActionC2S::action, UtilityActionC2S::new); + + @Override + public Id getId() { + return ID; + } + } +} diff --git a/src/main/java/me/roundaround/armorstands/network/PosePart.java b/src/main/java/me/roundaround/armorstands/network/PosePart.java index 14fce07..892b6ce 100644 --- a/src/main/java/me/roundaround/armorstands/network/PosePart.java +++ b/src/main/java/me/roundaround/armorstands/network/PosePart.java @@ -1,86 +1,82 @@ -package me.roundaround.armorstands.network; - -import java.util.Arrays; - -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.text.Text; -import net.minecraft.util.math.EulerAngle; - -public enum PosePart { - HEAD("head"), - BODY("body"), - RIGHT_ARM("rightArm"), - LEFT_ARM("leftArm"), - RIGHT_LEG("rightLeg"), - LEFT_LEG("leftLeg"); - - private final String id; - - private PosePart(String id) { - this.id = id; - } - - @Override - public String toString() { - return id; - } - - public Text getDisplayName() { - return Text.translatable("armorstands.part." + id); - } - - public EulerAngle get(ArmorStandEntity armorStand) { - switch (this) { - case HEAD: - return armorStand.getHeadRotation(); - case BODY: - return armorStand.getBodyRotation(); - case RIGHT_ARM: - return armorStand.getRightArmRotation(); - case LEFT_ARM: - return armorStand.getLeftArmRotation(); - case RIGHT_LEG: - return armorStand.getRightLegRotation(); - case LEFT_LEG: - return armorStand.getLeftLegRotation(); - default: - throw new IllegalArgumentException("Unknown part: " + this); - } - } - - public void set(ArmorStandEntity armorStand, EulerAngle angle) { - switch (this) { - case HEAD: - armorStand.setHeadRotation(angle); - break; - case BODY: - armorStand.setBodyRotation(angle); - break; - case RIGHT_ARM: - armorStand.setRightArmRotation(angle); - break; - case LEFT_ARM: - armorStand.setLeftArmRotation(angle); - break; - case RIGHT_LEG: - armorStand.setRightLegRotation(angle); - break; - case LEFT_LEG: - armorStand.setLeftLegRotation(angle); - break; - default: - throw new IllegalArgumentException("Unknown part: " + this); - } - } - - public void set(ArmorStandEntity armorStand, EulerAngleParameter parameter, float value) { - set(armorStand, parameter.set(get(armorStand), value)); - } - - public static PosePart fromString(String value) { - return Arrays.stream(PosePart.values()) - .filter((flag) -> flag.id.equals(value)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Unknown part: " + value)); - } -} +package me.roundaround.armorstands.network; + +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.text.Text; +import net.minecraft.util.function.ValueLists; +import net.minecraft.util.math.EulerAngle; + +import java.util.Arrays; +import java.util.function.Consumer; +import java.util.function.IntFunction; + +public enum PosePart { + HEAD(0, "head"), + BODY(1, "body"), + RIGHT_ARM(2, "rightArm"), + LEFT_ARM(3, "leftArm"), + RIGHT_LEG(4, "rightLeg"), + LEFT_LEG(5, "leftLeg"); + + public static final IntFunction ID_TO_VALUE_FUNCTION = ValueLists.createIdToValueFunction( + PosePart::getId, values(), ValueLists.OutOfBoundsHandling.CLAMP); + public static final PacketCodec PACKET_CODEC = PacketCodecs.indexed( + ID_TO_VALUE_FUNCTION, PosePart::getId); + + private final int id; + private final String name; + + PosePart(int id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public int getId() { + return this.id; + } + + public Text getDisplayName() { + return Text.translatable("armorstands.part." + name); + } + + public EulerAngle get(ArmorStandEntity armorStand) { + return switch (this) { + case HEAD -> armorStand.getHeadRotation(); + case BODY -> armorStand.getBodyRotation(); + case RIGHT_ARM -> armorStand.getRightArmRotation(); + case LEFT_ARM -> armorStand.getLeftArmRotation(); + case RIGHT_LEG -> armorStand.getRightLegRotation(); + case LEFT_LEG -> armorStand.getLeftLegRotation(); + }; + } + + public void set(ArmorStandEntity armorStand, EulerAngle angle) { + Consumer consumer = switch (this) { + case HEAD -> armorStand::setHeadRotation; + case BODY -> armorStand::setBodyRotation; + case RIGHT_ARM -> armorStand::setRightArmRotation; + case LEFT_ARM -> armorStand::setLeftArmRotation; + case RIGHT_LEG -> armorStand::setRightLegRotation; + case LEFT_LEG -> armorStand::setLeftLegRotation; + }; + consumer.accept(angle); + } + + public void set(ArmorStandEntity armorStand, EulerAngleParameter parameter, float value) { + set(armorStand, parameter.set(get(armorStand), value)); + } + + public static PosePart fromString(String value) { + return Arrays.stream(PosePart.values()) + .filter((flag) -> flag.name.equals(value)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unknown part: " + value)); + } +} diff --git a/src/main/java/me/roundaround/armorstands/network/ScreenType.java b/src/main/java/me/roundaround/armorstands/network/ScreenType.java index bd6e15f..241229e 100644 --- a/src/main/java/me/roundaround/armorstands/network/ScreenType.java +++ b/src/main/java/me/roundaround/armorstands/network/ScreenType.java @@ -1,61 +1,72 @@ -package me.roundaround.armorstands.network; - -import java.util.Arrays; - -import net.minecraft.text.Text; - -public enum ScreenType { - UTILITIES("utilities", 0), - MOVE("move", 1), - ROTATE("rotate", 2), - POSE("pose", 3), - PRESETS("presets", 4), - INVENTORY("inventory", 5); - - private String id; - private int uIndex; - - private ScreenType(String id, int uIndex) { - this.id = id; - this.uIndex = uIndex; - } - - public String getId() { - return id; - } - - public int getUIndex() { - return uIndex; - } - - public Text getDisplayName() { - return Text.translatable("armorstands.screen." + id); - } - - public boolean usesInventory() { - return this == INVENTORY; - } - - public ScreenType next() { - int index = ordinal() + 1; - if (index >= values().length) { - index = 0; - } - return values()[index]; - } - - public ScreenType previous() { - int index = ordinal() - 1; - if (index < 0) { - index = values().length - 1; - } - return values()[index]; - } - - public static ScreenType fromId(String id) { - return Arrays.stream(values()) - .filter(type -> type.getId().equals(id)) - .findFirst() - .orElse(null); - } -} +package me.roundaround.armorstands.network; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.text.Text; +import net.minecraft.util.function.ValueLists; + +import java.util.Arrays; +import java.util.function.IntFunction; + +public enum ScreenType { + UTILITIES(0, "utilities"), + MOVE(1, "move"), + ROTATE(2, "rotate"), + POSE(3, "pose"), + PRESETS(4, "presets"), + INVENTORY(5, "inventory"); + + public static final IntFunction ID_TO_VALUE_FUNCTION = ValueLists.createIdToValueFunction( + ScreenType::getId, values(), ValueLists.OutOfBoundsHandling.ZERO); + public static final PacketCodec PACKET_CODEC = PacketCodecs.indexed( + ID_TO_VALUE_FUNCTION, ScreenType::getId); + + private final int id; + private final String name; + + ScreenType(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return this.id; + } + + public String getName() { + return this.name; + } + + public int getUIndex() { + return this.id; + } + + public Text getDisplayName() { + return Text.translatable("armorstands.screen." + name); + } + + public boolean usesInventory() { + return this == INVENTORY; + } + + public ScreenType next() { + int index = ordinal() + 1; + if (index >= values().length) { + index = 0; + } + return values()[index]; + } + + public ScreenType previous() { + int index = ordinal() - 1; + if (index < 0) { + index = values().length - 1; + } + return values()[index]; + } + + public static ScreenType fromId(String id) { + return Arrays.stream(values()).filter(type -> type.getName().equals(id)).findFirst().orElse(null); + } +} diff --git a/src/main/java/me/roundaround/armorstands/network/UtilityAction.java b/src/main/java/me/roundaround/armorstands/network/UtilityAction.java index 80defee..591e890 100644 --- a/src/main/java/me/roundaround/armorstands/network/UtilityAction.java +++ b/src/main/java/me/roundaround/armorstands/network/UtilityAction.java @@ -1,20 +1,19 @@ package me.roundaround.armorstands.network; -import java.util.Arrays; - +import io.netty.buffer.ByteBuf; import me.roundaround.armorstands.ArmorStandsMod; -import me.roundaround.armorstands.network.packet.s2c.MessagePacket; +import me.roundaround.armorstands.server.network.ServerNetworking; import me.roundaround.armorstands.util.ArmorStandEditor; import me.roundaround.armorstands.util.ArmorStandHelper; import me.roundaround.armorstands.util.Clipboard; -import me.roundaround.armorstands.util.actions.ArmorStandAction; -import me.roundaround.armorstands.util.actions.HoldingAction; -import me.roundaround.armorstands.util.actions.PrepareAction; -import me.roundaround.armorstands.util.actions.SnapToGroundAction; -import me.roundaround.armorstands.util.actions.ToolRackAction; +import me.roundaround.armorstands.util.actions.*; import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.server.network.ServerPlayerEntity; +import java.util.Arrays; + public enum UtilityAction { COPY("copy"), PASTE("paste"), @@ -38,9 +37,12 @@ public enum UtilityAction { FACE_WITH("face_with"), UNKNOWN("unknown"); + public static final PacketCodec PACKET_CODEC = PacketCodec.tuple( + PacketCodecs.STRING, UtilityAction::getId, UtilityAction::fromString); + private final String id; - private UtilityAction(String id) { + UtilityAction(String id) { this.id = id; } @@ -49,6 +51,10 @@ public String toString() { return id; } + public String getId() { + return this.id; + } + public void apply(ArmorStandEditor editor, ServerPlayerEntity player) { ArmorStandEntity armorStand = editor.getArmorStand(); @@ -65,7 +71,7 @@ public void apply(ArmorStandEditor editor, ServerPlayerEntity player) { case TOOL_RACK: ToolRackAction action = ToolRackAction.create(armorStand); if (action == null) { - MessagePacket.sendToClient(player, "armorstands.utility.toolRack.noHook", 0xFF0000); + ServerNetworking.sendMessagePacket(player, "armorstands.utility.toolRack.noHook", 0xFF0000); } else { editor.applyAction(action); } @@ -115,22 +121,13 @@ public void apply(ArmorStandEditor editor, ServerPlayerEntity player) { } public UtilityAction forSmall(boolean small) { - switch (this) { - case UPRIGHT_ITEM: - case UPRIGHT_ITEM_SMALL: - return small ? UPRIGHT_ITEM_SMALL : UPRIGHT_ITEM; - case FLAT_ITEM: - case FLAT_ITEM_SMALL: - return small ? FLAT_ITEM_SMALL : FLAT_ITEM; - case BLOCK: - case BLOCK_SMALL: - return small ? BLOCK_SMALL : BLOCK; - case TOOL: - case TOOL_SMALL: - return small ? TOOL_SMALL : TOOL; - default: - return this; - } + return switch (this) { + case UPRIGHT_ITEM, UPRIGHT_ITEM_SMALL -> small ? UPRIGHT_ITEM_SMALL : UPRIGHT_ITEM; + case FLAT_ITEM, FLAT_ITEM_SMALL -> small ? FLAT_ITEM_SMALL : FLAT_ITEM; + case BLOCK, BLOCK_SMALL -> small ? BLOCK_SMALL : BLOCK; + case TOOL, TOOL_SMALL -> small ? TOOL_SMALL : TOOL; + default -> this; + }; } public static UtilityAction fromString(String value) { diff --git a/src/main/java/me/roundaround/armorstands/network/packet/NetworkPackets.java b/src/main/java/me/roundaround/armorstands/network/packet/NetworkPackets.java deleted file mode 100644 index 922be22..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/NetworkPackets.java +++ /dev/null @@ -1,66 +0,0 @@ -package me.roundaround.armorstands.network.packet; - -import me.roundaround.armorstands.ArmorStandsMod; -import net.minecraft.util.Identifier; - -public class NetworkPackets { - public static final Identifier REQUEST_SCREEN_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "request_screen_packet"); - - public static final Identifier OPEN_SCREEN_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "open_screen_packet"); - - public static final Identifier CLIENT_UPDATE_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "client_update_packet"); - - public static final Identifier MESSAGE_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "message_packet"); - - public static final Identifier SET_FLAG_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "set_flag_packet"); - - public static final Identifier ADJUST_YAW_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "adjust_yaw_packet"); - - public static final Identifier SET_YAW_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "set_yaw_packet"); - - public static final Identifier ADJUST_POS_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "adjust_pos_packet"); - - public static final Identifier UTILITY_ACTION_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "utility_action_packet"); - - public static final Identifier SET_POSE_PRESET_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "set_pose_preset_packet"); - - public static final Identifier SET_POSE_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "set_pose_packet"); - - public static final Identifier ADJUST_POSE_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "adjust_pose_packet"); - - public static final Identifier UNDO_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "undo_packet"); - - public static final Identifier PING_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "ping_packet"); - - public static final Identifier PONG_PACKET = new Identifier( - ArmorStandsMod.MOD_ID, - "pong_packet"); -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustPosPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustPosPacket.java deleted file mode 100644 index 2567d1f..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustPosPacket.java +++ /dev/null @@ -1,76 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import me.roundaround.armorstands.util.MoveMode; -import me.roundaround.armorstands.util.MoveUnits; -import me.roundaround.armorstands.util.actions.AdjustPosAction; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.math.Direction; - -public class AdjustPosPacket { - private final Direction direction; - private final int amount; - private final MoveMode mode; - private final MoveUnits units; - - public AdjustPosPacket(PacketByteBuf buf) { - this.direction = Direction.byId(buf.readInt()); - this.amount = buf.readInt(); - this.mode = MoveMode.fromId(buf.readString()); - this.units = MoveUnits.fromId(buf.readString()); - } - - public AdjustPosPacket(Direction direction, int amount, MoveMode mode, MoveUnits units) { - this.direction = direction; - this.amount = amount; - this.mode = mode; - this.units = units; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeInt(this.direction.getId()); - buf.writeInt(this.amount); - buf.writeString(this.mode.getId()); - buf.writeString(this.units.getId()); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.applyAction(this.mode.isLocal() - ? AdjustPosAction.local(this.direction, this.amount, this.units, this.mode.isLocalToPlayer()) - : AdjustPosAction.relative(this.direction, this.amount, this.units)); - } - - public static void sendToServer(Direction direction, int amount, MoveMode mode, MoveUnits units) { - ClientPlayNetworking.send(NetworkPackets.ADJUST_POS_PACKET, - new AdjustPosPacket(direction, amount, mode, units).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.ADJUST_POS_PACKET, - (server, player, handler, buf, responseSender) -> { - new AdjustPosPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustPosePacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustPosePacket.java deleted file mode 100644 index eceef65..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustPosePacket.java +++ /dev/null @@ -1,68 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.EulerAngleParameter; -import me.roundaround.armorstands.network.PosePart; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class AdjustPosePacket { - private final PosePart part; - private final EulerAngleParameter parameter; - private final float amount; - - public AdjustPosePacket(PacketByteBuf buf) { - this.part = PosePart.fromString(buf.readString()); - this.parameter = EulerAngleParameter.fromString(buf.readString()); - this.amount = buf.readFloat(); - } - - public AdjustPosePacket(PosePart part, EulerAngleParameter parameter, float amount) { - this.part = part; - this.parameter = parameter; - this.amount = amount; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeString(this.part.toString()); - buf.writeString(this.parameter.toString()); - buf.writeFloat(this.amount); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.adjustPose(this.part, this.parameter, this.amount); - } - - public static void sendToServer(PosePart part, EulerAngleParameter parameter, float amount) { - ClientPlayNetworking.send(NetworkPackets.ADJUST_POSE_PACKET, - new AdjustPosePacket(part, parameter, amount).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.ADJUST_POSE_PACKET, - (server, player, handler, buf, responseSender) -> { - new AdjustPosePacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustYawPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustYawPacket.java deleted file mode 100644 index 659d05c..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/AdjustYawPacket.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class AdjustYawPacket { - private final int amount; - - public AdjustYawPacket(PacketByteBuf buf) { - this.amount = buf.readInt(); - } - - public AdjustYawPacket(int amount) { - this.amount = amount; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeInt(this.amount); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.rotate(this.amount); - } - - public static void sendToServer(int amount) { - ClientPlayNetworking.send(NetworkPackets.ADJUST_YAW_PACKET, new AdjustYawPacket(amount).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.ADJUST_YAW_PACKET, - (server, player, handler, buf, responseSender) -> { - new AdjustYawPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/PingPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/PingPacket.java deleted file mode 100644 index 8f19ac0..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/PingPacket.java +++ /dev/null @@ -1,53 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import java.util.UUID; - -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.network.packet.s2c.PongPacket; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class PingPacket { - private final UUID playerUuid; - - private PingPacket(PacketByteBuf buf) { - this.playerUuid = buf.readUuid(); - } - - private PingPacket(UUID playerUuid) { - this.playerUuid = playerUuid; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeUuid(this.playerUuid); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - PongPacket.sendToClient(player); - } - - public static void sendToServer(ClientPlayerEntity player) { - ClientPlayNetworking.send(NetworkPackets.PING_PACKET, - new PingPacket(player.getUuid()).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver(NetworkPackets.PING_PACKET, - (server, player, handler, buf, responseSender) -> { - new PingPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/RequestScreenPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/RequestScreenPacket.java deleted file mode 100644 index 67231be..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/RequestScreenPacket.java +++ /dev/null @@ -1,70 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.ScreenType; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.screen.ArmorStandScreenHandler; -import me.roundaround.armorstands.util.LastUsedScreen; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class RequestScreenPacket { - private final int armorStandId; - private final ScreenType screenType; - - private RequestScreenPacket(PacketByteBuf buf) { - this.armorStandId = buf.readInt(); - this.screenType = ScreenType.fromId(buf.readString()); - } - - private RequestScreenPacket(ArmorStandEntity armorStand, ScreenType screenType) { - this.armorStandId = armorStand.getId(); - this.screenType = screenType; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeInt(this.armorStandId); - buf.writeString(this.screenType.getId()); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - ArmorStandEntity armorStand = (ArmorStandEntity) player.getWorld().getEntityById(this.armorStandId); - - if (armorStand == null) { - return; - } - - if (player.currentScreenHandler instanceof ArmorStandScreenHandler) { - // Bypass the normal screen closing logic, as we don't want to send a - // close packet to the client. - player.onHandledScreenClosed(); - } - - LastUsedScreen.set(player, armorStand, this.screenType); - player.openHandledScreen(ArmorStandScreenHandler.Factory.create(this.screenType, armorStand)); - } - - public static void sendToServer(ArmorStandEntity armorStand, ScreenType screenType) { - ClientPlayNetworking.send(NetworkPackets.REQUEST_SCREEN_PACKET, - new RequestScreenPacket(armorStand, screenType).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver(NetworkPackets.REQUEST_SCREEN_PACKET, - (server, player, handler, buf, responseSender) -> { - new RequestScreenPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetFlagPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetFlagPacket.java deleted file mode 100644 index 00f1763..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetFlagPacket.java +++ /dev/null @@ -1,65 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.ArmorStandFlag; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.network.packet.s2c.ClientUpdatePacket; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class SetFlagPacket { - private final ArmorStandFlag flag; - private final boolean value; - - public SetFlagPacket(PacketByteBuf buf) { - this.flag = ArmorStandFlag.fromString(buf.readString()); - this.value = buf.readBoolean(); - } - - public SetFlagPacket(ArmorStandFlag flag, boolean value) { - this.flag = flag; - this.value = value; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeString(this.flag.toString()); - buf.writeBoolean(this.value); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.setFlag(this.flag, this.value); - - ClientUpdatePacket.sendToClient(player, editor.getArmorStand()); - } - - public static void sendToServer(ArmorStandFlag flag, boolean value) { - ClientPlayNetworking.send(NetworkPackets.SET_FLAG_PACKET, new SetFlagPacket(flag, value).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.SET_FLAG_PACKET, - (server, player, handler, buf, responseSender) -> { - new SetFlagPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetPosePacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetPosePacket.java deleted file mode 100644 index ee57ed2..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetPosePacket.java +++ /dev/null @@ -1,128 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.NetworkHelpers; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import me.roundaround.armorstands.util.Pose; -import me.roundaround.armorstands.util.SavedPose; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.math.EulerAngle; - -public class SetPosePacket { - private final EulerAngle head; - private final EulerAngle body; - private final EulerAngle rightArm; - private final EulerAngle leftArm; - private final EulerAngle rightLeg; - private final EulerAngle leftLeg; - - public SetPosePacket(PacketByteBuf buf) { - this.head = NetworkHelpers.readEulerAngle(buf); - this.body = NetworkHelpers.readEulerAngle(buf); - this.rightArm = NetworkHelpers.readEulerAngle(buf); - this.leftArm = NetworkHelpers.readEulerAngle(buf); - this.rightLeg = NetworkHelpers.readEulerAngle(buf); - this.leftLeg = NetworkHelpers.readEulerAngle(buf); - } - - public SetPosePacket(SavedPose pose) { - this(pose.toPose()); - } - - public SetPosePacket(Pose pose) { - this( - pose.getHead(), - pose.getBody(), - pose.getRightArm(), - pose.getLeftArm(), - pose.getRightLeg(), - pose.getLeftLeg()); - } - - public SetPosePacket( - EulerAngle head, - EulerAngle body, - EulerAngle rightArm, - EulerAngle leftArm, - EulerAngle rightLeg, - EulerAngle leftLeg) { - this.head = head; - this.body = body; - this.rightArm = rightArm; - this.leftArm = leftArm; - this.rightLeg = rightLeg; - this.leftLeg = leftLeg; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - NetworkHelpers.writeEulerAngle(buf, head); - NetworkHelpers.writeEulerAngle(buf, body); - NetworkHelpers.writeEulerAngle(buf, rightArm); - NetworkHelpers.writeEulerAngle(buf, leftArm); - NetworkHelpers.writeEulerAngle(buf, rightLeg); - NetworkHelpers.writeEulerAngle(buf, leftLeg); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.setPose( - this.head, - this.body, - this.rightArm, - this.leftArm, - this.rightLeg, - this.leftLeg); - } - - public static void sendToServer(SavedPose pose) { - ClientPlayNetworking.send( - NetworkPackets.SET_POSE_PACKET, - new SetPosePacket(pose).toPacket()); - } - - public static void sendToServer(Pose pose) { - ClientPlayNetworking.send( - NetworkPackets.SET_POSE_PACKET, - new SetPosePacket(pose).toPacket()); - } - - public static void sendToServer( - EulerAngle head, - EulerAngle body, - EulerAngle rightArm, - EulerAngle leftArm, - EulerAngle rightLeg, - EulerAngle leftLeg) { - ClientPlayNetworking.send( - NetworkPackets.SET_POSE_PACKET, - new SetPosePacket(head, body, rightArm, leftArm, rightLeg, leftLeg) - .toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.SET_POSE_PACKET, - (server, player, handler, buf, responseSender) -> { - new SetPosePacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetPosePresetPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetPosePresetPacket.java deleted file mode 100644 index 4d81300..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetPosePresetPacket.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import me.roundaround.armorstands.util.PosePreset; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class SetPosePresetPacket { - private final PosePreset pose; - - public SetPosePresetPacket(PacketByteBuf buf) { - this.pose = PosePreset.fromString(buf.readString()); - } - - public SetPosePresetPacket(PosePreset pose) { - this.pose = pose; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeString(this.pose.toString()); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.setPose(this.pose.toPose()); - } - - public static void sendToServer(PosePreset pose) { - ClientPlayNetworking.send( - NetworkPackets.SET_POSE_PRESET_PACKET, - new SetPosePresetPacket(pose).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.SET_POSE_PRESET_PACKET, - (server, player, handler, buf, responseSender) -> { - new SetPosePresetPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetYawPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetYawPacket.java deleted file mode 100644 index 893cbfb..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/SetYawPacket.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class SetYawPacket { - private final float angle; - - public SetYawPacket(PacketByteBuf buf) { - this.angle = buf.readFloat(); - } - - public SetYawPacket(float amount) { - this.angle = amount; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeFloat(this.angle); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - editor.setRotation(this.angle); - } - - public static void sendToServer(float amount) { - ClientPlayNetworking.send(NetworkPackets.SET_YAW_PACKET, new SetYawPacket(amount).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.SET_YAW_PACKET, - (server, player, handler, buf, responseSender) -> { - new SetYawPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/UndoPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/UndoPacket.java deleted file mode 100644 index 4a1b64b..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/UndoPacket.java +++ /dev/null @@ -1,70 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.network.packet.s2c.MessagePacket; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -import java.util.function.Supplier; - -public class UndoPacket { - private final boolean redo; - - public UndoPacket(PacketByteBuf buf) { - this.redo = buf.readBoolean(); - } - - public UndoPacket(boolean redo) { - this.redo = redo; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeBoolean(redo); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { - return; - } - - ArmorStandEditor editor = screenHandler.getEditor(); - - Supplier action = this.redo ? editor::redo : editor::undo; - String successMessage = this.redo ? "armorstands.message.redo" : "armorstands.message.undo"; - String failureMessage = this.redo ? "armorstands.message.redo.fail" : "armorstands.message.undo.fail"; - - if (action.get()) { - MessagePacket.sendToClient(player, successMessage); - } else { - MessagePacket.sendToClient(player, failureMessage); - } - } - - public static void sendToServer(boolean redo) { - ClientPlayNetworking.send( - NetworkPackets.UNDO_PACKET, - new UndoPacket(redo).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.UNDO_PACKET, - (server, player, handler, buf, responseSender) -> { - new UndoPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/c2s/UtilityActionPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/c2s/UtilityActionPacket.java deleted file mode 100644 index bf3e1e5..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/c2s/UtilityActionPacket.java +++ /dev/null @@ -1,58 +0,0 @@ -package me.roundaround.armorstands.network.packet.c2s; - -import me.roundaround.armorstands.network.UtilityAction; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import me.roundaround.armorstands.util.ArmorStandEditor; -import me.roundaround.armorstands.util.HasArmorStandEditor; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; - -public class UtilityActionPacket { - private final UtilityAction action; - - public UtilityActionPacket(PacketByteBuf buf) { - this.action = UtilityAction.fromString(buf.readString()); - } - - public UtilityActionPacket(UtilityAction action) { - this.action = action; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeString(action.toString()); - return buf; - } - - private void handleOnServer( - MinecraftServer server, - ServerPlayerEntity player, - ServerPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(player.currentScreenHandler instanceof HasArmorStandEditor)) { - return; - } - - HasArmorStandEditor screenHandler = (HasArmorStandEditor) player.currentScreenHandler; - ArmorStandEditor editor = screenHandler.getEditor(); - this.action.apply(editor, player); - } - - public static void sendToServer(UtilityAction action) { - ClientPlayNetworking.send(NetworkPackets.UTILITY_ACTION_PACKET, new UtilityActionPacket(action).toPacket()); - } - - public static void registerServerReceiver() { - ServerPlayNetworking.registerGlobalReceiver( - NetworkPackets.UTILITY_ACTION_PACKET, - (server, player, handler, buf, responseSender) -> { - new UtilityActionPacket(buf).handleOnServer(server, player, handler, responseSender); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/s2c/ClientUpdatePacket.java b/src/main/java/me/roundaround/armorstands/network/packet/s2c/ClientUpdatePacket.java deleted file mode 100644 index b46c00d..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/s2c/ClientUpdatePacket.java +++ /dev/null @@ -1,91 +0,0 @@ -package me.roundaround.armorstands.network.packet.s2c; - -import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; -import me.roundaround.armorstands.mixin.ArmorStandEntityAccessor; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.math.MathHelper; - -public class ClientUpdatePacket { - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final boolean invulnerable; - private final int disabledSlots; - - private ClientUpdatePacket(PacketByteBuf buf) { - this.x = buf.readDouble(); - this.y = buf.readDouble(); - this.z = buf.readDouble(); - this.yaw = buf.readFloat(); - this.pitch = buf.readFloat(); - this.invulnerable = buf.readBoolean(); - this.disabledSlots = buf.readInt(); - } - - private ClientUpdatePacket(ArmorStandEntity armorStand) { - this.x = armorStand.getX(); - this.y = armorStand.getY(); - this.z = armorStand.getZ(); - this.yaw = armorStand.getYaw(); - this.pitch = armorStand.getPitch(); - this.invulnerable = armorStand.isInvulnerable(); - this.disabledSlots = ((ArmorStandEntityAccessor) armorStand).getDisabledSlots(); - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeDouble(this.x); - buf.writeDouble(this.y); - buf.writeDouble(this.z); - buf.writeFloat(this.yaw); - buf.writeFloat(this.pitch); - buf.writeBoolean(this.invulnerable); - buf.writeInt(this.disabledSlots); - return buf; - } - - private void handleOnClient( - MinecraftClient client, - ClientPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(client.currentScreen instanceof AbstractArmorStandScreen)) { - return; - } - - AbstractArmorStandScreen screen = (AbstractArmorStandScreen) client.currentScreen; - screen.updatePosOnClient(this.x, this.y, this.z); - screen.updateYawOnClient(MathHelper.wrapDegrees(this.yaw)); - screen.updatePitchOnClient(MathHelper.wrapDegrees(this.pitch)); - screen.updateInvulnerableOnClient(this.invulnerable); - screen.updateDisabledSlotsOnClient(this.disabledSlots); - } - - public static void sendToClient(ServerPlayerEntity player, ArmorStandEntity armorStand) { - ServerPlayNetworking.send( - player, - NetworkPackets.CLIENT_UPDATE_PACKET, - new ClientUpdatePacket(armorStand).toPacket()); - } - - public static void registerClientReceiver() { - ClientPlayNetworking.registerGlobalReceiver( - NetworkPackets.CLIENT_UPDATE_PACKET, - (client, handler, buf, responseSender) -> { - ClientUpdatePacket packet = new ClientUpdatePacket(buf); - client.execute(() -> { - packet.handleOnClient(client, handler, responseSender); - }); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/s2c/MessagePacket.java b/src/main/java/me/roundaround/armorstands/network/packet/s2c/MessagePacket.java deleted file mode 100644 index c3b88ad..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/s2c/MessagePacket.java +++ /dev/null @@ -1,105 +0,0 @@ -package me.roundaround.armorstands.network.packet.s2c; - -import me.roundaround.armorstands.client.gui.MessageRenderer; -import me.roundaround.armorstands.client.gui.MessageRenderer.HasMessageRenderer; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; - -public class MessagePacket { - private final boolean translatable; - private final String message; - private final boolean styled; - private final int color; - - public MessagePacket(PacketByteBuf buf) { - this.translatable = buf.readBoolean(); - this.message = buf.readString(); - this.styled = buf.readBoolean(); - this.color = this.styled ? buf.readInt() : -1; - } - - public MessagePacket(String message) { - this(true, message); - } - - public MessagePacket(String message, int color) { - this(true, message, color); - } - - public MessagePacket(boolean translatable, String message) { - this(translatable, message, false, -1); - } - - public MessagePacket(boolean translatable, String message, int color) { - this(translatable, message, true, color); - } - - public MessagePacket(boolean translatable, String message, boolean styled, int color) { - this.translatable = translatable; - this.message = message; - this.styled = styled; - this.color = color; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeBoolean(this.translatable); - buf.writeString(this.message); - buf.writeBoolean(this.styled); - if (this.styled) { - buf.writeInt(this.color); - } - return buf; - } - - private void handleOnClient( - MinecraftClient client, - ClientPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(client.currentScreen instanceof HasMessageRenderer)) { - return; - } - - MessageRenderer messageRenderer = ((HasMessageRenderer) client.currentScreen).getMessageRenderer(); - messageRenderer.addMessage( - this.translatable - ? Text.translatable(this.message) - : Text.literal(this.message), - this.styled - ? this.color - : MessageRenderer.BASE_COLOR); - } - - public static void sendToClient(ServerPlayerEntity player, String message) { - ServerPlayNetworking.send( - player, - NetworkPackets.MESSAGE_PACKET, - new MessagePacket(message).toPacket()); - } - - public static void sendToClient(ServerPlayerEntity player, String message, int color) { - ServerPlayNetworking.send( - player, - NetworkPackets.MESSAGE_PACKET, - new MessagePacket(message, color).toPacket()); - } - - public static void registerClientReceiver() { - ClientPlayNetworking.registerGlobalReceiver( - NetworkPackets.MESSAGE_PACKET, - (client, handler, buf, responseSender) -> { - MessagePacket packet = new MessagePacket(buf); - client.execute(() -> { - packet.handleOnClient(client, handler, responseSender); - }); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/network/packet/s2c/PongPacket.java b/src/main/java/me/roundaround/armorstands/network/packet/s2c/PongPacket.java deleted file mode 100644 index 977ac6c..0000000 --- a/src/main/java/me/roundaround/armorstands/network/packet/s2c/PongPacket.java +++ /dev/null @@ -1,61 +0,0 @@ -package me.roundaround.armorstands.network.packet.s2c; - -import java.util.UUID; - -import me.roundaround.armorstands.client.gui.screen.AbstractArmorStandScreen; -import me.roundaround.armorstands.network.packet.NetworkPackets; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.network.ServerPlayerEntity; - -public class PongPacket { - private final UUID playerUuid; - - private PongPacket(PacketByteBuf buf) { - this.playerUuid = buf.readUuid(); - } - - private PongPacket(UUID playerUuid) { - this.playerUuid = playerUuid; - } - - private PacketByteBuf toPacket() { - PacketByteBuf buf = new PacketByteBuf(PacketByteBufs.create()); - buf.writeUuid(this.playerUuid); - return buf; - } - - private void handleOnClient( - MinecraftClient client, - ClientPlayNetworkHandler handler, - PacketSender responseSender) { - if (!(client.currentScreen instanceof AbstractArmorStandScreen)) { - return; - } - - ((AbstractArmorStandScreen) client.currentScreen).onPong(); - } - - public static void sendToClient(ServerPlayerEntity player) { - ServerPlayNetworking.send( - player, - NetworkPackets.PONG_PACKET, - new PongPacket(player.getUuid()).toPacket()); - } - - public static void registerClientReceiver() { - ClientPlayNetworking.registerGlobalReceiver( - NetworkPackets.PONG_PACKET, - (client, handler, buf, responseSender) -> { - PongPacket packet = new PongPacket(buf); - client.execute(() -> { - packet.handleOnClient(client, handler, responseSender); - }); - }); - } -} diff --git a/src/main/java/me/roundaround/armorstands/screen/ArmorStandScreenHandler.java b/src/main/java/me/roundaround/armorstands/screen/ArmorStandScreenHandler.java index 0e36154..181ddb2 100644 --- a/src/main/java/me/roundaround/armorstands/screen/ArmorStandScreenHandler.java +++ b/src/main/java/me/roundaround/armorstands/screen/ArmorStandScreenHandler.java @@ -6,7 +6,7 @@ import me.roundaround.armorstands.entity.ArmorStandInventory; import me.roundaround.armorstands.mixin.ArmorStandEntityAccessor; import me.roundaround.armorstands.network.ScreenType; -import me.roundaround.armorstands.network.packet.s2c.ClientUpdatePacket; +import me.roundaround.armorstands.server.network.ServerNetworking; import me.roundaround.armorstands.util.ArmorStandEditor; import me.roundaround.armorstands.util.HasArmorStand; import me.roundaround.armorstands.util.HasArmorStandEditor; @@ -16,7 +16,9 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.slot.Slot; @@ -26,24 +28,20 @@ import java.util.ArrayList; -public class ArmorStandScreenHandler extends ScreenHandler - implements HasArmorStand, HasArmorStandEditor { - private static final Identifier EMPTY_MAINHAND_ARMOR_SLOT = - new Identifier("item/empty_slot_sword"); +public class ArmorStandScreenHandler extends ScreenHandler implements HasArmorStand, HasArmorStandEditor { + private static final Identifier EMPTY_MAINHAND_ARMOR_SLOT = new Identifier("item/empty_slot_sword"); - private static final Identifier[] EMPTY_ARMOR_SLOT_TEXTURES = new Identifier[] { - PlayerScreenHandler.EMPTY_BOOTS_SLOT_TEXTURE, - PlayerScreenHandler.EMPTY_LEGGINGS_SLOT_TEXTURE, - PlayerScreenHandler.EMPTY_CHESTPLATE_SLOT_TEXTURE, - PlayerScreenHandler.EMPTY_HELMET_SLOT_TEXTURE + private static final Identifier[] EMPTY_ARMOR_SLOT_TEXTURES = new Identifier[]{ + PlayerScreenHandler.EMPTY_BOOTS_SLOT_TEXTURE, PlayerScreenHandler.EMPTY_LEGGINGS_SLOT_TEXTURE, + PlayerScreenHandler.EMPTY_CHESTPLATE_SLOT_TEXTURE, PlayerScreenHandler.EMPTY_HELMET_SLOT_TEXTURE }; - private static final Identifier[] EMPTY_HAND_SLOT_TEXTURES = new Identifier[] { + private static final Identifier[] EMPTY_HAND_SLOT_TEXTURES = new Identifier[]{ EMPTY_MAINHAND_ARMOR_SLOT, PlayerScreenHandler.EMPTY_OFFHAND_ARMOR_SLOT }; - private static final EquipmentSlot[] EQUIPMENT_SLOT_ORDER = new EquipmentSlot[] { + private static final EquipmentSlot[] EQUIPMENT_SLOT_ORDER = new EquipmentSlot[]{ EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET }; - private static final EquipmentSlot[] HAND_SLOT_ORDER = new EquipmentSlot[] { + private static final EquipmentSlot[] HAND_SLOT_ORDER = new EquipmentSlot[]{ EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND }; @@ -55,10 +53,8 @@ public class ArmorStandScreenHandler extends ScreenHandler private final ArrayList> armorSlots = new ArrayList<>(); public ArmorStandScreenHandler( - int syncId, - PlayerInventory playerInventory, - ArmorStandEntity armorStand, - ScreenType screenType) { + int syncId, PlayerInventory playerInventory, ArmorStandEntity armorStand, ScreenType screenType + ) { super(ArmorStandsMod.ARMOR_STAND_SCREEN_HANDLER_TYPE, syncId); this.playerInventory = playerInventory; @@ -81,11 +77,12 @@ public ArmorStandScreenHandler( } public ArmorStandScreenHandler( - int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { - this(syncId, - playerInventory, - (ArmorStandEntity) playerInventory.player.getWorld().getEntityById(buf.readInt()), - ScreenType.fromId(buf.readString())); + int syncId, PlayerInventory playerInventory, Data data + ) { + this(syncId, playerInventory, + (ArmorStandEntity) playerInventory.player.getWorld().getEntityById(data.armorStandId()), + ScreenType.fromId(data.screenTypeId()) + ); } private void initSlots() { @@ -172,7 +169,8 @@ public boolean canInsert(ItemStack stack) { @Override public Pair getBackgroundSprite() { return Pair.of(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, - EMPTY_ARMOR_SLOT_TEXTURES[equipmentSlot.getEntitySlotId()]); + EMPTY_ARMOR_SLOT_TEXTURES[equipmentSlot.getEntitySlotId()] + ); } }); @@ -205,8 +203,7 @@ public PlayerInventory getPlayerInventory() { @Override public void sendContentUpdates() { if (this.playerInventory.player instanceof ServerPlayerEntity) { - ClientUpdatePacket.sendToClient((ServerPlayerEntity) this.playerInventory.player, - this.armorStand); + ServerNetworking.sendClientUpdatePacket((ServerPlayerEntity) this.playerInventory.player, this.armorStand); } super.sendContentUpdates(); @@ -224,8 +221,7 @@ public ItemStack quickMove(PlayerEntity player, int index) { } Slot slot = this.slots.get(index); - - if (slot == null || !slot.hasStack()) { + if (!slot.hasStack()) { return ItemStack.EMPTY; } @@ -241,8 +237,7 @@ public ItemStack quickMove(PlayerEntity player, int index) { ItemStack originalStack = stack.copy(); if (index < PlayerInventory.MAIN_SIZE) { - if (!tryTransferArmor(stack) && !tryTransferToMainHand(stack) && - !tryTransferToOffHand(stack)) { + if (!tryTransferArmor(stack) && !tryTransferToMainHand(stack) && !tryTransferToOffHand(stack)) { return ItemStack.EMPTY; } } else { @@ -289,11 +284,10 @@ private boolean tryTransferToOffHand(ItemStack stack) { } public static boolean isSlotDisabled(ArmorStandEntity armorStand, EquipmentSlot slot) { - return (((ArmorStandEntityAccessor) armorStand).getDisabledSlots() & - 1 << slot.getArmorStandSlotId()) != 0; + return (((ArmorStandEntityAccessor) armorStand).getDisabledSlots() & 1 << slot.getArmorStandSlotId()) != 0; } - public static class Factory implements ExtendedScreenHandlerFactory { + public static class Factory implements ExtendedScreenHandlerFactory { private final ScreenType screenType; private final ArmorStandEntity armorStand; @@ -313,14 +307,20 @@ public Text getDisplayName() { @Override public ScreenHandler createMenu( - int syncId, PlayerInventory playerInventory, PlayerEntity player) { + int syncId, PlayerInventory playerInventory, PlayerEntity player + ) { return new ArmorStandScreenHandler(syncId, playerInventory, this.armorStand, this.screenType); } @Override - public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { - buf.writeInt(this.armorStand.getId()); - buf.writeString(this.screenType.getId()); + public Data getScreenOpeningData(ServerPlayerEntity player) { + return new Data(this.armorStand.getId(), this.screenType.getName()); } } + + public record Data(int armorStandId, String screenTypeId) { + public static final PacketCodec PACKET_CODEC = PacketCodec.tuple(PacketCodecs.INTEGER, + Data::armorStandId, PacketCodecs.STRING, Data::screenTypeId, Data::new + ); + } } diff --git a/src/main/java/me/roundaround/armorstands/server/command/ArmorStandsCommand.java b/src/main/java/me/roundaround/armorstands/server/command/ArmorStandsCommand.java index 11d4304..9fdee5c 100644 --- a/src/main/java/me/roundaround/armorstands/server/command/ArmorStandsCommand.java +++ b/src/main/java/me/roundaround/armorstands/server/command/ArmorStandsCommand.java @@ -20,18 +20,17 @@ import java.util.stream.Stream; public class ArmorStandsCommand { - private static final SimpleCommandExceptionType ADD_FAILED_EXCEPTION = - new SimpleCommandExceptionType(Text.translatable("armorstands.commands.add.failed")); - private static final SimpleCommandExceptionType REMOVE_FAILED_EXCEPTION = - new SimpleCommandExceptionType(Text.translatable("armorstands.commands.remove.failed")); - private static final SimpleCommandExceptionType RELOAD_FAILED_EXCEPTION = - new SimpleCommandExceptionType(Text.translatable("armorstands.commands.reload.failed")); + private static final SimpleCommandExceptionType ADD_FAILED_EXCEPTION = new SimpleCommandExceptionType( + Text.translatable("armorstands.commands.add.failed")); + private static final SimpleCommandExceptionType REMOVE_FAILED_EXCEPTION = new SimpleCommandExceptionType( + Text.translatable("armorstands.commands.remove.failed")); + private static final SimpleCommandExceptionType RELOAD_FAILED_EXCEPTION = new SimpleCommandExceptionType( + Text.translatable("armorstands.commands.reload.failed")); public static void register(CommandDispatcher dispatcher) { - LiteralArgumentBuilder baseCommand = - CommandManager.literal(ArmorStandsMod.MOD_ID) - .requires(source -> source.isExecutedByPlayer() && - (source.hasPermissionLevel(2) || source.getServer().isSingleplayer())); + LiteralArgumentBuilder baseCommand = CommandManager.literal(ArmorStandsMod.MOD_ID) + .requires(source -> source.isExecutedByPlayer() && + (source.hasPermissionLevel(2) || source.getServer().isSingleplayer())); LiteralArgumentBuilder addSub = CommandManager.literal("add") .then(CommandManager.argument("targets", GameProfileArgumentType.gameProfile()) @@ -44,7 +43,8 @@ public static void register(CommandDispatcher dispatcher) { return CommandSource.suggestMatching(playerNames, builder); }) .executes((context) -> executeAdd(context.getSource(), - GameProfileArgumentType.getProfileArgument(context, "targets")))); + GameProfileArgumentType.getProfileArgument(context, "targets") + ))); LiteralArgumentBuilder removeSub = CommandManager.literal("remove") .then(CommandManager.argument("targets", GameProfileArgumentType.gameProfile()) @@ -52,13 +52,13 @@ public static void register(CommandDispatcher dispatcher) { return CommandSource.suggestMatching(ArmorStandUsers.getNames(), builder); }) .executes((context) -> executeRemove(context.getSource(), - GameProfileArgumentType.getProfileArgument(context, "targets")))); + GameProfileArgumentType.getProfileArgument(context, "targets") + ))); - LiteralArgumentBuilder reloadSub = - CommandManager.literal("reload").executes((context) -> executeReload(context.getSource())); + LiteralArgumentBuilder reloadSub = CommandManager.literal("reload") + .executes((context) -> executeReload(context.getSource())); - LiteralArgumentBuilder finalCommand = - baseCommand.then(addSub).then(removeSub).then(reloadSub); + LiteralArgumentBuilder finalCommand = baseCommand.then(addSub).then(removeSub).then(reloadSub); dispatcher.register(finalCommand); } @@ -75,8 +75,7 @@ private static int executeAdd(ServerCommandSource source, Collection Text.translatable("armorstands.commands.add.success", - Text.literal(profile.getName())), true); + source.sendFeedback(() -> Text.translatable("armorstands.commands.add.success", profile.getName()), true); added++; } @@ -99,8 +98,7 @@ private static int executeRemove(ServerCommandSource source, Collection Text.translatable("armorstands.commands.remove.success", - Text.literal(profile.getName())), true); + source.sendFeedback(() -> Text.translatable("armorstands.commands.remove.success", profile.getName()), true); removed++; } diff --git a/src/main/java/me/roundaround/armorstands/server/network/ServerNetworking.java b/src/main/java/me/roundaround/armorstands/server/network/ServerNetworking.java new file mode 100644 index 0000000..a1cc235 --- /dev/null +++ b/src/main/java/me/roundaround/armorstands/server/network/ServerNetworking.java @@ -0,0 +1,208 @@ +package me.roundaround.armorstands.server.network; + +import me.roundaround.armorstands.network.Networking; +import me.roundaround.armorstands.screen.ArmorStandScreenHandler; +import me.roundaround.armorstands.util.ArmorStandEditor; +import me.roundaround.armorstands.util.HasArmorStandEditor; +import me.roundaround.armorstands.util.LastUsedScreen; +import me.roundaround.armorstands.util.actions.AdjustPosAction; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.function.Supplier; + +public final class ServerNetworking { + private ServerNetworking() { + } + + public static void sendClientUpdatePacket(ServerPlayerEntity player, ArmorStandEntity armorStand) { + if (ServerPlayNetworking.canSend(player, Networking.ClientUpdateS2C.ID)) { + ServerPlayNetworking.send(player, new Networking.ClientUpdateS2C(armorStand)); + } + } + + public static void sendMessagePacket(ServerPlayerEntity player, String message) { + if (ServerPlayNetworking.canSend(player, Networking.MessageS2C.ID)) { + ServerPlayNetworking.send(player, new Networking.MessageS2C(message)); + } + } + + public static void sendMessagePacket(ServerPlayerEntity player, String message, int color) { + if (ServerPlayNetworking.canSend(player, Networking.MessageS2C.ID)) { + ServerPlayNetworking.send(player, new Networking.MessageS2C(message, color)); + } + } + + public static void sendPongPacket(ServerPlayerEntity player) { + ServerPlayNetworking.send(player, new Networking.PongS2C(player.getUuid())); + } + + public static void registerReceivers() { + ServerPlayNetworking.registerGlobalReceiver(Networking.AdjustPoseC2S.ID, ServerNetworking::handleAdjustPose); + ServerPlayNetworking.registerGlobalReceiver(Networking.AdjustPosC2S.ID, ServerNetworking::handleAdjustPos); + ServerPlayNetworking.registerGlobalReceiver(Networking.AdjustYawC2S.ID, ServerNetworking::handleAdjustYaw); + ServerPlayNetworking.registerGlobalReceiver(Networking.PingC2S.ID, ServerNetworking::handlePing); + ServerPlayNetworking.registerGlobalReceiver(Networking.RequestScreenC2S.ID, ServerNetworking::handleRequestScreen); + ServerPlayNetworking.registerGlobalReceiver(Networking.SetFlagC2S.ID, ServerNetworking::handleSetFlag); + ServerPlayNetworking.registerGlobalReceiver(Networking.SetPoseC2S.ID, ServerNetworking::handleSetPose); + ServerPlayNetworking.registerGlobalReceiver(Networking.SetPosePresetC2S.ID, ServerNetworking::handleSetPosePreset); + ServerPlayNetworking.registerGlobalReceiver(Networking.SetYawC2S.ID, ServerNetworking::handleSetYaw); + ServerPlayNetworking.registerGlobalReceiver(Networking.UndoC2S.ID, ServerNetworking::handleUndo); + ServerPlayNetworking.registerGlobalReceiver(Networking.UtilityActionC2S.ID, ServerNetworking::handleUtilityAction); + } + + private static void handleAdjustPose(Networking.AdjustPoseC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ScreenHandler currentScreenHandler = context.player().currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.adjustPose(payload.part(), payload.parameter(), payload.amount()); + }); + } + + private static void handleAdjustPos(Networking.AdjustPosC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ScreenHandler currentScreenHandler = context.player().currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.applyAction(payload.mode().isLocal() ? + AdjustPosAction.local(payload.direction(), payload.amount(), payload.units(), + payload.mode().isLocalToPlayer() + ) : + AdjustPosAction.relative(payload.direction(), payload.amount(), payload.units())); + }); + } + + private static void handleAdjustYaw(Networking.AdjustYawC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ScreenHandler currentScreenHandler = context.player().currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.rotate(payload.amount()); + }); + } + + private static void handlePing(Networking.PingC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + sendPongPacket(context.player()); + }); + } + + private static void handleRequestScreen(Networking.RequestScreenC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ServerPlayerEntity player = context.player(); + Entity entity = player.getServerWorld().getEntityById(payload.armorStandId()); + if (!(entity instanceof ArmorStandEntity armorStand)) { + return; + } + + if (player.currentScreenHandler instanceof ArmorStandScreenHandler) { + // Bypass the normal screen closing logic, as we don't want to send a + // close packet to the client. + player.onHandledScreenClosed(); + } + + LastUsedScreen.set(player, armorStand, payload.screenType()); + player.openHandledScreen(ArmorStandScreenHandler.Factory.create(payload.screenType(), armorStand)); + }); + } + + private static void handleSetFlag(Networking.SetFlagC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ServerPlayerEntity player = context.player(); + ScreenHandler currentScreenHandler = player.currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.setFlag(payload.flag(), payload.value()); + + sendClientUpdatePacket(player, editor.getArmorStand()); + }); + } + + private static void handleSetPose(Networking.SetPoseC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ScreenHandler currentScreenHandler = context.player().currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.setPose(payload.head(), payload.body(), payload.rightArm(), payload.leftArm(), payload.rightLeg(), + payload.leftLeg() + ); + }); + } + + private static void handleSetPosePreset(Networking.SetPosePresetC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ScreenHandler currentScreenHandler = context.player().currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.setPose(payload.pose().toPose()); + }); + } + + private static void handleSetYaw(Networking.SetYawC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ScreenHandler currentScreenHandler = context.player().currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + editor.setRotation(payload.angle()); + }); + } + + private static void handleUndo(Networking.UndoC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ServerPlayerEntity player = context.player(); + ScreenHandler currentScreenHandler = player.currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + Supplier action = payload.redo() ? editor::redo : editor::undo; + String successMessage = payload.redo() ? "armorstands.message.redo" : "armorstands.message.undo"; + String failureMessage = payload.redo() ? "armorstands.message.redo.fail" : "armorstands.message.undo.fail"; + + if (action.get()) { + sendMessagePacket(player, successMessage); + } else { + sendMessagePacket(player, failureMessage); + } + }); + } + + private static void handleUtilityAction(Networking.UtilityActionC2S payload, ServerPlayNetworking.Context context) { + context.player().server.execute(() -> { + ServerPlayerEntity player = context.player(); + ScreenHandler currentScreenHandler = player.currentScreenHandler; + if (!(currentScreenHandler instanceof HasArmorStandEditor screenHandler)) { + return; + } + + ArmorStandEditor editor = screenHandler.getEditor(); + payload.action().apply(editor, player); + }); + } +} diff --git a/src/main/java/me/roundaround/armorstands/util/Clipboard.java b/src/main/java/me/roundaround/armorstands/util/Clipboard.java index 3da591e..a267f53 100644 --- a/src/main/java/me/roundaround/armorstands/util/Clipboard.java +++ b/src/main/java/me/roundaround/armorstands/util/Clipboard.java @@ -1,21 +1,21 @@ package me.roundaround.armorstands.util; -import java.util.HashMap; -import java.util.Optional; -import java.util.UUID; - -import me.roundaround.armorstands.network.packet.s2c.MessagePacket; +import me.roundaround.armorstands.server.network.ServerNetworking; import me.roundaround.armorstands.util.actions.ClipboardPasteAction; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.network.ServerPlayerEntity; +import java.util.HashMap; +import java.util.Optional; +import java.util.UUID; + public class Clipboard { private static final HashMap entries = new HashMap<>(); public static void copy(ServerPlayerEntity player, ArmorStandEntity armorStand) { entries.put(player.getUuid(), Entry.everything(armorStand)); - MessagePacket.sendToClient(player, "armorstands.message.copy"); + ServerNetworking.sendMessagePacket(player, "armorstands.message.copy"); } public static boolean paste(ServerPlayerEntity player, ArmorStandEditor editor) { @@ -24,7 +24,7 @@ public static boolean paste(ServerPlayerEntity player, ArmorStandEditor editor) } editor.applyAction(ClipboardPasteAction.create(entries.get(player.getUuid()))); - MessagePacket.sendToClient(player, "armorstands.message.paste"); + ServerNetworking.sendMessagePacket(player, "armorstands.message.paste"); return true; } diff --git a/src/main/java/me/roundaround/armorstands/util/MoveMode.java b/src/main/java/me/roundaround/armorstands/util/MoveMode.java index ba81fa6..52a36ca 100644 --- a/src/main/java/me/roundaround/armorstands/util/MoveMode.java +++ b/src/main/java/me/roundaround/armorstands/util/MoveMode.java @@ -1,70 +1,83 @@ -package me.roundaround.armorstands.util; - -import net.minecraft.text.Text; -import net.minecraft.util.math.Direction; - -public enum MoveMode { - RELATIVE("relative", false, false), - LOCAL_TO_STAND("stand", true, false), - LOCAL_TO_PLAYER("player", true, true); - - private final String id; - private final boolean local; - private final boolean player; - - private MoveMode(String id, boolean local, boolean player) { - this.id = id; - this.local = local; - this.player = player; - } - - public String getId() { - return this.id; - } - - public boolean isLocal() { - return this.local; - } - - public boolean isLocalToPlayer() { - return this.player; - } - - public MoveUnits getDefaultUnits() { - switch (this) { - case RELATIVE: - return MoveUnits.PIXELS; - case LOCAL_TO_STAND: - case LOCAL_TO_PLAYER: - return MoveUnits.BLOCKS; - } - - return MoveUnits.PIXELS; - } - - public Text getOptionValueText() { - return Text.translatable("armorstands.move.mode." + this.id); - } - - public Text getDirectionText(Direction direction) { - if (this.equals(RELATIVE)) { - return Text.translatable("armorstands.move." + direction.getName()); - } else { - return Text.translatable("armorstands.move.local." + direction.getName()); - } - } - - public static Text getOptionLabelText() { - return Text.translatable("armorstands.move.mode"); - } - - public static MoveMode fromId(String id) { - for (MoveMode mode : MoveMode.values()) { - if (mode.getId().equals(id)) { - return mode; - } - } - - return RELATIVE; - } -} +package me.roundaround.armorstands.util; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.text.Text; +import net.minecraft.util.function.ValueLists; +import net.minecraft.util.math.Direction; + +import java.util.function.IntFunction; + +public enum MoveMode { + RELATIVE(0, "relative", false, false), + LOCAL_TO_STAND(1, "stand", true, false), + LOCAL_TO_PLAYER(2, "player", true, true); + + public static final IntFunction ID_TO_VALUE_FUNCTION = ValueLists.createIdToValueFunction( + MoveMode::getId, values(), ValueLists.OutOfBoundsHandling.CLAMP); + public static final PacketCodec PACKET_CODEC = PacketCodecs.indexed( + ID_TO_VALUE_FUNCTION, MoveMode::getId); + + private final int id; + private final String name; + private final boolean local; + private final boolean player; + + MoveMode(int id, String name, boolean local, boolean player) { + this.id = id; + this.name = name; + this.local = local; + this.player = player; + } + + public int getId() { + return this.id; + } + + public String getName() { + return this.name; + } + + public boolean isLocal() { + return this.local; + } + + public boolean isLocalToPlayer() { + return this.player; + } + + public MoveUnits getDefaultUnits() { + return switch (this) { + case RELATIVE -> MoveUnits.PIXELS; + case LOCAL_TO_STAND, LOCAL_TO_PLAYER -> MoveUnits.BLOCKS; + }; + + } + + public Text getOptionValueText() { + return Text.translatable("armorstands.move.mode." + this.name); + } + + public Text getDirectionText(Direction direction) { + if (this.equals(RELATIVE)) { + return Text.translatable("armorstands.move." + direction.getName()); + } else { + return Text.translatable("armorstands.move.local." + direction.getName()); + } + } + + public static Text getOptionLabelText() { + return Text.translatable("armorstands.move.mode"); + } + + public static MoveMode fromId(String id) { + for (MoveMode mode : MoveMode.values()) { + if (mode.getName().equals(id)) { + return mode; + } + } + + return RELATIVE; + } +} diff --git a/src/main/java/me/roundaround/armorstands/util/MoveUnits.java b/src/main/java/me/roundaround/armorstands/util/MoveUnits.java index 2ee2a43..e985104 100644 --- a/src/main/java/me/roundaround/armorstands/util/MoveUnits.java +++ b/src/main/java/me/roundaround/armorstands/util/MoveUnits.java @@ -1,75 +1,81 @@ -package me.roundaround.armorstands.util; - -import net.minecraft.text.Text; - -public enum MoveUnits { - PIXELS("pixels"), - BLOCKS("blocks"); - - private final String id; - - private MoveUnits(String id) { - this.id = id; - } - - public String getId() { - return this.id; - } - - public Text getOptionValueText() { - return Text.translatable("armorstands.move.units." + this.id); - } - - public Text getButtonText(int amount) { - return Text.translatable("armorstands.move." + this.id + "." + amount); - } - - public double getAmount(int amount) { - switch (this) { - case PIXELS: - return getPixelAmount(amount); - case BLOCKS: - return getBlockAmount(amount); - } - - return 0; - } - - private static double getPixelAmount(int amount) { - // 1, 3, and 8 pixels - switch (amount) { - case 2: - return 0.1875; - case 3: - return 0.5; - default: - return 0.0625; - } - } - - private static double getBlockAmount(int amount) { - // 1/4, 1/3, and 1 block - switch (amount) { - case 2: - return 1d / 3d; - case 3: - return 1; - default: - return 0.25; - } - } - - public static Text getOptionLabelText() { - return Text.translatable("armorstands.move.units"); - } - - public static MoveUnits fromId(String id) { - for (MoveUnits units : MoveUnits.values()) { - if (units.getId().equals(id)) { - return units; - } - } - - return PIXELS; - } -} +package me.roundaround.armorstands.util; + +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.text.Text; +import net.minecraft.util.function.ValueLists; + +import java.util.function.IntFunction; + +public enum MoveUnits { + PIXELS(0, "pixels"), BLOCKS(1, "blocks"); + + public static final IntFunction ID_TO_VALUE_FUNCTION = ValueLists.createIdToValueFunction( + MoveUnits::getId, values(), ValueLists.OutOfBoundsHandling.CLAMP); + public static final PacketCodec PACKET_CODEC = PacketCodecs.indexed( + ID_TO_VALUE_FUNCTION, MoveUnits::getId); + + private final int id; + private final String name; + + MoveUnits(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return this.id; + } + + public String getName() { + return this.name; + } + + public Text getOptionValueText() { + return Text.translatable("armorstands.move.units." + this.name); + } + + public Text getButtonText(int amount) { + return Text.translatable("armorstands.move." + this.name + "." + amount); + } + + public double getAmount(int amount) { + return switch (this) { + case PIXELS -> getPixelAmount(amount); + case BLOCKS -> getBlockAmount(amount); + }; + } + + private static double getPixelAmount(int amount) { + // 1, 3, and 8 pixels + return switch (amount) { + case 2 -> 0.1875; + case 3 -> 0.5; + default -> 0.0625; + }; + } + + private static double getBlockAmount(int amount) { + // 1/4, 1/3, and 1 block + return switch (amount) { + case 2 -> 1d / 3d; + case 3 -> 1; + default -> 0.25; + }; + } + + public static Text getOptionLabelText() { + return Text.translatable("armorstands.move.units"); + } + + public static MoveUnits fromId(String id) { + for (MoveUnits units : MoveUnits.values()) { + if (units.getName().equals(id)) { + return units; + } + } + + return PIXELS; + } +} diff --git a/src/main/java/me/roundaround/armorstands/util/PosePreset.java b/src/main/java/me/roundaround/armorstands/util/PosePreset.java index 70120f3..7eec8ca 100644 --- a/src/main/java/me/roundaround/armorstands/util/PosePreset.java +++ b/src/main/java/me/roundaround/armorstands/util/PosePreset.java @@ -1,375 +1,165 @@ package me.roundaround.armorstands.util; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - +import io.netty.buffer.ByteBuf; import me.roundaround.armorstands.ArmorStandsMod; import me.roundaround.armorstands.util.Pose.PoseSupplier; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; import net.minecraft.text.Text; import net.minecraft.util.math.EulerAngle; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + public enum PosePreset implements PoseSupplier { - DEFAULT( - "default", - Source.VANILLA, - Category.STANDING, - new EulerAngle(0f, 0f, 0f), - new EulerAngle(0f, 0f, 0f), - new EulerAngle(-15f, 0f, 10f), - new EulerAngle(-10f, 0f, -10f), - new EulerAngle(1f, 0f, 1f), - new EulerAngle(-1f, 0f, -1f)), - ATTENTION( - "attention", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(0f, 0f, 0f), - new EulerAngle(0f, 0f, 0f), - new EulerAngle(0f, 0f, 0f), - new EulerAngle(0f, 0f, 0f)), - CONFIDENT( - "confident", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(-10f, 20f, 0f), - new EulerAngle(-2f, 0f, 0f), - new EulerAngle(5f, 0f, 0f), - new EulerAngle(5f, 0f, 0f), - new EulerAngle(16f, 2f, 10f), - new EulerAngle(0f, -10f, -4f)), - WALKING( - "walking", - Source.VANILLA_TWEAKS, - Category.MOVING, - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(20f, 0f, 10f), - new EulerAngle(-20f, 0f, -10f), - new EulerAngle(-20f, 0f, 0f), - new EulerAngle(20f, 0f, 0f)), - RUNNING( - "running", - Source.VANILLA_TWEAKS, - Category.MOVING, - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(-40f, 0f, 10f), - new EulerAngle(40f, 0f, -10f), - new EulerAngle(-40f, 0f, 0f), - new EulerAngle(40f, 0f, 0f)), - LUNGING( - "lunging", - Source.VANILLA_TWEAKS, - Category.MOVING, - new EulerAngle(0.0f, 0.001f, 0.0f), - new EulerAngle(15.0f, 0.0f, 0.0f), - new EulerAngle(-60.0f, -10.0f, 0.0f), - new EulerAngle(10.0f, 0.0f, -10.0f), - new EulerAngle(-15.0f, 0.0f, 0.0f), - new EulerAngle(30.0f, 0.0f, 0.0f)), - POINTING( - "pointing", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(0f, 20f, 0f), - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(-90f, 18f, 0f), - new EulerAngle(0f, 0f, -10f), - new EulerAngle(0f, 0f, 0f), - new EulerAngle(0f, 0f, 0f)), - FACEPALM( - "facepalm", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(45f, -4f, 1f), - new EulerAngle(10f, 0f, 0f), - new EulerAngle(18f, -14f, 0f), - new EulerAngle(-72f, 24f, 47f), - new EulerAngle(25f, -2f, 0f), - new EulerAngle(-4f, -6f, -2f)), - BLOCKING( - "blocking", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(-20f, -20f, 0f), - new EulerAngle(-50f, 50f, 0f), - new EulerAngle(-20f, 0f, 0f), - new EulerAngle(20f, 0f, 0f)), - CONFUSED( - "confused", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(0.0f, 30.0f, 0f), - new EulerAngle(0.0f, 13.0f, 0.0f), - new EulerAngle(-22.0f, 31.0f, 10.0f), - new EulerAngle(145.0f, 22.0f, -49.0f), - new EulerAngle(6.0f, -20.0f, 0.0f), - new EulerAngle(-6.0f, 0.0f, 0.0f)), - WINNING( - "winning", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(-15.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.001f, 0.0f), - new EulerAngle(-120.0f, -10.0f, 0.0f), - new EulerAngle(10.0f, 0.0f, -10.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(15.0f, 0.0f, 0.0f)), - FORMAL( - "formal", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(4.0f, 0.0f, 0.0f), - new EulerAngle(4.0f, 0.0f, 0.0f), - new EulerAngle(30.0f, 22.0f, -20.0f), - new EulerAngle(30.0f, -20.0f, 21.0f), - new EulerAngle(0.0f, 0.0f, 5.0f), - new EulerAngle(0.0f, 0.0f, -5.0f)), - SALUTE( - "salute", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(0f, 0.001f, 0f), - new EulerAngle(5f, 0f, 0f), - new EulerAngle(-124f, -51f, -35f), - new EulerAngle(29f, 0f, 25f), - new EulerAngle(0f, -4f, -2f), - new EulerAngle(0f, 4f, 2f)), - SAD( - "sad", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(63.0f, 0.0f, 0.0f), - new EulerAngle(10.0f, 0.0f, 0.0f), - new EulerAngle(-5.0f, 0.0f, 5.0f), - new EulerAngle(-5.0f, 0.0f, -5.0f), - new EulerAngle(-5.0f, -10.0f, 5.0f), - new EulerAngle(-5.0f, 16.0f, -5.0f)), - ARABESQUE( - "arabesque", - Source.VANILLA_TWEAKS, - Category.DYNAMIC, - new EulerAngle(-15.0f, 0.0f, 0.0f), - new EulerAngle(10.0f, 0.0f, 0.0f), - new EulerAngle(-140.0f, -10.0f, 0.0f), - new EulerAngle(70.0f, 0.0f, -10.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(75.0f, 0.0f, 0.0f)), - CANCAN( - "cancan", - Source.BEDROCK, - Category.DYNAMIC, - new EulerAngle(-5.0f, 18.0f, 0.0f), - new EulerAngle(0.0f, 22.0f, 0.0f), - new EulerAngle(0.0f, 84.0f, 111.0f), - new EulerAngle(8.0f, 0.0f, -114.0f), - new EulerAngle(0.0f, 23.0f, -13.0f), - new EulerAngle(-111.0f, 55.0f, 0.0f)), - JOYOUS( - "joyous", - Source.VANILLA_TWEAKS, - Category.DYNAMIC, - new EulerAngle(-11.0f, 0.0f, 0.0f), - new EulerAngle(-4.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 100.0f), - new EulerAngle(0.0f, 0.0f, -100.0f), - new EulerAngle(-8.0f, 0.0f, 60.0f), - new EulerAngle(-8.0f, 0.0f, -60.0f)), - CUPID( - "cupid", - Source.VANILLA_TWEAKS, - Category.DYNAMIC, - new EulerAngle(0.0f, 0.001f, 0.0f), - new EulerAngle(10.0f, 0.0f, 0.0f), - new EulerAngle(-90.0f, -10.0f, 0.0f), - new EulerAngle(-75.0f, 0.0f, 10.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(75.0f, 0.0f, 0.0f)), - STARGAZING( - "stargazing", - Source.VANILLA_TWEAKS, - Category.STANDING, - new EulerAngle(-22.0f, 25.0f, 0.0f), - new EulerAngle(-4.0f, 10.0f, 0.0f), - new EulerAngle(-153.0f, 34.0f, -3.0f), - new EulerAngle(4.0f, 18.0f, 0.0f), - new EulerAngle(-4.0f, 17.0f, 2.0f), - new EulerAngle(6.0f, 24.0f, 0.0f)), - GUARD( - "guard", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(-5.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 2.0f), - new EulerAngle(-60.0f, 20.0f, -10.0f), - new EulerAngle(10.0f, 0.0f, -5.0f), - new EulerAngle(3.0f, 3.0f, 3.0f), - new EulerAngle(-3.0f, -3.0f, -3.0f)), - BRANDISH( - "brandish", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(-15.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, -2.0f), - new EulerAngle(-110.0f, 50.0f, 0.0f), - new EulerAngle(20.0f, 0.0f, -10.0f), - new EulerAngle(-5.0f, 3.0f, 3.0f), - new EulerAngle(5.0f, -3.0f, -3.0f)), - SPEAKING( - "speaking", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(-15.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(-110.0f, 35.0f, 0.0f), - new EulerAngle(-110.0f, -35.0f, 0.0f), - new EulerAngle(-5.0f, 3.0f, 3.0f), - new EulerAngle(5.0f, -3.0f, -3.0f)), - INSPIRING( - "inspiring", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(-4.0f, 67.0f, 0.0f), - new EulerAngle(0.0f, 8.0f, 0.0f), - new EulerAngle(-99.0f, 63.0f, 0.0f), - new EulerAngle(16.0f, 32.0f, -8.0f), - new EulerAngle(4.0f, 63.0f, 8.0f), - new EulerAngle(0.0f, -75.0f, -8.0f)), - THANKING( - "thanking", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(-15.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(-110.0f, -35.0f, 0.0f), - new EulerAngle(-110.0f, 35.0f, 0.0f), - new EulerAngle(-5.0f, 3.0f, 3.0f), - new EulerAngle(5.0f, -3.0f, -3.0f)), - DABBING( - "dabbing", - Source.BEDROCK, - Category.DYNAMIC, - new EulerAngle(16.0f, 20.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(246.0f, 0.0f, 89.0f), - new EulerAngle(4.0f, 8.0f, 237.0f), - new EulerAngle(8.0f, 20.0f, 4.0f), - new EulerAngle(-14.0f, -18.0f, -16.0f)), - PLEDGING( - "pledging", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(-70.0f, -40.0f, 0.0f), - new EulerAngle(10.0f, 0.0f, -5.0f), - new EulerAngle(1.0f, 0.0f, 1.0f), - new EulerAngle(-1.0f, 0.0f, -1.0f)), - CONTEMPLATING( - "contemplating", - Source.BEDROCK, - Category.STANDING, - new EulerAngle(15.0f, 0.0f, 0.0f), - new EulerAngle(0.0f, 0.0f, 2.0f), - new EulerAngle(-60.0f, -20.0f, -10.0f), - new EulerAngle(-30.0f, 15.0f, 15.0f), - new EulerAngle(1.0f, 0.0f, 1.0f), - new EulerAngle(-1.0f, 0.0f, -1.0f)), - ZOMBIE( - "zombie", - Source.BEDROCK, - Category.MOVING, - new EulerAngle(-10.0f, 0.0f, -5.0f), - new EulerAngle(0.0f, 0.0f, 0.0f), - new EulerAngle(-100.0f, 0.0f, 0.0f), - new EulerAngle(-105.0f, 0.0f, 0.0f), - new EulerAngle(-46.0f, 0.0f, 0.0f), - new EulerAngle(7.0f, 0.0f, 0.0f)), - SITTING( - "sitting", - Source.VANILLA_TWEAKS, - Category.SITTING, - new EulerAngle(0.0f, 0.001f, 0.0f), - new EulerAngle(0.0f, 0.001f, 0.0f), - new EulerAngle(-80.0f, 20.0f, 0.0f), - new EulerAngle(-80.0f, -20.0f, 0.0f), - new EulerAngle(-90.0f, 10.0f, 0.0f), - new EulerAngle(-90.0f, -10.0f, 0.0f)), - LAZING( - "lazing", - Source.VANILLA_TWEAKS, - Category.SITTING, - new EulerAngle(14f, -12f, 6f), - new EulerAngle(5f, 0f, 0f), - new EulerAngle(-40f, 20f, 0f), - new EulerAngle(-4f, -20f, -10f), - new EulerAngle(-88f, 71f, 0f), - new EulerAngle(-88f, 46f, 0f)), - JUMP_ATTACK( - "jumpAttack", - Source.ROUNDAROUND, - Category.DYNAMIC, - new EulerAngle(-43f, 0f, 0f), - new EulerAngle(4f, 0f, 0f), - new EulerAngle(-144f, -10f, 28f), - new EulerAngle(-129f, 47f, -7f), - new EulerAngle(30f, 0f, 20f), - new EulerAngle(30f, 0f, -20f)), - STEWARD( - "steward", - Source.ROUNDAROUND, - Category.STANDING, - new EulerAngle(-3f, 0f, 0f), - new EulerAngle(0f, 0f, 2f), - new EulerAngle(-105f, -45f, 180f), - new EulerAngle(-2f, 0f, -20f), - new EulerAngle(0f, 0f, 5f), - new EulerAngle(0f, 0f, -5f)), - SCARECROW( - "scarecrow", - Source.ROUNDAROUND, - Category.DYNAMIC, - new EulerAngle(8f, 26f, -6f), - new EulerAngle(0f, 0f, 5f), - new EulerAngle(-15f, 0f, 79f), - new EulerAngle(-16f, 0f, -40f), - new EulerAngle(0f, 0f, -18f), - new EulerAngle(16f, 20f, 0f)), - PRETTY( - "pretty", - Source.ROUNDAROUND, - Category.SITTING, - new EulerAngle(-17f, 0f, 0f), - new EulerAngle(0f, 0f, -8f), - new EulerAngle(-12f, 20f, 0f), - new EulerAngle(130f, -14f, -3f), - new EulerAngle(-100f, -44f, 0f), - new EulerAngle(-90f, -10f, 0f)), - DRUM_MAJOR( - "drumMajor", - Source.ROUNDAROUND, - Category.DYNAMIC, - new EulerAngle(-13f, 0f, 0f), - new EulerAngle(9f, 0f, 0f), - new EulerAngle(110f, 125f, 180f), - new EulerAngle(-10f, 0f, -20f), - new EulerAngle(-94f, 0f, 0f), - new EulerAngle(15f, 0f, 0f)), - FISHING( - "fishing", - Source.ROUNDAROUND, - Category.SITTING, - new EulerAngle(-15f, 0f, -12f), - new EulerAngle(-8f, 0f, 0f), - new EulerAngle(-68f, -24f, 0f), - new EulerAngle(-80f, 44f, 0f), - new EulerAngle(-90f, 20f, 0f), - new EulerAngle(-90f, -20f, 0f)); + DEFAULT("default", Source.VANILLA, Category.STANDING, new EulerAngle(0f, 0f, 0f), new EulerAngle(0f, 0f, 0f), + new EulerAngle(-15f, 0f, 10f), new EulerAngle(-10f, 0f, -10f), new EulerAngle(1f, 0f, 1f), + new EulerAngle(-1f, 0f, -1f) + ), + ATTENTION("attention", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(0f, 0.001f, 0f), + new EulerAngle(0f, 0.001f, 0f), new EulerAngle(0f, 0f, 0f), new EulerAngle(0f, 0f, 0f), + new EulerAngle(0f, 0f, 0f), new EulerAngle(0f, 0f, 0f) + ), + CONFIDENT("confident", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(-10f, 20f, 0f), + new EulerAngle(-2f, 0f, 0f), new EulerAngle(5f, 0f, 0f), new EulerAngle(5f, 0f, 0f), new EulerAngle(16f, 2f, 10f), + new EulerAngle(0f, -10f, -4f) + ), + WALKING("walking", Source.VANILLA_TWEAKS, Category.MOVING, new EulerAngle(0f, 0.001f, 0f), + new EulerAngle(0f, 0.001f, 0f), new EulerAngle(20f, 0f, 10f), new EulerAngle(-20f, 0f, -10f), + new EulerAngle(-20f, 0f, 0f), new EulerAngle(20f, 0f, 0f) + ), + RUNNING("running", Source.VANILLA_TWEAKS, Category.MOVING, new EulerAngle(0f, 0.001f, 0f), + new EulerAngle(0f, 0.001f, 0f), new EulerAngle(-40f, 0f, 10f), new EulerAngle(40f, 0f, -10f), + new EulerAngle(-40f, 0f, 0f), new EulerAngle(40f, 0f, 0f) + ), + LUNGING("lunging", Source.VANILLA_TWEAKS, Category.MOVING, new EulerAngle(0.0f, 0.001f, 0.0f), + new EulerAngle(15.0f, 0.0f, 0.0f), new EulerAngle(-60.0f, -10.0f, 0.0f), new EulerAngle(10.0f, 0.0f, -10.0f), + new EulerAngle(-15.0f, 0.0f, 0.0f), new EulerAngle(30.0f, 0.0f, 0.0f) + ), + POINTING("pointing", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(0f, 20f, 0f), + new EulerAngle(0f, 0.001f, 0f), new EulerAngle(-90f, 18f, 0f), new EulerAngle(0f, 0f, -10f), + new EulerAngle(0f, 0f, 0f), new EulerAngle(0f, 0f, 0f) + ), + FACEPALM("facepalm", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(45f, -4f, 1f), + new EulerAngle(10f, 0f, 0f), new EulerAngle(18f, -14f, 0f), new EulerAngle(-72f, 24f, 47f), + new EulerAngle(25f, -2f, 0f), new EulerAngle(-4f, -6f, -2f) + ), + BLOCKING("blocking", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(0f, 0.001f, 0f), + new EulerAngle(0f, 0.001f, 0f), new EulerAngle(-20f, -20f, 0f), new EulerAngle(-50f, 50f, 0f), + new EulerAngle(-20f, 0f, 0f), new EulerAngle(20f, 0f, 0f) + ), + CONFUSED("confused", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(0.0f, 30.0f, 0f), + new EulerAngle(0.0f, 13.0f, 0.0f), new EulerAngle(-22.0f, 31.0f, 10.0f), new EulerAngle(145.0f, 22.0f, -49.0f), + new EulerAngle(6.0f, -20.0f, 0.0f), new EulerAngle(-6.0f, 0.0f, 0.0f) + ), + WINNING("winning", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(-15.0f, 0.0f, 0.0f), + new EulerAngle(0.0f, 0.001f, 0.0f), new EulerAngle(-120.0f, -10.0f, 0.0f), new EulerAngle(10.0f, 0.0f, -10.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(15.0f, 0.0f, 0.0f) + ), + FORMAL("formal", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(4.0f, 0.0f, 0.0f), + new EulerAngle(4.0f, 0.0f, 0.0f), new EulerAngle(30.0f, 22.0f, -20.0f), new EulerAngle(30.0f, -20.0f, 21.0f), + new EulerAngle(0.0f, 0.0f, 5.0f), new EulerAngle(0.0f, 0.0f, -5.0f) + ), + SALUTE("salute", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(0f, 0.001f, 0f), new EulerAngle(5f, 0f, 0f), + new EulerAngle(-124f, -51f, -35f), new EulerAngle(29f, 0f, 25f), new EulerAngle(0f, -4f, -2f), + new EulerAngle(0f, 4f, 2f) + ), + SAD("sad", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(63.0f, 0.0f, 0.0f), + new EulerAngle(10.0f, 0.0f, 0.0f), new EulerAngle(-5.0f, 0.0f, 5.0f), new EulerAngle(-5.0f, 0.0f, -5.0f), + new EulerAngle(-5.0f, -10.0f, 5.0f), new EulerAngle(-5.0f, 16.0f, -5.0f) + ), + ARABESQUE("arabesque", Source.VANILLA_TWEAKS, Category.DYNAMIC, new EulerAngle(-15.0f, 0.0f, 0.0f), + new EulerAngle(10.0f, 0.0f, 0.0f), new EulerAngle(-140.0f, -10.0f, 0.0f), new EulerAngle(70.0f, 0.0f, -10.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(75.0f, 0.0f, 0.0f) + ), + CANCAN("cancan", Source.BEDROCK, Category.DYNAMIC, new EulerAngle(-5.0f, 18.0f, 0.0f), + new EulerAngle(0.0f, 22.0f, 0.0f), new EulerAngle(0.0f, 84.0f, 111.0f), new EulerAngle(8.0f, 0.0f, -114.0f), + new EulerAngle(0.0f, 23.0f, -13.0f), new EulerAngle(-111.0f, 55.0f, 0.0f) + ), + JOYOUS("joyous", Source.VANILLA_TWEAKS, Category.DYNAMIC, new EulerAngle(-11.0f, 0.0f, 0.0f), + new EulerAngle(-4.0f, 0.0f, 0.0f), new EulerAngle(0.0f, 0.0f, 100.0f), new EulerAngle(0.0f, 0.0f, -100.0f), + new EulerAngle(-8.0f, 0.0f, 60.0f), new EulerAngle(-8.0f, 0.0f, -60.0f) + ), + CUPID("cupid", Source.VANILLA_TWEAKS, Category.DYNAMIC, new EulerAngle(0.0f, 0.001f, 0.0f), + new EulerAngle(10.0f, 0.0f, 0.0f), new EulerAngle(-90.0f, -10.0f, 0.0f), new EulerAngle(-75.0f, 0.0f, 10.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(75.0f, 0.0f, 0.0f) + ), + STARGAZING("stargazing", Source.VANILLA_TWEAKS, Category.STANDING, new EulerAngle(-22.0f, 25.0f, 0.0f), + new EulerAngle(-4.0f, 10.0f, 0.0f), new EulerAngle(-153.0f, 34.0f, -3.0f), new EulerAngle(4.0f, 18.0f, 0.0f), + new EulerAngle(-4.0f, 17.0f, 2.0f), new EulerAngle(6.0f, 24.0f, 0.0f) + ), + GUARD("guard", Source.BEDROCK, Category.STANDING, new EulerAngle(-5.0f, 0.0f, 0.0f), new EulerAngle(0.0f, 0.0f, 2.0f), + new EulerAngle(-60.0f, 20.0f, -10.0f), new EulerAngle(10.0f, 0.0f, -5.0f), new EulerAngle(3.0f, 3.0f, 3.0f), + new EulerAngle(-3.0f, -3.0f, -3.0f) + ), + BRANDISH("brandish", Source.BEDROCK, Category.STANDING, new EulerAngle(-15.0f, 0.0f, 0.0f), + new EulerAngle(0.0f, 0.0f, -2.0f), new EulerAngle(-110.0f, 50.0f, 0.0f), new EulerAngle(20.0f, 0.0f, -10.0f), + new EulerAngle(-5.0f, 3.0f, 3.0f), new EulerAngle(5.0f, -3.0f, -3.0f) + ), + SPEAKING("speaking", Source.BEDROCK, Category.STANDING, new EulerAngle(-15.0f, 0.0f, 0.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(-110.0f, 35.0f, 0.0f), new EulerAngle(-110.0f, -35.0f, 0.0f), + new EulerAngle(-5.0f, 3.0f, 3.0f), new EulerAngle(5.0f, -3.0f, -3.0f) + ), + INSPIRING("inspiring", Source.BEDROCK, Category.STANDING, new EulerAngle(-4.0f, 67.0f, 0.0f), + new EulerAngle(0.0f, 8.0f, 0.0f), new EulerAngle(-99.0f, 63.0f, 0.0f), new EulerAngle(16.0f, 32.0f, -8.0f), + new EulerAngle(4.0f, 63.0f, 8.0f), new EulerAngle(0.0f, -75.0f, -8.0f) + ), + THANKING("thanking", Source.BEDROCK, Category.STANDING, new EulerAngle(-15.0f, 0.0f, 0.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(-110.0f, -35.0f, 0.0f), new EulerAngle(-110.0f, 35.0f, 0.0f), + new EulerAngle(-5.0f, 3.0f, 3.0f), new EulerAngle(5.0f, -3.0f, -3.0f) + ), + DABBING("dabbing", Source.BEDROCK, Category.DYNAMIC, new EulerAngle(16.0f, 20.0f, 0.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(246.0f, 0.0f, 89.0f), new EulerAngle(4.0f, 8.0f, 237.0f), + new EulerAngle(8.0f, 20.0f, 4.0f), new EulerAngle(-14.0f, -18.0f, -16.0f) + ), + PLEDGING("pledging", Source.BEDROCK, Category.STANDING, new EulerAngle(0.0f, 0.0f, 0.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(-70.0f, -40.0f, 0.0f), new EulerAngle(10.0f, 0.0f, -5.0f), + new EulerAngle(1.0f, 0.0f, 1.0f), new EulerAngle(-1.0f, 0.0f, -1.0f) + ), + CONTEMPLATING("contemplating", Source.BEDROCK, Category.STANDING, new EulerAngle(15.0f, 0.0f, 0.0f), + new EulerAngle(0.0f, 0.0f, 2.0f), new EulerAngle(-60.0f, -20.0f, -10.0f), new EulerAngle(-30.0f, 15.0f, 15.0f), + new EulerAngle(1.0f, 0.0f, 1.0f), new EulerAngle(-1.0f, 0.0f, -1.0f) + ), + ZOMBIE("zombie", Source.BEDROCK, Category.MOVING, new EulerAngle(-10.0f, 0.0f, -5.0f), + new EulerAngle(0.0f, 0.0f, 0.0f), new EulerAngle(-100.0f, 0.0f, 0.0f), new EulerAngle(-105.0f, 0.0f, 0.0f), + new EulerAngle(-46.0f, 0.0f, 0.0f), new EulerAngle(7.0f, 0.0f, 0.0f) + ), + SITTING("sitting", Source.VANILLA_TWEAKS, Category.SITTING, new EulerAngle(0.0f, 0.001f, 0.0f), + new EulerAngle(0.0f, 0.001f, 0.0f), new EulerAngle(-80.0f, 20.0f, 0.0f), new EulerAngle(-80.0f, -20.0f, 0.0f), + new EulerAngle(-90.0f, 10.0f, 0.0f), new EulerAngle(-90.0f, -10.0f, 0.0f) + ), + LAZING("lazing", Source.VANILLA_TWEAKS, Category.SITTING, new EulerAngle(14f, -12f, 6f), new EulerAngle(5f, 0f, 0f), + new EulerAngle(-40f, 20f, 0f), new EulerAngle(-4f, -20f, -10f), new EulerAngle(-88f, 71f, 0f), + new EulerAngle(-88f, 46f, 0f) + ), + JUMP_ATTACK("jumpAttack", Source.ROUNDAROUND, Category.DYNAMIC, new EulerAngle(-43f, 0f, 0f), + new EulerAngle(4f, 0f, 0f), new EulerAngle(-144f, -10f, 28f), new EulerAngle(-129f, 47f, -7f), + new EulerAngle(30f, 0f, 20f), new EulerAngle(30f, 0f, -20f) + ), + STEWARD("steward", Source.ROUNDAROUND, Category.STANDING, new EulerAngle(-3f, 0f, 0f), new EulerAngle(0f, 0f, 2f), + new EulerAngle(-105f, -45f, 180f), new EulerAngle(-2f, 0f, -20f), new EulerAngle(0f, 0f, 5f), + new EulerAngle(0f, 0f, -5f) + ), + SCARECROW("scarecrow", Source.ROUNDAROUND, Category.DYNAMIC, new EulerAngle(8f, 26f, -6f), new EulerAngle(0f, 0f, 5f), + new EulerAngle(-15f, 0f, 79f), new EulerAngle(-16f, 0f, -40f), new EulerAngle(0f, 0f, -18f), + new EulerAngle(16f, 20f, 0f) + ), + PRETTY("pretty", Source.ROUNDAROUND, Category.SITTING, new EulerAngle(-17f, 0f, 0f), new EulerAngle(0f, 0f, -8f), + new EulerAngle(-12f, 20f, 0f), new EulerAngle(130f, -14f, -3f), new EulerAngle(-100f, -44f, 0f), + new EulerAngle(-90f, -10f, 0f) + ), + DRUM_MAJOR("drumMajor", Source.ROUNDAROUND, Category.DYNAMIC, new EulerAngle(-13f, 0f, 0f), + new EulerAngle(9f, 0f, 0f), new EulerAngle(110f, 125f, 180f), new EulerAngle(-10f, 0f, -20f), + new EulerAngle(-94f, 0f, 0f), new EulerAngle(15f, 0f, 0f) + ), + FISHING("fishing", Source.ROUNDAROUND, Category.SITTING, new EulerAngle(-15f, 0f, -12f), new EulerAngle(-8f, 0f, 0f), + new EulerAngle(-68f, -24f, 0f), new EulerAngle(-80f, 44f, 0f), new EulerAngle(-90f, 20f, 0f), + new EulerAngle(-90f, -20f, 0f) + ); + + public static final PacketCodec PACKET_CODEC = PacketCodec.tuple( + PacketCodecs.STRING, PosePreset::getId, PosePreset::fromString); private final String id; private final Text label; @@ -382,7 +172,7 @@ public enum PosePreset implements PoseSupplier { private final EulerAngle rightLeg; private final EulerAngle leftLeg; - private PosePreset( + PosePreset( String id, Source source, Category category, @@ -391,7 +181,8 @@ private PosePreset( EulerAngle rightArm, EulerAngle leftArm, EulerAngle rightLeg, - EulerAngle leftLeg) { + EulerAngle leftLeg + ) { this.id = id; this.label = Text.translatable("armorstands.preset." + id); this.source = source; @@ -409,6 +200,10 @@ public String toString() { return id; } + public String getId() { + return this.id; + } + @Override public Pose toPose() { return new Pose(head, body, rightArm, leftArm, rightLeg, leftLeg); @@ -451,13 +246,10 @@ public EulerAngle getLeftLeg() { } public static PosePreset fromString(String value) { - return Arrays.stream(PosePreset.values()) - .filter((pose) -> pose.id.equals(value)) - .findFirst() - .orElseGet(() -> { - ArmorStandsMod.LOGGER.warn("Unknown id '{}'. Defaulting to DEFAULT.", Source.BEDROCK, value); - return DEFAULT; - }); + return Arrays.stream(PosePreset.values()).filter((pose) -> pose.id.equals(value)).findFirst().orElseGet(() -> { + ArmorStandsMod.LOGGER.warn("Unknown id '{}'. Defaulting to DEFAULT.", Source.BEDROCK, value); + return DEFAULT; + }); } public static List getPresets() { @@ -480,22 +272,17 @@ public static List getPresets(Source source, Category category) { } } - return a.getDisplayName().getString() - .compareTo(b.getDisplayName().getString()); + return a.getDisplayName().getString().compareTo(b.getDisplayName().getString()); }) .collect(Collectors.toList()); } - public static enum Source { - ALL("all"), - VANILLA("vanilla"), - VANILLA_TWEAKS("vanillaTweaks"), - BEDROCK("bedrock"), - ROUNDAROUND("roundaround"); + public enum Source { + ALL("all"), VANILLA("vanilla"), VANILLA_TWEAKS("vanillaTweaks"), BEDROCK("bedrock"), ROUNDAROUND("roundaround"); private final String id; - private Source(String id) { + Source(String id) { this.id = id; } @@ -508,27 +295,19 @@ public boolean matches(Source source) { } public static List getSources() { - return Arrays.stream(Source.values()) - .filter((source) -> { - return source == Source.ALL - || Arrays.stream(PosePreset.values()) - .anyMatch((pose) -> pose.getSource() == source); - }) - .collect(Collectors.toList()); + return Arrays.stream(Source.values()).filter((source) -> { + return source == Source.ALL || + Arrays.stream(PosePreset.values()).anyMatch((pose) -> pose.getSource() == source); + }).collect(Collectors.toList()); } } - public static enum Category { - ALL("all"), - STANDING("standing"), - MOVING("moving"), - DYNAMIC("dynamic"), - SITTING("sitting"), - OTHER("other"); + public enum Category { + ALL("all"), STANDING("standing"), MOVING("moving"), DYNAMIC("dynamic"), SITTING("sitting"), OTHER("other"); private final String id; - private Category(String id) { + Category(String id) { this.id = id; } @@ -542,11 +321,8 @@ public boolean matches(Category category) { public static List getCategories() { return Arrays.stream(Category.values()) - .filter((category) -> { - return category == Category.ALL - || Arrays.stream(PosePreset.values()) - .anyMatch((pose) -> pose.getCategory() == category); - }) + .filter((category) -> category == Category.ALL || + Arrays.stream(PosePreset.values()).anyMatch((pose) -> pose.getCategory() == category)) .collect(Collectors.toList()); } } diff --git a/src/main/resources/armorstands.mixins.json b/src/main/resources/armorstands.mixins.json index 97089c3..b1ca0bf 100644 --- a/src/main/resources/armorstands.mixins.json +++ b/src/main/resources/armorstands.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8", "package": "me.roundaround.armorstands.mixin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_21", "mixins": [ "ArmorStandEntityAccessor", "ArmorStandEntityServerMixin", diff --git a/src/main/resources/assets/armorstands/lang/en_us.json b/src/main/resources/assets/armorstands/lang/en_us.json index 55d7744..81d77a4 100644 --- a/src/main/resources/assets/armorstands/lang/en_us.json +++ b/src/main/resources/assets/armorstands/lang/en_us.json @@ -175,5 +175,24 @@ "armorstands.parameter.pitch": "X", "armorstands.parameter.yaw": "Y", "armorstands.parameter.roll": "Z", - "armorstands.adjustPose.label": "%s°" + "armorstands.adjustPose.label": "%s°", + "armorstands.commands.add.success": "Successfully added %s to Armor Stands allowlist", + "armorstands.commands.add.failed": "Failed to add to Armor Stands allowlist", + "armorstands.commands.remove.success": "Successfully removed %s from Armor Stands allowlist", + "armorstands.commands.remove.failed": "Failed to remove from Armor Stands allowlist", + "armorstands.commands.reload.success": "Successfully reloaded Armor Stands allowlist", + "armorstands.commands.reload.failed": "Failed to reload Armor Stands allowlist", + "armorstands.action.adjustPos": "", + "armorstands.action.adjustPose": "", + "armorstands.action.copy": "", + "armorstands.action.paste": "", + "armorstands.action.flag": "", + "armorstands.action.holding": "", + "armorstands.action.move": "", + "armorstands.action.moveToGround": "", + "armorstands.action.pose": "", + "armorstands.action.prepare": "", + "armorstands.action.rotate": "", + "armorstands.action.snapToGround": "", + "armorstands.action.toolRack": "" } \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 3401e50..88f9a02 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,38 +1,34 @@ -{ - "schemaVersion": 1, - "id": "armorstands", - "version": "${version}", - "name": "Armor Stands", - "description": "Place, pose, and dress armor stands with an easy-to-use UI.\n${library}", - "authors": [ - "Roundaround" - ], - "contact": { - "homepage": "https://modrinth.com/mod/armor-stands", - "sources": "https://github.com/Roundaround/mc-fabric-armor-stands", - "issues": "https://github.com/Roundaround/mc-fabric-armor-stands/issues" - }, - "license": "MIT", - "icon": "assets/armorstands/icon.png", - "environment": "*", - "entrypoints": { - "preLaunch": [ - "me.roundaround.armorstands.ArmorStandsPreLaunch" - ], - "client": [ - "me.roundaround.armorstands.client.ArmorStandsClientMod" - ], - "main": [ - "me.roundaround.armorstands.ArmorStandsMod" - ] - }, - "mixins": [ - "armorstands.mixins.json" - ], - "depends": { - "fabricloader": ">=0.13.3", - "fabric-api": "*", - "minecraft": "1.20.*", - "java": ">=17" - } -} +{ + "schemaVersion": 1, + "id": "armorstands", + "version": "${version}", + "name": "Armor Stands", + "description": "Place, pose, and dress armor stands with an easy-to-use UI.\n${library}", + "authors": [ + "Roundaround" + ], + "contact": { + "homepage": "https://modrinth.com/mod/armor-stands", + "sources": "https://github.com/Roundaround/mc-fabric-armor-stands", + "issues": "https://github.com/Roundaround/mc-fabric-armor-stands/issues" + }, + "license": "MIT", + "icon": "assets/armorstands/icon.png", + "environment": "*", + "entrypoints": { + "client": [ + "me.roundaround.armorstands.client.ArmorStandsClientMod" + ], + "main": [ + "me.roundaround.armorstands.ArmorStandsMod" + ] + }, + "mixins": [ + "armorstands.mixins.json" + ], + "depends": { + "fabricloader": ">=0.15.11", + "fabric-api": "*", + "minecraft": "1.20.*" + } +}