Tsuchinoko Real?!

This commit is contained in:
fate6 2024-12-29 15:39:10 -08:00
parent 4c25ed9a98
commit 661f983e1d
906 changed files with 57143 additions and 0 deletions

View file

@ -0,0 +1,25 @@
# binjgb
Fork of binji's Game Boy emulator built as a WebAssembly module.
It includes changes from [Daid's fork](https://github.com/daid/binjgb) and others to better support GB Studio.
## License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -0,0 +1,367 @@
body {
background: #031921;
color: #fff;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue",
Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
margin: 0;
padding: 0;
touch-action: none;
-webkit-touch-callout: none;
user-select: none;
-webkit-user-select: none;
overflow: hidden;
}
#game {
display: flex;
flex-direction: column;
position: absolute;
width: 100%;
height: 100%;
touch-action: none;
}
#game canvas {
object-fit: contain;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-crisp-edges;
image-rendering: pixelated;
image-rendering: crisp-edges;
height: 100%;
}
#controller {
display: none;
position: fixed;
bottom: 0px;
height: 210px;
width: 100%;
touch-action: none;
opacity: 0.8;
}
#controller_dpad {
position: absolute;
bottom: 20px;
left: 0px;
width: 184px;
height: 184px;
}
#controller_dpad:before {
content: "";
display: block;
width: 48px;
height: 48px;
background: #5c5c5c;
background: radial-gradient(
ellipse at center,
#5c5c5c 0%,
#555 59%,
#5c5c5c 60%
);
position: absolute;
left: 68px;
top: 68px;
}
#controller_left {
position: absolute;
left: 20px;
top: 68px;
width: 48px;
height: 48px;
background: #666;
background: radial-gradient(ellipse at center, #666 0%, #5c5c5c 80%);
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
#controller_right {
position: absolute;
left: 116px;
top: 68px;
width: 48px;
height: 48px;
background: #666;
background: radial-gradient(ellipse at center, #666 0%, #5c5c5c 80%);
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
#controller_up {
position: absolute;
left: 68px;
top: 20px;
width: 48px;
height: 48px;
background: #666;
background: radial-gradient(ellipse at center, #666 0%, #5c5c5c 80%);
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
#controller_down {
position: absolute;
left: 68px;
top: 116px;
width: 48px;
height: 48px;
background: #666;
background: radial-gradient(ellipse at center, #666 0%, #5c5c5c 80%);
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
#controller_a {
position: absolute;
bottom: 110px;
right: 20px;
}
#controller_b {
position: absolute;
bottom: 80px;
right: 100px;
}
.roundBtn {
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 32px;
color: #440f1f;
line-height: 64px;
width: 64px;
height: 64px;
border-radius: 64px;
background: #870a4c;
background: radial-gradient(ellipse at center, #ab1465 0%, #8b1e57 100%);
box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.2);
}
.capsuleBtn {
font-weight: bold;
font-size: 10px;
color: #111;
display: flex;
justify-content: center;
align-items: center;
line-height: 40px;
text-transform: uppercase;
width: 64px;
height: 32px;
border-radius: 40px;
background: #222;
background: radial-gradient(ellipse at center, #666 0%, #555 100%);
box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.2);
}
#controller_start {
position: absolute;
bottom: 20px;
right: 15px;
}
#controller_select {
position: absolute;
bottom: 20px;
right: 100px;
}
.btnPressed {
opacity: 0.5;
}
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation 0.8s linear infinite;
-moz-animation: rotation 0.8s linear infinite;
-o-animation: rotation 0.8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid #306850;
border-right: 10px solid #306850;
border-bottom: 10px solid #306850;
border-top: 10px solid #88c070;
border-radius: 100%;
background-color: #031921;
}
@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes rotation {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(360deg);
}
}
@-o-keyframes rotation {
from {
-o-transform: rotate(0deg);
}
to {
-o-transform: rotate(360deg);
}
}
@keyframes rotation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media only screen and (max-width: 640px) {
#game canvas {
margin-top: 0px;
width: 100%;
max-width: 512px;
border: 0px;
border-radius: 0px;
}
}
@media only screen and (max-device-width: 812px) and (orientation: portrait) {
body {
margin: 0;
}
#game {
width: 100%;
position: fixed;
touch-action: none;
}
#game canvas {
margin: 0;
display: block;
width: 100% !important;
height: auto !important;
}
}
@media only screen and (max-device-width: 320px) and (orientation: portrait) {
#controller_dpad {
left: -5px;
bottom: -5px;
}
#controller_a {
right: 5px;
bottom: 95px;
}
#controller_b {
right: 80px;
}
#controller_start {
right: 5px;
}
#controller_select {
right: 80px;
}
}
@media only screen and (max-width: 500px) and (max-height: 400px) {
#controller {
display: none;
}
}
/* Small devices in landscape */
@media only screen and (max-device-width: 300px) and (orientation: landscape) {
html,
body {
height: 100%;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
#game:after {
content: "PLEASE ROTATE ↻";
font-size: 24px;
font-weight: bold;
color: #fff;
}
#game canvas {
display: none;
max-width: 480px;
}
#controller {
display: none;
}
}
/* Devices large enough for landscape */
@media only screen and (min-width: 300px) and (orientation: landscape) {
#controller {
bottom: 50%;
transform: translateY(50%);
opacity: 0.5;
}
}
#debug {
display:flex;
flex-direction:column;
align-items:center;
padding:10px;
position:fixed;
top:0px;
left:0px;
right:0px;
bottom:0px;
background:rgba(0,0,0,0.5);
}
#debug div {
background: white;
color: black;
border: 1px solid #ddd;
border-radius: 4px;
transform: position;
font-size: 11px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
display: flex;
align-items: center;
}
#debug span {
padding: 5px 8px;
}
#debug button {
background: transparent;
border: none;
border-left: 1px solid #ddd;
display: flex;
align-items: center;
height: 100%;
}
#debug button:hover {
background: #eee;
}
#debug button:active {
background: #ddd;
}

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="css/style.css" />
<title>Slightys Midnight Adventure</title>
<meta name="author" content="fate6" />
<style type="text/css"> body { background-color:#202850; }</style>
</head>
<body>
<div id="game">
<canvas id="mainCanvas" width="256" height="224">No Canvas Support</canvas>
</div>
<div id="controller">
<div id="controller_dpad">
<div id="controller_left"></div>
<div id="controller_right"></div>
<div id="controller_up"></div>
<div id="controller_down"></div>
</div>
<div id="controller_select" class="capsuleBtn">Select</div>
<div id="controller_start" class="capsuleBtn">Start</div>
<div id="controller_b" class="roundBtn">B</div>
<div id="controller_a" class="roundBtn">A</div>
</div>
<script>
const customControls = {"up":["ArrowUp","w"],"down":["ArrowDown","s"],"left":["ArrowLeft","a"],"right":["ArrowRight","d"],"a":["Alt","z","j"],"b":["Control","k","x"],"start":["Enter"],"select":["Shift"]}
</script>
<script src="binjgb.js"></script>
<script src="js/script.js"></script>
<script src="js/debugger.js"></script>
</body>

View file

@ -0,0 +1,567 @@
/* global EVENT_NEW_FRAME, EVENT_AUDIO_BUFFER_FULL, EVENT_UNTIL_TICKS, vm, emulator, API */
let debug;
// Consts
const EVENT_BREAKPOINT = 8;
const EXECUTING_CTX_SYMBOL = "_executing_ctx";
const FIRST_CTX_SYMBOL = "_first_ctx";
const SCRIPT_MEMORY_SYMBOL = "_script_memory";
const CURRENT_SCENE_SYMBOL = "_current_scene";
const MAX_GLOBAL_VARS = "MAX_GLOBAL_VARS";
// Helpers
const toAddrHex = (value) =>
("0000" + value.toString(16).toUpperCase()).slice(-4);
const parseDebuggerSymbol = (input) => {
const match = input.match(
/GBVM\$([^$]+)\$([^$]+)\$([^$]+)\$([^$]+)\$([^$]+)\$([^$]+)/
);
if (!match) {
return undefined;
}
return {
scriptSymbol: match[1],
scriptEventId: match[2].replace(/_/g, "-"),
sceneId: match[3].replace(/_/g, "-"),
entityType: match[4],
entityId: match[5].replace(/_/g, "-"),
scriptKey: match[6],
};
};
const parseDebuggerEndSymbol = (input) => {
const match = input.match(/GBVM_END\$([^$]+)\$([^$]+)/);
if (!match) {
return undefined;
}
return {
scriptSymbol: match[1],
};
};
// Debugger
class Debug {
constructor(emulator) {
this.emulator = emulator;
this.module = emulator.module;
this.e = emulator.e;
this.vramCanvas = document.createElement("canvas");
this.vramCanvas.width = 256;
this.vramCanvas.height = 256;
this.memoryMap = {};
this.globalVariables = {};
this.variableMap = {};
this.memoryDict = new Map();
this.breakpoints = [];
this.pauseOnScriptChanged = false;
this.pauseOnWatchedVariableChanged = true;
this.pauseOnVMStep = false;
this.currentScriptSymbol = "";
this.scriptContexts = [];
this.pausedUI = null;
this.prevGlobals = [];
this.watchedVariables = [];
this.debugRunUntil = (ticks) => {
while (true) {
const event = this.module._emulator_run_until_f64(this.e, ticks);
if (event & EVENT_NEW_FRAME) {
this.emulator.rewind.pushBuffer();
this.emulator.video.uploadTexture();
}
if (event & EVENT_BREAKPOINT) {
// Breakpoint hit
const firstCtxAddr = this.memoryMap[FIRST_CTX_SYMBOL];
const executingCtxAddr = this.memoryMap[EXECUTING_CTX_SYMBOL];
const currentCtx = this.readMemInt16(executingCtxAddr);
let firstCtx = debug.readMemInt16(firstCtxAddr);
let scriptContexts = [];
let currentCtxData = undefined;
const prevCtxs = this.scriptContexts;
while (firstCtx !== 0) {
const ctxAddr = debug.readMemInt16(firstCtx);
const ctxBank = debug.readMem(firstCtx + 2);
const ctxStackPtrAddr = debug.readMemInt16(firstCtx + 8);
const ctxStackBaseAddr = debug.readMemInt16(firstCtx + 10);
const closestAddr = debug.getClosestAddress(ctxBank, ctxAddr);
const closestSymbol = debug.getSymbol(ctxBank, closestAddr);
const closestGBVMSymbol = parseDebuggerSymbol(closestSymbol);
const prevCtx = prevCtxs[scriptContexts.length];
let stackString = "";
for (var i = ctxStackBaseAddr; i < ctxStackPtrAddr + 4; i += 2) {
stackString += `${i === ctxStackPtrAddr ? "->" : " "}${toAddrHex(
i
)}: ${debug.readMemInt16(i)}\n`;
}
const ctxData = {
address: ctxAddr,
bank: ctxBank,
current: currentCtx === firstCtx,
closestAddr,
closestSymbol,
closestGBVMSymbol,
prevClosestSymbol: prevCtx?.closestSymbol,
prevClosestGBVMSymbol: prevCtx?.closestGBVMSymbol,
stackString,
};
scriptContexts.push(ctxData);
if (ctxData.current) {
currentCtxData = ctxData;
}
firstCtx = debug.readMemInt16(firstCtx + 3);
}
this.scriptContexts = scriptContexts;
if (currentCtxData) {
// If pausing on VM Step and current script block changed
if (
this.pauseOnVMStep &&
currentCtxData.closestGBVMSymbol &&
currentCtxData.closestGBVMSymbol.scriptEventId !== "end" &&
currentCtxData.closestSymbol !== currentCtxData.prevClosestSymbol
) {
emulator.pause();
this.pauseOnVMStep = false;
break;
}
// If manual breakpoint is hit
if (
currentCtxData.closestGBVMSymbol &&
currentCtxData.address === currentCtxData.closestAddr &&
currentCtxData.closestSymbol !==
currentCtxData.prevClosestSymbol &&
this.breakpoints.includes(
currentCtxData.closestGBVMSymbol.scriptEventId
)
) {
this.pauseOnVMStep = true;
emulator.pause();
break;
}
if (
this.pauseOnScriptChanged &&
// Found matching GBVM event
currentCtxData.closestGBVMSymbol &&
// GBVM event has changed since last pause
(!currentCtxData.prevClosestGBVMSymbol ||
currentCtxData.closestGBVMSymbol.scriptSymbol !==
currentCtxData.prevClosestGBVMSymbol.scriptSymbol)
) {
this.pauseOnVMStep = true;
emulator.pause();
break;
}
if (this.pauseOnWatchedVariableChanged) {
const globals = this.getGlobals();
if (this.prevGlobals.length > 0) {
// Check if watched has change
const modified = !this.prevGlobals.every(
(v, i) => v === globals[i]
);
if (modified) {
const changedVariable = this.watchedVariables.find(
(variableId) => {
const variableData = this.variableMap[variableId];
const symbol = variableData?.symbol;
const variableIndex = this.globalVariables[symbol];
if (variableIndex !== undefined) {
return (
this.prevGlobals[variableIndex] !== undefined &&
globals[variableIndex] !==
this.prevGlobals[variableIndex]
);
}
return false;
}
);
if (changedVariable) {
this.pauseOnVMStep = true;
emulator.pause();
}
}
}
this.prevGlobals = globals;
}
}
}
if (event & EVENT_AUDIO_BUFFER_FULL && !this.emulator.isRewinding) {
this.emulator.audio.pushBuffer();
}
if (event & EVENT_UNTIL_TICKS) {
break;
}
}
if (this.module._emulator_was_ext_ram_updated(this.e)) {
vm.extRamUpdated = true;
}
};
// replace the emulator run method with the debug one
this.emulator.runUntil = this.debugRunUntil;
}
initialize(
memoryMap,
globalVariables,
variableMap,
pauseOnScriptChanged,
pauseOnWatchedVarChanged,
breakpoints,
watchedVariables
) {
this.memoryMap = memoryMap;
this.globalVariables = globalVariables;
this.variableMap = variableMap;
this.pauseOnScriptChanged = pauseOnScriptChanged;
this.pauseOnWatchedVariableChanged = pauseOnWatchedVarChanged;
this.breakpoints = breakpoints;
this.watchedVariables = watchedVariables;
const memoryDict = new Map();
Object.keys(memoryMap).forEach((k) => {
// Banked resources
const match = k.match(/___bank_(.*)/);
if (match) {
const label = `_${match[1]}`;
const bank = memoryMap[k];
if (memoryMap[label]) {
const n = memoryDict.get(bank) ?? new Map();
const ptr = memoryMap[label] & 0x0ffff;
n.set(ptr, label);
memoryDict.set(bank, n);
}
}
// Script debug symbols
// const matchGBVM = k.match(/GBVM\$([^$]*)\$([^$]*)/);
const matchGBVM = parseDebuggerSymbol(k);
if (matchGBVM) {
const bankLabel = `___bank_${matchGBVM.scriptSymbol}`;
const label = k;
const bank = memoryMap[bankLabel];
if (memoryMap[label]) {
const n = memoryDict.get(bank) ?? new Map();
const ptr = memoryMap[label] & 0x0ffff;
n.set(ptr, label);
memoryDict.set(bank, n);
}
}
const matchEnd = parseDebuggerEndSymbol(k);
if (matchEnd) {
const bankLabel = `___bank_${matchEnd.scriptSymbol}`;
const label = k;
const bank = memoryMap[bankLabel];
if (memoryMap[label]) {
const n = memoryDict.get(bank) ?? new Map();
const ptr = memoryMap[label] & 0x0ffff;
if (!n.get(ptr)) {
n.set(ptr, label);
memoryDict.set(bank, n);
}
}
}
});
this.memoryDict = memoryDict;
// Break on VM_STEP
this.module._emulator_set_breakpoint(this.e, memoryMap["_VM_STEP"]);
// Add paused UI
this.initializeUI();
this.initializeKeyboardShortcuts();
}
initializeUI() {
const pausedUI = document.createElement("div");
const pausedUIContainer = document.createElement("div");
const pausedUILabel = document.createElement("span");
const pausedUIResumeBtn = document.createElement("button");
const pausedUIStepBtn = document.createElement("button");
const pausedUIStepFrameBtn = document.createElement("button");
document.body.appendChild(pausedUI);
pausedUI.appendChild(pausedUIContainer);
pausedUIContainer.appendChild(pausedUILabel);
pausedUIContainer.appendChild(pausedUIResumeBtn);
pausedUIContainer.appendChild(pausedUIStepBtn);
pausedUIContainer.appendChild(pausedUIStepFrameBtn);
pausedUI.id = "debug";
pausedUILabel.innerHTML = "Paused in debugger";
pausedUIResumeBtn.innerHTML = `<svg width="15" height="15" viewBox="0 0 24 24"><path d="M2 3H6V21H2V3Z" /><path d="M22 12L7 21L7 3L22 12Z" /></svg>`;
pausedUIResumeBtn.title = "Resume execution - F8";
pausedUIResumeBtn.addEventListener("click", this.resume.bind(this));
pausedUIStepBtn.innerHTML = `<svg width="15" height="15" viewBox="0 0 24 24"><path d="M16 8v-4l8 8-8 8v-4h-5v-8h5zm-7 0h-2v8h2v-8zm-4.014 0h-1.986v8h1.986v-8zm-3.986 0h-1v8h1v-8z" /></svg>`;
pausedUIStepBtn.title = "Step - F9";
pausedUIStepBtn.addEventListener("click", this.step.bind(this));
pausedUIStepFrameBtn.innerHTML = `<svg width="15" height="15" viewBox="0 0 24 24"><path d="M19 12l-18 12v-24l18 12zm4-11h-4v22h4v-22z" /></svg>`;
pausedUIStepFrameBtn.title = "Step Frame - F10";
pausedUIStepFrameBtn.addEventListener("click", this.stepFrame.bind(this));
this.pausedUI = pausedUI;
}
initializeKeyboardShortcuts() {
window.addEventListener("keydown", (e) => {
if (e.key === "F8") {
this.togglePlayPause();
} else if (e.key === "F9") {
this.step();
} else if (e.key === "F10") {
this.stepFrame();
}
});
}
getClosestAddress(bank, address) {
const bankScripts = this.memoryDict.get(bank);
const currentAddress = address;
let closestAddress = -1;
if (bankScripts) {
const addresses = Array.from(bankScripts.keys()).sort();
for (let i = 0; i < addresses.length; i++) {
if (addresses[i] > currentAddress) {
break;
} else {
closestAddress = addresses[i];
}
}
}
return closestAddress;
}
getSymbol(bank, address) {
const symbol = this.memoryDict.get(bank)?.get(address) ?? "";
return symbol.replace(/^_/, "");
}
readMem(addr) {
return this.module._emulator_read_mem(this.e, addr);
}
readMemInt16(addr) {
return (
(this.module._emulator_read_mem(this.e, addr + 1) << 8) |
this.module._emulator_read_mem(this.e, addr)
);
}
writeMem(addr, value) {
this.module._emulator_write_mem(this.e, addr, value & 0xff);
}
writeMemInt16(addr, value) {
this.module._emulator_write_mem(this.e, addr, value & 0xff);
this.module._emulator_write_mem(this.e, addr + 1, value >> 8);
}
readVariables(addr, size) {
const ptr = this.module._emulator_get_wram_ptr(this.e) - 0xc000;
return new Int16Array(
this.module.HEAP8.buffer.slice(ptr + addr, ptr + addr + size * 2)
);
}
renderVRam() {
var ctx = this.vramCanvas.getContext("2d");
var imgData = ctx.createImageData(256, 256);
var ptr = this.module._malloc(4 * 256 * 256);
this.module._emulator_render_vram(this.e, ptr);
var buffer = new Uint8Array(this.module.HEAP8.buffer, ptr, 4 * 256 * 256);
imgData.data.set(buffer);
ctx.putImageData(imgData, 0, 0);
this.module._free(ptr);
return this.vramCanvas.toDataURL("image/png");
}
setBreakPoints(breakpoints) {
this.breakpoints = breakpoints;
}
setWatchedVariables(watchedVariables) {
this.watchedVariables = watchedVariables;
}
pause() {
this.pauseOnVMStep = true;
this.emulator.pause();
}
resume() {
this.pauseOnVMStep = false;
this.emulator.resume();
}
togglePlayPause() {
if (this.isPaused()) {
this.resume();
} else {
this.pause();
}
}
step() {
if (this.isPaused()) {
this.resume();
this.pauseOnVMStep = true;
}
}
stepFrame() {
if (this.isPaused()) {
const ticks = this.module._emulator_get_ticks_f64(this.e) + 70224;
this.emulator.runUntil(ticks);
this.emulator.video.renderTexture();
}
}
isPaused() {
return this.emulator.isPaused || this.pauseOnVMStep;
}
getGlobals() {
const variablesStartAddr = this.memoryMap[SCRIPT_MEMORY_SYMBOL];
const variablesLength = this.globalVariables[MAX_GLOBAL_VARS];
return this.readVariables(variablesStartAddr, variablesLength);
}
setGlobal(symbol, value) {
const offset = (this.globalVariables[symbol] ?? 0) * 2;
const variablesStartAddr = this.memoryMap[SCRIPT_MEMORY_SYMBOL];
this.writeMemInt16(variablesStartAddr + offset, value);
this.prevGlobals = this.getGlobals();
}
getCurrentSceneSymbol() {
const currentSceneAddr = this.memoryMap[CURRENT_SCENE_SYMBOL];
return this.getSymbol(
this.readMem(currentSceneAddr),
this.readMemInt16(currentSceneAddr + 1)
);
}
getNumScriptCtxs() {
const firstCtxAddr = this.memoryMap[FIRST_CTX_SYMBOL];
let firstCtx = debug.readMemInt16(firstCtxAddr);
let numCtxs = 0;
while (firstCtx !== 0) {
numCtxs++;
firstCtx = debug.readMemInt16(firstCtx + 3);
}
return numCtxs;
}
}
// Debugger Initialisation
let ready = setInterval(() => {
const debugEnabled = window.location.href.includes("debug=true");
if (!debugEnabled) {
// Debugging not enabled
clearInterval(ready);
return;
}
console.log("Waiting for emulator...", emulator);
if (emulator !== null) {
debug = new Debug(emulator);
clearInterval(ready);
API.debugger.sendToProjectWindow({
action: "initialized",
});
API.events.debugger.data.subscribe((_, packet) => {
const { action, data } = packet;
switch (action) {
case "listener-ready":
debug.initialize(
data.memoryMap,
data.globalVariables,
data.variableMap,
data.pauseOnScriptChanged,
data.pauseOnWatchedVariableChanged,
data.breakpoints,
data.watchedVariables
);
setInterval(() => {
if (debug.pausedUI) {
debug.pausedUI.style.visibility = debug.isPaused()
? "visible"
: "hidden";
}
const scriptContexts =
debug.getNumScriptCtxs() > 0 ? debug.scriptContexts : [];
if (scriptContexts.length === 0) {
debug.pauseOnVMStep = false;
}
API.debugger.sendToProjectWindow({
action: "update-globals",
data: debug.getGlobals(),
vram: debug.renderVRam(),
isPaused: debug.isPaused(),
scriptContexts,
currentSceneSymbol: debug.getCurrentSceneSymbol(),
});
}, 100);
break;
case "set-breakpoints":
debug.setBreakPoints(data);
break;
case "pause":
debug.pause();
break;
case "resume":
debug.resume();
break;
case "step":
debug.step();
break;
case "step-frame":
debug.stepFrame();
break;
case "pause-on-script":
debug.pauseOnScriptChanged = data;
break;
case "pause-on-var":
debug.pauseOnWatchedVariableChanged = data;
break;
case "set-global":
debug.setGlobal(data.symbol, data.value);
break;
case "set-watched":
debug.setWatchedVariables(data);
break;
default:
// console.warn(event);
}
});
}
}, 200);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
Add your ROM here named as game.gb

Binary file not shown.