Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
)
public class MotherloadMinePlugin extends Plugin {

static final String version = "1.9.6";
static final String version = "1.9.7";

@Inject
private MotherloadMineConfig config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public class MotherloadMineScript extends Script

private boolean shouldEmptySack = false;
private boolean shouldRepairWaterwheel = false;
private boolean emptySackWorkflowActive = false;
private long idleSince = 0;
private int idleThreshold = 0;
private boolean pickedUpHammer = false;
Expand All @@ -110,7 +111,7 @@ public boolean run()
{
log.info("Starting MotherloadMine script");
initialize();
mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(this::executeTask, 0, 600, TimeUnit.MILLISECONDS);
mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(this::executeTaskSafely, 0, 600, TimeUnit.MILLISECONDS);
return true;
}

Expand All @@ -123,57 +124,60 @@ private void initialize()
lastLoggedStatus = null;
shouldEmptySack = false;
shouldRepairWaterwheel = false;
emptySackWorkflowActive = false;
}

private void executeTask()
private void executeTaskSafely()
{
// Guard the whole loop body: an unhandled exception on a single tick would otherwise
// silently cancel the scheduleWithFixedDelay task (JDK semantics), freezing the plugin
// on its last status with no log. Catching here lets the next 600ms tick recover state.
try
{
if (!super.run() || !Microbot.isLoggedIn())
{
resetMiningState(true);
return;
}

determineStatusFromInventory();
logStatusTransitionIfChanged();

switch (status)
{
case IDLE:
break;
case MINING:
Rs2Antiban.setActivityIntensity(Rs2Antiban.getActivity().getActivityIntensity());
handleMining();
break;
case EMPTY_SACK:
if (Rs2Player.isAnimating()) return;
Rs2Antiban.setActivityIntensity(ActivityIntensity.EXTREME);
emptySack();
break;
case FIXING_WATERWHEEL:
if (Rs2Player.isAnimating()) return;
fixWaterwheel();
break;
case DEPOSIT_HOPPER:
if (Rs2Player.isAnimating()) return;
depositHopper();
break;
case DROP_GEMS:
if (Rs2Player.isAnimating()) return;
dropGems();
break;
}
executeTask();
}
catch (Exception ex)
{
log.error("MLM executeTask error; recovering on next tick", ex);
log.error("Unhandled error in MLM main loop; resetting runtime state", ex);
abortCurrentWorkflow();
}
}

private void executeTask()
{
if (!super.run() || !isWorkflowRunnable())
{
abortCurrentWorkflow();
return;
}

determineStatusFromInventory();
logStatusTransitionIfChanged();

switch (status)
{
case IDLE:
break;
case MINING:
Rs2Antiban.setActivityIntensity(Rs2Antiban.getActivity().getActivityIntensity());
handleMining();
break;
case EMPTY_SACK:
if (Rs2Player.isAnimating()) return;
Rs2Antiban.setActivityIntensity(ActivityIntensity.EXTREME);
emptySack();
break;
case FIXING_WATERWHEEL:
if (Rs2Player.isAnimating()) return;
fixWaterwheel();
break;
case DEPOSIT_HOPPER:
if (Rs2Player.isAnimating()) return;
depositHopper();
break;
case DROP_GEMS:
if (Rs2Player.isAnimating()) return;
dropGems();
break;
}
}
private String[] SPEC_PICKAXES = {"dragon pickaxe", "crystal pickaxe", "infernal pickaxe"};

private void handlePickaxeSpec() {
Expand Down Expand Up @@ -273,32 +277,89 @@ private boolean isOnSelectedMiningFloor()

private void emptySack()
{
log.info("Emptying sack workflow started");
if (!emptySackWorkflowActive)
{
emptySackWorkflowActive = true;
log.info("Emptying sack workflow started");
}

if (!isWorkflowRunnable())
{
abortCurrentWorkflow();
return;
}

ensureLowerFloor();
if (!isWorkflowRunnable())
{
abortCurrentWorkflow();
return;
}

while ((Microbot.getVarbitValue(VarbitID.MOTHERLODE_SACK_TRANSMIT) > 0 || hasOreInInventory()) && isRunning())
if (Microbot.getVarbitValue(VarbitID.MOTHERLODE_SACK_TRANSMIT) <= 0 && !hasOreInInventory())
{
if (hasOreInInventory())
{
useDepositBox();
}
else if (canDropPayDirt()) {
depositHopper();
}
else
{
rs2TileObjectCache.query().interact(ObjectID.MOTHERLODE_SACK);
sleepUntil(this::hasOreInInventory);
}
completeEmptySackWorkflow();
return;
}

if (hasOreInInventory())
{
useDepositBox();
return;
}

if (canDropPayDirt())
{
depositHopper();
return;
}

rs2TileObjectCache.query().interact(ObjectID.MOTHERLODE_SACK);
sleepUntil(() -> !isWorkflowRunnable() || hasOreInInventory(), 10_000);
}

private void completeEmptySackWorkflow()
{
shouldEmptySack = false;
shouldRepairWaterwheel = false;
emptySackWorkflowActive = false;
Rs2Antiban.takeMicroBreakByChance();
status = MLMStatus.IDLE;
log.info("Emptying sack workflow complete");
}

private boolean isWorkflowRunnable()
{
if (!Microbot.isLoggedIn() || Microbot.pauseAllScripts.get() || Thread.currentThread().isInterrupted())
{
return false;
}

try
{
return Microbot.getClientThread().runOnClientThreadOptional(() -> {
var player = Microbot.getClient().getLocalPlayer();
return player != null && player.getWorldView() != null;
}).orElse(false);
}
catch (RuntimeException ex)
{
log.debug("Player state unavailable during MLM lifecycle transition", ex);
return false;
}
}

private void abortCurrentWorkflow()
{
resetMiningState(true);
status = MLMStatus.IDLE;
idleSince = 0;
shouldEmptySack = false;
shouldRepairWaterwheel = false;
emptySackWorkflowActive = false;
pickedUpHammer = false;
}

private boolean hasOreInInventory()
{
return Rs2Inventory.contains(
Expand Down