From 5fa7cdbc33a1237a88c577ed04d4c1cbac62a4b1 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Tue, 28 Apr 2026 21:17:16 +0800 Subject: [PATCH 01/34] add animation for opening manual --- .../tconstruct/tools/gui/TiCGuiManual.java | 100 +++++++++++++++--- 1 file changed, 84 insertions(+), 16 deletions(-) diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 793890ef2e..4c3e4c869e 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -26,6 +26,11 @@ @SideOnly(Side.CLIENT) public class TiCGuiManual extends GuiManual { + private static final int ANIMATIONDURATIONINMILLIS = 600; + private static final double FLYIN_DURATION = 0.55; // portion for fly-in + private static final double OVERSHOOT_DURATION = 0.1; // portion for overshoot + private static final double EXTENT = 0.02; // overshoot amount as fraction of total displacement + ItemStack itemstackBook; Document manual; public RenderItemCopy renderitem = new RenderItemCopy(); @@ -36,11 +41,17 @@ public class TiCGuiManual extends GuiManual { int maxPages; BookData bData; + private boolean needUpdateAnimation; + private TurnPageButton buttonNextPage; private TurnPageButton buttonPreviousPage; private static ResourceLocation bookRight;// = new ResourceLocation("mantle", "textures/gui/bookright.png"); private static ResourceLocation bookLeft;// = new ResourceLocation("mantle", "textures/gui/bookleft.png"); + private long guiOpenTime; + + private int baseDrawingX; + private int baseDrawingY; BookPage pageLeft; BookPage pageRight; @@ -56,6 +67,8 @@ public TiCGuiManual(ItemStack stack, BookData data) { bookLeft = data.leftImage; bookRight = data.rightImage; this.bData = data; + this.guiOpenTime = System.currentTimeMillis(); + this.needUpdateAnimation = true; // renderitem.renderInFrame = true; } @@ -70,7 +83,7 @@ public TiCGuiManual(ItemStack stack, BookData data) { public void initGui() { maxPages = manual.getElementsByTagName("page").getLength(); ticUpdateText(); - int xPos = (this.width) / 2; // TODO Width? + int xPos = this.width / 2; // TODO Width? // TODO buttonList this.buttonList.add( this.buttonNextPage = new TurnPageButton( @@ -160,33 +173,41 @@ private void changePage(int buttonId) { } public void drawScreen(int par1, int par2, float par3) { - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - this.mc.getTextureManager().bindTexture(bookRight); - // aligen to center - int localWidth = (this.width / 2); - int localHeight = ((this.height - this.bookImageHeight) / 2); + // int localWidth = (this.width / 2); + // int localHeight = ((this.height - this.bookImageHeight) / 2); - this.drawTexturedModalRect(localWidth, localHeight, 0, 0, this.bookImageWidth, this.bookImageHeight); + if (this.needUpdateAnimation) { + float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; + int[] point = this.getOvershootPosition(progress); + this.baseDrawingX = point[0]; + this.baseDrawingY = point[1]; + if (progress >= 1.0f) this.needUpdateAnimation = false; + } + + int drawX = this.baseDrawingX; + int drawY = this.baseDrawingY; GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.mc.getTextureManager().bindTexture(bookRight); + this.drawTexturedModalRect(drawX, drawY, 0, 0, this.bookImageWidth, this.bookImageHeight); + this.mc.getTextureManager().bindTexture(bookLeft); - localWidth = localWidth - this.bookImageWidth; + drawX = drawX - this.bookImageWidth; this.drawTexturedModalRect( - localWidth, - localHeight, + drawX, + drawY, 256 - this.bookImageWidth, 0, this.bookImageWidth, this.bookImageHeight); - this.drawButtons(par1, par2); - - if (pageLeft != null) pageLeft.renderBackgroundLayer(localWidth + 16, localHeight + 12); - if (pageRight != null) pageRight.renderBackgroundLayer(localWidth + 220, localHeight + 12); - if (pageLeft != null) pageLeft.renderContentLayer(localWidth + 16, localHeight + 12, bData.isTranslatable); - if (pageRight != null) pageRight.renderContentLayer(localWidth + 220, localHeight + 12, bData.isTranslatable); + if (!this.needUpdateAnimation) this.drawButtons(par1, par2); + if (pageLeft != null) pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); + if (pageRight != null) pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); + if (pageLeft != null) pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); + if (pageRight != null) pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); } /** @@ -212,4 +233,51 @@ public Minecraft getMC() { public boolean doesGuiPauseGame() { return false; } + + /** + * Computes the current position after applying an overshoot and bounce animation. + * + * @param progress global animation progress in [0,1], where 0 = start, 1 = end + * @return the current (X, Y) point for the given progress + */ + private int[] getOvershootPosition(float progress) { + + int endX = (this.width / 2); + int startX = endX; + + int endY = (this.height - this.bookImageHeight) / 2; + int startY = this.height + this.bookImageHeight; + + // Clamp progress to [0,1] + double t = Math.min(Math.max(progress, 0.0), 1.0); + + double factor; // displacement factor (0 → 1+EXTENT → 1) + + if (t <= FLYIN_DURATION) { + // Phase 1: linear fly in + double phaseT = t / FLYIN_DURATION; // [0,1] + factor = phaseT; + } else if (t <= FLYIN_DURATION + OVERSHOOT_DURATION) { + // Phase 2: overshoot (1 → 1+EXTENT) with ease out + double phaseT = (t - FLYIN_DURATION) / OVERSHOOT_DURATION; // [0,1] + double eased = 1.0 - Math.pow(1.0 - phaseT, 2); + factor = 1.0 + EXTENT * eased; + } else { + // Phase 3: correct back to target (1+EXTENT → 1) linear + double remaining = 1.0 - (FLYIN_DURATION + OVERSHOOT_DURATION); + double phaseT = (t - (FLYIN_DURATION + OVERSHOOT_DURATION)) / remaining; // [0,1] + double peak = 1.0 + EXTENT; + factor = peak + (1.0 - peak) * phaseT; + } + + // Clamp factor to reasonable range (should stay inside [0, 1+EXTENT]) + factor = Math.min(factor, 1.0 + EXTENT); + + // Linear interpolation + int x = (int) (startX + (endX - startX) * factor); + int y = (int) (startY + (endY - startY) * factor); + + return new int[] { x, y }; + } + } From c927af7e050bf4518e06e2ec7990ffc8f9c7fdaa Mon Sep 17 00:00:00 2001 From: MCTBL Date: Tue, 28 Apr 2026 21:36:58 +0800 Subject: [PATCH 02/34] add auto scaled but have some issue --- .../tconstruct/tools/gui/TiCGuiManual.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 4c3e4c869e..7bee7db292 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -177,6 +177,10 @@ public void drawScreen(int par1, int par2, float par3) { // int localWidth = (this.width / 2); // int localHeight = ((this.height - this.bookImageHeight) / 2); + float scale = Math.max( + 1.0f, + Math.min(this.width * 0.8f / (this.bookImageWidth * 2), this.height * 0.8f / this.bookImageHeight)); + if (this.needUpdateAnimation) { float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; int[] point = this.getOvershootPosition(progress); @@ -185,10 +189,12 @@ public void drawScreen(int par1, int par2, float par3) { if (progress >= 1.0f) this.needUpdateAnimation = false; } - int drawX = this.baseDrawingX; - int drawY = this.baseDrawingY; + int drawX = (int) (this.baseDrawingX / scale); + int drawY = (int) (this.baseDrawingY / scale / scale); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glScalef(scale, scale, 1.0f); + this.mc.getTextureManager().bindTexture(bookRight); this.drawTexturedModalRect(drawX, drawY, 0, 0, this.bookImageWidth, this.bookImageHeight); @@ -202,7 +208,7 @@ public void drawScreen(int par1, int par2, float par3) { this.bookImageWidth, this.bookImageHeight); - if (!this.needUpdateAnimation) this.drawButtons(par1, par2); + if (!this.needUpdateAnimation) this.drawButtons(par1, par2, drawX + this.bookImageWidth, drawY); if (pageLeft != null) pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); if (pageRight != null) pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); @@ -213,13 +219,23 @@ public void drawScreen(int par1, int par2, float par3) { /** * copy from {@link net.minecraft.client.gui.GuiScreen#drawScreen(int, int, float)} */ - public void drawButtons(int mouseX, int mouseY) { + public void drawButtons(int mouseX, int mouseY, int x, int y) { + + this.buttonNextPage.xPosition = (int) (x + this.bookImageWidth * 0.8); + this.buttonPreviousPage.xPosition = (int) (x - this.bookImageWidth * 0.9); + + this.buttonNextPage.yPosition = (int) (y + this.bookImageHeight * 0.85); + this.buttonPreviousPage.yPosition = (int) (y + this.bookImageHeight * 0.85); + + this.buttonNextPage.drawButton(this.mc, mouseX, mouseY); + this.buttonPreviousPage.drawButton(this.mc, mouseX, mouseY); + // copy from @GuiScreen.drawScreen int k; - for (k = 0; k < this.buttonList.size(); ++k) { - ((GuiButton) this.buttonList.get(k)).drawButton(this.mc, mouseX, mouseY); - } + // for (k = 0; k < this.buttonList.size(); ++k) { + // ((GuiButton) this.buttonList.get(k)).drawButton(this.mc, mouseX, mouseY); + // } for (k = 0; k < this.labelList.size(); ++k) { ((GuiLabel) this.labelList.get(k)).func_146159_a(this.mc, mouseX, mouseY); From f7c67cd0452e8905f429c1cef9c3b90833846af2 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Wed, 29 Apr 2026 11:14:36 +0800 Subject: [PATCH 03/34] add auto scale for manual --- .../tconstruct/tools/gui/TiCGuiManual.java | 60 ++++++++------- .../tools/gui/TiCTurnPageButton.java | 75 +++++++++++++++++++ 2 files changed, 109 insertions(+), 26 deletions(-) create mode 100644 src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 7bee7db292..143656c9a5 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -2,7 +2,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiLabel; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; @@ -19,7 +18,6 @@ import mantle.client.RenderItemCopy; import mantle.client.SmallFontRenderer; import mantle.client.gui.GuiManual; -import mantle.client.gui.TurnPageButton; import mantle.client.pages.BookPage; import tconstruct.TConstruct; @@ -41,10 +39,10 @@ public class TiCGuiManual extends GuiManual { int maxPages; BookData bData; - private boolean needUpdateAnimation; + private boolean isAnimationDone; - private TurnPageButton buttonNextPage; - private TurnPageButton buttonPreviousPage; + private TiCTurnPageButton buttonNextPage; + private TiCTurnPageButton buttonPreviousPage; private static ResourceLocation bookRight;// = new ResourceLocation("mantle", "textures/gui/bookright.png"); private static ResourceLocation bookLeft;// = new ResourceLocation("mantle", "textures/gui/bookleft.png"); @@ -68,7 +66,7 @@ public TiCGuiManual(ItemStack stack, BookData data) { bookRight = data.rightImage; this.bData = data; this.guiOpenTime = System.currentTimeMillis(); - this.needUpdateAnimation = true; + this.isAnimationDone = false; // renderitem.renderInFrame = true; } @@ -86,14 +84,14 @@ public void initGui() { int xPos = this.width / 2; // TODO Width? // TODO buttonList this.buttonList.add( - this.buttonNextPage = new TurnPageButton( + this.buttonNextPage = new TiCTurnPageButton( 1, xPos + bookImageWidth - 50, (this.height + this.bookImageHeight) / 2 - 28, true, bData)); this.buttonList.add( - this.buttonPreviousPage = new TurnPageButton( + this.buttonPreviousPage = new TiCTurnPageButton( 2, xPos - bookImageWidth + 24, (this.height + this.bookImageHeight) / 2 - 28, @@ -181,17 +179,19 @@ public void drawScreen(int par1, int par2, float par3) { 1.0f, Math.min(this.width * 0.8f / (this.bookImageWidth * 2), this.height * 0.8f / this.bookImageHeight)); - if (this.needUpdateAnimation) { - float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; - int[] point = this.getOvershootPosition(progress); - this.baseDrawingX = point[0]; - this.baseDrawingY = point[1]; - if (progress >= 1.0f) this.needUpdateAnimation = false; + float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; + int[] point = this.getOvershootPosition(progress); + this.baseDrawingX = point[0]; + this.baseDrawingY = point[1]; + + if (!this.isAnimationDone && progress >= 1.0f) { + this.isAnimationDone = true; } int drawX = (int) (this.baseDrawingX / scale); int drawY = (int) (this.baseDrawingY / scale / scale); + GL11.glPushMatrix(); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GL11.glScalef(scale, scale, 1.0f); @@ -208,38 +208,46 @@ public void drawScreen(int par1, int par2, float par3) { this.bookImageWidth, this.bookImageHeight); - if (!this.needUpdateAnimation) this.drawButtons(par1, par2, drawX + this.bookImageWidth, drawY); + if (this.isAnimationDone) this.drawButtons(par1, par2, scale); if (pageLeft != null) pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); if (pageRight != null) pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); if (pageLeft != null) pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); if (pageRight != null) pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); + + GL11.glPopMatrix(); } /** * copy from {@link net.minecraft.client.gui.GuiScreen#drawScreen(int, int, float)} */ - public void drawButtons(int mouseX, int mouseY, int x, int y) { + public void drawButtons(int mouseX, int mouseY, float scale) { - this.buttonNextPage.xPosition = (int) (x + this.bookImageWidth * 0.8); - this.buttonPreviousPage.xPosition = (int) (x - this.bookImageWidth * 0.9); + // base on `xPos + bookImageWidth - 50`, (206 - 50) / 206 ≈ 0.757 and (206 - 24) / 206 ≈ 0.883 + this.buttonNextPage.xPosition = this.baseDrawingX + (int) (this.bookImageWidth * scale * 0.757); + this.buttonPreviousPage.xPosition = this.baseDrawingX - (int) (this.bookImageWidth * scale * 0.883); - this.buttonNextPage.yPosition = (int) (y + this.bookImageHeight * 0.85); - this.buttonPreviousPage.yPosition = (int) (y + this.bookImageHeight * 0.85); + // base on scale calculate the real y position of the bottom gui + // and base on `(this.height + this.bookImageHeight) / 2 - 28`, the default button height is 13 + // 28 / 13 ≈ 2.15, so keep the same ratio + this.buttonNextPage.yPosition = (int) (this.baseDrawingY / scale) + + (int) ((this.bookImageHeight - 13 * 2.15) * scale); + this.buttonPreviousPage.yPosition = (int) (this.baseDrawingY / scale) + + (int) ((this.bookImageHeight - 13 * 2.15) * scale); - this.buttonNextPage.drawButton(this.mc, mouseX, mouseY); - this.buttonPreviousPage.drawButton(this.mc, mouseX, mouseY); + this.buttonNextPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); + this.buttonPreviousPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); // copy from @GuiScreen.drawScreen - int k; + // int k; // for (k = 0; k < this.buttonList.size(); ++k) { // ((GuiButton) this.buttonList.get(k)).drawButton(this.mc, mouseX, mouseY); // } - for (k = 0; k < this.labelList.size(); ++k) { - ((GuiLabel) this.labelList.get(k)).func_146159_a(this.mc, mouseX, mouseY); - } + // for (k = 0; k < this.labelList.size(); ++k) { + // ((GuiLabel) this.labelList.get(k)).func_146159_a(this.mc, mouseX, mouseY); + // } } public Minecraft getMC() { diff --git a/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java b/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java new file mode 100644 index 0000000000..a0d871526c --- /dev/null +++ b/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java @@ -0,0 +1,75 @@ +package tconstruct.tools.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.opengl.GL11; + +import mantle.books.BookData; + +public class TiCTurnPageButton extends GuiButton { + + private final boolean nextPage; + private static ResourceLocation background;// = new ResourceLocation("tinker", "textures/gui/bookleft.png"); + + public TiCTurnPageButton(int par1, int par2, int par3, boolean par4, BookData data) { + super(par1, par2, par3, 23, 13, ""); + this.nextPage = par4; + background = data.leftImage; + } + + public void drawButton(Minecraft par1Minecraft, int par2, int par3) { + if (this.visible) { + boolean var4 = par2 >= this.xPosition && par3 >= this.yPosition + && par2 < this.xPosition + this.width + && par3 < this.yPosition + this.height; + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + par1Minecraft.getTextureManager().bindTexture(background); + int var5 = 0; + int var6 = 192; + + if (var4) { + var5 += 23; + } + + if (!this.nextPage) { + var6 += 13; + } + + this.drawTexturedModalRect(this.xPosition, this.yPosition, var5, var6, 23, 13); + } + } + + public void drawButtonWithScale(Minecraft par1Minecraft, int par2, int par3, float scale) { + if (this.visible) { + this.width = (int) (23 * scale); + this.height = (int) (13 * scale); + + boolean var4 = par2 >= this.xPosition && par3 >= this.yPosition + && par2 < this.xPosition + this.width + && par3 < this.yPosition + this.height; + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + par1Minecraft.getTextureManager().bindTexture(background); + int var5 = 0; + int var6 = 192; + + if (var4) { + var5 += 23; + } + + if (!this.nextPage) { + var6 += 13; + } + this.drawTexturedModalRect( + (int) (this.xPosition / scale), + (int) (this.yPosition / scale), + var5, + var6, + 23, + 13); + + } + } + +} From cf62d752eae40580078c502b61e22c4212d5afde Mon Sep 17 00:00:00 2001 From: MCTBL Date: Wed, 29 Apr 2026 11:23:10 +0800 Subject: [PATCH 04/34] fix the wrong y position --- .../java/tconstruct/tools/gui/TiCGuiManual.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 143656c9a5..002453c5ca 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -180,7 +180,7 @@ public void drawScreen(int par1, int par2, float par3) { Math.min(this.width * 0.8f / (this.bookImageWidth * 2), this.height * 0.8f / this.bookImageHeight)); float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; - int[] point = this.getOvershootPosition(progress); + int[] point = this.getOvershootPosition(progress, scale); this.baseDrawingX = point[0]; this.baseDrawingY = point[1]; @@ -189,7 +189,7 @@ public void drawScreen(int par1, int par2, float par3) { } int drawX = (int) (this.baseDrawingX / scale); - int drawY = (int) (this.baseDrawingY / scale / scale); + int drawY = (int) (this.baseDrawingY / scale); GL11.glPushMatrix(); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); @@ -230,10 +230,8 @@ public void drawButtons(int mouseX, int mouseY, float scale) { // base on scale calculate the real y position of the bottom gui // and base on `(this.height + this.bookImageHeight) / 2 - 28`, the default button height is 13 // 28 / 13 ≈ 2.15, so keep the same ratio - this.buttonNextPage.yPosition = (int) (this.baseDrawingY / scale) - + (int) ((this.bookImageHeight - 13 * 2.15) * scale); - this.buttonPreviousPage.yPosition = (int) (this.baseDrawingY / scale) - + (int) ((this.bookImageHeight - 13 * 2.15) * scale); + this.buttonNextPage.yPosition = this.baseDrawingY + (int) ((this.bookImageHeight - 13 * 2.15) * scale); + this.buttonPreviousPage.yPosition = this.baseDrawingY + (int) ((this.bookImageHeight - 13 * 2.15) * scale); this.buttonNextPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonPreviousPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); @@ -264,13 +262,12 @@ public boolean doesGuiPauseGame() { * @param progress global animation progress in [0,1], where 0 = start, 1 = end * @return the current (X, Y) point for the given progress */ - private int[] getOvershootPosition(float progress) { - + private int[] getOvershootPosition(float progress, float scale) { int endX = (this.width / 2); int startX = endX; - int endY = (this.height - this.bookImageHeight) / 2; - int startY = this.height + this.bookImageHeight; + int endY = (int) ((this.height - this.bookImageHeight * scale) / 2); + int startY = (int) (this.height + this.bookImageHeight * scale); // Clamp progress to [0,1] double t = Math.min(Math.max(progress, 0.0), 1.0); From b41cbc9b20401cdf54c11f5410b97d4d5ac356fd Mon Sep 17 00:00:00 2001 From: Pierre Zhang Date: Wed, 29 Apr 2026 01:35:21 +0800 Subject: [PATCH 05/34] Dump button, dumps the grid to linked inventory (#228) --- .../tools/gui/CraftingStationGui.java | 64 ++++++++++++++++++ .../inventory/CraftingStationContainer.java | 17 +++++ .../network/CraftingStationDumpPacket.java | 30 ++++++++ .../util/network/PacketPipeline.java | 2 + .../resources/assets/tinker/lang/en_US.lang | 1 + .../assets/tinker/textures/gui/icons.png | Bin 4785 -> 4194 bytes 6 files changed, 114 insertions(+) create mode 100644 src/main/java/tconstruct/util/network/CraftingStationDumpPacket.java diff --git a/src/main/java/tconstruct/tools/gui/CraftingStationGui.java b/src/main/java/tconstruct/tools/gui/CraftingStationGui.java index 2cb4928d16..fd7ed55eb0 100644 --- a/src/main/java/tconstruct/tools/gui/CraftingStationGui.java +++ b/src/main/java/tconstruct/tools/gui/CraftingStationGui.java @@ -4,6 +4,8 @@ import java.util.Collections; import java.util.List; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.entity.player.InventoryPlayer; @@ -21,12 +23,14 @@ import codechicken.nei.api.INEIGuiHandler; import codechicken.nei.api.TaggedInventoryArea; import cpw.mods.fml.common.Optional; +import tconstruct.TConstruct; import tconstruct.library.TConstructRegistry; import tconstruct.library.crafting.PatternBuilder; import tconstruct.library.modifier.IModifyable; import tconstruct.library.tools.ToolMaterial; import tconstruct.library.util.HarvestLevels; import tconstruct.tools.logic.CraftingStationLogic; +import tconstruct.util.network.CraftingStationDumpPacket; @Optional.Interface(iface = "codechicken.nei.api.INEIGuiHandler", modid = "NotEnoughItems") public class CraftingStationGui extends GuiContainer implements INEIGuiHandler { @@ -121,6 +125,45 @@ public void initGui() { this.craftingTextLeft = this.craftingLeft - this.guiLeft; this.descTextLeft = this.descLeft - this.guiLeft; + + // Add dump button if chest is connected + this.buttonList.clear(); + if (logic.chest != null) { + int bothOffset = 0; + if (logic.slotCount > 54) bothOffset += 12; + bothOffset += 122; + this.buttonList.add(new GuiButtonDump(0, this.guiLeft + bothOffset + 161, this.guiTop + 5)); + } + } + + @Override + protected void actionPerformed(GuiButton button) { + if (button.id == 0 && logic.chest != null) { + TConstruct.packetPipeline.sendToServer(new CraftingStationDumpPacket()); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawScreen(mouseX, mouseY, partialTicks); + drawDumpButtonTooltip(mouseX, mouseY); + } + + private void drawDumpButtonTooltip(int mouseX, int mouseY) { + for (Object obj : this.buttonList) { + if (obj instanceof GuiButtonDump) { + GuiButtonDump button = (GuiButtonDump) obj; + if (button.func_146115_a()) { + this.drawHoveringText( + Collections.singletonList( + StatCollector.translateToLocal("craftingstation.dump_button.tooltip")), + mouseX, + mouseY, + this.fontRendererObj); + return; + } + } + } } @Override @@ -523,6 +566,27 @@ protected void drawChestSlots(int xPos, int yPos) { } } + private static class GuiButtonDump extends GuiButton { + + private GuiButtonDump(int id, int x, int y) { + super(id, x, y, 10, 10, ""); + } + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + if (this.visible) { + this.field_146123_n = mouseX >= this.xPosition && mouseY >= this.yPosition + && mouseX < this.xPosition + this.width + && mouseY < this.yPosition + this.height; + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + mc.getTextureManager().bindTexture(CraftingStationGui.icons); + int v = this.field_146123_n ? 213 : 223; + drawTexturedModalRect(this.xPosition, this.yPosition, 0, v, this.width, this.height); + } + } + } + /* * Hide the deprecated stuff at the bottom */ diff --git a/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java b/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java index 0189cc04ff..d774dcdc88 100644 --- a/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java +++ b/src/main/java/tconstruct/tools/inventory/CraftingStationContainer.java @@ -434,4 +434,21 @@ protected boolean mergeItemStackMove(@Nonnull ItemStack stack, int startIndex, i return didSomething; } + + // Dump crafting grid to connected chests + public void dumpCraftingGrid() { + if (logic.slotCount == 0) return; + + // 46 is the first slot index of the attached inventory + for (int i = 0; i < 9; i++) { + ItemStack stack = craftMatrix.getStackInSlot(i); + if (stack != null && stack.stackSize > 0) { + if (mergeItemStack(stack, 46, 46 + logic.slotCount, false)) { + craftMatrix.setInventorySlotContents(i, stack.stackSize > 0 ? stack : null); + } + } + } + + this.onCraftMatrixChanged(this.craftMatrix); + } } diff --git a/src/main/java/tconstruct/util/network/CraftingStationDumpPacket.java b/src/main/java/tconstruct/util/network/CraftingStationDumpPacket.java new file mode 100644 index 0000000000..bfd174ed23 --- /dev/null +++ b/src/main/java/tconstruct/util/network/CraftingStationDumpPacket.java @@ -0,0 +1,30 @@ +package tconstruct.util.network; + +import net.minecraft.entity.player.EntityPlayer; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import mantle.common.network.AbstractPacket; +import tconstruct.tools.inventory.CraftingStationContainer; + +public class CraftingStationDumpPacket extends AbstractPacket { + + public CraftingStationDumpPacket() {} + + @Override + public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {} + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {} + + @Override + public void handleClientSide(EntityPlayer player) {} + + @Override + public void handleServerSide(EntityPlayer player) { + if (player.openContainer instanceof CraftingStationContainer) { + CraftingStationContainer container = (CraftingStationContainer) player.openContainer; + container.dumpCraftingGrid(); + } + } +} diff --git a/src/main/java/tconstruct/util/network/PacketPipeline.java b/src/main/java/tconstruct/util/network/PacketPipeline.java index 1a40fed80e..454f19da21 100644 --- a/src/main/java/tconstruct/util/network/PacketPipeline.java +++ b/src/main/java/tconstruct/util/network/PacketPipeline.java @@ -135,6 +135,8 @@ public void registerPackets() { registerPacket(MovementUpdatePacket.class); registerPacket(ArmourGuiSyncPacket.class); + + registerPacket(CraftingStationDumpPacket.class); } // Method to call from FMLPostInitializationEvent diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index 488991e99f..63cc3221bb 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -859,6 +859,7 @@ smeltery.brick.tooltip2=(Safe for decoration) smeltery.castingtable.tooltip=Basic Smeltery equipment smeltery.castingfaucet.tooltip=This Smeltery is leaking smeltery.castingbasin.tooltip=For the ambitious Smeltery +craftingstation.dump_button.tooltip=Dump grid content to linked inventory #Dear translators, only translate these lines if the jokes are applicable in your language. grout.tooltip=I am Grout! frypankill.tooltip=This poor animal met its demise with a loud *bang* diff --git a/src/main/resources/assets/tinker/textures/gui/icons.png b/src/main/resources/assets/tinker/textures/gui/icons.png index 5ef7415c13c80b48221310d77fd29ddebc7c4542..300b4d611c55e59822c81097461e1c4715e27133 100644 GIT binary patch literal 4194 zcmd5;`9IX(_rJ5)vTs?llp-NZ4I(p^!PsI@MAi{9mJHcqhO&gn5(?R~WLK8RzEr$X zVoJ7>hz41rvCMaRf4<*ezW>1YdmfMbIM3%f=bn2X=brm|-FxO{2JASDjzeU2NPxHXMI@XLs?DxWs-Fcb6g z@i47Rw9uofgcogtQYs}J8F~=8XB6HmseL;S5{W0dYX$*k2p3qR#;dV z<915WB5QDP(A7xP(NHAdiljYS7^TQ_RZj?_5`$6YCtQ(u{rYvFjU>)QR7Z)&8!PT> zCBC(_WveTco}T{c)2GG7MZ{@NdJ&kIm{e3$#06L`T(~eiJnVm2;=_jzuEwG*EiEM_ zCFpa!BofKjQk+FxL;konKROC${J>1(sIYBmq*IHe-#an4b}?M*1N?}HUBz(%xg=~g zAt6CkRh34|@9*!Qo0}szsC!zem|Q${+eItyuIWNcP;IhpTb4^x+O;ojk*odjKf0m| zqp+A|vV8`Cjf&CJwhEr4 z61NPl~+lQEo|ut9>gRmRamw9`Qsx zMuVhyIRv}mqYoygezNIW`Ym8sZq{E&Bf}BVF3%B>sFQO$ zgUZjP)b9Z@GTS&79t!-ve!~ndFSrX`g@!P8rN7^}f9^_5$sYuINU9{o$Q>8^d;1Ld zh=0O48=*CLogif9U_gOe5wvz&c4GHlUQ%^HMMam z^Q;id{%?K<3Gqz0%?6o3KPWMD#i|C(919&x%G7aaT*jU-*c zWtyj+lrNwH4Lrw zE~#q9&pyu1UKuf4|M{umsAQ7$W48nOpe$>o@R)1JDYd>| zmaStITraZ6qBqOkAOmXg1&kR+3)l+ki|y@GB=!PYcXZIqD?g=oa(BwsB79a&(Zw#`nTf z-)jg^yQ0d=MeP&1$Sc^gZ#X!R!AIbnD5d^$_uA)H?@6OC6=>V6SoZO$?~JV25~kp3=LrQ@FL4 z{i+3zn1zo{_68Q_@qTRHuy|8Ut9T6mbUp*sq2MKKq5i;Cawp16VIgAayA)9hx?(5F2k@ko!?QMXWLfVE3YSa33lb_UZ zS`;zz%74+UT%N{TO^a#goEx(`Qcm7z7;4URR>3~1pYz);&p6DV?i)a8J-_ulE!M&Q zd1Z&RdiIEJ9sT!cv88$pRd4J4o%a41l6#k8X-XU|svX)O^Fi6d8@Uf%8mnSQ;-%XX z9}mB?&2X&ulB<}k%X0s|JwQ%6PE*m)32Z{d(@HKsS`xz~lQTKW*LYsi7l92L|LD<=MwDOkE+J*19sL(QvoP|fXHnkGv zpB-MeZ&EA|>syE_!55fnVbF0wug~@i{KHjL6|&QCOcYYV&Kapl%j}j|*BXc59(kq? zIdpTu<*4I@cj}%OAiZwZ&0i4Sf$%|^eCCT!uF;HDjVF4z#b<@Y3E6sh0<56(fX$m*uSM2(wB&R6Q7u6RXK~vwGjFP0(d2p zuH{wF#u*a!e~(-T8IdRg7s(K~@iB~AC;9zM;CjX~z06EPa0SN*TAYI{+vtaY6)HOSIby5aA85nG~o^gz+fOWaFZfB@NEXJIcdon2U2CG`|+sQCM zWdd^ZKu>DvE`}>C^?Xovrj=RLg1?^Gvdanh=pgIKKU%2PpZ?cZ=($|l$9jK`L266aO!>Fu;H8(? zq2S}Hc8-u?sbr_dMZ-21o$%uz-}hrd(3+yf`Q>C;L+xNq$TzY4O2Q|(*=olsCh&4} zt(UUrGI+ycMci5{($8r3PnnJt;&t+9jn&=JB;GBJCju&7oy;yPhL_EpDuk8{WNS0y zhMMp|;+D~aN|cjq5vnaBj@VX!XA~xJY{vqLY7@_#l9{vGuf{5oU1K-A0#*i2k3bX4HLKZVUCckrz{ z17=GVDO5ipRWPzwGc(~h!$~Sp^(UzvXpy>p5-Z^nKBauW^ntzP{ffwkyi1&b?GiCH z_L1`aM*f)EdJplM928APEGE_am*h+%9oytF?qS7>LjP70?t~k(t`P!M(L$JM&y+1Y z8#wf6gjviNJC-v;s6%35D4l^AVwcT#5Vtop^E-$Q%(os+bnrA-D{Eik6{`+Pd>B!F zoUe3t-Q6-jth4z?CInT~Ujj>}D2_s-N7Vd8J|)YFk@BzpSv5y$&32E0x3Hq_Z7(p0eB9)@Zvu z&`G7<r_*sfUz+NQ&T)>c<9%W{fM)s$_J$p|~7!%W-x z7L4D{D!ChWc#vQCde*_wZkDa4`fzdL8}#G!L1*a6FdWY|*M8ctfvx8e~ol+EzA->s~ zY^8S4E=iDH4RDIDQYdT4&@Eg?)hwPiUCccPezz0%gD(Yl9;Qhne;TahX+pI~YdcX1 z2jcWMCsjI$G+){|VXeYGqks;4BnO@T0BbLbV*YzfBtZWXpy|2n9{!98dW> zwHpr9`oI%2by8^&e9mBst>DMkjNb2$_&Y5-?z53#AMEd_;a#&@_t;**po*s?*M)(o z$wkr~Pewnkr=LByN!*`Vu*_{7V5C&EbMrLQ`jju6q(e%Tc*W=`t#%*iSLqP)t(Dmj zSI705LSiKEvyyI9{kE)nYe(rzxJp64pf>nyvie+`Oq3!`O8Ry%Qfh}g_FcGQy>BpP zpO|rAq?C1ad|*cLf%R92Z0NnC~LE zCH=NiiHq%{h7Vx4$b4hQURRWFq-%j;Z=;8OJ_~46f&`zmO4t>+uN%h%>K*h74`3#8 zz~eBD5LL=8)XZshr|jr(xQxzJ7Od8E+=*AOotbnZh0)>iyg%vdSN#LsUy&7D0dhKR zt2Oluq#Le`>l+JaQW%BXrF$Wyr+O$~us-^hbCMxSN-!AV=s;k0%C3-SVVoJcHn$`r zj4HEF<>YdkZYmXK;O=QnBa$~)RL<;mDK$4;~1s}rCH^uxO29zkq zc7cjNpG;qCe7A6DS_Ge-UVj5IfOegE!Xlg^BB^U564a&pNtm3JeCJ}sVBbGA+T;EE z!feBkD#bXc;{GvWYOd41^O9nh^OA@Cr8}0abM95C&b8&2(RJU@=4yY+FF(8Gu96C3 ers;j2weeeI;hrg;`+0&FpbG|VrdO@w6!l-yu!8yk literal 4785 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 Date: Wed, 29 Apr 2026 18:03:16 +0800 Subject: [PATCH 06/34] let buttons will render while during animation --- src/main/java/tconstruct/tools/gui/TiCGuiManual.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 002453c5ca..9e781bc319 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -66,7 +66,6 @@ public TiCGuiManual(ItemStack stack, BookData data) { bookRight = data.rightImage; this.bData = data; this.guiOpenTime = System.currentTimeMillis(); - this.isAnimationDone = false; // renderitem.renderInFrame = true; } @@ -184,10 +183,6 @@ public void drawScreen(int par1, int par2, float par3) { this.baseDrawingX = point[0]; this.baseDrawingY = point[1]; - if (!this.isAnimationDone && progress >= 1.0f) { - this.isAnimationDone = true; - } - int drawX = (int) (this.baseDrawingX / scale); int drawY = (int) (this.baseDrawingY / scale); @@ -208,7 +203,7 @@ public void drawScreen(int par1, int par2, float par3) { this.bookImageWidth, this.bookImageHeight); - if (this.isAnimationDone) this.drawButtons(par1, par2, scale); + this.drawButtons(par1, par2, scale); if (pageLeft != null) pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); if (pageRight != null) pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); From e1017ec32791b2bf31a79f1dc048faafc70ca3a1 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Thu, 30 Apr 2026 12:06:06 +0800 Subject: [PATCH 07/34] prevent calc position every time after finish --- src/main/java/tconstruct/tools/gui/TiCGuiManual.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 9e781bc319..4b2ef3e856 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -66,6 +66,7 @@ public TiCGuiManual(ItemStack stack, BookData data) { bookRight = data.rightImage; this.bData = data; this.guiOpenTime = System.currentTimeMillis(); + this.isAnimationDone = false; // renderitem.renderInFrame = true; } @@ -178,10 +179,13 @@ public void drawScreen(int par1, int par2, float par3) { 1.0f, Math.min(this.width * 0.8f / (this.bookImageWidth * 2), this.height * 0.8f / this.bookImageHeight)); - float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; - int[] point = this.getOvershootPosition(progress, scale); - this.baseDrawingX = point[0]; - this.baseDrawingY = point[1]; + if (!this.isAnimationDone) { + float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; + int[] point = this.getOvershootPosition(progress, scale); + this.baseDrawingX = point[0]; + this.baseDrawingY = point[1]; + if (progress >= 1) this.isAnimationDone = true; + } int drawX = (int) (this.baseDrawingX / scale); int drawY = (int) (this.baseDrawingY / scale); From b45b097446bc6a3a3bb8a143264627af67395080 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Fri, 1 May 2026 11:55:31 +0800 Subject: [PATCH 08/34] add a button to quickly back to home page like higher version --- .../tconstruct/tools/gui/TiCGuiManual.java | 50 +++++++--- .../tools/gui/TiCTurnPageButton.java | 86 +++++++++--------- .../assets/tinker/textures/gui/bookleft.png | Bin 0 -> 24256 bytes .../assets/tinker/textures/gui/bookright.png | Bin 0 -> 8536 bytes 4 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 src/main/resources/assets/tinker/textures/gui/bookleft.png create mode 100644 src/main/resources/assets/tinker/textures/gui/bookright.png diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java index 4b2ef3e856..9a7efa5e15 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/tools/gui/TiCGuiManual.java @@ -20,6 +20,7 @@ import mantle.client.gui.GuiManual; import mantle.client.pages.BookPage; import tconstruct.TConstruct; +import tconstruct.tools.gui.TiCTurnPageButton.ButtonType; @SideOnly(Side.CLIENT) public class TiCGuiManual extends GuiManual { @@ -28,6 +29,7 @@ public class TiCGuiManual extends GuiManual { private static final double FLYIN_DURATION = 0.55; // portion for fly-in private static final double OVERSHOOT_DURATION = 0.1; // portion for overshoot private static final double EXTENT = 0.02; // overshoot amount as fraction of total displacement + private static final float GUIMAXPERCENTAGE = 0.75f; // The maximum percentage that the manual GUI can occupy ItemStack itemstackBook; Document manual; @@ -43,8 +45,9 @@ public class TiCGuiManual extends GuiManual { private TiCTurnPageButton buttonNextPage; private TiCTurnPageButton buttonPreviousPage; - private static ResourceLocation bookRight;// = new ResourceLocation("mantle", "textures/gui/bookright.png"); - private static ResourceLocation bookLeft;// = new ResourceLocation("mantle", "textures/gui/bookleft.png"); + private TiCTurnPageButton buttonHomePage; + private static final ResourceLocation bookRight = new ResourceLocation("tinker", "textures/gui/bookright.png"); + private static final ResourceLocation bookLeft = new ResourceLocation("tinker", "textures/gui/bookleft.png"); private long guiOpenTime; @@ -62,8 +65,6 @@ public TiCGuiManual(ItemStack stack, BookData data) { currentPage = 0; // Stack page manual = data.getDoc(); if (data.font != null) this.fonts = data.font; - bookLeft = data.leftImage; - bookRight = data.rightImage; this.bData = data; this.guiOpenTime = System.currentTimeMillis(); this.isAnimationDone = false; @@ -77,25 +78,31 @@ public TiCGuiManual(ItemStack stack, BookData data) { * this.initGui(); } */ - @SuppressWarnings("unchecked") public void initGui() { maxPages = manual.getElementsByTagName("page").getLength(); ticUpdateText(); - int xPos = this.width / 2; // TODO Width? - // TODO buttonList + int xPos = this.width / 2; this.buttonList.add( this.buttonNextPage = new TiCTurnPageButton( 1, xPos + bookImageWidth - 50, (this.height + this.bookImageHeight) / 2 - 28, - true, + ButtonType.nextPage, bData)); this.buttonList.add( this.buttonPreviousPage = new TiCTurnPageButton( 2, xPos - bookImageWidth + 24, (this.height + this.bookImageHeight) / 2 - 28, - false, + ButtonType.previousPage, + bData)); + + this.buttonList.add( + this.buttonHomePage = new TiCTurnPageButton( + 3, + xPos - bookImageWidth - 24, + this.height - this.bookImageHeight, + ButtonType.homePage, bData)); updateButtonVisibility(); } @@ -103,6 +110,7 @@ public void initGui() { private void updateButtonVisibility() { buttonPreviousPage.visible = currentPage > 0; buttonNextPage.visible = currentPage < maxPages - 2; + buttonHomePage.visible = currentPage != 0; } protected void actionPerformed(GuiButton button) { @@ -168,6 +176,9 @@ private void changePage(int buttonId) { if (buttonId == 2) { currentPage -= 2; } + if (buttonId == 3) { + currentPage = 0; + } } public void drawScreen(int par1, int par2, float par3) { @@ -176,8 +187,10 @@ public void drawScreen(int par1, int par2, float par3) { // int localHeight = ((this.height - this.bookImageHeight) / 2); float scale = Math.max( - 1.0f, - Math.min(this.width * 0.8f / (this.bookImageWidth * 2), this.height * 0.8f / this.bookImageHeight)); + 0.95f, + Math.min( + this.width * GUIMAXPERCENTAGE / (this.bookImageWidth * 2), + this.height * GUIMAXPERCENTAGE / this.bookImageHeight)); if (!this.isAnimationDone) { float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; @@ -223,17 +236,24 @@ public void drawScreen(int par1, int par2, float par3) { public void drawButtons(int mouseX, int mouseY, float scale) { // base on `xPos + bookImageWidth - 50`, (206 - 50) / 206 ≈ 0.757 and (206 - 24) / 206 ≈ 0.883 - this.buttonNextPage.xPosition = this.baseDrawingX + (int) (this.bookImageWidth * scale * 0.757); - this.buttonPreviousPage.xPosition = this.baseDrawingX - (int) (this.bookImageWidth * scale * 0.883); + this.buttonNextPage.xPosition = this.baseDrawingX + (int) (this.bookImageWidth * scale * 0.8f); + this.buttonPreviousPage.xPosition = this.baseDrawingX - (int) (this.bookImageWidth * scale * 0.883f); + this.buttonHomePage.xPosition = this.baseDrawingX + - (int) ((this.bookImageWidth + TiCTurnPageButton.ButtonType.homePage.textureWidth * 1.15f) * scale); // base on scale calculate the real y position of the bottom gui // and base on `(this.height + this.bookImageHeight) / 2 - 28`, the default button height is 13 // 28 / 13 ≈ 2.15, so keep the same ratio - this.buttonNextPage.yPosition = this.baseDrawingY + (int) ((this.bookImageHeight - 13 * 2.15) * scale); - this.buttonPreviousPage.yPosition = this.baseDrawingY + (int) ((this.bookImageHeight - 13 * 2.15) * scale); + int yPosition = this.baseDrawingY + + (int) ((this.bookImageHeight - TiCTurnPageButton.ButtonType.nextPage.textureHeight * 2.747f) * scale); + this.buttonNextPage.yPosition = yPosition; + this.buttonPreviousPage.yPosition = yPosition; + this.buttonHomePage.yPosition = this.baseDrawingY + + (int) (TiCTurnPageButton.ButtonType.homePage.textureHeight * 0.5f); this.buttonNextPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonPreviousPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); + this.buttonHomePage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); // copy from @GuiScreen.drawScreen // int k; diff --git a/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java b/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java index a0d871526c..1a95063826 100644 --- a/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java +++ b/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java @@ -10,65 +10,67 @@ public class TiCTurnPageButton extends GuiButton { - private final boolean nextPage; - private static ResourceLocation background;// = new ResourceLocation("tinker", "textures/gui/bookleft.png"); + enum ButtonType { + + nextPage(0, 194, 18, 10), + previousPage(0, 204, 18, 10), + homePage(0, 178, 14, 16); + + int textureX; + int textureY; + int textureWidth; + int textureHeight; + + ButtonType(int textureX, int textureY, int textureWidth, int textureHeight) { + this.textureX = textureX; + this.textureY = textureY; + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + } - public TiCTurnPageButton(int par1, int par2, int par3, boolean par4, BookData data) { - super(par1, par2, par3, 23, 13, ""); - this.nextPage = par4; - background = data.leftImage; } - public void drawButton(Minecraft par1Minecraft, int par2, int par3) { - if (this.visible) { - boolean var4 = par2 >= this.xPosition && par3 >= this.yPosition - && par2 < this.xPosition + this.width - && par3 < this.yPosition + this.height; - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - par1Minecraft.getTextureManager().bindTexture(background); - int var5 = 0; - int var6 = 192; + public static int ARROWCOLOR = 0xFFFFD3; + public static int ARROWCOLORHOVER = 0xFF541C; - if (var4) { - var5 += 23; - } + private final ButtonType buttonType; + private static final ResourceLocation background = new ResourceLocation("tinker", "textures/gui/bookleft.png"); - if (!this.nextPage) { - var6 += 13; - } + public TiCTurnPageButton(int id, int xPosition, int yPosition, ButtonType buttonType, BookData data) { + super(id, xPosition, yPosition, buttonType.textureWidth, buttonType.textureHeight, ""); + this.buttonType = buttonType; + } - this.drawTexturedModalRect(this.xPosition, this.yPosition, var5, var6, 23, 13); - } + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + this.drawButtonWithScale(mc, mouseX, mouseY, 1.0f); } - public void drawButtonWithScale(Minecraft par1Minecraft, int par2, int par3, float scale) { + public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scale) { if (this.visible) { - this.width = (int) (23 * scale); - this.height = (int) (13 * scale); + this.width = (int) (this.buttonType.textureWidth * scale); + this.height = (int) (this.buttonType.textureHeight * scale); - boolean var4 = par2 >= this.xPosition && par3 >= this.yPosition - && par2 < this.xPosition + this.width - && par3 < this.yPosition + this.height; - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - par1Minecraft.getTextureManager().bindTexture(background); - int var5 = 0; - int var6 = 192; + boolean isMouseInButton = mouseX >= this.xPosition && mouseY >= this.yPosition + && mouseX < this.xPosition + this.width + && mouseY < this.yPosition + this.height; - if (var4) { - var5 += 23; - } + mc.getTextureManager().bindTexture(background); - if (!this.nextPage) { - var6 += 13; + if (isMouseInButton) { + GL11.glColor4f(255f / 255, 84f / 255, 28f / 255, 1.0F); + } else { + GL11.glColor4f(255f / 255, 255f / 255, 221f / 255, 1.0F); } + this.drawTexturedModalRect( (int) (this.xPosition / scale), (int) (this.yPosition / scale), - var5, - var6, - 23, - 13); + this.buttonType.textureX, + this.buttonType.textureY, + this.buttonType.textureWidth, + this.buttonType.textureHeight); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); } } diff --git a/src/main/resources/assets/tinker/textures/gui/bookleft.png b/src/main/resources/assets/tinker/textures/gui/bookleft.png new file mode 100644 index 0000000000000000000000000000000000000000..858cd70b93cc364d90460d6dae892a8a066bf095 GIT binary patch literal 24256 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

HLY@|fm6?}E|EC1)tLD!8IMC{$ zF?!VpI&iGi)#Ix(4x&TAy`e?~H==?WXoLZ}fkqnof4VbM^?P(t#_=!s?x#!VFPImJ zHnsJx_SnJa>t3g;g(J6_1_fZ=j1UrNPvSw##ovtp?yKRfjxSmcy z(FF|Oj5=gZE-=?>ChhhxnnXG0{lYgPk=*=IPcw^ zM+7+!VT;p^=MI%W!&URhC_9CdCrJYuF>C2ph&McN#ZKI|pMX6gI?MNiVofm$T-mRW zVjjlWO#tT_jh!Yz-ue3;V&?q=Rp=%UCn)lFG9^;dCCeVqb~kXWyW)!K&L2 z)5{cHwliR1uxi&1aqxl`aoWy6$98x+-i@jyi|J-$d>dKpclZ zujGdN`!olhgUOosKk4;+ci>dMgUy{`QIwk1`CqMPY0T0tHg_Ei$lE}?YDMewNJ+s7 z#+8L8m=KMdT7&2IUh6h~8Zw?$N%`|eI%lDTs(W!)-&&uN0RvmnRBR!uV0MmWqsO~5 z!lS%2=Hky3qQDJX*V*t{Xjc;~$cveD+%B?dO+oQBL-F*45g&9y?0R|XQbnbip=vd( zz0su>3ZxLvivt%=Fa zDku_ZQft56P#uA{o&cPmt>>h%1^ixFU0D8Xd-VF1sw+(RY%1u$ulgKfu~3_DR-sI` zNvv8IbxD`@gv@@8tg>`M)3+O&V!pEY{l%It2ewd6yR5g^vufF6x@us-@0(MwM0b*r zl8lCkGScVqG1e2OqpVcix8)tiCd04@0x#y~YSZfK`wpr)gPt%S_ z@I3(f4Iz3R8X*N50L>iK+>G>vet!oFe@Ye_V`tRT{S2UH0v*B$Lrp8P(gXJjj7+Z_ zVH2&^0B3&cvM8M?cA~_^%k$YYDy2SnLMi;wt}1CIV1$Du$wrkNmqoijFw?&OLGLle zf#VauPhCENvNQeE^Fh|0D)n{Xp^(l4Ofm*>z?`P)h{s4ET!pvbJ-(3E8S?q-BW3s3 zo*_@jX;hx&Zw_x{43ktEYa{psr?%GxLc^5DpT@M1v5CJ=Ukyt8(?^r`;@+WhC3t)o z-Gd$5l)&b179~4xE{6d8zHxKs9D?W6(41vtt>oV08vTYl9MUKG67wUJTZy?7;pj<1 zk%t^IQE2+PYgD35?EUcJT_6kpR?VYDEGR2wKUzMI`m?(I5r#Z)9Vf!bFo9BVj@;`a z&TkfRm}@67OlfeLS-FXRrbLlI9^UV4S|zxFd2>8-18SzG49&8Qk|-S}Z?sp_0C`In zlL70s_sHKyT;ELnLb;SLs``#d;{qPmHYgrY^cACYP5q_jJPHudej|Kt-m+GcY01uw*^l8b276Y>{Bgj2uo*NFQ+asz{98l6Z+^T=LX4RKBhOIq455U> z+-OS(JdP!(CVIrb+@I%Y>|u8#argAk59;G58lHy)k4u)gzkBNVnga}7|;4lAOGE{Rd z@qVvxsT_QQ`$1lPK|37jA-ZnQ2MMhAcZRpNtL8Irl`s;#7fkZ!E|K;N~ z8V`7e&PNh`P0cMD8k*M={g3Bi!gjl%o5?AH-eLycZx5ZXV=cGE;)v=Mv*oA1YTsbC z)Ld(G35vsz$uqOC8T6`V3JedfW~(8k^`C^Ovux?hm5Xi%@$Jb1IJjQMS*C0l!bp4f zKHh(9=M-avO}F|8hCHaRqn<~DiFAAdw7A7hcDhs^&Jcfergt6WqPiiW_`XL0YPP^H z2Xgp1{$O^?vDD33z#Ej}{*!RfLdJoJBAEsX zNPK~gHbfP*Xx19+fKcq8hX2l-9E%NRsQ1$4e_`vlamyM@m<9uok(Dtp9=jEukG+HM z5DcEs6Y_4zKIJ&tLVqctm_ZhH+4i_E=3!&-^2h@@i9a2lMkA$+H|EJ|>}-rS=8K+J zMEMzF?(9$!3FmyM#yMPO;mefFo3z3S;N}DQd7Aq# zGIIudPa8dp^$}m5H=tKw768!J8_iYk7-z8NYH@S2l#;MQduL>J%E6@UgbF!BDQb(C zC?A*lTeH`qSst5$jpoS4)7rASvs*z1+XDOCMCm-r2W!}ls~rAWa6c5VemT(y^D`i2 zc7EHjDAf#IMPuXXDCDp*MfI#}-vuM$)YF7clVJzgAC8v=zda-!P;mcV)#%$F#4|I~ zA2{{d4iReI0tobe3Fhozdj}7WjC9bg%0Rv0CBR?dscbbw_T`R2EQ&=vdC3_(|4DpY za$o}x`NO%Jt?!a8g)hJ{G10kf403Se*1d_j5`S38u2t1gFe&BHVdnZSPQdHBC3!t> zC$%Fx_Q=kx7IxQE<{1{xO6-le*cJ$}$dsIvz+ln__19#d`ANVB@>uuUR2G21SbG1u zq*NQQ*(0o#qF**TQF2r-{S)tE1WThV)1U8k$;%rS71?USvg6#8zYJltTr10T)38@=7ce-LJMqWBu}qu zMWtxd_yQ^U1;0>DziqcIcXOhk#&pw--qrK3K*j0rmEvnR4Uf@||6ai??l&xumMYFS zNR4O=ndBNy!0V&qvnotY<2U1uWt^n`)YBv@6IB^yy&d101?jXn_R!V;TuhO=*G<@X z!UR8j`X-uOyq!?=>b$ccJcW2C`I{oo?$SAqqCvneE8VGc3X0g{sYnXtE4}4lSOr1X z4|^??Is7#0%WCB~d;-vs}7D1Ons`tA$6@}u`H zMNnZ??Td~h97@U)eQRX*+J-gKeC_OyqYJepbx2bZO{O%|5NA_k>964Bu*^o5F~FZL z5%|g1b2_aJvx(d{8yR`@)5%EVO9yjoGf|ezCBJ0L2lS=+ltG6-kQ>+1=%c7RVWu~i z0Y)UauBpjC%cIWp313cVFVBvct0HG$myr(a8ht#Sl5DKhWAUivLhX4iQ7&AaUSE}+ zwZub0*Mq|H2s`EJ4*aHwV(FS>pi5GGokW!aiTygs6sw)O&Cbg-G+;JSBvJ9p`yQFY z`!l}dZfxHd)jBP#hMWahn@=u(LKX73*y0gQqa9t>yNR1hW_Pp;=b|(8WJfQYmZUHEhtDc zO6YY`Ov!+&{?4+)Fh6GHaE2aP=kD*2PFq`3h!J{hwG8r2+THJUQHj1_C&{TN1z5nQ z!{_tpcX;|7x9|JwpBF?hXG$<@`I#=r$=_HRpIsvULZ8N!q0kh!Tb{aT_v~u0*4F=n zs_sI}`z_Boo8NO$)G4at)BCn^z!6k#y*v@9}M7SKjWbe~VT0^zqb{v!1t=_vT)TtgkS7SL(TypQ8 z<*~{ijYyS&(8A*}7qci;yl|?P^GXWM3yvIOam`I~-Z-ws63Fcd80^wWuRN-(CkwaNqEY!`e3`U6A{=wzkSdXn|E@SvH+T2Q)b8r**ISBB{! zF3#Z#NY<0+5^$XYbdvc9b4}7SPtzETDnA*&rhY=TtNSfUm-})^B0-~CDk#x_u5oeC$p1AE6l3aDLvUYrM+fNw zXfs7}OkR-NA~S4(KXS^us9qW)>_<9M!a4vG=!G4 zczZ>LeWLs@$4VI)O|I5?2ONZ_t^60OMEe14WO5`EtJkeJAlHx7j?=A6`{yX9S zEKyIR<;V&J9TizQc+(UDo@G-0MR@6X8T|>$XVSINTXY;yQcYfd+*@ZAUan@%C79eYjMmNc}FZB%H| zTa*&aBAZ2Euzzegg^czxk$YxF!qB`WM4Dc?9#zfnn?qRnA$3s5`60lm#=At7folvUs8(Q3I_o)#awfctDL12WeeA1iiMKq$*UH%wwf% zDkPfUxY#(a#Z=Y4*UHn;8UE! zROHmj7f!Bd4t+mM%m|a*^@>tuQr_iIorN-JRNFV;rw;6wv9Z33*Zb5fnyx4E+7@*G z>qp|9zm8J!*tXWE#V+`Gfg^|{vuUO;A??;(Lq9of~b-1z;mIL?Jd^oXaW|TZslG18I zsLysj()iqO@_i`Lfav1wMuP!}XA%)Lt+cD#F=xNZR?}Y*k<*~NsW=OGKiTl7zB$hu zvP&N!*MdTTiQ5V)jykN)mIvR-nesF_NBK>IA^O&(xb2hSx_`4_&5GuATXakd0cX8;DEP{;+)A&9wBTw$fzmeaiu-F` zB#!YexS=66HTCJw4|B)k`SJw$AmZ0?(w5gClPw8~^6W5le+o>n$EpYzs(%ga6#nlFHP@7xp@h%OHHAP5BZ?Q0aiZsFW_Rym(- zu=e`{hE4s~j;^SYa^J^pHpK=EFO`(xI#-}!RIOe6aVho*ZoxL;w_r8F_{$K z&T=97XE?KHQ~fLzb74>d#iQ@sTnosVqqeaWMWks9l;DpP;Kh`WWSX3bs2zgnPxi^| z;Nu7=cSFEm?f_T5GI9B_?uc(ijWub)h-#8f^nhDGe_ z?A!;%Kcm>w7jinfx_jE%+G%NN0aMwLeDO&6J&yvCfQ})EZM7NYQn`d7V*f1rq4vB$ z{z)FU-;dsVKW`?vuZf;tv9De+^apxY_>9`QeWnh+^Iy}W`d$rS*G3?SW>UT=VwZt; zZ*P;77^8J`(woIh@jk3JRUzVG?i6do?aLAL)>BTE*RjMA4zBW2PItVU(Y_BZML*g& z!?`#yeHwhW*5Go74!d~LarWM~>y>UsCwPAnkFHC;$Q}UI+yVvOV?x0I2YUYS?8H14 z!5xp)A7y_0w@(agNCvgWB6_`er&z2=1|V$%ya{9>e(zY|brXrt0q!|6pzDTaSOa)t zOTbPYQ71h|O|1JZRN{<-Q2~BOH9Lom+ORtisc(U-LsGFWe{e)fkjBlL&9eZDU5PNl z`d;o44C8Xf4Qsvg!5rj`^`<$Z@hQSI_-2nqwhmwh|H)^>2WTWUO*vkHqU+L$cpK_V z?3liU|8zHv_)b|H4j)KE1zvuwS>-QXkRpNyCmD6)XkZ2o`j7o0;y%N|F~$)=Ys2Gr zojyT9&m2MpfJ-srASQ)GobMIcW*;MISO5O1J)2NSB@~6;=P#T0CJW~Cl6~{qPsg4& z$0nOasWoRYWN5?Ky}L^$0BaXf?NW4v4hS|3pSMk$9gult9GpHY(H(2<-QE6@J*Bza zBT^b9pl8m)aCXsBFttOoZ;JQkM+_ltVK#$8#dN4F)XjDF=m#Be{{pO5C=#^H!kWH_ zk|IWgj&#$#g$-cbXMzkEtL)Q!!`ecbqPxnCy@1o&VD)ZdJy2@dc8pLt!?AroDb*+D z?d24|2&{&wB{M0y3Y~H(tK38QkR+J#RksSJM&wPfKKL?GEhj&p|S-e{qP|ork8WZ3OFHVqo z3@|WIBxVgKMB;dRH8tMaWFlzYVTA5j5K6ROrZ$(5`i2Gma-3d8y4DDRbtmu*OCzaB z^xNx?0Ml6m9TzI(w`jxDclv{}R<3dz!W6<3BKxTdYdh&y$b?SkB5}I6c$;T0R}6Kw zrs$FJ%-VL4W0eMTqKjr{Ks%imRObJwkr!p#LMJ#lqOc6799}Wu$J4Cu>ueqr@=<~a zW=xJ4#akAu%`=Ie4)UjH$Kzu40rk3dyt}ai#Z_1ri5dBoo6R7k9YQ3di%-f?cO~#{ z!Yn8lC+~SRDNvI*(EjT+62F)60qz%1^1Lj{umwO9Iq~ZSm{#5*{8RTx(HYVHHH-|fsx;grbDTT|_hwSX;0#=U^`|Tg$Zu%si?wE_R@_ECbJ6o$HX0Fp+PH)rEjo!2| z*$JmMwvzlkTc|7XLJQSVqiBqRXIn%iFANV2ak)GMjMj$@L1~UZe2`R0c(5s@-vL~n+~M*y-uKb{kiWWQ+)4_j{&>Q zvGx2^{)E{Z@}rl228bbcF@?@w9bQLYL=`+kAd5vFXCGQh^$N^w^PSMk#tJKgOb&^q z)Z_viEG(Xv+5J*=U#4tF=cMsOuLKm!bm}BHyngCHHGYMes^xnq0`jZunfDY5DEXw| z2GK}#dL$=kYC`T|a(ltQ)w2u@*YI8FglOnyJQ3?-QkqBqdy(>Gm0$ z{Zwn`1-HuikS$oTc!2#8itG5)H$?RA;b^i%zdH=%4LHAzBp0(?9yjuuXE#E=i*~Sk zvli;&`W)HJpxOwJYLUe};r>uxwM5c6WaFy-7{?)ER9 zb?vrJ_8xF=2L#aSb0oe6HWAXcYsVG9%tx$wFBYdj$2W>?e-#_y41kPln%^5$n7}1gcd~$^hF|h4K zq*T1DkD7y_N60r&JFcU>EvJpyZsW8)v#Texh2eL39&QQA*%jwlg=7{Ot-p8Ls<-?U zgwrS0Pt+}PUhhA0KhvoNh@cp>yH0${N|%67WvbCV(aVWj)euQrVj1k1IE7+pl0=pb zVmmP#EIUWLUJ>|YL&^E;^w*i!g;FqZqS z1ZYXY2P6DRF|9k?L}KxxASQLBln4LT7UjmODhft*f!>$j;-H(@t)mgfFFU_LBVH#` z_42-zal|yaBff%U;yD&JE1m4)-0;R8E}UCaxpVdsWo-``46J2O-}cKC@t1qrUzA3= zwOE(dFHjRXb9W!?S#;%7^3~j%$RYh|GCwRS}pIidF-TKC5n&>#qdfes?_Pu~Up) zkubsgSv$5C6BeyBrIj(2x)yoe_cvNleEt+vKb!3xzM+!?Dv+;D&-aZ#lsf>I5f4zj z$2*u5r~~bHJa0aeE|JA}#k}%!5OqK*I+tiO9Q&=IyK5rdIbuxmlgpvL_7Ko zeKaEJI1c>>pcqf^*;szvhEx$jbEv%iC^Z;nLMbK>k+i}S! z*}=mux>Yc}BTDSACCUvh6>Bz?Dgk%REAb}HxFO($%Sg1{S=eGQ!{lCwxSnE!rzyRo1S#u)=dcqR~l znQ02m&n4iq5XlU4cCVVi zSgY42NdyJ{pyxOlw6=Ft8fJwiY%s!H3)I>vjgh^<(-HKDaJm+fy|ws_D~6JXuZfjt z35D4~)jMj2{ntS?yZ1WH<;CV%HNi*u5n`uo#-KFnpA4>q3cCL<2EtbyI0Ikr?G904)nXRyc)b@Tig z$XFO^3-GTdHGl?$ycx*l-=8uBV3=ugNu-%sGrDnP%pj+uW=n$^reYT+=*8W5KK zw#Jh+fF9Jv&;W~}Ks7Ff8@B}9d9^ft4Sdjg~IrlF90 zbz3YDM~Di%Sc0VMZb^UCkDqOX)$vBX8}yY!k&&UEZxh5P3Naz7o|n9iW0+ zNmkhe&D$J?d|}YRjENA?$3;vO6KnszsNy<17xr4DW`S=ssO<=+aZPpxI-S#gw>=xP zhg`1z`UiG4`9kOqJV|`%H@MIB;F0Gg6CG0FywJby*FAfT15NHQA41U1BGPxy1(u zBcPBM>>vL=l0`KJPvy@w6Y+OUuh!qKboRD(rUVXE3mKk>2?RbKNqj?7C z7AIhU89YhGagUsxFEoT2v7ufEZHSR(65vxvg`<-c$0ema!H4WlEqFbb(n76>S(&G0 zrUo6=++sC!dD$posdZbp(?sF}Diu{;N3E%W%L}xUq-9IPOmnI>Y81zvE;BMJFSt=& z4wuV1Jr*uxzI*<|T{?-Q6`45!V?_9WR&pbQqA7`;(5cq?hE4M@$Z)o(Y3!FAxD{&~ zs^L2{N|&XGC`VNrV^Wuvt_ELHW9kO_-1q%44+2rP;_~3bOABQ(8Vm`zOp9n7aH0(P zy~OM|<5;V8Lg1%Rb01{ocP29*AW-|d-|?|}G_jirc)$1j>LAZtfUQcQx9_D^=1g%u zY_#uo!MjuU!ve2`U@ktgWEBS1c*rhIf=xFK-JJuVJ1SxCS~$i zLGBe98Mbfz%w<-4+A&&s=$Lb4B3%?_D#`rN;se`asNe#PcR}+ndj12MDe|jT&R`(7 z2!xFZf!Fn9Fr$8T`(Slg5A#im4o#eFvD?MQGJZzRdu%4~?dH_3g4jQP?CE!$ZEm4K8R-gb0nYZhs`mg;=3FK>8>1Tpm_>|0Zk_3! zg8oH*eQ%hvAuPH!TSQRh^HFYg(D}ktS@Ddf3$ERjNde{Nn-dlR;NRyNn#L1lc49>N$2!CQ*uWZnl5CoRY&H-t0CfpQn_rYpRV3-e2BYb3e?~9 zUhdf)wtJ@fX<*J=;w#Yrt+U-|tpv`rL`ob%x2Pm&jR#?+7f=Z`6;=86t_&sE;N92P z%>IvCVc9X8dv|y9;--!pjf}AAcFhjweX25Y69%A&+04=SrZ$P6IMb~^?;w}}{z8C}^f}t>LR|m-}1n32tw4yp9-Zo24wQwOQY%1IR1}BrGpiUmSV8z_M5_0>uD7M=%Y)o!WuDvC z+2+4l;$O8BgQFWKf*ih@k|>l`8HIGv5}xhe`a$X)ipK- z?+nG=fH2w0QuI4S38StL`OZ+9R6ke%hu;)o%L~TC&Qs|-CX79Qxc>`xm%90Po3q~mB~2?2ulkVZWsKX*SiWxThlyS{2dOY z`=!CUUF`x&`e?VtgkX1!X7L$=u_X@QM@uL4^eutxUPdsE71`q@?A~uebfu#{S)nzX z%cple#u?u`bHuQG@3<-Xn{?yAZ$>x4g)6dA+gX_@1c%n`g}%lM;i(2el5@ zzv);A0HEB~IuLM6gRgyvGD}K1w_IVv*hc+lk@@(d=^3K0Yf9x;vXZbqJFlgWdeK1R z*IbcGL`i+W!nvt}quIRWI?u@+M-8v7ojCqUV$WT)LNo$iFH8`UYAGeWIr6YLobTCt zktvspKKjjf%OvRe^C?&XEXbM~AiOm|0}XVUq4U0fQh#g3*2R6o;D|=Q8|D4!BeakI z1GWvuPJJs|+CSo-SZ8^ib1i?d--gd6us4>m5!WTee;>Q+j`(W&pbHk51HtqDxbu2A zQz-VWFZKoLcmRZz`n@)5H4OrDtrJyQ2I{+o=c|GhBpwD z0aO7tJ~;`3OyfR722@wm$;imyFzou|Sz_))71#O*zO8%hQkD=T&QPEJmK(t_d7!*uk58C@ zde3tSf63)hY3^XTa;XFh8i75n?;gUTPGB)v!4zU+D9vhbPL;NEp9u z7QndVW^X=e`P(OuwR$|Z|8d~)o2zH_er66GzxcvMs=H0Z$a zvDPgkRd_t9vMtYKra6kAD;K0iBprgWKalsfDLRMbiAUe}D($adN=mQh>iI_@Uit~= zv)ww!*4%!@P`Q~cpF9ZCnUgcq4dQ4SmR(E1^>lB+5(0XG3Z~^Zpo@UF&p}|{fC@P$ zUp|Yy@7ewx@WvRzma9`I?pnQL@uA7!U80f2f*tnvxG4AHdG$WZcFVk45cW?^*h3Z%PgXf+Sbf||b z0lZgbTmb*RT~q;D7q(*$IEXDitCY1Vzkoqma@2Y@b+n$Dj_BQ_Iu#Er$GbpLt! zn7nwOO3TKm8C6rK{|nOo-T9KodR3nYiC;91Tvk}Zu8LtU`Vw-VnRp)4#T~W-VXTK` zgP`xeF_oApKik->toENnnjG+7EAxluKAn`-eT0hsb=*0wx`Q-y(daKhxgi6f6wwlT zi~B3sio#|$Wd0BSH?z4b{8K3$@H}2$#`nFPhP~X+3%r5|j46i*9Qd%cCjoOeTu541 zU7uwWl$f3t@Owx{T8X$JYNjYPl@^@HxSXmEHS{zY7lUponNo6w6%PHJf~?tjt7 z=bi2u+g;A@?J@hpOT~Ly>k}36AI%ROuIdP#jq(7*UPzZ+F<4zWecR|x9O%7yQaQN? za?`*>j+=uQFn&Z}5d-D@r7fj7$tVQ@@xLJyV?XS%?f~ff)V{NlnU1Ch`WJV};@fx0 zNT*$3!mfV6qg&7=7@~eEiXjnV*Dm|qjo?O-JGs1|tppk%oEVgke!P&N*l`1vCo z2)u7Ue(k?8(!)z@7L0e0dJ*nAt9Z;|7s7a__7ZD`Q+tlq)Y@fT1Agt3`o1da$@m_d zzQ@z)?9jN6x-*vR`*bcbJ8X#y^{|PFr2~CB`7wXNA2<=yPp4%s`#1v%4eMp+LK7C= zBs#zs{gl6CAVvxfPLKO7!4j42com@Vz(VrKHg5eH<=nl{-H-kJ)pJSa&zCrM9jLsR zJk^kZU_b1T{=XPJ$O{v+U%(kK6>laE(*1KqBdjN>15SDsEE5T#Vw4A=Lz z_W}OBWxRd6DTpt;9qa3p{9Ny3QYU~@$jGFiUdC~=(H{-TYODZbG%7kuCQ#-a$HP{| z2#ReGqW6Rac~VFJSZWn5#vg@i?xJ}}^#CO?FT z|8fI$=?Bv;eE_E7zDkI5N=4Ui5uKO8_cIu0ip>qGhmE?jtLAKWV$4!iH?tja{y)cH zVjE9G{3zG#?A)m-B5lHsNtT5>lezz^l(T+|;tkjM?6Sbpsgx{T(p?KIAu0%hfPf&4 z3rZs;wSa`u3W(Cu1}T!#(k$IAAl)IkoZ)+&^B0_-=Gwh>c4pq1_j&H;bCcWvS?v`r zA@xN=H3V*eKdEZ$-p3B7s6kSr&&)6lijva$x0>B_qT;^4Ca-uB^O~f-Xe?NMV6zQ1 zdK1>n!P)l2XKk|{Y2zfAQl`#hbD82RX4P}58OSsV8KLyDiT%OHH3`;5HNtzRUwAf+ zsn3U0kU4+4Ghb@JAsS^E_A!_%blLrn;D!lH!sE}kA!Z5K?XD32nxRYPrNl`Fs_BK} z!qGo3e|}KX8~D^(*iKoH!_F=U<8`~Cgw(Lt3Z?AG@SGJ9x7~#0bi70LLhmIRJmFrS zn-aR|U~tGC<0hDT>b*T{lOrADv%79e&54^68RLnT4`iepLEYQezdw#GS@gp&O?)&n zdn!G?W{*B>zzGM^&EeX_$ED?C4KsYj?n@;X^q+b`TZnJa;vP|78zgKha&PY8GZ@j_D{^7Cxy*2KH%F17PN6P^hljI3<1@I3ckKwsPqD&(c($iQaMUVCJ^?zXf9oLWx#)E%5cO?r; zZs?&UC%`hMf>P^X@e$qA+qjf?7sfUk-Z^)y-FUBwP?8w(XvmH= zLE&#rb;l=8%na?9JvYInEKbrFZFS!Ay%|hv(o@5G2g=hbjjIl8&`S9RfAV?MCPzO3 z(=&}e!U6|!rjSSL1N31NS@BBD&2M1^))F<~Od@GZY={cb(u;3n)_#gv1tr73#+Qk` zMU(i+sh^s1mm{xh4zCwUQ1;*ik@;Ng!;qh+lu(VXsq#o|y}X|4qpDfMkxzy#6>;H{ zBHI^`NryW~>jmnb>6^o-;9wO=g=~QyZS)zWBN%zZh@hs@;ES)*geP0^hmRsWl8Mh0 zhXy6e>eyllrrw7$wC00r2k~j>Qdjo$eTj4kkdtDF_oYeY2QSQ3D-Bsj z!<#xvNf@88wJA_6V$Dh4r<5ACjB{YD)jD(u%u0Vka@k$nt;tw^{ZqVteT`5==3j(~ z%*UV720B(*&N9&QV*R>&+Djw%!H2xR+bYUy-IET9dn9$5-Li{cF}q>yRQ6sBzi9bh zi6CWy#XbI?o@SIMtPOPx)(CA&FGlPBYBy1W3s-_H>-&@0zKYEg^zh(){3JA9rq{)9 z6X);EI-&_8yzVunill+JJXT8i4|K*2+b~LLcYAes&4~)?&bEhZ?jZcXm|=>HF)?NG zK(L_s%$lcR-Hxli)ny8q=)N;ralNmlBW`N1JxvMHkYs8rrK4+S<3#j~CnrF#xag}f zN**4y*fK1GMuXzU;;Q}xM>K8i-9P>q5KiVK^^5z7Nrk!kfW4o0wv z`57T1bqo>65;E~w*QH{dW8);6L?{D-!!L}*feUVPbCdP5Y+OG6@*Vo>qE?UDX>GN;1Io-Xm-v#^g`1i}*?lO7dOy?z?@nZZ6Q9AksgOmj~ za(v=n0Y3bcI> z8M~d50c}$YsorO5ivMU&cXiZn*)Q5(cIXG0 z*}KUYZ{-wVPQ-7LivG-zmSjfagIf0dde&KWfTq@KxaHLJU63D(svM#0Fo-jb?rG>> zJ_`f~{P*LWQW94D#(u1_F>*1}Hi^ki(}mVHwIX&~Y@4rgB|Wcl>Oco^inmm?kIvgE z5KX_A!YoOIbz{`6Yky^HO|pf0`MjD2grBFrJybr-ws4Ha?U#F58AcHe5h+*&}9OHY#pGV!4Ua>tpjdc z{A#roy4)fA10rYIdU#7elEk&>Imtdzis5|h;v!33;g85CqPM%+lEerG`@nh&ramk1 zk$~O5-E#~Ik<@Lu+?@_@OSh0rimgW!gMgk#Kw+S(iEIq{qL5u%nv(P&wDHsahEQ=E z-oys)r2t^@334@Ed`S&hlGjxzqP$)Vog|gRZD?oxY*rqw>HawwpZfc{qU%hra(D65 zXHD4K`w*I<{x&I!Y`k2{O)3rWHMuBY@Gwc0aw}DYEPUgFV}PY16&E)_vkv%U3YgcG(Xofew=42H#1xf9KnZM9WCm8(0(yCfIm80*GhAFYMhe>ZNQ zL5E)uuQX8nF_~%=&tGn^s`+8rx>-dQNu?vC-qGzcsQ9WmsUHC^iS2ztqzbsea4NW_yZT)b-AjT3LJ@%<<1DOtX0PU zI&T>0Hj4wq6pPF73u4PcE1P2iVDC&Ye2}>F0q^CkrVe}*tx`+#2)$``m=9xrJ);20 z;35Unw?rBkU%-Xj6>psXYq{dhw+nKFC^+BPo`UEXq)m3w@mjO@LHjrmMYe7RwGrt) z2RaYFIycvGwl*A0#f@U5%7h5Avev{K9}=w^4orz&YS!xUucMY9c!N`x*X2?}rgrA> z1UbSBH%(ur&aqKQ@f$yBX74PX5>fLI#SALnmS7#s;V3rfs0i~~kG080xgYEO{rA&eP@{D+b}y>GNc zWv7!l{oXLq$Csc8FAt(kbs--&x0##1hQt0<4l=AJs;M&X?@7sS3sEXv?s+%2w>Gjh zhhM-7@3N?|_MB(0oc}r2-SfSniiXmDg2(Zk1Qz5@1zQoqnmzuR*PPv^&_0Uj!fI0OoKf{vGmZrlcSew(t5Y zbbGD6%1+LWv;iZQ3=`hJkKR0QPlU1+(Ft8KuOM}j^`53+$*oCGze?bNM1IrRAMV-X zLluS81T($byHw}&C8;>!4Eb2)hFH*_q+mK2f*Mc%omolzZoq{kF(~l?27f1NP49Ww z;e_v9ggDHmbWi_he00rV>iFKDairVkSnLag#*b`9El2zvFlgbsN2AD3geg%V@je+k zP!a6_v13bw6HijcwE-G|^nFz`0eNGB)6}g!TKoG;@TY;M^&b zCW<+l%fe^VSQEttTS6>gKcAVoS`&?fSN>cIYsEf+zRG$P@J4Yy@hv4y2PXo~9WE(OmN#qG1=g9>6z}(Tyi`=+XW)O<6)_ zr-V2;z<<5LZyO1?-Wdnur_V(M?}q|21{&b4hQgHQ51NhQN=J`+Yp3Ld&v)3}T+!k} zK&RW8Y>`jIM&sgRZkEH*4-nvoC3wUp5TnHi;k%tG%8epD#~Es~ zXANcenRLh*qXYQ1fsp~kXyzT3Q&oW4XDs~AeCl(os)w1U7{$@cACnJe9HWQ=rz*(` zTDr%o>$-bvPgk754<4O-8^tnKHQq&&^j~Mm46W8v&i$*!#Oh4>1VDmQP)h48CJE$#me%dRkJJ|1=mv8d+ z550WovSsEn3EHK-T`>%d3aI}nUL=>&?ovUkYoLq4$yR2+iPTPYN6E_BpZSxiRep2# zSmKNd32CqF;^uBT6D+5N!7}AP681GI-?pu^t#t%rhiB)AC)G%fkcIr^sW)JZ^-CDP zQ)RZd*{=kGeHEIPfnnb`ajj3P!ipuPiH77co*rQ{URppu-z2nG&D!e0Q!ecNHh8nJ z#p2?m9DRaFUE`Sb_HqHR1Lk+V_#F`snhPHphPfkh7l(ABUn3`>v4dW*Ys?v8X~7JS zM>|B<-C~&ph)}$5BrnRchh!)qsE8B!F%6g6{SxsZbYK)=U{UU`YS=wy_lo>l{Oq<4 z-8#~ajSHavV{+4Vp`W}GE*p>tXMHkjFS1r~YaU5GXP<_F(Wu{&9Bl7Gd~!t<-s<`| zayBqz|9j(Vyopd3nh^}sxA}0Nhs}U6M0dqFJZq67;jKrxe}8@ zr=II9DYh`KHil+n+m!cjI`C0A{UrWCjQ!jK&5dm z0i8%%>bvu<=&nJU)&&)v2;$so9-6!SFaR)JNyJMHar*<%! zs#;#9B7OC>8DY@@{kL->Wy5pZ+e+kS(6X7a*}#1J_@w*p>aDeka;WwDaHuy!W@1n= z<+u+H^lAZPFO5?NVj!Hmu7;J~>V?Rd2rtXVOu8Eh_uVUypu5J10kGHrN~syN({S{x z*6rcp!XY8}gIX zEQiu%1K##R(MEb5`er8q}o?5`#FleCFNIgJZH!VXi0ejxC$(7%dLlB$R zFB(M`=+N&`^R#dD#5T$yY5*D%C_?|F1XuA#+KhLe_VO(Ucq54P^~>9pHn z1ToJ7=ZS^5Qc!9-Yba)j>Yn02@YtKEBJ^Jag8J+$nUyT^DoMiL&3Ww+JaS*&9eHK+1`UC$U@j!E(G0TcNZx@ykAln|Tq{r`wKGte#9xbWQA{> z0C~BSj?EK+YVEG^WVCqGK;npO!~Dp0 z;!MPxaw({rD#4MBZ(1xHotCCLwB}NM#FHB2!hIxCqe_X{NWuun3jA>Q*;T$g-|AA# zTUB8Yj*4lZ{o@#ry^Kiy_^6@stTUYEd;f_^*lBZ~B(-T>DzRHN;Rhp=Ur^Rjhy|Pt z;0#7Jo3QHa3TRGk1-~m0rFo4P6>0nSCBD-t<)(F=P1OE;h=6*xN8O{*(#6&c4}#xz zh31NvPK9cm0Y})By2Z)h9Bq*H%a4I=$oO6G-Xuq~fO%(ta8~J@oqT$qYEP`4T1W0` z*OR%34tG!6Fy{GERK?kAOdKVQN@g*F-Jf8-%<5~fYsxG-%}b=zop3p9NqBMhV>L|1 z|C6wg5EMxF-Ih(2^XU5Od8O)LtyE+*v1tYJ9LIAd5#Z~sf2}7|VW3H?GQG9C4`%}U z&G5YINF`#ra~CZv2nUL7Rr=HaasAD3;=1RdghyDO1avU}ZRep7(yx${Y_JsQ`Vq%W zF5k|wkjlht-VPdxVbc{h1mT|4;eUx5oL@15C{CL(Cilj|1RBJG`!4^i?9HPQP1pJL zgSiXt?UV6eRcoW~ffetqKHRVO+n_FNKE9wy1ko@^{=--#6ZI|Ui`xGarGX}|`Xdj}M&t2xiHqi2&sM2fwJOw|gZSj9kVu$4q>0B>PTxB^}c^;-uE5?MYq4?O_lta`2 z)4(AJdV2BSbWo)^U5s*i;QB+?i&=RH9Gw(+;hf%x4qP|@;`m_d_%i}N`8r)HLqT9V zKUb&et*88{<{F6MHLxdOsPi9Yw1K3_^`HzmT-B|j4M9~i2X6)ILuWlL5U(j);H%O9 zgcsc#PJEEZ(gEZLM}68mtogNga~IMN|1_MoUvbo*ugp!@KfY}}eNd8iQOXOA z^pM^+2b>_8d=T*pipARikmCu~sloh2r6-#7O&-J$kRRM<>G?s^T~d)Q8|pa~nuE9D z*&6>V^6sO+bvE&>#v(8j0ugxOid)T&m7Du@c|4^NU-h1s z8d`f}(EGW~W6)Q`wNusLtNsVBO@`7GNa`n-A8n~pK#_PkR zpr4gP)@2UH7ka$f({Eu>tJ50~ZR@WwqhV(*AjhNs?_X|m1Ttb|#2`Hvj`ZGTm6Dd; zTU5d=UhC`8takmZ(I8rc-Rj^kPHWc+T=}5407}f+amS!#pqN})^nds6C!v5b_g*nr zbbfWbXV>A7h0(*NSs6=&`=guUpca+Y^tQcWfTe8m|3< zpc5ktVzjjgAsCq-yzru!PJcUAefR-*$Be0_3BMM>OOAS^#n9wJy@BJ^iZ`75FDX%F zcrLp?W9R1`|NUu}FJ=@cbk=MnAY)7jp@sRBRN~BP61}(J_mtxZeK&TlTY8ep4u%RL z@TK>do0!g24te@o9gwgq2_JxC2*{2_7$NW6Yg{c4kNw~mc3X@O$JCA3sJ?8J<(N-%`u?YSjKHLyb literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/tinker/textures/gui/bookright.png b/src/main/resources/assets/tinker/textures/gui/bookright.png new file mode 100644 index 0000000000000000000000000000000000000000..8c255a77cb6dfab982d0040a1480c6574eddc29f GIT binary patch literal 8536 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 E7Yh?KnE(I) literal 0 HcmV?d00001 From 7eca5a86e8b9d1cbe3332e434e536808cb59b140 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Tue, 5 May 2026 22:09:16 +0800 Subject: [PATCH 09/34] make book front cover and page render separately --- .../tconstruct/library/util/TiCBookData.java | 47 ++++++++++ .../gui => library/util}/TiCGuiManual.java | 58 +++++++++--- .../util}/TiCTurnPageButton.java | 13 +-- .../java/tconstruct/tools/items/Manual.java | 2 +- .../tconstruct/tools/items/ManualInfo.java | 84 ++++++++++-------- .../assets/tinker/textures/gui/bookleft.png | Bin 24256 -> 0 bytes .../textures/gui/bookleftbackground.png | Bin 0 -> 23305 bytes .../tinker/textures/gui/bookleftpage.png | Bin 0 -> 17909 bytes .../assets/tinker/textures/gui/bookright.png | Bin 8536 -> 0 bytes .../textures/gui/bookrightbackground.png | Bin 0 -> 18898 bytes .../tinker/textures/gui/bookrightpage.png | Bin 0 -> 20064 bytes 11 files changed, 145 insertions(+), 59 deletions(-) create mode 100644 src/main/java/tconstruct/library/util/TiCBookData.java rename src/main/java/tconstruct/{tools/gui => library/util}/TiCGuiManual.java (84%) rename src/main/java/tconstruct/{tools/gui => library/util}/TiCTurnPageButton.java (90%) delete mode 100644 src/main/resources/assets/tinker/textures/gui/bookleft.png create mode 100644 src/main/resources/assets/tinker/textures/gui/bookleftbackground.png create mode 100644 src/main/resources/assets/tinker/textures/gui/bookleftpage.png delete mode 100644 src/main/resources/assets/tinker/textures/gui/bookright.png create mode 100644 src/main/resources/assets/tinker/textures/gui/bookrightbackground.png create mode 100644 src/main/resources/assets/tinker/textures/gui/bookrightpage.png diff --git a/src/main/java/tconstruct/library/util/TiCBookData.java b/src/main/java/tconstruct/library/util/TiCBookData.java new file mode 100644 index 0000000000..504f301849 --- /dev/null +++ b/src/main/java/tconstruct/library/util/TiCBookData.java @@ -0,0 +1,47 @@ +package tconstruct.library.util; + +import net.minecraft.util.ResourceLocation; + +import org.w3c.dom.Document; + +import mantle.books.BookData; + +public class TiCBookData extends BookData { + + private int bookColor = 0X8D754E; + + public int getBookColor() { + return bookColor; + } + + public TiCBookData setBookColor(int bookColor) { + this.bookColor = bookColor; + return this; + } + + public TiCBookData setUnlocalizedName(String unlocalizedName) { + this.unlocalizedName = unlocalizedName; + return this; + } + + public TiCBookData setToolTip(String toolTip) { + this.toolTip = toolTip; + return this; + } + + public TiCBookData setModID(String modID) { + this.modID = modID; + return this; + } + + public TiCBookData setItemImage(ResourceLocation itemImage) { + this.itemImage = itemImage; + return this; + } + + public TiCBookData setDoc(Document doc) { + this.doc = doc; + return this; + } + +} diff --git a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java similarity index 84% rename from src/main/java/tconstruct/tools/gui/TiCGuiManual.java rename to src/main/java/tconstruct/library/util/TiCGuiManual.java index 9a7efa5e15..8ad56c0ab7 100644 --- a/src/main/java/tconstruct/tools/gui/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -1,9 +1,10 @@ -package tconstruct.tools.gui; +package tconstruct.library.util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.oredict.OreDictionary; import org.lwjgl.opengl.GL11; import org.w3c.dom.Document; @@ -20,7 +21,8 @@ import mantle.client.gui.GuiManual; import mantle.client.pages.BookPage; import tconstruct.TConstruct; -import tconstruct.tools.gui.TiCTurnPageButton.ButtonType; +import tconstruct.library.TConstructRegistry; +import tconstruct.library.util.TiCTurnPageButton.ButtonType; @SideOnly(Side.CLIENT) public class TiCGuiManual extends GuiManual { @@ -46,8 +48,18 @@ public class TiCGuiManual extends GuiManual { private TiCTurnPageButton buttonNextPage; private TiCTurnPageButton buttonPreviousPage; private TiCTurnPageButton buttonHomePage; - private static final ResourceLocation bookRight = new ResourceLocation("tinker", "textures/gui/bookright.png"); - private static final ResourceLocation bookLeft = new ResourceLocation("tinker", "textures/gui/bookleft.png"); + private static final ResourceLocation bookRightBackGround = new ResourceLocation( + "tinker", + "textures/gui/bookrightbackground.png"); + private static final ResourceLocation bookLeftBackGround = new ResourceLocation( + "tinker", + "textures/gui/bookleftbackground.png"); + private static final ResourceLocation bookRightPage = new ResourceLocation( + "tinker", + "textures/gui/bookrightpage.png"); + private static final ResourceLocation bookLeftPage = new ResourceLocation( + "tinker", + "textures/gui/bookleftpage.png"); private long guiOpenTime; @@ -69,6 +81,13 @@ public TiCGuiManual(ItemStack stack, BookData data) { this.guiOpenTime = System.currentTimeMillis(); this.isAnimationDone = false; + TConstructRegistry.toolMaterialStrings.forEach( + (str, tm) -> { + System.out.println( + str + " - " + tm.localizationString + " - " + OreDictionary.getOres(tm.localizationString)); + }); + System.out.println(TConstructRegistry.getItemStack("flint")); + // renderitem.renderInFrame = true; } @@ -204,21 +223,32 @@ public void drawScreen(int par1, int par2, float par3) { int drawY = (int) (this.baseDrawingY / scale); GL11.glPushMatrix(); - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GL11.glScalef(scale, scale, 1.0f); - this.mc.getTextureManager().bindTexture(bookRight); + int backGroundColor = 0xD89A1D; + if (this.bData instanceof TiCBookData tbd) { + backGroundColor = tbd.getBookColor(); + } + + float r = ((backGroundColor >> 16) & 0xFF) / 255.0f; + float g = ((backGroundColor >> 8) & 0xFF) / 255.0f; + float b = (backGroundColor & 0xFF) / 255.0f; + + GL11.glColor4f(r, g, b, 1.0F); + this.mc.getTextureManager().bindTexture(bookRightBackGround); + this.drawTexturedModalRect(drawX, drawY, 0, 0, this.bookImageWidth, this.bookImageHeight); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.mc.getTextureManager().bindTexture(bookRightPage); this.drawTexturedModalRect(drawX, drawY, 0, 0, this.bookImageWidth, this.bookImageHeight); - this.mc.getTextureManager().bindTexture(bookLeft); drawX = drawX - this.bookImageWidth; - this.drawTexturedModalRect( - drawX, - drawY, - 256 - this.bookImageWidth, - 0, - this.bookImageWidth, - this.bookImageHeight); + int textureX = 256 - this.bookImageWidth; + GL11.glColor4f(r, g, b, 1.0F); + this.mc.getTextureManager().bindTexture(bookLeftBackGround); + this.drawTexturedModalRect(drawX, drawY, textureX, 0, this.bookImageWidth, this.bookImageHeight); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.mc.getTextureManager().bindTexture(bookLeftPage); + this.drawTexturedModalRect(drawX, drawY, textureX, 0, this.bookImageWidth, this.bookImageHeight); this.drawButtons(par1, par2, scale); diff --git a/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java similarity index 90% rename from src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java rename to src/main/java/tconstruct/library/util/TiCTurnPageButton.java index 1a95063826..543d1f90ff 100644 --- a/src/main/java/tconstruct/tools/gui/TiCTurnPageButton.java +++ b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java @@ -1,4 +1,4 @@ -package tconstruct.tools.gui; +package tconstruct.library.util; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; @@ -12,9 +12,10 @@ public class TiCTurnPageButton extends GuiButton { enum ButtonType { - nextPage(0, 194, 18, 10), - previousPage(0, 204, 18, 10), - homePage(0, 178, 14, 16); + nextPage(0, 16, 18, 10), + previousPage(0, 26, 18, 10), + backToJumpFrom(0, 36, 18, 10), + homePage(0, 0, 14, 16); int textureX; int textureY; @@ -34,7 +35,9 @@ enum ButtonType { public static int ARROWCOLORHOVER = 0xFF541C; private final ButtonType buttonType; - private static final ResourceLocation background = new ResourceLocation("tinker", "textures/gui/bookleft.png"); + private static final ResourceLocation background = new ResourceLocation( + "tinker", + "textures/gui/bookleftbackground.png"); public TiCTurnPageButton(int id, int xPosition, int yPosition, ButtonType buttonType, BookData data) { super(id, xPosition, yPosition, buttonType.textureWidth, buttonType.textureHeight, ""); diff --git a/src/main/java/tconstruct/tools/items/Manual.java b/src/main/java/tconstruct/tools/items/Manual.java index e2c120aa40..af7c4ccabd 100644 --- a/src/main/java/tconstruct/tools/items/Manual.java +++ b/src/main/java/tconstruct/tools/items/Manual.java @@ -17,7 +17,7 @@ import tconstruct.TConstruct; import tconstruct.achievements.TAchievements; import tconstruct.library.TConstructRegistry; -import tconstruct.tools.gui.TiCGuiManual; +import tconstruct.library.util.TiCGuiManual; import tconstruct.util.McTextFormatter; public class Manual extends CraftingItem { diff --git a/src/main/java/tconstruct/tools/items/ManualInfo.java b/src/main/java/tconstruct/tools/items/ManualInfo.java index 94467d6d02..c4238869d2 100644 --- a/src/main/java/tconstruct/tools/items/ManualInfo.java +++ b/src/main/java/tconstruct/tools/items/ManualInfo.java @@ -7,10 +7,10 @@ import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.relauncher.Side; -import mantle.books.BookData; import mantle.books.BookDataStore; import tconstruct.TConstruct; import tconstruct.client.TProxyClient; +import tconstruct.library.util.TiCBookData; /** * This class is now just a constructor with side effects, so a glorified method call. TODO: Clean up when breaking API @@ -20,45 +20,51 @@ public class ManualInfo { public ManualInfo() { Side side = FMLCommonHandler.instance().getEffectiveSide(); - initManual( - new BookData(), - "tconstruct.manual.beginner", - "\u00a7o" + StatCollector.translateToLocal("manual1.tooltip"), - side == Side.CLIENT ? TProxyClient.volume1 : null, - "tinker:tinkerbook_diary"); - initManual( - new BookData(), - "tconstruct.manual.toolstation", - "\u00a7o" + StatCollector.translateToLocal("manual2.tooltip"), - side == Side.CLIENT ? TProxyClient.volume2 : null, - "tinker:tinkerbook_toolstation"); - initManual( - new BookData(), - "tconstruct.manual.smeltery", - "\u00a7o" + StatCollector.translateToLocal("manual3.tooltip"), - side == Side.CLIENT ? TProxyClient.smelter : null, - "tinker:tinkerbook_smeltery"); - initManual( - new BookData(), - "tconstruct.manual.diary", - "\u00a7o" + StatCollector.translateToLocal("manual4.tooltip"), - side == Side.CLIENT ? TProxyClient.diary : null, - "tinker:tinkerbook_blue"); - initManual( - new BookData(), - "tconstruct.manual.weaponry", - "\u00a7o" + StatCollector.translateToLocal("manual5.tooltip"), - side == Side.CLIENT ? TProxyClient.weaponry : null, - "tinker:tinkerbook_green"); + BookDataStore.addBook( + initManual( + new TiCBookData(), + "tconstruct.manual.beginner", + "\u00a7o" + StatCollector.translateToLocal("manual1.tooltip"), + side == Side.CLIENT ? TProxyClient.volume1 : null, + "tinker:tinkerbook_diary", + 0xD89A1D)); + BookDataStore.addBook( + initManual( + new TiCBookData(), + "tconstruct.manual.toolstation", + "\u00a7o" + StatCollector.translateToLocal("manual2.tooltip"), + side == Side.CLIENT ? TProxyClient.volume2 : null, + "tinker:tinkerbook_toolstation", + 0xD61E17)); + BookDataStore.addBook( + initManual( + new TiCBookData(), + "tconstruct.manual.smeltery", + "\u00a7o" + StatCollector.translateToLocal("manual3.tooltip"), + side == Side.CLIENT ? TProxyClient.smelter : null, + "tinker:tinkerbook_smeltery", + 0xB6B6B6)); + BookDataStore.addBook( + initManual( + new TiCBookData(), + "tconstruct.manual.diary", + "\u00a7o" + StatCollector.translateToLocal("manual4.tooltip"), + side == Side.CLIENT ? TProxyClient.diary : null, + "tinker:tinkerbook_blue", + 0x21BBDC)); + BookDataStore.addBook( + initManual( + new TiCBookData(), + "tconstruct.manual.weaponry", + "\u00a7o" + StatCollector.translateToLocal("manual5.tooltip"), + side == Side.CLIENT ? TProxyClient.weaponry : null, + "tinker:tinkerbook_green", + 0x27CD1B)); } - public BookData initManual(BookData data, String unlocName, String toolTip, Document xmlDoc, String itemImage) { - data.unlocalizedName = unlocName; - data.toolTip = unlocName; - data.modID = TConstruct.modID; - data.itemImage = new ResourceLocation(data.modID, itemImage); - data.doc = xmlDoc; - BookDataStore.addBook(data); - return data; + public TiCBookData initManual(TiCBookData data, String unlocName, String toolTip, Document xmlDoc, String itemImage, + int color) { + return data.setUnlocalizedName(unlocName).setToolTip(unlocName).setModID(TConstruct.modID) + .setItemImage(new ResourceLocation(data.modID, itemImage)).setDoc(xmlDoc).setBookColor(color); } } diff --git a/src/main/resources/assets/tinker/textures/gui/bookleft.png b/src/main/resources/assets/tinker/textures/gui/bookleft.png deleted file mode 100644 index 858cd70b93cc364d90460d6dae892a8a066bf095..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24256 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

HLY@|fm6?}E|EC1)tLD!8IMC{$ zF?!VpI&iGi)#Ix(4x&TAy`e?~H==?WXoLZ}fkqnof4VbM^?P(t#_=!s?x#!VFPImJ zHnsJx_SnJa>t3g;g(J6_1_fZ=j1UrNPvSw##ovtp?yKRfjxSmcy z(FF|Oj5=gZE-=?>ChhhxnnXG0{lYgPk=*=IPcw^ zM+7+!VT;p^=MI%W!&URhC_9CdCrJYuF>C2ph&McN#ZKI|pMX6gI?MNiVofm$T-mRW zVjjlWO#tT_jh!Yz-ue3;V&?q=Rp=%UCn)lFG9^;dCCeVqb~kXWyW)!K&L2 z)5{cHwliR1uxi&1aqxl`aoWy6$98x+-i@jyi|J-$d>dKpclZ zujGdN`!olhgUOosKk4;+ci>dMgUy{`QIwk1`CqMPY0T0tHg_Ei$lE}?YDMewNJ+s7 z#+8L8m=KMdT7&2IUh6h~8Zw?$N%`|eI%lDTs(W!)-&&uN0RvmnRBR!uV0MmWqsO~5 z!lS%2=Hky3qQDJX*V*t{Xjc;~$cveD+%B?dO+oQBL-F*45g&9y?0R|XQbnbip=vd( zz0su>3ZxLvivt%=Fa zDku_ZQft56P#uA{o&cPmt>>h%1^ixFU0D8Xd-VF1sw+(RY%1u$ulgKfu~3_DR-sI` zNvv8IbxD`@gv@@8tg>`M)3+O&V!pEY{l%It2ewd6yR5g^vufF6x@us-@0(MwM0b*r zl8lCkGScVqG1e2OqpVcix8)tiCd04@0x#y~YSZfK`wpr)gPt%S_ z@I3(f4Iz3R8X*N50L>iK+>G>vet!oFe@Ye_V`tRT{S2UH0v*B$Lrp8P(gXJjj7+Z_ zVH2&^0B3&cvM8M?cA~_^%k$YYDy2SnLMi;wt}1CIV1$Du$wrkNmqoijFw?&OLGLle zf#VauPhCENvNQeE^Fh|0D)n{Xp^(l4Ofm*>z?`P)h{s4ET!pvbJ-(3E8S?q-BW3s3 zo*_@jX;hx&Zw_x{43ktEYa{psr?%GxLc^5DpT@M1v5CJ=Ukyt8(?^r`;@+WhC3t)o z-Gd$5l)&b179~4xE{6d8zHxKs9D?W6(41vtt>oV08vTYl9MUKG67wUJTZy?7;pj<1 zk%t^IQE2+PYgD35?EUcJT_6kpR?VYDEGR2wKUzMI`m?(I5r#Z)9Vf!bFo9BVj@;`a z&TkfRm}@67OlfeLS-FXRrbLlI9^UV4S|zxFd2>8-18SzG49&8Qk|-S}Z?sp_0C`In zlL70s_sHKyT;ELnLb;SLs``#d;{qPmHYgrY^cACYP5q_jJPHudej|Kt-m+GcY01uw*^l8b276Y>{Bgj2uo*NFQ+asz{98l6Z+^T=LX4RKBhOIq455U> z+-OS(JdP!(CVIrb+@I%Y>|u8#argAk59;G58lHy)k4u)gzkBNVnga}7|;4lAOGE{Rd z@qVvxsT_QQ`$1lPK|37jA-ZnQ2MMhAcZRpNtL8Irl`s;#7fkZ!E|K;N~ z8V`7e&PNh`P0cMD8k*M={g3Bi!gjl%o5?AH-eLycZx5ZXV=cGE;)v=Mv*oA1YTsbC z)Ld(G35vsz$uqOC8T6`V3JedfW~(8k^`C^Ovux?hm5Xi%@$Jb1IJjQMS*C0l!bp4f zKHh(9=M-avO}F|8hCHaRqn<~DiFAAdw7A7hcDhs^&Jcfergt6WqPiiW_`XL0YPP^H z2Xgp1{$O^?vDD33z#Ej}{*!RfLdJoJBAEsX zNPK~gHbfP*Xx19+fKcq8hX2l-9E%NRsQ1$4e_`vlamyM@m<9uok(Dtp9=jEukG+HM z5DcEs6Y_4zKIJ&tLVqctm_ZhH+4i_E=3!&-^2h@@i9a2lMkA$+H|EJ|>}-rS=8K+J zMEMzF?(9$!3FmyM#yMPO;mefFo3z3S;N}DQd7Aq# zGIIudPa8dp^$}m5H=tKw768!J8_iYk7-z8NYH@S2l#;MQduL>J%E6@UgbF!BDQb(C zC?A*lTeH`qSst5$jpoS4)7rASvs*z1+XDOCMCm-r2W!}ls~rAWa6c5VemT(y^D`i2 zc7EHjDAf#IMPuXXDCDp*MfI#}-vuM$)YF7clVJzgAC8v=zda-!P;mcV)#%$F#4|I~ zA2{{d4iReI0tobe3Fhozdj}7WjC9bg%0Rv0CBR?dscbbw_T`R2EQ&=vdC3_(|4DpY za$o}x`NO%Jt?!a8g)hJ{G10kf403Se*1d_j5`S38u2t1gFe&BHVdnZSPQdHBC3!t> zC$%Fx_Q=kx7IxQE<{1{xO6-le*cJ$}$dsIvz+ln__19#d`ANVB@>uuUR2G21SbG1u zq*NQQ*(0o#qF**TQF2r-{S)tE1WThV)1U8k$;%rS71?USvg6#8zYJltTr10T)38@=7ce-LJMqWBu}qu zMWtxd_yQ^U1;0>DziqcIcXOhk#&pw--qrK3K*j0rmEvnR4Uf@||6ai??l&xumMYFS zNR4O=ndBNy!0V&qvnotY<2U1uWt^n`)YBv@6IB^yy&d101?jXn_R!V;TuhO=*G<@X z!UR8j`X-uOyq!?=>b$ccJcW2C`I{oo?$SAqqCvneE8VGc3X0g{sYnXtE4}4lSOr1X z4|^??Is7#0%WCB~d;-vs}7D1Ons`tA$6@}u`H zMNnZ??Td~h97@U)eQRX*+J-gKeC_OyqYJepbx2bZO{O%|5NA_k>964Bu*^o5F~FZL z5%|g1b2_aJvx(d{8yR`@)5%EVO9yjoGf|ezCBJ0L2lS=+ltG6-kQ>+1=%c7RVWu~i z0Y)UauBpjC%cIWp313cVFVBvct0HG$myr(a8ht#Sl5DKhWAUivLhX4iQ7&AaUSE}+ zwZub0*Mq|H2s`EJ4*aHwV(FS>pi5GGokW!aiTygs6sw)O&Cbg-G+;JSBvJ9p`yQFY z`!l}dZfxHd)jBP#hMWahn@=u(LKX73*y0gQqa9t>yNR1hW_Pp;=b|(8WJfQYmZUHEhtDc zO6YY`Ov!+&{?4+)Fh6GHaE2aP=kD*2PFq`3h!J{hwG8r2+THJUQHj1_C&{TN1z5nQ z!{_tpcX;|7x9|JwpBF?hXG$<@`I#=r$=_HRpIsvULZ8N!q0kh!Tb{aT_v~u0*4F=n zs_sI}`z_Boo8NO$)G4at)BCn^z!6k#y*v@9}M7SKjWbe~VT0^zqb{v!1t=_vT)TtgkS7SL(TypQ8 z<*~{ijYyS&(8A*}7qci;yl|?P^GXWM3yvIOam`I~-Z-ws63Fcd80^wWuRN-(CkwaNqEY!`e3`U6A{=wzkSdXn|E@SvH+T2Q)b8r**ISBB{! zF3#Z#NY<0+5^$XYbdvc9b4}7SPtzETDnA*&rhY=TtNSfUm-})^B0-~CDk#x_u5oeC$p1AE6l3aDLvUYrM+fNw zXfs7}OkR-NA~S4(KXS^us9qW)>_<9M!a4vG=!G4 zczZ>LeWLs@$4VI)O|I5?2ONZ_t^60OMEe14WO5`EtJkeJAlHx7j?=A6`{yX9S zEKyIR<;V&J9TizQc+(UDo@G-0MR@6X8T|>$XVSINTXY;yQcYfd+*@ZAUan@%C79eYjMmNc}FZB%H| zTa*&aBAZ2Euzzegg^czxk$YxF!qB`WM4Dc?9#zfnn?qRnA$3s5`60lm#=At7folvUs8(Q3I_o)#awfctDL12WeeA1iiMKq$*UH%wwf% zDkPfUxY#(a#Z=Y4*UHn;8UE! zROHmj7f!Bd4t+mM%m|a*^@>tuQr_iIorN-JRNFV;rw;6wv9Z33*Zb5fnyx4E+7@*G z>qp|9zm8J!*tXWE#V+`Gfg^|{vuUO;A??;(Lq9of~b-1z;mIL?Jd^oXaW|TZslG18I zsLysj()iqO@_i`Lfav1wMuP!}XA%)Lt+cD#F=xNZR?}Y*k<*~NsW=OGKiTl7zB$hu zvP&N!*MdTTiQ5V)jykN)mIvR-nesF_NBK>IA^O&(xb2hSx_`4_&5GuATXakd0cX8;DEP{;+)A&9wBTw$fzmeaiu-F` zB#!YexS=66HTCJw4|B)k`SJw$AmZ0?(w5gClPw8~^6W5le+o>n$EpYzs(%ga6#nlFHP@7xp@h%OHHAP5BZ?Q0aiZsFW_Rym(- zu=e`{hE4s~j;^SYa^J^pHpK=EFO`(xI#-}!RIOe6aVho*ZoxL;w_r8F_{$K z&T=97XE?KHQ~fLzb74>d#iQ@sTnosVqqeaWMWks9l;DpP;Kh`WWSX3bs2zgnPxi^| z;Nu7=cSFEm?f_T5GI9B_?uc(ijWub)h-#8f^nhDGe_ z?A!;%Kcm>w7jinfx_jE%+G%NN0aMwLeDO&6J&yvCfQ})EZM7NYQn`d7V*f1rq4vB$ z{z)FU-;dsVKW`?vuZf;tv9De+^apxY_>9`QeWnh+^Iy}W`d$rS*G3?SW>UT=VwZt; zZ*P;77^8J`(woIh@jk3JRUzVG?i6do?aLAL)>BTE*RjMA4zBW2PItVU(Y_BZML*g& z!?`#yeHwhW*5Go74!d~LarWM~>y>UsCwPAnkFHC;$Q}UI+yVvOV?x0I2YUYS?8H14 z!5xp)A7y_0w@(agNCvgWB6_`er&z2=1|V$%ya{9>e(zY|brXrt0q!|6pzDTaSOa)t zOTbPYQ71h|O|1JZRN{<-Q2~BOH9Lom+ORtisc(U-LsGFWe{e)fkjBlL&9eZDU5PNl z`d;o44C8Xf4Qsvg!5rj`^`<$Z@hQSI_-2nqwhmwh|H)^>2WTWUO*vkHqU+L$cpK_V z?3liU|8zHv_)b|H4j)KE1zvuwS>-QXkRpNyCmD6)XkZ2o`j7o0;y%N|F~$)=Ys2Gr zojyT9&m2MpfJ-srASQ)GobMIcW*;MISO5O1J)2NSB@~6;=P#T0CJW~Cl6~{qPsg4& z$0nOasWoRYWN5?Ky}L^$0BaXf?NW4v4hS|3pSMk$9gult9GpHY(H(2<-QE6@J*Bza zBT^b9pl8m)aCXsBFttOoZ;JQkM+_ltVK#$8#dN4F)XjDF=m#Be{{pO5C=#^H!kWH_ zk|IWgj&#$#g$-cbXMzkEtL)Q!!`ecbqPxnCy@1o&VD)ZdJy2@dc8pLt!?AroDb*+D z?d24|2&{&wB{M0y3Y~H(tK38QkR+J#RksSJM&wPfKKL?GEhj&p|S-e{qP|ork8WZ3OFHVqo z3@|WIBxVgKMB;dRH8tMaWFlzYVTA5j5K6ROrZ$(5`i2Gma-3d8y4DDRbtmu*OCzaB z^xNx?0Ml6m9TzI(w`jxDclv{}R<3dz!W6<3BKxTdYdh&y$b?SkB5}I6c$;T0R}6Kw zrs$FJ%-VL4W0eMTqKjr{Ks%imRObJwkr!p#LMJ#lqOc6799}Wu$J4Cu>ueqr@=<~a zW=xJ4#akAu%`=Ie4)UjH$Kzu40rk3dyt}ai#Z_1ri5dBoo6R7k9YQ3di%-f?cO~#{ z!Yn8lC+~SRDNvI*(EjT+62F)60qz%1^1Lj{umwO9Iq~ZSm{#5*{8RTx(HYVHHH-|fsx;grbDTT|_hwSX;0#=U^`|Tg$Zu%si?wE_R@_ECbJ6o$HX0Fp+PH)rEjo!2| z*$JmMwvzlkTc|7XLJQSVqiBqRXIn%iFANV2ak)GMjMj$@L1~UZe2`R0c(5s@-vL~n+~M*y-uKb{kiWWQ+)4_j{&>Q zvGx2^{)E{Z@}rl228bbcF@?@w9bQLYL=`+kAd5vFXCGQh^$N^w^PSMk#tJKgOb&^q z)Z_viEG(Xv+5J*=U#4tF=cMsOuLKm!bm}BHyngCHHGYMes^xnq0`jZunfDY5DEXw| z2GK}#dL$=kYC`T|a(ltQ)w2u@*YI8FglOnyJQ3?-QkqBqdy(>Gm0$ z{Zwn`1-HuikS$oTc!2#8itG5)H$?RA;b^i%zdH=%4LHAzBp0(?9yjuuXE#E=i*~Sk zvli;&`W)HJpxOwJYLUe};r>uxwM5c6WaFy-7{?)ER9 zb?vrJ_8xF=2L#aSb0oe6HWAXcYsVG9%tx$wFBYdj$2W>?e-#_y41kPln%^5$n7}1gcd~$^hF|h4K zq*T1DkD7y_N60r&JFcU>EvJpyZsW8)v#Texh2eL39&QQA*%jwlg=7{Ot-p8Ls<-?U zgwrS0Pt+}PUhhA0KhvoNh@cp>yH0${N|%67WvbCV(aVWj)euQrVj1k1IE7+pl0=pb zVmmP#EIUWLUJ>|YL&^E;^w*i!g;FqZqS z1ZYXY2P6DRF|9k?L}KxxASQLBln4LT7UjmODhft*f!>$j;-H(@t)mgfFFU_LBVH#` z_42-zal|yaBff%U;yD&JE1m4)-0;R8E}UCaxpVdsWo-``46J2O-}cKC@t1qrUzA3= zwOE(dFHjRXb9W!?S#;%7^3~j%$RYh|GCwRS}pIidF-TKC5n&>#qdfes?_Pu~Up) zkubsgSv$5C6BeyBrIj(2x)yoe_cvNleEt+vKb!3xzM+!?Dv+;D&-aZ#lsf>I5f4zj z$2*u5r~~bHJa0aeE|JA}#k}%!5OqK*I+tiO9Q&=IyK5rdIbuxmlgpvL_7Ko zeKaEJI1c>>pcqf^*;szvhEx$jbEv%iC^Z;nLMbK>k+i}S! z*}=mux>Yc}BTDSACCUvh6>Bz?Dgk%REAb}HxFO($%Sg1{S=eGQ!{lCwxSnE!rzyRo1S#u)=dcqR~l znQ02m&n4iq5XlU4cCVVi zSgY42NdyJ{pyxOlw6=Ft8fJwiY%s!H3)I>vjgh^<(-HKDaJm+fy|ws_D~6JXuZfjt z35D4~)jMj2{ntS?yZ1WH<;CV%HNi*u5n`uo#-KFnpA4>q3cCL<2EtbyI0Ikr?G904)nXRyc)b@Tig z$XFO^3-GTdHGl?$ycx*l-=8uBV3=ugNu-%sGrDnP%pj+uW=n$^reYT+=*8W5KK zw#Jh+fF9Jv&;W~}Ks7Ff8@B}9d9^ft4Sdjg~IrlF90 zbz3YDM~Di%Sc0VMZb^UCkDqOX)$vBX8}yY!k&&UEZxh5P3Naz7o|n9iW0+ zNmkhe&D$J?d|}YRjENA?$3;vO6KnszsNy<17xr4DW`S=ssO<=+aZPpxI-S#gw>=xP zhg`1z`UiG4`9kOqJV|`%H@MIB;F0Gg6CG0FywJby*FAfT15NHQA41U1BGPxy1(u zBcPBM>>vL=l0`KJPvy@w6Y+OUuh!qKboRD(rUVXE3mKk>2?RbKNqj?7C z7AIhU89YhGagUsxFEoT2v7ufEZHSR(65vxvg`<-c$0ema!H4WlEqFbb(n76>S(&G0 zrUo6=++sC!dD$posdZbp(?sF}Diu{;N3E%W%L}xUq-9IPOmnI>Y81zvE;BMJFSt=& z4wuV1Jr*uxzI*<|T{?-Q6`45!V?_9WR&pbQqA7`;(5cq?hE4M@$Z)o(Y3!FAxD{&~ zs^L2{N|&XGC`VNrV^Wuvt_ELHW9kO_-1q%44+2rP;_~3bOABQ(8Vm`zOp9n7aH0(P zy~OM|<5;V8Lg1%Rb01{ocP29*AW-|d-|?|}G_jirc)$1j>LAZtfUQcQx9_D^=1g%u zY_#uo!MjuU!ve2`U@ktgWEBS1c*rhIf=xFK-JJuVJ1SxCS~$i zLGBe98Mbfz%w<-4+A&&s=$Lb4B3%?_D#`rN;se`asNe#PcR}+ndj12MDe|jT&R`(7 z2!xFZf!Fn9Fr$8T`(Slg5A#im4o#eFvD?MQGJZzRdu%4~?dH_3g4jQP?CE!$ZEm4K8R-gb0nYZhs`mg;=3FK>8>1Tpm_>|0Zk_3! zg8oH*eQ%hvAuPH!TSQRh^HFYg(D}ktS@Ddf3$ERjNde{Nn-dlR;NRyNn#L1lc49>N$2!CQ*uWZnl5CoRY&H-t0CfpQn_rYpRV3-e2BYb3e?~9 zUhdf)wtJ@fX<*J=;w#Yrt+U-|tpv`rL`ob%x2Pm&jR#?+7f=Z`6;=86t_&sE;N92P z%>IvCVc9X8dv|y9;--!pjf}AAcFhjweX25Y69%A&+04=SrZ$P6IMb~^?;w}}{z8C}^f}t>LR|m-}1n32tw4yp9-Zo24wQwOQY%1IR1}BrGpiUmSV8z_M5_0>uD7M=%Y)o!WuDvC z+2+4l;$O8BgQFWKf*ih@k|>l`8HIGv5}xhe`a$X)ipK- z?+nG=fH2w0QuI4S38StL`OZ+9R6ke%hu;)o%L~TC&Qs|-CX79Qxc>`xm%90Po3q~mB~2?2ulkVZWsKX*SiWxThlyS{2dOY z`=!CUUF`x&`e?VtgkX1!X7L$=u_X@QM@uL4^eutxUPdsE71`q@?A~uebfu#{S)nzX z%cple#u?u`bHuQG@3<-Xn{?yAZ$>x4g)6dA+gX_@1c%n`g}%lM;i(2el5@ zzv);A0HEB~IuLM6gRgyvGD}K1w_IVv*hc+lk@@(d=^3K0Yf9x;vXZbqJFlgWdeK1R z*IbcGL`i+W!nvt}quIRWI?u@+M-8v7ojCqUV$WT)LNo$iFH8`UYAGeWIr6YLobTCt zktvspKKjjf%OvRe^C?&XEXbM~AiOm|0}XVUq4U0fQh#g3*2R6o;D|=Q8|D4!BeakI z1GWvuPJJs|+CSo-SZ8^ib1i?d--gd6us4>m5!WTee;>Q+j`(W&pbHk51HtqDxbu2A zQz-VWFZKoLcmRZz`n@)5H4OrDtrJyQ2I{+o=c|GhBpwD z0aO7tJ~;`3OyfR722@wm$;imyFzou|Sz_))71#O*zO8%hQkD=T&QPEJmK(t_d7!*uk58C@ zde3tSf63)hY3^XTa;XFh8i75n?;gUTPGB)v!4zU+D9vhbPL;NEp9u z7QndVW^X=e`P(OuwR$|Z|8d~)o2zH_er66GzxcvMs=H0Z$a zvDPgkRd_t9vMtYKra6kAD;K0iBprgWKalsfDLRMbiAUe}D($adN=mQh>iI_@Uit~= zv)ww!*4%!@P`Q~cpF9ZCnUgcq4dQ4SmR(E1^>lB+5(0XG3Z~^Zpo@UF&p}|{fC@P$ zUp|Yy@7ewx@WvRzma9`I?pnQL@uA7!U80f2f*tnvxG4AHdG$WZcFVk45cW?^*h3Z%PgXf+Sbf||b z0lZgbTmb*RT~q;D7q(*$IEXDitCY1Vzkoqma@2Y@b+n$Dj_BQ_Iu#Er$GbpLt! zn7nwOO3TKm8C6rK{|nOo-T9KodR3nYiC;91Tvk}Zu8LtU`Vw-VnRp)4#T~W-VXTK` zgP`xeF_oApKik->toENnnjG+7EAxluKAn`-eT0hsb=*0wx`Q-y(daKhxgi6f6wwlT zi~B3sio#|$Wd0BSH?z4b{8K3$@H}2$#`nFPhP~X+3%r5|j46i*9Qd%cCjoOeTu541 zU7uwWl$f3t@Owx{T8X$JYNjYPl@^@HxSXmEHS{zY7lUponNo6w6%PHJf~?tjt7 z=bi2u+g;A@?J@hpOT~Ly>k}36AI%ROuIdP#jq(7*UPzZ+F<4zWecR|x9O%7yQaQN? za?`*>j+=uQFn&Z}5d-D@r7fj7$tVQ@@xLJyV?XS%?f~ff)V{NlnU1Ch`WJV};@fx0 zNT*$3!mfV6qg&7=7@~eEiXjnV*Dm|qjo?O-JGs1|tppk%oEVgke!P&N*l`1vCo z2)u7Ue(k?8(!)z@7L0e0dJ*nAt9Z;|7s7a__7ZD`Q+tlq)Y@fT1Agt3`o1da$@m_d zzQ@z)?9jN6x-*vR`*bcbJ8X#y^{|PFr2~CB`7wXNA2<=yPp4%s`#1v%4eMp+LK7C= zBs#zs{gl6CAVvxfPLKO7!4j42com@Vz(VrKHg5eH<=nl{-H-kJ)pJSa&zCrM9jLsR zJk^kZU_b1T{=XPJ$O{v+U%(kK6>laE(*1KqBdjN>15SDsEE5T#Vw4A=Lz z_W}OBWxRd6DTpt;9qa3p{9Ny3QYU~@$jGFiUdC~=(H{-TYODZbG%7kuCQ#-a$HP{| z2#ReGqW6Rac~VFJSZWn5#vg@i?xJ}}^#CO?FT z|8fI$=?Bv;eE_E7zDkI5N=4Ui5uKO8_cIu0ip>qGhmE?jtLAKWV$4!iH?tja{y)cH zVjE9G{3zG#?A)m-B5lHsNtT5>lezz^l(T+|;tkjM?6Sbpsgx{T(p?KIAu0%hfPf&4 z3rZs;wSa`u3W(Cu1}T!#(k$IAAl)IkoZ)+&^B0_-=Gwh>c4pq1_j&H;bCcWvS?v`r zA@xN=H3V*eKdEZ$-p3B7s6kSr&&)6lijva$x0>B_qT;^4Ca-uB^O~f-Xe?NMV6zQ1 zdK1>n!P)l2XKk|{Y2zfAQl`#hbD82RX4P}58OSsV8KLyDiT%OHH3`;5HNtzRUwAf+ zsn3U0kU4+4Ghb@JAsS^E_A!_%blLrn;D!lH!sE}kA!Z5K?XD32nxRYPrNl`Fs_BK} z!qGo3e|}KX8~D^(*iKoH!_F=U<8`~Cgw(Lt3Z?AG@SGJ9x7~#0bi70LLhmIRJmFrS zn-aR|U~tGC<0hDT>b*T{lOrADv%79e&54^68RLnT4`iepLEYQezdw#GS@gp&O?)&n zdn!G?W{*B>zzGM^&EeX_$ED?C4KsYj?n@;X^q+b`TZnJa;vP|78zgKha&PY8GZ@j_D{^7Cxy*2KH%F17PN6P^hljI3<1@I3ckKwsPqD&(c($iQaMUVCJ^?zXf9oLWx#)E%5cO?r; zZs?&UC%`hMf>P^X@e$qA+qjf?7sfUk-Z^)y-FUBwP?8w(XvmH= zLE&#rb;l=8%na?9JvYInEKbrFZFS!Ay%|hv(o@5G2g=hbjjIl8&`S9RfAV?MCPzO3 z(=&}e!U6|!rjSSL1N31NS@BBD&2M1^))F<~Od@GZY={cb(u;3n)_#gv1tr73#+Qk` zMU(i+sh^s1mm{xh4zCwUQ1;*ik@;Ng!;qh+lu(VXsq#o|y}X|4qpDfMkxzy#6>;H{ zBHI^`NryW~>jmnb>6^o-;9wO=g=~QyZS)zWBN%zZh@hs@;ES)*geP0^hmRsWl8Mh0 zhXy6e>eyllrrw7$wC00r2k~j>Qdjo$eTj4kkdtDF_oYeY2QSQ3D-Bsj z!<#xvNf@88wJA_6V$Dh4r<5ACjB{YD)jD(u%u0Vka@k$nt;tw^{ZqVteT`5==3j(~ z%*UV720B(*&N9&QV*R>&+Djw%!H2xR+bYUy-IET9dn9$5-Li{cF}q>yRQ6sBzi9bh zi6CWy#XbI?o@SIMtPOPx)(CA&FGlPBYBy1W3s-_H>-&@0zKYEg^zh(){3JA9rq{)9 z6X);EI-&_8yzVunill+JJXT8i4|K*2+b~LLcYAes&4~)?&bEhZ?jZcXm|=>HF)?NG zK(L_s%$lcR-Hxli)ny8q=)N;ralNmlBW`N1JxvMHkYs8rrK4+S<3#j~CnrF#xag}f zN**4y*fK1GMuXzU;;Q}xM>K8i-9P>q5KiVK^^5z7Nrk!kfW4o0wv z`57T1bqo>65;E~w*QH{dW8);6L?{D-!!L}*feUVPbCdP5Y+OG6@*Vo>qE?UDX>GN;1Io-Xm-v#^g`1i}*?lO7dOy?z?@nZZ6Q9AksgOmj~ za(v=n0Y3bcI> z8M~d50c}$YsorO5ivMU&cXiZn*)Q5(cIXG0 z*}KUYZ{-wVPQ-7LivG-zmSjfagIf0dde&KWfTq@KxaHLJU63D(svM#0Fo-jb?rG>> zJ_`f~{P*LWQW94D#(u1_F>*1}Hi^ki(}mVHwIX&~Y@4rgB|Wcl>Oco^inmm?kIvgE z5KX_A!YoOIbz{`6Yky^HO|pf0`MjD2grBFrJybr-ws4Ha?U#F58AcHe5h+*&}9OHY#pGV!4Ua>tpjdc z{A#roy4)fA10rYIdU#7elEk&>Imtdzis5|h;v!33;g85CqPM%+lEerG`@nh&ramk1 zk$~O5-E#~Ik<@Lu+?@_@OSh0rimgW!gMgk#Kw+S(iEIq{qL5u%nv(P&wDHsahEQ=E z-oys)r2t^@334@Ed`S&hlGjxzqP$)Vog|gRZD?oxY*rqw>HawwpZfc{qU%hra(D65 zXHD4K`w*I<{x&I!Y`k2{O)3rWHMuBY@Gwc0aw}DYEPUgFV}PY16&E)_vkv%U3YgcG(Xofew=42H#1xf9KnZM9WCm8(0(yCfIm80*GhAFYMhe>ZNQ zL5E)uuQX8nF_~%=&tGn^s`+8rx>-dQNu?vC-qGzcsQ9WmsUHC^iS2ztqzbsea4NW_yZT)b-AjT3LJ@%<<1DOtX0PU zI&T>0Hj4wq6pPF73u4PcE1P2iVDC&Ye2}>F0q^CkrVe}*tx`+#2)$``m=9xrJ);20 z;35Unw?rBkU%-Xj6>psXYq{dhw+nKFC^+BPo`UEXq)m3w@mjO@LHjrmMYe7RwGrt) z2RaYFIycvGwl*A0#f@U5%7h5Avev{K9}=w^4orz&YS!xUucMY9c!N`x*X2?}rgrA> z1UbSBH%(ur&aqKQ@f$yBX74PX5>fLI#SALnmS7#s;V3rfs0i~~kG080xgYEO{rA&eP@{D+b}y>GNc zWv7!l{oXLq$Csc8FAt(kbs--&x0##1hQt0<4l=AJs;M&X?@7sS3sEXv?s+%2w>Gjh zhhM-7@3N?|_MB(0oc}r2-SfSniiXmDg2(Zk1Qz5@1zQoqnmzuR*PPv^&_0Uj!fI0OoKf{vGmZrlcSew(t5Y zbbGD6%1+LWv;iZQ3=`hJkKR0QPlU1+(Ft8KuOM}j^`53+$*oCGze?bNM1IrRAMV-X zLluS81T($byHw}&C8;>!4Eb2)hFH*_q+mK2f*Mc%omolzZoq{kF(~l?27f1NP49Ww z;e_v9ggDHmbWi_he00rV>iFKDairVkSnLag#*b`9El2zvFlgbsN2AD3geg%V@je+k zP!a6_v13bw6HijcwE-G|^nFz`0eNGB)6}g!TKoG;@TY;M^&b zCW<+l%fe^VSQEttTS6>gKcAVoS`&?fSN>cIYsEf+zRG$P@J4Yy@hv4y2PXo~9WE(OmN#qG1=g9>6z}(Tyi`=+XW)O<6)_ zr-V2;z<<5LZyO1?-Wdnur_V(M?}q|21{&b4hQgHQ51NhQN=J`+Yp3Ld&v)3}T+!k} zK&RW8Y>`jIM&sgRZkEH*4-nvoC3wUp5TnHi;k%tG%8epD#~Es~ zXANcenRLh*qXYQ1fsp~kXyzT3Q&oW4XDs~AeCl(os)w1U7{$@cACnJe9HWQ=rz*(` zTDr%o>$-bvPgk754<4O-8^tnKHQq&&^j~Mm46W8v&i$*!#Oh4>1VDmQP)h48CJE$#me%dRkJJ|1=mv8d+ z550WovSsEn3EHK-T`>%d3aI}nUL=>&?ovUkYoLq4$yR2+iPTPYN6E_BpZSxiRep2# zSmKNd32CqF;^uBT6D+5N!7}AP681GI-?pu^t#t%rhiB)AC)G%fkcIr^sW)JZ^-CDP zQ)RZd*{=kGeHEIPfnnb`ajj3P!ipuPiH77co*rQ{URppu-z2nG&D!e0Q!ecNHh8nJ z#p2?m9DRaFUE`Sb_HqHR1Lk+V_#F`snhPHphPfkh7l(ABUn3`>v4dW*Ys?v8X~7JS zM>|B<-C~&ph)}$5BrnRchh!)qsE8B!F%6g6{SxsZbYK)=U{UU`YS=wy_lo>l{Oq<4 z-8#~ajSHavV{+4Vp`W}GE*p>tXMHkjFS1r~YaU5GXP<_F(Wu{&9Bl7Gd~!t<-s<`| zayBqz|9j(Vyopd3nh^}sxA}0Nhs}U6M0dqFJZq67;jKrxe}8@ zr=II9DYh`KHil+n+m!cjI`C0A{UrWCjQ!jK&5dm z0i8%%>bvu<=&nJU)&&)v2;$so9-6!SFaR)JNyJMHar*<%! zs#;#9B7OC>8DY@@{kL->Wy5pZ+e+kS(6X7a*}#1J_@w*p>aDeka;WwDaHuy!W@1n= z<+u+H^lAZPFO5?NVj!Hmu7;J~>V?Rd2rtXVOu8Eh_uVUypu5J10kGHrN~syN({S{x z*6rcp!XY8}gIX zEQiu%1K##R(MEb5`er8q}o?5`#FleCFNIgJZH!VXi0ejxC$(7%dLlB$R zFB(M`=+N&`^R#dD#5T$yY5*D%C_?|F1XuA#+KhLe_VO(Ucq54P^~>9pHn z1ToJ7=ZS^5Qc!9-Yba)j>Yn02@YtKEBJ^Jag8J+$nUyT^DoMiL&3Ww+JaS*&9eHK+1`UC$U@j!E(G0TcNZx@ykAln|Tq{r`wKGte#9xbWQA{> z0C~BSj?EK+YVEG^WVCqGK;npO!~Dp0 z;!MPxaw({rD#4MBZ(1xHotCCLwB}NM#FHB2!hIxCqe_X{NWuun3jA>Q*;T$g-|AA# zTUB8Yj*4lZ{o@#ry^Kiy_^6@stTUYEd;f_^*lBZ~B(-T>DzRHN;Rhp=Ur^Rjhy|Pt z;0#7Jo3QHa3TRGk1-~m0rFo4P6>0nSCBD-t<)(F=P1OE;h=6*xN8O{*(#6&c4}#xz zh31NvPK9cm0Y})By2Z)h9Bq*H%a4I=$oO6G-Xuq~fO%(ta8~J@oqT$qYEP`4T1W0` z*OR%34tG!6Fy{GERK?kAOdKVQN@g*F-Jf8-%<5~fYsxG-%}b=zop3p9NqBMhV>L|1 z|C6wg5EMxF-Ih(2^XU5Od8O)LtyE+*v1tYJ9LIAd5#Z~sf2}7|VW3H?GQG9C4`%}U z&G5YINF`#ra~CZv2nUL7Rr=HaasAD3;=1RdghyDO1avU}ZRep7(yx${Y_JsQ`Vq%W zF5k|wkjlht-VPdxVbc{h1mT|4;eUx5oL@15C{CL(Cilj|1RBJG`!4^i?9HPQP1pJL zgSiXt?UV6eRcoW~ffetqKHRVO+n_FNKE9wy1ko@^{=--#6ZI|Ui`xGarGX}|`Xdj}M&t2xiHqi2&sM2fwJOw|gZSj9kVu$4q>0B>PTxB^}c^;-uE5?MYq4?O_lta`2 z)4(AJdV2BSbWo)^U5s*i;QB+?i&=RH9Gw(+;hf%x4qP|@;`m_d_%i}N`8r)HLqT9V zKUb&et*88{<{F6MHLxdOsPi9Yw1K3_^`HzmT-B|j4M9~i2X6)ILuWlL5U(j);H%O9 zgcsc#PJEEZ(gEZLM}68mtogNga~IMN|1_MoUvbo*ugp!@KfY}}eNd8iQOXOA z^pM^+2b>_8d=T*pipARikmCu~sloh2r6-#7O&-J$kRRM<>G?s^T~d)Q8|pa~nuE9D z*&6>V^6sO+bvE&>#v(8j0ugxOid)T&m7Du@c|4^NU-h1s z8d`f}(EGW~W6)Q`wNusLtNsVBO@`7GNa`n-A8n~pK#_PkR zpr4gP)@2UH7ka$f({Eu>tJ50~ZR@WwqhV(*AjhNs?_X|m1Ttb|#2`Hvj`ZGTm6Dd; zTU5d=UhC`8takmZ(I8rc-Rj^kPHWc+T=}5407}f+amS!#pqN})^nds6C!v5b_g*nr zbbfWbXV>A7h0(*NSs6=&`=guUpca+Y^tQcWfTe8m|3< zpc5ktVzjjgAsCq-yzru!PJcUAefR-*$Be0_3BMM>OOAS^#n9wJy@BJ^iZ`75FDX%F zcrLp?W9R1`|NUu}FJ=@cbk=MnAY)7jp@sRBRN~BP61}(J_mtxZeK&TlTY8ep4u%RL z@TK>do0!g24te@o9gwgq2_JxC2*{2_7$NW6Yg{c4kNw~mc3X@O$JCA3sJ?8J<(N-%`u?YSjKHLyb diff --git a/src/main/resources/assets/tinker/textures/gui/bookleftbackground.png b/src/main/resources/assets/tinker/textures/gui/bookleftbackground.png new file mode 100644 index 0000000000000000000000000000000000000000..29ee3746ad5c614dc8ecb204f61ebb4e4171a0b0 GIT binary patch literal 23305 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 E7Yh?KnE(I) diff --git a/src/main/resources/assets/tinker/textures/gui/bookrightbackground.png b/src/main/resources/assets/tinker/textures/gui/bookrightbackground.png new file mode 100644 index 0000000000000000000000000000000000000000..0bfb7966c702ffdf1bb39e5ff2dd4e5ca6f11446 GIT binary patch literal 18898 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 DsaQ~g literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/tinker/textures/gui/bookrightpage.png b/src/main/resources/assets/tinker/textures/gui/bookrightpage.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd470018e6058133fdcb9ea69431ecc55c566c4 GIT binary patch literal 20064 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 Date: Wed, 6 May 2026 21:34:22 +0800 Subject: [PATCH 10/34] add navigation button class --- .../java/tconstruct/client/TProxyClient.java | 3 + .../client/pages/NavigationPage.java | 92 ++++++++++++++ .../tconstruct/client/pages/TiCCoverPage.java | 56 +++++++++ .../tconstruct/library/util/TiCGuiManual.java | 113 +++++++++++------- .../library/util/TiCNavigationButton.java | 112 +++++++++++++++++ .../library/util/TiCTurnPageButton.java | 4 +- .../tconstruct/tools/ToolProxyClient.java | 5 + .../java/tconstruct/tools/items/Manual.java | 17 ++- .../tconstruct/tools/items/ManualInfo.java | 9 ++ .../resources/assets/tinker/lang/en_US.lang | 12 ++ .../assets/tinker/manuals/materialsandyou.xml | 17 +++ .../items/tinkerbook_materialsandyou.png | Bin 0 -> 2055 bytes 12 files changed, 387 insertions(+), 53 deletions(-) create mode 100644 src/main/java/tconstruct/client/pages/NavigationPage.java create mode 100644 src/main/java/tconstruct/client/pages/TiCCoverPage.java create mode 100644 src/main/java/tconstruct/library/util/TiCNavigationButton.java create mode 100644 src/main/resources/assets/tinker/manuals/materialsandyou.xml create mode 100644 src/main/resources/assets/tinker/textures/items/tinkerbook_materialsandyou.png diff --git a/src/main/java/tconstruct/client/TProxyClient.java b/src/main/java/tconstruct/client/TProxyClient.java index d94d884e18..738e2b5d0e 100644 --- a/src/main/java/tconstruct/client/TProxyClient.java +++ b/src/main/java/tconstruct/client/TProxyClient.java @@ -57,6 +57,7 @@ public void registerRenderer() { public static Document volume2; public static Document smelter; public static Document weaponry; + public static Document materialsandyou; public static ManualInfo manualData; public void readManuals() { @@ -77,6 +78,7 @@ private void readTinkersConstructManuals() { Document volume2_cl = readManual("/assets/tinker/manuals/" + CurrentLanguage + "/materials.xml", dbFactory); Document smelter_cl = readManual("/assets/tinker/manuals/" + CurrentLanguage + "/smeltery.xml", dbFactory); Document weaponry_cl = readManual("/assets/tinker/manuals/" + CurrentLanguage + "/weaponry.xml", dbFactory); + Document materialsandyou_cl = readManual("/assets/tinker/manuals/materialsandyou.xml", dbFactory); diary = diary_cl != null ? diary_cl : readManual("/assets/tinker/manuals/en_US/diary.xml", dbFactory); volume1 = volume1_cl != null ? volume1_cl : readManual("/assets/tinker/manuals/en_US/firstday.xml", dbFactory); @@ -84,6 +86,7 @@ private void readTinkersConstructManuals() { smelter = smelter_cl != null ? smelter_cl : readManual("/assets/tinker/manuals/en_US/smeltery.xml", dbFactory); weaponry = weaponry_cl != null ? weaponry_cl : readManual("/assets/tinker/manuals/en_US/weaponry.xml", dbFactory); + materialsandyou = materialsandyou_cl; manualData = new ManualInfo(); } diff --git a/src/main/java/tconstruct/client/pages/NavigationPage.java b/src/main/java/tconstruct/client/pages/NavigationPage.java new file mode 100644 index 0000000000..318396361e --- /dev/null +++ b/src/main/java/tconstruct/client/pages/NavigationPage.java @@ -0,0 +1,92 @@ +package tconstruct.client.pages; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import mantle.client.pages.BookPage; +import tconstruct.library.util.TiCNavigationButton; +import tconstruct.smeltery.TinkerSmeltery; +import tconstruct.tools.TinkerTools; + +public class NavigationPage extends BookPage { + + private int buttonStartIdx = 10; + + private List navigationButtonList; + + private static ItemStack[] icons = new ItemStack[] { new ItemStack(TinkerTools.craftingStationWood), + new ItemStack(Items.iron_pickaxe), new ItemStack(Items.iron_ingot), new ItemStack(Items.redstone), + new ItemStack(TinkerSmeltery.smeltery), new ItemStack(Items.bow) }; + + @Override + public void readPageFromXML(Element element) { + navigationButtonList = new ArrayList<>(); + NodeList buttonList = element.getElementsByTagName("button"); + for (int idx = 0; idx < buttonList.getLength(); idx++) { + Node b = buttonList.item(idx); + + String naviTo = ((Element) b).getAttribute("to"); + String tempText = b.getTextContent(); + if (StatCollector.canTranslate(tempText)) tempText = StatCollector.translateToLocal(tempText); + + navigationButtonList.add( + new TiCNavigationButton( + buttonStartIdx + navigationButtonList.size(), + TiCNavigationButton.ButtonSize.large, + icons[idx], + tempText, + naviTo)); + } + } + + public List updateButtonPositionAndRender(int startX, int startY, float scale, int mouseX, + int mouseY) { + // 2 row and 3 column + + int middleX = startX + 190 / 2; + int middleY = startY + 165 / 2; + int buttonGap = 5; + + int[] buttonYArray = new int[] { + middleY - buttonGap + - (int) (TiCNavigationButton.defaultHeight * TiCNavigationButton.ButtonSize.large.multi), + middleY + buttonGap }; + int[] buttonXArray = new int[] { + middleX - buttonGap + - (int) (TiCNavigationButton.defaultWidth * TiCNavigationButton.ButtonSize.large.multi * 1.5f), + middleX - (int) (TiCNavigationButton.defaultWidth * TiCNavigationButton.ButtonSize.large.multi * 0.5), + middleX + buttonGap + + (int) (TiCNavigationButton.defaultWidth * TiCNavigationButton.ButtonSize.large.multi + * 0.5f) }; + + for (int idx = 0; idx < navigationButtonList.size(); idx++) { + TiCNavigationButton b = navigationButtonList.get(idx); + int row = idx / 3; + int column = idx % 3; + + b.xPosition = (int) (buttonXArray[column] * scale); + b.yPosition = (int) (buttonYArray[row] * scale); + b.drawButtonWithScale(manual.mc, mouseX, mouseY, scale, manual.fonts); + } + // navigationButtonList.forEach(b -> { + // b.xPosition = (int) (startX * scale); + // b.yPosition = (int) (startY * scale); + // b.drawButtonWithScale(manual.mc, mouseX, mouseY, scale, manual.fonts); + // }); + return navigationButtonList; + } + + @Override + public void renderContentLayer(int localwidth, int localheight, boolean isTranslatable) { + this.updateButtonPositionAndRender(localheight, localheight, 1.0f, 0, 0); + } + +} diff --git a/src/main/java/tconstruct/client/pages/TiCCoverPage.java b/src/main/java/tconstruct/client/pages/TiCCoverPage.java new file mode 100644 index 0000000000..04bf20b99e --- /dev/null +++ b/src/main/java/tconstruct/client/pages/TiCCoverPage.java @@ -0,0 +1,56 @@ +package tconstruct.client.pages; + +import net.minecraft.util.StatCollector; + +import org.lwjgl.opengl.GL11; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import mantle.client.pages.BookPage; + +public class TiCCoverPage extends BookPage { + + // page height 165 + // page wdith 190 + + String[] innerText; + + @Override + public void readPageFromXML(Element element) { + NodeList nodes = element.getElementsByTagName("text"); + String tempText = nodes.item(0).getTextContent(); + if (StatCollector.canTranslate(tempText)) tempText = StatCollector.translateToLocal(tempText); + innerText = tempText.split("\\\\n"); + } + + private void drawStrCenterAt(String str, int X, int Y, float scale, int color) { + manual.fonts.drawString( + str, + (int) (X / scale - manual.fonts.getStringWidth(str) / 2), + (int) ((Y - manual.fonts.FONT_HEIGHT / 2) / scale), + color); + } + + @Override + public void renderContentLayer(int startX, int startY, boolean isTranslatable) { + + int cousorX = 190 / 2; + int cousorY = 165 * 3 / 7; + + float scale = 2.5f; + GL11.glScalef(scale, scale, 1.0f); + this.drawStrCenterAt(innerText[0], startX + cousorX, startY + cousorY, scale, 0x000000); + cousorY += manual.fonts.FONT_HEIGHT * scale; + GL11.glScalef(1.0f / scale, 1.0f / scale, 1.0f); + + scale = 1.0f; + GL11.glScalef(scale, scale, 1.0f); + this.drawStrCenterAt(innerText[1], startX + cousorX, startY + cousorY, scale, 0x000000); + cousorY += manual.fonts.FONT_HEIGHT * scale; + this.drawStrCenterAt(innerText[2], startX + cousorX, startY + cousorY, scale, 0x000000); + cousorY += manual.fonts.FONT_HEIGHT * scale; + GL11.glScalef(1.0f / scale, 1.0f / scale, 1.0f); + + } + +} diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index 8ad56c0ab7..9cfd9f761d 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -1,10 +1,12 @@ package tconstruct.library.util; +import java.util.ArrayList; +import java.util.List; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.oredict.OreDictionary; import org.lwjgl.opengl.GL11; import org.w3c.dom.Document; @@ -21,16 +23,16 @@ import mantle.client.gui.GuiManual; import mantle.client.pages.BookPage; import tconstruct.TConstruct; -import tconstruct.library.TConstructRegistry; +import tconstruct.client.pages.NavigationPage; import tconstruct.library.util.TiCTurnPageButton.ButtonType; @SideOnly(Side.CLIENT) public class TiCGuiManual extends GuiManual { private static final int ANIMATIONDURATIONINMILLIS = 600; - private static final double FLYIN_DURATION = 0.55; // portion for fly-in - private static final double OVERSHOOT_DURATION = 0.1; // portion for overshoot - private static final double EXTENT = 0.02; // overshoot amount as fraction of total displacement + private static final float FLYIN_DURATION = 0.55f; // portion for fly-in + private static final float OVERSHOOT_DURATION = 0.1f; // portion for overshoot + private static final float EXTENT = 0.02f; // overshoot amount as fraction of total displacement private static final float GUIMAXPERCENTAGE = 0.75f; // The maximum percentage that the manual GUI can occupy ItemStack itemstackBook; @@ -43,8 +45,6 @@ public class TiCGuiManual extends GuiManual { int maxPages; BookData bData; - private boolean isAnimationDone; - private TiCTurnPageButton buttonNextPage; private TiCTurnPageButton buttonPreviousPage; private TiCTurnPageButton buttonHomePage; @@ -63,6 +63,7 @@ public class TiCGuiManual extends GuiManual { private long guiOpenTime; + public float scale = 1.0f; private int baseDrawingX; private int baseDrawingY; BookPage pageLeft; @@ -70,6 +71,8 @@ public class TiCGuiManual extends GuiManual { public SmallFontRenderer fonts = MProxyClient.smallFontRenderer; + private List navigationButtonsList; + public TiCGuiManual(ItemStack stack, BookData data) { super(stack, data); this.mc = Minecraft.getMinecraft(); @@ -79,20 +82,18 @@ public TiCGuiManual(ItemStack stack, BookData data) { if (data.font != null) this.fonts = data.font; this.bData = data; this.guiOpenTime = System.currentTimeMillis(); - this.isAnimationDone = false; - TConstructRegistry.toolMaterialStrings.forEach( - (str, tm) -> { - System.out.println( - str + " - " + tm.localizationString + " - " + OreDictionary.getOres(tm.localizationString)); - }); - System.out.println(TConstructRegistry.getItemStack("flint")); + // TConstructRegistry.toolMaterialStrings.forEach((str, tm) -> { System.out.println(str + " - " + tm.name()); + // }); + // PatternBuilder.instance.materials.forEach(k -> System.out.println(k.key + " - " + + // k.item.getUnlocalizedName())); + // PatternBuilder.instance.materialSets.forEach((str, mset) -> System.out.println(str + " - " + mset)); // renderitem.renderInFrame = true; } /* - * @Override public void setWorldAndResolution (Minecraft minecraft, int w, int h) { this.guiParticles = new + * @Override publi c void setWorldAndResolution (Minecraft minecraft, int w, int h) { this.guiParticles = new * GuiParticle(minecraft); this.mc = minecraft; this.width = w; this.height = h; this.buttonList.clear(); * this.initGui(); } */ @@ -106,23 +107,20 @@ public void initGui() { 1, xPos + bookImageWidth - 50, (this.height + this.bookImageHeight) / 2 - 28, - ButtonType.nextPage, - bData)); + ButtonType.nextPage)); this.buttonList.add( this.buttonPreviousPage = new TiCTurnPageButton( 2, xPos - bookImageWidth + 24, (this.height + this.bookImageHeight) / 2 - 28, - ButtonType.previousPage, - bData)); + ButtonType.previousPage)); this.buttonList.add( this.buttonHomePage = new TiCTurnPageButton( 3, xPos - bookImageWidth - 24, this.height - this.bookImageHeight, - ButtonType.homePage, - bData)); + ButtonType.homePage)); updateButtonVisibility(); } @@ -134,7 +132,11 @@ private void updateButtonVisibility() { protected void actionPerformed(GuiButton button) { if (button.enabled) { - changePage(button.id); + if (button instanceof TiCTurnPageButton) { + changePage(button.id); + } else if (button instanceof TiCNavigationButton nb) { + TConstruct.logger.info("navigation to " + nb.target + ""); + } updateButtonVisibility(); ticUpdateText(); } @@ -200,24 +202,27 @@ private void changePage(int buttonId) { } } + public void setCurrentPage(int pageNum) { + this.currentPage = Math.min(Math.max(pageNum % 2 == 1 ? pageNum - 1 : pageNum, 0), maxPages - 2); + updateButtonVisibility(); + ticUpdateText(); + } + public void drawScreen(int par1, int par2, float par3) { - // aligen to center - // int localWidth = (this.width / 2); - // int localHeight = ((this.height - this.bookImageHeight) / 2); + navigationButtonsList = new ArrayList<>(); + this.buttonList.subList(3, this.buttonList.size()).clear(); - float scale = Math.max( + this.scale = Math.max( 0.95f, Math.min( this.width * GUIMAXPERCENTAGE / (this.bookImageWidth * 2), this.height * GUIMAXPERCENTAGE / this.bookImageHeight)); - if (!this.isAnimationDone) { - float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; - int[] point = this.getOvershootPosition(progress, scale); - this.baseDrawingX = point[0]; - this.baseDrawingY = point[1]; - if (progress >= 1) this.isAnimationDone = true; - } + float progress = (System.currentTimeMillis() - this.guiOpenTime) * 1.0f / ANIMATIONDURATIONINMILLIS; + + int[] point = this.getOvershootPosition(progress, scale); + this.baseDrawingX = point[0]; + this.baseDrawingY = point[1]; int drawX = (int) (this.baseDrawingX / scale); int drawY = (int) (this.baseDrawingY / scale); @@ -254,8 +259,24 @@ public void drawScreen(int par1, int par2, float par3) { if (pageLeft != null) pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); if (pageRight != null) pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); - if (pageLeft != null) pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); - if (pageRight != null) pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); + if (pageLeft != null) { + if (pageLeft instanceof NavigationPage np) { + navigationButtonsList + .addAll(np.updateButtonPositionAndRender(drawX + 16, drawY + 12, scale, par1, par2)); + } else { + pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); + } + } + if (pageRight != null) { + if (pageRight instanceof NavigationPage np) { + navigationButtonsList + .addAll(np.updateButtonPositionAndRender(drawX + 220, drawY + 12, scale, par1, par2)); + } else { + pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); + } + } + + this.buttonList.addAll(navigationButtonsList); GL11.glPopMatrix(); } @@ -319,29 +340,29 @@ private int[] getOvershootPosition(float progress, float scale) { int startY = (int) (this.height + this.bookImageHeight * scale); // Clamp progress to [0,1] - double t = Math.min(Math.max(progress, 0.0), 1.0); + float t = Math.min(Math.max(progress, 0.0f), 1.0f); - double factor; // displacement factor (0 → 1+EXTENT → 1) + float factor; // displacement factor (0 → 1+EXTENT → 1) if (t <= FLYIN_DURATION) { // Phase 1: linear fly in - double phaseT = t / FLYIN_DURATION; // [0,1] + float phaseT = t / FLYIN_DURATION; // [0,1] factor = phaseT; } else if (t <= FLYIN_DURATION + OVERSHOOT_DURATION) { // Phase 2: overshoot (1 → 1+EXTENT) with ease out - double phaseT = (t - FLYIN_DURATION) / OVERSHOOT_DURATION; // [0,1] - double eased = 1.0 - Math.pow(1.0 - phaseT, 2); - factor = 1.0 + EXTENT * eased; + float phaseT = (t - FLYIN_DURATION) / OVERSHOOT_DURATION; // [0,1] + float eased = (float) (1.0f - Math.pow(1.0f - phaseT, 2.0f)); + factor = 1.0f + EXTENT * eased; } else { // Phase 3: correct back to target (1+EXTENT → 1) linear - double remaining = 1.0 - (FLYIN_DURATION + OVERSHOOT_DURATION); - double phaseT = (t - (FLYIN_DURATION + OVERSHOOT_DURATION)) / remaining; // [0,1] - double peak = 1.0 + EXTENT; - factor = peak + (1.0 - peak) * phaseT; + float remaining = 1.0f - (FLYIN_DURATION + OVERSHOOT_DURATION); + float phaseT = (t - (FLYIN_DURATION + OVERSHOOT_DURATION)) / remaining; // [0,1] + float peak = 1.0f + EXTENT; + factor = peak + (1.0f - peak) * phaseT; } // Clamp factor to reasonable range (should stay inside [0, 1+EXTENT]) - factor = Math.min(factor, 1.0 + EXTENT); + factor = Math.min(factor, 1.0f + EXTENT); // Linear interpolation int x = (int) (startX + (endX - startX) * factor); diff --git a/src/main/java/tconstruct/library/util/TiCNavigationButton.java b/src/main/java/tconstruct/library/util/TiCNavigationButton.java new file mode 100644 index 0000000000..3acedb767d --- /dev/null +++ b/src/main/java/tconstruct/library/util/TiCNavigationButton.java @@ -0,0 +1,112 @@ +package tconstruct.library.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import mantle.client.SmallFontRenderer; + +public class TiCNavigationButton extends GuiButton { + + public enum ButtonSize { + + small(0.5f), + large(2f), + medium(1f); + + public float multi; + + ButtonSize(float multi) { + this.multi = multi; + } + } + + public static int defaultHeight = 20; + public static int defaultWidth = 20; + + RenderItem itemRender = new RenderItem(); + ButtonSize bs; + ItemStack renderStack; + public String target; + public String ButtonStr; + + public TiCNavigationButton(int id, ButtonSize bs, ItemStack s, String ButtonStr, String target) { + super(id, 0, 0, defaultHeight, defaultWidth, ""); + this.bs = bs; + this.renderStack = s; + this.ButtonStr = ButtonStr; + this.target = target; + } + + public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scale, SmallFontRenderer fonts) { + if (this.visible) { + this.height = (int) (defaultHeight * this.bs.multi * scale); + this.width = (int) (defaultWidth * this.bs.multi * scale); + + boolean isMouseInButton = mouseX >= this.xPosition && mouseY >= this.yPosition + && mouseX < this.xPosition + this.width + && mouseY < this.yPosition + this.height; + + if (isMouseInButton) { + GuiButton.drawRect( + (int) (this.xPosition / scale), + (int) (this.yPosition / scale), + (int) ((this.xPosition / scale + defaultWidth * this.bs.multi)), + (int) ((this.yPosition / scale + defaultHeight * this.bs.multi)), + 0xAAAAAAAA); + } + + this.drawStrCenterAt( + this.ButtonStr, + (int) (this.xPosition + this.width / 2), + (int) (this.yPosition + this.height), + scale, + 0x000000, + fonts); + this.drawItem(mc, scale); + } + } + + private void drawStrCenterAt(String str, int X, int Y, float scale, int color, SmallFontRenderer fonts) { + fonts.drawString( + str, + Math.round(X / scale - fonts.getStringWidth(str) / 2), + Math.round(Y / scale - fonts.FONT_HEIGHT), + color); + } + + private void drawItem(final Minecraft mc, float scale) { + GL11.glPushMatrix(); + RenderHelper.enableGUIStandardItemLighting(); + this.zLevel = 100.0F; + this.itemRender.zLevel = 100.0F; + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + GL11.glScalef(2.0f, 2.0f, 1.0f); + this.itemRender.renderItemAndEffectIntoGUI( + mc.fontRenderer, + mc.renderEngine, + this.renderStack, + Math.round(this.xPosition / scale / 2) + 2, + Math.round(this.yPosition / scale / 2) + 1); + this.itemRender.renderItemOverlayIntoGUI( + mc.fontRenderer, + mc.renderEngine, + this.renderStack, + Math.round(this.xPosition / scale / 2) + 2, + Math.round(this.yPosition / scale / 2) + 1); + GL11.glScalef(0.5f, 0.5f, 1.0f); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_BLEND); + this.itemRender.zLevel = 0.0F; + this.zLevel = 0.0F; + RenderHelper.disableStandardItemLighting(); + GL11.glPopMatrix(); + } + +} diff --git a/src/main/java/tconstruct/library/util/TiCTurnPageButton.java b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java index 543d1f90ff..905b274f19 100644 --- a/src/main/java/tconstruct/library/util/TiCTurnPageButton.java +++ b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java @@ -6,8 +6,6 @@ import org.lwjgl.opengl.GL11; -import mantle.books.BookData; - public class TiCTurnPageButton extends GuiButton { enum ButtonType { @@ -39,7 +37,7 @@ enum ButtonType { "tinker", "textures/gui/bookleftbackground.png"); - public TiCTurnPageButton(int id, int xPosition, int yPosition, ButtonType buttonType, BookData data) { + public TiCTurnPageButton(int id, int xPosition, int yPosition, ButtonType buttonType) { super(id, xPosition, yPosition, buttonType.textureWidth, buttonType.textureHeight, ""); this.buttonType = buttonType; } diff --git a/src/main/java/tconstruct/tools/ToolProxyClient.java b/src/main/java/tconstruct/tools/ToolProxyClient.java index 40132c9d79..b40dbe5305 100644 --- a/src/main/java/tconstruct/tools/ToolProxyClient.java +++ b/src/main/java/tconstruct/tools/ToolProxyClient.java @@ -36,6 +36,8 @@ import tconstruct.client.entity.projectile.LaunchedItemRender; import tconstruct.client.pages.MaterialPage; import tconstruct.client.pages.ModifierPage; +import tconstruct.client.pages.NavigationPage; +import tconstruct.client.pages.TiCCoverPage; import tconstruct.client.pages.ToolPage; import tconstruct.common.TProxyCommon; import tconstruct.library.TConstructRegistry; @@ -321,6 +323,9 @@ public void registerManualIcons() { MProxyClient.registerManualPage("materialstats", MaterialPage.class); MProxyClient.registerManualPage("toolpage", ToolPage.class); MProxyClient.registerManualPage("modifier", ModifierPage.class); + + MProxyClient.registerManualPage("cover", TiCCoverPage.class); + MProxyClient.registerManualPage("navigation", NavigationPage.class); } void registerManualRecipes() { diff --git a/src/main/java/tconstruct/tools/items/Manual.java b/src/main/java/tconstruct/tools/items/Manual.java index af7c4ccabd..05fb4d3eb8 100644 --- a/src/main/java/tconstruct/tools/items/Manual.java +++ b/src/main/java/tconstruct/tools/items/Manual.java @@ -22,9 +22,10 @@ public class Manual extends CraftingItem { - static String[] name = new String[] { "beginner", "toolstation", "smeltery", "diary", "weaponry" }; + static String[] name = new String[] { "beginner", "toolstation", "smeltery", "diary", "weaponry", + "materialsandyou" }; static String[] textureName = new String[] { "tinkerbook_diary", "tinkerbook_toolstation", "tinkerbook_smeltery", - "tinkerbook_blue", "tinkerbook_green" }; + "tinkerbook_blue", "tinkerbook_green", "tinkerbook_materialsandyou" }; public Manual() { super(name, textureName, "", "tinker", TConstructRegistry.materialTab); @@ -55,8 +56,10 @@ private static String getBookName(int bookItemDamage) { case 0 -> "tconstruct.manual.beginner"; case 1 -> "tconstruct.manual.toolstation"; case 2 -> "tconstruct.manual.smeltery"; + case 3 -> "tconstruct.manual.diary"; case 4 -> "tconstruct.manual.weaponry"; - default -> "tconstruct.manual.diary"; + case 5 -> "tconstruct.manual.materialsandyou"; + default -> "tconstruct.manual.materialsandyou"; }; } @@ -76,9 +79,15 @@ public void addInformation(ItemStack stack, EntityPlayer player, List li case 4: list.add(McTextFormatter.addItalic(StatCollector.translateToLocal("manual4.tooltip"))); break; - default: + case 5: list.add(McTextFormatter.addItalic(StatCollector.translateToLocal("manual5.tooltip"))); break; + case 6: + list.add(McTextFormatter.addItalic(StatCollector.translateToLocal("manual6.tooltip"))); + break; + default: + list.add(McTextFormatter.addItalic(StatCollector.translateToLocal("manual6.tooltip"))); + break; } } } diff --git a/src/main/java/tconstruct/tools/items/ManualInfo.java b/src/main/java/tconstruct/tools/items/ManualInfo.java index c4238869d2..3453c57f04 100644 --- a/src/main/java/tconstruct/tools/items/ManualInfo.java +++ b/src/main/java/tconstruct/tools/items/ManualInfo.java @@ -60,6 +60,15 @@ public ManualInfo() { side == Side.CLIENT ? TProxyClient.weaponry : null, "tinker:tinkerbook_green", 0x27CD1B)); + + BookDataStore.addBook( + initManual( + new TiCBookData(), + "tconstruct.manual.materialsandyou", + "\u00a7o" + StatCollector.translateToLocal("manual6.tooltip"), + side == Side.CLIENT ? TProxyClient.materialsandyou : null, + "tinker:tinkerbook_materialsandyou", + 0xEB00EF)); } public TiCBookData initManual(TiCBookData data, String unlocName, String toolTip, Document xmlDoc, String itemImage, diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index 63cc3221bb..d9c77476c6 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -516,6 +516,7 @@ item.tconstruct.manual.toolstation.name=Materials and You: Volume 2 item.tconstruct.manual.smeltery.name=Mighty Smelting item.tconstruct.manual.diary.name=Diary of a Tinker item.tconstruct.manual.weaponry.name=Tinkers' Weaponry +item.tconstruct.manual.materialsandyou.name=Materials and You item.tconstruct.bucket.name=Bucket item.tconstruct.bucket.Iron.name=Molten Iron Bucket @@ -816,6 +817,7 @@ manual2.tooltip=By: Skyla manual3.tooltip=By: Thruul M'gon manual4.tooltip=By: Sheriff Bownana manual5.tooltip=By: Nameless Tinker +manual5.tooltip=By: MCTBL searedtank1.tooltip=Contains searedtank2.tooltip=Keeps any fluids it has when harvested searedtank3.tooltip=Heart of the Smeltery @@ -1195,3 +1197,13 @@ tconstruct.mobsinfocompat.tinkers_construct_beheading_1=If you are using a Cleav #Baubles compat (Baubles Expanded already has the relevant localizations) baubletype.any=Equippable in a §aRing§7 slot + + +#manual text +tconstruct.manual.materialsandyou.homepage=Materials and You\nThis is all of what you need in TiC\nBy MCTBL +tconstruct.manual.materialsandyou.jumptointro=Introduce +tconstruct.manual.materialsandyou.jumptotools=Tools +tconstruct.manual.materialsandyou.jumptomaterials=Materials +tconstruct.manual.materialsandyou.jumptomodifies=Modifies +tconstruct.manual.materialsandyou.jumptosmeltery=Smeltery +tconstruct.manual.materialsandyou.jumptobowmaterials=Bow Materials \ No newline at end of file diff --git a/src/main/resources/assets/tinker/manuals/materialsandyou.xml b/src/main/resources/assets/tinker/manuals/materialsandyou.xml new file mode 100644 index 0000000000..13dc16f552 --- /dev/null +++ b/src/main/resources/assets/tinker/manuals/materialsandyou.xml @@ -0,0 +1,17 @@ + + + + +tconstruct.manual.materialsandyou.homepage + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/assets/tinker/textures/items/tinkerbook_materialsandyou.png b/src/main/resources/assets/tinker/textures/items/tinkerbook_materialsandyou.png new file mode 100644 index 0000000000000000000000000000000000000000..c291600cb6a31957b2f1d0a18a595a948380a10c GIT binary patch literal 2055 zcmbVNeQXnD81MLUt62ufmk`}?`#@yZ`&ietM++Nm*(!97t-z*;T<_kt$J)E|?zVOd z2HDtTA%jT_L54VD@DDLl6vGx|AVy69VZs~`L6HxY1w_JdN?`N7t!uyxBwTX2_r3c) zzvuUSywBAa7UU)Br|NY&U7{=BQ3Ri3wL5-{P8S#GIo=C52~vKkqSHP3ly=AIwr-oE z(~bU$_mrq5?u9ffh71fRdVwJlk|0{Av(Al33|j_N#0&hqU_-C(JAfiQXG51}xe2#q z2LV36N(RMM1s=AljJ0s++&PFfLPLTOP#Gi=3JMAxv7rOJG+b-1aTFPVsAV=ZS96Gz zxC;@xC<7$RV8U3^n1y6p45TU3Xt87<6hWGC!ikv zaA!jUsw&Yq9u9{M;Y@=l`*G4@vET%SQxpafm{KXIOav2@lpzKOP*|ClR9+Mijgj$+ z<*E&ZN(Vy-NikYMiKYoA4397pP8tX;qyZqu#&A-(92{`Yu{a2V5D-)aV#yd*3W%zx z1jGkW$3EZZ0H)UMj`Wr3COIporx%3!D{DW{MV#MB8P+ zsG{r<#o$n(3Wp>kcDq&>3-a7jUf{&AGV>lA;9yi>Ln(qXVMG>2m^>6oQ(1H-HH$FQ z1ThG8iyZH(91faE(WL1;+jE#ZuXr$!H`o#>kME&&Zmyfsr#>vb{t0 z4v{U_iaTV_L3_gN^O-Fyi5UsTi?NiE!Yq&gBfVadB`L4jWTJ-bUzB-xxR~H$^Jqs- z>k2xbS75y=qlcmxycS&rd1RmwXol4q+=jARWdVmqU-QFc;L#!&qzwlEBz;J^2Vsin zQ^Sl5a{Vw{kJ3^2gY+v*#lzJwW*|Un8P46W{WliFQQz%y+vGHc!Nt#%qi=bpjXllk9N1W_bwUH+C@1N&fog`%Jo(Kr7e?tIcuYIu&+Bp z&%Cf^?b)NEvPyRB-<3J}yTa?;3*7~uy^Q@LByOEowlwu%=OyEv%dpgpe zKd$Xs&AaP;1ZIzOA6c>b^rBNEKbdfiTG@~`#hsbkBUZ)m@2m$SgpGH*rozleU#Jpcdz literal 0 HcmV?d00001 From 5c0a62337ec7308d0d908eaaefd9354c3134d13a Mon Sep 17 00:00:00 2001 From: MCTBL Date: Thu, 7 May 2026 11:05:30 +0800 Subject: [PATCH 11/34] add tooltips for manual button --- .../client/pages/NavigationPage.java | 24 +++----- .../tconstruct/library/util/TiCGuiButton.java | 25 +++++++++ .../tconstruct/library/util/TiCGuiManual.java | 11 ++++ .../library/util/TiCNavigationButton.java | 53 ++++++++++-------- .../library/util/TiCTurnPageButton.java | 28 +++++---- .../resources/assets/tinker/lang/en_US.lang | 8 +++ .../items/tinkerbook_materialsandyou.png | Bin 2055 -> 2262 bytes 7 files changed, 100 insertions(+), 49 deletions(-) create mode 100644 src/main/java/tconstruct/library/util/TiCGuiButton.java diff --git a/src/main/java/tconstruct/client/pages/NavigationPage.java b/src/main/java/tconstruct/client/pages/NavigationPage.java index 318396361e..152e97a88a 100644 --- a/src/main/java/tconstruct/client/pages/NavigationPage.java +++ b/src/main/java/tconstruct/client/pages/NavigationPage.java @@ -13,6 +13,7 @@ import mantle.client.pages.BookPage; import tconstruct.library.util.TiCNavigationButton; +import tconstruct.library.util.TiCNavigationButton.ButtonSize; import tconstruct.smeltery.TinkerSmeltery; import tconstruct.tools.TinkerTools; @@ -26,6 +27,8 @@ public class NavigationPage extends BookPage { new ItemStack(Items.iron_pickaxe), new ItemStack(Items.iron_ingot), new ItemStack(Items.redstone), new ItemStack(TinkerSmeltery.smeltery), new ItemStack(Items.bow) }; + private static final ButtonSize BS = ButtonSize.large; + @Override public void readPageFromXML(Element element) { navigationButtonList = new ArrayList<>(); @@ -40,7 +43,7 @@ public void readPageFromXML(Element element) { navigationButtonList.add( new TiCNavigationButton( buttonStartIdx + navigationButtonList.size(), - TiCNavigationButton.ButtonSize.large, + BS, icons[idx], tempText, naviTo)); @@ -55,17 +58,12 @@ public List updateButtonPositionAndRender(int startX, int s int middleY = startY + 165 / 2; int buttonGap = 5; - int[] buttonYArray = new int[] { - middleY - buttonGap - - (int) (TiCNavigationButton.defaultHeight * TiCNavigationButton.ButtonSize.large.multi), + int[] buttonYArray = new int[] { middleY - buttonGap - (int) (TiCNavigationButton.defaultHeight * BS.multi), middleY + buttonGap }; int[] buttonXArray = new int[] { - middleX - buttonGap - - (int) (TiCNavigationButton.defaultWidth * TiCNavigationButton.ButtonSize.large.multi * 1.5f), - middleX - (int) (TiCNavigationButton.defaultWidth * TiCNavigationButton.ButtonSize.large.multi * 0.5), - middleX + buttonGap - + (int) (TiCNavigationButton.defaultWidth * TiCNavigationButton.ButtonSize.large.multi - * 0.5f) }; + middleX - buttonGap - (int) (TiCNavigationButton.defaultWidth * BS.multi * 1.5f), + middleX - (int) (TiCNavigationButton.defaultWidth * BS.multi * 0.5), + middleX + buttonGap + (int) (TiCNavigationButton.defaultWidth * BS.multi * 0.5f) }; for (int idx = 0; idx < navigationButtonList.size(); idx++) { TiCNavigationButton b = navigationButtonList.get(idx); @@ -76,11 +74,7 @@ public List updateButtonPositionAndRender(int startX, int s b.yPosition = (int) (buttonYArray[row] * scale); b.drawButtonWithScale(manual.mc, mouseX, mouseY, scale, manual.fonts); } - // navigationButtonList.forEach(b -> { - // b.xPosition = (int) (startX * scale); - // b.yPosition = (int) (startY * scale); - // b.drawButtonWithScale(manual.mc, mouseX, mouseY, scale, manual.fonts); - // }); + return navigationButtonList; } diff --git a/src/main/java/tconstruct/library/util/TiCGuiButton.java b/src/main/java/tconstruct/library/util/TiCGuiButton.java new file mode 100644 index 0000000000..5c353aca1b --- /dev/null +++ b/src/main/java/tconstruct/library/util/TiCGuiButton.java @@ -0,0 +1,25 @@ +package tconstruct.library.util; + +import java.util.List; + +import net.minecraft.client.gui.GuiButton; + +public abstract class TiCGuiButton extends GuiButton { + + public List toolTips; + + public TiCGuiButton(int stateName, int id, int p_i1021_3_, int p_i1021_4_, int p_i1021_5_, String p_i1021_6_) { + super(stateName, id, p_i1021_3_, p_i1021_4_, p_i1021_5_, p_i1021_6_); + } + + public boolean isHover(int mouseX, int mouseY) { + return mouseX >= this.xPosition && mouseY >= this.yPosition + && mouseX < this.xPosition + this.width + && mouseY < this.yPosition + this.height; + } + + public List getTooltips() { + return this.toolTips; + } + +} diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index 9cfd9f761d..8bd16bed25 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -279,6 +279,17 @@ public void drawScreen(int par1, int par2, float par3) { this.buttonList.addAll(navigationButtonsList); GL11.glPopMatrix(); + this.renderTooltips(par1, par2); + } + + void renderTooltips(int mouseX, int mouseY) { + List tooltip = new ArrayList(); + this.buttonList.forEach(b -> { + if (b instanceof TiCGuiButton tgb && tgb.isHover(mouseX, mouseY)) { + tooltip.addAll(tgb.getTooltips()); + } + }); + this.drawHoveringText(tooltip, mouseX, mouseY, fontRendererObj); } /** diff --git a/src/main/java/tconstruct/library/util/TiCNavigationButton.java b/src/main/java/tconstruct/library/util/TiCNavigationButton.java index 3acedb767d..468d304930 100644 --- a/src/main/java/tconstruct/library/util/TiCNavigationButton.java +++ b/src/main/java/tconstruct/library/util/TiCNavigationButton.java @@ -1,17 +1,21 @@ package tconstruct.library.util; +import java.util.Arrays; +import java.util.List; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import mantle.client.SmallFontRenderer; -public class TiCNavigationButton extends GuiButton { +public class TiCNavigationButton extends TiCGuiButton { public enum ButtonSize { @@ -35,12 +39,20 @@ public enum ButtonSize { public String target; public String ButtonStr; + private final static String PATTERN = StatCollector.translateToLocal("tconstruct.manual.button.tooltip.navigatto"); + public TiCNavigationButton(int id, ButtonSize bs, ItemStack s, String ButtonStr, String target) { + this(id, bs, s, ButtonStr, target, Arrays.asList(String.format(PATTERN, ButtonStr))); + } + + public TiCNavigationButton(int id, ButtonSize bs, ItemStack s, String ButtonStr, String target, + List tooltips) { super(id, 0, 0, defaultHeight, defaultWidth, ""); this.bs = bs; this.renderStack = s; this.ButtonStr = ButtonStr; this.target = target; + this.toolTips = tooltips; } public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scale, SmallFontRenderer fonts) { @@ -48,9 +60,7 @@ public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scal this.height = (int) (defaultHeight * this.bs.multi * scale); this.width = (int) (defaultWidth * this.bs.multi * scale); - boolean isMouseInButton = mouseX >= this.xPosition && mouseY >= this.yPosition - && mouseX < this.xPosition + this.width - && mouseY < this.yPosition + this.height; + boolean isMouseInButton = this.isHover(mouseX, mouseY); if (isMouseInButton) { GuiButton.drawRect( @@ -61,25 +71,22 @@ public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scal 0xAAAAAAAA); } - this.drawStrCenterAt( + // let string a half size of multi + GL11.glScalef(this.bs.multi / 2, this.bs.multi / 2, 1.0f); + fonts.drawString( this.ButtonStr, - (int) (this.xPosition + this.width / 2), - (int) (this.yPosition + this.height), - scale, - 0x000000, - fonts); + Math.round( + (this.xPosition + this.width / 2) / scale / this.bs.multi * 2 + - fonts.getStringWidth(this.ButtonStr) / 2), + Math.round((this.yPosition + this.height) / scale / this.bs.multi * 2 - fonts.FONT_HEIGHT), + 0x000000); + // resize back + GL11.glScalef(2.0f, 2.0f, 1.0f); this.drawItem(mc, scale); + GL11.glScalef(1.0f / this.bs.multi, 1.0f / this.bs.multi, 1.0f); } } - private void drawStrCenterAt(String str, int X, int Y, float scale, int color, SmallFontRenderer fonts) { - fonts.drawString( - str, - Math.round(X / scale - fonts.getStringWidth(str) / 2), - Math.round(Y / scale - fonts.FONT_HEIGHT), - color); - } - private void drawItem(final Minecraft mc, float scale) { GL11.glPushMatrix(); RenderHelper.enableGUIStandardItemLighting(); @@ -87,20 +94,18 @@ private void drawItem(final Minecraft mc, float scale) { this.itemRender.zLevel = 100.0F; GL11.glEnable(GL11.GL_LIGHTING); GL11.glEnable(GL12.GL_RESCALE_NORMAL); - GL11.glScalef(2.0f, 2.0f, 1.0f); this.itemRender.renderItemAndEffectIntoGUI( mc.fontRenderer, mc.renderEngine, this.renderStack, - Math.round(this.xPosition / scale / 2) + 2, - Math.round(this.yPosition / scale / 2) + 1); + Math.round(this.xPosition / scale / this.bs.multi) + 2, + Math.round(this.yPosition / scale / this.bs.multi)); this.itemRender.renderItemOverlayIntoGUI( mc.fontRenderer, mc.renderEngine, this.renderStack, - Math.round(this.xPosition / scale / 2) + 2, - Math.round(this.yPosition / scale / 2) + 1); - GL11.glScalef(0.5f, 0.5f, 1.0f); + Math.round(this.xPosition / scale / this.bs.multi) + 2, + Math.round(this.yPosition / scale / this.bs.multi)); GL11.glDisable(GL11.GL_LIGHTING); GL11.glEnable(GL11.GL_BLEND); this.itemRender.zLevel = 0.0F; diff --git a/src/main/java/tconstruct/library/util/TiCTurnPageButton.java b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java index 905b274f19..7cced0c02a 100644 --- a/src/main/java/tconstruct/library/util/TiCTurnPageButton.java +++ b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java @@ -1,30 +1,36 @@ package tconstruct.library.util; +import java.util.Arrays; +import java.util.List; + import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiButton; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; import org.lwjgl.opengl.GL11; -public class TiCTurnPageButton extends GuiButton { +public class TiCTurnPageButton extends TiCGuiButton { enum ButtonType { - nextPage(0, 16, 18, 10), - previousPage(0, 26, 18, 10), - backToJumpFrom(0, 36, 18, 10), - homePage(0, 0, 14, 16); + nextPage(0, 16, 18, 10, "nextPage"), + previousPage(0, 26, 18, 10, "previousPage"), + backToJumpFrom(0, 36, 18, 10, "backToJumpFrom"), + homePage(0, 0, 14, 16, "homePage"); int textureX; int textureY; int textureWidth; int textureHeight; + List tooltips; - ButtonType(int textureX, int textureY, int textureWidth, int textureHeight) { + ButtonType(int textureX, int textureY, int textureWidth, int textureHeight, String tooltips) { this.textureX = textureX; this.textureY = textureY; this.textureWidth = textureWidth; this.textureHeight = textureHeight; + this.tooltips = Arrays + .asList(StatCollector.translateToLocal("tconstruct.manual.button.tooltip." + tooltips)); } } @@ -51,9 +57,7 @@ public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scal this.width = (int) (this.buttonType.textureWidth * scale); this.height = (int) (this.buttonType.textureHeight * scale); - boolean isMouseInButton = mouseX >= this.xPosition && mouseY >= this.yPosition - && mouseX < this.xPosition + this.width - && mouseY < this.yPosition + this.height; + boolean isMouseInButton = this.isHover(mouseX, mouseY); mc.getTextureManager().bindTexture(background); @@ -75,4 +79,8 @@ public void drawButtonWithScale(Minecraft mc, int mouseX, int mouseY, float scal } } + @Override + public List getTooltips() { + return this.buttonType.tooltips; + } } diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index d9c77476c6..fc18c06e1f 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -1199,6 +1199,14 @@ tconstruct.mobsinfocompat.tinkers_construct_beheading_1=If you are using a Cleav baubletype.any=Equippable in a §aRing§7 slot +#manual button +tconstruct.manual.button.tooltip.nextPage=Next Page +tconstruct.manual.button.tooltip.previousPage=Previous Page +tconstruct.manual.button.tooltip.backToJumpFrom=Back Ward +tconstruct.manual.button.tooltip.homePage=Home Page +tconstruct.manual.button.tooltip.navigatto=Jump to %s Page + + #manual text tconstruct.manual.materialsandyou.homepage=Materials and You\nThis is all of what you need in TiC\nBy MCTBL tconstruct.manual.materialsandyou.jumptointro=Introduce diff --git a/src/main/resources/assets/tinker/textures/items/tinkerbook_materialsandyou.png b/src/main/resources/assets/tinker/textures/items/tinkerbook_materialsandyou.png index c291600cb6a31957b2f1d0a18a595a948380a10c..69ee0324dbd9dd04296f1b2333862e2a06bff400 100644 GIT binary patch delta 689 zcmZn{xF$Hkf{AVNMyp;XF7prrODiK|D-+Af7nziix&N2~RLl&M49rX{Om)*NQcQJC z4Na1DEfY;sb?MVq znHxn;3N>YBIB;c&XPW=lVa&~#7PKPzrG|*C&UwDMS2WX%EcU3HvdBjowM-CTT9nar z_;qy6mH?S`&b8Cc>}0>p*86^^cwhCo@0^;d3@T2Zk!PfXc9`!gUoF3+{-Ta@jD_gw zgm0^Q7?vbSGD!X16)-0_^o;bUqkFFlIf!g}Z6tf1$)N1>@sHfG*He|Ie0lKiRfUj9 zXFyP%UT$GUiNo4xMcMN~uft|Y%}*=OmyTZ?FYdNkhjH1ld9^M;uc%m?f#r|mQ-w9IJO94fC2(|)V(xLJ z2mDFaVu`w|bn18im^e{A-+V@GP4C8w#VuPk+%~UK(w*w%RJ-PGo;T20io4&*el9rj zf8OB@2j(}pXlUxs-G8R}W;?@;zN7E%nf2EF6>*=V!jPkvt9ikfIiW7CasBW4oY{e9 z_4n3jD$d`%;bn!`?TsQA%XF-or`?ikIJdy{fV_(NcBiZf6Vujroe$kVY4-uYg^PBz zZ(T9#&YFFy9^8roD80>elF{r5}E+YMkPN0 delta 565 zcmV-50?Pf?5r+_vI06O3u{wUcUS;(>(R%x`miazwqWGZ)QJ@9IoVPP1Dr z;cg9@LTgtfz|`b4^{&ps%pxDYzH_D@{d3mww-{v+_T$#oJ96dvI>#qRn17bR%9|yj zR4mW0Vw+(r2>L?Y-nk}3xu8kYGVpr*n3h4%7gCZX64$Gb8!SDz%Z0Iv1brd2c7@q+ z3V@QnCDdS6RZ6|MC)YAXXPZYY{&ycn3I3Fb2NH7p(ggQY4*@VOgWYP0)}VO?BTfSV zHuKvmX}bZCjpgVc9uV|}*nfEcND;a1gPn_JFfBs?P0L_^*iqL5us`hJ_4rwyUnMzA zOLgSgSdN?d8|)7|^bZfzKC-c#>aMjb0L+F{T%Ne%EFl?5^Wy1Co;-i73KnJ-36DqF zsyqXr(W^0b?mUfepM|4|Hjy2TUJc+k^V9_YyT%{piQqEMT%hp)015yANkvXXu0mjf Dv?l{W From 717adf0f3db6899ee92ad69328959a840aa27bdd Mon Sep 17 00:00:00 2001 From: MCTBL Date: Thu, 7 May 2026 23:48:23 +0800 Subject: [PATCH 12/34] add new tic crafting page --- .../client/pages/NavigationPage.java | 60 ++--- .../client/pages/TiCButtonBookPage.java | 34 +++ .../tconstruct/client/pages/TiCCoverPage.java | 7 +- .../client/pages/TiCCraftingPage.java | 250 ++++++++++++++++++ .../tconstruct/client/pages/TiCTextPage.java | 26 ++ .../client/TConstructClientRegistry.java | 56 ++++ .../tconstruct/library/util/TiCGuiButton.java | 8 +- .../tconstruct/library/util/TiCGuiManual.java | 57 ++-- .../library/util/TiCNavigationButton.java | 25 +- .../library/util/TiCTurnPageButton.java | 17 +- .../tconstruct/tools/ToolProxyClient.java | 4 + .../assets/tinker/.vscode/settings.json | 4 + .../resources/assets/tinker/lang/en_US.lang | 11 +- .../assets/tinker/manuals/materialsandyou.xml | 85 +++++- 14 files changed, 543 insertions(+), 101 deletions(-) create mode 100644 src/main/java/tconstruct/client/pages/TiCButtonBookPage.java create mode 100644 src/main/java/tconstruct/client/pages/TiCCraftingPage.java create mode 100644 src/main/java/tconstruct/client/pages/TiCTextPage.java create mode 100644 src/main/resources/assets/tinker/.vscode/settings.json diff --git a/src/main/java/tconstruct/client/pages/NavigationPage.java b/src/main/java/tconstruct/client/pages/NavigationPage.java index 152e97a88a..6746790b14 100644 --- a/src/main/java/tconstruct/client/pages/NavigationPage.java +++ b/src/main/java/tconstruct/client/pages/NavigationPage.java @@ -3,59 +3,46 @@ import java.util.ArrayList; import java.util.List; -import net.minecraft.init.Items; +import net.minecraft.client.gui.GuiButton; import net.minecraft.item.ItemStack; import net.minecraft.util.StatCollector; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import mantle.client.pages.BookPage; +import tconstruct.TConstruct; +import tconstruct.library.client.TConstructClientRegistry; import tconstruct.library.util.TiCNavigationButton; import tconstruct.library.util.TiCNavigationButton.ButtonSize; -import tconstruct.smeltery.TinkerSmeltery; -import tconstruct.tools.TinkerTools; -public class NavigationPage extends BookPage { - - private int buttonStartIdx = 10; - - private List navigationButtonList; - - private static ItemStack[] icons = new ItemStack[] { new ItemStack(TinkerTools.craftingStationWood), - new ItemStack(Items.iron_pickaxe), new ItemStack(Items.iron_ingot), new ItemStack(Items.redstone), - new ItemStack(TinkerSmeltery.smeltery), new ItemStack(Items.bow) }; +public class NavigationPage extends TiCButtonBookPage { private static final ButtonSize BS = ButtonSize.large; @Override public void readPageFromXML(Element element) { - navigationButtonList = new ArrayList<>(); + this.pageButtonList = new ArrayList<>(); NodeList buttonList = element.getElementsByTagName("button"); for (int idx = 0; idx < buttonList.getLength(); idx++) { - Node b = buttonList.item(idx); + Element b = (Element) buttonList.item(idx); - String naviTo = ((Element) b).getAttribute("to"); - String tempText = b.getTextContent(); + String naviTo = b.getAttribute("to"); + String tempText = b.getElementsByTagName("text").item(0).getTextContent(); if (StatCollector.canTranslate(tempText)) tempText = StatCollector.translateToLocal(tempText); - navigationButtonList.add( - new TiCNavigationButton( - buttonStartIdx + navigationButtonList.size(), - BS, - icons[idx], - tempText, - naviTo)); + String iconStr = b.getElementsByTagName("icon").item(0).getTextContent(); + ItemStack iconStack = TConstructClientRegistry.getOrRegisterManualIcon(iconStr); + + this.pageButtonList.add(new TiCNavigationButton(0, BS, iconStack, tempText, naviTo, this)); } } - public List updateButtonPositionAndRender(int startX, int startY, float scale, int mouseX, - int mouseY) { + public void updateButtonPositionAndRender(int startX, int startY, float scale, int mouseX, int mouseY, + List parentButtonList) { // 2 row and 3 column - int middleX = startX + 190 / 2; - int middleY = startY + 165 / 2; + int middleX = startX + PAGECONTENTWIDTH / 2; + int middleY = startY + PAGECONTENTHEIGHT / 2; int buttonGap = 5; int[] buttonYArray = new int[] { middleY - buttonGap - (int) (TiCNavigationButton.defaultHeight * BS.multi), @@ -65,22 +52,27 @@ public List updateButtonPositionAndRender(int startX, int s middleX - (int) (TiCNavigationButton.defaultWidth * BS.multi * 0.5), middleX + buttonGap + (int) (TiCNavigationButton.defaultWidth * BS.multi * 0.5f) }; - for (int idx = 0; idx < navigationButtonList.size(); idx++) { - TiCNavigationButton b = navigationButtonList.get(idx); + for (int idx = 0; idx < this.pageButtonList.size(); idx++) { + TiCNavigationButton b = (TiCNavigationButton) this.pageButtonList.get(idx); int row = idx / 3; int column = idx % 3; + b.id = idx + parentButtonList.size(); b.xPosition = (int) (buttonXArray[column] * scale); b.yPosition = (int) (buttonYArray[row] * scale); b.drawButtonWithScale(manual.mc, mouseX, mouseY, scale, manual.fonts); } - return navigationButtonList; + if (parentButtonList != null) { + parentButtonList.addAll(this.pageButtonList); + } } @Override - public void renderContentLayer(int localwidth, int localheight, boolean isTranslatable) { - this.updateButtonPositionAndRender(localheight, localheight, 1.0f, 0, 0); + public void actionPerformed(GuiButton button) { + TiCNavigationButton b = (TiCNavigationButton) button; + TConstruct.logger.info(b.target + " is clicked"); + } } diff --git a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java new file mode 100644 index 0000000000..d5f0656b48 --- /dev/null +++ b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java @@ -0,0 +1,34 @@ +package tconstruct.client.pages; + +import java.util.List; + +import net.minecraft.client.gui.GuiButton; + +import mantle.client.pages.BookPage; +import tconstruct.library.util.TiCGuiButton; + +public abstract class TiCButtonBookPage extends BookPage { + + public static final int PAGECONTENTHEIGHT = 165; + public static final int PAGECONTENTWIDTH = 190; + + List pageButtonList; + + public void updateButtonPositionAndRender(int startX, int startY, float scale, int mouseX, int mouseY, + List parentButtonList) { + updateButtonPosition(startX, startY, scale, mouseX, mouseY, parentButtonList); + render(startX, startY, scale, mouseX, mouseY, parentButtonList); + } + + public void updateButtonPosition(int startX, int startY, float scale, int mouseX, int mouseY, + List parentButtonList) {} + + public void render(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) {} + + @Override + public void renderContentLayer(int localwidth, int localheight, boolean isTranslatable) { + this.updateButtonPositionAndRender(localheight, localheight, 1.0f, 0, 0, null); + } + + public void actionPerformed(GuiButton button) {} +} diff --git a/src/main/java/tconstruct/client/pages/TiCCoverPage.java b/src/main/java/tconstruct/client/pages/TiCCoverPage.java index 04bf20b99e..6eccf3f3a2 100644 --- a/src/main/java/tconstruct/client/pages/TiCCoverPage.java +++ b/src/main/java/tconstruct/client/pages/TiCCoverPage.java @@ -10,9 +10,6 @@ public class TiCCoverPage extends BookPage { - // page height 165 - // page wdith 190 - String[] innerText; @Override @@ -34,8 +31,8 @@ private void drawStrCenterAt(String str, int X, int Y, float scale, int color) { @Override public void renderContentLayer(int startX, int startY, boolean isTranslatable) { - int cousorX = 190 / 2; - int cousorY = 165 * 3 / 7; + int cousorX = TiCButtonBookPage.PAGECONTENTWIDTH / 2; + int cousorY = TiCButtonBookPage.PAGECONTENTHEIGHT * 3 / 7; float scale = 2.5f; GL11.glScalef(scale, scale, 1.0f); diff --git a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java new file mode 100644 index 0000000000..242b4e1d30 --- /dev/null +++ b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java @@ -0,0 +1,250 @@ +package tconstruct.client.pages; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import tconstruct.library.client.TConstructClientRegistry; +import tconstruct.library.util.TiCTurnPageButton; +import tconstruct.library.util.TiCTurnPageButton.ButtonType; +import tconstruct.util.McTextFormatter; + +public class TiCCraftingPage extends TiCButtonBookPage { + + String title; + ItemStack target; + IRecipe[] recipes; + + int selectedIdx; + TiCTurnPageButton previousRecipeButton; + TiCTurnPageButton nextRecipeButton; + + private static final ResourceLocation background = new ResourceLocation("mantle", "textures/gui/bookcrafting.png"); + + @Override + public void readPageFromXML(Element element) { + this.pageButtonList = new ArrayList<>(); + NodeList nodes = element.getElementsByTagName("text"); + + if (nodes != null) this.title = nodes.item(0).getTextContent(); + if (StatCollector.canTranslate(this.title)) this.title = StatCollector.translateToLocal(this.title); + + nodes = element.getElementsByTagName("icon"); + if (nodes != null) { + this.recipes = TConstructClientRegistry.getOrRegisterRecipeIcon(nodes.item(0).getTextContent()); + this.target = TConstructClientRegistry.getOrRegisterManualIcon(nodes.item(0).getTextContent()); + } + this.selectedIdx = 0; + + this.pageButtonList + .add(this.previousRecipeButton = new TiCTurnPageButton(0, 0, 0, ButtonType.previousPage, this)); + this.pageButtonList.add(this.nextRecipeButton = new TiCTurnPageButton(0, 0, 0, ButtonType.nextPage, this)); + } + + private void drawStrCenterAt(String str, int X, int Y, float scale, int color) { + manual.fonts.drawString( + str, + (int) (X / scale - manual.fonts.getStringWidth(str) / 2), + (int) ((Y - manual.fonts.FONT_HEIGHT / 2) / scale), + color); + } + + @Override + public void updateButtonPosition(int startX, int startY, float scale, int mouseX, int mouseY, + List parentButtonList) { + this.previousRecipeButton.id = parentButtonList.size(); + this.nextRecipeButton.id = parentButtonList.size() + 1; + + this.previousRecipeButton.xPosition = (int) ((startX + this.previousRecipeButton.getWidth() * 0.5f) * scale); + this.nextRecipeButton.xPosition = (int) ((startX + PAGECONTENTWIDTH - this.nextRecipeButton.getWidth() * 1.5f) + * scale); + + this.previousRecipeButton.yPosition = (int) ((startY + 15) * scale); + this.nextRecipeButton.yPosition = (int) ((startY + 15) * scale); + + this.updateVisible(); + } + + @Override + public void render(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) { + + this.previousRecipeButton.drawButtonWithScale(manual.mc, mouseX, mouseY, scale); + this.nextRecipeButton.drawButtonWithScale(manual.mc, mouseX, mouseY, scale); + + IRecipe selectedRecipe = this.recipes[this.selectedIdx]; + String craftingType = ""; + ItemStack[] inputs = new ItemStack[0]; + int recipeSize = 0; + if (selectedRecipe instanceof ShapedOreRecipe sor) { + craftingType = "ShapedOreRecipe"; + List a = new ArrayList<>(); + for (Object b : Arrays.asList(sor.getInput())) { + if (b instanceof List l) { + a.add((ItemStack) l.get(0)); + } else if (b instanceof ItemStack l) { + a.add(l); + } else { + a.add(null); + } + } + inputs = a.toArray(inputs); + recipeSize = getWidth(sor); + } else if (selectedRecipe instanceof ShapelessOreRecipe sor) { + craftingType = "ShapelessOreRecipe"; + List a = new ArrayList<>(); + for (Object b : Arrays.asList(sor.getInput())) { + if (b instanceof List l) { + a.add((ItemStack) l.get(0)); + } else if (b instanceof ItemStack l) { + a.add(l); + } + } + inputs = a.toArray(inputs); + } else if (selectedRecipe instanceof ShapedRecipes sr) { + craftingType = "ShapedRecipes"; + inputs = sr.recipeItems; + recipeSize = Math.max(sr.recipeWidth, sr.recipeHeight); + } else if (selectedRecipe instanceof ShapelessRecipes sr) { + craftingType = "ShapelessRecipes"; + inputs = sr.recipeItems.toArray(inputs); + } + recipeSize = recipeSize == 0 ? (inputs.length > 4 ? 3 : 2) : recipeSize; + + craftingType = StatCollector.translateToLocal("tconstruct.manual.materialsandyou.recipetype." + craftingType); + + if (title != null) this.drawStrCenterAt( + McTextFormatter.addUnderLine(title), + startX + PAGECONTENTWIDTH / 2, + startY + 4, + 1.0f, + 0x000000); + this.drawStrCenterAt(craftingType, startX + PAGECONTENTWIDTH / 2, startY + 15, 1.0f, 0x000000); + + GL11.glScalef(2f, 2f, 2f); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + RenderHelper.enableGUIStandardItemLighting(); + manual.renderitem.zLevel = 100; + + if (recipeSize == 2) { + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + target, + (startX + 126) / 2, + (startY + 68) / 2); + if (target.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + target, + (startX + 126) / 2, + (startY + 68) / 2, + String.valueOf(target.stackSize)); + for (int i = 0; i < inputs.length; i++) { + if (inputs[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + inputs[i], + (startX + 14 + 36 * (i % 2)) / 2, + (startY + 36 * (i / 2) + 52) / 2); + } + } + + if (recipeSize == 3) { + int biasX = startX + (side != 1 ? 6 : 0); + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + target, + (biasX + 138) / 2, + (startY + 70) / 2); + if (target.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + target, + (biasX + 126) / 2, + (startY + 68) / 2, + String.valueOf(target.stackSize)); + for (int i = 0; i < inputs.length; i++) { + if (inputs[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + inputs[i], + (biasX - 2 + 36 * (i % 3)) / 2, + (startY + 36 * (i / 3) + 34) / 2); + } + } + + manual.renderitem.zLevel = 0; + GL11.glScalef(0.5F, 0.5F, 0.5F); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + + this.renderBackgroundLayer(startX, startY, recipeSize); + + if (parentButtonList != null) { + parentButtonList.addAll(pageButtonList); + } + } + + public void renderBackgroundLayer(int localwidth, int localheight, int recipeSize) { + if (recipeSize == 2) drawBackground(recipeSize, localwidth, localheight); + + if (recipeSize == 3) drawBackground(recipeSize, localwidth + (side != 1 ? 6 : 0), localheight); + } + + public void drawBackground(int size, int localWidth, int localHeight) { + manual.getMC().getTextureManager().bindTexture(background); + if (size == 2) manual.drawTexturedModalRect(localWidth + 8, localHeight + 46, 0, 116, 154, 78); + if (size == 3) manual.drawTexturedModalRect(localWidth - 8, localHeight + 28, 0, 0, 183, 114); + } + + @Override + public void actionPerformed(GuiButton button) { + TiCTurnPageButton b = (TiCTurnPageButton) button; + if (b == this.previousRecipeButton) { + this.selectedIdx -= 1; + } else if (b == this.nextRecipeButton) { + this.selectedIdx += 1; + } + this.selectedIdx = Math.min(this.recipes.length - 1, Math.max(selectedIdx, 0)); + this.updateVisible(); + } + + void updateVisible() { + this.previousRecipeButton.visible = this.selectedIdx != 0; + this.nextRecipeButton.visible = this.selectedIdx != this.recipes.length - 1; + } + + private static int getWidth(ShapedOreRecipe sor) { + try { + Field widthField = sor.getClass().getDeclaredField("width"); + widthField.setAccessible(true); + int width = widthField.getInt(sor); + Field heightField = sor.getClass().getDeclaredField("height"); + heightField.setAccessible(true); + int height = heightField.getInt(sor); + return Math.max(width, height); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + return -1; + } + } + +} diff --git a/src/main/java/tconstruct/client/pages/TiCTextPage.java b/src/main/java/tconstruct/client/pages/TiCTextPage.java new file mode 100644 index 0000000000..ac299bd617 --- /dev/null +++ b/src/main/java/tconstruct/client/pages/TiCTextPage.java @@ -0,0 +1,26 @@ +package tconstruct.client.pages; + +import net.minecraft.util.StatCollector; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import mantle.client.pages.BookPage; + +public class TiCTextPage extends BookPage { + + String text; + + @Override + public void readPageFromXML(Element element) { + NodeList nodes = element.getElementsByTagName("text"); + if (nodes != null) text = nodes.item(0).getTextContent(); + if (StatCollector.canTranslate(text)) text = StatCollector.translateToLocal(text); + } + + @Override + public void renderContentLayer(int localWidth, int localHeight, boolean IsTranslatable) { + manual.fonts.drawSplitString(text, localWidth, localHeight, 178, 0); + } + +} diff --git a/src/main/java/tconstruct/library/client/TConstructClientRegistry.java b/src/main/java/tconstruct/library/client/TConstructClientRegistry.java index 90acbab48a..eab9514309 100644 --- a/src/main/java/tconstruct/library/client/TConstructClientRegistry.java +++ b/src/main/java/tconstruct/library/client/TConstructClientRegistry.java @@ -2,10 +2,16 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import net.minecraft.init.Items; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; + +import com.google.common.collect.Maps; import mantle.lib.client.MantleClientRegistry; import tconstruct.library.TConstructRegistry; @@ -19,6 +25,7 @@ public class TConstructClientRegistry { public static ArrayList toolButtons = new ArrayList<>(20); public static ArrayList tierTwoButtons = new ArrayList<>(); public static Map manualIcons = new HashMap<>(); + public static Map recipeIcons = Maps.newHashMap(); public static ItemStack defaultStack = new ItemStack(Items.iron_ingot); public static void addMaterialRenderMapping(int materialID, String domain, String renderName, @@ -113,6 +120,55 @@ public static void registerManualSmeltery(String name, ItemStack output, ItemSta MantleClientRegistry.recipeIcons.put(name, recipe); } + public static boolean checkHadManualIconRegistered(String name) { + return manualIcons.containsKey(name); + } + + public static void registerManualIcon(String name, ItemStack stack) { + manualIcons.put(name, stack); + } + + public static ItemStack getManualIcon(String name) { + return manualIcons.get(name); + } + + public static ItemStack getOrRegisterManualIcon(String name) { + if (!checkHadManualIconRegistered(name)) { + String[] icon = name.split(":"); + String iconStackName = name; + int iconDamage = 0; + if (icon.length == 3) { + iconStackName = icon[0] + ":" + icon[1]; + iconDamage = Integer.parseInt(icon[2]); + } + ItemStack tempStack = new ItemStack((Item) Item.itemRegistry.getObject(iconStackName), 1, iconDamage); + registerManualIcon(name, tempStack); + } + return getManualIcon(name); + } + + public static IRecipe[] getOrRegisterRecipeIcon(String name) { + if (!recipeIcons.containsKey(name)) { + ItemStack outPutStack = getOrRegisterManualIcon(name); + List recipes = new ArrayList<>(); + for (IRecipe i : CraftingManager.getInstance().getRecipeList()) { + ItemStack output = i.getRecipeOutput(); + if (output != null && output.isItemEqual(outPutStack)) recipes.add(i); + } + recipeIcons.put(name, recipes.toArray(new IRecipe[] {})); + } + return recipeIcons.get(name); + } + + // private static ItemStack[] combine(ItemStack single, ItemStack[] array) { + // ItemStack[] result = new ItemStack[1 + array.length]; + // result[0] = single; + // for (int i = 0; i < array.length; i++) { + // result[i + 1] = array[i]; + // } + // return result; + // } + // Gui public static void addStencilButton(StencilGuiElement element) { stencilButtons.add(element); diff --git a/src/main/java/tconstruct/library/util/TiCGuiButton.java b/src/main/java/tconstruct/library/util/TiCGuiButton.java index 5c353aca1b..442769b17f 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiButton.java +++ b/src/main/java/tconstruct/library/util/TiCGuiButton.java @@ -4,12 +4,18 @@ import net.minecraft.client.gui.GuiButton; +import tconstruct.client.pages.TiCButtonBookPage; + public abstract class TiCGuiButton extends GuiButton { + public TiCButtonBookPage parentPage; public List toolTips; + public boolean needRenderTips = true; - public TiCGuiButton(int stateName, int id, int p_i1021_3_, int p_i1021_4_, int p_i1021_5_, String p_i1021_6_) { + public TiCGuiButton(int stateName, int id, int p_i1021_3_, int p_i1021_4_, int p_i1021_5_, String p_i1021_6_, + TiCButtonBookPage parentPage) { super(stateName, id, p_i1021_3_, p_i1021_4_, p_i1021_5_, p_i1021_6_); + this.parentPage = parentPage; } public boolean isHover(int mouseX, int mouseY) { diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index 8bd16bed25..06cacd79ae 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -23,7 +23,7 @@ import mantle.client.gui.GuiManual; import mantle.client.pages.BookPage; import tconstruct.TConstruct; -import tconstruct.client.pages.NavigationPage; +import tconstruct.client.pages.TiCButtonBookPage; import tconstruct.library.util.TiCTurnPageButton.ButtonType; @SideOnly(Side.CLIENT) @@ -71,8 +71,6 @@ public class TiCGuiManual extends GuiManual { public SmallFontRenderer fonts = MProxyClient.smallFontRenderer; - private List navigationButtonsList; - public TiCGuiManual(ItemStack stack, BookData data) { super(stack, data); this.mc = Minecraft.getMinecraft(); @@ -107,20 +105,23 @@ public void initGui() { 1, xPos + bookImageWidth - 50, (this.height + this.bookImageHeight) / 2 - 28, - ButtonType.nextPage)); + ButtonType.nextPage, + null)); this.buttonList.add( this.buttonPreviousPage = new TiCTurnPageButton( 2, xPos - bookImageWidth + 24, (this.height + this.bookImageHeight) / 2 - 28, - ButtonType.previousPage)); + ButtonType.previousPage, + null)); this.buttonList.add( this.buttonHomePage = new TiCTurnPageButton( 3, xPos - bookImageWidth - 24, this.height - this.bookImageHeight, - ButtonType.homePage)); + ButtonType.homePage, + null)); updateButtonVisibility(); } @@ -132,13 +133,15 @@ private void updateButtonVisibility() { protected void actionPerformed(GuiButton button) { if (button.enabled) { - if (button instanceof TiCTurnPageButton) { - changePage(button.id); - } else if (button instanceof TiCNavigationButton nb) { - TConstruct.logger.info("navigation to " + nb.target + ""); + if (button instanceof TiCGuiButton tgb) { + if (tgb.parentPage != null) { + tgb.parentPage.actionPerformed(button); + } else { + changePage(button.id); + updateButtonVisibility(); + ticUpdateText(); + } } - updateButtonVisibility(); - ticUpdateText(); } } @@ -209,7 +212,6 @@ public void setCurrentPage(int pageNum) { } public void drawScreen(int par1, int par2, float par3) { - navigationButtonsList = new ArrayList<>(); this.buttonList.subList(3, this.buttonList.size()).clear(); this.scale = Math.max( @@ -257,27 +259,23 @@ public void drawScreen(int par1, int par2, float par3) { this.drawButtons(par1, par2, scale); - if (pageLeft != null) pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); - if (pageRight != null) pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); if (pageLeft != null) { - if (pageLeft instanceof NavigationPage np) { - navigationButtonsList - .addAll(np.updateButtonPositionAndRender(drawX + 16, drawY + 12, scale, par1, par2)); + if (pageLeft instanceof TiCButtonBookPage tbbp) { + tbbp.updateButtonPositionAndRender(drawX + 16, drawY + 12, scale, par1, par2, this.buttonList); } else { pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); + pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); } } if (pageRight != null) { - if (pageRight instanceof NavigationPage np) { - navigationButtonsList - .addAll(np.updateButtonPositionAndRender(drawX + 220, drawY + 12, scale, par1, par2)); + if (pageRight instanceof TiCButtonBookPage tbbp) { + tbbp.updateButtonPositionAndRender(drawX + 220, drawY + 12, scale, par1, par2, this.buttonList); } else { pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); + pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); } } - this.buttonList.addAll(navigationButtonsList); - GL11.glPopMatrix(); this.renderTooltips(par1, par2); } @@ -285,7 +283,7 @@ public void drawScreen(int par1, int par2, float par3) { void renderTooltips(int mouseX, int mouseY) { List tooltip = new ArrayList(); this.buttonList.forEach(b -> { - if (b instanceof TiCGuiButton tgb && tgb.isHover(mouseX, mouseY)) { + if (b instanceof TiCGuiButton tgb && tgb.isHover(mouseX, mouseY) && tgb.needRenderTips && tgb.visible) { tooltip.addAll(tgb.getTooltips()); } }); @@ -316,17 +314,6 @@ public void drawButtons(int mouseX, int mouseY, float scale) { this.buttonNextPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonPreviousPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonHomePage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); - - // copy from @GuiScreen.drawScreen - // int k; - - // for (k = 0; k < this.buttonList.size(); ++k) { - // ((GuiButton) this.buttonList.get(k)).drawButton(this.mc, mouseX, mouseY); - // } - - // for (k = 0; k < this.labelList.size(); ++k) { - // ((GuiLabel) this.labelList.get(k)).func_146159_a(this.mc, mouseX, mouseY); - // } } public Minecraft getMC() { diff --git a/src/main/java/tconstruct/library/util/TiCNavigationButton.java b/src/main/java/tconstruct/library/util/TiCNavigationButton.java index 468d304930..735618d298 100644 --- a/src/main/java/tconstruct/library/util/TiCNavigationButton.java +++ b/src/main/java/tconstruct/library/util/TiCNavigationButton.java @@ -1,5 +1,6 @@ package tconstruct.library.util; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -8,12 +9,12 @@ import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.item.ItemStack; -import net.minecraft.util.StatCollector; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import mantle.client.SmallFontRenderer; +import tconstruct.client.pages.TiCButtonBookPage; public class TiCNavigationButton extends TiCGuiButton { @@ -39,15 +40,21 @@ public enum ButtonSize { public String target; public String ButtonStr; - private final static String PATTERN = StatCollector.translateToLocal("tconstruct.manual.button.tooltip.navigatto"); - - public TiCNavigationButton(int id, ButtonSize bs, ItemStack s, String ButtonStr, String target) { - this(id, bs, s, ButtonStr, target, Arrays.asList(String.format(PATTERN, ButtonStr))); + public TiCNavigationButton(int id, ButtonSize bs, ItemStack s, String ButtonStr, String target, + TiCButtonBookPage parentPage) { + this( + id, + bs, + s, + ButtonStr, + target, + ButtonStr.length() != 0 ? Arrays.asList(ButtonStr) : new ArrayList<>(), + parentPage); } public TiCNavigationButton(int id, ButtonSize bs, ItemStack s, String ButtonStr, String target, - List tooltips) { - super(id, 0, 0, defaultHeight, defaultWidth, ""); + List tooltips, TiCButtonBookPage parentPage) { + super(id, 0, 0, defaultHeight, defaultWidth, "", parentPage); this.bs = bs; this.renderStack = s; this.ButtonStr = ButtonStr; @@ -99,13 +106,13 @@ private void drawItem(final Minecraft mc, float scale) { mc.renderEngine, this.renderStack, Math.round(this.xPosition / scale / this.bs.multi) + 2, - Math.round(this.yPosition / scale / this.bs.multi)); + Math.round(this.yPosition / scale / this.bs.multi) + (this.ButtonStr.length() == 0 ? 2 : 0)); this.itemRender.renderItemOverlayIntoGUI( mc.fontRenderer, mc.renderEngine, this.renderStack, Math.round(this.xPosition / scale / this.bs.multi) + 2, - Math.round(this.yPosition / scale / this.bs.multi)); + Math.round(this.yPosition / scale / this.bs.multi) + (this.ButtonStr.length() == 0 ? 2 : 0)); GL11.glDisable(GL11.GL_LIGHTING); GL11.glEnable(GL11.GL_BLEND); this.itemRender.zLevel = 0.0F; diff --git a/src/main/java/tconstruct/library/util/TiCTurnPageButton.java b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java index 7cced0c02a..8987e32e75 100644 --- a/src/main/java/tconstruct/library/util/TiCTurnPageButton.java +++ b/src/main/java/tconstruct/library/util/TiCTurnPageButton.java @@ -9,9 +9,11 @@ import org.lwjgl.opengl.GL11; +import tconstruct.client.pages.TiCButtonBookPage; + public class TiCTurnPageButton extends TiCGuiButton { - enum ButtonType { + public enum ButtonType { nextPage(0, 16, 18, 10, "nextPage"), previousPage(0, 26, 18, 10, "previousPage"), @@ -43,11 +45,20 @@ enum ButtonType { "tinker", "textures/gui/bookleftbackground.png"); - public TiCTurnPageButton(int id, int xPosition, int yPosition, ButtonType buttonType) { - super(id, xPosition, yPosition, buttonType.textureWidth, buttonType.textureHeight, ""); + public TiCTurnPageButton(int id, int xPosition, int yPosition, ButtonType buttonType, + TiCButtonBookPage parentPage) { + super(id, xPosition, yPosition, buttonType.textureWidth, buttonType.textureHeight, "", parentPage); this.buttonType = buttonType; } + public int getWidth() { + return this.buttonType.textureWidth; + } + + public int getHeight() { + return this.buttonType.textureHeight; + } + public void drawButton(Minecraft mc, int mouseX, int mouseY) { this.drawButtonWithScale(mc, mouseX, mouseY, 1.0f); } diff --git a/src/main/java/tconstruct/tools/ToolProxyClient.java b/src/main/java/tconstruct/tools/ToolProxyClient.java index b40dbe5305..5f5330ef52 100644 --- a/src/main/java/tconstruct/tools/ToolProxyClient.java +++ b/src/main/java/tconstruct/tools/ToolProxyClient.java @@ -38,6 +38,8 @@ import tconstruct.client.pages.ModifierPage; import tconstruct.client.pages.NavigationPage; import tconstruct.client.pages.TiCCoverPage; +import tconstruct.client.pages.TiCCraftingPage; +import tconstruct.client.pages.TiCTextPage; import tconstruct.client.pages.ToolPage; import tconstruct.common.TProxyCommon; import tconstruct.library.TConstructRegistry; @@ -325,6 +327,8 @@ public void registerManualIcons() { MProxyClient.registerManualPage("modifier", ModifierPage.class); MProxyClient.registerManualPage("cover", TiCCoverPage.class); + MProxyClient.registerManualPage("tictext", TiCTextPage.class); + MProxyClient.registerManualPage("ticcrafting", TiCCraftingPage.class); MProxyClient.registerManualPage("navigation", NavigationPage.class); } diff --git a/src/main/resources/assets/tinker/.vscode/settings.json b/src/main/resources/assets/tinker/.vscode/settings.json new file mode 100644 index 0000000000..d10522852b --- /dev/null +++ b/src/main/resources/assets/tinker/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.formatOnSave": false, + "editor.formatOnPaste": false +} diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index fc18c06e1f..8dc1961864 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -1204,7 +1204,6 @@ tconstruct.manual.button.tooltip.nextPage=Next Page tconstruct.manual.button.tooltip.previousPage=Previous Page tconstruct.manual.button.tooltip.backToJumpFrom=Back Ward tconstruct.manual.button.tooltip.homePage=Home Page -tconstruct.manual.button.tooltip.navigatto=Jump to %s Page #manual text @@ -1214,4 +1213,12 @@ tconstruct.manual.materialsandyou.jumptotools=Tools tconstruct.manual.materialsandyou.jumptomaterials=Materials tconstruct.manual.materialsandyou.jumptomodifies=Modifies tconstruct.manual.materialsandyou.jumptosmeltery=Smeltery -tconstruct.manual.materialsandyou.jumptobowmaterials=Bow Materials \ No newline at end of file +tconstruct.manual.materialsandyou.jumptobowmaterials=Bow Materials + +tconstruct.manual.materialsandyou.welcome1=Welcome to the §mfirst§r second edition of Materials and You: Surviving the first day and beyond. Within these pages you will find the first steps to making the tools and materials you need to survive.\n\nThis book is a magic copy; it updates whenever the original has been modified. Check back occasionally for information on new things. +tconstruct.manual.materialsandyou.welcome2=The first step in making tools is crafting a blank pattern. It is a blank slate to stamp a shape into, providing a reference for future creations. The patterns are shaped on the Stencil Table or are used as tabletops.\n\nYou can then shape a material in a part builder with the pattern, then combine parts in the tool station. Patterns can be stored and accessed in the pattern chest.\n\nTogether these make the Tool Workshop. It is recommended you keep all of these nearby when using any of them. + +tconstruct.manual.materialsandyou.recipetype.ShapedOreRecipe=Shaped Ore Recipe +tconstruct.manual.materialsandyou.recipetype.ShapelessOreRecipe=Shapeless Ore Recipe +tconstruct.manual.materialsandyou.recipetype.ShapedRecipes=Shaped Recipes +tconstruct.manual.materialsandyou.recipetype.ShapelessRecipes=Shapeless Recipes \ No newline at end of file diff --git a/src/main/resources/assets/tinker/manuals/materialsandyou.xml b/src/main/resources/assets/tinker/manuals/materialsandyou.xml index 13dc16f552..cf6df826f1 100644 --- a/src/main/resources/assets/tinker/manuals/materialsandyou.xml +++ b/src/main/resources/assets/tinker/manuals/materialsandyou.xml @@ -1,17 +1,78 @@ - -tconstruct.manual.materialsandyou.homepage - - - - - - - - - - + + tconstruct.manual.materialsandyou.homepage + + + + + + + + + + + + + tconstruct.manual.materialsandyou.welcome1 + + + + tconstruct.manual.materialsandyou.welcome2 + + + + item.tconstruct.Pattern.blank_pattern.name + TConstruct:blankPattern + + + + ToolStation.PatternShaper.name + TConstruct:ToolStationBlock:10 + + + + ToolStation.Parts.name + TConstruct:ToolStationBlock:1 + + + + ToolStation.PatternChest.name + TConstruct:ToolStationBlock:5 + + + + ToolStation.Crafter.name + TConstruct:ToolStationBlock + + + + tile.ToolForge.name + TConstruct:ToolForgeBlock + + + + tile.Armor.DryingRack.name + TConstruct:Armor.DryingRack + \ No newline at end of file From dd6d4463762dcfdd5fb472c5de0d204621f49e85 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Sat, 9 May 2026 08:28:08 +0800 Subject: [PATCH 13/34] can use mouse scroll and arrow key to turn page --- .../tconstruct/library/util/TiCGuiManual.java | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index 06cacd79ae..f3e39f1932 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -8,6 +8,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -138,13 +139,24 @@ protected void actionPerformed(GuiButton button) { tgb.parentPage.actionPerformed(button); } else { changePage(button.id); - updateButtonVisibility(); - ticUpdateText(); } } } } + @Override + protected void keyTyped(char typedChar, int keyCode) { + // right arrow is 205 + // left arrow is 203 + if (keyCode == 205) { + this.turnToNextPage(); + } else if (keyCode == 203) { + this.turnToPreviousPage(); + } else { + super.keyTyped(typedChar, keyCode); + } + } + void ticUpdateText() { if (maxPages % 2 == 1) { if (currentPage > maxPages) currentPage = maxPages; @@ -193,18 +205,39 @@ void ticUpdateText() { } } + @Override + public void handleMouseInput() { + int scrollAmount = Mouse.getEventDWheel(); + + if (scrollAmount > 0) { + this.turnToPreviousPage(); + } else if (scrollAmount < 0) { + this.turnToNextPage(); + } else { + super.handleMouseInput(); + } + } + private void changePage(int buttonId) { if (buttonId == 1) { - currentPage += 2; + this.turnToNextPage(); } if (buttonId == 2) { - currentPage -= 2; + this.turnToPreviousPage(); } if (buttonId == 3) { - currentPage = 0; + this.setCurrentPage(0); } } + public void turnToNextPage() { + this.setCurrentPage(this.currentPage + 2); + } + + public void turnToPreviousPage() { + this.setCurrentPage(this.currentPage - 2); + } + public void setCurrentPage(int pageNum) { this.currentPage = Math.min(Math.max(pageNum % 2 == 1 ? pageNum - 1 : pageNum, 0), maxPages - 2); updateButtonVisibility(); From 96eefadc5845c96949761cf8d54d1b2f73c8fec1 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Sat, 9 May 2026 08:28:40 +0800 Subject: [PATCH 14/34] add TiC pic/furnace render --- .../java/tconstruct/client/TProxyClient.java | 7 +- .../client/pages/TiCCraftingPage.java | 295 ++++++++++-------- .../client/pages/TiCPicturePage.java | 57 ++++ .../client/TConstructClientRegistry.java | 27 +- .../tconstruct/tools/ToolProxyClient.java | 2 + .../java/tconstruct/util/TiCRecipeHolder.java | 126 ++++++++ .../resources/assets/tinker/lang/en_US.lang | 12 +- .../assets/tinker/manuals/materialsandyou.xml | 92 +++++- .../textures/gui/bookmodifyandstation.png | Bin 0 -> 5922 bytes 9 files changed, 455 insertions(+), 163 deletions(-) create mode 100644 src/main/java/tconstruct/client/pages/TiCPicturePage.java create mode 100644 src/main/java/tconstruct/util/TiCRecipeHolder.java create mode 100644 src/main/resources/assets/tinker/textures/gui/bookmodifyandstation.png diff --git a/src/main/java/tconstruct/client/TProxyClient.java b/src/main/java/tconstruct/client/TProxyClient.java index 738e2b5d0e..e9fdd03ee7 100644 --- a/src/main/java/tconstruct/client/TProxyClient.java +++ b/src/main/java/tconstruct/client/TProxyClient.java @@ -16,7 +16,6 @@ import org.w3c.dom.Document; -import cpw.mods.fml.common.Loader; import mantle.client.SmallFontRenderer; import mantle.lib.client.MantleClientRegistry; import tconstruct.TConstruct; @@ -64,9 +63,9 @@ public void readManuals() { initManualIcons(); initManualRecipes(); initManualPages(); - if (!Loader.isModLoaded("dreamcraft")) { - readTinkersConstructManuals(); - } + // if (!Loader.isModLoaded("dreamcraft")) { + readTinkersConstructManuals(); + // } } private void readTinkersConstructManuals() { diff --git a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java index 242b4e1d30..78e7b2da1a 100644 --- a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java +++ b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java @@ -1,20 +1,13 @@ package tconstruct.client.pages; -import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.ShapedRecipes; -import net.minecraft.item.crafting.ShapelessRecipes; import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; -import net.minecraftforge.oredict.ShapedOreRecipe; -import net.minecraftforge.oredict.ShapelessOreRecipe; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -25,37 +18,46 @@ import tconstruct.library.util.TiCTurnPageButton; import tconstruct.library.util.TiCTurnPageButton.ButtonType; import tconstruct.util.McTextFormatter; +import tconstruct.util.TiCRecipeHolder; +import tconstruct.util.TiCRecipeHolder.RecipeType; public class TiCCraftingPage extends TiCButtonBookPage { String title; - ItemStack target; - IRecipe[] recipes; + TiCRecipeHolder[] recipes; + int maxRecipesSize = 1; int selectedIdx; TiCTurnPageButton previousRecipeButton; TiCTurnPageButton nextRecipeButton; - private static final ResourceLocation background = new ResourceLocation("mantle", "textures/gui/bookcrafting.png"); + private static final ResourceLocation craftingTableBackground = new ResourceLocation( + "mantle", + "textures/gui/bookcrafting.png"); + private static final ResourceLocation furnaceBackground = new ResourceLocation( + "mantle", + "textures/gui/bookfurnace.png"); + + long lastUpdate; + int counter; @Override public void readPageFromXML(Element element) { this.pageButtonList = new ArrayList<>(); - NodeList nodes = element.getElementsByTagName("text"); - - if (nodes != null) this.title = nodes.item(0).getTextContent(); - if (StatCollector.canTranslate(this.title)) this.title = StatCollector.translateToLocal(this.title); - - nodes = element.getElementsByTagName("icon"); + NodeList nodes = element.getElementsByTagName("icon"); if (nodes != null) { this.recipes = TConstructClientRegistry.getOrRegisterRecipeIcon(nodes.item(0).getTextContent()); - this.target = TConstructClientRegistry.getOrRegisterManualIcon(nodes.item(0).getTextContent()); + this.title = TConstructClientRegistry.getOrRegisterManualIcon(nodes.item(0).getTextContent()) + .getDisplayName(); } this.selectedIdx = 0; this.pageButtonList .add(this.previousRecipeButton = new TiCTurnPageButton(0, 0, 0, ButtonType.previousPage, this)); this.pageButtonList.add(this.nextRecipeButton = new TiCTurnPageButton(0, 0, 0, ButtonType.nextPage, this)); + + this.lastUpdate = System.currentTimeMillis(); + this.counter = 0; } private void drawStrCenterAt(String str, int X, int Y, float scale, int color) { @@ -84,135 +86,171 @@ public void updateButtonPosition(int startX, int startY, float scale, int mouseX @Override public void render(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) { + this.maxRecipesSize = 1; this.previousRecipeButton.drawButtonWithScale(manual.mc, mouseX, mouseY, scale); this.nextRecipeButton.drawButtonWithScale(manual.mc, mouseX, mouseY, scale); - IRecipe selectedRecipe = this.recipes[this.selectedIdx]; - String craftingType = ""; - ItemStack[] inputs = new ItemStack[0]; - int recipeSize = 0; - if (selectedRecipe instanceof ShapedOreRecipe sor) { - craftingType = "ShapedOreRecipe"; - List a = new ArrayList<>(); - for (Object b : Arrays.asList(sor.getInput())) { - if (b instanceof List l) { - a.add((ItemStack) l.get(0)); - } else if (b instanceof ItemStack l) { - a.add(l); - } else { - a.add(null); - } + if (this.selectedIdx >= 0 && this.selectedIdx < this.recipes.length) { + + TiCRecipeHolder selectedRecipe = this.recipes[this.selectedIdx]; + + String craftingType = StatCollector + .translateToLocal("tconstruct.manual.materialsandyou.recipetype." + selectedRecipe.recipeType.type); + + // update displayed item + if (this.maxRecipesSize > 1 && System.currentTimeMillis() - lastUpdate > 1000) { + lastUpdate = System.currentTimeMillis(); + counter++; + if (counter >= this.maxRecipesSize) counter = 0; } - inputs = a.toArray(inputs); - recipeSize = getWidth(sor); - } else if (selectedRecipe instanceof ShapelessOreRecipe sor) { - craftingType = "ShapelessOreRecipe"; - List a = new ArrayList<>(); - for (Object b : Arrays.asList(sor.getInput())) { - if (b instanceof List l) { - a.add((ItemStack) l.get(0)); - } else if (b instanceof ItemStack l) { - a.add(l); + + if (title != null) this.drawStrCenterAt( + McTextFormatter.addUnderLine(title), + startX + PAGECONTENTWIDTH / 2, + startY + 4, + 1.0f, + 0x000000); + this.drawStrCenterAt(craftingType, startX + PAGECONTENTWIDTH / 2, startY + 15, 1.0f, 0x000000); + + if (selectedRecipe.recipeType == RecipeType.Furnace) { + renderFurnaceRecipe(startX, startY, selectedRecipe); + } else { + switch (selectedRecipe.recipeSize) { + case 2 -> render22CraftingRecipe(startX, startY, selectedRecipe); + case 3 -> render33CraftingRecipe(startX, startY, selectedRecipe); } } - inputs = a.toArray(inputs); - } else if (selectedRecipe instanceof ShapedRecipes sr) { - craftingType = "ShapedRecipes"; - inputs = sr.recipeItems; - recipeSize = Math.max(sr.recipeWidth, sr.recipeHeight); - } else if (selectedRecipe instanceof ShapelessRecipes sr) { - craftingType = "ShapelessRecipes"; - inputs = sr.recipeItems.toArray(inputs); - } - recipeSize = recipeSize == 0 ? (inputs.length > 4 ? 3 : 2) : recipeSize; - craftingType = StatCollector.translateToLocal("tconstruct.manual.materialsandyou.recipetype." + craftingType); + } - if (title != null) this.drawStrCenterAt( - McTextFormatter.addUnderLine(title), - startX + PAGECONTENTWIDTH / 2, - startY + 4, - 1.0f, - 0x000000); - this.drawStrCenterAt(craftingType, startX + PAGECONTENTWIDTH / 2, startY + 15, 1.0f, 0x000000); + if (parentButtonList != null) { + parentButtonList.addAll(pageButtonList); + } + } + private void beforeRenderItem() { GL11.glScalef(2f, 2f, 2f); GL11.glEnable(GL12.GL_RESCALE_NORMAL); RenderHelper.enableGUIStandardItemLighting(); manual.renderitem.zLevel = 100; + } - if (recipeSize == 2) { - manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - target, - (startX + 126) / 2, - (startY + 68) / 2); - if (target.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - target, - (startX + 126) / 2, - (startY + 68) / 2, - String.valueOf(target.stackSize)); - for (int i = 0; i < inputs.length; i++) { - if (inputs[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - inputs[i], - (startX + 14 + 36 * (i % 2)) / 2, - (startY + 36 * (i / 2) + 52) / 2); - } - } + private void afterRenderItem() { + manual.renderitem.zLevel = 0; + GL11.glScalef(0.5F, 0.5F, 0.5F); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + } - if (recipeSize == 3) { - int biasX = startX + (side != 1 ? 6 : 0); - manual.renderitem.renderItemAndEffectIntoGUI( + private void render22CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { + + ItemStack[][] inputStacks = selectedRecipe.inputStacks; + ItemStack outputStack = selectedRecipe.outputStack; + + beforeRenderItem(); + + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + outputStack, + (startX + 126) / 2, + (startY + 68) / 2); + if (outputStack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + outputStack, + (startX + 126) / 2, + (startY + 68) / 2, + String.valueOf(outputStack.stackSize)); + for (int i = 0; i < inputStacks.length; i++) { + if (inputStacks[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( manual.fonts, manual.getMC().renderEngine, - target, - (biasX + 138) / 2, - (startY + 70) / 2); - if (target.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - target, - (biasX + 126) / 2, - (startY + 68) / 2, - String.valueOf(target.stackSize)); - for (int i = 0; i < inputs.length; i++) { - if (inputs[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - inputs[i], - (biasX - 2 + 36 * (i % 3)) / 2, - (startY + 36 * (i / 3) + 34) / 2); - } + inputStacks[i][this.counter % inputStacks[i].length], + (startX + 14 + 36 * (i % 2)) / 2, + (startY + 36 * (i / 2) + 52) / 2); } - manual.renderitem.zLevel = 0; - GL11.glScalef(0.5F, 0.5F, 0.5F); - RenderHelper.disableStandardItemLighting(); - GL11.glDisable(GL12.GL_RESCALE_NORMAL); + afterRenderItem(); - this.renderBackgroundLayer(startX, startY, recipeSize); + manual.getMC().getTextureManager().bindTexture(craftingTableBackground); + manual.drawTexturedModalRect(startX + 8, startY + 46, 0, 116, 154, 78); + } - if (parentButtonList != null) { - parentButtonList.addAll(pageButtonList); + private void render33CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { + + ItemStack[][] inputStacks = selectedRecipe.inputStacks; + ItemStack outputStack = selectedRecipe.outputStack; + + beforeRenderItem(); + + int biasX = startX + (side != 1 ? 6 : 0); + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + outputStack, + (biasX + 138) / 2, + (startY + 70) / 2); + if (outputStack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + outputStack, + (biasX + 138) / 2, + (startY + 68) / 2, + String.valueOf(outputStack.stackSize)); + for (int i = 0; i < inputStacks.length; i++) { + if (inputStacks[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + inputStacks[i][this.counter % inputStacks[i].length], + (biasX - 2 + 36 * (i % 3)) / 2, + (startY + 36 * (i / 3) + 34) / 2); } - } - public void renderBackgroundLayer(int localwidth, int localheight, int recipeSize) { - if (recipeSize == 2) drawBackground(recipeSize, localwidth, localheight); + afterRenderItem(); - if (recipeSize == 3) drawBackground(recipeSize, localwidth + (side != 1 ? 6 : 0), localheight); + manual.getMC().getTextureManager().bindTexture(craftingTableBackground); + manual.drawTexturedModalRect(startX + (side != 1 ? 6 : 0) - 8, startY + 28, 0, 0, 183, 114); } - public void drawBackground(int size, int localWidth, int localHeight) { - manual.getMC().getTextureManager().bindTexture(background); - if (size == 2) manual.drawTexturedModalRect(localWidth + 8, localHeight + 46, 0, 116, 154, 78); - if (size == 3) manual.drawTexturedModalRect(localWidth - 8, localHeight + 28, 0, 0, 183, 114); + private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { + ItemStack[][] inputStacks = selectedRecipe.inputStacks; + ItemStack outputStack = selectedRecipe.outputStack; + + beforeRenderItem(); + + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + TConstructClientRegistry.getOrRegisterManualIcon("minecraft:coal"), + (startX + 38) / 2, + (startY + 110) / 2); + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + outputStack, + (startX + 106) / 2, + (startY + 74) / 2); + manual.renderitem.renderItemAndEffectIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + inputStacks[0][0], + (startX + 38) / 2, + (startY + 38) / 2); + + if (outputStack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + outputStack, + (startX + 106) / 2, + (startY + 74) / 2, + String.valueOf(outputStack.stackSize)); + + afterRenderItem(); + + manual.getMC().getTextureManager().bindTexture(furnaceBackground); + manual.drawTexturedModalRect(startX + 32, startY + 32, 0, 0, 111, 114); } @Override @@ -223,28 +261,13 @@ public void actionPerformed(GuiButton button) { } else if (b == this.nextRecipeButton) { this.selectedIdx += 1; } - this.selectedIdx = Math.min(this.recipes.length - 1, Math.max(selectedIdx, 0)); + this.selectedIdx = Math.max(0, Math.min(this.recipes.length - 1, selectedIdx)); this.updateVisible(); } void updateVisible() { this.previousRecipeButton.visible = this.selectedIdx != 0; - this.nextRecipeButton.visible = this.selectedIdx != this.recipes.length - 1; - } - - private static int getWidth(ShapedOreRecipe sor) { - try { - Field widthField = sor.getClass().getDeclaredField("width"); - widthField.setAccessible(true); - int width = widthField.getInt(sor); - Field heightField = sor.getClass().getDeclaredField("height"); - heightField.setAccessible(true); - int height = heightField.getInt(sor); - return Math.max(width, height); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - return -1; - } + this.nextRecipeButton.visible = this.recipes.length != 0 && this.selectedIdx != this.recipes.length - 1; } } diff --git a/src/main/java/tconstruct/client/pages/TiCPicturePage.java b/src/main/java/tconstruct/client/pages/TiCPicturePage.java new file mode 100644 index 0000000000..4e60e09bab --- /dev/null +++ b/src/main/java/tconstruct/client/pages/TiCPicturePage.java @@ -0,0 +1,57 @@ +package tconstruct.client.pages; + +import static mantle.lib.CoreRepo.logger; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; + +import org.lwjgl.opengl.GL11; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import mantle.client.pages.BookPage; + +public class TiCPicturePage extends BookPage { + + String text; + String location; + ResourceLocation background; + + @Override + public void readPageFromXML(Element element) { + NodeList nodes = element.getElementsByTagName("text"); + if (nodes != null) text = nodes.item(0).getTextContent(); + if (StatCollector.canTranslate(this.text)) this.text = StatCollector.translateToLocal(this.text); + + nodes = element.getElementsByTagName("location"); + if (nodes != null) { + location = nodes.item(0).getTextContent(); + background = new ResourceLocation(location); + if (background == null) { + logger.warn(nodes.item(0).getTextContent() + " could not be found in the image cache(location)!"); + } + } + + } + + @Override + public void renderContentLayer(int localWidth, int localHeight, boolean isTranslatable) { + manual.fonts.drawSplitString(text, localWidth + 8, localHeight + 6, 178, 0); + } + + public void renderBackgroundLayer(int localWidth, int localHeight) { + if (background != null) { + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + manual.getMC().getTextureManager().bindTexture(background); + + manual.drawTexturedModalRect( + localWidth, + localHeight + (TiCButtonBookPage.PAGECONTENTHEIGHT - 120) / 2, + 0, + 0, + 170, + 144); + } + } + +} diff --git a/src/main/java/tconstruct/library/client/TConstructClientRegistry.java b/src/main/java/tconstruct/library/client/TConstructClientRegistry.java index eab9514309..df0de7422b 100644 --- a/src/main/java/tconstruct/library/client/TConstructClientRegistry.java +++ b/src/main/java/tconstruct/library/client/TConstructClientRegistry.java @@ -4,11 +4,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.item.crafting.IRecipe; import com.google.common.collect.Maps; @@ -17,6 +19,7 @@ import tconstruct.library.TConstructRegistry; import tconstruct.library.crafting.ModifyBuilder; import tconstruct.library.tools.ToolCore; +import tconstruct.util.TiCRecipeHolder; public class TConstructClientRegistry { @@ -25,7 +28,7 @@ public class TConstructClientRegistry { public static ArrayList toolButtons = new ArrayList<>(20); public static ArrayList tierTwoButtons = new ArrayList<>(); public static Map manualIcons = new HashMap<>(); - public static Map recipeIcons = Maps.newHashMap(); + public static Map recipeIcons = Maps.newHashMap(); public static ItemStack defaultStack = new ItemStack(Items.iron_ingot); public static void addMaterialRenderMapping(int materialID, String domain, String renderName, @@ -147,28 +150,24 @@ public static ItemStack getOrRegisterManualIcon(String name) { return getManualIcon(name); } - public static IRecipe[] getOrRegisterRecipeIcon(String name) { + public static TiCRecipeHolder[] getOrRegisterRecipeIcon(String name) { if (!recipeIcons.containsKey(name)) { ItemStack outPutStack = getOrRegisterManualIcon(name); - List recipes = new ArrayList<>(); + List recipes = new ArrayList<>(); for (IRecipe i : CraftingManager.getInstance().getRecipeList()) { ItemStack output = i.getRecipeOutput(); - if (output != null && output.isItemEqual(outPutStack)) recipes.add(i); + if (output != null && output.isItemEqual(outPutStack)) recipes.add(new TiCRecipeHolder(i)); } - recipeIcons.put(name, recipes.toArray(new IRecipe[] {})); + + for (Entry t : FurnaceRecipes.smelting().getSmeltingList().entrySet()) { + if (t.getValue().isItemEqual(outPutStack)) recipes.add(new TiCRecipeHolder(t.getKey(), t.getValue())); + } + + recipeIcons.put(name, recipes.toArray(new TiCRecipeHolder[] {})); } return recipeIcons.get(name); } - // private static ItemStack[] combine(ItemStack single, ItemStack[] array) { - // ItemStack[] result = new ItemStack[1 + array.length]; - // result[0] = single; - // for (int i = 0; i < array.length; i++) { - // result[i + 1] = array[i]; - // } - // return result; - // } - // Gui public static void addStencilButton(StencilGuiElement element) { stencilButtons.add(element); diff --git a/src/main/java/tconstruct/tools/ToolProxyClient.java b/src/main/java/tconstruct/tools/ToolProxyClient.java index 5f5330ef52..9093ce99f4 100644 --- a/src/main/java/tconstruct/tools/ToolProxyClient.java +++ b/src/main/java/tconstruct/tools/ToolProxyClient.java @@ -39,6 +39,7 @@ import tconstruct.client.pages.NavigationPage; import tconstruct.client.pages.TiCCoverPage; import tconstruct.client.pages.TiCCraftingPage; +import tconstruct.client.pages.TiCPicturePage; import tconstruct.client.pages.TiCTextPage; import tconstruct.client.pages.ToolPage; import tconstruct.common.TProxyCommon; @@ -330,6 +331,7 @@ public void registerManualIcons() { MProxyClient.registerManualPage("tictext", TiCTextPage.class); MProxyClient.registerManualPage("ticcrafting", TiCCraftingPage.class); MProxyClient.registerManualPage("navigation", NavigationPage.class); + MProxyClient.registerManualPage("ticpicture", TiCPicturePage.class); } void registerManualRecipes() { diff --git a/src/main/java/tconstruct/util/TiCRecipeHolder.java b/src/main/java/tconstruct/util/TiCRecipeHolder.java new file mode 100644 index 0000000000..ab14884e8d --- /dev/null +++ b/src/main/java/tconstruct/util/TiCRecipeHolder.java @@ -0,0 +1,126 @@ +package tconstruct.util; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; + +public class TiCRecipeHolder { + + private static final Field WIDTH_FIELD; + private static final Field HEIGHT_FIELD; + + static { + try { + WIDTH_FIELD = ShapedOreRecipe.class.getDeclaredField("width"); + HEIGHT_FIELD = ShapedOreRecipe.class.getDeclaredField("height"); + + WIDTH_FIELD.setAccessible(true); + HEIGHT_FIELD.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public enum RecipeType { + + ShapedOre("ShapedOreRecipe", ShapedOreRecipe.class), + ShapelessOre("ShapelessOreRecipe", ShapelessOreRecipe.class), + Shaped("ShapedRecipes", ShapedRecipes.class), + Shapeless("ShapelessRecipes", ShapelessRecipes.class), + Furnace("FurnaceRecipes", FurnaceRecipes.class); + + public String type; + public Class clz; + + private RecipeType(String t, Class clz) { + this.type = t; + this.clz = clz; + } + + } + + private static int getSize(ShapedOreRecipe sor) { + try { + return Math.max(WIDTH_FIELD.getInt(sor), HEIGHT_FIELD.getInt(sor)); + } catch (IllegalAccessException e) { + return 0; + } + } + + public final RecipeType recipeType; + public final ItemStack outputStack; + public final ItemStack[][] inputStacks; + public final int varietyOfOre; + public final int recipeSize; + + public TiCRecipeHolder(IRecipe recipe) { + int maxRecipesSize = 0; + RecipeType craftingType = null; + ItemStack target = recipe.getRecipeOutput(); + ItemStack[][] inputs = new ItemStack[0][]; + int recipeSize = 0; + List a = new ArrayList<>(); + if (recipe instanceof ShapedOreRecipe sor) { + craftingType = RecipeType.ShapedOre; + for (Object b : Arrays.asList(sor.getInput())) { + if (b instanceof Listl) { + maxRecipesSize = Math.max(maxRecipesSize, l.size()); + a.add(l.toArray(new ItemStack[] {})); + } else if (b instanceof ItemStack l) { + a.add(new ItemStack[] { l }); + } else { + a.add(null); + } + } + inputs = a.toArray(inputs); + recipeSize = getSize(sor); + } else if (recipe instanceof ShapelessOreRecipe sor) { + craftingType = RecipeType.ShapelessOre; + for (Object b : sor.getInput()) { + if (b instanceof Listl) { + maxRecipesSize = Math.max(maxRecipesSize, l.size()); + a.add(l.toArray(new ItemStack[] {})); + } else if (b instanceof ItemStack l) { + a.add(new ItemStack[] { l }); + } + } + inputs = a.toArray(inputs); + } else if (recipe instanceof ShapedRecipes sr) { + craftingType = RecipeType.Shaped; + inputs = Arrays.asList(sr.recipeItems).stream().map(i -> new ItemStack[] { i }).collect(Collectors.toList()) + .toArray(inputs); + recipeSize = Math.max(sr.recipeWidth, sr.recipeHeight); + } else if (recipe instanceof ShapelessRecipes sr) { + craftingType = RecipeType.Shapeless; + inputs = sr.recipeItems.stream().map(i -> new ItemStack[] { i }).collect(Collectors.toList()) + .toArray(inputs); + } + recipeSize = recipeSize == 0 ? (inputs.length > 4 ? 3 : 2) : recipeSize; + + this.recipeType = craftingType; + this.outputStack = target; + this.inputStacks = inputs; + this.varietyOfOre = maxRecipesSize; + this.recipeSize = recipeSize; + + } + + public TiCRecipeHolder(ItemStack input, ItemStack output) { + this.inputStacks = new ItemStack[][] { { input } }; + this.outputStack = output; + this.varietyOfOre = 1; + this.recipeSize = 0; + this.recipeType = RecipeType.Furnace; + } + +} diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index 8dc1961864..3222f4cd2b 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -1217,8 +1217,16 @@ tconstruct.manual.materialsandyou.jumptobowmaterials=Bow Materials tconstruct.manual.materialsandyou.welcome1=Welcome to the §mfirst§r second edition of Materials and You: Surviving the first day and beyond. Within these pages you will find the first steps to making the tools and materials you need to survive.\n\nThis book is a magic copy; it updates whenever the original has been modified. Check back occasionally for information on new things. tconstruct.manual.materialsandyou.welcome2=The first step in making tools is crafting a blank pattern. It is a blank slate to stamp a shape into, providing a reference for future creations. The patterns are shaped on the Stencil Table or are used as tabletops.\n\nYou can then shape a material in a part builder with the pattern, then combine parts in the tool station. Patterns can be stored and accessed in the pattern chest.\n\nTogether these make the Tool Workshop. It is recommended you keep all of these nearby when using any of them. +tconstruct.manual.materialsandyou.oreberrydesc=Oreberry Bushes\n\nSometime in your travels you will happen upon the bush known as the Oreberry. They grow underground in dark areas, and require close to complete darkness to produce anything.\n\nThe berries can be melted down into nuggets and ingots, making them an invaluable source of metals. +tconstruct.manual.materialsandyou.oreberrypic=Oreberries in their natural environment +tconstruct.manual.materialsandyou.slimechannels=Slime Channels\n\nSlime channels are useful for moving items or entities around. They are used as a sort of easily placeable water and can be paired with bounce pads for best effect. +tconstruct.manual.materialsandyou.trap=A few traps or blockades may help with your early survival experience +tconstruct.manual.materialsandyou.smelterydesc=Once you're well established, you can begin to process metals in a more efficient manner. The scope of the smeltery is beyond this volume, but a few recipes will help you get started.\n\nNote: The Smeltery is required to process all metals, including iron. +tconstruct.manual.materialsandyou.makenewbook=If you ever find yourself without this book, a new one is simple to make. Other books can be made from this one as well. + tconstruct.manual.materialsandyou.recipetype.ShapedOreRecipe=Shaped Ore Recipe tconstruct.manual.materialsandyou.recipetype.ShapelessOreRecipe=Shapeless Ore Recipe -tconstruct.manual.materialsandyou.recipetype.ShapedRecipes=Shaped Recipes -tconstruct.manual.materialsandyou.recipetype.ShapelessRecipes=Shapeless Recipes \ No newline at end of file +tconstruct.manual.materialsandyou.recipetype.ShapedRecipes=Shaped Recipe +tconstruct.manual.materialsandyou.recipetype.ShapelessRecipes=Shapeless Recipe +tconstruct.manual.materialsandyou.recipetype.FurnaceRecipes=Furnace Recipe \ No newline at end of file diff --git a/src/main/resources/assets/tinker/manuals/materialsandyou.xml b/src/main/resources/assets/tinker/manuals/materialsandyou.xml index cf6df826f1..d31edc4849 100644 --- a/src/main/resources/assets/tinker/manuals/materialsandyou.xml +++ b/src/main/resources/assets/tinker/manuals/materialsandyou.xml @@ -41,38 +41,116 @@ - item.tconstruct.Pattern.blank_pattern.name TConstruct:blankPattern - ToolStation.PatternShaper.name TConstruct:ToolStationBlock:10 - ToolStation.Parts.name TConstruct:ToolStationBlock:1 - ToolStation.PatternChest.name TConstruct:ToolStationBlock:5 - ToolStation.Crafter.name TConstruct:ToolStationBlock - tile.ToolForge.name TConstruct:ToolForgeBlock - tile.Armor.DryingRack.name TConstruct:Armor.DryingRack + + tconstruct.manual.materialsandyou.oreberrydesc + + + + tconstruct.manual.materialsandyou.oreberrypic + tinker:manuals/oreberries.png + + + + tconstruct.manual.materialsandyou.slimechannels + + + + TConstruct:slime.channel + + + + TConstruct:slime.pad + + + + tconstruct.manual.materialsandyou.trap + + + + TConstruct:trap.punji + + + + TConstruct:trap.barricade.oak + + + + tconstruct.manual.materialsandyou.smelterydesc + + + + TConstruct:CraftedSoil:1 + + + + TConstruct:materials:2 + + + + TConstruct:Smeltery:2 + + + + TConstruct:Smeltery + + + + tconstruct.manual.materialsandyou.makenewbook + + + + minecraft:book + + + + TConstruct:manualBook + + + + TConstruct:manualBook:1 + + + + TConstruct:manualBook:2 + + + + TConstruct:manualBook:3 + + + + TConstruct:manualBook:4 + + + + TConstruct:manualBook:5 + + \ No newline at end of file diff --git a/src/main/resources/assets/tinker/textures/gui/bookmodifyandstation.png b/src/main/resources/assets/tinker/textures/gui/bookmodifyandstation.png new file mode 100644 index 0000000000000000000000000000000000000000..412c1405521953ddf34d5589f7b9ba685ce29948 GIT binary patch literal 5922 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 Date: Sat, 9 May 2026 09:01:28 +0800 Subject: [PATCH 15/34] fix wrong render order --- .../client/pages/TiCButtonBookPage.java | 11 ++++++++ .../client/pages/TiCCraftingPage.java | 28 ++++++------------- .../client/pages/TiCPicturePage.java | 2 -- .../tconstruct/library/util/TiCGuiManual.java | 9 ++++-- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java index d5f0656b48..7543e72097 100644 --- a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java +++ b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java @@ -4,6 +4,8 @@ import net.minecraft.client.gui.GuiButton; +import org.lwjgl.opengl.GL11; + import mantle.client.pages.BookPage; import tconstruct.library.util.TiCGuiButton; @@ -31,4 +33,13 @@ public void renderContentLayer(int localwidth, int localheight, boolean isTransl } public void actionPerformed(GuiButton button) {} + + void drawStrCenterAt(String str, int X, int Y, float scale, int color) { + manual.fonts.drawString( + str, + (int) (X / scale - manual.fonts.getStringWidth(str) / 2), + (int) ((Y - manual.fonts.FONT_HEIGHT / 2) / scale), + color); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + } } diff --git a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java index 78e7b2da1a..091dfcb32b 100644 --- a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java +++ b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java @@ -60,14 +60,6 @@ public void readPageFromXML(Element element) { this.counter = 0; } - private void drawStrCenterAt(String str, int X, int Y, float scale, int color) { - manual.fonts.drawString( - str, - (int) (X / scale - manual.fonts.getStringWidth(str) / 2), - (int) ((Y - manual.fonts.FONT_HEIGHT / 2) / scale), - color); - } - @Override public void updateButtonPosition(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) { @@ -144,10 +136,12 @@ private void afterRenderItem() { } private void render22CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { - ItemStack[][] inputStacks = selectedRecipe.inputStacks; ItemStack outputStack = selectedRecipe.outputStack; + manual.getMC().getTextureManager().bindTexture(craftingTableBackground); + manual.drawTexturedModalRect(startX + 8, startY + 46, 0, 116, 154, 78); + beforeRenderItem(); manual.renderitem.renderItemAndEffectIntoGUI( @@ -173,16 +167,15 @@ private void render22CraftingRecipe(int startX, int startY, TiCRecipeHolder sele } afterRenderItem(); - - manual.getMC().getTextureManager().bindTexture(craftingTableBackground); - manual.drawTexturedModalRect(startX + 8, startY + 46, 0, 116, 154, 78); } private void render33CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { - ItemStack[][] inputStacks = selectedRecipe.inputStacks; ItemStack outputStack = selectedRecipe.outputStack; + manual.getMC().getTextureManager().bindTexture(craftingTableBackground); + manual.drawTexturedModalRect(startX + (side != 1 ? 6 : 0) - 8, startY + 28, 0, 0, 183, 114); + beforeRenderItem(); int biasX = startX + (side != 1 ? 6 : 0); @@ -209,15 +202,15 @@ private void render33CraftingRecipe(int startX, int startY, TiCRecipeHolder sele } afterRenderItem(); - - manual.getMC().getTextureManager().bindTexture(craftingTableBackground); - manual.drawTexturedModalRect(startX + (side != 1 ? 6 : 0) - 8, startY + 28, 0, 0, 183, 114); } private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { ItemStack[][] inputStacks = selectedRecipe.inputStacks; ItemStack outputStack = selectedRecipe.outputStack; + manual.getMC().getTextureManager().bindTexture(furnaceBackground); + manual.drawTexturedModalRect(startX + 32, startY + 32, 0, 0, 111, 114); + beforeRenderItem(); manual.renderitem.renderItemAndEffectIntoGUI( @@ -248,9 +241,6 @@ private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selecte String.valueOf(outputStack.stackSize)); afterRenderItem(); - - manual.getMC().getTextureManager().bindTexture(furnaceBackground); - manual.drawTexturedModalRect(startX + 32, startY + 32, 0, 0, 111, 114); } @Override diff --git a/src/main/java/tconstruct/client/pages/TiCPicturePage.java b/src/main/java/tconstruct/client/pages/TiCPicturePage.java index 4e60e09bab..cedd8761af 100644 --- a/src/main/java/tconstruct/client/pages/TiCPicturePage.java +++ b/src/main/java/tconstruct/client/pages/TiCPicturePage.java @@ -5,7 +5,6 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; -import org.lwjgl.opengl.GL11; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -41,7 +40,6 @@ public void renderContentLayer(int localWidth, int localHeight, boolean isTransl public void renderBackgroundLayer(int localWidth, int localHeight) { if (background != null) { - GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); manual.getMC().getTextureManager().bindTexture(background); manual.drawTexturedModalRect( diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index f3e39f1932..fb94d9ff90 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -296,16 +296,21 @@ public void drawScreen(int par1, int par2, float par3) { if (pageLeft instanceof TiCButtonBookPage tbbp) { tbbp.updateButtonPositionAndRender(drawX + 16, drawY + 12, scale, par1, par2, this.buttonList); } else { - pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); pageLeft.renderBackgroundLayer(drawX + 16, drawY + 12); + pageLeft.renderContentLayer(drawX + 16, drawY + 12, bData.isTranslatable); + // because of some mantel page will draw some string in content + // and it will set color to 0x000000, so reset it + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); } } + if (pageRight != null) { if (pageRight instanceof TiCButtonBookPage tbbp) { tbbp.updateButtonPositionAndRender(drawX + 220, drawY + 12, scale, par1, par2, this.buttonList); } else { - pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); pageRight.renderBackgroundLayer(drawX + 220, drawY + 12); + pageRight.renderContentLayer(drawX + 220, drawY + 12, bData.isTranslatable); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); } } From 89cb77e955de955e84f7001e4797d263b772b856 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Sat, 9 May 2026 16:00:53 +0800 Subject: [PATCH 16/34] let item stack can hover --- .../client/pages/TiCButtonBookPage.java | 15 +++ .../tconstruct/client/pages/TiCCoverPage.java | 1 + .../client/pages/TiCCraftingPage.java | 122 ++++++++---------- .../tconstruct/library/util/TiCGuiManual.java | 20 ++- .../util/ItemStackWithPosition.java | 42 ++++++ .../assets/tinker/manuals/materialsandyou.xml | 4 + 6 files changed, 132 insertions(+), 72 deletions(-) create mode 100644 src/main/java/tconstruct/util/ItemStackWithPosition.java diff --git a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java index 7543e72097..20b2a829d3 100644 --- a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java +++ b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java @@ -1,13 +1,16 @@ package tconstruct.client.pages; +import java.util.ArrayList; import java.util.List; import net.minecraft.client.gui.GuiButton; +import net.minecraft.item.ItemStack; import org.lwjgl.opengl.GL11; import mantle.client.pages.BookPage; import tconstruct.library.util.TiCGuiButton; +import tconstruct.util.ItemStackWithPosition; public abstract class TiCButtonBookPage extends BookPage { @@ -15,6 +18,7 @@ public abstract class TiCButtonBookPage extends BookPage { public static final int PAGECONTENTWIDTH = 190; List pageButtonList; + public List pageItemStackList = new ArrayList<>(); public void updateButtonPositionAndRender(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) { @@ -42,4 +46,15 @@ void drawStrCenterAt(String str, int X, int Y, float scale, int color) { color); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); } + + void renderItemStackIntoPage(ItemStack stack, int x, int y) { + manual.renderitem.renderItemAndEffectIntoGUI(manual.fonts, manual.getMC().renderEngine, stack, x, y); + if (stack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( + manual.fonts, + manual.getMC().renderEngine, + stack, + x, + y, + String.valueOf(stack.stackSize)); + } } diff --git a/src/main/java/tconstruct/client/pages/TiCCoverPage.java b/src/main/java/tconstruct/client/pages/TiCCoverPage.java index 6eccf3f3a2..d8ea1928ec 100644 --- a/src/main/java/tconstruct/client/pages/TiCCoverPage.java +++ b/src/main/java/tconstruct/client/pages/TiCCoverPage.java @@ -26,6 +26,7 @@ private void drawStrCenterAt(String str, int X, int Y, float scale, int color) { (int) (X / scale - manual.fonts.getStringWidth(str) / 2), (int) ((Y - manual.fonts.FONT_HEIGHT / 2) / scale), color); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } @Override diff --git a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java index 091dfcb32b..69ba60554d 100644 --- a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java +++ b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java @@ -17,6 +17,7 @@ import tconstruct.library.client.TConstructClientRegistry; import tconstruct.library.util.TiCTurnPageButton; import tconstruct.library.util.TiCTurnPageButton.ButtonType; +import tconstruct.util.ItemStackWithPosition; import tconstruct.util.McTextFormatter; import tconstruct.util.TiCRecipeHolder; import tconstruct.util.TiCRecipeHolder.RecipeType; @@ -41,6 +42,8 @@ public class TiCCraftingPage extends TiCButtonBookPage { long lastUpdate; int counter; + final static ItemStack fuel = TConstructClientRegistry.getOrRegisterManualIcon("minecraft:coal"); + @Override public void readPageFromXML(Element element) { this.pageButtonList = new ArrayList<>(); @@ -58,6 +61,7 @@ public void readPageFromXML(Element element) { this.lastUpdate = System.currentTimeMillis(); this.counter = 0; + } @Override @@ -79,6 +83,7 @@ public void updateButtonPosition(int startX, int startY, float scale, int mouseX @Override public void render(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) { this.maxRecipesSize = 1; + this.pageItemStackList.clear(); this.previousRecipeButton.drawButtonWithScale(manual.mc, mouseX, mouseY, scale); this.nextRecipeButton.drawButtonWithScale(manual.mc, mouseX, mouseY, scale); @@ -106,11 +111,11 @@ public void render(int startX, int startY, float scale, int mouseX, int mouseY, this.drawStrCenterAt(craftingType, startX + PAGECONTENTWIDTH / 2, startY + 15, 1.0f, 0x000000); if (selectedRecipe.recipeType == RecipeType.Furnace) { - renderFurnaceRecipe(startX, startY, selectedRecipe); + renderFurnaceRecipe(startX, startY, selectedRecipe, scale); } else { switch (selectedRecipe.recipeSize) { - case 2 -> render22CraftingRecipe(startX, startY, selectedRecipe); - case 3 -> render33CraftingRecipe(startX, startY, selectedRecipe); + case 2 -> render22CraftingRecipe(startX, startY, selectedRecipe, scale); + case 3 -> render33CraftingRecipe(startX, startY, selectedRecipe, scale); } } @@ -135,7 +140,7 @@ private void afterRenderItem() { GL11.glDisable(GL12.GL_RESCALE_NORMAL); } - private void render22CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { + private void render22CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe, float scale) { ItemStack[][] inputStacks = selectedRecipe.inputStacks; ItemStack outputStack = selectedRecipe.outputStack; @@ -144,32 +149,30 @@ private void render22CraftingRecipe(int startX, int startY, TiCRecipeHolder sele beforeRenderItem(); - manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - outputStack, - (startX + 126) / 2, - (startY + 68) / 2); - if (outputStack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - outputStack, - (startX + 126) / 2, - (startY + 68) / 2, - String.valueOf(outputStack.stackSize)); + renderItemStackIntoPage(outputStack, (startX + 126) / 2, (startY + 68) / 2); + this.pageItemStackList + .add(new ItemStackWithPosition(outputStack, (startX + 126) / 2, (startY + 68) / 2, 2 * scale)); + for (int i = 0; i < inputStacks.length; i++) { - if (inputStacks[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - inputStacks[i][this.counter % inputStacks[i].length], - (startX + 14 + 36 * (i % 2)) / 2, - (startY + 36 * (i / 2) + 52) / 2); + if (inputStacks[i] != null && inputStacks[i][0] != null) { + ItemStack renderStack = inputStacks[i][this.counter % inputStacks[i].length]; + renderItemStackIntoPage( + renderStack, + (startX + 14 + 36 * (i % 2)) / 2, + (startY + 36 * (i / 2) + 52) / 2); + this.pageItemStackList.add( + new ItemStackWithPosition( + renderStack, + (startX + 14 + 36 * (i % 2)) / 2, + (startY + 36 * (i / 2) + 52) / 2, + 2 * scale)); + } } afterRenderItem(); } - private void render33CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { + private void render33CraftingRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe, float scale) { ItemStack[][] inputStacks = selectedRecipe.inputStacks; ItemStack outputStack = selectedRecipe.outputStack; @@ -179,32 +182,28 @@ private void render33CraftingRecipe(int startX, int startY, TiCRecipeHolder sele beforeRenderItem(); int biasX = startX + (side != 1 ? 6 : 0); - manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - outputStack, - (biasX + 138) / 2, - (startY + 70) / 2); - if (outputStack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - outputStack, - (biasX + 138) / 2, - (startY + 68) / 2, - String.valueOf(outputStack.stackSize)); + + renderItemStackIntoPage(outputStack, (biasX + 138) / 2, (startY + 70) / 2); + this.pageItemStackList + .add(new ItemStackWithPosition(outputStack, (biasX + 138) / 2, (startY + 70) / 2, 2 * scale)); + for (int i = 0; i < inputStacks.length; i++) { - if (inputStacks[i] != null) manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - inputStacks[i][this.counter % inputStacks[i].length], - (biasX - 2 + 36 * (i % 3)) / 2, - (startY + 36 * (i / 3) + 34) / 2); + if (inputStacks[i] != null && inputStacks[i][0] != null) { + ItemStack renderStack = inputStacks[i][this.counter % inputStacks[i].length]; + renderItemStackIntoPage(renderStack, (biasX - 2 + 36 * (i % 3)) / 2, (startY + 36 * (i / 3) + 34) / 2); + this.pageItemStackList.add( + new ItemStackWithPosition( + renderStack, + (biasX - 2 + 36 * (i % 3)) / 2, + (startY + 36 * (i / 3) + 34) / 2, + 2 * scale)); + } } afterRenderItem(); } - private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe) { + private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selectedRecipe, float scale) { ItemStack[][] inputStacks = selectedRecipe.inputStacks; ItemStack outputStack = selectedRecipe.outputStack; @@ -213,32 +212,15 @@ private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selecte beforeRenderItem(); - manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - TConstructClientRegistry.getOrRegisterManualIcon("minecraft:coal"), - (startX + 38) / 2, - (startY + 110) / 2); - manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - outputStack, - (startX + 106) / 2, - (startY + 74) / 2); - manual.renderitem.renderItemAndEffectIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - inputStacks[0][0], - (startX + 38) / 2, - (startY + 38) / 2); - - if (outputStack.stackSize > 1) manual.renderitem.renderItemOverlayIntoGUI( - manual.fonts, - manual.getMC().renderEngine, - outputStack, - (startX + 106) / 2, - (startY + 74) / 2, - String.valueOf(outputStack.stackSize)); + renderItemStackIntoPage(fuel, (startX + 38) / 2, (startY + 110) / 2); + renderItemStackIntoPage(outputStack, (startX + 106) / 2, (startY + 74) / 2); + renderItemStackIntoPage(inputStacks[0][0], (startX + 38) / 2, (startY + 38) / 2); + + this.pageItemStackList.add(new ItemStackWithPosition(fuel, (startX + 38) / 2, (startY + 110) / 2, 2 * scale)); + this.pageItemStackList + .add(new ItemStackWithPosition(outputStack, (startX + 106) / 2, (startY + 74) / 2, 2 * scale)); + this.pageItemStackList + .add(new ItemStackWithPosition(inputStacks[0][0], (startX + 38) / 2, (startY + 38) / 2, 2 * scale)); afterRenderItem(); } diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index fb94d9ff90..8c348ee0e1 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -315,10 +315,10 @@ public void drawScreen(int par1, int par2, float par3) { } GL11.glPopMatrix(); - this.renderTooltips(par1, par2); + this.renderButtonAndStackTooltips(par1, par2); } - void renderTooltips(int mouseX, int mouseY) { + void renderButtonAndStackTooltips(int mouseX, int mouseY) { List tooltip = new ArrayList(); this.buttonList.forEach(b -> { if (b instanceof TiCGuiButton tgb && tgb.isHover(mouseX, mouseY) && tgb.needRenderTips && tgb.visible) { @@ -326,6 +326,22 @@ void renderTooltips(int mouseX, int mouseY) { } }); this.drawHoveringText(tooltip, mouseX, mouseY, fontRendererObj); + + if (pageLeft != null && pageLeft instanceof TiCButtonBookPage tbbp) { + tbbp.pageItemStackList.forEach(t -> { + if (t.isHovered(mouseX, mouseY)) { + this.renderToolTip(t.getItemStack(), mouseX, mouseY); + } + }); + } + + if (pageRight != null && pageRight instanceof TiCButtonBookPage tbbp) { + tbbp.pageItemStackList.forEach(t -> { + if (t.isHovered(mouseX, mouseY)) { + this.renderToolTip(t.getItemStack(), mouseX, mouseY); + } + }); + } } /** diff --git a/src/main/java/tconstruct/util/ItemStackWithPosition.java b/src/main/java/tconstruct/util/ItemStackWithPosition.java new file mode 100644 index 0000000000..a0b411b962 --- /dev/null +++ b/src/main/java/tconstruct/util/ItemStackWithPosition.java @@ -0,0 +1,42 @@ +package tconstruct.util; + +import net.minecraft.item.ItemStack; + +public class ItemStackWithPosition { + + final private ItemStack i; + + final private int startPositionX; + final private int startPositionY; + final private int width; + final private int height; + + final static int defaultWidth = 16; + final static int defaultHeight = 16; + + public ItemStackWithPosition(ItemStack i, int startPositionX, int startPositionY, int width, int height) { + this.i = i; + this.startPositionX = startPositionX; + this.startPositionY = startPositionY; + this.width = width; + this.height = height; + } + + public ItemStackWithPosition(ItemStack i, int startPositionX, int startPositionY, float scale) { + this.i = i; + this.startPositionX = (int) (startPositionX * scale); + this.startPositionY = (int) (startPositionY * scale); + this.width = (int) (defaultWidth * scale); + this.height = (int) (defaultHeight * scale); + } + + public boolean isHovered(int mouseX, int mouseY) { + return (this.startPositionX <= mouseX && mouseX <= this.startPositionX + this.width) + && (this.startPositionY <= mouseY && mouseY <= this.startPositionY + this.height); + } + + public ItemStack getItemStack() { + return this.i; + } + +} diff --git a/src/main/resources/assets/tinker/manuals/materialsandyou.xml b/src/main/resources/assets/tinker/manuals/materialsandyou.xml index d31edc4849..4594ce2442 100644 --- a/src/main/resources/assets/tinker/manuals/materialsandyou.xml +++ b/src/main/resources/assets/tinker/manuals/materialsandyou.xml @@ -153,4 +153,8 @@ TConstruct:manualBook:5 + + + + \ No newline at end of file From 2943e3e6dd7f504a280bb29f26341e67682838aa Mon Sep 17 00:00:00 2001 From: MCTBL Date: Sun, 10 May 2026 00:50:17 +0800 Subject: [PATCH 17/34] add auto generate page / quick jump button --- .../client/pages/NavigationPage.java | 72 +++++++++--- .../client/pages/TiCButtonBookPage.java | 3 +- .../client/pages/TiCCraftingPage.java | 3 +- .../client/TConstructClientRegistry.java | 15 +++ .../library/crafting/ToolRecipe.java | 20 ++++ .../tconstruct/library/util/TiCBookData.java | 105 ++++++++++++++++++ .../tconstruct/library/util/TiCGuiManual.java | 64 ++++++----- .../library/util/TiCNavigationButton.java | 27 ++++- .../java/tconstruct/util/TiCRecipeHolder.java | 25 +++-- .../resources/assets/tinker/lang/en_US.lang | 5 +- .../assets/tinker/manuals/materialsandyou.xml | 10 +- 11 files changed, 275 insertions(+), 74 deletions(-) diff --git a/src/main/java/tconstruct/client/pages/NavigationPage.java b/src/main/java/tconstruct/client/pages/NavigationPage.java index 6746790b14..851107a3be 100644 --- a/src/main/java/tconstruct/client/pages/NavigationPage.java +++ b/src/main/java/tconstruct/client/pages/NavigationPage.java @@ -10,20 +10,40 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import mantle.books.BookData; import tconstruct.TConstruct; import tconstruct.library.client.TConstructClientRegistry; +import tconstruct.library.util.TiCBookData; +import tconstruct.library.util.TiCGuiManual; import tconstruct.library.util.TiCNavigationButton; import tconstruct.library.util.TiCNavigationButton.ButtonSize; +import tconstruct.util.McTextFormatter; public class NavigationPage extends TiCButtonBookPage { - private static final ButtonSize BS = ButtonSize.large; + private static final String namePrefix = "tconstruct.manual.materialsandyou.navigation."; + + private ButtonSize BS; + + private String title; @Override public void readPageFromXML(Element element) { this.pageButtonList = new ArrayList<>(); + + String size = element.getAttribute("size"); + this.BS = ButtonSize.getSize(size); + + String name = element.getAttribute("name"); + if (StatCollector.canTranslate(namePrefix + name)) { + this.title = StatCollector.translateToLocal(namePrefix + name); + } else { + this.title = name; + } + NodeList buttonList = element.getElementsByTagName("button"); - for (int idx = 0; idx < buttonList.getLength(); idx++) { + int length = buttonList.getLength(); + for (int idx = 0; idx < length; idx++) { Element b = (Element) buttonList.item(idx); String naviTo = b.getAttribute("to"); @@ -33,33 +53,46 @@ public void readPageFromXML(Element element) { String iconStr = b.getElementsByTagName("icon").item(0).getTextContent(); ItemStack iconStack = TConstructClientRegistry.getOrRegisterManualIcon(iconStr); - this.pageButtonList.add(new TiCNavigationButton(0, BS, iconStack, tempText, naviTo, this)); + this.pageButtonList.add(new TiCNavigationButton(0, this.BS, iconStack, tempText, naviTo, this)); } } public void updateButtonPositionAndRender(int startX, int startY, float scale, int mouseX, int mouseY, List parentButtonList) { - // 2 row and 3 column + if (title != null) this.drawStrCenterAt( + McTextFormatter.addUnderLine(title), + startX + PAGECONTENTWIDTH / 2, + startY + 4, + 1.0f, + 0x000000); int middleX = startX + PAGECONTENTWIDTH / 2; int middleY = startY + PAGECONTENTHEIGHT / 2; + + int buttonWidth = (int) (TiCNavigationButton.defaultWidth * BS.multi); + int buttonHeight = (int) (TiCNavigationButton.defaultHeight * BS.multi); + // int buttonGap = buttonWidth / 8; int buttonGap = 5; - int[] buttonYArray = new int[] { middleY - buttonGap - (int) (TiCNavigationButton.defaultHeight * BS.multi), - middleY + buttonGap }; - int[] buttonXArray = new int[] { - middleX - buttonGap - (int) (TiCNavigationButton.defaultWidth * BS.multi * 1.5f), - middleX - (int) (TiCNavigationButton.defaultWidth * BS.multi * 0.5), - middleX + buttonGap + (int) (TiCNavigationButton.defaultWidth * BS.multi * 0.5f) }; + int buttonRows = this.pageButtonList.size() / this.BS.buttonEachRow; + + int buttonsGroupHeight = buttonRows * buttonHeight + (buttonRows - 1) * buttonGap; + int buttonsGroupWidth = this.BS.buttonEachRow * buttonWidth + (this.BS.buttonEachRow - 1) * buttonGap; + + int buttonsGroupStartX = middleX - buttonsGroupWidth / 2; + int buttonsGroupStartY = middleY - buttonsGroupHeight / 2; for (int idx = 0; idx < this.pageButtonList.size(); idx++) { TiCNavigationButton b = (TiCNavigationButton) this.pageButtonList.get(idx); - int row = idx / 3; - int column = idx % 3; + int row = idx / this.BS.buttonEachRow; + int column = idx % this.BS.buttonEachRow; + + int buttonX = buttonsGroupStartX + column * (buttonWidth + buttonGap); + int buttonY = buttonsGroupStartY + row * (buttonHeight + buttonGap); b.id = idx + parentButtonList.size(); - b.xPosition = (int) (buttonXArray[column] * scale); - b.yPosition = (int) (buttonYArray[row] * scale); + b.xPosition = (int) (buttonX * scale); + b.yPosition = (int) (buttonY * scale); b.drawButtonWithScale(manual.mc, mouseX, mouseY, scale, manual.fonts); } @@ -69,9 +102,16 @@ public void updateButtonPositionAndRender(int startX, int startY, float scale, i } @Override - public void actionPerformed(GuiButton button) { + public void actionPerformed(GuiButton button, BookData d) { TiCNavigationButton b = (TiCNavigationButton) button; - TConstruct.logger.info(b.target + " is clicked"); + if (d instanceof TiCBookData tcbd) { + int pageIndex = tcbd.getIndexFromName(b.target); + if (pageIndex != -1) { + ((TiCGuiManual) manual).setCurrentPage(pageIndex); + } else { + TConstruct.logger.error("There's no page name " + b.target); + } + } } diff --git a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java index 20b2a829d3..26e4d9c4bd 100644 --- a/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java +++ b/src/main/java/tconstruct/client/pages/TiCButtonBookPage.java @@ -8,6 +8,7 @@ import org.lwjgl.opengl.GL11; +import mantle.books.BookData; import mantle.client.pages.BookPage; import tconstruct.library.util.TiCGuiButton; import tconstruct.util.ItemStackWithPosition; @@ -36,7 +37,7 @@ public void renderContentLayer(int localwidth, int localheight, boolean isTransl this.updateButtonPositionAndRender(localheight, localheight, 1.0f, 0, 0, null); } - public void actionPerformed(GuiButton button) {} + public void actionPerformed(GuiButton button, BookData b) {} void drawStrCenterAt(String str, int X, int Y, float scale, int color) { manual.fonts.drawString( diff --git a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java index 69ba60554d..b02e459013 100644 --- a/src/main/java/tconstruct/client/pages/TiCCraftingPage.java +++ b/src/main/java/tconstruct/client/pages/TiCCraftingPage.java @@ -14,6 +14,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import mantle.books.BookData; import tconstruct.library.client.TConstructClientRegistry; import tconstruct.library.util.TiCTurnPageButton; import tconstruct.library.util.TiCTurnPageButton.ButtonType; @@ -226,7 +227,7 @@ private void renderFurnaceRecipe(int startX, int startY, TiCRecipeHolder selecte } @Override - public void actionPerformed(GuiButton button) { + public void actionPerformed(GuiButton button, BookData d) { TiCTurnPageButton b = (TiCTurnPageButton) button; if (b == this.previousRecipeButton) { this.selectedIdx -= 1; diff --git a/src/main/java/tconstruct/library/client/TConstructClientRegistry.java b/src/main/java/tconstruct/library/client/TConstructClientRegistry.java index df0de7422b..70525e1c85 100644 --- a/src/main/java/tconstruct/library/client/TConstructClientRegistry.java +++ b/src/main/java/tconstruct/library/client/TConstructClientRegistry.java @@ -20,6 +20,7 @@ import tconstruct.library.crafting.ModifyBuilder; import tconstruct.library.tools.ToolCore; import tconstruct.util.TiCRecipeHolder; +import tconstruct.util.TiCRecipeHolder.RecipeType; public class TConstructClientRegistry { @@ -150,6 +151,13 @@ public static ItemStack getOrRegisterManualIcon(String name) { return getManualIcon(name); } + public static ItemStack getOrRegisterManualIcon(String name, ItemStack stack) { + if (!checkHadManualIconRegistered(name)) { + registerManualIcon(name, stack); + } + return getManualIcon(name); + } + public static TiCRecipeHolder[] getOrRegisterRecipeIcon(String name) { if (!recipeIcons.containsKey(name)) { ItemStack outPutStack = getOrRegisterManualIcon(name); @@ -168,6 +176,13 @@ public static TiCRecipeHolder[] getOrRegisterRecipeIcon(String name) { return recipeIcons.get(name); } + public static void registerTiCToolRecipeIcon(String name, ItemStack[] inputs, ItemStack output, RecipeType type) { + if (!recipeIcons.containsKey(name)) { + getOrRegisterManualIcon(name, output); + recipeIcons.put(name, new TiCRecipeHolder[] { new TiCRecipeHolder(inputs, output, type) }); + } + } + // Gui public static void addStencilButton(StencilGuiElement element) { stencilButtons.add(element); diff --git a/src/main/java/tconstruct/library/crafting/ToolRecipe.java b/src/main/java/tconstruct/library/crafting/ToolRecipe.java index bbc5a89727..a4eb15c5ca 100644 --- a/src/main/java/tconstruct/library/crafting/ToolRecipe.java +++ b/src/main/java/tconstruct/library/crafting/ToolRecipe.java @@ -97,4 +97,24 @@ public boolean validExtra(Item input) { public ToolCore getType() { return result; } + + public LinkedList getHeadList() { + return headList; + } + + public LinkedList getHandleList() { + return handleList; + } + + public LinkedList getAccessoryList() { + return accessoryList; + } + + public LinkedList getExtraList() { + return extraList; + } + + public Item getToolRod() { + return toolRod; + } } diff --git a/src/main/java/tconstruct/library/util/TiCBookData.java b/src/main/java/tconstruct/library/util/TiCBookData.java index 504f301849..65a6aca4f2 100644 --- a/src/main/java/tconstruct/library/util/TiCBookData.java +++ b/src/main/java/tconstruct/library/util/TiCBookData.java @@ -1,13 +1,31 @@ package tconstruct.library.util; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import mantle.books.BookData; +import tconstruct.library.client.TConstructClientRegistry; +import tconstruct.library.crafting.ToolBuilder; +import tconstruct.library.crafting.ToolRecipe; +import tconstruct.tools.TinkerTools; +import tconstruct.util.TiCRecipeHolder.RecipeType; public class TiCBookData extends BookData { + private static final String ToolPagesTag = "tictoolpages"; + + private final Map> replaceMap = new HashMap<>(); + + private Map indexMap = new HashMap<>(); + private int bookColor = 0X8D754E; public int getBookColor() { @@ -41,7 +59,94 @@ public TiCBookData setItemImage(ResourceLocation itemImage) { public TiCBookData setDoc(Document doc) { this.doc = doc; + this.processGenerate(); + + this.setupIndex(); return this; } + private void setupIndex() { + if (this.doc != null) { + NodeList pages = this.doc.getElementsByTagName("page"); + int pagesSize = pages.getLength(); + String pageName; + for (int idx = 0; idx < pagesSize; idx++) { + Element e = (Element) pages.item(idx); + if ((pageName = e.getAttribute("name")).length() != 0) { + this.indexMap.put(pageName, idx); + } + } + } + } + + public int getIndexFromName(String name) { + if (this.indexMap.containsKey(name)) { + return this.indexMap.get(name); + } else { + return -1; + } + } + + private void processGenerate() { + replaceMap.clear(); + if (this.doc != null) { + NodeList pages = this.doc.getElementsByTagName("page"); + int pagesSize = pages.getLength(); + for (int idx = 0; idx < pagesSize; idx++) { + Element e = (Element) pages.item(idx); + if (e.getAttribute("type").equals(ToolPagesTag)) { + // replaceMap.put(e, generateTools(e)); + generateTools(e); + } + } + } + } + + private void generateTools(Element parent) { + for (ToolRecipe r : ToolBuilder.instance.combos) { + + ItemStack head = r.getHeadList().size() != 0 + ? new ItemStack(r.getHeadList().getFirst(), 1, TinkerTools.MaterialID.Cobalt) + : null; + + ItemStack handle = r.getHandleList().size() != 0 + ? new ItemStack(r.getHandleList().getFirst(), 1, TinkerTools.MaterialID.Iron) + : null; + + ItemStack accessory = r.getAccessoryList().size() != 0 + ? new ItemStack(r.getAccessoryList().getFirst(), 1, TinkerTools.MaterialID.Iron) + : null; + + ItemStack extra = r.getExtraList().size() != 0 + ? new ItemStack(r.getExtraList().getFirst(), 1, TinkerTools.MaterialID.Ardite) + : null; + + ItemStack output = ToolBuilder.instance + .buildTool(head, handle, accessory, extra, r.getType().getLocalizedToolName()); + + String toolUnlocalizedName = r.getType().getUnlocalizedToolName(); + + TConstructClientRegistry.registerTiCToolRecipeIcon( + toolUnlocalizedName, + new ItemStack[] { head, handle, accessory, extra }, + output, + extra != null ? RecipeType.ToolForge : RecipeType.ToolStation); + + Element newB = this.doc.createElement("button"); + newB.setAttribute("to", toolUnlocalizedName); + + Element itemStack = this.doc.createElement("icon"); + itemStack.setTextContent(toolUnlocalizedName); + + Element desc = this.doc.createElement("text"); + desc.setTextContent(output.getDisplayName()); + + newB.appendChild(itemStack); + newB.appendChild(desc); + parent.appendChild(newB); + } + parent.setAttribute("type", "navigation"); + + } + } diff --git a/src/main/java/tconstruct/library/util/TiCGuiManual.java b/src/main/java/tconstruct/library/util/TiCGuiManual.java index 8c348ee0e1..ccf0caf6f2 100644 --- a/src/main/java/tconstruct/library/util/TiCGuiManual.java +++ b/src/main/java/tconstruct/library/util/TiCGuiManual.java @@ -42,6 +42,7 @@ public class TiCGuiManual extends GuiManual { int bookImageWidth = 206; int bookImageHeight = 200; int bookTotalPages = 1; + int jumpFromPage = -1; int currentPage; int maxPages; BookData bData; @@ -49,6 +50,8 @@ public class TiCGuiManual extends GuiManual { private TiCTurnPageButton buttonNextPage; private TiCTurnPageButton buttonPreviousPage; private TiCTurnPageButton buttonHomePage; + private TiCTurnPageButton buttonBackToJumpFrom; + private static final ResourceLocation bookRightBackGround = new ResourceLocation( "tinker", "textures/gui/bookrightbackground.png"); @@ -82,11 +85,14 @@ public TiCGuiManual(ItemStack stack, BookData data) { this.bData = data; this.guiOpenTime = System.currentTimeMillis(); - // TConstructRegistry.toolMaterialStrings.forEach((str, tm) -> { System.out.println(str + " - " + tm.name()); + // TConstructRegistry.toolMaterialStrings.forEach((str, tm) -> { + // System.out.println(str + " - " + tm.name()); // }); - // PatternBuilder.instance.materials.forEach(k -> System.out.println(k.key + " - " + + // PatternBuilder.instance.materials.forEach(k -> System.out.println(k.key + " - + // " + // k.item.getUnlocalizedName())); - // PatternBuilder.instance.materialSets.forEach((str, mset) -> System.out.println(str + " - " + mset)); + // PatternBuilder.instance.materialSets.forEach((str, mset) -> + // System.out.println(str + " - " + mset)); // renderitem.renderInFrame = true; } @@ -100,29 +106,11 @@ public TiCGuiManual(ItemStack stack, BookData data) { public void initGui() { maxPages = manual.getElementsByTagName("page").getLength(); ticUpdateText(); - int xPos = this.width / 2; - this.buttonList.add( - this.buttonNextPage = new TiCTurnPageButton( - 1, - xPos + bookImageWidth - 50, - (this.height + this.bookImageHeight) / 2 - 28, - ButtonType.nextPage, - null)); - this.buttonList.add( - this.buttonPreviousPage = new TiCTurnPageButton( - 2, - xPos - bookImageWidth + 24, - (this.height + this.bookImageHeight) / 2 - 28, - ButtonType.previousPage, - null)); - - this.buttonList.add( - this.buttonHomePage = new TiCTurnPageButton( - 3, - xPos - bookImageWidth - 24, - this.height - this.bookImageHeight, - ButtonType.homePage, - null)); + this.buttonList.add(this.buttonNextPage = new TiCTurnPageButton(1, 0, 0, ButtonType.nextPage, null)); + this.buttonList.add(this.buttonPreviousPage = new TiCTurnPageButton(2, 0, 0, ButtonType.previousPage, null)); + this.buttonList.add(this.buttonHomePage = new TiCTurnPageButton(3, 0, 0, ButtonType.homePage, null)); + this.buttonList + .add(this.buttonBackToJumpFrom = new TiCTurnPageButton(4, 0, 0, ButtonType.backToJumpFrom, null)); updateButtonVisibility(); } @@ -130,13 +118,14 @@ private void updateButtonVisibility() { buttonPreviousPage.visible = currentPage > 0; buttonNextPage.visible = currentPage < maxPages - 2; buttonHomePage.visible = currentPage != 0; + buttonBackToJumpFrom.visible = jumpFromPage != -1; } protected void actionPerformed(GuiButton button) { if (button.enabled) { if (button instanceof TiCGuiButton tgb) { if (tgb.parentPage != null) { - tgb.parentPage.actionPerformed(button); + tgb.parentPage.actionPerformed(button, this.bData); } else { changePage(button.id); } @@ -228,6 +217,9 @@ private void changePage(int buttonId) { if (buttonId == 3) { this.setCurrentPage(0); } + if (buttonId == 4) { + this.setCurrentPage(this.jumpFromPage); + } } public void turnToNextPage() { @@ -239,13 +231,19 @@ public void turnToPreviousPage() { } public void setCurrentPage(int pageNum) { + if (Math.abs(pageNum - this.currentPage) > 2 && pageNum != this.jumpFromPage) { + this.jumpFromPage = this.currentPage; + } else { + this.jumpFromPage = -1; + } + this.currentPage = Math.min(Math.max(pageNum % 2 == 1 ? pageNum - 1 : pageNum, 0), maxPages - 2); updateButtonVisibility(); ticUpdateText(); } public void drawScreen(int par1, int par2, float par3) { - this.buttonList.subList(3, this.buttonList.size()).clear(); + this.buttonList.subList(4, this.buttonList.size()).clear(); this.scale = Math.max( 0.95f, @@ -349,14 +347,18 @@ void renderButtonAndStackTooltips(int mouseX, int mouseY) { */ public void drawButtons(int mouseX, int mouseY, float scale) { - // base on `xPos + bookImageWidth - 50`, (206 - 50) / 206 ≈ 0.757 and (206 - 24) / 206 ≈ 0.883 + // base on `xPos + bookImageWidth - 50`, (206 - 50) / 206 ≈ 0.757 and (206 - 24) + // / 206 ≈ 0.883 this.buttonNextPage.xPosition = this.baseDrawingX + (int) (this.bookImageWidth * scale * 0.8f); this.buttonPreviousPage.xPosition = this.baseDrawingX - (int) (this.bookImageWidth * scale * 0.883f); this.buttonHomePage.xPosition = this.baseDrawingX - (int) ((this.bookImageWidth + TiCTurnPageButton.ButtonType.homePage.textureWidth * 1.15f) * scale); + this.buttonBackToJumpFrom.xPosition = this.baseDrawingX + - (int) (TiCTurnPageButton.ButtonType.backToJumpFrom.textureWidth * 0.5f * scale); // base on scale calculate the real y position of the bottom gui - // and base on `(this.height + this.bookImageHeight) / 2 - 28`, the default button height is 13 + // and base on `(this.height + this.bookImageHeight) / 2 - 28`, the default + // button height is 13 // 28 / 13 ≈ 2.15, so keep the same ratio int yPosition = this.baseDrawingY + (int) ((this.bookImageHeight - TiCTurnPageButton.ButtonType.nextPage.textureHeight * 2.747f) * scale); @@ -364,7 +366,9 @@ public void drawButtons(int mouseX, int mouseY, float scale) { this.buttonPreviousPage.yPosition = yPosition; this.buttonHomePage.yPosition = this.baseDrawingY + (int) (TiCTurnPageButton.ButtonType.homePage.textureHeight * 0.5f); + this.buttonBackToJumpFrom.yPosition = yPosition; + this.buttonBackToJumpFrom.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonNextPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonPreviousPage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); this.buttonHomePage.drawButtonWithScale(this.mc, mouseX, mouseY, scale); diff --git a/src/main/java/tconstruct/library/util/TiCNavigationButton.java b/src/main/java/tconstruct/library/util/TiCNavigationButton.java index 735618d298..b17a4b79f7 100644 --- a/src/main/java/tconstruct/library/util/TiCNavigationButton.java +++ b/src/main/java/tconstruct/library/util/TiCNavigationButton.java @@ -20,19 +20,34 @@ public class TiCNavigationButton extends TiCGuiButton { public enum ButtonSize { - small(0.5f), - large(2f), - medium(1f); + small(0.5f, 7), + large(2f, 3), + medium(1f, 5); public float multi; + public int buttonEachRow; - ButtonSize(float multi) { + ButtonSize(float multi, int eachRow) { this.multi = multi; + this.buttonEachRow = eachRow; + } + + public static ButtonSize getSize(String s) { + switch (s) { + case "large": + return large; + case "small": + return small; + case "medium": + return medium; + default: + return large; + } } } - public static int defaultHeight = 20; - public static int defaultWidth = 20; + public static final int defaultHeight = 20; + public static final int defaultWidth = 20; RenderItem itemRender = new RenderItem(); ButtonSize bs; diff --git a/src/main/java/tconstruct/util/TiCRecipeHolder.java b/src/main/java/tconstruct/util/TiCRecipeHolder.java index ab14884e8d..aa62578a06 100644 --- a/src/main/java/tconstruct/util/TiCRecipeHolder.java +++ b/src/main/java/tconstruct/util/TiCRecipeHolder.java @@ -7,7 +7,6 @@ import java.util.stream.Collectors; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.item.crafting.ShapelessRecipes; @@ -33,18 +32,18 @@ public class TiCRecipeHolder { public enum RecipeType { - ShapedOre("ShapedOreRecipe", ShapedOreRecipe.class), - ShapelessOre("ShapelessOreRecipe", ShapelessOreRecipe.class), - Shaped("ShapedRecipes", ShapedRecipes.class), - Shapeless("ShapelessRecipes", ShapelessRecipes.class), - Furnace("FurnaceRecipes", FurnaceRecipes.class); + ShapedOre("ShapedOreRecipe"), + ShapelessOre("ShapelessOreRecipe"), + Shaped("ShapedRecipes"), + Shapeless("ShapelessRecipes"), + Furnace("FurnaceRecipes"), + ToolStation("ToolStationRecipe"), + ToolForge("ToolForgeRecipe"); public String type; - public Class clz; - private RecipeType(String t, Class clz) { + private RecipeType(String t) { this.type = t; - this.clz = clz; } } @@ -116,11 +115,15 @@ public TiCRecipeHolder(IRecipe recipe) { } public TiCRecipeHolder(ItemStack input, ItemStack output) { - this.inputStacks = new ItemStack[][] { { input } }; + this(new ItemStack[] { input }, output, RecipeType.Furnace); + } + + public TiCRecipeHolder(ItemStack[] input, ItemStack output, RecipeType t) { + this.inputStacks = new ItemStack[][] { input }; this.outputStack = output; this.varietyOfOre = 1; this.recipeSize = 0; - this.recipeType = RecipeType.Furnace; + this.recipeType = t; } } diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index 3222f4cd2b..3a99188343 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -1229,4 +1229,7 @@ tconstruct.manual.materialsandyou.recipetype.ShapedOreRecipe=Shaped Ore Recipe tconstruct.manual.materialsandyou.recipetype.ShapelessOreRecipe=Shapeless Ore Recipe tconstruct.manual.materialsandyou.recipetype.ShapedRecipes=Shaped Recipe tconstruct.manual.materialsandyou.recipetype.ShapelessRecipes=Shapeless Recipe -tconstruct.manual.materialsandyou.recipetype.FurnaceRecipes=Furnace Recipe \ No newline at end of file +tconstruct.manual.materialsandyou.recipetype.FurnaceRecipes=Furnace Recipe + + +tconstruct.manual.materialsandyou.navigation.tools=Tools \ No newline at end of file diff --git a/src/main/resources/assets/tinker/manuals/materialsandyou.xml b/src/main/resources/assets/tinker/manuals/materialsandyou.xml index 4594ce2442..a388b6a4f3 100644 --- a/src/main/resources/assets/tinker/manuals/materialsandyou.xml +++ b/src/main/resources/assets/tinker/manuals/materialsandyou.xml @@ -5,7 +5,7 @@ tconstruct.manual.materialsandyou.homepage - +