js-dos 8.1.5 → 8.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/emulators/emulators.js +2 -0
- package/dist/emulators/emulators.js.map +1 -0
- package/dist/emulators/types/build.d.ts +28 -0
- package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
- package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
- package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
- package/dist/emulators/types/emulators.d.ts +76 -0
- package/dist/emulators/types/http.d.ts +9 -0
- package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
- package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
- package/dist/emulators/types/impl/modules.d.ts +38 -0
- package/dist/emulators/types/libzip/libzip.d.ts +16 -0
- package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
- package/dist/emulators/types/protocol/protocol.d.ts +128 -0
- package/dist/emulators/wdosbox-x.js +55 -0
- package/dist/emulators/wdosbox-x.js.symbols +8760 -0
- package/dist/emulators/wdosbox-x.wasm +0 -0
- package/dist/emulators/wdosbox.js +55 -0
- package/dist/emulators/wdosbox.js.symbols +3001 -0
- package/dist/emulators/wdosbox.wasm +0 -0
- package/dist/emulators/wlibzip.js +21 -0
- package/dist/emulators/wlibzip.js.symbols +268 -0
- package/dist/emulators/wlibzip.wasm +0 -0
- package/dist/js-dos.css +1 -0
- package/dist/js-dos.js +22 -0
- package/dist/js-dos.js.map +1 -0
- package/package.json +1 -1
- package/release.zip +0 -0
- package/.eslintrc.json +0 -43
- package/.github/workflows/build.yml +0 -51
- package/.gitmodules +0 -4
- package/index.html +0 -110
- package/postcss.config.cjs +0 -8
- package/src/app.css +0 -14
- package/src/base.css +0 -10
- package/src/components/checkbox.tsx +0 -41
- package/src/components/close-button.tsx +0 -17
- package/src/components/components.css +0 -28
- package/src/components/dos-option-checkbox.tsx +0 -94
- package/src/components/dos-option-select.tsx +0 -108
- package/src/components/dos-option-slider.tsx +0 -35
- package/src/components/error.tsx +0 -16
- package/src/components/loading.tsx +0 -26
- package/src/components/lock.tsx +0 -10
- package/src/components/select.tsx +0 -33
- package/src/components/slider.tsx +0 -69
- package/src/download-file.ts +0 -18
- package/src/frame/account-frame.tsx +0 -156
- package/src/frame/editor/defaults.ts +0 -419
- package/src/frame/editor/editor-conf-frame.tsx +0 -227
- package/src/frame/editor/editor-frame.css +0 -55
- package/src/frame/editor/editor-fs-frame.tsx +0 -314
- package/src/frame/fat-drives-frame.tsx +0 -199
- package/src/frame/frame.css +0 -119
- package/src/frame/frame.tsx +0 -34
- package/src/frame/image-rendering-frame.tsx +0 -8
- package/src/frame/network-frame.tsx +0 -157
- package/src/frame/quick-save-frame.tsx +0 -98
- package/src/frame/settings-frame.tsx +0 -14
- package/src/frame/stats-frame.tsx +0 -87
- package/src/host/bundle-storage.ts +0 -91
- package/src/host/fullscreen.ts +0 -35
- package/src/host/lcache.ts +0 -203
- package/src/host/lstorage.ts +0 -156
- package/src/i18n.ts +0 -185
- package/src/index.css +0 -7
- package/src/load.ts +0 -132
- package/src/login/login.css +0 -9
- package/src/login/login.tsx +0 -77
- package/src/main.tsx +0 -197
- package/src/public/types.ts +0 -45
- package/src/sidebar/account-button.tsx +0 -33
- package/src/sidebar/cloud-save-button.tsx +0 -89
- package/src/sidebar/diskette-icon.tsx +0 -14
- package/src/sidebar/fullscreen-button.tsx +0 -44
- package/src/sidebar/network-button.tsx +0 -39
- package/src/sidebar/sidebar-button.tsx +0 -244
- package/src/sidebar/sidebar.css +0 -47
- package/src/sidebar/sidebar.tsx +0 -30
- package/src/sockdrive/LICENSE +0 -674
- package/src/sockdrive/README.md +0 -45
- package/src/sockdrive/include/sockdrive.h +0 -23
- package/src/sockdrive/js/.eslintrc.json +0 -43
- package/src/sockdrive/js/package.json +0 -29
- package/src/sockdrive/js/src/fatfs/chains.js +0 -318
- package/src/sockdrive/js/src/fatfs/dir.js +0 -385
- package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
- package/src/sockdrive/js/src/fatfs/index.js +0 -606
- package/src/sockdrive/js/src/fatfs/structs.js +0 -255
- package/src/sockdrive/js/src/fatfs/vol.js +0 -166
- package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
- package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
- package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
- package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
- package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
- package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
- package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
- package/src/sockdrive/js/src/test/test.ts +0 -289
- package/src/sockdrive/js/tsconfig.json +0 -11
- package/src/sockdrive/js/webpack.config.js +0 -68
- package/src/sockdrive/js/yarn.lock +0 -1808
- package/src/store/auth.ts +0 -115
- package/src/store/dos.ts +0 -305
- package/src/store/editor.ts +0 -61
- package/src/store/init.ts +0 -48
- package/src/store/storage.ts +0 -32
- package/src/store/ui.ts +0 -191
- package/src/store.tsx +0 -116
- package/src/ui.tsx +0 -140
- package/src/v8/changes.ts +0 -56
- package/src/v8/config.ts +0 -20
- package/src/v8/subscriptions.ts +0 -62
- package/src/vite-env.d.ts +0 -5
- package/src/window/dos/controls/keyboard.ts +0 -32
- package/src/window/dos/controls/keys.ts +0 -331
- package/src/window/dos/controls/mouse/mount.ts +0 -99
- package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
- package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
- package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
- package/src/window/dos/controls/mouse/pointer.ts +0 -85
- package/src/window/dos/controls/mouse.ts +0 -21
- package/src/window/dos/dos-dhry2.tsx +0 -191
- package/src/window/dos/dos-runtime.tsx +0 -216
- package/src/window/dos/dos-window.tsx +0 -91
- package/src/window/dos/render/canvas.ts +0 -65
- package/src/window/dos/render/resize.ts +0 -31
- package/src/window/dos/render/webgl.ts +0 -173
- package/src/window/dos/sound/audio-node.ts +0 -148
- package/src/window/error-window.tsx +0 -9
- package/src/window/loading-window.tsx +0 -54
- package/src/window/prerun-window.tsx +0 -121
- package/src/window/select-window.tsx +0 -118
- package/src/window/window.css +0 -78
- package/src/window/window.tsx +0 -49
- package/src/ws/ws-sockdrive.ts +0 -123
- package/src/ws/ws-transport-layer.ts +0 -468
- package/tailwind.config.cjs +0 -48
- package/tsconfig.json +0 -32
- package/tsconfig.node.json +0 -9
- package/vite.config.ts +0 -25
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { CommandInterface } from "emulators";
|
|
2
|
-
import { mouseCapture } from "./mouse/mouse-locked";
|
|
3
|
-
import { mouseDefault } from "./mouse/mouse-not-locked";
|
|
4
|
-
import { mouseSwipe } from "./mouse/mouse-swipe";
|
|
5
|
-
import { pointer } from "./mouse/pointer";
|
|
6
|
-
|
|
7
|
-
export function mouse(lock: boolean,
|
|
8
|
-
sensitivity: number,
|
|
9
|
-
pointerButton: number,
|
|
10
|
-
el: HTMLElement,
|
|
11
|
-
ci: CommandInterface) {
|
|
12
|
-
if (lock && !pointer.canLock) {
|
|
13
|
-
return mouseSwipe(sensitivity, pointerButton, el, ci);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (lock) {
|
|
17
|
-
return mouseCapture(sensitivity, pointerButton, el, ci);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return mouseDefault(pointerButton, el, ci);
|
|
21
|
-
}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { CommandInterface } from "emulators";
|
|
2
|
-
import { useEffect, useState } from "preact/hooks";
|
|
3
|
-
import { useSelector } from "react-redux";
|
|
4
|
-
import { State } from "../../store";
|
|
5
|
-
|
|
6
|
-
export const dhry2Bundle = "/b4b5275904d86a4ab8a20917b2b7e34f0df47bf7.jsdos";
|
|
7
|
-
|
|
8
|
-
export function Dhry2Results(props: { ci: CommandInterface }) {
|
|
9
|
-
const ci = props.ci;
|
|
10
|
-
const backend = useSelector((state: State) => state.dos.backend);
|
|
11
|
-
const worker = useSelector((state: State) => state.dos.worker);
|
|
12
|
-
|
|
13
|
-
const [results, setResults] = useState<{
|
|
14
|
-
runs: number,
|
|
15
|
-
time: number,
|
|
16
|
-
vax: number,
|
|
17
|
-
pc: string | null,
|
|
18
|
-
}>({
|
|
19
|
-
runs: 0,
|
|
20
|
-
time: 0,
|
|
21
|
-
vax: 0,
|
|
22
|
-
pc: null,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const [stats, setStats] = useState<{sleepPerSec: number, cyclesPerMs: number}>({
|
|
26
|
-
sleepPerSec: 0,
|
|
27
|
-
cyclesPerMs: 0,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
const listeners: ((message: string) => void)[] = [];
|
|
32
|
-
|
|
33
|
-
ci.events().onStdout((message: string) => {
|
|
34
|
-
for (const next of listeners) {
|
|
35
|
-
next(message);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const oldStdoutFn = ci.events().onStdout;
|
|
40
|
-
ci.events().onStdout = (fn: (message: string) => void) => {
|
|
41
|
-
listeners.push(fn);
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// listen program outpus for `~>dtime` marker
|
|
45
|
-
let startedAt = Date.now();
|
|
46
|
-
let prevSleepCount = 0;
|
|
47
|
-
let prevCycles = 0;
|
|
48
|
-
ci.events().onStdout((message) => {
|
|
49
|
-
if (!message.startsWith("dhry2:")) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
ci.asyncifyStats().then((stats) => {
|
|
54
|
-
const dt = Date.now() - startedAt;
|
|
55
|
-
setStats({
|
|
56
|
-
sleepPerSec: Math.round((stats.sleepCount - prevSleepCount) * 1000 / dt),
|
|
57
|
-
cyclesPerMs: Math.round((stats.cycles - prevCycles) / dt),
|
|
58
|
-
});
|
|
59
|
-
startedAt = Date.now();
|
|
60
|
-
prevSleepCount = stats.sleepCount;
|
|
61
|
-
prevCycles = stats.cycles;
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// eslint-disable-next-line
|
|
65
|
-
const [_, runsStr, deltaStr, vaxRatingStr] = message.split(" ");
|
|
66
|
-
const runs = Number.parseInt(runsStr);
|
|
67
|
-
const delta = Number.parseFloat(deltaStr);
|
|
68
|
-
const vaxRating = Number.parseFloat(vaxRatingStr);
|
|
69
|
-
|
|
70
|
-
if (delta >= 5000) {
|
|
71
|
-
setResults({
|
|
72
|
-
runs,
|
|
73
|
-
time: Math.round(delta * 10) / 10,
|
|
74
|
-
vax: Math.round(vaxRating * 100) / 100,
|
|
75
|
-
pc: getComparablePc(vaxRating),
|
|
76
|
-
});
|
|
77
|
-
} else {
|
|
78
|
-
setResults({
|
|
79
|
-
runs,
|
|
80
|
-
time: Math.round(delta * 10) / 10,
|
|
81
|
-
vax: Math.round(vaxRating * 100) / 100,
|
|
82
|
-
pc: null,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
return () => {
|
|
88
|
-
ci.events().onStdout = oldStdoutFn;
|
|
89
|
-
};
|
|
90
|
-
}, [ci]);
|
|
91
|
-
|
|
92
|
-
return <div class="dhry2-window">
|
|
93
|
-
<div class="title">Dhrystone 2 Benchmark</div>
|
|
94
|
-
<div class="backend">Backend: {backend + "-" + (worker ? "worker" : "direct")}</div>
|
|
95
|
-
<div class="results">
|
|
96
|
-
<div>VAX:</div>
|
|
97
|
-
<div>{results.vax}</div>
|
|
98
|
-
<div>Cycles p/ms:</div>
|
|
99
|
-
<div>{stats.cyclesPerMs}</div>
|
|
100
|
-
<div>Sleep p/sec:</div>
|
|
101
|
-
<div>{stats.sleepPerSec}</div>
|
|
102
|
-
<div>Runs:</div>
|
|
103
|
-
<div>{results.runs}</div>
|
|
104
|
-
<div>Time:</div>
|
|
105
|
-
<div>{results.time} <span>ms</span></div>
|
|
106
|
-
{results.pc !== null && <div>PC:</div>}
|
|
107
|
-
{results.pc !== null && <div>{results.pc ?? "..."}</div>}
|
|
108
|
-
</div>
|
|
109
|
-
</div>;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
function getComparablePc(vax: number): string {
|
|
114
|
-
let index = 0;
|
|
115
|
-
while ((index * 2 + 1) < results.length) {
|
|
116
|
-
if (results[index * 2 + 1] as number >= vax) {
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
index++;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
index = Math.min((results.length / 2 - 1), index);
|
|
124
|
-
return (results[index * 2] + "").trim();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Reuslts from
|
|
128
|
-
// http://www.roylongbottom.org.uk/dhrystone%20results.htm
|
|
129
|
-
const results = [
|
|
130
|
-
"AMD 80386 40MHz", 13.7,
|
|
131
|
-
"IBM 486D2 50MHz", 22.4,
|
|
132
|
-
"80486 DX2 66MHz", 35.3,
|
|
133
|
-
"IBM 486BL 100MHz", 40.9,
|
|
134
|
-
"AMD 5X86 133MHz", 84.5,
|
|
135
|
-
"Pentium 75MHz", 87.1,
|
|
136
|
-
"Cyrix P150 120MHz", 160,
|
|
137
|
-
"Pentium 100MHz", 122,
|
|
138
|
-
"Cyrix PP166 133MHz", 180,
|
|
139
|
-
"IBM 6x86 150MHz", 188,
|
|
140
|
-
"Pentium 133MHz", 181,
|
|
141
|
-
"Pentium 166MHz", 189,
|
|
142
|
-
"Cyrix PR233 188MHz", 232,
|
|
143
|
-
"Pentium 200MHz", 269,
|
|
144
|
-
"Pentium MMX 200MHz", 276,
|
|
145
|
-
"AMD K6 200MHz", 289,
|
|
146
|
-
"Pentium Pro 200MHz", 312,
|
|
147
|
-
"Celeron A 300MHz", 484,
|
|
148
|
-
"Pentium II 300MHz", 477,
|
|
149
|
-
"AMD K62 500MHz", 606,
|
|
150
|
-
"AMD K63 450MHz", 645,
|
|
151
|
-
"Pentium II 450MHz", 713,
|
|
152
|
-
"Celeron A 450MHz", 720,
|
|
153
|
-
"Pentium III 450MHz", 722,
|
|
154
|
-
"Pentium III 600MHz", 959,
|
|
155
|
-
"Athlon 600MHz", 942,
|
|
156
|
-
"Duron 600MHz", 999,
|
|
157
|
-
"Pentium III 1000MHz", 1595,
|
|
158
|
-
"PIII Tualatin 1200MHz", 1907,
|
|
159
|
-
"Pentium 4 1700MHz", 1843,
|
|
160
|
-
"Athlon Tbird 1000MHz", 1659,
|
|
161
|
-
"Duron 1000MHz", 1674,
|
|
162
|
-
"Celeron M 1295MHz", 2273,
|
|
163
|
-
"Atom 1600MHz", 1828,
|
|
164
|
-
"Pentium 4 1900MHz", 2003,
|
|
165
|
-
"Atom 1666MHz", 1948,
|
|
166
|
-
"P4 Xeon 2200MHz", 2265,
|
|
167
|
-
"Atom Z8300 1840MHz", 2686,
|
|
168
|
-
"Athlon 4 1600MHz", 2830,
|
|
169
|
-
"Pentium M 1862MHz", 3933,
|
|
170
|
-
"Ath4 Barton 1800MHz", 3172,
|
|
171
|
-
"Pentium 4E 3000MHz", 3553,
|
|
172
|
-
"Athlon XP 2080MHz", 3700,
|
|
173
|
-
"Turion 64 M 1900MHz", 3742,
|
|
174
|
-
"Pentium 4 3066MHz", 4012,
|
|
175
|
-
"Opteron 1991MHz", 3985,
|
|
176
|
-
"Core 2 Duo M 1830MHz", 4952,
|
|
177
|
-
"Athlon XP 2338MHz", 4160,
|
|
178
|
-
"Athlon 64 2150MHz", 4288,
|
|
179
|
-
"Pentium 4 3678MHz", 4227,
|
|
180
|
-
"Athlon 64 2211MHz", 4462,
|
|
181
|
-
"Celeron C2 M 2000MHz", 5275,
|
|
182
|
-
"Core 2 Duo 1 CP 2400MHz", 6446,
|
|
183
|
-
"Core i5 2467M 2300MHz", 4752,
|
|
184
|
-
"Phenom II 1 CP 3000MHz", 7615,
|
|
185
|
-
"Core i7 930 3066MHz", 8684,
|
|
186
|
-
"Core i7 860 3460MHz", 9978,
|
|
187
|
-
"Core i7 3930K 3800MHz", 11197,
|
|
188
|
-
"Core i7 4820K 3900MHz", 11867,
|
|
189
|
-
"Core i7 4820K 3900MHz", 11978,
|
|
190
|
-
"Core i7 3930K", 13877,
|
|
191
|
-
];
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { useDispatch, useSelector, useStore } from "react-redux";
|
|
2
|
-
import { dosSlice, FitConstant } from "../../store/dos";
|
|
3
|
-
import { State, Store } from "../../store";
|
|
4
|
-
import { CommandInterface } from "emulators";
|
|
5
|
-
import { keyboard } from "./controls/keyboard";
|
|
6
|
-
import { webGl as webglRender } from "./render/webgl";
|
|
7
|
-
import { canvas as canvasRender } from "./render/canvas";
|
|
8
|
-
import { audioNode } from "./sound/audio-node";
|
|
9
|
-
import { useEffect } from "preact/hooks";
|
|
10
|
-
import { mouse } from "./controls/mouse";
|
|
11
|
-
import { KBD_0 } from "./controls/keys";
|
|
12
|
-
import { uiSlice } from "../../store/ui";
|
|
13
|
-
import { useT } from "../../i18n";
|
|
14
|
-
|
|
15
|
-
export function useDosRuntime(canvas: HTMLCanvasElement,
|
|
16
|
-
ci: CommandInterface): void {
|
|
17
|
-
useLog(ci);
|
|
18
|
-
useRenderImage(canvas);
|
|
19
|
-
useStats(ci);
|
|
20
|
-
usePause(ci);
|
|
21
|
-
useKeyboard(ci);
|
|
22
|
-
useMouse(canvas, ci);
|
|
23
|
-
useRenderBackend(canvas, ci);
|
|
24
|
-
useAudioBackend(ci);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function useLog(ci: CommandInterface): void {
|
|
28
|
-
const dispatch = useDispatch();
|
|
29
|
-
const t = useT();
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
let totalPreload = 0;
|
|
32
|
-
const preloadProgress: { [drive: string]: number } = {};
|
|
33
|
-
ci.events().onMessage((msgType, ...args: string[]) => {
|
|
34
|
-
if (msgType === "error" && args[0]?.startsWith("[panic]")) {
|
|
35
|
-
dispatch(uiSlice.actions.showToast({
|
|
36
|
-
message: args[0],
|
|
37
|
-
intent: "panic",
|
|
38
|
-
}));
|
|
39
|
-
} else if (msgType === "log" && args[0]?.indexOf("sockdrive:") !== -1) {
|
|
40
|
-
const drive = args[0].substring(args[0].indexOf(" ") + 1, args[0].indexOf(","));
|
|
41
|
-
dispatch(uiSlice.actions.cloudSaves(false));
|
|
42
|
-
if (args[0]?.indexOf("write=") !== -1) {
|
|
43
|
-
console.log("drive", drive, "config:", args[0]);
|
|
44
|
-
}
|
|
45
|
-
if (args[0]?.indexOf("write=false") !== -1) {
|
|
46
|
-
dispatch(uiSlice.actions.readOnlyWarning(true));
|
|
47
|
-
}
|
|
48
|
-
if (args[0]?.indexOf("preload=") !== -1) {
|
|
49
|
-
const rest = Number.parseInt(args[0].substring(args[0].indexOf("preload=") + "preload=".length));
|
|
50
|
-
if (preloadProgress[drive] === undefined) {
|
|
51
|
-
preloadProgress[drive] = rest;
|
|
52
|
-
totalPreload += rest;
|
|
53
|
-
} else {
|
|
54
|
-
preloadProgress[drive] = rest;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let downloaded = totalPreload;
|
|
58
|
-
for (const rest of Object.values(preloadProgress)) {
|
|
59
|
-
downloaded -= rest;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
dispatch(uiSlice.actions.showToast({
|
|
63
|
-
message: t("preloading_sockdrive") + " " +
|
|
64
|
-
(Math.round(downloaded / 1024 / 1024 * 100) / 100) + "/" +
|
|
65
|
-
(Math.round(totalPreload / 1024 / 1024 * 100) / 100) + "Mb",
|
|
66
|
-
long: true,
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}, [ci, dispatch]);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function useRenderImage(canvas: HTMLCanvasElement): void {
|
|
75
|
-
const rendering = useSelector((state: State) => state.dos.imageRendering);
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
canvas.style.imageRendering = rendering === "smooth" ? "auto" : rendering;
|
|
78
|
-
}, [canvas, rendering]);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function useMouse(canvas: HTMLCanvasElement,
|
|
82
|
-
ci: CommandInterface): void {
|
|
83
|
-
const mouseCapture = useSelector((state: State) => state.dos.mouseCapture);
|
|
84
|
-
const mouseSensitivity = useSelector((state: State) => state.dos.mouseSensitivity);
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
const sensistiviy = 0.1 + mouseSensitivity * 3;
|
|
87
|
-
return mouse(mouseCapture, sensistiviy, 0, canvas, ci);
|
|
88
|
-
}, [canvas, ci, mouseCapture, mouseSensitivity]);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function useKeyboard(ci: CommandInterface): void {
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
return keyboard(window as any, ci);
|
|
94
|
-
}, [ci]);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function useRenderBackend(canvas: HTMLCanvasElement,
|
|
98
|
-
ci: CommandInterface): void {
|
|
99
|
-
const renderBackend = useSelector((state: State) => state.dos.renderBackend);
|
|
100
|
-
const renderAspect = useSelector((state: State) => state.dos.renderAspect);
|
|
101
|
-
|
|
102
|
-
let aspect: number | undefined = undefined;
|
|
103
|
-
switch (renderAspect) {
|
|
104
|
-
case "1/1": aspect = 1; break;
|
|
105
|
-
case "5/4": aspect = 5 / 4; break;
|
|
106
|
-
case "4/3": aspect = 4 / 3; break;
|
|
107
|
-
case "16/10": aspect = 16 / 10; break;
|
|
108
|
-
case "16/9": aspect = 16 / 9; break;
|
|
109
|
-
case "Fit": aspect = FitConstant;
|
|
110
|
-
default:
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
let unbind = () => { };
|
|
115
|
-
|
|
116
|
-
if (renderBackend === "canvas") {
|
|
117
|
-
unbind = canvasRender(canvas, ci, aspect);
|
|
118
|
-
} else {
|
|
119
|
-
try {
|
|
120
|
-
unbind = webglRender(canvas, ci, aspect);
|
|
121
|
-
} catch (e) {
|
|
122
|
-
console.error("Unalbe to start webgl render", e);
|
|
123
|
-
unbind = canvasRender(canvas, ci, aspect);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return unbind;
|
|
128
|
-
}, [canvas, ci, renderBackend, aspect]);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function useAudioBackend(ci: CommandInterface): void {
|
|
132
|
-
const store = useStore() as Store;
|
|
133
|
-
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
const unbind = audioNode(ci, (setVolume) => {
|
|
136
|
-
let volume = 1;
|
|
137
|
-
|
|
138
|
-
const updateVolumeIfNeeded = () => {
|
|
139
|
-
const newVolume = store.getState().dos.volume;
|
|
140
|
-
if (Math.abs(volume - newVolume) >= 0.05) {
|
|
141
|
-
setVolume(newVolume);
|
|
142
|
-
volume = newVolume;
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const unsubscribe = store.subscribe(updateVolumeIfNeeded);
|
|
147
|
-
return unsubscribe;
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
return unbind;
|
|
151
|
-
}, [ci]);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function usePause(ci: CommandInterface): void {
|
|
155
|
-
const paused = useSelector((state: State) => state.dos.paused);
|
|
156
|
-
useEffect(() => {
|
|
157
|
-
paused ? ci.pause() : ci.resume();
|
|
158
|
-
}, [paused, ci]);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function useStats(ci: CommandInterface): void {
|
|
162
|
-
const dispatch = useDispatch();
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
let prevCycles = 0;
|
|
165
|
-
let prevNonSkippableSleepCount = 0;
|
|
166
|
-
let prevSleepCount = 0;
|
|
167
|
-
let prevSleepTime = KBD_0;
|
|
168
|
-
let prevFrame = 0;
|
|
169
|
-
let prevSound = 0;
|
|
170
|
-
let prevMsgSent = 0;
|
|
171
|
-
let prevMsgRecv = 0;
|
|
172
|
-
let intervalStartedAt = Date.now();
|
|
173
|
-
const intervalId = setInterval(() => {
|
|
174
|
-
ci.asyncifyStats().then((stats) => {
|
|
175
|
-
const dtMs = Date.now() - intervalStartedAt;
|
|
176
|
-
const dtSec = dtMs / 1000;
|
|
177
|
-
if (dtSec > 0) {
|
|
178
|
-
const dStats = {
|
|
179
|
-
cyclesPerMs: Math.round((stats.cycles - prevCycles) / dtMs),
|
|
180
|
-
nonSkippableSleepPreSec: Math.round((stats.nonSkippableSleepCount -
|
|
181
|
-
prevNonSkippableSleepCount) / dtSec),
|
|
182
|
-
sleepPerSec: Math.round((stats.sleepCount - prevSleepCount) / dtSec),
|
|
183
|
-
sleepTimePerSec: Math.round((stats.sleepTime - prevSleepTime) / dtSec),
|
|
184
|
-
framePerSec: Math.round((stats.messageFrame - prevFrame) / dtSec),
|
|
185
|
-
soundPerSec: Math.round((stats.messageSound - prevSound) / dtSec),
|
|
186
|
-
msgSentPerSec: Math.round((stats.messageSent - prevMsgSent) / dtSec),
|
|
187
|
-
msgRecvPerSec: Math.round((stats.messageReceived - prevMsgRecv) / dtSec),
|
|
188
|
-
netSent: stats.netSent,
|
|
189
|
-
netRecv: stats.netRecv,
|
|
190
|
-
driveSent: stats.driveSent,
|
|
191
|
-
driveRecv: stats.driveRecv,
|
|
192
|
-
driveRecvTime: stats.driveRecvTime,
|
|
193
|
-
driveCacheHit: stats.driveCacheHit,
|
|
194
|
-
driveCacheMiss: stats.driveCacheMiss,
|
|
195
|
-
driveCacheUsed: stats.driveCacheUsed,
|
|
196
|
-
};
|
|
197
|
-
dispatch(dosSlice.actions.stats(dStats));
|
|
198
|
-
|
|
199
|
-
prevCycles = stats.cycles;
|
|
200
|
-
prevNonSkippableSleepCount = stats.nonSkippableSleepCount;
|
|
201
|
-
prevSleepCount = stats.sleepCount;
|
|
202
|
-
prevSleepTime = stats.sleepTime;
|
|
203
|
-
prevFrame = stats.messageFrame;
|
|
204
|
-
prevSound = stats.messageSound;
|
|
205
|
-
prevMsgSent = stats.messageSent;
|
|
206
|
-
prevMsgRecv = stats.messageReceived;
|
|
207
|
-
intervalStartedAt = Date.now();
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}, 3000);
|
|
211
|
-
|
|
212
|
-
return () => {
|
|
213
|
-
clearInterval(intervalId);
|
|
214
|
-
};
|
|
215
|
-
}, [dispatch, ci]);
|
|
216
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { Emulators, CommandInterface } from "emulators";
|
|
2
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
3
|
-
import { useDispatch, useSelector } from "react-redux";
|
|
4
|
-
import { dosSlice } from "../../store/dos";
|
|
5
|
-
import { State, useNonSerializableStore, postJsDosEvent } from "../../store";
|
|
6
|
-
import { useDosRuntime } from "./dos-runtime";
|
|
7
|
-
import { dhry2Bundle, Dhry2Results } from "./dos-dhry2";
|
|
8
|
-
import { createWsTransportLayer } from "../../ws/ws-transport-layer";
|
|
9
|
-
import { actualWsVersion } from "../../v8/config";
|
|
10
|
-
import { uiSlice } from "../../store/ui";
|
|
11
|
-
|
|
12
|
-
declare const emulators: Emulators;
|
|
13
|
-
|
|
14
|
-
export function DosWindow(props: {
|
|
15
|
-
}) {
|
|
16
|
-
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
17
|
-
const [ci, setCi] = useState<CommandInterface | null>(null);
|
|
18
|
-
const sockdriveWrite = useSelector((state: State) => state.dos.sockdriveWrite);
|
|
19
|
-
const accessToken = useSelector((state: State) => state.auth.account?.token.access_token);
|
|
20
|
-
const token = sockdriveWrite ? accessToken : undefined;
|
|
21
|
-
const worker = useSelector((state: State) => state.dos.worker);
|
|
22
|
-
const backend = useSelector((state: State) => state.dos.backend);
|
|
23
|
-
const backendHardware = useSelector((state: State) => state.dos.backendHardware);
|
|
24
|
-
const dispatch = useDispatch();
|
|
25
|
-
const nonSerializableStore = useNonSerializableStore();
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
try {
|
|
29
|
-
const bundles = nonSerializableStore.loadedBundle!.bundleChanges !== null ?
|
|
30
|
-
[nonSerializableStore.loadedBundle!.bundle, nonSerializableStore.loadedBundle!.bundleChanges] :
|
|
31
|
-
nonSerializableStore.loadedBundle!.bundle;
|
|
32
|
-
|
|
33
|
-
nonSerializableStore.loadedBundle!.bundle = null;
|
|
34
|
-
nonSerializableStore.loadedBundle!.bundleChanges = null;
|
|
35
|
-
|
|
36
|
-
const ci: Promise<CommandInterface> = (async () => {
|
|
37
|
-
if (backendHardware && nonSerializableStore.options.backendHardware) {
|
|
38
|
-
const ws = await nonSerializableStore.options.backendHardware(backend);
|
|
39
|
-
if (ws !== null) {
|
|
40
|
-
return emulators.backend(bundles as any, await createWsTransportLayer(ws, (version) => {
|
|
41
|
-
if (version < actualWsVersion) {
|
|
42
|
-
dispatch(uiSlice.actions.updateWsWarning(true));
|
|
43
|
-
}
|
|
44
|
-
console.log("wsServer:", version, " expected:", actualWsVersion);
|
|
45
|
-
}), { token });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return (emulators as any)[backend + (worker ? "Worker" : "Direct")](bundles, {
|
|
50
|
-
token,
|
|
51
|
-
});
|
|
52
|
-
})();
|
|
53
|
-
|
|
54
|
-
ci
|
|
55
|
-
.then((ci) => {
|
|
56
|
-
setCi(ci);
|
|
57
|
-
dispatch(dosSlice.actions.ci(true));
|
|
58
|
-
nonSerializableStore.ci = ci;
|
|
59
|
-
postJsDosEvent(nonSerializableStore, "ci-ready", ci);
|
|
60
|
-
(window as any).ci = ci;
|
|
61
|
-
})
|
|
62
|
-
.catch((e) => dispatch(dosSlice.actions.emuError(e.message)));
|
|
63
|
-
|
|
64
|
-
return () => {
|
|
65
|
-
ci.then((ci) => {
|
|
66
|
-
dispatch(dosSlice.actions.ci(false));
|
|
67
|
-
nonSerializableStore.ci = null;
|
|
68
|
-
ci.exit();
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
} catch (e) {
|
|
72
|
-
dispatch(dosSlice.actions.emuError((e as any).message));
|
|
73
|
-
}
|
|
74
|
-
}, [worker, backend, token ?? null]);
|
|
75
|
-
|
|
76
|
-
return <div class="bg-black h-full flex-grow overflow-hidden relative">
|
|
77
|
-
<canvas ref={canvasRef} />
|
|
78
|
-
{canvasRef.current && ci && <DosRuntime canvas={canvasRef.current} ci={ci} />}
|
|
79
|
-
</div>;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function DosRuntime(props: { canvas: HTMLCanvasElement, ci: CommandInterface }) {
|
|
83
|
-
const { canvas, ci } = props;
|
|
84
|
-
const bundle = useSelector((state: State) => state.dos.bundle);
|
|
85
|
-
|
|
86
|
-
useDosRuntime(canvas, ci);
|
|
87
|
-
|
|
88
|
-
return <>
|
|
89
|
-
{bundle?.endsWith(dhry2Bundle) && <Dhry2Results ci={ci} />}
|
|
90
|
-
</>;
|
|
91
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { CommandInterface } from "emulators";
|
|
2
|
-
import { resizeCanvas } from "./resize";
|
|
3
|
-
|
|
4
|
-
export function canvas(canvas: HTMLCanvasElement,
|
|
5
|
-
ci: CommandInterface,
|
|
6
|
-
forceAspect?: number) {
|
|
7
|
-
const context = canvas.getContext("2d");
|
|
8
|
-
if (context === null) {
|
|
9
|
-
throw new Error("Unable to create 2d context on given canvas");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
let frameWidth = 0;
|
|
13
|
-
let frameHeight = 0;
|
|
14
|
-
|
|
15
|
-
const onResize = () => {
|
|
16
|
-
resizeCanvas(canvas, frameWidth, frameHeight, forceAspect);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
let rgba = new Uint8ClampedArray(0);
|
|
20
|
-
const onResizeFrame = (w: number, h: number) => {
|
|
21
|
-
frameWidth = w;
|
|
22
|
-
frameHeight = h;
|
|
23
|
-
canvas.width = frameWidth;
|
|
24
|
-
canvas.height = frameHeight;
|
|
25
|
-
rgba = new Uint8ClampedArray(w * h * 4);
|
|
26
|
-
onResize();
|
|
27
|
-
};
|
|
28
|
-
ci.events().onFrameSize(onResizeFrame);
|
|
29
|
-
ci.events().onFrame((frameRgb, frameRgba) => {
|
|
30
|
-
if (frameRgb === null && frameRgba === null) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const frame = (frameRgb !== null ? frameRgb : frameRgba) as Uint8Array;
|
|
35
|
-
|
|
36
|
-
let frameOffset = 0;
|
|
37
|
-
let rgbaOffset = 0;
|
|
38
|
-
|
|
39
|
-
while (rgbaOffset < rgba.length) {
|
|
40
|
-
rgba[rgbaOffset++] = frame[frameOffset++];
|
|
41
|
-
rgba[rgbaOffset++] = frame[frameOffset++];
|
|
42
|
-
rgba[rgbaOffset++] = frame[frameOffset++];
|
|
43
|
-
rgba[rgbaOffset++] = 255;
|
|
44
|
-
|
|
45
|
-
if (frame.length === rgba.length) {
|
|
46
|
-
frameOffset++;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
context.putImageData(new ImageData(rgba, frameWidth, frameHeight), 0, 0);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
onResizeFrame(ci.width(), ci.height());
|
|
54
|
-
|
|
55
|
-
const resizeObserver = new ResizeObserver(onResize);
|
|
56
|
-
resizeObserver.observe(canvas.parentElement!);
|
|
57
|
-
window.addEventListener("resize", onResize);
|
|
58
|
-
|
|
59
|
-
return () => {
|
|
60
|
-
ci.events().onFrameSize(() => {});
|
|
61
|
-
ci.events().onFrame(() => {});
|
|
62
|
-
resizeObserver.disconnect();
|
|
63
|
-
window.removeEventListener("resize", onResize);
|
|
64
|
-
};
|
|
65
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { FitConstant } from "../../../store/dos";
|
|
2
|
-
|
|
3
|
-
export function resizeCanvas(canvas: HTMLCanvasElement,
|
|
4
|
-
frameWidth: number,
|
|
5
|
-
frameHeight: number,
|
|
6
|
-
forceAspect?: number) {
|
|
7
|
-
const rect = canvas.parentElement!.getBoundingClientRect();
|
|
8
|
-
const containerWidth = rect.width;
|
|
9
|
-
const containerHeight = rect.height;
|
|
10
|
-
|
|
11
|
-
if (frameHeight === 0) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
const aspect =
|
|
15
|
-
forceAspect === FitConstant ? (containerWidth / containerHeight) :
|
|
16
|
-
(forceAspect ?? (frameWidth / frameHeight));
|
|
17
|
-
|
|
18
|
-
let width = containerWidth;
|
|
19
|
-
let height = containerWidth / aspect;
|
|
20
|
-
|
|
21
|
-
if (height > containerHeight) {
|
|
22
|
-
height = containerHeight;
|
|
23
|
-
width = containerHeight * aspect;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
canvas.style.position = "relative";
|
|
27
|
-
canvas.style.top = (containerHeight - height) / 2 + "px";
|
|
28
|
-
canvas.style.left = (containerWidth - width) / 2 + "px";
|
|
29
|
-
canvas.style.width = width + "px";
|
|
30
|
-
canvas.style.height = height + "px";
|
|
31
|
-
};
|