Skip to content

Commit

Permalink
Add mirror/swap buttons
Browse files Browse the repository at this point in the history
Allowing to mirror pose, mirror legs, mirror arms, swap main hand with head and swap main and off hand
  • Loading branch information
Mrbysco committed Sep 27, 2023
1 parent fa38d04 commit 3670fd8
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 16 deletions.
1 change: 1 addition & 0 deletions common/src/main/java/com/mrbysco/armorposer/Reference.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String> defaultPoseMap = initializePoseMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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;
Expand All @@ -149,26 +155,97 @@ 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");
this.poseTextFields[20].setValue("0");
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
Expand Down Expand Up @@ -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;
Expand All @@ -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]);
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
42 changes: 42 additions & 0 deletions common/src/main/java/com/mrbysco/armorposer/data/SwapData.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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
*/
Expand Down
6 changes: 6 additions & 0 deletions common/src/main/resources/assets/armorposer/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions common/src/main/resources/assets/armorposer/lang/fr_fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions common/src/main/resources/assets/armorposer/lang/zh_tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions fabric/src/main/java/com/mrbysco/armorposer/ArmorPoser.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mrbysco.armorposer;

import com.mrbysco.armorposer.config.PoserConfig;
import com.mrbysco.armorposer.data.SwapData;
import com.mrbysco.armorposer.data.SyncData;
import com.mrbysco.armorposer.handlers.EventHandler;
import me.shedaniel.autoconfig.AutoConfig;
Expand Down Expand Up @@ -34,5 +35,19 @@ public void onInitialize() {
}
});
});


ServerPlayNetworking.registerGlobalReceiver(Reference.SWAP_PACKET_ID, (server, player, handler, buf, responseSender) -> {
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);
}
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
4 changes: 3 additions & 1 deletion forge/src/main/java/com/mrbysco/armorposer/ArmorPoser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
Loading

0 comments on commit 3670fd8

Please sign in to comment.