Added QuestRunner for managing game state, orchestrating the VM and controlling the visual aspects of a virtual quest run.

This commit is contained in:
Daan Vanden Bosch 2019-11-05 21:07:17 +01:00
parent 4a755a884f
commit 9545f056ab
3 changed files with 80 additions and 26 deletions

View File

@ -0,0 +1,73 @@
import { ExecutionResult, VirtualMachine } from "./scripting/vm";
import { QuestModel } from "./model/QuestModel";
import { VirtualMachineIO } from "./scripting/vm/io";
import { AsmToken } from "./scripting/instructions";
import Logger from "js-logger";
const logger = Logger.get("quest_editor/QuestRunner");
export class QuestRunner {
private readonly vm: VirtualMachine;
private animation_frame?: number;
constructor() {
this.vm = new VirtualMachine(this.create_vm_io());
}
run(quest: QuestModel): void {
if (this.animation_frame != undefined) {
cancelAnimationFrame(this.animation_frame);
}
this.vm.load_object_code(quest.object_code);
this.vm.start_thread(0);
this.animation_frame = requestAnimationFrame(this.execution_loop);
}
private execution_loop = (): void => {
this.vm.vsync();
let result: ExecutionResult;
do {
result = this.vm.execute();
} while (result == ExecutionResult.Ok);
if (result === ExecutionResult.WaitingVsync) {
this.animation_frame = requestAnimationFrame(this.execution_loop);
}
};
private create_vm_io = (): VirtualMachineIO => {
return {
async advance_msg(): Promise<any> {
throw new Error("Not implemented.");
},
window_msg: (msg: string): void => {
logger.info(`window_msg "${msg}"`);
},
message: (msg: string): void => {
logger.info(`message "${msg}"`);
},
add_msg: (msg: string): void => {
logger.info(`add_msg "${msg}"`);
},
winend: (): void => {},
mesend: (): void => {},
warning: (msg: string, srcloc?: AsmToken): void => {
logger.warn(msg);
},
error: (err: Error, srcloc?: AsmToken): void => {
logger.error(err);
},
};
};
}

View File

@ -117,7 +117,7 @@ export class QuestEditorToolBar extends ToolBar {
quest_editor_store.set_current_area(area), quest_editor_store.set_current_area(area),
), ),
run_button.click.observe(quest_editor_store.run_current_quest_in_vm), run_button.click.observe(quest_editor_store.run_current_quest),
gui_store.on_global_keydown(GuiTool.QuestEditor, "Ctrl-O", () => gui_store.on_global_keydown(GuiTool.QuestEditor, "Ctrl-O", () =>
open_file_button.click(), open_file_button.click(),
@ -140,7 +140,7 @@ export class QuestEditorToolBar extends ToolBar {
gui_store.on_global_keydown( gui_store.on_global_keydown(
GuiTool.QuestEditor, GuiTool.QuestEditor,
"F5", "F5",
quest_editor_store.run_current_quest_in_vm, quest_editor_store.run_current_quest,
), ),
); );

View File

@ -27,8 +27,8 @@ import { CreateEntityAction } from "../actions/CreateEntityAction";
import { RemoveEntityAction } from "../actions/RemoveEntityAction"; import { RemoveEntityAction } from "../actions/RemoveEntityAction";
import { Euler, Vector3 } from "three"; import { Euler, Vector3 } from "three";
import { RotateEntityAction } from "../actions/RotateEntityAction"; import { RotateEntityAction } from "../actions/RotateEntityAction";
import { ExecutionResult, VirtualMachine } from "../scripting/vm";
import { convert_quest_from_model, convert_quest_to_model } from "./model_conversion"; import { convert_quest_from_model, convert_quest_to_model } from "./model_conversion";
import { QuestRunner } from "../QuestRunner";
import Logger = require("js-logger"); import Logger = require("js-logger");
const logger = Logger.get("quest_editor/gui/QuestEditorStore"); const logger = Logger.get("quest_editor/gui/QuestEditorStore");
@ -39,6 +39,7 @@ export class QuestEditorStore implements Disposable {
private readonly _current_quest = property<QuestModel | undefined>(undefined); private readonly _current_quest = property<QuestModel | undefined>(undefined);
private readonly _current_area = property<AreaModel | undefined>(undefined); private readonly _current_area = property<AreaModel | undefined>(undefined);
private readonly _selected_entity = property<QuestEntityModel | undefined>(undefined); private readonly _selected_entity = property<QuestEntityModel | undefined>(undefined);
private readonly quest_runner = new QuestRunner();
readonly debug: WritableProperty<boolean> = property(false); readonly debug: WritableProperty<boolean> = property(false);
readonly undo = new UndoStack(); readonly undo = new UndoStack();
@ -259,31 +260,11 @@ export class QuestEditorStore implements Disposable {
} }
}; };
run_current_quest_in_vm = (): void => { run_current_quest = (): void => {
logger.setLevel(logger.TRACE);
const quest = this.current_quest.val; const quest = this.current_quest.val;
if (!quest) { if (quest) {
throw new Error("No quest"); this.quest_runner.run(quest);
}
const vm = new VirtualMachine();
vm.load_object_code(quest.object_code);
vm.start_thread(0);
exec_loop: while (true) {
const exec_result = vm.execute();
switch (exec_result) {
case ExecutionResult.Ok:
break;
case ExecutionResult.WaitingVsync:
vm.vsync();
break;
case ExecutionResult.Halted:
break exec_loop;
}
} }
}; };
} }