emoemu 0.1.0
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/.claude/settings.local.json +77 -0
- package/.node-version +1 -0
- package/CLAUDE.md +435 -0
- package/README.md +404 -0
- package/TODO.md +655 -0
- package/dist/index.cjs +25108 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +25085 -0
- package/docs/building-libretro-cores-arm-mac.md +237 -0
- package/docs/config-file-format.md +488 -0
- package/docs/cores-trd.md +425 -0
- package/docs/headless-hardware-rendering-trd.md +676 -0
- package/docs/libretro-cores-trd.md +997 -0
- package/docs/mupen64-software-rendering-trd.md +751 -0
- package/docs/n64-support-trd.md +306 -0
- package/docs/native-rendering-trd.md +540 -0
- package/docs/native-ui-rendering-trd.md +1195 -0
- package/docs/netplay-trd.md +665 -0
- package/docs/retroarch-netplay-docs.md +277 -0
- package/docs/save-state-format.md +666 -0
- package/eslint.config.js +111 -0
- package/icon/icon.png +0 -0
- package/icon/icon.pxd +0 -0
- package/package.json +63 -0
- package/pnpm-workspace.yaml +10 -0
- package/src/Emulator/consts.ts +14 -0
- package/src/Emulator/index.ts +2496 -0
- package/src/Emulator/saveState/index.ts +155 -0
- package/src/Emulator/screenshot/index.ts +160 -0
- package/src/Emulator/terminalDimensions/index.ts +79 -0
- package/src/Emulator/types.ts +83 -0
- package/src/cli/commands/consts.ts +10 -0
- package/src/cli/commands/index.ts +462 -0
- package/src/cli/parseArgs/consts.ts +17 -0
- package/src/cli/parseArgs/index.ts +457 -0
- package/src/cli/parseArgs/types.ts +61 -0
- package/src/cli/runEmulator/index.ts +406 -0
- package/src/cli/runEmulator/types.ts +7 -0
- package/src/consts.ts +19 -0
- package/src/core/button/consts.ts +35 -0
- package/src/core/button/index.ts +123 -0
- package/src/core/core.ts +300 -0
- package/src/core/index.ts +19 -0
- package/src/cores/libretro/api/index.ts +334 -0
- package/src/cores/libretro/api/types.ts +148 -0
- package/src/cores/libretro/callbacks/consts.ts +41 -0
- package/src/cores/libretro/callbacks/index.ts +456 -0
- package/src/cores/libretro/consts.ts +45 -0
- package/src/cores/libretro/coreOptions/consts.ts +36 -0
- package/src/cores/libretro/coreOptions/index.ts +222 -0
- package/src/cores/libretro/environment/consts.ts +118 -0
- package/src/cores/libretro/environment/index.ts +1095 -0
- package/src/cores/libretro/index.ts +937 -0
- package/src/cores/libretro/loader/index.ts +496 -0
- package/src/cores/libretro/pixelFormat/consts.ts +43 -0
- package/src/cores/libretro/pixelFormat/index.ts +397 -0
- package/src/cores/libretro/types.ts +339 -0
- package/src/frontend/AudioManager/index.ts +420 -0
- package/src/frontend/SettingsManager/index.ts +250 -0
- package/src/frontend/config/index.ts +608 -0
- package/src/frontend/config/tests.ts +354 -0
- package/src/frontend/config/types.ts +36 -0
- package/src/frontend/consts.ts +114 -0
- package/src/frontend/coreBuilder/index.ts +644 -0
- package/src/frontend/coreBuilder/types.ts +15 -0
- package/src/frontend/coreDownloader/index.ts +620 -0
- package/src/frontend/coreDownloader/types.ts +17 -0
- package/src/frontend/corePreferences/index.ts +69 -0
- package/src/frontend/coreRegistry/index.ts +276 -0
- package/src/frontend/directoryCache/index.ts +75 -0
- package/src/frontend/index.ts +79 -0
- package/src/frontend/notifications/consts.ts +14 -0
- package/src/frontend/notifications/index.ts +250 -0
- package/src/frontend/playlist/consts.ts +168 -0
- package/src/frontend/playlist/index.ts +899 -0
- package/src/frontend/playlist/labelFormatter/consts.ts +15 -0
- package/src/frontend/playlist/labelFormatter/index.ts +155 -0
- package/src/frontend/playlist/labelFormatter/tests.ts +153 -0
- package/src/frontend/playlist/reader/index.ts +559 -0
- package/src/frontend/playlist/sync/index.ts +511 -0
- package/src/frontend/playlist/systemLookup/index.ts +233 -0
- package/src/frontend/playlist/utils/index.ts +50 -0
- package/src/frontend/romScanner/consts.ts +348 -0
- package/src/frontend/romScanner/index.ts +1957 -0
- package/src/frontend/saveServices/consts.ts +2 -0
- package/src/frontend/saveServices/index.ts +313 -0
- package/src/frontend/serviceProvider/index.ts +108 -0
- package/src/frontend/serviceProvider/types.ts +13 -0
- package/src/index.ts +428 -0
- package/src/input/Controller/consts.ts +50 -0
- package/src/input/Controller/index.ts +81 -0
- package/src/input/GamepadManager/consts.ts +22 -0
- package/src/input/GamepadManager/index.ts +418 -0
- package/src/input/InputManager/consts.ts +86 -0
- package/src/input/InputManager/index.ts +593 -0
- package/src/input/InputMapper/consts.ts +33 -0
- package/src/input/InputMapper/index.ts +436 -0
- package/src/input/consts.ts +410 -0
- package/src/input/gamepadProfiles/index.ts +1100 -0
- package/src/input/index.ts +38 -0
- package/src/input/inputUtils/index.ts +31 -0
- package/src/netplay/FrameBuffer/consts.ts +2 -0
- package/src/netplay/FrameBuffer/index.ts +364 -0
- package/src/netplay/FrameBuffer/tests.ts +286 -0
- package/src/netplay/InputBuffer/consts.ts +7 -0
- package/src/netplay/InputBuffer/index.ts +347 -0
- package/src/netplay/InputBuffer/tests.ts +166 -0
- package/src/netplay/NetplayClient/index.ts +976 -0
- package/src/netplay/NetplayConnection/index.ts +536 -0
- package/src/netplay/NetplayDiscovery/consts.ts +41 -0
- package/src/netplay/NetplayDiscovery/index.ts +525 -0
- package/src/netplay/NetplayServer/index.ts +1407 -0
- package/src/netplay/SyncManager/index.ts +984 -0
- package/src/netplay/SyncManager/tests.ts +419 -0
- package/src/netplay/consts.ts +371 -0
- package/src/netplay/crc32/consts.ts +14 -0
- package/src/netplay/crc32/index.ts +97 -0
- package/src/netplay/crc32/tests.ts +40 -0
- package/src/netplay/index.ts +41 -0
- package/src/netplay/netplayLogger/consts.ts +30 -0
- package/src/netplay/netplayLogger/index.ts +345 -0
- package/src/netplay/protocol/consts.ts +86 -0
- package/src/netplay/protocol/index.ts +1280 -0
- package/src/netplay/protocol/tests.ts +606 -0
- package/src/netplay/protocol/types.ts +20 -0
- package/src/netplay/types.ts +395 -0
- package/src/rendering/KittyRenderer/index.ts +616 -0
- package/src/rendering/NativeRenderer/index.ts +279 -0
- package/src/rendering/NativeRenderer/tests.ts +133 -0
- package/src/rendering/TerminalRenderer/index.ts +770 -0
- package/src/rendering/consts.ts +401 -0
- package/src/rendering/fonts/CozetteVector.ttf +0 -0
- package/src/rendering/index.ts +26 -0
- package/src/rendering/nativeUi/NativeWindowManager/index.ts +158 -0
- package/src/rendering/nativeUi/NativeWindowManager/tests.ts +81 -0
- package/src/rendering/nativeUi/consts.ts +6 -0
- package/src/rendering/nativeUi/index.ts +20 -0
- package/src/rendering/postProcessing/consts.ts +38 -0
- package/src/rendering/postProcessing/index.ts +923 -0
- package/src/rendering/shared/ansi/consts.ts +12 -0
- package/src/rendering/shared/ansi/index.ts +104 -0
- package/src/rendering/shared/consts.ts +2 -0
- package/src/rendering/shared/fitToTerminal/index.ts +67 -0
- package/src/ui/AddRomsPrompt/consts.ts +13 -0
- package/src/ui/AddRomsPrompt/index.tsx +781 -0
- package/src/ui/App/consts.ts +2 -0
- package/src/ui/App/index.tsx +456 -0
- package/src/ui/AppCapabilities/index.tsx +67 -0
- package/src/ui/ConfigContext/index.tsx +56 -0
- package/src/ui/CoreManager/consts.ts +11 -0
- package/src/ui/CoreManager/index.tsx +779 -0
- package/src/ui/CoreSelector/consts.ts +2 -0
- package/src/ui/CoreSelector/index.tsx +251 -0
- package/src/ui/DialogContainer/index.tsx +42 -0
- package/src/ui/DialogOptionsList/index.tsx +61 -0
- package/src/ui/DuplicateCrcPrompt/consts.ts +5 -0
- package/src/ui/DuplicateCrcPrompt/index.tsx +146 -0
- package/src/ui/GamepadContext/consts.ts +15 -0
- package/src/ui/GamepadContext/index.tsx +295 -0
- package/src/ui/NativeDialog/index.tsx +120 -0
- package/src/ui/NetplayDisconnectedDialog/index.tsx +93 -0
- package/src/ui/NetplayPauseMenu/consts.ts +2 -0
- package/src/ui/NetplayPauseMenu/index.tsx +97 -0
- package/src/ui/RomBrowser/NetplayPanel/consts.ts +24 -0
- package/src/ui/RomBrowser/NetplayPanel/index.tsx +520 -0
- package/src/ui/RomBrowser/SettingsPanel/index.tsx +478 -0
- package/src/ui/RomBrowser/consts.ts +61 -0
- package/src/ui/RomBrowser/index.tsx +1164 -0
- package/src/ui/RomBrowser/settingsConfig/index.ts +320 -0
- package/src/ui/RomBrowser/types.ts +67 -0
- package/src/ui/SaveStateDialog/consts.ts +2 -0
- package/src/ui/SaveStateDialog/index.tsx +225 -0
- package/src/ui/WarningDialog/index.tsx +113 -0
- package/src/ui/consts.ts +27 -0
- package/src/ui/hooks/useClearTerminal/consts.ts +2 -0
- package/src/ui/hooks/useClearTerminal/index.ts +37 -0
- package/src/ui/hooks/useDialogNavigation/index.ts +99 -0
- package/src/ui/hooks/useGamepad/consts.ts +21 -0
- package/src/ui/hooks/useGamepad/index.ts +194 -0
- package/src/ui/index.ts +27 -0
- package/src/utils/buffer/consts.ts +17 -0
- package/src/utils/buffer/index.ts +129 -0
- package/src/utils/color/consts.ts +58 -0
- package/src/utils/color/index.ts +183 -0
- package/src/utils/compression/consts.ts +50 -0
- package/src/utils/compression/index.ts +101 -0
- package/src/utils/consts.ts +2 -0
- package/src/utils/crc32/consts.ts +22 -0
- package/src/utils/crc32/index.ts +83 -0
- package/src/utils/ensureDirectory/index.ts +10 -0
- package/src/utils/format/consts.ts +8 -0
- package/src/utils/format/index.ts +53 -0
- package/src/utils/getErrorMessage/index.ts +10 -0
- package/src/utils/index.ts +113 -0
- package/src/utils/ini/index.ts +200 -0
- package/src/utils/kitty/consts.ts +13 -0
- package/src/utils/kitty/index.ts +181 -0
- package/src/utils/logger/consts.ts +35 -0
- package/src/utils/logger/index.ts +217 -0
- package/src/utils/paths/consts.ts +18 -0
- package/src/utils/paths/index.ts +151 -0
- package/src/utils/png/consts.ts +34 -0
- package/src/utils/png/index.ts +131 -0
- package/src/utils/readJsonFile/index.ts +16 -0
- package/src/utils/rotateLogFile/index.ts +44 -0
- package/src/utils/safeClose/index.ts +10 -0
- package/src/utils/terminal/consts.ts +8 -0
- package/src/utils/terminal/index.ts +102 -0
- package/src/utils/thumbnailRenderer/consts.ts +2 -0
- package/src/utils/thumbnailRenderer/index.ts +147 -0
- package/src/utils/typedError/index.ts +26 -0
- package/tsconfig.json +31 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { clamp } from 'remeda';
|
|
2
|
+
import type { RenderMode } from '../../Emulator';
|
|
3
|
+
import type { Config, VideoDriver } from '../../frontend/config';
|
|
4
|
+
import { loadConfig, getPlaylistsDirectory } from '../../frontend/config';
|
|
5
|
+
import { initializeServices } from '../../frontend/serviceProvider';
|
|
6
|
+
import { setNotificationsEnabled } from '../../frontend/notifications';
|
|
7
|
+
import { PNG_COMPRESSION_MIN, PNG_COMPRESSION_MAX } from '../../rendering';
|
|
8
|
+
import { MAX_INPUT_DELAY_FRAMES } from '../../netplay';
|
|
9
|
+
import type { CliOptions } from './types';
|
|
10
|
+
import {
|
|
11
|
+
DEFAULT_SCANLINES,
|
|
12
|
+
DEFAULT_VIGNETTE,
|
|
13
|
+
DEFAULT_BLOOM,
|
|
14
|
+
MIN_FRAME_LIMIT,
|
|
15
|
+
DEFAULT_NTSC,
|
|
16
|
+
DEFAULT_CURVATURE,
|
|
17
|
+
DEFAULT_CHROMATIC_ABERRATION,
|
|
18
|
+
CRT_SCALE,
|
|
19
|
+
CRT_NTSC,
|
|
20
|
+
CRT_SCANLINES,
|
|
21
|
+
CRT_GAMMA,
|
|
22
|
+
CRT_VIGNETTE,
|
|
23
|
+
CRT_CURVATURE,
|
|
24
|
+
CRT_CHROMATIC_ABERRATION,
|
|
25
|
+
} from './consts';
|
|
26
|
+
|
|
27
|
+
export * from './consts';
|
|
28
|
+
export * from './types';
|
|
29
|
+
|
|
30
|
+
// Map config video_driver to RenderMode (null = Auto, use system-specific default)
|
|
31
|
+
const videoDriverToRenderMode = (driver: VideoDriver | null): RenderMode | undefined => {
|
|
32
|
+
switch (driver) {
|
|
33
|
+
case null: return undefined; // Auto (system-specific default)
|
|
34
|
+
case "native": return "native";
|
|
35
|
+
case "kitty": return "kitty";
|
|
36
|
+
case "terminal": return "terminal";
|
|
37
|
+
case "ascii": return "ascii";
|
|
38
|
+
case "emoji": return "emoji";
|
|
39
|
+
default: return "kitty";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const parseArgs = (args: string[]): CliOptions => {
|
|
44
|
+
// First pass: find --config flag to load config file before processing other args
|
|
45
|
+
let configPath: string | undefined;
|
|
46
|
+
for (let i = 0; i < args.length; i++) {
|
|
47
|
+
if (args[i] === "--config" && args[i + 1]) {
|
|
48
|
+
configPath = args[i + 1];
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Load config (will use defaults if no config file exists)
|
|
54
|
+
const { config, loadedFrom: _loadedFrom } = loadConfig(configPath);
|
|
55
|
+
|
|
56
|
+
// Initialize services with config (makes them available globally)
|
|
57
|
+
initializeServices(config);
|
|
58
|
+
|
|
59
|
+
// Initialize notifications setting from config
|
|
60
|
+
setNotificationsEnabled(config.notifications_enable);
|
|
61
|
+
|
|
62
|
+
// Initialize result with values from config (CLI flags will override)
|
|
63
|
+
const result: CliOptions = {
|
|
64
|
+
romPath: undefined,
|
|
65
|
+
width: config.custom_viewport_width ?? undefined,
|
|
66
|
+
height: config.custom_viewport_height ?? undefined,
|
|
67
|
+
colorEnabled: config.video_color_enable,
|
|
68
|
+
renderMode: videoDriverToRenderMode(config.video_driver), // undefined = Auto
|
|
69
|
+
scale: config.video_scale ?? undefined, // null = Auto (system-specific default)
|
|
70
|
+
help: false,
|
|
71
|
+
showVersion: false,
|
|
72
|
+
listGamepads: false,
|
|
73
|
+
listCoresFlag: false,
|
|
74
|
+
installCore: undefined,
|
|
75
|
+
removeCore: undefined,
|
|
76
|
+
core: config.core_default || undefined,
|
|
77
|
+
enableGamepad: config.input_joypad_enable,
|
|
78
|
+
enableAudio: config.audio_enable,
|
|
79
|
+
startMuted: config.audio_mute_enable,
|
|
80
|
+
enableSaveState: config.savestate_auto_load && config.savestate_auto_save,
|
|
81
|
+
enableBatterySave: config.battery_save_enable,
|
|
82
|
+
showStatusBar: config.fps_show_enable,
|
|
83
|
+
enableDiffRendering: config.video_diff_render,
|
|
84
|
+
noRender: false,
|
|
85
|
+
debugGamepad: false,
|
|
86
|
+
fpsLimit: config.fps_limit || undefined,
|
|
87
|
+
loadRetroArch: config.retroarch_cores_enable,
|
|
88
|
+
pngCompressionLevel: config.kitty_png_level,
|
|
89
|
+
// Post-processing effects based on mode: off (no effects), crt (presets), or custom (user values)
|
|
90
|
+
gamma: config.video_postprocessing_mode === 'crt' ? config.crt_gamma :
|
|
91
|
+
config.video_postprocessing_mode === 'custom' ? config.video_gamma : 1.0,
|
|
92
|
+
scanlines: config.video_postprocessing_mode === 'crt' ? config.crt_scanlines :
|
|
93
|
+
config.video_postprocessing_mode === 'custom' ? config.video_scanlines : 0,
|
|
94
|
+
saturation: config.video_postprocessing_mode === 'crt' ? config.crt_saturation :
|
|
95
|
+
config.video_postprocessing_mode === 'custom' ? config.video_saturation : 1.0,
|
|
96
|
+
brightness: config.video_postprocessing_mode === 'custom' ? config.video_brightness : 1.0,
|
|
97
|
+
contrast: config.video_postprocessing_mode === 'custom' ? config.video_contrast : 1.0,
|
|
98
|
+
vignette: config.video_postprocessing_mode === 'crt' ? config.crt_vignette :
|
|
99
|
+
config.video_postprocessing_mode === 'custom' ? config.video_vignette : 0,
|
|
100
|
+
bloom: config.video_postprocessing_mode === 'custom' ? config.video_bloom : 0,
|
|
101
|
+
bloomThreshold: config.video_bloom_threshold,
|
|
102
|
+
ntsc: config.video_postprocessing_mode === 'crt' ? config.crt_ntsc :
|
|
103
|
+
config.video_postprocessing_mode === 'custom' ? config.video_ntsc : 0,
|
|
104
|
+
curvature: config.video_postprocessing_mode === 'crt' ? config.crt_curvature :
|
|
105
|
+
config.video_postprocessing_mode === 'custom' ? config.video_curvature : 0,
|
|
106
|
+
chromaticAberration: config.video_postprocessing_mode === 'crt' ? config.crt_chromatic_aberration :
|
|
107
|
+
config.video_postprocessing_mode === 'custom' ? config.video_chromatic_aberration : 0,
|
|
108
|
+
hasUserEffects: false, // Will be set to true if any effect flag is specified
|
|
109
|
+
configPath,
|
|
110
|
+
config,
|
|
111
|
+
scanDepth: config.browser_scan_depth,
|
|
112
|
+
// Playlist generation options
|
|
113
|
+
generatePlaylist: false,
|
|
114
|
+
playlistOutput: getPlaylistsDirectory(config),
|
|
115
|
+
singlePlaylist: undefined,
|
|
116
|
+
windowsPaths: false,
|
|
117
|
+
// Netplay options
|
|
118
|
+
netplayHost: false,
|
|
119
|
+
netplayConnect: undefined,
|
|
120
|
+
netplayPort: 55435,
|
|
121
|
+
netplayPassword: undefined,
|
|
122
|
+
netplaySpectate: false,
|
|
123
|
+
netplayNickname: 'Player',
|
|
124
|
+
netplayInputDelay: 0,
|
|
125
|
+
clearLogs: false,
|
|
126
|
+
verbose: false,
|
|
127
|
+
frameLimit: config.video_frame_limit,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Track if config had non-default effect values (for hasUserEffects)
|
|
131
|
+
const configHasEffects = config.video_gamma !== 1.0 ||
|
|
132
|
+
config.video_scanlines !== 0 ||
|
|
133
|
+
config.video_saturation !== 1.0 ||
|
|
134
|
+
config.video_brightness !== 1.0 ||
|
|
135
|
+
config.video_contrast !== 1.0 ||
|
|
136
|
+
config.video_vignette !== 0 ||
|
|
137
|
+
config.video_bloom !== 0 ||
|
|
138
|
+
config.video_ntsc !== 0 ||
|
|
139
|
+
config.video_curvature !== 0 ||
|
|
140
|
+
config.video_chromatic_aberration !== 0;
|
|
141
|
+
|
|
142
|
+
// Track which CRT-related flags were explicitly set (for --crt override logic)
|
|
143
|
+
let crtMode = false;
|
|
144
|
+
let scaleExplicit = false;
|
|
145
|
+
let gammaExplicit = false;
|
|
146
|
+
let scanlinesExplicit = false;
|
|
147
|
+
let saturationExplicit = false;
|
|
148
|
+
let brightnessExplicit = false;
|
|
149
|
+
let contrastExplicit = false;
|
|
150
|
+
let ntscExplicit = false;
|
|
151
|
+
let vignetteExplicit = false;
|
|
152
|
+
let bloomExplicit = false;
|
|
153
|
+
let bloomThresholdExplicit = false;
|
|
154
|
+
let curvatureExplicit = false;
|
|
155
|
+
let chromaticAberrationExplicit = false;
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < args.length; i++) {
|
|
158
|
+
const arg = args[i];
|
|
159
|
+
|
|
160
|
+
if (arg === "--help" || arg === "-h") {
|
|
161
|
+
result.help = true;
|
|
162
|
+
} else if (arg === "--version" || arg === "-V") {
|
|
163
|
+
result.showVersion = true;
|
|
164
|
+
} else if (arg === "--width" && args[i + 1]) {
|
|
165
|
+
result.width = parseInt(args[++i], 10);
|
|
166
|
+
} else if (arg === "--height" && args[i + 1]) {
|
|
167
|
+
result.height = parseInt(args[++i], 10);
|
|
168
|
+
} else if (arg === "--scale" && args[i + 1]) {
|
|
169
|
+
result.scale = parseFloat(args[++i]);
|
|
170
|
+
scaleExplicit = true;
|
|
171
|
+
} else if (arg === "--png-level" && args[i + 1]) {
|
|
172
|
+
const level = parseInt(args[++i], 10);
|
|
173
|
+
result.pngCompressionLevel = clamp(level, { min: PNG_COMPRESSION_MIN, max: PNG_COMPRESSION_MAX });
|
|
174
|
+
} else if (arg === "--ascii") {
|
|
175
|
+
result.renderMode = "ascii";
|
|
176
|
+
result.config.video_driver = "ascii";
|
|
177
|
+
} else if (arg === "--emoji") {
|
|
178
|
+
result.renderMode = "emoji";
|
|
179
|
+
result.config.video_driver = "emoji";
|
|
180
|
+
} else if (arg === "--no-color") {
|
|
181
|
+
result.colorEnabled = false;
|
|
182
|
+
} else if (arg === "--native") {
|
|
183
|
+
result.renderMode = "native";
|
|
184
|
+
result.config.video_driver = "native";
|
|
185
|
+
} else if (arg === "--kitty") {
|
|
186
|
+
result.renderMode = "kitty";
|
|
187
|
+
result.config.video_driver = "kitty";
|
|
188
|
+
} else if (arg === "--terminal") {
|
|
189
|
+
result.renderMode = "terminal";
|
|
190
|
+
result.config.video_driver = "terminal";
|
|
191
|
+
} else if (arg === "--list-gamepads") {
|
|
192
|
+
result.listGamepads = true;
|
|
193
|
+
} else if (arg === "--list-cores") {
|
|
194
|
+
result.listCoresFlag = true;
|
|
195
|
+
} else if (arg === "--install-core" && args[i + 1]) {
|
|
196
|
+
result.installCore = args[++i];
|
|
197
|
+
} else if (arg === "--remove-core" && args[i + 1]) {
|
|
198
|
+
result.removeCore = args[++i];
|
|
199
|
+
} else if (arg === "--core" && args[i + 1]) {
|
|
200
|
+
result.core = args[++i];
|
|
201
|
+
} else if (arg === "--no-gamepad") {
|
|
202
|
+
result.enableGamepad = false;
|
|
203
|
+
} else if (arg === "--no-audio") {
|
|
204
|
+
result.enableAudio = false;
|
|
205
|
+
} else if (arg === "--no-save-state") {
|
|
206
|
+
result.enableSaveState = false;
|
|
207
|
+
} else if (arg === "--no-battery-save") {
|
|
208
|
+
result.enableBatterySave = false;
|
|
209
|
+
} else if (arg === "--status") {
|
|
210
|
+
result.showStatusBar = true;
|
|
211
|
+
} else if (arg === "--no-diff-render") {
|
|
212
|
+
result.enableDiffRendering = false;
|
|
213
|
+
} else if (arg === "--no-render") {
|
|
214
|
+
result.noRender = true;
|
|
215
|
+
} else if (arg === "--debug-gamepad") {
|
|
216
|
+
result.debugGamepad = true;
|
|
217
|
+
} else if (arg === "--clear-logs") {
|
|
218
|
+
result.clearLogs = true;
|
|
219
|
+
} else if (arg === "--verbose" || arg === "-v") {
|
|
220
|
+
result.verbose = true;
|
|
221
|
+
} else if (arg === "--fps-limit" && args[i + 1]) {
|
|
222
|
+
result.fpsLimit = parseInt(args[++i], 10);
|
|
223
|
+
} else if (arg === "--frame-limit" && args[i + 1]) {
|
|
224
|
+
const limit = parseInt(args[++i], 10);
|
|
225
|
+
result.frameLimit = limit <= 0 ? 0 : Math.max(MIN_FRAME_LIMIT, limit); // 0 = off, otherwise min 1
|
|
226
|
+
} else if (arg === "--retroarch") {
|
|
227
|
+
result.loadRetroArch = true;
|
|
228
|
+
} else if (arg === "--crt") {
|
|
229
|
+
crtMode = true;
|
|
230
|
+
} else if (arg === "--gamma" && args[i + 1]) {
|
|
231
|
+
result.gamma = parseFloat(args[++i]);
|
|
232
|
+
gammaExplicit = true;
|
|
233
|
+
} else if (arg === "--scanlines") {
|
|
234
|
+
// Check if next arg is a number (not another flag)
|
|
235
|
+
const nextArg = args[i + 1];
|
|
236
|
+
if (nextArg && !nextArg.startsWith("-") && !isNaN(parseFloat(nextArg))) {
|
|
237
|
+
result.scanlines = parseFloat(args[++i]);
|
|
238
|
+
} else {
|
|
239
|
+
result.scanlines = DEFAULT_SCANLINES;
|
|
240
|
+
}
|
|
241
|
+
scanlinesExplicit = true;
|
|
242
|
+
} else if (arg === "--saturation" && args[i + 1]) {
|
|
243
|
+
result.saturation = parseFloat(args[++i]);
|
|
244
|
+
saturationExplicit = true;
|
|
245
|
+
} else if (arg === "--brightness" && args[i + 1]) {
|
|
246
|
+
result.brightness = parseFloat(args[++i]);
|
|
247
|
+
brightnessExplicit = true;
|
|
248
|
+
} else if (arg === "--contrast" && args[i + 1]) {
|
|
249
|
+
result.contrast = parseFloat(args[++i]);
|
|
250
|
+
contrastExplicit = true;
|
|
251
|
+
} else if (arg === "--vignette") {
|
|
252
|
+
// Check if next arg is a number (not another flag)
|
|
253
|
+
const nextArg = args[i + 1];
|
|
254
|
+
if (nextArg && !nextArg.startsWith("-") && !isNaN(parseFloat(nextArg))) {
|
|
255
|
+
result.vignette = parseFloat(args[++i]);
|
|
256
|
+
} else {
|
|
257
|
+
result.vignette = DEFAULT_VIGNETTE;
|
|
258
|
+
}
|
|
259
|
+
vignetteExplicit = true;
|
|
260
|
+
} else if (arg === "--bloom") {
|
|
261
|
+
// Check if next arg is a number (not another flag)
|
|
262
|
+
const nextArg = args[i + 1];
|
|
263
|
+
if (nextArg && !nextArg.startsWith("-") && !isNaN(parseFloat(nextArg))) {
|
|
264
|
+
result.bloom = parseFloat(args[++i]);
|
|
265
|
+
} else {
|
|
266
|
+
result.bloom = DEFAULT_BLOOM;
|
|
267
|
+
}
|
|
268
|
+
bloomExplicit = true;
|
|
269
|
+
} else if (arg === "--bloom-threshold" && args[i + 1]) {
|
|
270
|
+
result.bloomThreshold = parseFloat(args[++i]);
|
|
271
|
+
bloomThresholdExplicit = true;
|
|
272
|
+
} else if (arg === "--ntsc") {
|
|
273
|
+
// Check if next arg is a number (not another flag)
|
|
274
|
+
const nextArg = args[i + 1];
|
|
275
|
+
if (nextArg && !nextArg.startsWith("-") && !isNaN(parseFloat(nextArg))) {
|
|
276
|
+
result.ntsc = parseFloat(args[++i]);
|
|
277
|
+
} else {
|
|
278
|
+
result.ntsc = DEFAULT_NTSC;
|
|
279
|
+
}
|
|
280
|
+
ntscExplicit = true;
|
|
281
|
+
} else if (arg === "--curvature") {
|
|
282
|
+
// Check if next arg is a number (not another flag)
|
|
283
|
+
const nextArg = args[i + 1];
|
|
284
|
+
if (nextArg && !nextArg.startsWith("-") && !isNaN(parseFloat(nextArg))) {
|
|
285
|
+
result.curvature = parseFloat(args[++i]);
|
|
286
|
+
} else {
|
|
287
|
+
result.curvature = DEFAULT_CURVATURE;
|
|
288
|
+
}
|
|
289
|
+
curvatureExplicit = true;
|
|
290
|
+
} else if (arg === "--chromatic-aberration") {
|
|
291
|
+
// Check if next arg is a number (not another flag)
|
|
292
|
+
const nextArg = args[i + 1];
|
|
293
|
+
if (nextArg && !nextArg.startsWith("-") && !isNaN(parseFloat(nextArg))) {
|
|
294
|
+
result.chromaticAberration = parseFloat(args[++i]);
|
|
295
|
+
} else {
|
|
296
|
+
result.chromaticAberration = DEFAULT_CHROMATIC_ABERRATION;
|
|
297
|
+
}
|
|
298
|
+
chromaticAberrationExplicit = true;
|
|
299
|
+
} else if (arg === "--scan-depth" && args[i + 1]) {
|
|
300
|
+
result.scanDepth = parseInt(args[++i], 10);
|
|
301
|
+
} else if (arg === "--generate-playlist") {
|
|
302
|
+
// Check if next arg is a path (not another flag)
|
|
303
|
+
const nextArg = args[i + 1];
|
|
304
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
305
|
+
result.generatePlaylist = args[++i];
|
|
306
|
+
} else {
|
|
307
|
+
result.generatePlaylist = true; // Use cwd
|
|
308
|
+
}
|
|
309
|
+
} else if (arg === "--playlist-output" && args[i + 1]) {
|
|
310
|
+
result.playlistOutput = args[++i];
|
|
311
|
+
} else if (arg === "--single-playlist" && args[i + 1]) {
|
|
312
|
+
result.singlePlaylist = args[++i];
|
|
313
|
+
} else if (arg === "--windows-paths") {
|
|
314
|
+
result.windowsPaths = true;
|
|
315
|
+
} else if (arg === "--config" && args[i + 1]) {
|
|
316
|
+
// Already handled in first pass, just skip the argument
|
|
317
|
+
i++;
|
|
318
|
+
} else if (arg === "--netplay-host") {
|
|
319
|
+
result.netplayHost = true;
|
|
320
|
+
} else if (arg === "--netplay-connect") {
|
|
321
|
+
// Check if next arg is a host (not another flag)
|
|
322
|
+
const nextArg = args[i + 1];
|
|
323
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
324
|
+
result.netplayConnect = args[++i];
|
|
325
|
+
} else {
|
|
326
|
+
// No host specified - use LAN discovery
|
|
327
|
+
result.netplayConnect = '';
|
|
328
|
+
}
|
|
329
|
+
} else if (arg === "--netplay-port" && args[i + 1]) {
|
|
330
|
+
result.netplayPort = parseInt(args[++i], 10);
|
|
331
|
+
} else if (arg === "--netplay-password" && args[i + 1]) {
|
|
332
|
+
result.netplayPassword = args[++i];
|
|
333
|
+
} else if (arg === "--netplay-spectate") {
|
|
334
|
+
result.netplaySpectate = true;
|
|
335
|
+
} else if (arg === "--netplay-nick" && args[i + 1]) {
|
|
336
|
+
result.netplayNickname = args[++i];
|
|
337
|
+
} else if (arg === "--netplay-frames" && args[i + 1]) {
|
|
338
|
+
const frames = parseInt(args[++i], 10);
|
|
339
|
+
result.netplayInputDelay = clamp(frames, { min: 0, max: MAX_INPUT_DELAY_FRAMES });
|
|
340
|
+
} else if (!arg.startsWith("-")) {
|
|
341
|
+
result.romPath = arg;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Apply --crt preset defaults for flags not explicitly set
|
|
346
|
+
if (crtMode) {
|
|
347
|
+
if (!scaleExplicit) {
|
|
348
|
+
result.scale = CRT_SCALE;
|
|
349
|
+
}
|
|
350
|
+
if (!ntscExplicit) {
|
|
351
|
+
result.ntsc = CRT_NTSC;
|
|
352
|
+
}
|
|
353
|
+
if (!scanlinesExplicit) {
|
|
354
|
+
result.scanlines = CRT_SCANLINES;
|
|
355
|
+
}
|
|
356
|
+
if (!gammaExplicit) {
|
|
357
|
+
result.gamma = CRT_GAMMA;
|
|
358
|
+
}
|
|
359
|
+
if (!vignetteExplicit) {
|
|
360
|
+
result.vignette = CRT_VIGNETTE;
|
|
361
|
+
}
|
|
362
|
+
if (!curvatureExplicit) {
|
|
363
|
+
result.curvature = CRT_CURVATURE;
|
|
364
|
+
}
|
|
365
|
+
if (!chromaticAberrationExplicit) {
|
|
366
|
+
result.chromaticAberration = CRT_CHROMATIC_ABERRATION;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Determine if user explicitly specified any post-processing effects
|
|
371
|
+
// --crt counts as having user effects since it's an explicit choice
|
|
372
|
+
// video_postprocessing_mode !== 'off' means effects are enabled in config
|
|
373
|
+
// configHasEffects means the config file had non-default custom effect values
|
|
374
|
+
result.hasUserEffects = crtMode ||
|
|
375
|
+
config.video_postprocessing_mode !== 'off' ||
|
|
376
|
+
configHasEffects ||
|
|
377
|
+
gammaExplicit ||
|
|
378
|
+
scanlinesExplicit ||
|
|
379
|
+
saturationExplicit ||
|
|
380
|
+
brightnessExplicit ||
|
|
381
|
+
contrastExplicit ||
|
|
382
|
+
vignetteExplicit ||
|
|
383
|
+
bloomExplicit ||
|
|
384
|
+
bloomThresholdExplicit ||
|
|
385
|
+
ntscExplicit ||
|
|
386
|
+
curvatureExplicit ||
|
|
387
|
+
chromaticAberrationExplicit;
|
|
388
|
+
|
|
389
|
+
return result;
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Update runtime options from a fresh config (for settings changed in browser)
|
|
394
|
+
* Only updates settings that can be changed at runtime, preserving CLI overrides
|
|
395
|
+
*/
|
|
396
|
+
export const updateOptionsFromConfig = (options: CliOptions, config: Config): void => {
|
|
397
|
+
// Update video settings
|
|
398
|
+
options.renderMode = videoDriverToRenderMode(config.video_driver); // undefined = Auto
|
|
399
|
+
options.scale = config.video_scale ?? undefined; // null = Auto (system-specific default)
|
|
400
|
+
|
|
401
|
+
// Update audio/input settings
|
|
402
|
+
options.enableAudio = config.audio_enable;
|
|
403
|
+
options.startMuted = config.audio_mute_enable;
|
|
404
|
+
options.enableGamepad = config.input_joypad_enable;
|
|
405
|
+
|
|
406
|
+
// Update save state settings
|
|
407
|
+
options.enableSaveState = config.savestate_auto_load && config.savestate_auto_save;
|
|
408
|
+
|
|
409
|
+
// Update status bar setting
|
|
410
|
+
options.showStatusBar = config.fps_show_enable;
|
|
411
|
+
|
|
412
|
+
// Update frame limit setting
|
|
413
|
+
options.frameLimit = config.video_frame_limit;
|
|
414
|
+
|
|
415
|
+
// Update notifications
|
|
416
|
+
setNotificationsEnabled(config.notifications_enable);
|
|
417
|
+
|
|
418
|
+
// Update post-processing effects based on mode
|
|
419
|
+
if (config.video_postprocessing_mode === 'crt') {
|
|
420
|
+
options.gamma = config.crt_gamma;
|
|
421
|
+
options.scanlines = config.crt_scanlines;
|
|
422
|
+
options.saturation = config.crt_saturation;
|
|
423
|
+
options.vignette = config.crt_vignette;
|
|
424
|
+
options.ntsc = config.crt_ntsc;
|
|
425
|
+
options.curvature = config.crt_curvature;
|
|
426
|
+
options.chromaticAberration = config.crt_chromatic_aberration;
|
|
427
|
+
options.hasUserEffects = true;
|
|
428
|
+
} else if (config.video_postprocessing_mode === 'custom') {
|
|
429
|
+
options.gamma = config.video_gamma;
|
|
430
|
+
options.scanlines = config.video_scanlines;
|
|
431
|
+
options.saturation = config.video_saturation;
|
|
432
|
+
options.brightness = config.video_brightness;
|
|
433
|
+
options.contrast = config.video_contrast;
|
|
434
|
+
options.vignette = config.video_vignette;
|
|
435
|
+
options.bloom = config.video_bloom;
|
|
436
|
+
options.ntsc = config.video_ntsc;
|
|
437
|
+
options.curvature = config.video_curvature;
|
|
438
|
+
options.chromaticAberration = config.video_chromatic_aberration;
|
|
439
|
+
options.hasUserEffects = true;
|
|
440
|
+
} else {
|
|
441
|
+
// 'off' mode - reset to defaults
|
|
442
|
+
options.gamma = 1.0;
|
|
443
|
+
options.scanlines = 0;
|
|
444
|
+
options.saturation = 1.0;
|
|
445
|
+
options.brightness = 1.0;
|
|
446
|
+
options.contrast = 1.0;
|
|
447
|
+
options.vignette = 0;
|
|
448
|
+
options.bloom = 0;
|
|
449
|
+
options.ntsc = 0;
|
|
450
|
+
options.curvature = 0;
|
|
451
|
+
options.chromaticAberration = 0;
|
|
452
|
+
options.hasUserEffects = false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Update browser scan depth
|
|
456
|
+
options.scanDepth = config.browser_scan_depth;
|
|
457
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { RenderMode } from '../../Emulator';
|
|
2
|
+
import type { Config } from '../../frontend/config';
|
|
3
|
+
|
|
4
|
+
export interface CliOptions {
|
|
5
|
+
romPath?: string;
|
|
6
|
+
width: number | undefined;
|
|
7
|
+
height: number | undefined;
|
|
8
|
+
colorEnabled: boolean;
|
|
9
|
+
renderMode: RenderMode | undefined; // undefined = Auto (system-specific default)
|
|
10
|
+
scale: number | undefined;
|
|
11
|
+
help: boolean;
|
|
12
|
+
showVersion: boolean;
|
|
13
|
+
listGamepads: boolean;
|
|
14
|
+
listCoresFlag: boolean;
|
|
15
|
+
installCore: string | undefined;
|
|
16
|
+
removeCore: string | undefined;
|
|
17
|
+
core: string | undefined;
|
|
18
|
+
enableGamepad: boolean;
|
|
19
|
+
enableAudio: boolean;
|
|
20
|
+
startMuted: boolean;
|
|
21
|
+
enableSaveState: boolean;
|
|
22
|
+
enableBatterySave: boolean;
|
|
23
|
+
showStatusBar: boolean;
|
|
24
|
+
enableDiffRendering: boolean;
|
|
25
|
+
noRender: boolean;
|
|
26
|
+
debugGamepad: boolean;
|
|
27
|
+
fpsLimit: number | undefined;
|
|
28
|
+
loadRetroArch: boolean;
|
|
29
|
+
pngCompressionLevel: number;
|
|
30
|
+
gamma: number;
|
|
31
|
+
scanlines: number;
|
|
32
|
+
saturation: number;
|
|
33
|
+
brightness: number;
|
|
34
|
+
contrast: number;
|
|
35
|
+
vignette: number;
|
|
36
|
+
bloom: number;
|
|
37
|
+
bloomThreshold: number;
|
|
38
|
+
ntsc: number;
|
|
39
|
+
curvature: number;
|
|
40
|
+
chromaticAberration: number;
|
|
41
|
+
hasUserEffects: boolean; // Whether user explicitly specified any post-processing effects
|
|
42
|
+
configPath: string | undefined;
|
|
43
|
+
config: Config;
|
|
44
|
+
scanDepth: number; // Max depth for ROM scanning
|
|
45
|
+
// Playlist generation options
|
|
46
|
+
generatePlaylist: string | boolean; // Path to scan, or true for cwd, or false for disabled
|
|
47
|
+
playlistOutput: string;
|
|
48
|
+
singlePlaylist: string | undefined; // Single playlist name, or undefined for per-system
|
|
49
|
+
windowsPaths: boolean;
|
|
50
|
+
// Netplay options
|
|
51
|
+
netplayHost: boolean; // Host a netplay session
|
|
52
|
+
netplayConnect: string | undefined; // Connect to server (hostname or hostname:port)
|
|
53
|
+
netplayPort: number; // Netplay port (default: 55435)
|
|
54
|
+
netplayPassword: string | undefined; // Netplay password
|
|
55
|
+
netplaySpectate: boolean; // Join as spectator
|
|
56
|
+
netplayNickname: string; // Player nickname
|
|
57
|
+
netplayInputDelay: number; // Input delay frames (0-16)
|
|
58
|
+
clearLogs: boolean; // Delete all log files and exit
|
|
59
|
+
verbose: boolean; // Enable verbose logging to stderr
|
|
60
|
+
frameLimit: number; // Limit rendering to N fps (0=off)
|
|
61
|
+
}
|