From b91e6b9147a6d48efa48b176e26ae1f5b07bc53a Mon Sep 17 00:00:00 2001 From: Christian Knaapen Date: Sat, 14 Jan 2023 15:33:24 +0100 Subject: [PATCH] Updated radial menu to match 1.18, with build mode categories, descriptions and new icons. Changed reach upgrade recipes. --- build.gradle | 2 +- .../buildmode/BuildModes.java | 50 +++- .../gui/buildmode/RadialMenu.java | 248 ++++++++++-------- .../render/BuildRenderTypes.java | 140 +++------- src/main/resources/META-INF/mods.toml | 8 +- .../assets/effortlessbuilding/lang/en_us.json | 23 +- .../assets/effortlessbuilding/lang/ru_ru.json | 79 ++++++ .../textures/icons/cone.png | Bin 0 -> 361 bytes .../textures/icons/cube.png | Bin 319 -> 4987 bytes .../textures/icons/dome.png | Bin 0 -> 361 bytes .../textures/icons/normal.png | Bin 317 -> 333 bytes .../textures/icons/normal_plus.png | Bin 355 -> 317 bytes .../textures/icons/pyramid.png | Bin 0 -> 361 bytes .../textures/items/reachupgrade1.png | Bin 603 -> 625 bytes .../textures/items/reachupgrade2.png | Bin 625 -> 603 bytes .../recipes/reach_upgrade1.json | 2 +- .../recipes/reach_upgrade2.json | 11 +- .../recipes/reach_upgrade3.json | 6 +- 18 files changed, 326 insertions(+), 243 deletions(-) create mode 100644 src/main/resources/assets/effortlessbuilding/lang/ru_ru.json create mode 100644 src/main/resources/assets/effortlessbuilding/textures/icons/cone.png create mode 100644 src/main/resources/assets/effortlessbuilding/textures/icons/dome.png create mode 100644 src/main/resources/assets/effortlessbuilding/textures/icons/pyramid.png diff --git a/build.gradle b/build.gradle index 5427158..7dab023 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ apply plugin: 'net.minecraftforge.gradle' apply plugin: 'eclipse' apply plugin: 'maven-publish' -version = '1.16.3-2.28' +version = '1.16.3-2.32' group = 'nl.requios.effortlessbuilding' // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = 'effortlessbuilding' diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java index fad04d3..2d12e56 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -6,6 +6,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceContext; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector4f; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.buildmode.buildmodes.*; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; @@ -245,27 +246,50 @@ public class BuildModes { } public enum BuildModeEnum { - NORMAL("effortlessbuilding.mode.normal", new Normal()), - NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), OptionEnum.BUILD_SPEED), - LINE("effortlessbuilding.mode.line", new Line() /*, OptionEnum.THICKNESS*/), - WALL("effortlessbuilding.mode.wall", new Wall(), OptionEnum.FILL), - FLOOR("effortlessbuilding.mode.floor", new Floor(), OptionEnum.FILL), - DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine() /*, OptionEnum.THICKNESS*/), - DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall() /*, OptionEnum.FILL*/), - SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), OptionEnum.RAISED_EDGE), - CIRCLE("effortlessbuilding.mode.circle", new Circle(), OptionEnum.CIRCLE_START, OptionEnum.FILL), - CYLINDER("effortlessbuilding.mode.cylinder", new Cylinder(), OptionEnum.CIRCLE_START, OptionEnum.FILL), - SPHERE("effortlessbuilding.mode.sphere", new Sphere(), OptionEnum.CIRCLE_START, OptionEnum.FILL), - CUBE("effortlessbuilding.mode.cube", new Cube(), OptionEnum.CUBE_FILL); + NORMAL("normal", new Normal(), BuildModeCategoryEnum.BASIC), + NORMAL_PLUS("normal_plus", new NormalPlus(), BuildModeCategoryEnum.BASIC, OptionEnum.BUILD_SPEED), + LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/), + WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL), + FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL), + CUBE("cube", new Cube(), BuildModeCategoryEnum.BASIC, OptionEnum.CUBE_FILL), + DIAGONAL_LINE("diagonal_line", new DiagonalLine(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.THICKNESS*/), + DIAGONAL_WALL("diagonal_wall", new DiagonalWall(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.FILL*/), + SLOPE_FLOOR("slope_floor", new SlopeFloor(), BuildModeCategoryEnum.DIAGONAL, OptionEnum.RAISED_EDGE), + CIRCLE("circle", new Circle(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL), + CYLINDER("cylinder", new Cylinder(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL), + SPHERE("sphere", new Sphere(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL); public String name; public IBuildMode instance; + public final BuildModeCategoryEnum category; public OptionEnum[] options; - BuildModeEnum(String name, IBuildMode instance, OptionEnum... options) { + BuildModeEnum(String name, IBuildMode instance, BuildModeCategoryEnum category, OptionEnum... options) { this.name = name; this.instance = instance; + this.category = category; this.options = options; } + + public String getNameKey() { + return "effortlessbuilding.mode." + name; + } + + public String getDescriptionKey() { + return "effortlessbuilding.modedescription." + name; + } + } + + public enum BuildModeCategoryEnum { + BASIC(new Vector4f(0f, .5f, 1f, .8f)), + DIAGONAL(new Vector4f(0.56f, 0.28f, 0.87f, .8f)), + CIRCULAR(new Vector4f(0.29f, 0.76f, 0.3f, 1f)), + ROOF(new Vector4f(0.83f, 0.87f, 0.23f, .8f)); + + public final Vector4f color; + + BuildModeCategoryEnum(Vector4f color) { + this.color = color; + } } } diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java index 84e469f..967d033 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/buildmode/RadialMenu.java @@ -12,10 +12,12 @@ import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Direction; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.vector.Vector4f; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import nl.requios.effortlessbuilding.EffortlessBuilding; @@ -40,7 +42,7 @@ import nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum; /** * Initially from Chisels and Bits by AlgorithmX2 - * https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/client/gui/ChiselsAndBitsMenu.java + * Link */ @ParametersAreNonnullByDefault @@ -48,9 +50,30 @@ import nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum; public class RadialMenu extends Screen { public static final RadialMenu instance = new RadialMenu(); + + private final Vector4f radialButtonColor = new Vector4f(0f, 0f, 0f, .5f); + private final Vector4f sideButtonColor = new Vector4f(.5f, .5f, .5f, .5f); + private final Vector4f highlightColor = new Vector4f(.6f, .8f, 1f, .6f); + private final Vector4f selectedColor = new Vector4f(0f, .5f, 1f, .5f); + private final Vector4f highlightSelectedColor = new Vector4f(0.2f, .7f, 1f, .7f); + + private final int whiteTextColor = 0xffffffff; + private final int watermarkTextColor = 0x88888888; + private final int descriptionTextColor = 0xdd888888; + private final int optionTextColor = 0xeeeeeeff; + + private final double ringInnerEdge = 30; + private final double ringOuterEdge = 65; + private final double categoryLineWidth = 1; + private final double textDistance = 75; + private final double buttonDistance = 105; + private final float fadeSpeed = 0.3f; + private final int descriptionHeight = 100; + public BuildModeEnum switchTo = null; public ActionEnum doAction = null; public boolean performedActionUsingMouse; + private float visibility; public RadialMenu() { @@ -84,7 +107,7 @@ public class RadialMenu extends Screen { RenderSystem.pushMatrix(); RenderSystem.translatef(0.0F, 0.0F, 200.0F); - visibility += 0.3f * partialTicks; + visibility += fadeSpeed * partialTicks; if (visibility > 1f) visibility = 1f; final int startColor = (int) (visibility * 98) << 24; @@ -115,10 +138,6 @@ public class RadialMenu extends Screen { final double mouseYCenter = mouseYY - middleY; double mouseRadians = Math.atan2(mouseYCenter, mouseXCenter); - final double ringInnerEdge = 30; - final double ringOuterEdge = 65; - final double textDistance = 75; - final double buttonDistance = 105; final double quarterCircle = Math.PI / 2.0; if (mouseRadians < -quarterCircle) { @@ -153,17 +172,35 @@ public class RadialMenu extends Screen { doAction = null; //Draw buildmode backgrounds + drawRadialButtonBackgrounds(currentBuildMode, buffer, middleX, middleY, mouseXCenter, mouseYCenter, mouseRadians, + quarterCircle, modes); + + //Draw action backgrounds + drawSideButtonBackgrounds(buffer, middleX, middleY, mouseXCenter, mouseYCenter, buttons); + + tessellator.end(); + + drawIcons(buffer, middleX, middleY, mc, modes, buttons); + + tessellator.end(); + + drawTexts(ms, currentBuildMode, middleX, middleY, modes, buttons, options); + + RenderSystem.popMatrix(); + } + + private void drawRadialButtonBackgrounds(BuildModeEnum currentBuildMode, BufferBuilder buffer, double middleX, double middleY, + double mouseXCenter, double mouseYCenter, double mouseRadians, double quarterCircle, ArrayList modes) { if (!modes.isEmpty()) { final int totalModes = Math.max(3, modes.size()); - int currentMode = 0; final double fragment = Math.PI * 0.005; final double fragment2 = Math.PI * 0.0025; final double perObject = 2.0 * Math.PI / totalModes; for (int i = 0; i < modes.size(); i++) { MenuRegion menuRegion = modes.get(i); - final double beginRadians = currentMode * perObject - quarterCircle; - final double endRadians = (currentMode + 1) * perObject - quarterCircle; + final double beginRadians = i * perObject - quarterCircle; + final double endRadians = (i + 1) * perObject - quarterCircle; menuRegion.x1 = Math.cos(beginRadians); menuRegion.x2 = Math.cos(endRadians); @@ -180,81 +217,74 @@ public class RadialMenu extends Screen { final double y1m2 = Math.sin(beginRadians + fragment2) * ringOuterEdge; final double y2m2 = Math.sin(endRadians - fragment2) * ringOuterEdge; - float r = 0.0f; - float g = 0.0f; - float b = 0.0f; - float a = 0.5f; - - //check if current mode - int buildMode = currentBuildMode.ordinal(); - if (buildMode == i) { - r = 0f; - g = 0.5f; - b = 1f; - a = 0.5f; - //menuRegion.highlighted = true; //draw text - } - - //check if mouse is over this region + final boolean isSelected = currentBuildMode.ordinal() == i; final boolean isMouseInQuad = inTriangle(x1m1, y1m1, x2m2, y2m2, x2m1, y2m1, mouseXCenter, mouseYCenter) - || inTriangle(x1m1, y1m1, x1m2, y1m2, x2m2, y2m2, mouseXCenter, mouseYCenter); + || inTriangle(x1m1, y1m1, x1m2, y1m2, x2m2, y2m2, mouseXCenter, mouseYCenter); + final boolean isHighlighted = beginRadians <= mouseRadians && mouseRadians <= endRadians && isMouseInQuad; - if (beginRadians <= mouseRadians && mouseRadians <= endRadians && isMouseInQuad) { - r = 0.6f; - g = 0.8f; - b = 1f; - a = 0.6f; + Vector4f color = radialButtonColor; + if (isSelected) color = selectedColor; + if (isHighlighted) color = highlightColor; + if (isSelected && isHighlighted) color = highlightSelectedColor; + + if (isHighlighted) { menuRegion.highlighted = true; switchTo = menuRegion.mode; } - buffer.vertex(middleX + x1m1, middleY + y1m1, getBlitOffset()).color(r, g, b, a).endVertex(); - buffer.vertex(middleX + x2m1, middleY + y2m1, getBlitOffset()).color(r, g, b, a).endVertex(); - buffer.vertex(middleX + x2m2, middleY + y2m2, getBlitOffset()).color(r, g, b, a).endVertex(); - buffer.vertex(middleX + x1m2, middleY + y1m2, getBlitOffset()).color(r, g, b, a).endVertex(); + buffer.vertex(middleX + x1m1, middleY + y1m1, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + x2m1, middleY + y2m1, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + x2m2, middleY + y2m2, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + x1m2, middleY + y1m2, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); - currentMode++; + //Category line + color = menuRegion.mode.category.color; + final double categoryLineOuterEdge = ringInnerEdge + categoryLineWidth; + + final double x1m3 = Math.cos(beginRadians + fragment) * categoryLineOuterEdge; + final double y1m3 = Math.sin(beginRadians + fragment) * categoryLineOuterEdge; + final double x2m3 = Math.cos(endRadians - fragment) * categoryLineOuterEdge; + final double y2m3 = Math.sin(endRadians - fragment) * categoryLineOuterEdge; + + buffer.vertex(middleX + x1m1, middleY + y1m1, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + x2m1, middleY + y2m1, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + x2m3, middleY + y2m3, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + x1m3, middleY + y1m3, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); } } + } - //Draw action backgrounds + private void drawSideButtonBackgrounds(BufferBuilder buffer, double middleX, double middleY, double mouseXCenter, double mouseYCenter, ArrayList buttons) { for (final MenuButton btn : buttons) { - float r = 0.5f; - float g = 0.5f; - float b = 0.5f; - float a = 0.5f; - //highlight when active option - if (btn.action == getBuildSpeed() || - btn.action == getFill() || - btn.action == getCubeFill() || - btn.action == getRaisedEdge() || - btn.action == getLineThickness() || - btn.action == getCircleStart()) { - r = 0.0f; - g = 0.5f; - b = 1f; - a = 0.6f; - } + final boolean isSelected = + btn.action == getBuildSpeed() || + btn.action == getFill() || + btn.action == getCubeFill() || + btn.action == getRaisedEdge() || + btn.action == getLineThickness() || + btn.action == getCircleStart(); - //highlight when mouse over - if (btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter) { - r = 0.6f; - g = 0.8f; - b = 1f; - a = 0.6f; + final boolean isHighlighted = btn.x1 <= mouseXCenter && btn.x2 >= mouseXCenter && btn.y1 <= mouseYCenter && btn.y2 >= mouseYCenter; + + Vector4f color = sideButtonColor; + if (isSelected) color = selectedColor; + if (isHighlighted) color = highlightColor; + if (isSelected && isHighlighted) color = highlightSelectedColor; + + if (isHighlighted) { btn.highlighted = true; doAction = btn.action; } - buffer.vertex(middleX + btn.x1, middleY + btn.y1, getBlitOffset()).color(r, g, b, a).endVertex(); - buffer.vertex(middleX + btn.x1, middleY + btn.y2, getBlitOffset()).color(r, g, b, a).endVertex(); - buffer.vertex(middleX + btn.x2, middleY + btn.y2, getBlitOffset()).color(r, g, b, a).endVertex(); - buffer.vertex(middleX + btn.x2, middleY + btn.y1, getBlitOffset()).color(r, g, b, a).endVertex(); + buffer.vertex(middleX + btn.x1, middleY + btn.y1, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + btn.x1, middleY + btn.y2, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + btn.x2, middleY + btn.y2, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); + buffer.vertex(middleX + btn.x2, middleY + btn.y1, getBlitOffset()).color(color.x(), color.y(), color.z(), color.w()).endVertex(); } + } - tessellator.end(); - + private void drawIcons(BufferBuilder buffer, double middleX, double middleY, Minecraft mc, ArrayList modes, ArrayList buttons) { RenderSystem.shadeModel(GL11.GL_FLAT); RenderSystem.translatef(0f, 0f, 5f); @@ -269,8 +299,8 @@ public class RadialMenu extends Screen { //Draw buildmode icons for (final MenuRegion menuRegion : modes) { - final double x = (menuRegion.x1 + menuRegion.x2) * 0.5 * (ringOuterEdge * 0.6 + 0.4 * ringInnerEdge); - final double y = (menuRegion.y1 + menuRegion.y2) * 0.5 * (ringOuterEdge * 0.6 + 0.4 * ringInnerEdge); + final double x = (menuRegion.x1 + menuRegion.x2) * 0.5 * (ringOuterEdge * 0.55 + 0.45 * ringInnerEdge); + final double y = (menuRegion.y1 + menuRegion.y2) * 0.5 * (ringOuterEdge * 0.55 + 0.45 * ringInnerEdge); final TextureAtlasSprite sprite = ModClientEventHandler.getBuildModeIcon(menuRegion.mode); @@ -318,20 +348,19 @@ public class RadialMenu extends Screen { buffer.vertex(middleX + btnx2, middleY + btny2, getBlitOffset()).uv(sprite.getU(u2), sprite.getV(v2)).color(f, f, f, a).endVertex(); buffer.vertex(middleX + btnx2, middleY + btny1, getBlitOffset()).uv(sprite.getU(u2), sprite.getV(v1)).color(f, f, f, a).endVertex(); } + } - tessellator.end(); - - //Draw strings + private void drawTexts(MatrixStack ms, BuildModeEnum currentBuildMode, double middleX, double middleY, ArrayList modes, ArrayList buttons, OptionEnum[] options) { //font.drawStringWithShadow("Actions", (int) (middleX - buttonDistance - 13) - font.getStringWidth("Actions") * 0.5f, (int) middleY - 38, 0xffffffff); //Draw option strings for (int i = 0; i < currentBuildMode.options.length; i++) { OptionEnum option = options[i]; - font.drawShadow(ms, I18n.get(option.name), (int) (middleX + buttonDistance - 9), (int) middleY - 37 + i * 39, 0xeeeeeeff); + font.drawShadow(ms, I18n.get(option.name), (int) (middleX + buttonDistance - 9), (int) middleY - 37 + i * 39, optionTextColor); } String credits = "Effortless Building"; - font.drawShadow(ms, credits, width - font.width(credits) - 4, height - 10, 0x88888888); + font.drawShadow(ms, credits, width - font.width(credits) - 4, height - 10, watermarkTextColor); //Draw buildmode text for (final MenuRegion menuRegion : modes) { @@ -342,7 +371,7 @@ public class RadialMenu extends Screen { int fixed_x = (int) (x * textDistance); final int fixed_y = (int) (y * textDistance) - font.lineHeight / 2; - final String text = I18n.get(menuRegion.mode.name); + String text = I18n.get(menuRegion.mode.getNameKey()); if (x <= -0.2) { fixed_x -= font.width(text); @@ -350,7 +379,11 @@ public class RadialMenu extends Screen { fixed_x -= font.width(text) / 2; } - font.drawShadow(ms, text, (int) middleX + fixed_x, (int) middleY + fixed_y, 0xffffffff); + font.drawShadow(ms, text, (int) middleX + fixed_x, (int) middleY + fixed_y, whiteTextColor); + + //Draw description + text = I18n.get(menuRegion.mode.getDescriptionKey()); + font.drawShadow(ms, text, (int) middleX - font.width(text) / 2f, (int) middleY + descriptionHeight, descriptionTextColor); } } @@ -358,66 +391,71 @@ public class RadialMenu extends Screen { for (final MenuButton button : buttons) { if (button.highlighted) { String text = TextFormatting.AQUA + button.name; - int wrap = 120; - String keybind = ""; // FIXME - String keybindFormatted = ""; //Add keybind in brackets - if (button.action == ActionEnum.UNDO) { - keybind = I18n.get(ClientProxy.keyBindings[3].saveString()); - } - if (button.action == ActionEnum.REDO) { - keybind = I18n.get(ClientProxy.keyBindings[4].saveString()); - } - if (button.action == ActionEnum.REPLACE) { - keybind = I18n.get(ClientProxy.keyBindings[1].saveString()); - } - if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) { - keybind = I18n.get(ClientProxy.keyBindings[0].saveString()); - } - if (currentBuildMode.options.length > 0) { - //Add (ctrl) to first two actions of first option - if (button.action == currentBuildMode.options[0].actions[0] - || button.action == currentBuildMode.options[0].actions[1]) { - keybind = I18n.get(ClientProxy.keyBindings[5].saveString()); - if (keybind.equals("Left Control")) keybind = "Ctrl"; - } - } + String keybind = findKeybind(button, currentBuildMode); + String keybindFormatted = ""; if (!keybind.isEmpty()) keybindFormatted = TextFormatting.GRAY + "(" + WordUtils.capitalizeFully(keybind) + ")"; if (button.textSide == Direction.WEST) { font.draw(ms, text, (int) (middleX + button.x1 - 8) - font.width(text), - (int) (middleY + button.y1 + 6), 0xffffffff); + (int) (middleY + button.y1 + 6), whiteTextColor); } else if (button.textSide == Direction.EAST) { font.draw(ms, text, (int) (middleX + button.x2 + 8), - (int) (middleY + button.y1 + 6), 0xffffffff); + (int) (middleY + button.y1 + 6), whiteTextColor); } else if (button.textSide == Direction.UP || button.textSide == Direction.NORTH) { font.draw(ms, keybindFormatted, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(keybindFormatted) * 0.5), - (int) (middleY + button.y1 - 26), 0xffffffff); + (int) (middleY + button.y1 - 26), whiteTextColor); font.draw(ms, text, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(text) * 0.5), - (int) (middleY + button.y1 - 14), 0xffffffff); + (int) (middleY + button.y1 - 14), whiteTextColor); } else if (button.textSide == Direction.DOWN || button.textSide == Direction.SOUTH) { font.draw(ms, text, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(text) * 0.5), - (int) (middleY + button.y1 + 26), 0xffffffff); + (int) (middleY + button.y1 + 26), whiteTextColor); font.draw(ms, keybindFormatted, (int) (middleX + (button.x1 + button.x2) * 0.5 - font.width(keybindFormatted) * 0.5), - (int) (middleY + button.y1 + 38), 0xffffffff); + (int) (middleY + button.y1 + 38), whiteTextColor); } } } + } - RenderSystem.popMatrix(); + private String findKeybind(MenuButton button, BuildModeEnum currentBuildMode){ + String result = ""; + int keybindingIndex = -1; + if (button.action == ActionEnum.UNDO) keybindingIndex = 3; + if (button.action == ActionEnum.REDO) keybindingIndex = 4; + if (button.action == ActionEnum.REPLACE) keybindingIndex = 1; + if (button.action == ActionEnum.OPEN_MODIFIER_SETTINGS) keybindingIndex = 0; + + if (keybindingIndex != -1) { + KeyBinding keyMap = ClientProxy.keyBindings[keybindingIndex]; + + if (!keyMap.getKeyModifier().name().equals("none")) { + result = keyMap.getKeyModifier().name() + " "; + } + result += I18n.get(keyMap.getKey().getName()); + } + + if (currentBuildMode.options.length > 0) { + //Add (ctrl) to first two actions of first option + if (button.action == currentBuildMode.options[0].actions[0] + || button.action == currentBuildMode.options[0].actions[1]) { + result = I18n.get(ClientProxy.keyBindings[5].getKey().getName()); + if (result.equals("Left Control")) result = "Ctrl"; + } + } + return result; } private boolean inTriangle(final double x1, final double y1, final double x2, final double y2, @@ -463,7 +501,7 @@ public class RadialMenu extends Screen { ModeSettingsManager.setModeSettings(player, modeSettings); PacketHandler.INSTANCE.sendToServer(new ModeSettingsMessage(modeSettings)); - EffortlessBuilding.log(player, I18n.get(modeSettings.getBuildMode().name), true); + EffortlessBuilding.log(player, I18n.get(modeSettings.getBuildMode().getNameKey()), true); if (fromMouseClick) performedActionUsingMouse = true; } diff --git a/src/main/java/nl/requios/effortlessbuilding/render/BuildRenderTypes.java b/src/main/java/nl/requios/effortlessbuilding/render/BuildRenderTypes.java index f4021f0..e984513 100644 --- a/src/main/java/nl/requios/effortlessbuilding/render/BuildRenderTypes.java +++ b/src/main/java/nl/requios/effortlessbuilding/render/BuildRenderTypes.java @@ -6,6 +6,7 @@ import net.minecraft.client.renderer.RenderState; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; @@ -14,22 +15,7 @@ import org.lwjgl.opengl.*; import java.util.OptionalDouble; import java.util.function.Consumer; -public class BuildRenderTypes { - public static final RenderState.TransparencyState TRANSLUCENT_TRANSPARENCY; - public static final RenderState.TransparencyState NO_TRANSPARENCY; - - public static final RenderState.DiffuseLightingState DIFFUSE_LIGHTING_ENABLED; - public static final RenderState.DiffuseLightingState DIFFUSE_LIGHTING_DISABLED; - - public static final RenderState.LayerState PROJECTION_LAYERING; - - public static final RenderState.CullState CULL_DISABLED; - - public static final RenderState.AlphaState DEFAULT_ALPHA; - - public static final RenderState.WriteMaskState WRITE_TO_DEPTH_AND_COLOR; - public static final RenderState.WriteMaskState COLOR_WRITE; - +public class BuildRenderTypes extends RenderType { public static final RenderType LINES; public static final RenderType PLANES; @@ -37,57 +23,42 @@ public class BuildRenderTypes { private static final int secondaryTextureUnit = 2; static { - TRANSLUCENT_TRANSPARENCY = ObfuscationReflectionHelper.getPrivateValue(RenderState.class, null, "TRANSLUCENT_TRANSPARENCY"); - NO_TRANSPARENCY = ObfuscationReflectionHelper.getPrivateValue(RenderState.class, null, "NO_TRANSPARENCY"); - - DIFFUSE_LIGHTING_ENABLED = new RenderState.DiffuseLightingState(true); - DIFFUSE_LIGHTING_DISABLED = new RenderState.DiffuseLightingState(false); - - PROJECTION_LAYERING = ObfuscationReflectionHelper.getPrivateValue(RenderState.class, null, "VIEW_OFFSET_Z_LAYERING"); - - CULL_DISABLED = new RenderState.CullState(false); - - DEFAULT_ALPHA = new RenderState.AlphaState(0.003921569F); - - final boolean ENABLE_DEPTH_WRITING = true; - final boolean ENABLE_COLOUR_COMPONENTS_WRITING = true; - WRITE_TO_DEPTH_AND_COLOR = new RenderState.WriteMaskState(ENABLE_COLOUR_COMPONENTS_WRITING, ENABLE_DEPTH_WRITING); - COLOR_WRITE = new RenderState.WriteMaskState(true, false); - + final LineState LINE = new LineState(OptionalDouble.of(2.0)); final int INITIAL_BUFFER_SIZE = 128; RenderType.State renderState; //LINES -// RenderSystem.pushLightingAttributes(); -// RenderSystem.pushTextureAttributes(); -// RenderSystem.disableCull(); -// RenderSystem.disableLighting(); -// RenderSystem.disableTexture(); -// -// RenderSystem.enableBlend(); -// RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); -// -// RenderSystem.lineWidth(2); - renderState = RenderType.State.builder() - .setLineState(new RenderState.LineState(OptionalDouble.of(2))) - .setLayeringState(PROJECTION_LAYERING) - .setTransparencyState(TRANSLUCENT_TRANSPARENCY) - .setWriteMaskState(WRITE_TO_DEPTH_AND_COLOR) - .setCullState(CULL_DISABLED) - .createCompositeState(false); + renderState = State.builder() + .setLineState(LINE) + .setLayeringState(VIEW_OFFSET_Z_LAYERING) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setTextureState(NO_TEXTURE) + .setDepthTestState(NO_DEPTH_TEST) + .setLightmapState(NO_LIGHTMAP) + .setWriteMaskState(COLOR_DEPTH_WRITE) + .setCullState(NO_CULL) + .createCompositeState(false); LINES = RenderType.create("eb_lines", - DefaultVertexFormats.POSITION_COLOR, GL11.GL_LINES, INITIAL_BUFFER_SIZE, renderState); + DefaultVertexFormats.POSITION_COLOR, GL11.GL_LINES, INITIAL_BUFFER_SIZE, false, false, renderState); - renderState = RenderType.State.builder() - .setLineState(new RenderState.LineState(OptionalDouble.of(2))) - .setLayeringState(PROJECTION_LAYERING) - .setTransparencyState(TRANSLUCENT_TRANSPARENCY) - .setWriteMaskState(COLOR_WRITE) - .setCullState(CULL_DISABLED) - .createCompositeState(false); + //PLANES + renderState = State.builder() + .setLineState(LINE) + .setLayeringState(VIEW_OFFSET_Z_LAYERING) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setTextureState(NO_TEXTURE) + .setDepthTestState(NO_DEPTH_TEST) + .setLightmapState(NO_LIGHTMAP) + .setWriteMaskState(COLOR_WRITE) + .setCullState(NO_CULL) + .createCompositeState(false); PLANES = RenderType.create("eb_planes", - DefaultVertexFormats.POSITION_COLOR, GL11.GL_TRIANGLE_STRIP, INITIAL_BUFFER_SIZE, renderState); + DefaultVertexFormats.POSITION_COLOR, GL11.GL_TRIANGLE_STRIP, INITIAL_BUFFER_SIZE, false, false, renderState); + } + // Dummy constructor needed to make java happy + public BuildRenderTypes(String p_i225992_1_, VertexFormat p_i225992_2_, int p_i225992_3_, int p_i225992_4_, boolean p_i225992_5_, boolean p_i225992_6_, Runnable p_i225992_7_, Runnable p_i225992_8_) { + super(p_i225992_1_, p_i225992_2_, p_i225992_3_, p_i225992_4_, p_i225992_5_, p_i225992_6_, p_i225992_7_, p_i225992_8_); } public static RenderType getBlockPreviewRenderType(float dissolve, BlockPos blockPos, BlockPos firstPos, @@ -107,7 +78,7 @@ public class BuildRenderTypes { //highjacking texturing state (which does nothing by default) to do my own things String stateName = "eb_texturing_" + dissolve + "_" + blockPos + "_" + firstPos + "_" + secondPos + "_" + red; - RenderState.TexturingState MY_TEXTURING = new RenderState.TexturingState(stateName, () -> { + TexturingState MY_TEXTURING = new TexturingState(stateName, () -> { // RenderSystem.pushLightingAttributes(); // RenderSystem.pushTextureAttributes(); @@ -116,14 +87,14 @@ public class BuildRenderTypes { }, ShaderHandler::releaseShader); RenderType.State renderState = RenderType.State.builder() - .setTextureState(new RenderState.TextureState(ShaderHandler.shaderMaskTextureLocation, false, false)) + .setTextureState(new TextureState(ShaderHandler.shaderMaskTextureLocation, false, false)) .setTexturingState(MY_TEXTURING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) - .setDiffuseLightingState(DIFFUSE_LIGHTING_DISABLED) + .setDiffuseLightingState(NO_DIFFUSE_LIGHTING) .setAlphaState(DEFAULT_ALPHA) - .setCullState(new RenderState.CullState(true)) - .setLightmapState(new RenderState.LightmapState(false)) - .setOverlayState(new RenderState.OverlayState(false)) + .setCullState(new CullState(true)) + .setLightmapState(new LightmapState(false)) + .setOverlayState(new OverlayState(false)) .createCompositeState(true); //Unique name for every combination, otherwise it will reuse the previous one String name = "eb_block_previews_" + dissolve + "_" + blockPos + "_" + firstPos + "_" + secondPos + "_" + red; @@ -198,43 +169,4 @@ public class BuildRenderTypes { this.red = red; } } - -// public static class MyTexturingState extends RenderState.TexturingState { -// -// public float dissolve; -// public Vector3d blockPos; -// public Vector3d firstPos; -// public Vector3d secondPos; -// public boolean highlight; -// public boolean red; -// -// public MyTexturingState(String p_i225989_1_, float dissolve, Vector3d blockPos, Vector3d firstPos, -// Vector3d secondPos, boolean highlight, boolean red, Runnable p_i225989_2_, Runnable p_i225989_3_) { -// super(p_i225989_1_, p_i225989_2_, p_i225989_3_); -// this.dissolve = dissolve; -// this.blockPos = blockPos; -// this.firstPos = firstPos; -// this.secondPos = secondPos; -// this.highlight = highlight; -// this.red = red; -// } -// -// @Override -// public boolean equals(Object p_equals_1_) { -// if (this == p_equals_1_) { -// return true; -// } else if (p_equals_1_ != null && this.getClass() == p_equals_1_.getClass()) { -// MyTexturingState other = (MyTexturingState)p_equals_1_; -// return this.dissolve == other.dissolve && this.blockPos == other.blockPos && this.firstPos == other.firstPos -// && this.secondPos == other.secondPos && this.highlight == other.highlight && this.red == other.red; -// } else { -// return false; -// } -// } -// -// @Override -// public int hashCode() { -// -// } -// } } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index cd021f1..2e8f888 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,9 +1,3 @@ -# This is an example mods.toml file. It contains the data relating to the loading mods. -# There are several mandatory fields (#mandatory), and many more that are optional (#optional). -# The overall format is standard TOML format, v0.5.0. -# Note that there are a couple of TOML lists in this file. -# Find more information on toml format here: https://github.com/toml-lang/toml -# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the forge version loaderVersion="[34,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. @@ -30,7 +24,7 @@ credits="" #optional authors="Requios" #optional # The description text for the mod (multi line!) (#mandatory) description=''' -Makes building easier by providing tools like mirrors, arrays, QuickReplace and a block randomizer. For survival and creative mode. +Makes building easier by providing tools like mirrors, arrays, build modes and a block randomizer. For survival and creative mode. ''' # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. [[dependencies.examplemod]] #optional diff --git a/src/main/resources/assets/effortlessbuilding/lang/en_us.json b/src/main/resources/assets/effortlessbuilding/lang/en_us.json index aebc911..3a37363 100644 --- a/src/main/resources/assets/effortlessbuilding/lang/en_us.json +++ b/src/main/resources/assets/effortlessbuilding/lang/en_us.json @@ -18,8 +18,8 @@ "effortlessbuilding:reach_upgrade2": "Reach Upgrade 2", "effortlessbuilding:reach_upgrade3": "Reach Upgrade 3", - "effortlessbuilding.mode.normal": "Normal", - "effortlessbuilding.mode.normal_plus": "Normal+", + "effortlessbuilding.mode.normal": "Disable", + "effortlessbuilding.mode.normal_plus": "Single", "effortlessbuilding.mode.line": "Line", "effortlessbuilding.mode.wall": "Wall", "effortlessbuilding.mode.floor": "Floor", @@ -30,6 +30,25 @@ "effortlessbuilding.mode.circle": "Circle", "effortlessbuilding.mode.cylinder": "Cylinder", "effortlessbuilding.mode.sphere": "Sphere", + "effortlessbuilding.mode.pyramid": "Pyramid", + "effortlessbuilding.mode.cone": "Cone", + "effortlessbuilding.mode.dome": "Dome", + + "effortlessbuilding.modedescription.normal": "Disable mod and use vanilla placement rules", + "effortlessbuilding.modedescription.normal_plus": "Like vanilla, but with increased reach and placement preview", + "effortlessbuilding.modedescription.line": "", + "effortlessbuilding.modedescription.wall": "", + "effortlessbuilding.modedescription.floor": "", + "effortlessbuilding.modedescription.diagonal_line": "", + "effortlessbuilding.modedescription.diagonal_wall": "", + "effortlessbuilding.modedescription.slope_floor": "", + "effortlessbuilding.modedescription.cube": "", + "effortlessbuilding.modedescription.circle": "", + "effortlessbuilding.modedescription.cylinder": "", + "effortlessbuilding.modedescription.sphere": "", + "effortlessbuilding.modedescription.pyramid": "", + "effortlessbuilding.modedescription.cone": "", + "effortlessbuilding.modedescription.dome": "", "effortlessbuilding.action.undo": "Undo", "effortlessbuilding.action.redo": "Redo", diff --git a/src/main/resources/assets/effortlessbuilding/lang/ru_ru.json b/src/main/resources/assets/effortlessbuilding/lang/ru_ru.json new file mode 100644 index 0000000..e28a436 --- /dev/null +++ b/src/main/resources/assets/effortlessbuilding/lang/ru_ru.json @@ -0,0 +1,79 @@ +{ +"efortlessbuilding.screen.modifier_settings": "Настройки модификатора", +"efortlessbuilding.screen.radial_menu": "Режимы строительства", +"efortlessbuilding.screen.player_settings": "Настройки игрока", + +"key.efortlessbuilding.category": "Строительство без усилий", +"key.efortlessbuilding.hud.desc": "Меню модификаторов", +"key.effortlessbuilding.replace.desc": "Переключить быструю замену", +"key.efortlessbuilding.mode.desc": "Круговое меню", +"key.efortlessbuilding.undo.desc": "Отменить", +"key.effortlessbuilding.redo.desc": "Повторить", +"key.efortlessbuilding.altplacement.desc": "Альтернативное размещение", + +"efortlessbuilding:randomizer_bag": "Кожаная сумка рандомизатора", +"efortlessbuilding:golden_randomizer_bag": "Золотой мешок рандомизатора", +"efortlessbuilding:diamond_randomizer_bag": "Бриллиантовый рандомизатор", +"efortlessbuilding:reach_upgrade1": "Достичь улучшения 1", +"efortlessbuilding:reach_upgrade2": "Достичь улучшения 2", +"efortlessbuilding:reach_upgrade3": "Достичь улучшения 3", + +"efortlessbuilding.mode.normal": "Отключить", +"efortlessbuilding.mode.normal_plus": "Одиночный", +"efortlessbuilding.mode.line": "Линия", +"efortlessbuilding.mode.wall": "Стена", +"efortlessbuilding.mode.floor": "Этаж", +"efortlessbuilding.mode.diagonal_line": "Диагональная линия", +"efortlessbuilding.mode.diagonal_wall": "Диагональная стена", +"effortlessbuilding.mode.slope_floor": "Наклонный этаж", +"effortlessbuilding.mode.cube": "Куб", +"efortlessbuilding.mode.circle": "Круг", +"efortlessbuilding.mode.cylinder": "Цилиндр", +"efortlessbuilding.mode.sphere": "Сфера", +"efortlessbuilding.mode.pyramid": "Пирамида", +"effortlessbuilding.mode.cone": "Конус", +"efortlessbuilding.mode.dome": "Купол", + +"effortlessbuilding.modedescription.normal": "Отключить мод и использовать ванильные правила размещения", +"effortlessbuilding.modedescription.normal_plus": "Как и ваниль, но с увеличенным охватом и предварительным просмотром места размещения", +"efortlessbuilding.modedescription.line": "", +"efortlessbuilding.modedescription.wall": "", +"efortlessbuilding.modedescription.floor": "", +"efortlessbuilding.modedescription.diagonal_line": "", +"efortlessbuilding.modedescription.diagonal_wall": "", +"effortlessbuilding.modedescription.slope_floor": "", +"efortlessbuilding.modedescription.cube": "", +"efortlessbuilding.modedescription.circle": "", +"efortlessbuilding.modedescription.cylinder": "", +"efortlessbuilding.modedescription.sphere": "", +"efortlessbuilding.modedescription.pyramid": "", +"efortlessbuilding.modedescription.cone": "", +"efortlessbuilding.modedescription.dome": "", + +"efortlessbuilding.action.undo": "Отменить", +"efortlessbuilding.action.redo": "Повторить", +"efortlessbuilding.action.replace": "Заменить", +"efortlessbuilding.action.open_modifier_settings": "Открыть настройки модификатора", +"efortlessbuilding.action.open_player_settings": "Открыть настройки", + +"efortlessbuilding.action.build_speed": "Скорость сборки", +"efortlessbuilding.action.filling": "Заполнение", +"efortlessbuilding.action.raised_edge": "Приподнятый край", +"efortlessbuilding.action.thickness": "Толщина линии", +"efortlessbuilding.action.circle_start": "Начальная точка", + +"efortlessbuilding.action.normal_speed": "Нормальный", +"efortlessbuilding.action.fast_speed": "Быстро", +"efortlessbuilding.action.full": "Заполнено", +"efortlessbuilding.action.hollow": "Пустой", +"efortlessbuilding.action.skeleton": "Скелет", +"efortlessbuilding.action.short_edge": "Короткая кромка", +"efortlessbuilding.action.long_edge": "Длинный край", +"efortlessbuilding.action.thickness_1": "Толщиной 1 блок", +"efortlessbuilding.action.thickness_3": "Толщиной 3 блока", +"efortlessbuilding.action.thickness_5": "Толщиной 5 блоков", +"efortlessbuilding.action.start_center": "Посередине", +"efortlessbuilding.action.start_corner": "Угол", + +"commands.reach.usage": "/reach <уровень>" +} diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/cone.png b/src/main/resources/assets/effortlessbuilding/textures/icons/cone.png new file mode 100644 index 0000000000000000000000000000000000000000..0444196c342e45b790117696411a4db77f6beb34 GIT binary patch literal 361 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 H>g)dk%NBW# delta 267 zcmV+m0rdX+CcgrZBM<-vVoOIv0RI600RN!9r<0SW5*~l!0tf;DDk4;r`Tzg`%t=H+ zR5;6>lg$x?APj{cJ2n%C6UBJ64ok2NEXWH^D2F}4gz)3ezEhCAj~ECr5fLRKO0yg@ zG6DcI0|3@_1pvet%@m-GT0>ASRV##$y!Xv_`D=!Vl0NZyo)X{pUE+P;n~D|yxUQ>8 zu+~-}ZIo{ZEOMg<$}ny00!E;oG3z52&N-atS%IW^+qSAF4IoQGr1`aie^m9rS_@__ z4@N6r_v}_@UYd*yrLnhX zT$4I%Fu{D*3b_Vd~oE!(FU-RcyV wPTtYG>3^8~8i6;hQLl@qtUvt3QSppK^R-`fGyYkh+kZr?Ro3~!IZb{2+=>5*7xWPvLpBgslmGw#07*qoM6N<$ Ef)E3Z<^TWy delta 290 zcmV+-0p0%10=)u|B!32COGiWi{{a60|De66lK=n!32;bRa{vGizW@LZzX3P}QzQTY z00(qQO+^Re0tf;DA}o&_$N&HU%1J~)R5;7UQ$Y@cAP^iHKf@mViV5C$hd1#la3t|H z8ox8W6iQW$Nt<*M4rFI$7Z?;te1iwR#HE3VP(&_AY-&OP*nhTdzgGvc_a5GRkc8Hn zT5Hyj>WNSCJ%NZYb*!PB$XcroM+hMR0IapA2J5=syMw*anef&tgb*&pKgmJUw(WnD zm@hHLsEjcLfMFO;$;KD}K;QQ{P|ZBg0D!LR5Mxv?;)l^*IF4gBRp~cQ)0B;hj;skY oQY6deoWrs#a2w8@*2^eA0nZ_vDtO7Ds{jB107*qoM6N<$g1t<3KmY&$ diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/normal_plus.png b/src/main/resources/assets/effortlessbuilding/textures/icons/normal_plus.png index 96d9d618d16715d53b27c140d6fbf255343f0ffc..2d846ea5882eeb39d721bfe40f80f4249e6a8119 100644 GIT binary patch delta 239 zcmVN92!5v9{q|5-gt*M@hNa5 z@iiL1Grbf_Rg6iSbP^6^XJ!`|6iIx82foCmfrwBY%F2z5|LDRPF zf0LLmF~+EjF$92N7*5H?7yv-u_c>6_JkJ1tuImtER4?L((Ox)?V>VUkH%`-(jf#$} p2{Te8%jKNIvMg}Uoz}}JKLO7noGN(9psN4?002ovPDHLkV1l!|Xjyn9f9aU20~&XEHZAp`*Gx{f!R(0`!Y`79{Jl>rb z?@ie>4FDpt2(U^Em)xZD1AJQy5mA7)ZDY-QAJ0`)acwgrNJKP*pncz~<$s=UvG7{h c`U89dB35%YU=JpJW&i*H07*qoM6N<$g1cmYIsgCw diff --git a/src/main/resources/assets/effortlessbuilding/textures/icons/pyramid.png b/src/main/resources/assets/effortlessbuilding/textures/icons/pyramid.png new file mode 100644 index 0000000000000000000000000000000000000000..4c3d72fb73438f45b9cacd3b64e594231cc0bd18 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5M?jcysy3fAP;i5% zi(`mI@6pKzd0Q2D9ORFszL}V4#jR}N{oJr{&c9|423LMLJI?85?*pSa-kqCnTD#~z zi_)XY`%f8W%zrRN$j~k1>h@gj(tBt48apNgWj!d3-P<=)a@DJ}YaT97s#@jVsn+fh z?0KN>DY)mLvS-9J)&!2@68Vo;aS1F_|FKr+fH&)bRH?;WpI$N~o=a$0%CJMVGG z)l1EFqJecDyb;{)O>QhLb{pUSp7`T;{vXDQjnRwMl@u=m-Ok|Y>gTe~DWS>sfbanc z=iA#NvKjr%k``sKpWC_qcHH%^_nO{6x-C?$`02jnt()IvvvtqyRAxV~ebKUgiqWl3 yap~k8y_^1r$*&Q3(;D@lld1jny26}X8&;B%ZMQ%d1)AH;m>5Y=5lKQKbc?cDsY z9l4&s(QT#2b_R<{!)xy+l6-+vbN|MDj`IyC$o0~LW0MU7E8iEWiVA`niwjHiT|Umh z)f1wDAR8;-(tkX7?fodS8AUd8q4N^4!_U0jeL|&H!P2UbOB7J;=0*iy-lR}X8kJg! z)o7U2Xc&Q@tEHDunKf3HUgPSsVWi6#>2f1Mo7+mOxeb7KKVC7?J;B4xdkl45pVKlx6~LLFRRDHs8qJJ? z(D1zm&mY`jq|adL*77eJz5B2{H>LVdTp%)*1|iTb8`YMC>^MWo5h4Sl*o_aF?EA*` z9~!M25F4IAw`_!_qgytz{u#|Mf4rd`;`Scjq&hA$M zK)qN%Go$F1y?-MP^(OGYHIdaKD4*VlMWynEK|2(5u$ZfX&`?St-7?ZGgYpq!i}r>~ z^~D0w)G3NzB_A6y2$&qO(89*H?Rtf9-yoioCmh=c%E$HEWS1V&>U7YB2m)TN>0;^b z4g6LU^S~qkN_u$3Jf4%|(3wjdNm#5@wlG$E#BXzO`+wp=HFJEF^-_iLV<)KVKlx6~LLFRRDHs8qJJ? z(D1zm&mY`jq|adL*77eJz5B2{H>LVdTp%)*1|iTb8`YMC>^MWo5h4Sl*o_aF?EA*` z9~!M25F4IAw`_!_qgytz{u#|Mf4rd`;`Scjq&hA$M zK)qN%Go$F1y?-MP^(OGYHIdaKD4*VlMWynEK|2(5u$ZfX&`?St-7?ZGgYpq!i}r>~ z^~D0w)G3NzB_A6y2$&qO(89*H?Rtf9-yoioCmh=c%E$HEWS1V&>U7YB2m)TN>0;^b z4g6LU^S~qkN_u$3Jf4%|(3wjdNm#5@wlG$E#BXzO`+wp=HFJEF^-_iLV<)Klld1jny26}X8&;B%ZMQ%d1)AH;m>5Y=5lKQKbc?cDsY z9l4&s(QT#2b_R<{!)xy+l6-+vbN|MDj`IyC$o0~LW0MU7E8iEWiVA`niwjHiT|Umh z)f1wDAR8;-(tkX7?fodS8AUd8q4N^4!_U0jeL|&H!P2UbOB7J;=0*iy-lR}X8kJg! z)o7U2Xc&Q@tEHDunKf3HUgPSsVWi6#>2f1Mo7+mOxeb7KKVC7?J;B4xdkl45p