feat: Rollback steps back through the last 50 interactions (wheel up, PageUp, Rollback action)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ea351e44b3
commit
7652f7d010
2 files changed
+28
-2
No files matched your search
@@ -48,6 +48,9 @@ function fontGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
/** How many interactions Rollback can step back through. */
|
||||
const ROLLBACK_LIMIT = 50;
|
||||
|
||||
export class Engine {
|
||||
private liveImages?: LiveImages;
|
||||
private imageScales = new Map<string, number>();
|
||||
@@ -83,6 +86,8 @@ export class Engine {
|
||||
private windowShown = true;
|
||||
private lastSay: { name: string; text: string; color?: string; char?: CharacterDef } | null = null;
|
||||
private history: { name: string; text: string }[] = [];
|
||||
/** One state per interaction, newest last: what Rollback steps back through. */
|
||||
private rollbackLog: { snap: SaveData; history: { name: string; text: string }[] }[] = [];
|
||||
private nvlLines: HTMLElement[] = [];
|
||||
private interactions = 0;
|
||||
|
||||
@@ -1061,6 +1066,7 @@ export class Engine {
|
||||
quit: () => this.onExit(),
|
||||
mainMenu: () => this.restart(() => { this.stack = []; this.cur = { label: "", path: [0] }; }),
|
||||
openMenu: () => this.openGameMenu(),
|
||||
rollback: () => this.rollback(),
|
||||
openUrl: (url) => {
|
||||
if (/^https?:\/\//i.test(url)) window.open(url, "_blank", "noopener,noreferrer");
|
||||
},
|
||||
@@ -1531,11 +1537,24 @@ export class Engine {
|
||||
|
||||
private interactionStart() {
|
||||
this.renderer.commit();
|
||||
this.rollbackLog.push({ snap: this.snapshotState(), history: this.history.slice() });
|
||||
if (this.rollbackLog.length > ROLLBACK_LIMIT) this.rollbackLog.shift();
|
||||
this.interactions++;
|
||||
if (this.interactions % 15 === 0) void this.save("auto", true);
|
||||
this.preloadAhead();
|
||||
}
|
||||
|
||||
/** Back to the previous interaction: the one being shown is dropped, the one before it is shown again. */
|
||||
private rollback() {
|
||||
if (!this.running || this.rollbackLog.length < 2) return;
|
||||
this.rollbackLog.pop();
|
||||
const entry = this.rollbackLog.pop()!;
|
||||
this.restart(() => {
|
||||
this.applySave(entry.snap);
|
||||
this.history = entry.history;
|
||||
});
|
||||
}
|
||||
|
||||
private preloadAhead() {
|
||||
const block = this.labels.has(this.cur.label) ? this.blockFor(this.cur) : [];
|
||||
const start = this.cur.path[this.cur.path.length - 1];
|
||||
@@ -1878,6 +1897,7 @@ export class Engine {
|
||||
this.newStore();
|
||||
this.stack = [];
|
||||
this.history = [];
|
||||
this.rollbackLog = [];
|
||||
this.lastSay = null;
|
||||
this.textbox.classList.add("pg-hidden");
|
||||
this.cur = at ?? { label: this.game.entry, path: [0] };
|
||||
@@ -1973,6 +1993,7 @@ export class Engine {
|
||||
}
|
||||
if (!data.revision && !(await this.confirmAsk("Старое сохранение не содержит ревизию игры. После изменения скрипта его позиции могут быть неверны. Попробовать загрузить?", "Загрузить"))) return;
|
||||
this.replayStash = null;
|
||||
this.rollbackLog = [];
|
||||
this.restart(() => this.applySave(data));
|
||||
}
|
||||
|
||||
@@ -2123,7 +2144,7 @@ export class Engine {
|
||||
this.advanceInput();
|
||||
});
|
||||
stage.addEventListener("wheel", (ev) => {
|
||||
if (ev.deltaY < 0 && this.screen.classList.contains("pg-hidden") && this.running) this.openHistory();
|
||||
if (ev.deltaY < 0 && this.screen.classList.contains("pg-hidden") && this.running) this.rollback();
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
@@ -2203,6 +2224,9 @@ export class Engine {
|
||||
this.setSkip(!this.skip);
|
||||
} else if (ev.key === "a" || ev.key === "ф") {
|
||||
this.setAuto(!this.auto);
|
||||
} else if (ev.key === "PageUp") {
|
||||
ev.preventDefault();
|
||||
this.rollback();
|
||||
} else if (ev.key === "h" || ev.key === "р") {
|
||||
this.textbox.classList.toggle("pg-ui-hidden");
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ export interface ScreenHost {
|
||||
quit(): void;
|
||||
mainMenu(): void;
|
||||
openMenu(): void;
|
||||
/** The Rollback action: back to the previous interaction. */
|
||||
rollback?(): void;
|
||||
openUrl(url: string): void;
|
||||
quickSave(): void;
|
||||
quickLoad(): void;
|
||||
@@ -1797,7 +1799,7 @@ export class ScreenManager {
|
||||
case "UploadSync":
|
||||
case "DownloadSync": this.host.notify("Синхронизация недоступна в браузере"); return;
|
||||
case "Skip": this.host.setSkipping?.(true); return;
|
||||
case "Rollback": return; // there is no rollback in the browser player
|
||||
case "Rollback": this.host.rollback?.(); return;
|
||||
case "ToggleLocalVariable": {
|
||||
const now = owner?.vars.get(a);
|
||||
owner?.vars.set(a, !truthy(now));
|
||||
|
||||
Reference in new issue
Block a user