From 3670fd861924cb1e1365a7619f795444a213fa51 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Wed, 27 Sep 2023 19:50:18 +0200 Subject: [PATCH] Add mirror/swap buttons Allowing to mirror pose, mirror legs, mirror arms, swap main hand with head and swap main and off hand --- .../com/mrbysco/armorposer/Reference.java | 1 + .../client/gui/ArmorStandScreen.java | 109 +++++++++++++++--- .../client/gui/widgets/PoseImageButton.java | 33 ++++++ .../com/mrbysco/armorposer/data/SwapData.java | 42 +++++++ .../platform/services/IPlatformHelper.java | 6 + .../assets/armorposer/lang/en_us.json | 6 + .../assets/armorposer/lang/fr_fr.json | 6 + .../assets/armorposer/lang/zh_tw.json | 6 + .../armorposer/textures/gui/poser_buttons.png | Bin 0 -> 2069 bytes .../com/mrbysco/armorposer/ArmorPoser.java | 15 +++ .../platform/FabricPlatformHelper.java | 9 ++ .../com/mrbysco/armorposer/ArmorPoser.java | 4 +- .../packets/ArmorStandSwapMessage.java | 42 +++++++ .../platform/ForgePlatformHelper.java | 7 ++ 14 files changed, 270 insertions(+), 16 deletions(-) create mode 100644 common/src/main/java/com/mrbysco/armorposer/client/gui/widgets/PoseImageButton.java create mode 100644 common/src/main/java/com/mrbysco/armorposer/data/SwapData.java create mode 100644 common/src/main/resources/assets/armorposer/textures/gui/poser_buttons.png create mode 100644 forge/src/main/java/com/mrbysco/armorposer/packets/ArmorStandSwapMessage.java diff --git a/common/src/main/java/com/mrbysco/armorposer/Reference.java b/common/src/main/java/com/mrbysco/armorposer/Reference.java index 66b8a88..56fafc9 100644 --- a/common/src/main/java/com/mrbysco/armorposer/Reference.java +++ b/common/src/main/java/com/mrbysco/armorposer/Reference.java @@ -14,6 +14,7 @@ public class Reference { public static final ResourceLocation SYNC_PACKET_ID = new ResourceLocation(Reference.MOD_ID, "sync_packet"); + public static final ResourceLocation SWAP_PACKET_ID = new ResourceLocation(Reference.MOD_ID, "swap_packet"); public static final ResourceLocation SCREEN_PACKET_ID = new ResourceLocation(Reference.MOD_ID, "screen_packet"); public static final Map defaultPoseMap = initializePoseMap(); diff --git a/common/src/main/java/com/mrbysco/armorposer/client/gui/ArmorStandScreen.java b/common/src/main/java/com/mrbysco/armorposer/client/gui/ArmorStandScreen.java index 9fcde6c..57cd35c 100644 --- a/common/src/main/java/com/mrbysco/armorposer/client/gui/ArmorStandScreen.java +++ b/common/src/main/java/com/mrbysco/armorposer/client/gui/ArmorStandScreen.java @@ -3,7 +3,9 @@ import com.mrbysco.armorposer.Reference; import com.mrbysco.armorposer.client.gui.widgets.NumberFieldBox; import com.mrbysco.armorposer.client.gui.widgets.PoseButton; +import com.mrbysco.armorposer.client.gui.widgets.PoseImageButton; import com.mrbysco.armorposer.client.gui.widgets.ToggleButton; +import com.mrbysco.armorposer.data.SwapData; import com.mrbysco.armorposer.mixin.EditBoxAccessor; import com.mrbysco.armorposer.platform.Services; import com.mrbysco.armorposer.util.ArmorStandData; @@ -67,7 +69,7 @@ public void init() { super.init(); int offsetX = 110; - int offsetY = 30; + int offsetY = 20; // toggle buttons for (int i = 0; i < this.toggleButtons.length; i++) { @@ -124,17 +126,21 @@ public void init() { this.addWidget(this.poseTextFields[i]); } - offsetY = this.height / 4 + 120 + 12; + offsetY = this.height / 4 + 134; // copy & paste buttons offsetX = 20; + this.addRenderableWidget(Button.builder(Component.translatable("armorposer.gui.label.poses"), (button) -> + this.poseTabVisible = !this.poseTabVisible) + .bounds(offsetX, offsetY, 130, 20) + .tooltip(Tooltip.create(Component.translatable("armorposer.gui.tooltip.poses"))).build()); this.addRenderableWidget(Button.builder(Component.translatable("armorposer.gui.label.copy"), (button) -> { CompoundTag compound = this.writeFieldsToNBT(); String clipboardData = compound.toString(); if (this.minecraft != null) { this.minecraft.keyboardHandler.setClipboard(clipboardData); } - }).bounds(offsetX, offsetY, 64, 20).tooltip(Tooltip.create(Component.translatable("armorposer.gui.tooltip.copy"))).build()); + }).bounds(offsetX, offsetY + 22, 64, 20).tooltip(Tooltip.create(Component.translatable("armorposer.gui.tooltip.copy"))).build()); this.addRenderableWidget(Button.builder(Component.translatable("armorposer.gui.label.paste"), (button) -> { try { String clipboardData = null; @@ -149,18 +155,89 @@ public void init() { } catch (Exception e) { //Nope } - }).bounds(offsetX + 66, offsetY, 64, 20).tooltip(Tooltip.create(Component.translatable("armorposer.gui.tooltip.paste"))).build()); - this.addRenderableWidget(Button.builder(Component.translatable("armorposer.gui.label.poses"), (button) -> - this.poseTabVisible = !this.poseTabVisible) - .bounds(offsetX + 44, offsetY + 22, 40, 20) - .tooltip(Tooltip.create(Component.translatable("armorposer.gui.tooltip.poses"))).build()); + }).bounds(offsetX + 66, offsetY + 22, 64, 20).tooltip(Tooltip.create(Component.translatable("armorposer.gui.tooltip.paste"))).build()); - // done & cancel buttons offsetX = this.width - 20; + this.addRenderableWidget(new PoseImageButton(offsetX - (22 * 5) - 41, offsetY, (button) -> { + //Mirror head + float[] head = new float[]{poseTextFields[0].getFloat(), poseTextFields[1].getFloat(), poseTextFields[2].getFloat()}; + poseTextFields[0].setValue(String.valueOf(head[0])); + poseTextFields[1].setValue(String.valueOf(head[1] != 0 ? -head[1] : 0)); + poseTextFields[2].setValue(String.valueOf(head[2] != 0 ? -head[2] : 0)); + + //Mirror head + float[] body = new float[]{poseTextFields[3].getFloat(), poseTextFields[4].getFloat(), poseTextFields[5].getFloat()}; + poseTextFields[3].setValue(String.valueOf(body[0])); + poseTextFields[4].setValue(String.valueOf(body[1] != 0 ? -body[1] : 0)); + poseTextFields[5].setValue(String.valueOf(body[2] != 0 ? -body[2] : 0)); + + //Mirror Legs + float[] leftLeg = new float[]{poseTextFields[6].getFloat(), poseTextFields[7].getFloat(), poseTextFields[8].getFloat()}; + float[] rightLeg = new float[]{poseTextFields[9].getFloat(), poseTextFields[10].getFloat(), poseTextFields[11].getFloat()}; + + //Swap angles and mirror the angles + poseTextFields[6].setValue(String.valueOf(rightLeg[0])); + poseTextFields[7].setValue(String.valueOf(rightLeg[1] != 0 ? -rightLeg[1] : 0)); + poseTextFields[8].setValue(String.valueOf(rightLeg[2] != 0 ? -rightLeg[2] : 0)); + poseTextFields[9].setValue(String.valueOf(leftLeg[0])); + poseTextFields[10].setValue(String.valueOf(leftLeg[1] != 0 ? -leftLeg[1] : 0)); + poseTextFields[11].setValue(String.valueOf(leftLeg[2] != 0 ? -leftLeg[2] : 0)); + + //Mirror Arms + float[] leftArm = new float[]{poseTextFields[12].getFloat(), poseTextFields[13].getFloat(), poseTextFields[14].getFloat()}; + float[] rightArm = new float[]{poseTextFields[15].getFloat(), poseTextFields[16].getFloat(), poseTextFields[17].getFloat()}; + + //Swap angles and mirror the angles + poseTextFields[12].setValue(String.valueOf(rightArm[0])); + poseTextFields[13].setValue(String.valueOf(rightArm[1] != 0 ? -rightArm[1] : 0)); + poseTextFields[14].setValue(String.valueOf(rightArm[2] != 0 ? -rightArm[2] : 0)); + poseTextFields[15].setValue(String.valueOf(leftArm[0])); + poseTextFields[16].setValue(String.valueOf(leftArm[1] != 0 ? -leftArm[1] : 0)); + poseTextFields[17].setValue(String.valueOf(leftArm[2] != 0 ? -leftArm[2] : 0)); + + }, 0, Tooltip.create(Component.translatable("armorposer.gui.tooltip.mirror")))); + this.addRenderableWidget(new PoseImageButton(offsetX - (22 * 4) - 41, offsetY, (button) -> { + //Mirror Legs + float[] leftLeg = new float[]{poseTextFields[6].getFloat(), poseTextFields[7].getFloat(), poseTextFields[8].getFloat()}; + float[] rightLeg = new float[]{poseTextFields[9].getFloat(), poseTextFields[10].getFloat(), poseTextFields[11].getFloat()}; + + //Swap angles and mirror the angles + poseTextFields[6].setValue(String.valueOf(rightLeg[0])); + poseTextFields[7].setValue(String.valueOf(rightLeg[1] != 0 ? -rightLeg[1] : 0)); + poseTextFields[8].setValue(String.valueOf(rightLeg[2] != 0 ? -rightLeg[2] : 0)); + poseTextFields[9].setValue(String.valueOf(leftLeg[0])); + poseTextFields[10].setValue(String.valueOf(leftLeg[1] != 0 ? -leftLeg[1] : 0)); + poseTextFields[11].setValue(String.valueOf(leftLeg[2] != 0 ? -leftLeg[2] : 0)); + }, 1, Tooltip.create(Component.translatable("armorposer.gui.tooltip.mirror_legs")))); + this.addRenderableWidget(new PoseImageButton(offsetX - (22 * 3) - 41, offsetY, (button) -> { + //Mirror Arms + float[] leftArm = new float[]{poseTextFields[12].getFloat(), poseTextFields[13].getFloat(), poseTextFields[14].getFloat()}; + float[] rightArm = new float[]{poseTextFields[15].getFloat(), poseTextFields[16].getFloat(), poseTextFields[17].getFloat()}; + + //Swap angles and mirror the angles + poseTextFields[12].setValue(String.valueOf(rightArm[0])); + poseTextFields[13].setValue(String.valueOf(rightArm[1] != 0 ? -rightArm[1] : 0)); + poseTextFields[14].setValue(String.valueOf(rightArm[2] != 0 ? -rightArm[2] : 0)); + poseTextFields[15].setValue(String.valueOf(leftArm[0])); + poseTextFields[16].setValue(String.valueOf(leftArm[1] != 0 ? -leftArm[1] : 0)); + poseTextFields[17].setValue(String.valueOf(leftArm[2] != 0 ? -leftArm[2] : 0)); + }, 2, Tooltip.create(Component.translatable("armorposer.gui.tooltip.mirror_arms")))); + this.addRenderableWidget(new PoseImageButton(offsetX - (22 * 2) - 41, offsetY, (button) -> { + //Swap item in main hand with head + Services.PLATFORM.swapSlots(this.entityArmorStand, SwapData.Action.SWAP_WITH_HEAD); + + }, 3, Tooltip.create(Component.translatable("armorposer.gui.tooltip.swap_head")))); + this.addRenderableWidget(new PoseImageButton(offsetX - (22) - 41, offsetY, (button) -> { + //Swap item in main and offhand + Services.PLATFORM.swapSlots(this.entityArmorStand, SwapData.Action.SWAP_HANDS); + + }, 4, Tooltip.create(Component.translatable("armorposer.gui.tooltip.swap_hands")))); + + // done & cancel buttons this.addRenderableWidget(Button.builder(Component.translatable("gui.done"), (button) -> { this.updateEntity(this.writeFieldsToNBT()); this.minecraft.setScreen((Screen) null); - }).bounds(offsetX - ((2 * 96) + 2), offsetY, 96, 20).build()); + }).bounds(offsetX - ((2 * 96) + 2), offsetY + 22, 96, 20).build()); this.addRenderableWidget(Button.builder(Component.translatable("gui.cancel"), (button) -> { this.poseTextFields[18].setValue("0"); this.poseTextFields[19].setValue("0"); @@ -168,7 +245,7 @@ public void init() { this.textFieldUpdated(); this.updateEntity(this.armorStandData.writeToNBT()); this.minecraft.setScreen((Screen) null); - }).bounds(offsetX - 96, offsetY, 96, 20).build()); + }).bounds(offsetX - 96, offsetY + 22, 96, 20).build()); //Setup pose buttons @@ -230,7 +307,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia for (EditBox textField : this.poseTextFields) textField.render(guiGraphics, mouseX, mouseY, partialTicks); - int offsetY = 30; + int offsetY = 20; // left column labels int offsetX = 20; @@ -244,9 +321,11 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia // right column labels offsetX = this.width - 20 - 100; // x, y, z - guiGraphics.drawString(this.font, "X", offsetX + 10, 17, 0xA0A0A0, false); - guiGraphics.drawString(this.font, "Y", offsetX + 45, 17, 0xA0A0A0, false); - guiGraphics.drawString(this.font, "Z", offsetX + 80, 17, 0xA0A0A0, false); + if (!poseTabVisible) { + guiGraphics.drawString(this.font, "X", offsetX + 10, 7, 0xA0A0A0, false); + guiGraphics.drawString(this.font, "Y", offsetX + 45, 7, 0xA0A0A0, false); + guiGraphics.drawString(this.font, "Z", offsetX + 80, 7, 0xA0A0A0, false); + } // pose textboxes for (int i = 0; i < this.sliderLabels.length; i++) { String translatedLabel = I18n.get("armorposer.gui.label." + this.sliderLabels[i]); diff --git a/common/src/main/java/com/mrbysco/armorposer/client/gui/widgets/PoseImageButton.java b/common/src/main/java/com/mrbysco/armorposer/client/gui/widgets/PoseImageButton.java new file mode 100644 index 0000000..31a04e1 --- /dev/null +++ b/common/src/main/java/com/mrbysco/armorposer/client/gui/widgets/PoseImageButton.java @@ -0,0 +1,33 @@ +package com.mrbysco.armorposer.client.gui.widgets; + +import com.mrbysco.armorposer.Reference; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.screens.inventory.BookViewScreen; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; + +public class PoseImageButton extends Button { + private static final ResourceLocation BUTTON_LOCATION = new ResourceLocation(Reference.MOD_ID, "textures/gui/poser_buttons.png"); + private final int yOffset; + + public PoseImageButton(int x, int y, Button.OnPress onPress, int buttonID) { + super(x, y, 20, 20, CommonComponents.EMPTY, onPress, DEFAULT_NARRATION); + this.yOffset = buttonID == 0 ? 0 : buttonID * 20; + } + + public PoseImageButton(int x, int y, Button.OnPress onPress, int buttonID, Tooltip tooltip) { + this(x, y, onPress, buttonID); + this.setTooltip(tooltip); + } + + public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + int i = 0; + if (this.isHovered()) { + i += 20; + } + + guiGraphics.blit(PoseImageButton.BUTTON_LOCATION, this.getX(), this.getY(), i, yOffset, 20, 20, 64, 128); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/mrbysco/armorposer/data/SwapData.java b/common/src/main/java/com/mrbysco/armorposer/data/SwapData.java new file mode 100644 index 0000000..04e6781 --- /dev/null +++ b/common/src/main/java/com/mrbysco/armorposer/data/SwapData.java @@ -0,0 +1,42 @@ +package com.mrbysco.armorposer.data; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.item.ItemStack; + +import java.util.UUID; + +public record SwapData(UUID entityUUID, Action action) { + public void encode(FriendlyByteBuf buf) { + buf.writeUUID(entityUUID); + buf.writeEnum(action); + } + + public static SwapData decode(final FriendlyByteBuf packetBuffer) { + return new SwapData(packetBuffer.readUUID(), packetBuffer.readEnum(Action.class)); + } + + public void handleData(ArmorStand armorStand) { + switch (action) { + case SWAP_HANDS: + ItemStack offStack = armorStand.getItemInHand(InteractionHand.OFF_HAND); + armorStand.setItemInHand(InteractionHand.OFF_HAND, armorStand.getItemInHand(InteractionHand.MAIN_HAND)); + armorStand.setItemInHand(InteractionHand.MAIN_HAND, offStack); + return; + case SWAP_WITH_HEAD: + ItemStack headStack = armorStand.getItemBySlot(EquipmentSlot.HEAD); + armorStand.setItemSlot(EquipmentSlot.HEAD, armorStand.getItemBySlot(EquipmentSlot.MAINHAND)); + armorStand.setItemSlot(EquipmentSlot.MAINHAND, headStack); + return; + default: + throw new IllegalArgumentException("Invalid Pose action"); + } + } + + public static enum Action { + SWAP_WITH_HEAD, + SWAP_HANDS; + } +} diff --git a/common/src/main/java/com/mrbysco/armorposer/platform/services/IPlatformHelper.java b/common/src/main/java/com/mrbysco/armorposer/platform/services/IPlatformHelper.java index 2a4ee01..a7a81a2 100644 --- a/common/src/main/java/com/mrbysco/armorposer/platform/services/IPlatformHelper.java +++ b/common/src/main/java/com/mrbysco/armorposer/platform/services/IPlatformHelper.java @@ -1,5 +1,6 @@ package com.mrbysco.armorposer.platform.services; +import com.mrbysco.armorposer.data.SwapData; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.decoration.ArmorStand; @@ -9,6 +10,11 @@ public interface IPlatformHelper { */ void updateEntity(ArmorStand armorStand, CompoundTag compound); + /** + * Update Armor Stand Entity + */ + void swapSlots(ArmorStand armorStand, SwapData.Action action); + /** * Allow scrolling to increase/decrease the angle of text fields */ diff --git a/common/src/main/resources/assets/armorposer/lang/en_us.json b/common/src/main/resources/assets/armorposer/lang/en_us.json index fe2e43f..3c8a6b7 100644 --- a/common/src/main/resources/assets/armorposer/lang/en_us.json +++ b/common/src/main/resources/assets/armorposer/lang/en_us.json @@ -43,6 +43,12 @@ "armorposer.gui.tooltip.paste": "Paste the pose from the clipboard", "armorposer.gui.tooltip.poses": "Check built-in poses", + "armorposer.gui.tooltip.mirror": "Mirror pose", + "armorposer.gui.tooltip.mirror_legs": "Mirror legs", + "armorposer.gui.tooltip.mirror_arms": "Mirror Arms", + "armorposer.gui.tooltip.swap_head": "Swap main hand and head", + "armorposer.gui.tooltip.swap_hands": "Swap main and off hand", + "armorposer.gui.pose.attention": "Attention", "armorposer.gui.pose.walking": "Walking", "armorposer.gui.pose.running": "Running", diff --git a/common/src/main/resources/assets/armorposer/lang/fr_fr.json b/common/src/main/resources/assets/armorposer/lang/fr_fr.json index 2eb4c7b..ec29c32 100644 --- a/common/src/main/resources/assets/armorposer/lang/fr_fr.json +++ b/common/src/main/resources/assets/armorposer/lang/fr_fr.json @@ -43,6 +43,12 @@ "armorposer.gui.tooltip.paste": "Paste the pose from the clipboard", "armorposer.gui.tooltip.poses": "Check built-in poses", + "armorposer.gui.tooltip.mirror": "Mirror pose", + "armorposer.gui.tooltip.mirror_legs": "Mirror legs", + "armorposer.gui.tooltip.mirror_arms": "Mirror Arms", + "armorposer.gui.tooltip.swap_head": "Swap main hand and head", + "armorposer.gui.tooltip.swap_hands": "Swap main and off hand", + "armorposer.gui.pose.attention": "Attention", "armorposer.gui.pose.walking": "Walking", "armorposer.gui.pose.running": "Running", diff --git a/common/src/main/resources/assets/armorposer/lang/zh_tw.json b/common/src/main/resources/assets/armorposer/lang/zh_tw.json index 41a557c..5d1d446 100644 --- a/common/src/main/resources/assets/armorposer/lang/zh_tw.json +++ b/common/src/main/resources/assets/armorposer/lang/zh_tw.json @@ -43,6 +43,12 @@ "armorposer.gui.tooltip.paste": "Paste the pose from the clipboard", "armorposer.gui.tooltip.poses": "Check built-in poses", + "armorposer.gui.tooltip.mirror": "Mirror pose", + "armorposer.gui.tooltip.mirror_legs": "Mirror legs", + "armorposer.gui.tooltip.mirror_arms": "Mirror Arms", + "armorposer.gui.tooltip.swap_head": "Swap main hand and head", + "armorposer.gui.tooltip.swap_hands": "Swap main and off hand", + "armorposer.gui.pose.attention": "Attention", "armorposer.gui.pose.walking": "Walking", "armorposer.gui.pose.running": "Running", diff --git a/common/src/main/resources/assets/armorposer/textures/gui/poser_buttons.png b/common/src/main/resources/assets/armorposer/textures/gui/poser_buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..a9708f906016ad55d9331e0c5e07b0a74b87d143 GIT binary patch literal 2069 zcmZ8idpy%^8z0SK%c(XRN$Qc!A%}Q8!#okAb#iF0WK53hD4Q0RYF5dqq#oqKLb05a z9ETo7%fw>hmBTO$!yMA|I6Uu9@B7#L$9-R)&vk$9>vMm<_xF2U@ouMFl%ZNs5D27< zJL=>CM0;S-73G1Q9dq>}5M;tVT#kUsI<==kAO#-I$pIgkHJ5er(rJg?u@VbwR*KuY zrb+jsdxQvc&Jn8sbB6A!LP`90)vSC}fS%C?1oGw*1P)I~94q*2G8muuGG{*E&#drC z-@ByYjOCQ%kb(x&?Cr;pZJ)9;mKTF2J1xkdu=97rODSR6oG!zsf638_<>|D23Hw3z zxo#h?%%UG67P`823^(1}4nm{RUIfXqh!^=|X~N@_ougE19?!wtJXth%`(M45Eir8gQLT zJqd^x*Tfm`m(gGScZeK6$&o}SXvAy%7(8aAc-!UqJg zk#>N{8gYgvV%>X7NjrmebRD-X+}ztFN$jNB>`8L|g*=HGYfll}Wg7f}0NK|WSN>ip zGqSNJ-B01$Z*Huydb&zUP%>z0GxHP+K6#(~)FgRN^);{60~p<>LdRSsCFSA`^M7ZKcXF?wMMulLsp5wD+@N+om}QfJ+0v53Rq^OBlEXHdCO;hUtm5iJj;eY@uFvO z>+<<3@AbAP$hz{Hfh(H}qmC-{@XjBbo10&0$$Jk^uJ3%v7=v&V)uVEcq+el{wp#PP zfvM9OPK)4))`SMP{^4PH5vH#V)m2|n z)>2D(!kV}2QLT|O0h#Hxh~FM`BeKd{*_7Du@iM;Dv+KMi+%Y@_S^JQQ)1Wb;e0pFF zFPR3DG=|^XTfV4Q30o%yE&gfg#jov@K~jl;!;X;j#3mX1PE13-Jk5iL+coe0Ei^8H zDKbbFqKW-mD1oGdrnUWn0b?^TX#%gqkM2!D97stBL9*To&oTXr){HPd=Pv2)l% z)6Wn?JPp-HN0sk8;tkb77VYA`a=*H~DCUSEtrzx&Iie(nXnmkD@UNITE8tS(dAnwe zss#9!yps1YpMU+AQCvi^@o^_i1cj3KNnkn#A>w)Px+q4^**+@Pl68nmOT{!(znyrTiS#P| zGHG?$Qp;#!3(w)NhYs-zhd^m458$qqcgg8i~D|UQFuSn_x|v+!?)k4SSI_pKAOK^U7o!9 zeQtmo#VDRR>-w3-uqZ*EM~ERF%{0b!$-_w9O0trkd(oP&pN`30CE;$8zy zEACP%14gw{luc=JPCnxR$d0lMj>$NgI@m8~-#?mNH9!Dd0(|m0tE;Z_v)=MRt+o{~ z5-^ zjhK%+wF`PL|7PQs|5GxMwT+DrbQQy-^Fyi8cA7(g-#TC=ePYA|=Qv^H1wYB`tdh-& z$(>ZG%C?V#Vk1+(GyS$%Ea{r`>fD`VUDXybbI_nap6ZoPu!llJo|AaY z_zpF)cHp6mAR5C4=rxlvWdQ8s^)yxp1v^YbR1Jf6F;1|V}lzqk$Nxtam>J-$KS z0Ckw#o6++U$joO892cfHPGxInX>;7G8*Z&GI7G9LPxV^hW~AUJk8T)cW+fIB0!YTr zrJ)QCSp`>DS9@f)Zx1052xwc|Z6a+21%=uO$?#Vii^WQ}*g?@os^`3xO%p{046HTO z12^|$nspUhb|W7g|2q|VEV#YM2#K5i%>JfVNNY4 { + final ServerLevel world = player.serverLevel(); + + SwapData swapData = SwapData.decode(buf); + + server.execute(() -> { + Entity entity = world.getEntity(swapData.entityUUID()); + if (entity instanceof ArmorStand armorStandEntity) { + swapData.handleData(armorStandEntity); + } + }); + }); } } diff --git a/fabric/src/main/java/com/mrbysco/armorposer/platform/FabricPlatformHelper.java b/fabric/src/main/java/com/mrbysco/armorposer/platform/FabricPlatformHelper.java index a0ec770..37baa3f 100644 --- a/fabric/src/main/java/com/mrbysco/armorposer/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/com/mrbysco/armorposer/platform/FabricPlatformHelper.java @@ -2,6 +2,7 @@ import com.mrbysco.armorposer.Reference; import com.mrbysco.armorposer.config.PoserConfig; +import com.mrbysco.armorposer.data.SwapData; import com.mrbysco.armorposer.data.SyncData; import com.mrbysco.armorposer.platform.services.IPlatformHelper; import me.shedaniel.autoconfig.AutoConfig; @@ -24,6 +25,14 @@ public void updateEntity(ArmorStand armorStand, CompoundTag compound) { ClientPlayNetworking.send(Reference.SYNC_PACKET_ID, buf); } + @Override + public void swapSlots(ArmorStand armorStand, SwapData.Action action) { + FriendlyByteBuf buf = PacketByteBufs.create(); + SwapData data = new SwapData(armorStand.getUUID(), action); + data.encode(buf); + ClientPlayNetworking.send(Reference.SWAP_PACKET_ID, buf); + } + @Override public boolean allowScrolling() { PoserConfig config = AutoConfig.getConfigHolder(PoserConfig.class).getConfig(); diff --git a/forge/src/main/java/com/mrbysco/armorposer/ArmorPoser.java b/forge/src/main/java/com/mrbysco/armorposer/ArmorPoser.java index 68391db..cbd7e15 100644 --- a/forge/src/main/java/com/mrbysco/armorposer/ArmorPoser.java +++ b/forge/src/main/java/com/mrbysco/armorposer/ArmorPoser.java @@ -2,6 +2,7 @@ import com.mrbysco.armorposer.config.PoserConfig; import com.mrbysco.armorposer.packets.ArmorStandScreenMessage; +import com.mrbysco.armorposer.packets.ArmorStandSwapMessage; import com.mrbysco.armorposer.packets.ArmorStandSyncMessage; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.eventbus.api.IEventBus; @@ -34,6 +35,7 @@ public ArmorPoser() { private void setup(final FMLCommonSetupEvent event) { CHANNEL.registerMessage(0, ArmorStandSyncMessage.class, ArmorStandSyncMessage::encode, ArmorStandSyncMessage::decode, ArmorStandSyncMessage::handle); - CHANNEL.registerMessage(1, ArmorStandScreenMessage.class, ArmorStandScreenMessage::encode, ArmorStandScreenMessage::decode, ArmorStandScreenMessage::handle); + CHANNEL.registerMessage(1, ArmorStandSwapMessage.class, ArmorStandSwapMessage::encode, ArmorStandSwapMessage::decode, ArmorStandSwapMessage::handle); + CHANNEL.registerMessage(2, ArmorStandScreenMessage.class, ArmorStandScreenMessage::encode, ArmorStandScreenMessage::decode, ArmorStandScreenMessage::handle); } } \ No newline at end of file diff --git a/forge/src/main/java/com/mrbysco/armorposer/packets/ArmorStandSwapMessage.java b/forge/src/main/java/com/mrbysco/armorposer/packets/ArmorStandSwapMessage.java new file mode 100644 index 0000000..58d6eee --- /dev/null +++ b/forge/src/main/java/com/mrbysco/armorposer/packets/ArmorStandSwapMessage.java @@ -0,0 +1,42 @@ +package com.mrbysco.armorposer.packets; + +import com.mrbysco.armorposer.data.SwapData; +import com.mrbysco.armorposer.data.SyncData; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraftforge.network.NetworkEvent.Context; + +import java.util.function.Supplier; + + +public class ArmorStandSwapMessage { + private final SwapData data; + + public ArmorStandSwapMessage(SwapData syncData) { + this.data = syncData; + } + + public void encode(FriendlyByteBuf buf) { + data.encode(buf); + } + + public static ArmorStandSwapMessage decode(final FriendlyByteBuf packetBuffer) { + return new ArmorStandSwapMessage(SwapData.decode(packetBuffer)); + } + + public void handle(Supplier context) { + Context ctx = context.get(); + ctx.enqueueWork(() -> { + if (ctx.getDirection().getReceptionSide().isServer() && ctx.getSender() != null) { + final ServerLevel serverLevel = ctx.getSender().serverLevel(); + Entity entity = serverLevel.getEntity(data.entityUUID()); + if (entity instanceof ArmorStand armorStandEntity) { + data.handleData(armorStandEntity); + } + } + }); + ctx.setPacketHandled(true); + } +} diff --git a/forge/src/main/java/com/mrbysco/armorposer/platform/ForgePlatformHelper.java b/forge/src/main/java/com/mrbysco/armorposer/platform/ForgePlatformHelper.java index 7ca32fe..a56a8d3 100644 --- a/forge/src/main/java/com/mrbysco/armorposer/platform/ForgePlatformHelper.java +++ b/forge/src/main/java/com/mrbysco/armorposer/platform/ForgePlatformHelper.java @@ -2,7 +2,9 @@ import com.mrbysco.armorposer.ArmorPoser; import com.mrbysco.armorposer.config.PoserConfig; +import com.mrbysco.armorposer.data.SwapData; import com.mrbysco.armorposer.data.SyncData; +import com.mrbysco.armorposer.packets.ArmorStandSwapMessage; import com.mrbysco.armorposer.packets.ArmorStandSyncMessage; import com.mrbysco.armorposer.platform.services.IPlatformHelper; import net.minecraft.nbt.CompoundTag; @@ -19,6 +21,11 @@ public void updateEntity(ArmorStand armorStand, CompoundTag compound) { ArmorPoser.CHANNEL.send(PacketDistributor.SERVER.noArg(), new ArmorStandSyncMessage(new SyncData(armorStand.getUUID(), compound))); } + @Override + public void swapSlots(ArmorStand armorStand, SwapData.Action action) { + ArmorPoser.CHANNEL.send(PacketDistributor.SERVER.noArg(), new ArmorStandSwapMessage(new SwapData(armorStand.getUUID(), action))); + } + @Override public boolean allowScrolling() { return PoserConfig.COMMON.allowScrolling.get();