This commit is contained in:
Karli
2025-10-12 21:43:27 +03:00
parent 9324c7f55c
commit ce480a1185
5 changed files with 490 additions and 115 deletions

View File

@@ -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'
}

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -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",

View File

@@ -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<LineComponent> 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<LineComponent> buildStatusLines()
{
List<LineComponent> 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<LineComponent> buildProgressLines()
{
List<LineComponent> 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<LineComponent> buildHeatPlannerLines()
{
List<LineComponent> 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<LineComponent> buildHeatPlanLines(int heatChangeNeeded)
{
List<LineComponent> 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<LineComponent> buildReputationLines()
{
List<LineComponent> lines = new ArrayList<>();
if (!config.drawShopPoints())
{
return lines;
}
lines.add(LineComponent.builder().left("Reputation").right(Integer.toString(plugin.getReputation())).build());
return lines;
}
private List<LineComponent> buildMetalLines()
{
List<LineComponent> 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<LineComponent> 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()
);
}
}
}

View File

@@ -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);
}
}
}