mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-27 13:29:32 +00:00
load/saveControlsState() support in recorder
This commit is contained in:
parent
d9c41ca9d7
commit
86823c2c21
@ -54,6 +54,7 @@ TODO:
|
||||
- make sure we don't store files in local storage unnecc.
|
||||
- state buffer/replay
|
||||
- intro/help text for each platform
|
||||
- make sure controls work with replay feature (we'll have to save control state every frame)
|
||||
|
||||
FYI: Image links for the books on http://8bitworkshop.com/ are broken
|
||||
On the website the additional grey spacing next to the program line numbers is not dynamically resized when the web browser window size is changed. Intentional?
|
||||
|
@ -19,8 +19,16 @@ export interface CpuState {
|
||||
A:number, X:number, Y:number, SP:number, R:boolean,
|
||||
N,V,D,Z,C:boolean*/
|
||||
};
|
||||
export interface EmuState {c:CpuState, b?:number[]};
|
||||
export type DisasmLine = {line:string, nbytes:number};
|
||||
export interface EmuState {
|
||||
c:CpuState, // CPU state
|
||||
b?:number[] // RAM
|
||||
};
|
||||
export interface EmuControlsState {
|
||||
}
|
||||
export type DisasmLine = {
|
||||
line:string,
|
||||
nbytes:number
|
||||
};
|
||||
|
||||
export interface Platform {
|
||||
start() : void;
|
||||
@ -60,6 +68,8 @@ export interface Platform {
|
||||
|
||||
setRecorder?(recorder : EmuRecorder) : void;
|
||||
advance?(novideo? : boolean) : void;
|
||||
loadControlsState?(state : EmuControlsState) : void;
|
||||
saveControlsState?() : EmuControlsState;
|
||||
}
|
||||
|
||||
export interface Preset {
|
||||
@ -80,7 +90,7 @@ type BreakpointCallback = (EmuState) => void;
|
||||
|
||||
export interface EmuRecorder {
|
||||
frameRequested() : boolean;
|
||||
recordFrame(platform : Platform, state : EmuState);
|
||||
recordFrame(state : EmuState);
|
||||
}
|
||||
|
||||
/////
|
||||
@ -132,7 +142,7 @@ abstract class BaseDebugPlatform {
|
||||
updateRecorder() {
|
||||
// are we recording and do we need to save a frame?
|
||||
if (this.recorder && (<Platform><any>this).isRunning() && this.recorder.frameRequested()) {
|
||||
this.recorder.recordFrame(<Platform><any>this, this.saveState());
|
||||
this.recorder.recordFrame(this.saveState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,6 +335,14 @@ var Apple2Platform = function(mainElement) {
|
||||
lc:{s:auxRAMselected,b:auxRAMbank,w:writeinhibit},
|
||||
};
|
||||
}
|
||||
this.loadControlsState = function(state) {
|
||||
kbdlatch = state.kbd;
|
||||
}
|
||||
this.saveControlsState = function() {
|
||||
return {
|
||||
kbd:kbdlatch,
|
||||
};
|
||||
}
|
||||
this.getCPUState = function() {
|
||||
return cpu.saveState();
|
||||
}
|
||||
|
83
src/recorder.ts
Normal file
83
src/recorder.ts
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
import { Platform, EmuState, EmuControlsState, EmuRecorder } from "./baseplatform";
|
||||
|
||||
export class StateRecorderImpl implements EmuRecorder {
|
||||
checkpointInterval : number = 60;
|
||||
callbackStateChanged : () => void;
|
||||
maxCheckpoints : number = 120;
|
||||
|
||||
platform : Platform;
|
||||
buffer : EmuState[];
|
||||
controls : EmuControlsState[];
|
||||
frameCount : number;
|
||||
lastSeekFrame : number = -1;
|
||||
|
||||
constructor(platform : Platform) {
|
||||
this.reset();
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.buffer = [];
|
||||
this.controls = [];
|
||||
this.frameCount = 0;
|
||||
this.lastSeekFrame = -1;
|
||||
}
|
||||
|
||||
frameRequested() : boolean {
|
||||
// buffer full?
|
||||
if (this.buffer.length >= this.maxCheckpoints) {
|
||||
return false;
|
||||
}
|
||||
// record the control state, if available
|
||||
if (this.platform.saveControlsState) {
|
||||
this.controls.push(this.platform.saveControlsState());
|
||||
}
|
||||
// pick up where we left off, if we used the seek function
|
||||
if (this.lastSeekFrame >= 0) {
|
||||
this.frameCount = this.lastSeekFrame;
|
||||
this.lastSeekFrame = -1;
|
||||
// truncate buffers
|
||||
this.buffer = this.buffer.slice(0, Math.floor((this.frameCount + this.checkpointInterval - 1) / this.checkpointInterval));
|
||||
this.controls = this.controls.slice(0, this.frameCount);
|
||||
}
|
||||
// time to save next frame?
|
||||
this.frameCount++;
|
||||
if (this.callbackStateChanged) {
|
||||
this.callbackStateChanged();
|
||||
}
|
||||
return (this.frameCount % this.checkpointInterval) == 0;
|
||||
}
|
||||
|
||||
numFrames() : number {
|
||||
return this.frameCount;
|
||||
}
|
||||
|
||||
recordFrame(state : EmuState) {
|
||||
this.buffer.push(state);
|
||||
}
|
||||
|
||||
getStateAtOrBefore(frame : number) : {frame : number, state : EmuState} {
|
||||
var bufidx = Math.floor(frame / this.checkpointInterval);
|
||||
var foundidx = bufidx < this.buffer.length ? bufidx : this.buffer.length-1;
|
||||
var foundframe = foundidx * this.checkpointInterval;
|
||||
return {frame:foundframe, state:this.buffer[foundidx]};
|
||||
}
|
||||
|
||||
loadFrame(seekframe : number) {
|
||||
let {frame,state} = this.getStateAtOrBefore(seekframe);
|
||||
if (state) {
|
||||
this.platform.pause();
|
||||
this.platform.loadState(state);
|
||||
while (frame < seekframe) {
|
||||
if (frame < this.controls.length) {
|
||||
this.platform.loadControlsState(this.controls[frame]);
|
||||
}
|
||||
this.platform.advance(true); // TODO: infinite loop?
|
||||
frame++;
|
||||
}
|
||||
this.platform.advance();
|
||||
this.lastSeekFrame = seekframe;
|
||||
}
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ var current_project : CodeProject; // current CodeProject object
|
||||
|
||||
var projectWindows : ProjectWindows; // window manager
|
||||
|
||||
var stateRecorder : StateRecorderImpl = new StateRecorderImpl();
|
||||
var stateRecorder : StateRecorderImpl;
|
||||
|
||||
// TODO: codemirror multiplex support?
|
||||
var TOOL_TO_SOURCE_STYLE = {
|
||||
@ -771,7 +771,7 @@ function setupDebugControls(){
|
||||
};
|
||||
replayslider.on('input', function(e) {
|
||||
_pause();
|
||||
stateRecorder.loadFrame(platform, (<any>e.target).value);
|
||||
stateRecorder.loadFrame((<any>e.target).value);
|
||||
});
|
||||
$("#replay_bar").show();
|
||||
}
|
||||
@ -908,6 +908,7 @@ function addPageFocusHandlers() {
|
||||
function startPlatform() {
|
||||
if (!PLATFORMS[platform_id]) throw Error("Invalid platform '" + platform_id + "'.");
|
||||
platform = new PLATFORMS[platform_id]($("#emulator")[0]);
|
||||
stateRecorder = new StateRecorderImpl(platform);
|
||||
PRESETS = platform.getPresets();
|
||||
if (qs['file']) {
|
||||
// start platform and load file
|
||||
|
Loading…
x
Reference in New Issue
Block a user