Skip to content

Commit f0a5a4a

Browse files
committed
feat: implement async cache operations and file-based storage for Rs2CacheManager
- Add async save/load operations (savePersistentCachesAsync, loadCachesAsync) using CompletableFuture - Implement file-based cache storage under .runelite/microbot-profiles to prevent profile bloat - Add cloud sync configuration option for optional RuneLite profile synchronization - Enhance CacheMetadata with data integrity checks and debugging information - Improve profile change handling with async operations and proper operation chaining - Add dedicated thread pool (cacheManagerExecutor) for cache persistence operations - Implement operation tracking to prevent concurrent save/load conflicts - Update skill level checks in PathfinderConfig to use cached values when available - Add graceful shutdown handling with timeout for ongoing cache operations - Improve error handling and logging throughout cache management system
1 parent c5d503d commit f0a5a4a

6 files changed

Lines changed: 513 additions & 183 deletions

File tree

runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotConfig.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ public interface MicrobotConfig extends Config
3434
)
3535
String cacheSection = "cacheSection";
3636

37+
@ConfigSection(
38+
name = "Cloud sync",
39+
description = "Cache data synchronization settings",
40+
position = 3
41+
)
42+
String cloudSyncSection = "cloudSyncSection";
43+
3744
String keyEnableGameChatLogging = "enableGameChatLogging";
3845
@ConfigItem(
3946
keyName = keyEnableGameChatLogging,
@@ -111,6 +118,18 @@ default boolean isRs2CacheEnabled() {
111118
return false;
112119
}
113120

121+
String keyEnableCacheCloudSync = "enableCacheCloudSync";
122+
@ConfigItem(
123+
keyName = keyEnableCacheCloudSync,
124+
name = "Enable cache cloud sync",
125+
description = "Sync cache data to RuneLite profile (compressed). This allows cache data to sync across devices but may increase profile size.",
126+
position = 0,
127+
section = cloudSyncSection
128+
)
129+
default boolean enableCacheCloudSync() {
130+
return false;
131+
}
132+
114133
@AllArgsConstructor
115134
enum GameChatLogLevel {
116135
ERROR("Error", Level.ERROR),

runelite-client/src/main/java/net/runelite/client/plugins/microbot/MicrobotPlugin.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ public void onRuneScapeProfileChanged(RuneScapeProfileChanged event)
221221
{
222222
log.info("\nReceived RuneScape profile change event from '{}' to '{}'", oldProfile, newProfile);
223223
if (microbotConfig.isRs2CacheEnabled()) {
224+
// Use async profile change to avoid blocking client thread
224225
Rs2CacheManager.handleProfileChange(newProfile, oldProfile);
226+
log.info("Initiated async profile change from '{}' to '{}'", oldProfile, newProfile);
225227
}
226228
return;
227229
}
@@ -535,9 +537,17 @@ public void onGameTick(GameTick event)
535537
@Subscribe(priority = 100)
536538
private void onClientShutdown(ClientShutdown e)
537539
{
538-
// Save all caches through Rs2CacheManager
540+
// Save all caches through Rs2CacheManager using async operations
539541
if (microbotConfig.isRs2CacheEnabled()) {
540-
Rs2CacheManager.savePersistentCaches();
542+
try {
543+
// Use async save but wait for completion during shutdown
544+
Rs2CacheManager.savePersistentCachesAsync().get(30, java.util.concurrent.TimeUnit.SECONDS);
545+
log.info("Successfully saved all caches asynchronously during shutdown");
546+
} catch (Exception ex) {
547+
log.error("Failed to save caches during shutdown: {}", ex.getMessage(), ex);
548+
// Fallback to synchronous save if async fails
549+
Rs2CacheManager.savePersistentCaches();
550+
}
541551
Rs2CacheManager.getInstance().close();
542552
}
543553
}

runelite-client/src/main/java/net/runelite/client/plugins/microbot/shortestpath/pathfinder/PathfinderConfig.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import net.runelite.client.plugins.microbot.util.poh.PohTeleports;
2525
import net.runelite.client.plugins.microbot.util.tabs.Rs2Tab;
2626
import net.runelite.client.plugins.microbot.util.walker.Rs2Walker;
27-
27+
import net.runelite.client.plugins.microbot.util.cache.Rs2SkillCache;
2828
import java.util.*;
2929
import java.util.concurrent.ConcurrentHashMap;
3030
import java.util.concurrent.CopyOnWriteArrayList;
@@ -539,7 +539,13 @@ private boolean hasRequiredLevels(Transport transport) {
539539
Skill[] skills = Skill.values();
540540
return IntStream.range(0, requiredLevels.length)
541541
.filter(i -> requiredLevels[i] > 0)
542-
.allMatch(i -> Microbot.getClient().getBoostedSkillLevel(skills[i]) >= requiredLevels[i]);
542+
.allMatch(i -> {
543+
if (Microbot.isRs2CacheEnabled()) {
544+
return Rs2SkillCache.getBoostedSkillLevel(skills[i]) >= requiredLevels[i];
545+
} else {
546+
return Microbot.getClient().getBoostedSkillLevel(skills[i]) >= requiredLevels[i];
547+
}
548+
});
543549
}
544550

545551
/** Checks if the player has all the required skill levels for the restriction */
@@ -548,7 +554,13 @@ private boolean hasRequiredLevels(Restriction restriction) {
548554
Skill[] skills = Skill.values();
549555
return IntStream.range(0, requiredLevels.length)
550556
.filter(i -> requiredLevels[i] > 0)
551-
.allMatch(i -> Microbot.getClient().getBoostedSkillLevel(skills[i]) >= requiredLevels[i]);
557+
.allMatch(i -> {
558+
if (Microbot.isRs2CacheEnabled()) {
559+
return Rs2SkillCache.getBoostedSkillLevel(skills[i]) >= requiredLevels[i];
560+
} else {
561+
return Microbot.getClient().getBoostedSkillLevel(skills[i]) >= requiredLevels[i];
562+
}
563+
});
552564
}
553565

554566
private void updateActionBasedOnQuestState(Transport transport) {

runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/cache/Rs2Cache.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,10 +577,11 @@ public synchronized void invalidateAll() {
577577
* Gets the cache timestamp for a specific key.
578578
*
579579
* @param key The key to get the timestamp for
580-
* @return The timestamp when the key was cached, or null if not found
580+
* @return The timestamp when the key was cached, or -1 if not found
581581
*/
582-
public Long getCacheTimestamp(K key) {
583-
return cacheTimestamps.get(key);
582+
public long getCacheTimestamp(K key) {
583+
Long timestamp = cacheTimestamps.get(key);
584+
return timestamp != null ? timestamp : 0L;
584585
}
585586

586587
// ============================================

0 commit comments

Comments
 (0)