Skip to content
Merged
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 @@ -27,7 +27,7 @@
)
@Slf4j
public class ValeTotemPlugin extends Plugin {
static final String version = "1.0.9";
static final String version = "1.0.10";

@Inject
private ValeTotemConfig config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import static net.runelite.client.plugins.microbot.util.Global.sleep;
import static net.runelite.client.plugins.microbot.util.Global.sleepGaussian;
import static net.runelite.client.plugins.microbot.util.Global.sleepUntil;

import java.util.Random;
import net.runelite.client.plugins.microbot.valetotems.enums.TotemLocation;
Expand Down Expand Up @@ -176,26 +177,22 @@ public static boolean withdrawRequiredItems(GameSession gameSession) {
int logId = InventoryUtils.getLogId();
String logTypeName = config != null ? config.logType().getDisplayName() : "Yew Logs";

// Withdraw logs (materials check already performed, so this should succeed)
// Rs2Bank.withdrawX only queues the menu click — it returns immediately and the item
// can lag several ticks behind. Generic waitForInventoryChanges + hasRequiredItems
// was racing and reporting shortages right after a successful withdraw.
Microbot.log("Withdrawing " + logsToWithdraw + " " + logTypeName + " from bank");
boolean withdrew = Rs2Bank.withdrawX(logId, logsToWithdraw);
if (withdrew) {
Microbot.log("Successfully withdrew " + logsToWithdraw + " " + logTypeName);
Rs2Inventory.waitForInventoryChanges(3000);
} else {
Microbot.log("Failed to withdraw logs from bank");
int logsBefore = InventoryUtils.getLogCount();
int expectedLogs = logsBefore + logsToWithdraw;
if (!Rs2Bank.withdrawX(logId, logsToWithdraw)) {
Microbot.log("Failed to queue log withdrawal");
return false;
}

// Final verification
boolean hasRequired = InventoryUtils.hasRequiredItems();
if (hasRequired) {
Microbot.log("Successfully completed item withdrawal - all required items now in inventory");
} else {
Microbot.log("Warning: Required items verification failed after withdrawal");
if (!sleepUntil(() -> InventoryUtils.getLogCount() >= expectedLogs, 3000)) {
Microbot.log("Log withdrawal timed out (have " + InventoryUtils.getLogCount() + "/" + expectedLogs + ")");
return false;
}

return hasRequired;
Microbot.log("Successfully withdrew " + logsToWithdraw + " " + logTypeName);
return InventoryUtils.hasRequiredItems();

} catch (Exception e) {
Microbot.log("Error withdrawing required items: " + e.getMessage());
Expand Down Expand Up @@ -603,14 +600,11 @@ public static boolean ensureLogBasketAvailable() {
// Check if log basket is in bank and withdraw it
if (Rs2Bank.hasItem(InventoryUtils.LOG_BASKET_ID)) {
Microbot.log("Withdrawing log basket from bank for extended route");
boolean withdrew = Rs2Bank.withdrawOne(InventoryUtils.LOG_BASKET_ID);
if (withdrew) {
Rs2Inventory.waitForInventoryChanges(3000);
return InventoryUtils.hasLogBasket();
} else {
Microbot.log("Failed to withdraw log basket from bank");
if (!Rs2Bank.withdrawOne(InventoryUtils.LOG_BASKET_ID)) {
Microbot.log("Failed to queue log basket withdrawal");
return false;
}
return sleepUntil(InventoryUtils::hasLogBasket, 3000);
}

Microbot.log("No log basket found in bank");
Expand Down Expand Up @@ -667,32 +661,37 @@ private static boolean ensureKnifeInInventory(GameSession gameSession) {
return true;
}

// Try to withdraw fletching knife first (prioritized)
// Try to withdraw fletching knife first (prioritized).
// Rs2Bank.withdrawOne returns true as soon as the click is queued; we must wait
// on the concrete predicate (hasKnife), not a generic inventory-change wait,
// or a slow server tick causes a stale "no knife" read right after we withdrew —
// the code then used to fall through and try the regular knife, which isn't in
// the bank either, and report a critical shortage on a knife that was in-flight.
if (Rs2Bank.hasItem(InventoryUtils.FLETCHING_KNIFE_ID)) {
Microbot.log("Withdrawing Fletching knife from bank (prioritized)");
if (Rs2Bank.withdrawOne(InventoryUtils.FLETCHING_KNIFE_ID)) {
Rs2Inventory.waitForInventoryChanges(3000);
if (InventoryUtils.hasKnife()) {
if (sleepUntil(InventoryUtils::hasKnife, 3000)) {
Microbot.log("Successfully withdrew Fletching knife");
return true;
}
} else {
Microbot.log("Failed to withdraw Fletching knife from bank");
Microbot.log("Fletching knife withdrawal timed out");
return false;
}
Microbot.log("Failed to queue Fletching knife withdrawal");
}

// Try to withdraw regular knife as fallback
if (Rs2Bank.hasItem(InventoryUtils.KNIFE_ID)) {
Microbot.log("Withdrawing regular knife from bank");
if (Rs2Bank.withdrawOne(InventoryUtils.KNIFE_ID)) {
Rs2Inventory.waitForInventoryChanges(3000);
if (InventoryUtils.hasKnife()) {
if (sleepUntil(InventoryUtils::hasKnife, 3000)) {
Microbot.log("Successfully withdrew regular knife");
return true;
}
} else {
Microbot.log("Failed to withdraw regular knife from bank");
Microbot.log("Regular knife withdrawal timed out");
return false;
}
Microbot.log("Failed to queue regular knife withdrawal");
}

// No knife found anywhere - critical error
Expand All @@ -717,42 +716,49 @@ private static boolean ensureKnifeAndLogBasketInInventory(GameSession gameSessio
return false;
}

// Ensure we have a knife (prioritizing fletching knife)
// Ensure we have a knife (prioritizing fletching knife). Wait on the concrete
// predicate so a slow inventory update doesn't get misread as "no knife in bank".
if (!InventoryUtils.hasKnife()) {
if (Rs2Bank.hasItem(InventoryUtils.FLETCHING_KNIFE_ID)) {
Microbot.log("Withdrawing Fletching knife from bank (prioritized)");
if (!Rs2Bank.withdrawOne(InventoryUtils.FLETCHING_KNIFE_ID)) {
Microbot.log("Failed to withdraw Fletching knife");
Microbot.log("Failed to queue Fletching knife withdrawal");
return false;
}
} else if (Rs2Bank.hasItem(InventoryUtils.KNIFE_ID)) {
Microbot.log("Withdrawing regular knife from bank");
if (!Rs2Bank.withdrawOne(InventoryUtils.KNIFE_ID)) {
Microbot.log("Failed to withdraw knife");
Microbot.log("Failed to queue knife withdrawal");
return false;
}
} else {
handleCriticalMaterialShortage(gameSession, "No knife available (checked inventory and bank for both Fletching knife and regular knife)");
return false;
}
Rs2Inventory.waitForInventoryChanges(3000);
if (!sleepUntil(InventoryUtils::hasKnife, 3000)) {
Microbot.log("Knife withdrawal timed out");
return false;
}
}

// Ensure we have a log basket
if (!InventoryUtils.hasLogBasket()) {
if (Rs2Bank.hasItem(InventoryUtils.LOG_BASKET_ID)) {
if (!Rs2Bank.withdrawOne(InventoryUtils.LOG_BASKET_ID)) {
Microbot.log("Failed to withdraw log basket");
Microbot.log("Failed to queue log basket withdrawal");
return false;
}
} else {
handleCriticalMaterialShortage(gameSession, "No log basket available (checked inventory and bank)");
return false;
}
Rs2Inventory.waitForInventoryChanges(3000);
if (!sleepUntil(InventoryUtils::hasLogBasket, 3000)) {
Microbot.log("Log basket withdrawal timed out");
return false;
}
}

return InventoryUtils.hasKnife() && InventoryUtils.hasLogBasket();
return true;

} catch (Exception e) {
Microbot.log("Error ensuring knife and log basket in inventory: " + e.getMessage());
Expand Down Expand Up @@ -832,13 +838,18 @@ private static boolean performLogBasketFillingOperation(net.runelite.client.plug
// Step 1: Take inventory full of logs (leaving space for knife and basket)
int logsToWithdraw = InventoryUtils.getOptimalLogBasketLogAmountForExtendedRoute(gameSession) - InventoryUtils.getLogCount();
int logId = InventoryUtils.getLogId();
int logsBeforeFirst = InventoryUtils.getLogCount();

if (!Rs2Bank.withdrawX(logId, logsToWithdraw)) {
Microbot.log("Failed to withdraw logs to fill inventory");
Microbot.log("Failed to queue log withdrawal for basket-fill step");
return false;
}

Rs2Inventory.waitForInventoryChanges(3000);
int expectedAfterFirst = logsBeforeFirst + logsToWithdraw;
if (!sleepUntil(() -> InventoryUtils.getLogCount() >= expectedAfterFirst, 3000)) {
Microbot.log("Log withdrawal timed out in basket-fill step");
return false;
}

// Step 2: Close bank
Rs2Bank.closeBank();
Expand All @@ -861,11 +872,16 @@ private static boolean performLogBasketFillingOperation(net.runelite.client.plug
int logsStillNeeded = InventoryUtils.getOptimalLogAmountForExtendedRoute(gameSession);
if (logsStillNeeded > 0) {
Microbot.log("Withdrawing additional " + logsStillNeeded + " logs for extended route");
int logsBeforeSecond = InventoryUtils.getLogCount();
if (!Rs2Bank.withdrawX(logId, logsStillNeeded)) {
Microbot.log("Failed to withdraw additional logs");
Microbot.log("Failed to queue additional log withdrawal");
return false;
}
int expectedAfterSecond = logsBeforeSecond + logsStillNeeded;
if (!sleepUntil(() -> InventoryUtils.getLogCount() >= expectedAfterSecond, 3000)) {
Microbot.log("Additional log withdrawal timed out");
return false;
}
Rs2Inventory.waitForInventoryChanges(3000);
}

Microbot.log("Log basket filling operation completed successfully");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,19 +295,20 @@ public static boolean selectBow(int quantity) {
}

sleepGaussian(300,100);
// Click the configured bow option using the mapper
if (config != null) {
int bowChildId = FletchingItemMapper.getFletchingInterfaceChildId(config.logType(), config.bowType());
String description = FletchingItemMapper.getFletchingDescriptionWithShortcut(config.logType(), config.bowType());
interactWithWidget(bowChildId, description);
Microbot.log("Selected " + FletchingItemMapper.getFletchingDescription(config.logType(), config.bowType()));
} else {
// Fallback to yew longbow
interactWithWidget(16, "Yew Longbow (u) (expected key: 3)");
Microbot.log("Selected Yew Longbow (u) - fallback");

// Select the configured bow option by name — resolves the correct hotkey dynamically
// against the actual fletching interface layout, instead of assuming fixed child IDs.
// The previous child-ID scheme mapped SHORTBOW → child 15 with hotkey-index 1, but the
// sparse dynamic-children layout of widget 270,13 in skillmulti could produce "3" at
// that slot for some log types, so shortbow-selected was pressing the longbow key.
String bowAction = (config != null && config.bowType() == ValeTotemConfig.BowType.SHORTBOW)
? "shortbow" : "longbow";
if (!Rs2Widget.handleProcessingInterface(bowAction)) {
Microbot.log("Failed to select " + bowAction + " from fletching interface");
return false;
}

Microbot.log("Selected " + bowAction);

sleepGaussian(200,100);

return true;
Expand Down
Loading