Skip to content

Commit

Permalink
Add a page in the posing GUI that has default poses
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrbysco committed Sep 21, 2023
1 parent 5f8c5ae commit fa38d04
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 11 deletions.
34 changes: 34 additions & 0 deletions common/src/main/java/com/mrbysco/armorposer/Reference.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import net.minecraft.resources.ResourceLocation;
import org.slf4j.Logger;

import java.util.LinkedHashMap;
import java.util.Map;

public class Reference {
public static final String MOD_ID = "armorposer";
public static final String MOD_NAME = "Armor Poser";
Expand All @@ -12,4 +15,35 @@ public class Reference {

public static final ResourceLocation SYNC_PACKET_ID = new ResourceLocation(Reference.MOD_ID, "sync_packet");
public static final ResourceLocation SCREEN_PACKET_ID = new ResourceLocation(Reference.MOD_ID, "screen_packet");

public static final Map<String, String> defaultPoseMap = initializePoseMap();

private static Map<String, String> initializePoseMap() {
Map<String, String> poseMap = new LinkedHashMap<>();
poseMap.put("attention", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[0.0f,0.0f,0.0f],LeftLeg:[0.0f,0.0f,0.0f],RightArm:[0.0f,0.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("walking", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[-20.0f,0.0f,-10.0f],LeftLeg:[20.0f,0.0f,0.0f],RightArm:[20.0f,0.0f,10.0f],RightLeg:[-20.0f,0.0f,0.0f]}}");
poseMap.put("running", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[40.0f,0.0f,-10.0f],LeftLeg:[-40.0f,0.0f,0.0f],RightArm:[-40.0f,0.0f,10.0f],RightLeg:[40.0f,0.0f,0.0f]}}");
poseMap.put("pointing", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,20.0f,0.0f],LeftArm:[0.0f,0.0f,-10.0f],LeftLeg:[0.0f,0.0f,0.0f],RightArm:[-90.0f,18.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("blocking", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[-50.0f,50.0f,0.0f],LeftLeg:[20.0f,0.0f,0.0f],RightArm:[-20.0f,-20.0f,0.0f],RightLeg:[-20.0f,0.0f,0.0f]}}");
poseMap.put("lunging", "{Pose:{Body:[15.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[10.0f,0.0f,-10.0f],LeftLeg:[30.0f,0.0f,0.0f],RightArm:[-60.0f,-10.0f,0.0f],RightLeg:[-15.0f,0.0f,0.0f]}}");
poseMap.put("winning", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[-15.0f,0.0f,0.0f],LeftArm:[10.0f,0.0f,-10.0f],LeftLeg:[15.0f,0.0f,0.0f],RightArm:[-120.0f,-10.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("sitting", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[-80.0f,-20.0f,0.0f],LeftLeg:[-90.0f,-10.0f,0.0f],RightArm:[-80.0f,20.0f,0.0f],RightLeg:[-90.0f,10.0f,0.0f]}}");
poseMap.put("arabesque", "{Pose:{Body:[10.0f,0.0f,0.0f],Head:[-15.0f,0.0f,0.0f],LeftArm:[70.0f,0.0f,-10.0f],LeftLeg:[75.0f,0.0f,0.0f],RightArm:[-140.0f,-10.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("cupid", "{Pose:{Body:[10.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[-75.0f,0.0f,10.0f],LeftLeg:[75.0f,0.0f,0.0f],RightArm:[-90.0f,-10.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("point_and_laugh", "{Pose:{Body:[10.0f,7.0f,8.0f],Head:[25.0f,17.0f,-8.0f],LeftArm:[-90.0f,0.0f,20.0f],LeftLeg:[20.0f,30.0f,-10.0f],RightArm:[-8.0f,0.0f,-77.0f],RightLeg:[20.0f,-10.0f,20.0f]}}");
poseMap.put("confident", "{Pose:{Body:[-2.0f,0.0f,0.0f],Head:[-10.0f,20.0f,0.0f],LeftArm:[5.0f,0.0f,0.0f],LeftLeg:[0.0f,-10.0f,-4.0f],RightArm:[5.0f,0.0f,0.0f],RightLeg:[16.0f,2.0f,10.0f]}}");
poseMap.put("salute", "{Pose:{Body:[5.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[29.0f,0.0f,25.0f],LeftLeg:[0.0f,4.0f,2.0f],RightArm:[-124.0f,-51.0f,-35.0f],RightLeg:[0.0f,-4.0f,-2.0f]}}");
poseMap.put("death", "{Pose:{Body:[-90.0f,0.0f,0.0f],Head:[-85.0f,0.0f,0.0f],LeftArm:[-90.0f,-10.0f,0.0f],LeftLeg:[0.0f,0.0f,0.0f],RightArm:[-90.0f,10.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("facepalm", "{Pose:{Body:[10.0f,0.0f,0.0f],Head:[45.0f,-4.0f,1.0f],LeftArm:[-72.0f,24.0f,47.0f],LeftLeg:[-4.0f,-6.0f,-2.0f],RightArm:[18.0f,-14.0f,0.0f],RightLeg:[25.0f,-2.0f,0.0f]}}");
poseMap.put("lazing", "{Pose:{Body:[5.0f,0.0f,0.0f],Head:[14.0f,-12.0f,6.0f],LeftArm:[-4.0f,-20.0f,-10.0f],LeftLeg:[-88.0f,46.0f,0.0f],RightArm:[-40.0f,20.0f,0.0f],RightLeg:[-88.0f,71.0f,0.0f]}}");
poseMap.put("confused", "{Pose:{Body:[0.0f,13.0f,0.0f],Head:[0.0f,30.0f,0.0f],LeftArm:[145.0f,22.0f,-49.0f],LeftLeg:[-6.0f,0.0f,0.0f],RightArm:[-22.0f,31.0f,10.0f],RightLeg:[6.0f,-20.0f,0.0f]}}");
poseMap.put("formal", "{Pose:{Body:[4.0f,0.0f,0.0f],Head:[4.0f,0.0f,0.0f],LeftArm:[30.0f,-20.0f,21.0f],LeftLeg:[0.0f,0.0f,-5.0f],RightArm:[30.0f,22.0f,-20.0f],RightLeg:[0.0f,0.0f,5.0f]}}");
poseMap.put("sad", "{Pose:{Body:[10.0f,0.0f,0.0f],Head:[63.0f,0.0f,0.0f],LeftArm:[-5.0f,0.0f,-5.0f],LeftLeg:[-5.0f,16.0f,-5.0f],RightArm:[-5.0f,0.0f,5.0f],RightLeg:[-5.0f,-10.0f,5.0f]}}");
poseMap.put("joyous", "{Pose:{Body:[-4.0f,0.0f,0.0f],Head:[-11.0f,0.0f,0.0f],LeftArm:[0.0f,0.0f,-100.0f],LeftLeg:[-8.0f,0.0f,-60.0f],RightArm:[0.0f,0.0f,100.0f],RightLeg:[-8.0f,0.0f,60.0f]}}");
poseMap.put("stargazing", "{Pose:{Body:[-4.0f,10.0f,0.0f],Head:[-22.0f,25.0f,0.0f],LeftArm:[4.0f,18.0f,0.0f],LeftLeg:[6.0f,24.0f,0.0f],RightArm:[-153.0f,34.0f,-3.0f],RightLeg:[-4.0f,17.0f,2.0f]}}");
poseMap.put("block", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[0.0f,0.0f,0.0f],LeftLeg:[0.0f,0.0f,0.0f],RightArm:[-15.0f,-45.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("item", "{Pose:{Body:[0.0f,0.0f,0.0f],Head:[0.0f,0.0f,0.0f],LeftArm:[0.0f,0.0f,0.0f],LeftLeg:[0.0f,0.0f,0.0f],RightArm:[-90.0f,0.0f,0.0f],RightLeg:[0.0f,0.0f,0.0f]}}");
poseMap.put("random", "{Pose:{Body:[0.0f,90.0f,0.0f],Head:[25.0f,0.0f,0.0f],LeftArm:[0.0f,0.0f,-50.0f],LeftLeg:[0.0f,0.0f,-50.0f],RightArm:[0.0f,0.0f,50.0f],RightLeg:[0.0f,0.0f,50.0f]}");
return poseMap;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.mrbysco.armorposer.client.gui;

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.ToggleButton;
import com.mrbysco.armorposer.mixin.EditBoxAccessor;
import com.mrbysco.armorposer.platform.Services;
Expand All @@ -23,6 +25,8 @@
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.phys.Vec3;

import java.util.Map;

public class ArmorStandScreen extends Screen {
private final ArmorStand entityArmorStand;
private final ArmorStandData armorStandData;
Expand All @@ -33,7 +37,9 @@ public class ArmorStandScreen extends Screen {
private NumberFieldBox rotationTextField;
private final ToggleButton[] toggleButtons = new ToggleButton[6];
private final NumberFieldBox[] poseTextFields = new NumberFieldBox[3 * 7];
private final PoseButton[] poseButtons = new PoseButton[Reference.defaultPoseMap.size()];
private final boolean allowScrolling;
private boolean poseTabVisible = false;

private Vec3 lastSendOffset = new Vec3(0, 0, 0);

Expand Down Expand Up @@ -144,6 +150,10 @@ public void init() {
//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());

// done & cancel buttons
offsetX = this.width - 20;
Expand All @@ -159,15 +169,61 @@ public void init() {
this.updateEntity(this.armorStandData.writeToNBT());
this.minecraft.setScreen((Screen) null);
}).bounds(offsetX - 96, offsetY, 96, 20).build());


//Setup pose buttons
int centerX = this.width / 2;
int exclusionLeft = centerX - 60;
int exclusionRight = centerX + 80;
offsetX = 10;
offsetY = 10;

int id = 0;
for (Map.Entry<String, String> entry : Reference.defaultPoseMap.entrySet()) {
String poseID = entry.getKey();
String tag = entry.getValue();

final int buttonEnd = offsetX + 40;
if (buttonEnd >= exclusionLeft && buttonEnd <= exclusionRight) {
//Move the button until it's no longer in the exclusion zone
offsetX = exclusionRight;
}

this.addRenderableWidget(this.poseButtons[id] = new PoseButton.Builder(poseID, tag, (button) -> {
PoseButton poseButton = ((PoseButton) button);
if (poseButton.getPoseID().equals("random")) {
//Randomize all fields but the last 3 (as those are position) but don't make the rotations too crazy
for (int i = 0; i < this.poseTextFields.length - 3; i++) {
//generate a random number between -35 and 35
float randomRotation = (float) (Math.random() * 70 - 35);
this.poseTextFields[i].setValue(String.valueOf((int) randomRotation));
}
} else {
this.readFieldsFromNBT(poseButton.getTag());
}
this.updateEntity(poseButton.getTag());
}).pos(offsetX, offsetY).build());
//Disable visibility of the buttons at first
this.poseButtons[id].visible = this.poseTabVisible;

// Adjust the offsetX for the next button
offsetX += 40 + 4;
id++;

// Move to the next row if necessary
if (offsetX + 40 > this.width) {
offsetX = 10; // Reset the X position
offsetY += 40 + 4; // Move to the next row
}
}
}

@Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
this.renderBackground(guiGraphics);

// Draw gui title
guiGraphics.drawCenteredString(this.font, Component.translatable("armorposer.gui.title"),
this.width / 2, 10, 0xFFFFFF);
guiGraphics.drawCenteredString(this.font, Component.translatable("armorposer.gui.title"), this.width / 2, 10, 0xFFFFFF);

// Draw textboxes
this.rotationTextField.render(guiGraphics, mouseX, mouseY, partialTicks);
Expand All @@ -181,7 +237,8 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia
for (int i = 0; i < this.buttonLabels.length; i++) {
int x = offsetX;
int y = offsetY + (i * 22) + (10 - (this.font.lineHeight / 2));
guiGraphics.drawString(this.font, I18n.get("armorposer.gui.label." + this.buttonLabels[i]), x, y, 0xA0A0A0, false);
if (!poseTabVisible)
guiGraphics.drawString(this.font, I18n.get("armorposer.gui.label." + this.buttonLabels[i]), x, y, 0xA0A0A0, false);
}

// right column labels
Expand All @@ -195,7 +252,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia
String translatedLabel = I18n.get("armorposer.gui.label." + this.sliderLabels[i]);
int x = offsetX - this.font.width(translatedLabel) - 10;
int y = offsetY + (i * 22) + (10 - (this.font.lineHeight / 2));
guiGraphics.drawString(this.font, translatedLabel, x, y, 0xA0A0A0, false);
if (!poseTabVisible) guiGraphics.drawString(this.font, translatedLabel, x, y, 0xA0A0A0, false);
}

super.render(guiGraphics, mouseX, mouseY, partialTicks);
Expand All @@ -220,6 +277,34 @@ public void tick() {
//Adjust tooltip to show it's disabled
yPositionField.setTooltip(yPositionTooltipDisabled);
}

if (poseTabVisible) {
for (PoseButton poseButton : this.poseButtons) {
poseButton.visible = true;
}

//Show the rest of the fields
rotationTextField.visible = false;
for (ToggleButton toggleButton : toggleButtons) {
toggleButton.visible = false;
}
for (NumberFieldBox textField : poseTextFields) {
textField.visible = false;
}
} else {
for (PoseButton poseButton : this.poseButtons) {
poseButton.visible = false;
}

//Show the rest of the fields
rotationTextField.visible = true;
for (ToggleButton toggleButton : toggleButtons) {
toggleButton.visible = true;
}
for (NumberFieldBox textField : poseTextFields) {
textField.visible = true;
}
}
}

@Override
Expand Down Expand Up @@ -391,15 +476,11 @@ private CompoundTag writeFieldsToNBT() {
}

private void readFieldsFromNBT(CompoundTag compound) {
ArmorStandData armorStandData = new ArmorStandData();
armorStandData.readFromNBT(compound);

for (int i = 0; i < this.toggleButtons.length; i++) {
this.toggleButtons[i].setValue(armorStandData.getBooleanValue(i));
}
CompoundTag armorStandTag = this.armorStandData.writeToNBT();
armorStandTag.merge(compound);
this.armorStandData.readFromNBT(armorStandTag);

this.rotationTextField.setValue(String.valueOf((int) armorStandData.rotation));

for (int i = 0; i < this.poseTextFields.length; i++) {
this.poseTextFields[i].setValue(String.valueOf((int) armorStandData.pose[i]));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.mrbysco.armorposer.client.gui.widgets;

import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
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.InventoryScreen;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.TagParser;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;

import java.util.function.Function;

public class PoseButton extends Button {

private final String poseID;
private final CompoundTag tag;
private LivingEntity cachedEntity;

public PoseButton(int x, int y, int width, int height, String poseID, Component pose, CompoundTag tag, OnPress onPress, CreateNarration createNarration) {
super(x, y, width, height, pose, onPress, createNarration);
this.poseID = poseID;
this.tag = tag;

CompoundTag nbt = new CompoundTag();
nbt.putString("id", "minecraft:armor_stand");
if (!tag.isEmpty()) {
nbt.merge(tag);
}

Minecraft mc = Minecraft.getInstance();
Level level = mc.hasSingleplayerServer() && mc.getSingleplayerServer() != null ? mc.getSingleplayerServer().getAllLevels().iterator().next() : mc.level;
if (level != null) {
ArmorStand armorStand = (ArmorStand) EntityType.loadEntityRecursive(nbt, level, Function.identity());
if (armorStand != null) {
armorStand.setNoBasePlate(true);
armorStand.setShowArms(true);
armorStand.yBodyRot = 210.0F;
armorStand.setXRot(25.0F);
armorStand.yHeadRot = armorStand.getYRot();
armorStand.yHeadRotO = armorStand.getYRot();
this.cachedEntity = armorStand;
}
}
}

@Override
protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
super.renderWidget(guiGraphics, mouseX, mouseY, partialTick);
Minecraft minecraft = Minecraft.getInstance();

if (cachedEntity != null) {
InventoryScreen.renderEntityInInventory(guiGraphics, getX() + 20, getY() + 38, 15,
(new Quaternionf()).rotationXYZ(0.43633232F, 0.0F, (float) Math.PI), (Quaternionf) null, this.cachedEntity);

}

PoseStack poseStack = guiGraphics.pose();
poseStack.pushPose();
poseStack.translate(0, -14F, 100F);
int color = this.active ? 16777215 : 10526880;
this.renderScrollingString(guiGraphics, minecraft.font, 2, color | Mth.ceil(this.alpha * 255.0F) << 24);
poseStack.popPose();
}

@Override
public void renderString(GuiGraphics guiGraphics, Font font, int color) {
//
}

public CompoundTag getTag() {
return tag;
}

public String getPoseID() {
return poseID;
}

public static class Builder {
private final String poseID;
private final Component pose;
private CompoundTag tag = new CompoundTag();
private final OnPress onPress;
@Nullable
private Tooltip tooltip;
private int x;
private int y;
private int width = 40;
private int height = 40;
private CreateNarration createNarration = Button.DEFAULT_NARRATION;

public Builder(String poseID, String tag, OnPress onPress) {
this.poseID = poseID;
this.pose = Component.translatable(("armorposer.gui.pose." + poseID));
try {
this.tag = TagParser.parseTag(tag);
} catch (Exception e) {
//Nope
}
this.onPress = onPress;
}

public PoseButton.Builder pos(int x, int y) {
this.x = x;
this.y = y;
return this;
}

public PoseButton.Builder size(int width, int height) {
this.width = width;
this.height = height;
return this;
}

public PoseButton.Builder bounds(int x, int y, int width, int height) {
return this.pos(x, y).size(width, height);
}

public PoseButton.Builder tooltip(@Nullable Tooltip tooltip) {
this.tooltip = tooltip;
return this;
}

public PoseButton.Builder createNarration(CreateNarration createNarration) {
this.createNarration = createNarration;
return this;
}

public PoseButton build() {
PoseButton button = new PoseButton(this.x, this.y, this.width, this.height, this.poseID, this.pose, this.tag, this.onPress, this.createNarration);
button.setTooltip(this.tooltip);
return button;
}
}
}
Loading

0 comments on commit fa38d04

Please sign in to comment.