From 4e080ad392b07f60aa30a100c3153e709062549f Mon Sep 17 00:00:00 2001 From: Jkibbels Date: Sat, 15 Feb 2025 00:12:42 -0500 Subject: [PATCH] #3 Added GUI support for start of shop system. Still premature, but it's finally starting to get there --- .../keeblarcraft/ClientHelpers/Helper.java | 9 + .../Entities/ShopKeeperModel.java | 35 ++ .../Entities/ShopKeeperRenderer.java | 2 +- .../keeblarcraft/KeeblarcraftClient.java | 15 +- .../Shortcuts/ShortcutManager.java | 3 - .../keeblarcraft/gui/ClientHandlers.java | 4 +- .../FactionBlockScreen.java | 5 +- .../jesse/keeblarcraft/gui/GenericLayerT.java | 74 ---- .../gui/Generics/ClickableLayer.java | 55 +++ .../jesse/keeblarcraft/gui/ScreenManager.java | 381 ------------------ .../gui/ShopKeeperGUI/NewItemButton.java | 41 ++ .../gui/ShopKeeperGUI/NewItemMenu.java | 45 +++ .../gui/ShopKeeperGUI/ShopKeeperMenu.java | 108 +++++ .../keeblarcraft/gui/widgets/TreeWidget.java | 165 -------- .../mixin/ClientPlayNetworkHandlerMixin.java | 26 ++ .../ClientPlayerInteractionManagerMixin.java | 17 - .../BlockEntities/FactionBlockEntity.java | 1 - .../keeblarcraft/CustomItems/ItemManager.java | 3 + .../Entities/EntityRegistration.java | 2 +- .../keeblarcraft/Entities/ShopKeeper.java | 75 +++- .../GuiMgr/ScreenHandlerRegistration.java | 9 +- .../GuiMgr/ShopKeeperHandler.java | 62 +++ .../java/jesse/keeblarcraft/Keeblarcraft.java | 8 +- .../keeblarcraft/mixin/EntitySpawnMixin.java | 2 - .../jesse/keeblarcraft/mixin/PlayerMixin.java | 2 +- .../assets/keeblarcraft/lang/en_us.json | 2 + .../models/item/shop_keeper_spawn_egg.json | 3 + .../textures/gui/shopkeeper_add_icon.jpeg | Bin 0 -> 5728 bytes .../gui/shopkeeper_checkout_button.jpeg | Bin 0 -> 6415 bytes .../textures/gui/shopkeeper_gui.jpeg | Bin 0 -> 41223 bytes .../textures/gui/shopkeeper_item_slot.jpeg | Bin 0 -> 1348 bytes .../textures/gui/shopkeeper_scrollbar.jpeg | Bin 0 -> 1498 bytes .../textures/gui/shopkeeper_subtract.png | Bin 0 -> 572 bytes src/main/resources/keeblarcraft.mixins.json | 2 +- 34 files changed, 478 insertions(+), 678 deletions(-) create mode 100644 src/client/java/jesse/keeblarcraft/ClientHelpers/Helper.java create mode 100644 src/client/java/jesse/keeblarcraft/Entities/ShopKeeperModel.java rename src/{main/java/jesse/keeblarcraft/GuiMgr => client/java/jesse/keeblarcraft}/Entities/ShopKeeperRenderer.java (87%) rename src/client/java/jesse/keeblarcraft/gui/{ => FactionBlockGUI}/FactionBlockScreen.java (88%) delete mode 100644 src/client/java/jesse/keeblarcraft/gui/GenericLayerT.java create mode 100644 src/client/java/jesse/keeblarcraft/gui/Generics/ClickableLayer.java delete mode 100644 src/client/java/jesse/keeblarcraft/gui/ScreenManager.java create mode 100644 src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemButton.java create mode 100644 src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemMenu.java create mode 100644 src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/ShopKeeperMenu.java delete mode 100644 src/client/java/jesse/keeblarcraft/gui/widgets/TreeWidget.java create mode 100644 src/client/java/jesse/keeblarcraft/mixin/ClientPlayNetworkHandlerMixin.java delete mode 100644 src/client/java/jesse/keeblarcraft/mixin/ClientPlayerInteractionManagerMixin.java create mode 100644 src/main/java/jesse/keeblarcraft/GuiMgr/ShopKeeperHandler.java create mode 100644 src/main/resources/assets/keeblarcraft/models/item/shop_keeper_spawn_egg.json create mode 100644 src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_add_icon.jpeg create mode 100644 src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_checkout_button.jpeg create mode 100644 src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_gui.jpeg create mode 100644 src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_item_slot.jpeg create mode 100644 src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_scrollbar.jpeg create mode 100644 src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_subtract.png diff --git a/src/client/java/jesse/keeblarcraft/ClientHelpers/Helper.java b/src/client/java/jesse/keeblarcraft/ClientHelpers/Helper.java new file mode 100644 index 0000000..210ab73 --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/ClientHelpers/Helper.java @@ -0,0 +1,9 @@ +package jesse.keeblarcraft.ClientHelpers; + +public class Helper { + public static boolean WithinBounds(double x, double y, double w, double h, double clickX, double clickY) { +// System.out.println("Mouse click X Y: " + clickX + " " + clickY); +// System.out.println("Rectangle X Y W H: " + x + " " + y + " " + w + " " + h); + return (clickX >= x) && (clickX <= x + w) && (clickY >= y) && (clickY <= y + h); + } +} diff --git a/src/client/java/jesse/keeblarcraft/Entities/ShopKeeperModel.java b/src/client/java/jesse/keeblarcraft/Entities/ShopKeeperModel.java new file mode 100644 index 0000000..388fe0c --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/Entities/ShopKeeperModel.java @@ -0,0 +1,35 @@ +package jesse.keeblarcraft.Entities; + +import net.minecraft.client.model.*; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.render.entity.model.EntityModelPartNames; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.include.com.google.common.collect.ImmutableList; + +public class ShopKeeperModel extends EntityModel { + private final ModelPart base; + public ShopKeeperModel(ModelPart modelPart) { + this.base = modelPart.getChild(EntityModelPartNames.CUBE); + } + + public static TexturedModelData getTexturedModelData() { + ModelData modelData = new ModelData(); + ModelPartData modelPartData = modelData.getRoot(); + modelPartData.addChild(EntityModelPartNames.CUBE, ModelPartBuilder.create().uv(0, 0).cuboid(-6F, 12F, -6F, 12F, 12F, 12F), + ModelTransform.pivot(0F, 0F, 0F)); + return TexturedModelData.of(modelData, 64, 64); + } + + @Override + public void setAngles(ShopKeeper entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) { + + } + + @Override + public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) { + ImmutableList.of(this.base).forEach((modelRenderer) -> { + modelRenderer.render(matrices, vertices, light, overlay, red, green, blue, alpha); + }); + } +} diff --git a/src/main/java/jesse/keeblarcraft/GuiMgr/Entities/ShopKeeperRenderer.java b/src/client/java/jesse/keeblarcraft/Entities/ShopKeeperRenderer.java similarity index 87% rename from src/main/java/jesse/keeblarcraft/GuiMgr/Entities/ShopKeeperRenderer.java rename to src/client/java/jesse/keeblarcraft/Entities/ShopKeeperRenderer.java index 8592a8a..346db3c 100644 --- a/src/main/java/jesse/keeblarcraft/GuiMgr/Entities/ShopKeeperRenderer.java +++ b/src/client/java/jesse/keeblarcraft/Entities/ShopKeeperRenderer.java @@ -1,4 +1,4 @@ -package jesse.keeblarcraft.GuiMgr.Entities; +package jesse.keeblarcraft.Entities; import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.VillagerEntityRenderer; diff --git a/src/client/java/jesse/keeblarcraft/KeeblarcraftClient.java b/src/client/java/jesse/keeblarcraft/KeeblarcraftClient.java index f3c3ace..a92dbc2 100644 --- a/src/client/java/jesse/keeblarcraft/KeeblarcraftClient.java +++ b/src/client/java/jesse/keeblarcraft/KeeblarcraftClient.java @@ -1,28 +1,27 @@ package jesse.keeblarcraft; import jesse.keeblarcraft.Entities.EntityRegistration; -import jesse.keeblarcraft.GuiMgr.Entities.ShopKeeperRenderer; +import jesse.keeblarcraft.Entities.ShopKeeperModel; import jesse.keeblarcraft.gui.ClientHandlers; import jesse.keeblarcraft.Shortcuts.ShortcutManager; +import jesse.keeblarcraft.Entities.ShopKeeperRenderer; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.minecraft.client.render.entity.model.EntityModelLayer; import net.minecraft.util.Identifier; public class KeeblarcraftClient implements ClientModInitializer { public static final EntityModelLayer SHOP_KEEPER_LAYER = new EntityModelLayer(new Identifier("textures/entity/villager/villager.png"), "VILLAGE_ENTITY_MODEL_LAYER"); + @Override public void onInitializeClient() { ShortcutManager.RegisterKeybinds(); ClientHandlers.RegisterHandlers(); -// EntityRendererRegistry.INSTANCE.register(EntityRegistration.SHOP_KEEPER_ENTITY_TYPE, (context) -> { -// return new ShopKeeperRenderer(context); -// }); - - // ScreenManager.GetInstance(); - // ScreenManager.AddWidget(TreeWidget.class, 10); + EntityRendererRegistry.register(EntityRegistration.SHOP_KEEPER_ENTITY_TYPE, ShopKeeperRenderer::new); + EntityModelLayerRegistry.registerModelLayer(SHOP_KEEPER_LAYER, ShopKeeperModel::getTexturedModelData); } } diff --git a/src/client/java/jesse/keeblarcraft/Shortcuts/ShortcutManager.java b/src/client/java/jesse/keeblarcraft/Shortcuts/ShortcutManager.java index 218ceb7..2fb17f8 100644 --- a/src/client/java/jesse/keeblarcraft/Shortcuts/ShortcutManager.java +++ b/src/client/java/jesse/keeblarcraft/Shortcuts/ShortcutManager.java @@ -11,8 +11,6 @@ package jesse.keeblarcraft.Shortcuts; import org.lwjgl.glfw.GLFW; -// import jesse.keeblarcraft.Keeblarcraft; -// import jesse.keeblarcraft.gui.ScreenManager; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.minecraft.client.MinecraftClient; @@ -25,7 +23,6 @@ public class ShortcutManager { private static KeyBinding skillTreeShortcut; private static KeyBinding globalConfig; private static Boolean toggleTreeGui = true; // Initialized to true for first time pressing keybind to actually display gui - // private static ScreenManager treeGui = null; ///////////////////////////////////////////////////////////////////////////// /// @fn RegisterKeybinds diff --git a/src/client/java/jesse/keeblarcraft/gui/ClientHandlers.java b/src/client/java/jesse/keeblarcraft/gui/ClientHandlers.java index 079ca75..d70189e 100644 --- a/src/client/java/jesse/keeblarcraft/gui/ClientHandlers.java +++ b/src/client/java/jesse/keeblarcraft/gui/ClientHandlers.java @@ -1,7 +1,8 @@ package jesse.keeblarcraft.gui; -import jesse.keeblarcraft.Keeblarcraft; import jesse.keeblarcraft.GuiMgr.ScreenHandlerRegistration; +import jesse.keeblarcraft.gui.FactionBlockGUI.FactionBlockScreen; +import jesse.keeblarcraft.gui.ShopKeeperGUI.ShopKeeperMenu; import net.minecraft.client.gui.screen.ingame.HandledScreens; public class ClientHandlers { @@ -9,5 +10,6 @@ public class ClientHandlers { System.out.println("Registering tree handler screen"); // HandledScreens.register(Keeblarcraft.TREE_HANDLER, ScreenManager::new); HandledScreens.register(ScreenHandlerRegistration.FACTION_BLOCK_SCREEN_HANDLER, FactionBlockScreen::new); + HandledScreens.register(ScreenHandlerRegistration.SHOP_KEEPER_HANDLER_SCREEN_HANDLER_TYPE, ShopKeeperMenu::new); } } diff --git a/src/client/java/jesse/keeblarcraft/gui/FactionBlockScreen.java b/src/client/java/jesse/keeblarcraft/gui/FactionBlockGUI/FactionBlockScreen.java similarity index 88% rename from src/client/java/jesse/keeblarcraft/gui/FactionBlockScreen.java rename to src/client/java/jesse/keeblarcraft/gui/FactionBlockGUI/FactionBlockScreen.java index bf85663..a54f95f 100644 --- a/src/client/java/jesse/keeblarcraft/gui/FactionBlockScreen.java +++ b/src/client/java/jesse/keeblarcraft/gui/FactionBlockGUI/FactionBlockScreen.java @@ -1,4 +1,4 @@ -package jesse.keeblarcraft.gui; +package jesse.keeblarcraft.gui.FactionBlockGUI; import com.mojang.blaze3d.systems.RenderSystem; @@ -36,10 +36,7 @@ public class FactionBlockScreen extends HandledScreen this.backgroundHeight = 256; this.backgroundWidth = 256; - int x = (width - backgroundWidth) / 2; - int y = (height - backgroundHeight) / 2; - context.drawTexture(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight); } @Override diff --git a/src/client/java/jesse/keeblarcraft/gui/GenericLayerT.java b/src/client/java/jesse/keeblarcraft/gui/GenericLayerT.java deleted file mode 100644 index ffb8481..0000000 --- a/src/client/java/jesse/keeblarcraft/gui/GenericLayerT.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * GenericLayerT - * - * GenericLayerT is the class that all layers must inherit from in order to be drawn. This allows for the GUI to properly - * draw the layers on which you want your canvas to exist! - * - * -*/ - -package jesse.keeblarcraft.gui; - -import jesse.keeblarcraft.Utils.CommonStructures.Position2d; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.text.Text; - -abstract public class GenericLayerT extends ClickableWidget { - // These are the box bounds of the widget - public int startX; - public int startY; - public int endX; - public int endY; - - public GenericLayerT() { - // default constructor - super(0, 0, 0, 0, Text.of("")); - } - - ///////////////////////////////////////////////////////////////////////////// - /// @fn GenericLayerT - /// - /// @brief Constructor for class. This is setup directly by the screen - /// manager object and it is not recommended to change the x/y - /// positions or you may break the relation of your widget to - /// others on the screen at the same time! - ///////////////////////////////////////////////////////////////////////////// - public GenericLayerT(int x, int y, int width, int height, Text message) { - super(x, y, width, height, message); - } - - ///////////////////////////////////////////////////////////////////////////// - /// @fn DrawLayer - /// - /// @brief Draw on a layer! This is an early implementation of being - /// able to choose the layer you are drawing on and making sure - /// you can customize which layer your context will draw on. - /// This will be called by the overall screen manager so the - /// layer id will be passed in. You will need to handle the layer - /// id yourself. - /// - /// @note It is possible to get passed any layer id and you handle each - /// layer respectively; however, it is possible to draw on the - /// wrong layer if handled wrong. For example, you could be - /// passed layer '3' but this function is called for every layer - /// drawn on screen; so you must handle this to only draw on a - /// specific layer. Be careful! - ///////////////////////////////////////////////////////////////////////////// - public abstract void DrawLayer(DrawContext context, int layer); - - public void UpdateAnchorValues(int x, int y) { - this.startX = x; - this.startY = y; - } - - // Calculated based on center of box values - public Position2d GetScreenCenter() { - return new Position2d((this.endX - this.startX) / 2, (this.endY - this.startY) / 2); - } - - public abstract void renderButton(DrawContext context, int mouseX, int mouseY, float delta); - protected abstract void appendClickableNarrations(NarrationMessageBuilder builder); -} \ No newline at end of file diff --git a/src/client/java/jesse/keeblarcraft/gui/Generics/ClickableLayer.java b/src/client/java/jesse/keeblarcraft/gui/Generics/ClickableLayer.java new file mode 100644 index 0000000..949bace --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/gui/Generics/ClickableLayer.java @@ -0,0 +1,55 @@ +package jesse.keeblarcraft.gui.Generics; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.ArrayList; +import java.util.List; + +abstract public class ClickableLayer extends ClickableWidget { + private final Identifier texture; + private final Text layerName; + private final List subLayers = new ArrayList<>(); + + protected abstract void appendClickableNarrations(NarrationMessageBuilder builder); + + public ClickableLayer(Identifier texture, Text layerName, int width, int height, int startX, int startY) { + super(startX, startY, width, height, Text.empty()); + this.texture = texture; + this.layerName = layerName; + } + + protected void AddSubLayer(ClickableLayer newLayer) { + subLayers.add(newLayer); + } + + protected void ClearSubLayers() { + subLayers.clear(); + } + + public List GetSubLayers() { + return subLayers; + } + + // This will be called every draw frame + public void UpdateSubLayers() { + + } + + @Override + public void renderButton(DrawContext context, int mouseX, int mouseY, float delta) { + context.drawTexture(this.GetTexture(), this.getX(), this.getY(), 0, 0, this.getWidth(), this.getHeight(), this.getWidth(), this.getHeight()); + + } + + public Identifier GetTexture() { + return this.texture; + } + + public Text GetLayerName() { + return this.layerName; + } +} diff --git a/src/client/java/jesse/keeblarcraft/gui/ScreenManager.java b/src/client/java/jesse/keeblarcraft/gui/ScreenManager.java deleted file mode 100644 index 26688e3..0000000 --- a/src/client/java/jesse/keeblarcraft/gui/ScreenManager.java +++ /dev/null @@ -1,381 +0,0 @@ -// /* -// * -// * ScreenManager -// * -// * This is the screen manager for the global screen handler of `TreeHandler` type -// * Please note: `TreeHandler` is suited for a more broad range of things; however -// * its initial implementation is for the skill tree. It will be renamed to a more -// * generic name so this class is more obviously re-usable after its implementation -// * is complete AND we verify this class can be made more generic for it. Since this -// * is unknown, it will remain the name it has currently. -// * -// * -// */ - -// package jesse.keeblarcraft.gui; - -// import java.lang.reflect.InvocationTargetException; -// import java.util.ArrayList; -// import java.util.HashMap; -// import java.util.List; -// import java.util.Map.Entry; - -// import jesse.keeblarcraft.Keeblarcraft; -// import jesse.keeblarcraft.GuiMgr.TreeHandler; -// import net.minecraft.client.MinecraftClient; -// import net.minecraft.client.gui.DrawContext; -// import net.minecraft.client.gui.screen.Screen; -// import net.minecraft.client.gui.screen.ingame.HandledScreen; -// import net.minecraft.entity.player.PlayerInventory; -// import net.minecraft.text.Text; - -// // Client side renderer -// public class ScreenManager extends HandledScreen { -// private static ScreenManager static_inst; -// @SuppressWarnings("resource") -// private static PlayerInventory static_inventory = new PlayerInventory(null);// = MinecraftClient.getInstance().player.getInventory(); - -// public static ScreenManager GetInstance() { -// if (static_inst == null) { -// static_inst = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, static_inventory), static_inventory, Text.of("Test")); -// } -// return static_inst; -// } - -// private static HashMap>> layerMap = new HashMap>>(); -// private static HashMap> layers = new HashMap>(); // key: layer id; value: list of classes to draw - -// // private TreeWidget treeWidget = null; -// private Screen parent; - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn ScreenManager -// /// -// /// @arg[in] handler is the TreeHandler (ScreenHandler) object -// /// -// /// @arg[in] inventory is the players inventory. Required by HandledScreen -// /// object however is unused currently in this Screen -// /// -// /// @arg[in] title is the title of the screen window -// /// -// /// @brief Class constructor -// ///////////////////////////////////////////////////////////////////////////// -// public ScreenManager(TreeHandler handler, PlayerInventory inventory, Text title) { -// super(handler, inventory, title); -// System.out.println("Called constructor of screen manager!"); - -// // Initialize layers in map -// // for (int i = 0; i < NUMBER_DRAW_LAYERS; i++) { -// // layers.put(i, new ArrayList>()); -// // } -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn AddParent -// /// -// /// @arg[in] parent is the parent screen object -// /// -// /// @brief Add a parent screen to the screen object. This is useful if -// /// you want to return to the previous screen when this one gets -// /// closed by the user -// ///////////////////////////////////////////////////////////////////////////// -// public void AddParent(Screen parent) { -// this.parent = parent; -// } - -// public static void AddWidget(Class widget, int drawLayer) { -// if (layerMap.containsKey(drawLayer)) { -// // Just append the widget to the draw layer -// var layerList = layerMap.get(drawLayer); -// layerList.add(widget); -// } else { -// // Brand new layer! -// layerMap.put(drawLayer, new ArrayList<>(List.of(widget))); -// } -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn init -// /// -// /// @brief Initialize method; called one-time to setup class variables -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public void init() { -// // initialize screen size to the global background picture -// this.width = MinecraftClient.getInstance().getWindow().getScaledWidth(); -// this.height = MinecraftClient.getInstance().getWindow().getScaledHeight(); - -// // Let's go through and initialize all the screen types now in our active memory -// for (Entry>> layerEntry : layerMap.entrySet()) { -// var layerList = layerEntry.getValue(); - -// layers.put(layerEntry.getKey(), new ArrayList<>()); -// var activeLayerList = layers.get(layerEntry.getKey()); -// for (int i = 0; i < layerList.size(); i++) { -// try { -// System.out.println("Attempting to initialize widget with information: LAYER I-VAL W H: " + layerEntry.getKey() + " " + i + " " + this.width + " " + this.height); -// GenericLayerT initializedWidget = layerList.get(i).getDeclaredConstructor(int.class, int.class, int.class, int.class, Text.class).newInstance(0, 0, this.width, this.height, Text.of("")); -// activeLayerList.add(initializedWidget); -// } catch (InstantiationException e) { -// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IntantiationException"); -// e.printStackTrace(); -// } catch (IllegalAccessException e) { -// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalAccessException"); -// e.printStackTrace(); -// } catch (IllegalArgumentException e) { -// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalArgumentException"); -// e.printStackTrace(); -// } catch (InvocationTargetException e) { -// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of InvocationTargetException"); -// e.printStackTrace(); -// } catch (NoSuchMethodException e) { -// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of NoSuchMethodException"); -// e.printStackTrace(); -// } catch (SecurityException e) { -// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of SecurityException"); -// e.printStackTrace(); -// } -// } -// } - - -// // Initialize child widgets with correct screen values so they can draw themselves in the right area on the screen (duh!) -// // treeWidget = new TreeWidget(GLOBAL_SCREEN_START_X + 24, GLOBAL_SCREEN_START_Y + 24, GLOBAL_SCREEN_WIDTH - 24, GLOBAL_SCREEN_HEIGHT - 24); -// // this.addDrawableChild(treeWidget); -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn render -// /// -// /// @arg[in] context is the drawing context of super class -// /// -// /// @arg[in] mouseX is passed to parent class but unused here -// /// -// /// @arg[in] mouseY is passed to parent class but unused here -// /// -// /// @brief Render is called every frame while the screen is open -// /// -// /// @note This is a pure abstract in parent and is required -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public void render(DrawContext context, int mouseX, int mouseY, float delta) { -// super.render(context, mouseX, mouseY, delta); // This takes care of calling drawBackground which calls DrawMainScreen -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn drawForeground -// /// -// /// @arg[in] context is the drawing context of super class -// /// -// /// @arg[in] mouseX is unused -// /// -// /// @arg[in] mouseY is unused -// /// -// /// @brief Draw foreground exists to draw the titles; however we -// /// intentionally override it so the superclass object does not -// /// draw the overlay over the background screen -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public void drawForeground(DrawContext context, int mouseX, int mouseY) { -// // We override this function to intentionally do nothing -// // If in the future we want, we would draw the foreground and TITLES with this! -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn close -// /// -// /// @brief Called when the screen closes -// /// -// /// @note This is a pure abstract in parent and is required -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public void close() { -// this.client.setScreen(parent); // return to previous screen or null -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn mouseDragged -// /// -// /// @arg[in] mouseX is x-axis position of original mouse click -// /// -// /// @arg[in] mouseY is y-axis position of original mouse click -// /// -// /// @arg[in] button is the int value of button pressed for mouse dragging -// /// -// /// @arg[in] deltaX is the change in the X position from the previous -// /// mouse click -// /// -// /// @arg[in] deltaY is the change in the Y position from the previous -// /// mouse click -// /// -// /// @brief The drag event is called on all widgets on the screen so -// /// long as the initial position of the drag is within the -// /// bounds of the widget box itself. Widgets themselves will need -// /// to handle any sub-widgets since the bound check is only -// /// there to verify if the event happened ANYWHERE within a -// /// widget box -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { -// super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); -// // UpdateAnchorValues(); - -// for (Entry> layerEntry : layers.entrySet()) { -// var layerList = layerEntry.getValue(); - -// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { -// var layer = layerList.get(layerListIterator); - -// // Check to make sure scroll is within the context of the widget then deliver information -// if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) { -// layer.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); -// } -// } -// } -// return true; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn mouseScrolled -// /// -// /// @arg[in] mouseX is the initial X position of the cursor on a scroll -// /// -// /// @arg[in] mouseY is the initial Y position of the cursor on a scroll -// /// -// /// @arg[in] amount is a normalized value that indicates scroll direction -// /// -// /// @brief The scroll event is called on all widgets on the screen so -// /// long as the initial position of the scroll is within the -// /// bounds of the widget box itself. Widgets themselves will need -// /// to handle any sub-widgets since the bound check is only -// /// there to verify if the event happened ANYWHERE within a -// /// widget box -// /// -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public boolean mouseScrolled(double mouseX, double mouseY, double amount) { -// super.mouseScrolled(mouseX, mouseY, amount); - -// for (Entry> layerEntry : layers.entrySet()) { -// var layerList = layerEntry.getValue(); - -// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { -// var layer = layerList.get(layerListIterator); - -// // Check to make sure scroll is within the context of the widget then deliver information -// if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) { -// layer.mouseScrolled(mouseX, mouseY, amount); -// } -// } -// } -// return true; // The parent function defines this to be boolean; but I have no idea when I would want to return false from this -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn mouseClicked -// /// -// /// @arg[in] mouseX is the initial X position of the mouse click event -// /// -// /// @arg[in] mouseY is the initial Y position of the mouse click event -// /// -// /// @arg[in] button is the mouse click button (left/right click value) -// /// -// /// @brief The mouse click is called on all widgets on the screen so -// /// long as the initial position of the click is within the -// /// bounds of the widget box itself. Widgets themselves will need -// /// to handle any sub-widgets since the bound check is only -// /// there to verify if the event happened ANYWHERE within a -// /// widget box -// /// -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public boolean mouseClicked(double mouseX, double mouseY, int button) { -// super.mouseClicked(mouseX, mouseY, button); - -// for (Entry> layerEntry : layers.entrySet()) { -// var layerList = layerEntry.getValue(); - -// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { -// var layer = layerList.get(layerListIterator); - -// // Check to make sure scroll is within the context of the widget then deliver information -// if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) { -// layer.mouseClicked(mouseX, mouseY, button); -// } -// } -// } -// return true; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn DrawLayers -// /// -// /// @arg[in] context is the global drawing context for the screen -// /// -// /// @arg[in] delta is passed in from background draw -// /// -// /// @brief This is the primary drawing function so that all the texture -// /// draws can be done in one place in this class. We want as -// /// little distance as possible between redraws when possible! -// /// -// /// @note Currently the foreground is not drawn in the custom screen -// /// manager. This is because the foreground features the general -// /// inventory manager that this screen handler is based on and we -// /// do not want to see those text pop ups. -// ///////////////////////////////////////////////////////////////////////////// -// public void DrawLayers(DrawContext context, float delta) { -// for (Entry> layerEntry : layers.entrySet()) { -// var layerList = layerEntry.getValue(); - -// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { -// var layer = layerList.get(layerListIterator); -// System.out.println("Drawing layer " + layerEntry.getKey() + " for class type " + layer.getClass().toString()); -// layer.DrawLayer(context, layerEntry.getKey()); -// } -// } -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn InBounds -// /// -// /// @arg[in] initX is initial position of X axis -// /// -// /// @arg[in] initY is initial position of Y axis -// /// -// /// @arg[in] endX is the end position of X axis -// /// -// /// @arg[in] endY is the end position of Y axis -// /// -// /// @arg[in] x is the current X value we are comparing in the X axis -// /// -// /// @arg[in] y is the current Y value we are comparing in the Y axis -// /// -// /// @brief Checks if an x,y coordinate position falls within the bounds -// /// of a bounded box -// ///////////////////////////////////////////////////////////////////////////// -// private boolean InBounds(int initX, int initY, int endX, int endY, int x, int y) { -// return (x >= initX && x <= endX) && (y >= initY && y <= endY); -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn drawBackground -// /// -// /// @arg[in] context is the drawing context of super class -// /// -// /// @arg[in] delta is the change in background draw -// /// -// /// @arg[in] mouseX is the mouse x-axis position -// /// -// /// @arg[in] mouseY is the mouse y-axis position -// /// -// /// @brief This function is an abstract parent class and must be -// /// implemented. This is "hijacked" and just being used as our -// /// main drawing method of all the background images. There isn't -// /// a huge difference of drawing our stuff in background vs the -// /// foreground - except possibly foreground is drawn first. -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { -// DrawLayers(context, delta); -// } -// } diff --git a/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemButton.java b/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemButton.java new file mode 100644 index 0000000..330a12e --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemButton.java @@ -0,0 +1,41 @@ +package jesse.keeblarcraft.gui.ShopKeeperGUI; + +import jesse.keeblarcraft.ClientHelpers.Helper; +import jesse.keeblarcraft.Keeblarcraft; +import jesse.keeblarcraft.gui.Generics.ClickableLayer; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class NewItemButton extends ClickableLayer { + private static final Identifier NEW_ITEM_MENU = new Identifier(Keeblarcraft.MOD_ID, "textures/gui/shopkeeper_item_slot.jpeg"); + private static NewItemMenu newItemMenu; + + public NewItemButton(Identifier texture, Text layerName, int width, int height, int startX, int startY) { + super(texture, layerName, width, height, startX, startY); + + // These values may be temporary + newItemMenu = new NewItemMenu(NEW_ITEM_MENU, Text.of("Add Item"), 32, 24, this.getX() + 20, this.getY() + 20); + } + + @Override + public void onClick(double x, double y) { + // Toggle the menu sub layer to be on if it was clicked. @See UpdateSubLayers for when it gets closed + System.out.println("Status of new item menu: " + newItemMenu.IsOpen()); + if (!newItemMenu.IsOpen()) { + System.out.println("Adding new item menu and telling it to open"); + this.AddSubLayer(newItemMenu); + newItemMenu.OpenMenu(); + } + } + + @Override + public void UpdateSubLayers() { + if (!newItemMenu.IsOpen()) { + this.ClearSubLayers(); + } + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) {} +} diff --git a/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemMenu.java b/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemMenu.java new file mode 100644 index 0000000..bc79b13 --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/NewItemMenu.java @@ -0,0 +1,45 @@ +package jesse.keeblarcraft.gui.ShopKeeperGUI; + +import jesse.keeblarcraft.ClientHelpers.Helper; +import jesse.keeblarcraft.gui.Generics.ClickableLayer; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class NewItemMenu extends ClickableLayer { + private boolean isOpen = false; + public NewItemMenu(Identifier texture, Text layerName, int width, int height, int startX, int startY) { + super(texture, layerName, width, height, startX, startY); + System.out.println("Item menu created at coordinates X Y: " + this.getX() + " " + this.getY()); + } + + public void CloseMenu() { + this.isOpen = false; + this.visible = false; + } + + public void OpenMenu() { + this.visible = true; + this.isOpen = true; + } + + public boolean IsOpen() { + return this.isOpen; + } + + @Override + public void onClick(double x, double y) { + // Check to see if user clicked the 'x' area (mark closed in case) + // TODO: The coordinates for the 'X' button aren't known at the moment. For now just mark + // TODO: top right of the image with a 5 pixel buffer + if (this.visible && Helper.WithinBounds((this.getX() + this.getWidth() - 5), this.getY(), 5, 5, x, y)) { + System.out.println("User clicked fake 'X' button"); + this.isOpen = false; + } + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) { + + } +} diff --git a/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/ShopKeeperMenu.java b/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/ShopKeeperMenu.java new file mode 100644 index 0000000..975e411 --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/gui/ShopKeeperGUI/ShopKeeperMenu.java @@ -0,0 +1,108 @@ +package jesse.keeblarcraft.gui.ShopKeeperGUI; + +import jesse.keeblarcraft.GuiMgr.ShopKeeperHandler; +import jesse.keeblarcraft.Keeblarcraft; +import jesse.keeblarcraft.ClientHelpers.Helper; +import jesse.keeblarcraft.gui.Generics.ClickableLayer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ShopKeeperMenu extends HandledScreen { + private static final Identifier MENU_TEXTURE = new Identifier(Keeblarcraft.MOD_ID, "textures/gui/shopkeeper_gui.jpeg"); + private static final Identifier ADD_BUTTON = new Identifier(Keeblarcraft.MOD_ID, "textures/gui/shopkeeper_add_icon.jpeg"); + private static final Identifier NEW_ITEM_MENU = new Identifier(Keeblarcraft.MOD_ID, "textures/gui/shopkeeper_item_slot.jpeg"); + private int x = 0; + private int y = 0; + private final List layers = new ArrayList<>(); + + public ShopKeeperMenu(ShopKeeperHandler handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + } + + @Override + protected void init() { + super.init(); + titleY = 1000; //begone from screen + playerInventoryTitleY = 1000; //begone from screen + + // Set the main shop keeping menu variables here + this.backgroundWidth = 256; + this.backgroundHeight = 256; + this.x = (width - backgroundWidth) / 2; + this.y = (height - backgroundHeight) / 2; + + // Add all layers below + AddNewButton(ADD_BUTTON, Text.of("ADD ITEM BUTTON"), x, y, 64, 64); + } + + @Override + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + // Draw the menu texture first +// context.drawTexture(MENU_TEXTURE, this.x, this.y, 0, 0, this.backgroundWidth, this.backgroundHeight); + context.drawTexture(MENU_TEXTURE, this.x, this.y, 0, 0, this.backgroundWidth, this.backgroundHeight, this.backgroundWidth, this.backgroundHeight); +// context.drawTexture(NEW_ITEM_MENU, this.x, this.y, 0, 0, 32, 24); +// context.drawTexture(NEW_ITEM_MENU, this.x, this.y, 0, 0, 32, 24, 32, 24); + + for (ClickableLayer layer : layers) { + layer.renderButton(context, mouseX, mouseY, delta); + + for (ClickableLayer subLayer : layer.GetSubLayers()) { + subLayer.renderButton(context, mouseX, mouseY, delta); + } + + // We only notify the parent to update sub layers. It must manage its own sub layers + layer.UpdateSubLayers(); + } + } + + // Takes an image and adds it to the background draw list and saves coordinates to return to a callback if it is clicked + private void AddNewButton(Identifier iconId, Text layerName, int drawX, int drawY, int imgWidth, int imgHeight) { + layers.add(new NewItemButton(iconId, layerName, imgWidth, imgHeight, drawX, drawY)); + } + + @Override + public void drawForeground(DrawContext context, int mouseX, int mouseY) { + // We override this function to intentionally do nothing + // If in the future we want, we would draw the foreground and TITLES with this! + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + for (ClickableLayer layer : layers) { + // Check main layer first + if (Helper.WithinBounds(layer.getX(), layer.getY(), layer.getWidth(), layer.getHeight(), mouseX, mouseY)) { + layer.mouseClicked(mouseX, mouseY, button); + } + + for (ClickableLayer subLayer : layer.GetSubLayers()) { + + if (subLayer.visible && Helper.WithinBounds(subLayer.getX(), subLayer.getY(), subLayer.getWidth(), subLayer.getHeight(), mouseX, mouseY)) { + subLayer.mouseClicked(mouseX, mouseY, button); + } + } + } + + return true; + } + + // Check if a click point is within the context of a square (square = x, y, w, h) +// public static boolean WithinBounds(double x, double y, double w, double h, double clickX, double clickY) { +//// System.out.println("Mouse click X Y: " + clickX + " " + clickY); +//// System.out.println("Rectangle X Y W H: " + x + " " + y + " " + w + " " + h); +// return (clickX >= x) && (clickX <= x + w) && (clickY >= y) && (clickY <= y + h); +// } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + renderBackground(context, mouseX, mouseY, delta); + super.render(context, mouseX, mouseY, delta); + drawMouseoverTooltip(context, mouseX, mouseY); + } +} diff --git a/src/client/java/jesse/keeblarcraft/gui/widgets/TreeWidget.java b/src/client/java/jesse/keeblarcraft/gui/widgets/TreeWidget.java deleted file mode 100644 index 39e5318..0000000 --- a/src/client/java/jesse/keeblarcraft/gui/widgets/TreeWidget.java +++ /dev/null @@ -1,165 +0,0 @@ -// /* -// * -// * TreeWidget -// * -// * Handles the skill tree widget -// * -// * -// */ - -// package jesse.keeblarcraft.gui.widgets; - -// import jesse.keeblarcraft.Keeblarcraft; -// import jesse.keeblarcraft.Utils.CommonStructures.Position2d; -// import jesse.keeblarcraft.gui.GenericLayerT; -// import net.minecraft.client.gui.DrawContext; -// import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; -// import net.minecraft.text.Text; -// import net.minecraft.util.Identifier; - -// public class TreeWidget extends GenericLayerT { -// private static Identifier BACKGROUND_TEXTURE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_tree_background.png"); -// private static int maxHeight = 320; -// private static int maxLength = 640; -// private int zoomScale = 1; -// // private static Identifier FLIGHT_ATTRIBUTE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_flight.png"); - -// ///TODO: Make this THE root node in the attribute tree! Rename in future -// // private static Identifier EXAMPLE_NODE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_tree_example_node.png"); ///TODO: Make a way to make this programmatic (Proabably extend AbstractNode to carry this var) - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn TreeWidget -// /// -// /// @brief Class constructor for constructing a tree widget. This will -// /// be deprecated in a future version but exists for testing -// ///////////////////////////////////////////////////////////////////////////// -// public TreeWidget() { -// this(0, 0, 0, 0, Text.of("Test")); -// System.out.println("Calling empty tree constructor"); -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn TreeWidget -// /// -// /// @brief Class constructor for constructing a tree widget -// ///////////////////////////////////////////////////////////////////////////// -// public TreeWidget(int x, int y, int width, int height, Text message) { -// super(x, y, width, height, message); - -// this.startX = x; -// this.startY = y; -// this.endX = x + width; -// this.endY = y + height; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn renderButton -// /// -// /// @param[in] context is the drawing pane -// /// -// /// @param[in] x is the X position to draw at -// /// -// /// @param[in] y is the Y position to draw at -// /// -// /// @param[in] delta is unused in this version -// /// -// /// @brief Primary call to draw the GUI for this widget -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public void renderButton(DrawContext context, int x, int y, float delta) { -// context.drawTexture(BACKGROUND_TEXTURE, x, y, 0, 0, maxLength, maxHeight, maxLength, maxHeight); -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn appendClickableNarrations -// /// -// /// @param[in] builder is the narration builder. This is pure virtual in -// /// the parent but is unused in this widget currently -// /// -// /// @brief Handles the narrator -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// protected void appendClickableNarrations(NarrationMessageBuilder builder) { -// return; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn mouseClicked -// /// -// /// @param[in] mouseX is where on the x-axis the mouse was clicked -// /// -// /// @param[in] mouseY is where on the y-axis the mouse was clicked -// /// -// /// @param[in] button is the button clicked with (think of a mouse...) -// /// -// /// @brief Handler for mouse click events -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public boolean mouseClicked(double mouseX, double mouseY, int button) { -// return true; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn mouseDragged -// /// -// /// @param[in] mouseX is where on the x-axis the mouse was dragged -// /// -// /// @param[in] mouseY is where on the y-axis the mouse was dragged -// /// -// /// @param[in] button is the button dragged with (think of a mouse...) -// /// -// /// @brief Handler for mouse drag events. delta's unused currently -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { -// boolean ret = false; -// if (this.isValidClickButton(button)) { -// // Do camera panning magic stuff here -// ret = true; -// } -// return ret; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn mouseDragged -// /// -// /// @param[in] mouseX is where on the x-axis the mouse was dragged -// /// -// /// @param[in] mouseY is where on the y-axis the mouse was dragged -// /// -// /// @param[in] amount represents scroll direction. If the value is negative -// /// we scale out. If positive, we scale in -// /// -// /// @brief Handler for mouse scroll events -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public boolean mouseScrolled(double mouseX, double mouseY, double amount) { -// // Zooming INWARDS on scroll wheel produces 1.0 (which means zoom in) -// // Zooming BACKWARDS on scroll wheel produces -1.0 (which means zoom out) -// // We enforce a max scroll of 10 in either direction here -// if (amount > 0 && zoomScale <= 10) { -// // Zoom in -// zoomScale++; -// } else if (amount < 0 && zoomScale >= -10) { -// // Zoom out -// zoomScale--; -// } -// return true; -// } - -// ///////////////////////////////////////////////////////////////////////////// -// /// @fn DrawLayer -// /// -// /// @param[in] context is the drawing pane -// /// -// /// @param[in] layer is the layer in which this widget is being drawn in -// /// -// /// @brief This calls renderButton and gives it the valid drawing -// /// context to use. This function is called by a ScreenManager -// ///////////////////////////////////////////////////////////////////////////// -// @Override -// public void DrawLayer(DrawContext context, int layer) { -// Position2d pos = GetScreenCenter(); -// this.renderButton(context, pos.x - (maxLength / 2), pos.y - (maxHeight / 2), 0); -// } -// } diff --git a/src/client/java/jesse/keeblarcraft/mixin/ClientPlayNetworkHandlerMixin.java b/src/client/java/jesse/keeblarcraft/mixin/ClientPlayNetworkHandlerMixin.java new file mode 100644 index 0000000..e04d07f --- /dev/null +++ b/src/client/java/jesse/keeblarcraft/mixin/ClientPlayNetworkHandlerMixin.java @@ -0,0 +1,26 @@ +package jesse.keeblarcraft.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import jesse.keeblarcraft.GuiMgr.ShopKeeperHandler; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.SetTradeOffersS2CPacket; +import net.minecraft.screen.ScreenHandler; +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.CallbackInfo; + +@Mixin(ClientPlayNetworkHandler.class) +public abstract class ClientPlayNetworkHandlerMixin { + @Inject(at = @At("TAIL"), method = "onSetTradeOffers") + public void onSetTradeOffers(SetTradeOffersS2CPacket packet, CallbackInfo ci, @Local ScreenHandler screenHandler) { + if (packet.getSyncId() == screenHandler.syncId && screenHandler instanceof ShopKeeperHandler shopKeeperHandler) { + shopKeeperHandler.SetOffers(packet.getOffers()); + shopKeeperHandler.SetExperienceLevel(packet.getExperience()); + shopKeeperHandler.SetLevelProgress(packet.getLevelProgress()); + shopKeeperHandler.SetLeveled(packet.isLeveled()); + shopKeeperHandler.SetCanRefreshTrades(packet.isRefreshable()); + } + } +} diff --git a/src/client/java/jesse/keeblarcraft/mixin/ClientPlayerInteractionManagerMixin.java b/src/client/java/jesse/keeblarcraft/mixin/ClientPlayerInteractionManagerMixin.java deleted file mode 100644 index 1fa709f..0000000 --- a/src/client/java/jesse/keeblarcraft/mixin/ClientPlayerInteractionManagerMixin.java +++ /dev/null @@ -1,17 +0,0 @@ -package jesse.keeblarcraft.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 net.minecraft.client.network.ClientPlayerInteractionManager; - -@Mixin(ClientPlayerInteractionManager.class) -public abstract class ClientPlayerInteractionManagerMixin { - // This initial basically lets the player highlight the block at 10 blocks away. Does NOT let them break it, that is all handled in the new server mixin - // @Inject(method = "getReachDistance()F", at = @At ("HEAD"), cancellable = true) - // public void getReachDistance(CallbackInfoReturnable cir) { - // cir.setReturnValue(10.0f); - // } -} diff --git a/src/main/java/jesse/keeblarcraft/CustomBlocks/BlockEntities/FactionBlockEntity.java b/src/main/java/jesse/keeblarcraft/CustomBlocks/BlockEntities/FactionBlockEntity.java index 11ce764..dd95324 100644 --- a/src/main/java/jesse/keeblarcraft/CustomBlocks/BlockEntities/FactionBlockEntity.java +++ b/src/main/java/jesse/keeblarcraft/CustomBlocks/BlockEntities/FactionBlockEntity.java @@ -221,7 +221,6 @@ public class FactionBlockEntity extends BlockEntity implements ExtendedScreenHan if (hasSuperBeacon) { AttributeMgr.ApplyAttribute(player.getUuidAsString(), "faction_beacon"); - // ActionResult result = PlayerInBaseCallback.EVENT.invoker().interact(player, world); } } else if (!isPlayerInFactionRadius && playersInRadius.contains(player.getUuidAsString())) { playersInRadius.remove(player.getUuidAsString()); diff --git a/src/main/java/jesse/keeblarcraft/CustomItems/ItemManager.java b/src/main/java/jesse/keeblarcraft/CustomItems/ItemManager.java index 26f6890..3bc1d3c 100644 --- a/src/main/java/jesse/keeblarcraft/CustomItems/ItemManager.java +++ b/src/main/java/jesse/keeblarcraft/CustomItems/ItemManager.java @@ -15,9 +15,11 @@ import java.util.List; import jesse.keeblarcraft.CustomItems.Items.FactionBeaconItem; import jesse.keeblarcraft.CustomItems.Items.FactionFlightItem; +import jesse.keeblarcraft.Entities.EntityRegistration; import jesse.keeblarcraft.Keeblarcraft; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.item.Item; +import net.minecraft.item.SpawnEggItem; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; @@ -68,5 +70,6 @@ public class ItemManager { // The example item provides a demo of how you could make an item in your class RegisterItem("faction_upgrade_flight", new FactionFlightItem(new FabricItemSettings().maxCount(1))); RegisterItem("faction_upgrade_beacon", new FactionBeaconItem(new FabricItemSettings().maxCount(1))); + RegisterItem("shop_keeper_spawn_egg", new SpawnEggItem(EntityRegistration.SHOP_KEEPER_ENTITY_TYPE, 0xc4c4c4, 0xadadad, new FabricItemSettings())); } } diff --git a/src/main/java/jesse/keeblarcraft/Entities/EntityRegistration.java b/src/main/java/jesse/keeblarcraft/Entities/EntityRegistration.java index f81e3ef..b12a7c8 100644 --- a/src/main/java/jesse/keeblarcraft/Entities/EntityRegistration.java +++ b/src/main/java/jesse/keeblarcraft/Entities/EntityRegistration.java @@ -12,7 +12,7 @@ public class EntityRegistration { public static final EntityType SHOP_KEEPER_ENTITY_TYPE = Registry.register( Registries.ENTITY_TYPE, Identifier.of(Keeblarcraft.MOD_ID, "shop_keeper"), - EntityType.Builder.create(ShopKeeper::new, SpawnGroup.MISC).setDimensions(1.0f, 1.0f).build("shop_keeper") + EntityType.Builder.create(ShopKeeper::new, SpawnGroup.CREATURE).setDimensions(0.75f, 2.0f).build("cube") ); public static void RegisterEntities() { diff --git a/src/main/java/jesse/keeblarcraft/Entities/ShopKeeper.java b/src/main/java/jesse/keeblarcraft/Entities/ShopKeeper.java index fbdbe84..c9ae6aa 100644 --- a/src/main/java/jesse/keeblarcraft/Entities/ShopKeeper.java +++ b/src/main/java/jesse/keeblarcraft/Entities/ShopKeeper.java @@ -1,30 +1,79 @@ package jesse.keeblarcraft.Entities; +import jesse.keeblarcraft.GuiMgr.ShopKeeperHandler; import net.minecraft.entity.EntityType; -import net.minecraft.entity.passive.MerchantEntity; -import net.minecraft.entity.passive.PassiveEntity; -import net.minecraft.server.world.ServerWorld; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.screen.SimpleNamedScreenHandlerFactory; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import net.minecraft.village.TradeOffer; +import net.minecraft.village.TradeOfferList; import net.minecraft.world.World; -import org.jetbrains.annotations.Nullable; -public class ShopKeeper extends MerchantEntity { - public ShopKeeper(EntityType entityType, World world) { +import java.util.OptionalInt; + +public class ShopKeeper extends VillagerEntity { + public ShopKeeper(EntityType entityType, World world) { super(entityType, world); } + @Override + public ActionResult interactMob(PlayerEntity player, Hand hand) { + BeginTrades(player); + return ActionResult.success(this.getWorld().isClient()); + } + + private void BeginTrades(PlayerEntity player) { + super.setCustomer(player); + this.sendOffers(player, this.getDisplayName(), this.getVillagerData().getLevel()); + } + + @Override + public void sendOffers(PlayerEntity player, Text name, int levelProgress) { + OptionalInt optInt = player.openHandledScreen( + new SimpleNamedScreenHandlerFactory((syncId, playerInventory, playerx) -> + new ShopKeeperHandler(syncId, playerInventory, this), name) + ); + + if (optInt.isPresent()) { + TradeOfferList offers = this.getOffers(); + if (!offers.isEmpty()) { + player.sendTradeOffers(optInt.getAsInt(), offers, levelProgress, this.getExperience(), this.isLeveledMerchant(), this.canRefreshTrades()); + } + } + } + + // Shop Keepers do not breed! + @Override + public boolean canBreed() { + return false; + } + + @Override + protected Text getDefaultName() { + return Text.of("Shop Keeper"); + } + @Override protected void afterUsing(TradeOffer offer) { + System.out.println("After using called"); + } + // Get the offer list upon opening handled screen if valid + @Override + public TradeOfferList getOffers() { + if (this.offers == null) { + this.offers = new TradeOfferList(); + this.fillRecipes(); + } + + return this.offers; } @Override - protected void fillRecipes() { - - } - - @Override - public @Nullable PassiveEntity createChild(ServerWorld world, PassiveEntity entity) { - return null; + public boolean canSummonGolem(long time) { + return false; } } diff --git a/src/main/java/jesse/keeblarcraft/GuiMgr/ScreenHandlerRegistration.java b/src/main/java/jesse/keeblarcraft/GuiMgr/ScreenHandlerRegistration.java index 945e2ee..cf3e61e 100644 --- a/src/main/java/jesse/keeblarcraft/GuiMgr/ScreenHandlerRegistration.java +++ b/src/main/java/jesse/keeblarcraft/GuiMgr/ScreenHandlerRegistration.java @@ -4,6 +4,7 @@ import jesse.keeblarcraft.Keeblarcraft; import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; +import net.minecraft.resource.featuretoggle.FeatureFlags; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.util.Identifier; @@ -12,7 +13,13 @@ public class ScreenHandlerRegistration { Registry.register(Registries.SCREEN_HANDLER, new Identifier(Keeblarcraft.MOD_ID, "faction_block"), new ExtendedScreenHandlerType<>(FactionBlockScreenHandler::new)); + public static final ScreenHandlerType SHOP_KEEPER_HANDLER_SCREEN_HANDLER_TYPE = + Registry.register(Registries.SCREEN_HANDLER, new Identifier(Keeblarcraft.MOD_ID, "shopkeeper"), + new ScreenHandlerType<>(ShopKeeperHandler::new, FeatureFlags.VANILLA_FEATURES)); + + + public static void registerScreenHandlers() { - Keeblarcraft.LOGGER.info("Registering screen handlers for " + Keeblarcraft.MOD_ID); + Keeblarcraft.LOGGER.info("Registering screen handlers for {}", Keeblarcraft.MOD_ID); } } diff --git a/src/main/java/jesse/keeblarcraft/GuiMgr/ShopKeeperHandler.java b/src/main/java/jesse/keeblarcraft/GuiMgr/ShopKeeperHandler.java new file mode 100644 index 0000000..eb67f68 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/GuiMgr/ShopKeeperHandler.java @@ -0,0 +1,62 @@ +package jesse.keeblarcraft.GuiMgr; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.village.Merchant; +import net.minecraft.village.MerchantInventory; +import net.minecraft.village.SimpleMerchant; +import net.minecraft.village.TradeOfferList; + +public class ShopKeeperHandler extends ScreenHandler { + private Merchant merchant; + private MerchantInventory merchantInventory; + boolean canRefreshTrades = false; + boolean isLeveledMerchant = false; + int levelAmount = 0; + int merchantExperience = 0; + + public ShopKeeperHandler(int syncId, PlayerInventory playerInventory) { + this(syncId, playerInventory, new SimpleMerchant(playerInventory.player)); + } + + public ShopKeeperHandler(int syncId, PlayerInventory playerInventory, Merchant merchant) { + super(ScreenHandlerRegistration.SHOP_KEEPER_HANDLER_SCREEN_HANDLER_TYPE, syncId); + this.merchant = merchant; + this.merchantInventory = new MerchantInventory(merchant); + // Add slots below + } + + public void SetOffers(TradeOfferList offers) { + this.merchant.setOffersFromServer(offers); + } + + public void SetExperienceLevel(int xp) { + this.merchantExperience = xp; + } + + public void SetLevelProgress(int level) { + this.levelAmount = level; + } + + public void SetLeveled(boolean leveled) { + this.isLeveledMerchant = leveled; + } + + public void SetCanRefreshTrades(boolean isRefreshable) { + this.canRefreshTrades = isRefreshable; + } + + @Override + public ItemStack quickMove(PlayerEntity player, int slot) { + return null; + } + + // Called every tick + @Override + public boolean canUse(PlayerEntity player) { +// System.out.println("canUse called on Merchant!"); + return true; + } +} diff --git a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java index ad4882f..da8192e 100644 --- a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java +++ b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java @@ -3,12 +3,13 @@ * Keeblarcraft * * This is the primary server side "main" object that is referenced by Fabric. This is where everything is setup for the mod - * and a very important class. Please becareful as you add to it + * and a very important class. Please be careful as you add to it * */ package jesse.keeblarcraft; +import jesse.keeblarcraft.Entities.EntityRegistration; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; @@ -78,9 +79,7 @@ public class Keeblarcraft implements ModInitializer { var player = handler.player; Keeblarcraft.LOGGER.info("Player " + player.getName() + " has logged out. Deleting tree..."); - if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == true) { - AttributeMgr.activeTrees.remove(player.getUuidAsString()); - } + AttributeMgr.activeTrees.remove(player.getUuidAsString()); }); ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> { @@ -131,6 +130,7 @@ public class Keeblarcraft implements ModInitializer { BlockEntityRegistration.RegisterBlockEntities(); // World generation + EntityRegistration.RegisterEntities(); // Custom portal generator System.out.println("BUILDING CUSTOM PORTAL"); diff --git a/src/main/java/jesse/keeblarcraft/mixin/EntitySpawnMixin.java b/src/main/java/jesse/keeblarcraft/mixin/EntitySpawnMixin.java index a7a617b..06968ae 100644 --- a/src/main/java/jesse/keeblarcraft/mixin/EntitySpawnMixin.java +++ b/src/main/java/jesse/keeblarcraft/mixin/EntitySpawnMixin.java @@ -2,8 +2,6 @@ package jesse.keeblarcraft.mixin; import net.minecraft.entity.mob.MobEntity; -// import javax.annotation.Nullable; - import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/jesse/keeblarcraft/mixin/PlayerMixin.java b/src/main/java/jesse/keeblarcraft/mixin/PlayerMixin.java index fed0ca7..16c037c 100644 --- a/src/main/java/jesse/keeblarcraft/mixin/PlayerMixin.java +++ b/src/main/java/jesse/keeblarcraft/mixin/PlayerMixin.java @@ -51,6 +51,6 @@ public abstract class PlayerMixin { // 3. Casting '(Object) this' into 'PlayerEntity' gets us to the mixin inject - and NOW we can store the result of this cast into the type we want as a reference // which is the 'PlayerEntity' on the left hand side. Now we can access stuff from that class AS IF WE ARE CODING INSIDE OF THAT CLASS :))) PlayerEntity player = (PlayerEntity) (Object) this; - Keeblarcraft.LOGGER.info("PLAYER MIXIN: " + player.getEntityName()); +// Keeblarcraft.LOGGER.info("PLAYER MIXIN: " + player.getEntityName()); } } diff --git a/src/main/resources/assets/keeblarcraft/lang/en_us.json b/src/main/resources/assets/keeblarcraft/lang/en_us.json index 3cc7ce8..4729a05 100644 --- a/src/main/resources/assets/keeblarcraft/lang/en_us.json +++ b/src/main/resources/assets/keeblarcraft/lang/en_us.json @@ -8,6 +8,8 @@ "itemgroup.keeblarcraft": "Keeblarcraft Modded Items", + "item.keeblarcraft.shop_keeper_spawn_egg": "Shop Keeper Spawn Egg", + "block.keeblarcraft.example_block": "Keeblarcraft example block", "block.keeblarcraft.example_block_ore": "Keeblarcraft example block ore", "block.keeblarcraft.example_statue": "Keeblarcraft example statue", diff --git a/src/main/resources/assets/keeblarcraft/models/item/shop_keeper_spawn_egg.json b/src/main/resources/assets/keeblarcraft/models/item/shop_keeper_spawn_egg.json new file mode 100644 index 0000000..7a2c6da --- /dev/null +++ b/src/main/resources/assets/keeblarcraft/models/item/shop_keeper_spawn_egg.json @@ -0,0 +1,3 @@ +{ + "parent": "item/template_spawn_egg" +} \ No newline at end of file diff --git a/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_add_icon.jpeg b/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_add_icon.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6319a8221a716fe66988ed826e56a8289b4eea60 GIT binary patch literal 5728 zcmeHLdsGu=7XR|%jV2ISeAEsB72BO8lP5_H?^jq*1hlf+Lnkv6h~{My2%xswT5W56 z;97Uznez~j$49mBhXQS=E4R*OMaXP^3WXsA*ASSD0px@$h9^Kg zxU<)Ao`}2813aP^zX~{|S4RMt0NZG|FNaG7SPJ*`aM>0KIon-;*^%vGNFPIEew(iv z%QqL7pzd)9O@o=fJ1fLgazZIrr-Cn~N^4ZAjD!Xw3`VWW2tqzuxFQq{1Dns_;%(@U z6dr@);gtey(aWlRKDSY!aC+q=?Xoa(%H>ehk!}ScS1Qo>^g1_5&18I-g{iVRO|okr z{8fh8Xp`(&ZLzZ0oy}C+3K~32S;K^Ks$nK&pk?W4*!VhQox|;5d?Z%qusglRI+KiZ zZUoGV6*7!d@y#^Jro!g3T^35^?L$yxQmN} zjvvW^!@)+&X?uOSwP5@>#=PbAZbnhccwIFfipi~IoW7(!bD9d;x@$akZUZ!>VC;+o z)V#nr5nPJRc~G0(aFxyB<}85Opcdeu(j$Xsmxdi0b6ivnyNEf*Bx5}pX%}UqjU3dd zRZ0V4u;La%Pv9D@)qqJ*JmoHz z-6RXPWY1hN)HF@{$Q|y37Ed+k4J_p< z95SiH83y`_w5knyYiggp*JbtjNe`1*1$6`rKoxN>B`k$wcU+&IznWpG0}gPd3MVuy z2O7Om4UZfLivMB!TC38c(=$4pq?Ay4YMQ`PNvjH1>2+GAj<%?kl%+4O|0aHT%W4b* z;#aV*lAcs3{xwV7+g|nR+ zg^-ljomo;+6g=rY1a5uFojK77ob~n4^y3B5G#sMfSc!pJ2Icnn06z~{=l8i;{0G2N z_`*p8-U|5F9taTdDOPUj!B<&a#bG``B=wY+X2agtQ!!RG09yuNs@mfK9S!It(+(&2 z=TGgyG>hl3*kP}M*to%-%%d3R=By-(1FpHKf5fyN-e8WMM;pIFs2sQ|I*QO+s}UMg1-_^M!oJzxJ%YSF zR;QQ0z!{W{1bjaGfgyyCC`=?03Plm2p&?;W5m8Z*5s{J6Lt@0yLnK2YBgOGzNvt$3 zE-q^5uM*;=2{F<*DeHtM02`qwTqFvYMn^_V|Kkz(8A%`U6URqL5{5ERhJYtQdxld3-@AOpfH{V3OA}1OIuUA$)-_OceMUMS++v7KlOEt++X~ zacztJ!!M(;|pZA@)9C#(zK zzGQo5=Y^J29aAs7U%o2(&h>5f8K2%OU3X@e|MQhUegVr!B?DIA0)3uyEa36dc`RpI z39Kp*gocN6v+xfdg`yB7mc$VA8=IQj;<3ccNoAIu$K#SmtF#$er7v+F_^gNhJKgV^ zQmz)?u$Qhnv;0cBqTtfWkIz@Oo|`-Ba#4N$43~C6XzAoFOZHKMdt0jB+x*j*KQ(6F z$`nKyedh}IpCB%}Qg|!89ee+R&2IlbzNjU-V*P}jx1QQ~@jIgA#78ZQU%65<4cERD zbLVd#Ctq0fPM3M=nwDY{W$v=szB~S#M;*womYqPfOAZt5I?wm-i) zC1L5vowL%8HN4RD+7#2-7r~gTO|GcLj)FDLPezPweQkv~89r~fo`FYu!5WBS1T+GF zKygDN#Yh7C>!~C*;o{8o=ZDQ+Gyg5m;YFUmM;%ceiMlO5Rtd&qp-k95>90rVD{&$* zAIqFHt7&Iv2HAZ4dSfu};$53%OD4adc&2&O!M2di&#g+n_Tx80KiMyv?o7%}H_qEJ zB&YSgBZv02m!yQRO}JlN|JBj4QC$~0ezVXp>PBAn#COKTj+`E!{lU7=J1T_j3u?Bv z%>DAl4Ci;MdlO=tyH8(!#xGZ#Qm}Ec)Iw7TgWR%l5tHUOLs1^ToXENs^MszCI;QaYyNAy%%gWb$D*xg` wQB$ENOA?7)n`O?DH7vaO?GsnhPd(U{bT<8o!|C|aC$F?0sQ6(qRMF{w0@`O03jhEB literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_checkout_button.jpeg b/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_checkout_button.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..fd4ff521d5ba374862fad8f0e848f5a35d4148c5 GIT binary patch literal 6415 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 SX1HS^9}>-bX{r7FKmXa8%**ls literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_item_slot.jpeg b/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_item_slot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8e051c31fcc458ceaa0bba7f962b06e095bbe348 GIT binary patch literal 1348 zcmex=L?6mQqXwbzED#l4gO`Kd};u4Zls%q*Qnp!5NX66=_R?aT2ZtfnQ zUcn)uVc`*xQOPN(Y3Ui6S;Zx#W#tu>Rn0A}ZS5VMU6UqHnL2IyjG40*Enc#8+42=D zS8dw7W$U)>J9h3mboj{8W5-XNJay^vm8;jT-?(|};iJb-o<4j2;^nK4pFV&2`tAFV zpT9u3cne5Ee1_&PU?4Cuv9K_+u!H=?$W#vUxF8Fwq9L1*V<3BCp|FxsBZr97 z#DyCVaw;1KeGpA5y2vG_V)9V+BgkuDpAqM=CbE16_ZY%ow;7y)NrE!)A7}_=CIEH+ zzstbF!1DhV0}nGJFflO;GT1Zxh}*AjXQRP<;E%O=N8_m9_p?$7>RuHOAit*`k&S)J|0_j1Q$HcYFP`xLou$*x^jN`9YQ^FHlAgU9E$ z{~0c=%UieaYU$bMf9)RqXPA@4_Mbr}s^x2by!+pKm-_R6N*H2)U=b6D>z>=n?;7rs@!cKf%l z)%(sb`n}!s$)Qgx&C9mc?}>`LH~W5do%!^2;d7>X-o3xw<3GcvK%jGYzwNy8Ve8Wq zcY*A9u~&bm=iRUTe-UVz=Hd_k8DejK-25Z{^k++d`HK1f1nQZ7+&*?c`QN4g3@y%w z;*>wye~Z6ucl__-zpab!X8mWl`8?pa?)jVhu6~Q(_;>T0^81O;|1vy&w#L*xJ5>9o zS75l;@4M#NYj>A^x@Rl0CHLEZ2KCoJYoE`rc>nNv-#_mChh+0TKCZpqQQCj2?{UOO z@h;u`hd@_+%dyk=@U;J^EYtmf54C&ux0&po&z@m_BYyMO`7QPj`9G>{{OI@VKf{|S z@oxKvX_?>uGklnqA^vsRGn36$Gv25qO6=KY;i@(_`cqQvQkUgtcE-$^JoV+LrDs(x z?NO8u=H%IZOMAPvwrbX^TfQ&zEp319%D!;ngY5JE((dE?uIoQ-cHcZLJ5o1q%Uip1 z*{5&RU;NWu|0Ozmb^NBgg_Zvq{C8}4Y}K&go3WS4OJ`=*#r@Z+_ue(X=D+{@KDVDs WjL!L%eL14H<=4vnr{CHCzXL?6mQqXwbzED#l4gO`Kd};u4Zls%q*Qnp!5NX66=_R?aT2ZtfnQ zUcn)uVc`*xQOPN(Y3Ui6S;Zx#W#tu>Rn0A}ZS5VMU6UqHnL2IyjG40*Enc#8+42=D zS8dw7W$U)>J9h3mboj{8W5-XNJay^vm8;jT-?(|};iJb-o<4j2;^nK4pFV&2`tAFV zpT9u3cne5Ee1_&PU?4Cuv9K_+u!H=?$W#vUxF8Fwq9L1*V<3BCp|FxsBZr97 z#DyCVaw;1KeGpA5y2vG_V)9V+BgkuDpAqM=CbE16_ZY%ow;7y)NrE!)A7}_=CIEH+ zzstbF!1VtX0}nGJFflO;GT1ZxdHq5DVD#(zZLdGZJ@(!Dk-vRi{x z&ehJp-T%&iz4<>w#!}b7L$yI&z46t8zkgSoR_=88@%iwc^oP51rK2XDQ$4$6!qLif zLA&&ukLKiL6i@E)W}Z{new4UUQvV;H z-**3J`0|@Mxjr$uKJ|xN;iQxr-)U>ulw^LU*xxOz`Ela6Ue=e@;r|)ZTcad8KR+^f zHT}KX&pM0h{wY5`pWUB%(@rM7qWf^2;*ZkAbs1$<&w2~hHa~dlxNO(f5A!y%zBWDD z*Z4>x|H+=~HMXVS=5Ni+T^n^XJF3LzTKS`&S539|*(|DjCNGeOgU$y(qtG+jU^rYL;0PD|1%s~{~;@? zX0n~l&&%Hy{K$V)-&$vL`H%La;*^v6?Qc#0Gw@Y3d+xB>-?k_5;o77}uYYSFl@q(V zHt(&%RTEu5>#%C;E15E^X5tfWyfPEt7Fa9K_uL{+>43BBRJ#c8*|!3}-`}(~>r3MA zGp(~S zn|p_!y*}=Af09%8kw?#`Sbo}3^!ZU`{#(nHf79%DKI>Ok>fd~+?(5IHYaZ+OTgH~h z?fB^WJN}jMeV2`H)4qj$@ZV+a9edvX<|3U_E^e92_9ou@^zCb#==5?kyKVBUk$dc< iCx!0s*3S-#`FBp>$)zmMqLnABSDEkIzUe9d|C<0cc#q5g literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_subtract.png b/src/main/resources/assets/keeblarcraft/textures/gui/shopkeeper_subtract.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3baae64ebcc0cb3fade84bc52e5ef26e24702c GIT binary patch literal 572 zcmV-C0>k}@P)EX>4Tx04R}tkv&MmKpe$iQ^gM|4t5Z6$WWauf{F+(wF*V35Nd^19ZW9$f+h_~ zii@M*T5#}VvFhOBtgC~oAP9bdxC>5-E>hzEl0u6Z503ls?%w0>9U#=pOtU&-fTr7K zDiIem*;TRY6#{w?#yDnWW*Kvml!Wj2x<`PocTt|@f9}uGr{*jM1VrK(GfbO!gLrz= zHaPDShgnfpiO-40Ou8WPBi9v=-#8as7IZLMN=c5B95qOtZfq_6u^`-eob@00006VoOIv0RI600RN!9r;`8x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=>iE9G87ilcc1_O02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{000z8L_t&-(_>&5e1P#ggV=wDAqW6>i~