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
50 changes: 21 additions & 29 deletions src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
import net.runelite.api.events.InteractingChanged;
import net.runelite.api.events.SoundEffectPlayed;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.VarClientIntChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.gameval.VarPlayerID;
import net.runelite.api.gameval.VarbitID;
Expand Down Expand Up @@ -123,7 +122,7 @@ public enum AttackState
public Color CurrentColor = Color.WHITE;

private Spellbook currentSpellBook = Spellbook.STANDARD;
private int lastEquippingMonotonicValue = -1;
private int lastUsedWeaponId = -1;
private int soundEffectTick = -1;
private int soundEffectId = -1;
private boolean isUsingMagic = false;
Expand Down Expand Up @@ -206,31 +205,6 @@ public void onVarbitChanged(VarbitChanged varbitChanged)
}
}

// onVarbitChanged happens when the user causes some interaction therefore we can't rely on some fixed
// timing relative to a tick. A player can swap many items in the duration of the a tick.
@Subscribe
public void onVarClientIntChanged(VarClientIntChanged varClientIntChanged)
{
if (!config.enableMetronome()) return;
final int currentMagicVarBit = client.getVarcIntValue(EQUIPPING_MONOTONIC);
if (currentMagicVarBit <= lastEquippingMonotonicValue)
{
return;
}
lastEquippingMonotonicValue = currentMagicVarBit;

// This windowing safe guards of from late swaps inside a tick, if we have already rendered the tick
// then we shouldn't perform another attack.
boolean preAttackWindow = attackState == AttackState.DELAYED_FIRST_TICK && renderedState != attackState;
if (preAttackWindow)
{
// "Perform an attack" this is overwrites the last attack since we now know the user swapped
// "Something" this tick, the equipped weapon detection will pick up specific weapon swaps. Even
// swapping more than 1 weapon inside a single tick.
performAttack();
}
}

// onSoundEffectPlayed used to track spell casts, for when the player casts a spell on first tick coming
// off cooldown, in some cases (e.g. ice barrage) the player will have no animation. Also they don't have
// a projectile to detect instead :/
Expand Down Expand Up @@ -341,6 +315,7 @@ private void setAttackDelay()
PoweredStaves stave = PoweredStaves.getPoweredStaves(weaponId, curAnimation);
boolean matchesSpellbook = matchesSpellbook(curAnimation);
attackDelayHoldoffTicks = getWeaponSpeed(weaponId, stave, curAnimation, matchesSpellbook);
lastUsedWeaponId = weaponId;
}

// matchesSpellbook tries two methods, matching the animation the spell book based on the enum of
Expand Down Expand Up @@ -570,7 +545,7 @@ public void onGameTick(GameTick tick)
}
else
{
uiHideDebounceTickCount--;
uiHideDebounceTickCount = Math.max(-20, uiHideDebounceTickCount - 1);
}
break;
case DELAYED_FIRST_TICK:
Expand Down Expand Up @@ -648,7 +623,6 @@ public void writeState(ByteArrayDataOutput outChannel)
sb.append("renderedState: "); sb.append(this.renderedState);sb.append(SEPARATOR);
sb.append("pendingEatDelayTicks: "); sb.append(this.pendingEatDelayTicks);sb.append(SEPARATOR);
sb.append("currentSpellBook: "); sb.append(this.currentSpellBook);sb.append(SEPARATOR);
sb.append("lastEquippingMonotonicValue: "); sb.append(this.lastEquippingMonotonicValue);sb.append(SEPARATOR);
sb.append("soundEffectTick: "); sb.append(this.soundEffectTick);sb.append(SEPARATOR);
sb.append("soundEffectId: "); sb.append(this.soundEffectId);sb.append("\n");
// @formatter:on
Expand All @@ -672,5 +646,23 @@ public void onRender()
attackState = AttackState.NOT_ATTACKING;
}
}
checkForLateWeaponSwaps();
}

public void checkForLateWeaponSwaps()
{
final boolean weaponMisMatch = Utils.getWeaponId(client) != lastUsedWeaponId;

// This windowing safe guards of from late swaps inside a tick, if we have already rendered the tick
// then we shouldn't perform another attack.
final boolean preAttackWindow = attackState == AttackState.DELAYED_FIRST_TICK && renderedState != attackState;
if (preAttackWindow && weaponMisMatch)
{
// "Perform an attack" this is overwrites the last attack since we now know the user swapped
// "Something" this tick, the equipped weapon detection will pick up specific weapon swaps. Even
// swapping more than 1 weapon inside a single tick.
performAttack();
}
}

}
1 change: 0 additions & 1 deletion src/test/java/com/attacktimer/IntegrationTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ protected void performStateVerificationOrUpdate(ByteArrayDataOutput channel, Pat
try (var file = Files.newByteChannel(path, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE)))
{
file.write(ByteBuffer.wrap(actualBytes));
file.close();
}
fail("Updated file: " + path);
return;
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/com/attacktimer/testdata/PunishTest.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
tickPeriod: 0, uiHideDebounceTickCount: 0, attackDelayHoldoffTicks: 0, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: -1, attackDelayHoldoffTicks: -1, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 4, uiHideDebounceTickCount: 1, attackDelayHoldoffTicks: 3, attackState: DELAYED_FIRST_TICK, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: 0, attackDelayHoldoffTicks: 0, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: -1, attackDelayHoldoffTicks: -1, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 4, uiHideDebounceTickCount: 1, attackDelayHoldoffTicks: 3, attackState: DELAYED_FIRST_TICK, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
6 changes: 3 additions & 3 deletions src/test/java/com/attacktimer/testdata/PunishWastedTest.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
tickPeriod: 0, uiHideDebounceTickCount: 0, attackDelayHoldoffTicks: 0, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: -1, attackDelayHoldoffTicks: -1, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 4, uiHideDebounceTickCount: 1, attackDelayHoldoffTicks: 3, attackState: DELAYED_FIRST_TICK, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: 0, attackDelayHoldoffTicks: 0, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: -1, attackDelayHoldoffTicks: -1, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 4, uiHideDebounceTickCount: 1, attackDelayHoldoffTicks: 3, attackState: DELAYED_FIRST_TICK, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
tickPeriod: 0, uiHideDebounceTickCount: 0, attackDelayHoldoffTicks: 0, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: -1, attackDelayHoldoffTicks: -1, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 8, uiHideDebounceTickCount: 1, attackDelayHoldoffTicks: 7, attackState: DELAYED_FIRST_TICK, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, lastEquippingMonotonicValue: -1, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: 0, attackDelayHoldoffTicks: 0, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 0, uiHideDebounceTickCount: -1, attackDelayHoldoffTicks: -1, attackState: NOT_ATTACKING, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
tickPeriod: 8, uiHideDebounceTickCount: 1, attackDelayHoldoffTicks: 7, attackState: DELAYED_FIRST_TICK, renderedState: NOT_ATTACKING, pendingEatDelayTicks: 0, currentSpellBook: STANDARD, soundEffectTick: -1, soundEffectId: -1
Loading
Loading