#ifndef QUESTSHOCK_QS_CONFIG_H #define QUESTSHOCK_QS_CONFIG_H #include #ifdef __cplusplus extern "C" { #endif // Persistent, human-editable JSON config file - see CONFIG.md at the repo // root for the documented schema. Lives at a plain relative path // ("questshock.config.json") since the whole engine already runs with its // cwd chdir()'d to the user-facing /sdcard/questshock/ folder (see // QuestShockActivity.java's nativeChdir()) before main() ever runs - the // same way prefs.txt/keybinds.txt (Prefs.c) already do. // // Deliberately independent of prefs.txt: this file is never read or written // as a side effect of prefs.txt load/save, and vice versa. // Parses the config file if it exists (silent no-op if it doesn't - this // never creates the file itself) and applies every recognized option // directly into gShockPrefs/mode_id. Call once, early in main() - see // android/engine-patches/21-android-config.patch - after LoadPrefs() (so the // config file can override prefs.txt) and before init_all() (so there's no // live-vs-restart distinction to worry about: nothing is initialized yet, so // every field takes full effect as part of this same startup). void qs_config_load_startup(void); // Called from the "Save Configuration"/"Load Configuration" button JNI // handlers (questshock_native.c), which run on Android's UI thread. These // only enqueue a custom SDL event - the actual file I/O and any // gShockPrefs/mode_id/message_info() work happens on the engine's own SDL // main thread instead (see qs_config_handle_event() below), matching this // codebase's existing convention for crossing this exact thread boundary // (xr_session.c's xr_poll_events(), questshock_native.c's SDL_TEXTINPUT // push for keyboard input). void qs_config_request_save(void); void qs_config_request_load(void); // Same cross-thread-dispatch reasoning as qs_config_request_save()/_load() // above - called from the Video Options tab's controls (MenuOverlay.java), // which are just as much on Android's UI thread as the Save/Load buttons. // opengl=true/false selects "opengl"/"software"; resolution_index is 0-4, // indexing the same table qs_config_current_resolution_index() below // reads. Applies live immediately (no restart involved - see CONFIG.md); // unlike Load Configuration, these don't post a message_info() HUD // notification for every single tap - the tab's own selection highlight is // the feedback. void qs_config_request_set_renderer(bool opengl); void qs_config_request_set_resolution(int resolution_index); // Same cross-thread-dispatch reasoning as the two above - called from the // Main Menu tab's Language row (MenuOverlay.java). language_index is 0 // English/1 French/2 German (gShockPrefs.goLanguage's own numbering, // Prefs.h). Applies live immediately, the same way the game's own options // menu applies a language change (see qs_config.c's qs_apply_language()). void qs_config_request_set_language(int language_index); // Same cross-thread-dispatch reasoning as the three above - called from the // Main Menu tab's "Reset Position" button. A pure, live "return to a sane // view of the game quad" action (see xr_input.h's own // xr_input_recenter_player_to_screen(), which this dispatches to) - // unrelated to questshock.config.json despite living in this file for the // cross-thread dispatch machinery: it never reads or writes the config // file, and isn't a "reset to (0,0,0)" - it recenters based on the // player's current real head pose instead. void qs_config_request_reset_position(void); // Same cross-thread-dispatch reasoning as the four above - called from the // Video Options tab's "Initial Screen"/"Game Screen" width/distance // preset rows (MenuOverlay.java). preset_index indexes qs_config.c's own // shared, offset+step-generated width/distance preset lists (both in // meters; the offset/step themselves are config-file-only, not exposed // as buttons), read back via the four qs_config_current_*_screen_*_index() // getters below. Applies live immediately if the just-changed profile is // the currently active one (see CONFIG.md) - otherwise just updates the // stored preference, invisibly, until that profile becomes active (e.g. // tweaking "Initial Screen" mid-game). void qs_config_request_set_initial_screen_width(int preset_index); void qs_config_request_set_initial_screen_distance(int preset_index); void qs_config_request_set_game_screen_width(int preset_index); void qs_config_request_set_game_screen_distance(int preset_index); // Returns true and handles the event if it's one of the ten custom events // qs_config_request_save()/_load()/_set_renderer()/_set_resolution()/ // _set_language()/_reset_position()/the four _set_*_screen_*() setters // enqueue - called from pump_events() (sdl_events.c, see // android/engine-patches/21-android-config.patch) on the engine's own // thread, once per polled event, before its normal switch on well-known // SDL_* event types. Returns false (no-op) for any other event type, // including before the ten custom types have even been registered. bool qs_config_handle_event(const SDL_Event *event); // Called directly (no event-queue dispatch - see // android/engine-patches/22-android-screen-profile.patch and this // function's own definition in qs_config.c for why) from the engine's // mainloop.c whenever the loop mode changes, and once from // qs_config_load_startup() - picks between the "Initial Screen" (menu/ // intro) and "Game Screen" (actual gameplay) presets based on new_mode // (mainloop.h's SETUP_LOOP/CUTSCENE_LOOP vs. everything else) and applies // the newly-active one's shape to xr_session.c, but only if it's actually // different from what was already active. void qs_screen_profile_notify_loop_mode(short new_mode); // Read-only queries for the Video Options tab's own selection highlight // (MenuOverlay.java re-reads these whenever the tab is (re)shown, so it // reflects the live value even if it was last changed some other way, e.g. // the Ctrl+G hotkey or Load Configuration). Safe to call directly from // Android's UI thread despite not going through the event-queue dispatch // the mutating calls above use - same low-risk reasoning already used for // Save Configuration's own reads of gShockPrefs/mode_id: these are simple, // independent POD scalar reads, not a sequence that needs to be atomic // with anything else. bool qs_config_current_renderer_is_opengl(void); int qs_config_current_resolution_index(void); // -1 (not just an unlikely fallback, a routine, expected result here - // unlike qs_config_current_resolution_index() above) if the profile's // current value doesn't exactly match one of qs_config.c's own // offset+step-generated width/distance presets, e.g. after a hand-edited // config file sets an in-between value - MenuOverlay.java's own // setSelected() naturally shows no button selected in that case, no // special-casing needed. int qs_config_current_initial_screen_width_index(void); int qs_config_current_initial_screen_distance_index(void); int qs_config_current_game_screen_width_index(void); int qs_config_current_game_screen_distance_index(void); // Returns the value preset button `index` (0..4) currently shows for the // width/distance option - shared by both "Initial Screen" and "Game // Screen" columns (their offset/step is config-file-only, not per-profile // - see qs_config.c's own comment on the underlying statics), so // MenuOverlay.java can label its preset buttons correctly even after a // Load Configuration changes the offset/step. Index is clamped into // range, not validated - every index 0..4 always has a value. float qs_config_screen_width_preset_value(int index); float qs_config_screen_distance_preset_value(int index); // gShockPrefs.goLanguage (0 English/1 French/2 German, Prefs.h) - read by // MenuOverlay.java's/KeyboardOverlay.java's periodic header-refresh timer // to pick which language's chrome text (Strings.java) to display, so a // language change made mid-session via the game's own options menu (or our // own Language row, or Load Configuration) is picked up without needing to // reopen either panel; also doubles as the Main Menu tab's Language row's // own selection highlight, same as qs_config_current_renderer_is_opengl()/ // qs_config_current_resolution_index() above. Same off-thread-scalar-read // reasoning as those two getters. int qs_config_current_language(void); #ifdef __cplusplus } #endif #endif // QUESTSHOCK_QS_CONFIG_H