Skip to content

Commit

Permalink
fix(level): avoid early initialization of skills (pajlads#514)
Browse files Browse the repository at this point in the history
  • Loading branch information
iProdigy authored Aug 13, 2024
1 parent 538efa1 commit efea3ac
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Unreleased

- Minor: Include rarity and luck for pet notifications. (#433)
- Bugfix: Avoid level notification upon login. (#514)
- Bugfix: Avoid outdated notification data if disabling and enabling notifiers over time. (#515)
- Dev: Add raid party members to loot notification metadata. (#478)

Expand Down
42 changes: 19 additions & 23 deletions src/main/java/dinkplugin/notifiers/LevelNotifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import net.runelite.api.events.StatChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.util.QuantityFormatter;
import org.jetbrains.annotations.VisibleForTesting;

import javax.inject.Inject;
import javax.inject.Singleton;
Expand All @@ -29,25 +30,23 @@
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import static net.runelite.api.Experience.MAX_REAL_LEVEL;

@Slf4j
@Singleton
public class LevelNotifier extends BaseNotifier {
public static final int LEVEL_FOR_MAX_XP = Experience.MAX_VIRT_LEVEL + 1; // 127
private static final int INIT_GAME_TICKS = 25; // 15s
static final @VisibleForTesting int INIT_GAME_TICKS = 16; // ~10s
private static final int SKILL_COUNT = Skill.values().length;
private static final String COMBAT_NAME = "Combat";
private static final Set<String> COMBAT_COMPONENTS;
private final BlockingQueue<String> levelledSkills = new ArrayBlockingQueue<>(Skill.values().length + 1);
private final BlockingQueue<String> levelledSkills = new ArrayBlockingQueue<>(SKILL_COUNT + 1);
private final Set<Skill> xpReached = EnumSet.noneOf(Skill.class);
private final Map<String, Integer> currentLevels = new HashMap<>();
private final Map<Skill, Integer> currentXp = new EnumMap<>(Skill.class);
private final AtomicInteger ticksWaited = new AtomicInteger();
private final AtomicInteger initTicks = new AtomicInteger();
private final AtomicBoolean shouldInit = new AtomicBoolean();
private int ticksWaited = 0;
private int initTicks = 0;

@Inject
private ClientThread clientThread;
Expand All @@ -68,41 +67,39 @@ private void initLevels() {
currentXp.put(skill, xp);
}
currentLevels.put(COMBAT_NAME, calculateCombatLevel());
initTicks.set(0);
this.initTicks = 0;
log.debug("Initialized current skill levels: {}", currentLevels);
}

public void reset() {
shouldInit.set(false);
initTicks.set(0);
levelledSkills.clear();
ticksWaited.set(0);
clientThread.invoke(() -> {
this.initTicks = 0;
this.ticksWaited = 0;
xpReached.clear();
currentXp.clear();
currentLevels.clear();
});
}

public void onTick() {
if (shouldInit.getAndSet(false)) {
if (this.initTicks > INIT_GAME_TICKS) {
initLevels();
return;
}

if (currentLevels.isEmpty()) {
shouldInit.compareAndSet(false, initTicks.incrementAndGet() > INIT_GAME_TICKS);
if (currentLevels.size() < SKILL_COUNT) {
this.initTicks++;
return;
}

if (levelledSkills.isEmpty() && xpReached.isEmpty()) {
return;
}

int ticks = ticksWaited.incrementAndGet();
// We wait a couple extra ticks so we can ensure that we process all the levels of the previous tick
if (ticks > 2) {
ticksWaited.set(0);
if (++this.ticksWaited > 2) {
this.ticksWaited = 0;
// ensure notifier was not disabled during ticks waited
if (isEnabled()) {
attemptNotify();
Expand All @@ -123,11 +120,10 @@ public void onGameStateChanged(GameStateChanged gameStateChanged) {
}

private void handleLevelUp(Skill skill, int level, int xp) {
if (!isEnabled()) return;
if (xp <= 0 || level <= 1 || !isEnabled()) return;

Integer previousXp = currentXp.put(skill, xp);
if (previousXp == null) {
shouldInit.set(true);
return;
}

Expand All @@ -136,7 +132,7 @@ private void handleLevelUp(Skill skill, int level, int xp) {
Integer previousLevel = currentLevels.put(skillName, virtualLevel);

if (previousLevel == null) {
shouldInit.set(true);
this.initTicks = INIT_GAME_TICKS; // force init on next tick
return;
}

Expand All @@ -157,7 +153,7 @@ private void handleLevelUp(Skill skill, int level, int xp) {
if (remainder == 0 || xp - remainder > previousXp || xp >= Experience.MAX_SKILL_XP) {
log.debug("Observed XP milestone for {} to {}", skill, xp);
xpReached.add(skill);
ticksWaited.set(0);
this.ticksWaited = 0;
}
}

Expand All @@ -169,7 +165,7 @@ private void handleLevelUp(Skill skill, int level, int xp) {
}

// Check for combat level increase
if (COMBAT_COMPONENTS.contains(skillName)) {
if (COMBAT_COMPONENTS.contains(skillName) && currentLevels.size() >= SKILL_COUNT) {
int combatLevel = calculateCombatLevel();
Integer previousCombatLevel = currentLevels.put(COMBAT_NAME, combatLevel);
checkLevelUp(enabled && config.levelNotifyCombat(), COMBAT_NAME, previousCombatLevel, combatLevel);
Expand All @@ -196,7 +192,7 @@ private void checkLevelUp(boolean configEnabled, String skill, Integer previousL
log.debug("Observed level up for {} to {}", skill, currentLevel);

// allow more accumulation of level ups into single notification
ticksWaited.set(0);
this.ticksWaited = 0;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/java/dinkplugin/notifiers/LevelNotifierTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected void setUp() {
plugin.onStatChanged(new StatChanged(Skill.HUNTER, 300, 4, 4));
plugin.onStatChanged(new StatChanged(Skill.SLAYER, 9_800_000, 96, 96));
plugin.onStatChanged(new StatChanged(Skill.FARMING, Experience.MAX_SKILL_XP, 99, 99));
notifier.onTick();
IntStream.rangeClosed(0, LevelNotifier.INIT_GAME_TICKS + 1).forEach(i -> notifier.onTick());
}

@Test
Expand Down

0 comments on commit efea3ac

Please sign in to comment.