updated demo.html navbar; embedui does state recording

This commit is contained in:
Steven Hugg 2019-04-30 13:44:29 -04:00
parent 3429e72e8d
commit 159b7048cc
5 changed files with 70 additions and 10 deletions

View File

@ -32,14 +32,16 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" target="_new" href="https://twitter.com/8bitworkshop">@8bitworkshop</a>
<!-- <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> -->
<a class="navbar-brand" href="./blog/">Blog</a>
<a class="navbar-brand" href="#books" onclick="ga('send', 'event', 'books', 'click');">Books</a>
<a class="navbar-brand" href="#">8bitworkshop</a>
</div>
<ul class="nav navbar-nav">
<li class="hidden-xs"><a href="#books">Books</a></li>
<li><a href="./blog">Blog</a></li>
<li><a target="_new" href="https://twitter.com/8bitworkshop">Twitter</a></li>
</ul>
<div id="navbar" class="hidden-sm hidden-xs">
<form class="navbar-form navbar-right">
<a class="btn btn-default" href="redir.html?" role="button">Continue to 8bitworkshop IDE
@ -53,7 +55,6 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<div class="jumbotron">
<div class="container">
<div class="col-md-6">
<br>
<h1>Write 8-bit code in your browser.</h1>
<p>
Ever wanted to be an old-school game programmer?<br>

View File

@ -129,6 +129,8 @@ TODO:
- PPU/TIA register write visualization
- nes debug view toolbar
- vcs sound continues when paused
- upload multiple files/zip file to subdirectory
- allow "include graphics.asm" instead of "include project/graphics.asm"
WEB WORKER FORMAT

View File

@ -9,7 +9,6 @@
top:0;
width:100%;
height:100%;
background-color:#555;
display: flex;
align-items: center;
justify-content: center;
@ -76,6 +75,10 @@ function require(modname) {
<script src="lib/liblzg.js"></script>
<script>
// are we not in an iframe?
if(self === top) {
document.body.style.backgroundColor = '#555';
}
startEmbed();
</script>

View File

@ -4,9 +4,11 @@ window['Javatari'].AUTO_START = false;
import { PLATFORMS } from "./emu";
import { Platform } from "./baseplatform";
import { stringToByteArray, getWithBinary } from "./util";
import { StateRecorderImpl } from "./recorder";
export var platform_id : string; // platform ID string
export var platform : Platform; // platform object
export var stateRecorder : StateRecorderImpl;
// external libs (TODO)
declare var ga, lzgmini;
@ -77,9 +79,20 @@ function startROM(title, rom) {
platform.resume();
}
function enableRecording() {
stateRecorder = new StateRecorderImpl(platform);
stateRecorder.reset();
stateRecorder.checkpointInterval = 60*5; // every 5 sec
stateRecorder.maxCheckpoints = 360; // 30 minutes
platform.setRecorder(stateRecorder);
}
function startPlatform(qs) {
if (!PLATFORMS[platform_id]) throw Error("Invalid platform '" + platform_id + "'.");
platform = new PLATFORMS[platform_id]($("#emulator")[0]);
if (qs['rec']) {
enableRecording();
}
platform.start();
var title = qs['n'] || 'Game';
var rom : Uint8Array;
@ -122,7 +135,42 @@ function loadScript(scriptfn, onload) {
// start
export function startEmbed() {
installErrorHandler();
window.addEventListener("message", loadPlatform, false);
if (_qs['p']) loadPlatform(_qs);
if (_qs['p']) {
loadPlatform(_qs);
}
}
// iframe API
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
if (event.data) {
if (event.data.cmd == 'start' && !platform) {
loadPlatform(event);
}
else if (event.data.cmd == 'reset') {
platform.reset();
stateRecorder.reset();
}
else if (event.data.cmd == 'getReplay') {
var replay = {
frameCount: stateRecorder.frameCount,
checkpoints: stateRecorder.checkpoints,
framerecs: stateRecorder.framerecs,
checkpointInterval: stateRecorder.checkpointInterval,
maxCheckpoints: stateRecorder.maxCheckpoints,
}
event.source.postMessage({replay:replay}, event.origin);
}
else if (event.data.cmd == 'watchState') {
var watchfn = new Function('platform', 'state', event.data.fn);
stateRecorder.callbackNewCheckpoint = (state) => {
event.source.postMessage({state:watchfn(platform, state)}, event.origin);
}
}
else {
console.log("Unknown data.cmd: " + event.data.cmd);
}
}
}

View File

@ -7,6 +7,7 @@ type FrameRec = {controls:EmuControlsState, seed:number};
export class StateRecorderImpl implements EmuRecorder {
checkpointInterval : number = 60;
callbackStateChanged : () => void;
callbackNewCheckpoint : (state:EmuState) => void;
maxCheckpoints : number = 120;
platform : Platform;
@ -60,6 +61,7 @@ export class StateRecorderImpl implements EmuRecorder {
recordFrame(state : EmuState) {
this.checkpoints.push(state);
if (this.callbackNewCheckpoint) this.callbackNewCheckpoint(state);
// checkpoints full?
if (this.checkpoints.length > this.maxCheckpoints) {
this.checkpoints.shift(); // remove 1st checkpoint
@ -104,4 +106,8 @@ export class StateRecorderImpl implements EmuRecorder {
this.platform.loadControlsState(this.framerecs[frame].controls);
setNoiseSeed(this.framerecs[frame].seed);
}
getLastCheckpoint() : EmuState {
return this.checkpoints.length && this.checkpoints[this.checkpoints.length-1];
}
}