phantasmal-world/src/application/index.ts

133 lines
4.2 KiB
TypeScript

import { HttpClient } from "../core/HttpClient";
import { Disposable } from "../core/observable/Disposable";
import { GuiStore, GuiTool } from "../core/stores/GuiStore";
import { create_item_type_stores } from "../core/stores/ItemTypeStore";
import { create_item_drop_stores } from "../hunt_optimizer/stores/ItemDropStore";
import { ApplicationView } from "./gui/ApplicationView";
import { throttle } from "lodash";
import { DisposableThreeRenderer } from "../core/rendering/Renderer";
import { Disposer } from "../core/observable/Disposer";
import { disposable_custom_listener, disposable_listener } from "../core/gui/dom";
export function initialize_application(
http_client: HttpClient,
create_three_renderer: () => DisposableThreeRenderer,
): Disposable {
const disposer = new Disposer();
// Disable native undo/redo.
disposer.add(disposable_custom_listener(document, "beforeinput", before_input));
// Work-around for FireFox:
disposer.add(disposable_listener(document, "keydown", keydown));
// Disable native drag-and-drop to avoid users dragging in unsupported file formats and leaving
// the application unexpectedly.
disposer.add_all(
disposable_listener(document, "dragenter", dragenter),
disposable_listener(document, "dragover", dragover),
disposable_listener(document, "drop", drop),
);
// Initialize core stores shared by several submodules.
const gui_store = disposer.add(new GuiStore());
const item_type_stores = disposer.add(create_item_type_stores(http_client, gui_store));
const item_drop_stores = disposer.add(
create_item_drop_stores(http_client, gui_store, item_type_stores),
);
// Initialize application view.
const application_view = disposer.add(
new ApplicationView(gui_store, [
[
GuiTool.Viewer,
async () => {
const { initialize_viewer } = await import("../viewer");
const viewer = disposer.add(
initialize_viewer(http_client, gui_store, create_three_renderer),
);
return viewer.view;
},
],
[
GuiTool.QuestEditor,
async () => {
const { initialize_quest_editor } = await import("../quest_editor");
const quest_editor = disposer.add(
initialize_quest_editor(http_client, gui_store, create_three_renderer),
);
return quest_editor.view;
},
],
[
GuiTool.HuntOptimizer,
async () => {
const { initialize_hunt_optimizer } = await import("../hunt_optimizer");
const hunt_optimizer = disposer.add(
initialize_hunt_optimizer(
http_client,
gui_store,
item_type_stores,
item_drop_stores,
),
);
return hunt_optimizer.view;
},
],
]),
);
// Resize the view on window resize.
const resize = throttle(
() => {
application_view.resize(window.innerWidth, window.innerHeight);
},
100,
{ leading: true, trailing: true },
);
resize();
document.body.append(application_view.element);
disposer.add(disposable_listener(window, "resize", resize));
return {
dispose(): void {
disposer.dispose();
},
};
}
function before_input(e: Event): void {
const ie = e as any;
if (ie.inputType === "historyUndo" || ie.inputType === "historyRedo") {
e.preventDefault();
}
}
function keydown(e: Event): void {
const kbe = e as KeyboardEvent;
if (kbe.ctrlKey && !kbe.altKey && kbe.key.toUpperCase() === "Z") {
kbe.preventDefault();
}
}
function dragenter(e: DragEvent): void {
e.preventDefault();
if (e.dataTransfer) {
e.dataTransfer.dropEffect = "none";
}
}
function dragover(e: DragEvent): void {
dragenter(e);
}
function drop(e: DragEvent): void {
dragenter(e);
}