From ce480a1185ad2726e3c74e47a198c32cfb0ef487 Mon Sep 17 00:00:00 2001 From: Karli Date: Sun, 12 Oct 2025 21:43:27 +0300 Subject: [PATCH] update --- build.gradle | 8 + gradlew | 0 .../EasyGiantsFoundryConfig.java | 52 ++ .../easygiantsfoundry/FoundryOverlay2D.java | 500 ++++++++++++++---- .../easygiantsfoundry/FoundryOverlay3D.java | 45 +- 5 files changed, 490 insertions(+), 115 deletions(-) mode change 100644 => 100755 gradlew diff --git a/build.gradle b/build.gradle index 2217078..20bff8b 100644 --- a/build.gradle +++ b/build.gradle @@ -62,3 +62,11 @@ tasks.register('shadowJar', Jar) { archiveFileName.set("${rootProject.name}-${project.version}-all.jar") } + +task runClient(type: JavaExec) { + group = 'application' + description = 'Run the PluginTester main class to launch RuneLite with plugins' + classpath = sourceSets.test.runtimeClasspath + mainClass = 'com.toofifty.easygiantsfoundry.EasyGiantsFoundryPluginTest' + jvmArgs '-ea' +} diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java index 5c1b682..83c84e2 100644 --- a/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java +++ b/src/main/java/com/toofifty/easygiantsfoundry/EasyGiantsFoundryConfig.java @@ -190,6 +190,22 @@ public interface EasyGiantsFoundryConfig extends Config return true; } + @Range( + min = 100, + max = 200 + ) + @ConfigItem( + keyName = "clickboxScale", + name = "Clickbox scale %", + description = "Scale clickbox highlights to make targets easier to click.", + position = 4, + section = highlightList + ) + default int clickboxScale() + { + return 150; + } + @ConfigItem( keyName = "waterLavaHighlight", name = "Highlight Waterfall/Lava Pool", @@ -353,6 +369,42 @@ public interface EasyGiantsFoundryConfig extends Config return false; } + @ConfigItem( + keyName = "heatDelta", + name = "Heat change", + description = "Show the heat delta and recommended location for the next adjust.", + position = 7, + section = infoPanelList + ) + default boolean drawHeatDelta() + { + return true; + } + + @ConfigItem( + keyName = "heatPlan", + name = "Heat plan", + description = "Show fast/slow heat action plans with predicted results.", + position = 8, + section = infoPanelList + ) + default boolean drawHeatPlan() + { + return true; + } + + @ConfigItem( + keyName = "heatActionTimer", + name = "Heat action timer", + description = "Show the active heat action countdown in the info panel.", + position = 9, + section = infoPanelList + ) + default boolean drawHeatActionTimer() + { + return true; + } + @ConfigSection( name = "Info Overlay", description = "Overlay Text Info On Objects", diff --git a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java index 1954b3a..3965e3b 100644 --- a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java +++ b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay2D.java @@ -3,13 +3,13 @@ package com.toofifty.easygiantsfoundry; import com.toofifty.easygiantsfoundry.enums.Heat; import com.toofifty.easygiantsfoundry.enums.MetalBarType; import com.toofifty.easygiantsfoundry.enums.Stage; - import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; - import net.runelite.api.Client; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.overlay.OverlayPanel; @@ -21,6 +21,8 @@ import net.runelite.client.ui.overlay.components.TitleComponent; public class FoundryOverlay2D extends OverlayPanel { private static final int REGION_ID = 13491; + private static final int PANEL_WIDTH = 240; + private final Client client; private final EasyGiantsFoundryPlugin plugin; private final EasyGiantsFoundryState state; @@ -40,7 +42,395 @@ public class FoundryOverlay2D extends OverlayPanel this.state = state; this.metalBarCounter = metalBarCounter; this.config = config; - this.setPosition(OverlayPosition.BOTTOM_LEFT); + setPosition(OverlayPosition.BOTTOM_LEFT); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!config.alwaysDrawInfoPanel() && client.getLocalPlayer().getWorldLocation().getRegionID() != REGION_ID) + { + return null; + } + + panelComponent.getChildren().clear(); + panelComponent.setPreferredSize(new Dimension(PANEL_WIDTH, 0)); + + boolean hasContent = false; + if (config.drawTitle()) + { + panelComponent.getChildren().add(TitleComponent.builder().text("Easy Giants' Foundry").build()); + hasContent = true; + } + + boolean swordPickedUp = state.isEnabled() && state.getCurrentStage() != null; + if (swordPickedUp) + { + hasContent = appendSection(buildStatusLines(), hasContent); + hasContent = appendSection(buildProgressLines(), hasContent); + hasContent = appendSection(buildHeatPlannerLines(), hasContent); + } + + hasContent = appendSection(buildReputationLines(), hasContent); + hasContent = appendSection(buildMetalLines(), hasContent); + + if (!hasContent) + { + return null; + } + + return super.render(graphics); + } + + private boolean appendSection(List lines, boolean hasPreviousContent) + { + if (lines.isEmpty()) + { + return hasPreviousContent; + } + + if (hasPreviousContent) + { + panelComponent.getChildren().add(LineComponent.builder().left(" ").right("").build()); + } + + panelComponent.getChildren().addAll(lines); + return true; + } + + private List buildStatusLines() + { + List lines = new ArrayList<>(); + Heat heat = state.getCurrentHeat(); + Stage stage = state.getCurrentStage(); + + if (config.drawHeatInfo()) + { + lines.add( + LineComponent.builder() + .left("Heat") + .right(heat.getName() + " (" + state.getHeatAmount() / 10 + "%)") + .rightColor(heat.getColor()) + .build() + ); + } + + if (config.drawStageInfo()) + { + lines.add( + LineComponent.builder() + .left("Stage") + .right(stage.getName() + " (" + state.getProgressAmount() / 10 + "%)") + .rightColor(stage.getHeat().getColor()) + .build() + ); + } + + return lines; + } + + private List buildProgressLines() + { + List lines = new ArrayList<>(); + int actionsLeft = state.getActionsLeftInStage(); + int heatLeft = state.getActionsForHeatLevel(); + + if (config.drawActionsLeft()) + { + lines.add(LineComponent.builder().left("Actions left").right(Integer.toString(actionsLeft)).build()); + } + + if (config.drawHeatLeft()) + { + lines.add( + LineComponent.builder() + .left("Heat left") + .right(Integer.toString(heatLeft)) + .rightColor(getHeatColor(actionsLeft, heatLeft)) + .build() + ); + } + + if (config.drawBonusActions()) + { + lines.add( + LineComponent.builder() + .left("Bonus actions") + .right(state.getBonusActionsReceived() + "/" + state.getBonusActionsExpected()) + .rightColor(getBonusActionsColor(state.getBonusActionsReceived(), state.getBonusActionsExpected())) + .build() + ); + } + + return lines; + } + + private List buildHeatPlannerLines() + { + List lines = new ArrayList<>(); + if (!config.drawHeatDelta() && !config.drawHeatPlan() && !config.drawHeatActionTimer()) + { + return lines; + } + + if (state.getCurrentStage() == null) + { + return lines; + } + + int heatChangeNeeded = state.getHeatChangeNeeded(); + + if (config.drawHeatDelta()) + { + lines.add(buildHeatDeltaLine(heatChangeNeeded)); + } + + if (config.drawHeatPlan()) + { + lines.addAll(buildHeatPlanLines(heatChangeNeeded)); + } + + if (config.drawHeatActionTimer()) + { + LineComponent timerLine = buildHeatActionTimerLine(); + if (timerLine != null) + { + lines.add(timerLine); + } + } + + return lines; + } + + private LineComponent buildHeatDeltaLine(int heatChangeNeeded) + { + String location; + if (heatChangeNeeded > 0) + { + location = "Lava"; + } + else if (heatChangeNeeded < 0) + { + location = "Waterfall"; + } + else + { + location = "In range"; + } + + String deltaText = heatChangeNeeded == 0 + ? "0 (in range)" + : String.format("%+d (%s)", heatChangeNeeded, location); + + Color color = heatChangeNeeded == 0 ? ColorScheme.PROGRESS_COMPLETE_COLOR : config.lavaWaterfallColour(); + + return LineComponent.builder() + .left("Heat Δ") + .right(deltaText) + .rightColor(color) + .build(); + } + + private List buildHeatPlanLines(int heatChangeNeeded) + { + List lines = new ArrayList<>(); + + if (heatChangeNeeded == 0) + { + lines.add( + LineComponent.builder() + .left("Heat plan") + .right("Hold") + .rightColor(ColorScheme.PROGRESS_COMPLETE_COLOR) + .build() + ); + return lines; + } + + boolean isHeating = heatChangeNeeded > 0; + HeatActionSolver.DurationResult fast = solveHeatAction(true, isHeating); + HeatActionSolver.DurationResult slow = solveHeatAction(false, isHeating); + boolean added = false; + + if (fast != null && fast.getDuration() > 0) + { + lines.add(buildHeatPlanLine("Fast", isHeating, true, fast)); + added = true; + } + + if (slow != null && slow.getDuration() > 0) + { + lines.add(buildHeatPlanLine("Slow", isHeating, false, slow)); + added = true; + } + + if (!added) + { + lines.add( + LineComponent.builder() + .left("Heat plan") + .right("Hold") + .rightColor(ColorScheme.PROGRESS_COMPLETE_COLOR) + .build() + ); + } + + return lines; + } + + private LineComponent buildHeatPlanLine(String label, boolean isHeating, boolean fast, HeatActionSolver.DurationResult result) + { + String actionName = getActionName(isHeating, fast); + String value = String.format("%s %dt → %s%s", + actionName, + result.getDuration(), + formatPredictedHeat(result.getPredictedHeat()), + formatPlanStatus(result)); + + return LineComponent.builder() + .left(label) + .right(value) + .rightColor(config.lavaWaterfallColour()) + .build(); + } + + private HeatActionSolver.DurationResult solveHeatAction(boolean fast, boolean isHeating) + { + Stage stage = state.getCurrentStage(); + if (stage == null) + { + return null; + } + + return HeatActionSolver.solve( + stage, + state.getCurrentHeatRange(), + state.getActionsLeftInStage(), + state.getHeatAmount(), + fast, + isHeating, + config.heatActionPadTicks(), + state.isPlayerRunning() + ); + } + + private LineComponent buildHeatActionTimerLine() + { + HeatActionStateMachine machine = state.heatActionStateMachine; + if (machine.isIdle() || machine.getActionname() == null) + { + return null; + } + + return LineComponent.builder() + .left("Action") + .right(String.format( + "%s %dt → %s%s", + prettifyActionName(machine.getActionname()), + machine.getRemainingDuration(), + formatPredictedHeat(machine.getPredictedHeat()), + machine.isGoalInRange() ? "" : machine.isOverShooting() ? " (overshoot)" : " (limit)")) + .rightColor(config.lavaWaterfallColour()) + .build(); + } + + private String formatPredictedHeat(int predictedHeat) + { + return heatPercent(predictedHeat) + "%"; + } + + private String formatPlanStatus(HeatActionSolver.DurationResult result) + { + if (result == null || result.isGoalInRange()) + { + return ""; + } + + return result.isOvershooting() ? " (overshoot)" : " (limit)"; + } + + private String getActionName(boolean isHeating, boolean fast) + { + if (isHeating) + { + return fast ? "Dunk" : "Heat"; + } + return fast ? "Quench" : "Cool"; + } + + private String prettifyActionName(String action) + { + if (action == null || action.isEmpty()) + { + return ""; + } + + switch (action) + { + case "dunks": + return "Dunk"; + case "heats": + return "Heat"; + case "cools": + return "Cool"; + case "quenches": + return "Quench"; + default: + return Character.toUpperCase(action.charAt(0)) + action.substring(1); + } + } + + private int heatPercent(int heat) + { + return Math.max(0, Math.min(1000, heat)) / 10; + } + + private List buildReputationLines() + { + List lines = new ArrayList<>(); + if (!config.drawShopPoints()) + { + return lines; + } + + lines.add(LineComponent.builder().left("Reputation").right(Integer.toString(plugin.getReputation())).build()); + return lines; + } + + private List buildMetalLines() + { + List lines = new ArrayList<>(); + if (!config.drawMetals()) + { + return lines; + } + + if (!metalBarCounter.isSeenBank()) + { + lines.add( + LineComponent.builder() + .left("Metals: open bank") + .leftColor(Color.RED) + .build() + ); + } + + addMetalCount(lines, "Bronze bars:", metalBarCounter.get(MetalBarType.BRONZE)); + addMetalCount(lines, "Iron bars:", metalBarCounter.get(MetalBarType.IRON)); + addMetalCount(lines, "Steel bars:", metalBarCounter.get(MetalBarType.STEEL)); + addMetalCount(lines, "Mithril bars:", metalBarCounter.get(MetalBarType.MITHRIL)); + addMetalCount(lines, "Adamant bars:", metalBarCounter.get(MetalBarType.ADAMANT)); + addMetalCount(lines, "Runite bars:", metalBarCounter.get(MetalBarType.RUNITE)); + + return lines; + } + + private void addMetalCount(List lines, String displayName, int count) + { + if (count > 0 || config.drawAllMetals()) + { + lines.add(LineComponent.builder().left(displayName).right(Integer.toString(count)).build()); + } } private Color getHeatColor(int actions, int heat) @@ -67,108 +457,4 @@ public class FoundryOverlay2D extends OverlayPanel return ColorScheme.PROGRESS_INPROGRESS_COLOR; } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!config.alwaysDrawInfoPanel() && client.getLocalPlayer().getWorldLocation().getRegionID() != REGION_ID) - { - return null; - } - boolean swordPickedUp = state.isEnabled() && state.getCurrentStage() != null; - - if (config.drawTitle()) - { - panelComponent.getChildren().add(TitleComponent.builder().text("Easy Giants' Foundry").build()); - } - - if (config.drawMetals()) - { - drawMetals(graphics); - } - - if (swordPickedUp) - { - Heat heat = state.getCurrentHeat(); - Stage stage = state.getCurrentStage(); - - if (config.drawHeatInfo()) - { - panelComponent.getChildren().add( - LineComponent.builder().left("Heat").right(heat.getName() + " (" + state.getHeatAmount() / 10 + "%)").rightColor(heat.getColor()).build() - ); - } - if (config.drawStageInfo()) - { - panelComponent.getChildren().add( - LineComponent.builder().left("Stage").right(stage.getName() + " (" + state.getProgressAmount() / 10 + "%)").rightColor(stage.getHeat().getColor()).build() - ); - } - - int actionsLeft = state.getActionsLeftInStage(); - int heatLeft = state.getActionsForHeatLevel(); - - if (config.drawActionsLeft()) - { - panelComponent.getChildren().add( - LineComponent.builder().left("Actions left").right(actionsLeft + "").build() - ); - } - if (config.drawHeatLeft()) - { - panelComponent.getChildren().add( - LineComponent.builder().left("Heat left").right(heatLeft + "").rightColor(getHeatColor(actionsLeft, heatLeft)).build() - ); - } - if (config.drawBonusActions()) - { - panelComponent.getChildren().add( - LineComponent.builder().left("Bonus actions").right(state.getBonusActionsReceived() + "/" + state.getBonusActionsExpected()).rightColor(getBonusActionsColor(state.getBonusActionsReceived(), state.getBonusActionsExpected())).build() - ); - } - } -// -// int points = plugin.getPointsTracker().getShopPoints(); - if (config.drawShopPoints()) - { - panelComponent.getChildren().add( - LineComponent.builder().left("Reputation").right(plugin.getReputation() + "").build() - ); - } - - return super.render(graphics); - } - - private void drawMetals(Graphics2D graphics2D) - { - if (!metalBarCounter.isSeenBank()) - { - panelComponent.getChildren().add( - LineComponent.builder() - .left("Metals: open bank") - .leftColor(Color.RED) - .build() - ); - } - - drawMetalCount(graphics2D, "Bronze bars:", metalBarCounter.get(MetalBarType.BRONZE)); - drawMetalCount(graphics2D, "Iron bars:", metalBarCounter.get(MetalBarType.IRON)); - drawMetalCount(graphics2D, "Steel bars:", metalBarCounter.get(MetalBarType.STEEL)); - drawMetalCount(graphics2D, "Mithril bars:", metalBarCounter.get(MetalBarType.MITHRIL)); - drawMetalCount(graphics2D, "Adamant bars:", metalBarCounter.get(MetalBarType.ADAMANT)); - drawMetalCount(graphics2D, "Runite bars:", metalBarCounter.get(MetalBarType.RUNITE)); - } - - private void drawMetalCount(Graphics2D graphics2D, String displayName, int count) - { - if (count > 0 || config.drawAllMetals()) - { - panelComponent.getChildren().add( - LineComponent.builder() - .left(displayName) - .right(Integer.toString(count)) - .build() - ); - } - } } diff --git a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java index 1c32064..e50afab 100644 --- a/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java +++ b/src/main/java/com/toofifty/easygiantsfoundry/FoundryOverlay3D.java @@ -14,6 +14,8 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; import javax.inject.Inject; import net.runelite.api.Client; @@ -200,6 +202,7 @@ public class FoundryOverlay3D extends Overlay Shape objectClickbox = stageObject.getClickbox(); if (objectClickbox != null && config.highlightTools()) { + objectClickbox = scaleShape(objectClickbox); Point mousePosition = client.getMouseCanvasPosition(); if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) { @@ -330,6 +333,7 @@ public class FoundryOverlay3D extends Overlay } if (shape != null) { + shape = scaleShape(shape); Point mousePosition = client.getMouseCanvasPosition(); Color color = config.lavaWaterfallColour(); if (shape.contains(mousePosition.getX(), mousePosition.getY())) @@ -450,6 +454,7 @@ public class FoundryOverlay3D extends Overlay Shape shape = crucible.getConvexHull(); if (shape != null) { + shape = scaleShape(shape); Color color = config.generalHighlight(); if (state.getCrucibleCount() == CRUCIBLE_CAPACITY) { @@ -495,6 +500,7 @@ public class FoundryOverlay3D extends Overlay Shape shape = mouldJig.getConvexHull(); if (shape != null) { + shape = scaleShape(shape); Color color = config.generalHighlight(); graphics.setColor(color); graphics.draw(shape); @@ -520,11 +526,33 @@ public class FoundryOverlay3D extends Overlay } } + private Shape scaleShape(Shape shape) + { + if (shape == null) + { + return null; + } + + double scale = config.clickboxScale() / 100.0; + if (Math.abs(scale - 1.0) < 0.01) + { + return shape; + } + + Rectangle2D bounds = shape.getBounds2D(); + AffineTransform transform = new AffineTransform(); + transform.translate(bounds.getCenterX(), bounds.getCenterY()); + transform.scale(scale, scale); + transform.translate(-bounds.getCenterX(), -bounds.getCenterY()); + return transform.createTransformedShape(shape); + } + private void drawStorage(Graphics2D graphics) { Shape shape = storage.getConvexHull(); if (shape != null) { + shape = scaleShape(shape); Color color = config.generalHighlight(); graphics.setColor(color); graphics.draw(shape); @@ -538,14 +566,15 @@ public class FoundryOverlay3D extends Overlay Widget handInWidget = client.getWidget(HAND_IN_WIDGET); if (handInWidget != null && !handInWidget.isHidden()) { - Shape shape = kovac.getConvexHull(); - if (shape != null) - { - Color color = config.generalHighlight(); - graphics.setColor(color); - graphics.draw(shape); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20)); - graphics.fill(shape); + Shape shape = kovac.getConvexHull(); + if (shape != null) + { + shape = scaleShape(shape); + Color color = config.generalHighlight(); + graphics.setColor(color); + graphics.draw(shape); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20)); + graphics.fill(shape); } } }