mirror of
https://github.com/rommapp/romm.git
synced 2026-02-18 00:27:41 +01:00
add debug and controls
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
import sys
|
||||
from typing import Final
|
||||
from typing import Final, NotRequired, TypedDict
|
||||
|
||||
import pydash
|
||||
import yaml
|
||||
@@ -30,6 +30,11 @@ ROMM_USER_CONFIG_FILE: Final = f"{ROMM_USER_CONFIG_PATH}/config.yml"
|
||||
SQLITE_DB_BASE_PATH: Final = f"{ROMM_BASE_PATH}/database"
|
||||
|
||||
|
||||
class EjsControlsButton(TypedDict):
|
||||
value: NotRequired[str]
|
||||
value2: NotRequired[str]
|
||||
|
||||
|
||||
class Config:
|
||||
EXCLUDED_PLATFORMS: list[str]
|
||||
EXCLUDED_SINGLE_EXT: list[str]
|
||||
@@ -41,7 +46,13 @@ class Config:
|
||||
PLATFORMS_VERSIONS: dict[str, str]
|
||||
ROMS_FOLDER_NAME: str
|
||||
FIRMWARE_FOLDER_NAME: str
|
||||
EJS_CORE_OPTIONS: dict[str, dict[str, str]]
|
||||
EJS_DEBUG: bool
|
||||
EJS_OPTIONS: dict[
|
||||
str, dict[str, str]
|
||||
] # dict[core_name, dict[option_name, option_value]]
|
||||
EJS_CONTROLS: dict[
|
||||
str, dict[int, dict[int, EjsControlsButton]]
|
||||
] # dict[core_name, dict[player_number, dict[button_number, EjsControlsButton]]]
|
||||
HIGH_PRIO_STRUCTURE_PATH: str
|
||||
|
||||
def __init__(self, **entries):
|
||||
@@ -150,7 +161,9 @@ class ConfigManager:
|
||||
FIRMWARE_FOLDER_NAME=pydash.get(
|
||||
self._raw_config, "filesystem.firmware_folder", "bios"
|
||||
),
|
||||
EJS_CORE_OPTIONS=pydash.get(self._raw_config, "emulatorjs", {}),
|
||||
EJS_DEBUG=pydash.get(self._raw_config, "emulatorjs.debug", False),
|
||||
EJS_OPTIONS=pydash.get(self._raw_config, "emulatorjs.options", {}),
|
||||
EJS_CONTROLS=pydash.get(self._raw_config, "emulatorjs.controls", {}),
|
||||
)
|
||||
|
||||
def _validate_config(self):
|
||||
@@ -233,17 +246,46 @@ class ConfigManager:
|
||||
)
|
||||
sys.exit(3)
|
||||
|
||||
if not isinstance(self.config.EJS_CORE_OPTIONS, dict):
|
||||
if not isinstance(self.config.EJS_DEBUG, bool):
|
||||
log.critical("Invalid config.yml: emulatorjs.debug must be a boolean")
|
||||
sys.exit(3)
|
||||
|
||||
if not isinstance(self.config.EJS_OPTIONS, dict):
|
||||
log.critical("Invalid config.yml: emulatorjs must be a dictionary")
|
||||
sys.exit(3)
|
||||
else:
|
||||
for core, options in self.config.EJS_CORE_OPTIONS.items():
|
||||
for core, options in self.config.EJS_OPTIONS.items():
|
||||
if not isinstance(options, dict):
|
||||
log.critical(
|
||||
f"Invalid config.yml: emulatorjs.{core} must be a dictionary"
|
||||
)
|
||||
sys.exit(3)
|
||||
|
||||
if not isinstance(self.config.EJS_CONTROLS, dict):
|
||||
log.critical("Invalid config.yml: emulatorjs.controls must be a dictionary")
|
||||
sys.exit(3)
|
||||
else:
|
||||
for core, controls in self.config.EJS_CONTROLS.items():
|
||||
if not isinstance(controls, dict):
|
||||
log.critical(
|
||||
f"Invalid config.yml: emulatorjs.controls.{core} must be a dictionary"
|
||||
)
|
||||
sys.exit(3)
|
||||
|
||||
for player, buttons in controls.items():
|
||||
if not isinstance(buttons, dict):
|
||||
log.critical(
|
||||
f"Invalid config.yml: emulatorjs.controls.{core}.{player} must be a dictionary"
|
||||
)
|
||||
sys.exit(3)
|
||||
|
||||
for button, value in buttons.items():
|
||||
if not isinstance(value, dict):
|
||||
log.critical(
|
||||
f"Invalid config.yml: emulatorjs.controls.{core}.{player}.{button} must be a dictionary"
|
||||
)
|
||||
sys.exit(3)
|
||||
|
||||
def get_config(self) -> Config:
|
||||
with open(self.config_file) as config_file:
|
||||
self._raw_config = yaml.load(config_file, Loader=SafeLoader) or {}
|
||||
|
||||
@@ -35,7 +35,9 @@ def get_config() -> ConfigResponse:
|
||||
EXCLUDED_MULTI_PARTS_FILES=cfg.EXCLUDED_MULTI_PARTS_FILES,
|
||||
PLATFORMS_BINDING=cfg.PLATFORMS_BINDING,
|
||||
PLATFORMS_VERSIONS=cfg.PLATFORMS_VERSIONS,
|
||||
EJS_CORE_OPTIONS=cfg.EJS_CORE_OPTIONS,
|
||||
EJS_DEBUG=cfg.EJS_DEBUG,
|
||||
EJS_CONTROLS=cfg.EJS_CONTROLS,
|
||||
EJS_OPTIONS=cfg.EJS_OPTIONS,
|
||||
)
|
||||
except ConfigNotReadableException as exc:
|
||||
log.critical(exc.message)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from typing import TypedDict
|
||||
|
||||
from config.config_manager import EjsControlsButton
|
||||
|
||||
|
||||
class ConfigResponse(TypedDict):
|
||||
EXCLUDED_PLATFORMS: list[str]
|
||||
@@ -10,4 +12,6 @@ class ConfigResponse(TypedDict):
|
||||
EXCLUDED_MULTI_PARTS_FILES: list[str]
|
||||
PLATFORMS_BINDING: dict[str, str]
|
||||
PLATFORMS_VERSIONS: dict[str, str]
|
||||
EJS_CORE_OPTIONS: dict[str, dict[str, str]]
|
||||
EJS_DEBUG: bool
|
||||
EJS_OPTIONS: dict[str, dict[str, str]]
|
||||
EJS_CONTROLS: dict[str, dict[int, dict[int, EjsControlsButton]]]
|
||||
|
||||
@@ -31,7 +31,15 @@ filesystem:
|
||||
firmware_folder: "BIOS"
|
||||
|
||||
emulatorjs:
|
||||
parallel_n64:
|
||||
vsync: disable
|
||||
snes9x:
|
||||
snes9x_region: ntsc
|
||||
debug: true
|
||||
options:
|
||||
parallel_n64:
|
||||
vsync: disable
|
||||
snes9x:
|
||||
snes9x_region: ntsc
|
||||
controls:
|
||||
snes9x:
|
||||
0:
|
||||
0:
|
||||
value: x
|
||||
value2: BUTTON_2
|
||||
|
||||
@@ -19,10 +19,16 @@ def test_config_loader():
|
||||
assert loader.config.PLATFORMS_VERSIONS == {"naomi": "arcade"}
|
||||
assert loader.config.ROMS_FOLDER_NAME == "ROMS"
|
||||
assert loader.config.FIRMWARE_FOLDER_NAME == "BIOS"
|
||||
assert loader.config.EJS_CORE_OPTIONS == {
|
||||
assert loader.config.EJS_DEBUG
|
||||
assert loader.config.EJS_OPTIONS == {
|
||||
"parallel_n64": {"vsync": "disable"},
|
||||
"snes9x": {"snes9x_region": "ntsc"},
|
||||
}
|
||||
assert loader.config.EJS_CONTROLS == {
|
||||
"snes9x": {
|
||||
0: {0: {"value": "x", "value2": "BUTTON_2"}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_empty_config_loader():
|
||||
@@ -42,4 +48,6 @@ def test_empty_config_loader():
|
||||
assert loader.config.PLATFORMS_VERSIONS == {}
|
||||
assert loader.config.ROMS_FOLDER_NAME == "roms"
|
||||
assert loader.config.FIRMWARE_FOLDER_NAME == "bios"
|
||||
assert loader.config.EJS_CORE_OPTIONS == {}
|
||||
assert not loader.config.EJS_DEBUG
|
||||
assert loader.config.EJS_OPTIONS == {}
|
||||
assert loader.config.EJS_CONTROLS == {}
|
||||
|
||||
@@ -49,9 +49,20 @@ filesystem: {} # { roms_folder: 'roms' } For example if your folder structure is
|
||||
|
||||
# EmulatorJS per-core options
|
||||
emulatorjs:
|
||||
parallel_n64: # Use the exact core name
|
||||
vsync: disable
|
||||
snes9x:
|
||||
snes9x_region: ntsc
|
||||
default: # These settings apply to all cores
|
||||
fps: show
|
||||
debug: true # Available options will be logged to the browser consolewhen the emulator is started
|
||||
options:
|
||||
parallel_n64: # Use the exact core name
|
||||
vsync: disable
|
||||
snes9x:
|
||||
snes9x_region: ntsc
|
||||
default: # These settings apply to all cores
|
||||
fps: show
|
||||
controls: # https://emulatorjs.org/docs4devs/control-mapping/
|
||||
snes9x:
|
||||
0: # Player 1
|
||||
0:
|
||||
value: x # Default mapping for keyboard
|
||||
value2: BUTTON_2 # Default mapping for connected controller
|
||||
1: # Player 2
|
||||
2: # Player 3
|
||||
3: # Player 4
|
||||
|
||||
1
frontend/src/__generated__/index.ts
generated
1
frontend/src/__generated__/index.ts
generated
@@ -24,6 +24,7 @@ export type { ConfigResponse } from './models/ConfigResponse';
|
||||
export type { CustomLimitOffsetPage_SimpleRomSchema_ } from './models/CustomLimitOffsetPage_SimpleRomSchema_';
|
||||
export type { DetailedRomSchema } from './models/DetailedRomSchema';
|
||||
export type { EarnedAchievement } from './models/EarnedAchievement';
|
||||
export type { EjsControlsButton } from './models/EjsControlsButton';
|
||||
export type { EmulationDict } from './models/EmulationDict';
|
||||
export type { FilesystemDict } from './models/FilesystemDict';
|
||||
export type { FirmwareSchema } from './models/FirmwareSchema';
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { EjsControlsButton } from './EjsControlsButton';
|
||||
export type ConfigResponse = {
|
||||
EXCLUDED_PLATFORMS: Array<string>;
|
||||
EXCLUDED_SINGLE_EXT: Array<string>;
|
||||
@@ -11,6 +12,8 @@ export type ConfigResponse = {
|
||||
EXCLUDED_MULTI_PARTS_FILES: Array<string>;
|
||||
PLATFORMS_BINDING: Record<string, string>;
|
||||
PLATFORMS_VERSIONS: Record<string, string>;
|
||||
EJS_CORE_OPTIONS: Record<string, Record<string, string>>;
|
||||
EJS_DEBUG: boolean;
|
||||
EJS_OPTIONS: Record<string, Record<string, string>>;
|
||||
EJS_CONTROLS: Record<string, Record<string, Record<string, EjsControlsButton>>>;
|
||||
};
|
||||
|
||||
|
||||
9
frontend/src/__generated__/models/EjsControlsButton.ts
generated
Normal file
9
frontend/src/__generated__/models/EjsControlsButton.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
/* generated using openapi-typescript-codegen -- do not edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type EjsControlsButton = {
|
||||
value?: string;
|
||||
value2?: string;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
import type { ConfigResponse } from "@/__generated__";
|
||||
import type { ConfigResponse, EjsControlsButton } from "@/__generated__";
|
||||
import api from "@/services/api";
|
||||
|
||||
type ExclusionTypes =
|
||||
@@ -20,7 +20,9 @@ const defaultConfig = {
|
||||
EXCLUDED_MULTI_PARTS_FILES: [],
|
||||
PLATFORMS_BINDING: {},
|
||||
PLATFORMS_VERSIONS: {},
|
||||
EJS_CORE_OPTIONS: {},
|
||||
EJS_DEBUG: false,
|
||||
EJS_OPTIONS: {},
|
||||
EJS_CONTROLS: {},
|
||||
} as ConfigResponse;
|
||||
|
||||
export default defineStore("config", {
|
||||
@@ -68,11 +70,21 @@ export default defineStore("config", {
|
||||
return Object.keys(this.config).includes(type);
|
||||
},
|
||||
getEJSCoreOptions(core: string | null): Record<string, string | boolean> {
|
||||
const defaultOptions = this.config.EJS_CORE_OPTIONS["default"];
|
||||
const defaultOptions = this.config.EJS_OPTIONS["default"] || {};
|
||||
if (!core) return defaultOptions;
|
||||
return {
|
||||
...defaultOptions,
|
||||
...this.config.EJS_CORE_OPTIONS[core],
|
||||
...this.config.EJS_OPTIONS[core],
|
||||
};
|
||||
},
|
||||
getEJSControls(
|
||||
core: string | null,
|
||||
): Record<string, Record<string, EjsControlsButton>> {
|
||||
const defaultControls = this.config.EJS_CONTROLS["default"] || {};
|
||||
if (!core) return defaultControls;
|
||||
return {
|
||||
...defaultControls,
|
||||
...this.config.EJS_CONTROLS[core],
|
||||
};
|
||||
},
|
||||
reset() {},
|
||||
|
||||
@@ -56,7 +56,6 @@ declare global {
|
||||
EJS_player: string;
|
||||
EJS_pathtodata: string;
|
||||
EJS_color: string;
|
||||
EJS_defaultOptions: object;
|
||||
EJS_gameID: number;
|
||||
EJS_gameName: string;
|
||||
EJS_backgroundImage: string;
|
||||
@@ -72,6 +71,8 @@ declare global {
|
||||
EJS_fullscreenOnLoaded: boolean;
|
||||
EJS_threads: boolean;
|
||||
EJS_controlScheme: string | null;
|
||||
EJS_defaultOptions: object;
|
||||
EJS_defaultControls: object;
|
||||
EJS_emulator: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
EJS_language: string;
|
||||
EJS_disableAutoLang: boolean;
|
||||
@@ -124,13 +125,14 @@ window.EJS_defaultOptions = {
|
||||
rewindEnabled: "enabled",
|
||||
...coreOptions,
|
||||
};
|
||||
window.EJS_defaultControls = configStore.getEJSControls(props.core);
|
||||
// Set a valid game name
|
||||
window.EJS_gameName = romRef.value.fs_name_no_tags
|
||||
.replace(INVALID_CHARS_REGEX, "")
|
||||
.trim();
|
||||
window.EJS_language = selectedLanguage.value.value.replace("_", "-");
|
||||
window.EJS_disableAutoLang = true;
|
||||
window.EJS_DEBUG_XX = true;
|
||||
window.EJS_DEBUG_XX = configStore.config.EJS_DEBUG;
|
||||
|
||||
onMounted(() => {
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
Reference in New Issue
Block a user