mirror of
https://github.com/smogon/pokemon-showdown-client.git
synced 2026-03-21 17:50:29 -05:00
Fix performance on long battles
1000-turn battles often took over a minute to load, but they should now be loaded in a few seconds. In addition, loading no longer freezes tabs, and skipping several turns back should be a lot more performant. There are two tricks here: 1. Every 300ms, we rest for 1ms to let the event loop run, which doesn't provide _that_ much UI responsiveness, but enough for the tab not to freeze entirely, and allows things like leaving the battle or clicking "Prev turn" multiple times in a row. 2. Instead of writing every single turn to the battle log when skipping to the end of a replay (such as when joining a battle), we only write the most recent 100 turns. This drastically speeds up loading.
This commit is contained in:
parent
7ba9053742
commit
fc00e68231
|
|
@ -176,14 +176,14 @@ var Replays = {
|
|||
this.battle.reset();
|
||||
},
|
||||
ff: function () {
|
||||
this.battle.skipTurn();
|
||||
this.battle.seekBy(1);
|
||||
},
|
||||
rewind: function () {
|
||||
this.battle.seekTurn(this.battle.turn - 1);
|
||||
this.battle.seekBy(-1);
|
||||
},
|
||||
ffto: function () {
|
||||
var turn = prompt('Turn?');
|
||||
if (!turn.trim()) return;
|
||||
if (!turn || !turn.trim()) return;
|
||||
if (turn === 'e' || turn === 'end' || turn === 'f' || turn === 'finish') turn = Infinity;
|
||||
turn = Number(turn);
|
||||
if (isNaN(turn) || turn < 0) alert("Invalid turn");
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ export class BattleLog {
|
|||
scene: BattleScene | null = null;
|
||||
preemptElem: HTMLDivElement = null!;
|
||||
atBottom = true;
|
||||
skippedLines = false;
|
||||
className: string;
|
||||
battleParser: BattleTextParser | null = null;
|
||||
joinLeave: {
|
||||
|
|
@ -78,12 +79,42 @@ export class BattleLog {
|
|||
reset() {
|
||||
this.innerElem.innerHTML = '';
|
||||
this.atBottom = true;
|
||||
this.skippedLines = false;
|
||||
}
|
||||
destroy() {
|
||||
this.elem.onscroll = null;
|
||||
}
|
||||
addSeekEarlierButton() {
|
||||
if (this.skippedLines) return;
|
||||
this.skippedLines = true;
|
||||
const el = document.createElement('div');
|
||||
el.className = 'chat';
|
||||
el.innerHTML = '<button class="button earlier-button"><i class="fa fa-caret-up"></i><br />Earlier messages</button>';
|
||||
const button = el.getElementsByTagName('button')[0];
|
||||
button?.addEventListener?.('click', e => {
|
||||
e.preventDefault();
|
||||
this.scene?.battle.seekTurn(this.scene.battle.turn - 100);
|
||||
});
|
||||
this.addNode(el);
|
||||
}
|
||||
add(args: Args, kwArgs?: KWArgs, preempt?: boolean) {
|
||||
if (kwArgs?.silent) return;
|
||||
if (this.scene?.battle.seeking) {
|
||||
const battle = this.scene.battle;
|
||||
if (battle.stepQueue.length > 2000) {
|
||||
// adding elements gets slower and slower the more there are
|
||||
// (so showing 100 turns takes around 2 seconds, and 1000 turns takes around a minute)
|
||||
// capping at 100 turns makes everything _reasonably_ snappy
|
||||
if (
|
||||
battle.seeking === Infinity ?
|
||||
battle.currentStep < battle.stepQueue.length - 2000 :
|
||||
battle.turn < battle.seeking! - 100
|
||||
) {
|
||||
this.addSeekEarlierButton();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let divClass = 'chat';
|
||||
let divHTML = '';
|
||||
let noNotify: boolean | undefined;
|
||||
|
|
|
|||
|
|
@ -3734,13 +3734,19 @@ export class Battle {
|
|||
this.subscription?.('playing');
|
||||
}
|
||||
skipTurn() {
|
||||
this.seekTurn(this.turn + 1);
|
||||
this.seekBy(1);
|
||||
}
|
||||
seekBy(deltaTurn: number) {
|
||||
if (this.seeking === Infinity && deltaTurn < 0) {
|
||||
return this.seekTurn(this.turn + 1);
|
||||
}
|
||||
this.seekTurn((this.seeking ?? this.turn) + deltaTurn);
|
||||
}
|
||||
seekTurn(turn: number, forceReset?: boolean) {
|
||||
if (isNaN(turn)) return;
|
||||
turn = Math.max(Math.floor(turn), 0);
|
||||
|
||||
if (this.seeking !== null && this.seeking > turn && !forceReset) {
|
||||
if (this.seeking !== null && turn > this.turn && !forceReset) {
|
||||
this.seeking = turn;
|
||||
return;
|
||||
}
|
||||
|
|
@ -3779,9 +3785,11 @@ export class Battle {
|
|||
nextStep() {
|
||||
if (!this.shouldStep()) return;
|
||||
|
||||
let time = Date.now();
|
||||
this.scene.startAnimations();
|
||||
let animations = undefined;
|
||||
|
||||
let interruptionCount: number;
|
||||
do {
|
||||
this.waitForAnimations = true;
|
||||
if (this.currentStep >= this.stepQueue.length) {
|
||||
|
|
@ -3802,6 +3810,16 @@ export class Battle {
|
|||
} else if (this.waitForAnimations === 'simult') {
|
||||
this.scene.timeOffset = 0;
|
||||
}
|
||||
|
||||
if (Date.now() - time > 300) {
|
||||
interruptionCount = this.scene.interruptionCount;
|
||||
setTimeout(() => {
|
||||
if (interruptionCount === this.scene.interruptionCount) {
|
||||
this.nextStep();
|
||||
}
|
||||
}, 1);
|
||||
return;
|
||||
}
|
||||
} while (!animations && this.shouldStep());
|
||||
|
||||
if (this.paused && this.turn >= 0 && this.seeking === null) {
|
||||
|
|
@ -3812,7 +3830,7 @@ export class Battle {
|
|||
|
||||
if (!animations) return;
|
||||
|
||||
const interruptionCount = this.scene.interruptionCount;
|
||||
interruptionCount = this.scene.interruptionCount;
|
||||
animations.done(() => {
|
||||
if (interruptionCount === this.scene.interruptionCount) {
|
||||
this.nextStep();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user