mirror of
https://github.com/aydencharles/onionHEN.git
synced 2026-10-23 04:12:37 -05:00
428 lines
14 KiB
C++
428 lines
14 KiB
C++
/* Copyright (C) 2025 OnionHEN / LightningMods
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 3, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#pragma once
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Single product config schema for daemon / util / shellui.
|
|
//
|
|
// Paths:
|
|
// primary /data/OnionHEN/config.ini (elevated daemons)
|
|
// shellui /user/data/OnionHEN/config.ini (SceShellUI sandbox view)
|
|
// Load tries both; save writes all writable targets so the files stay twins.
|
|
//
|
|
// Process-local store: use SettingsStore for multi-threaded daemons (snapshot
|
|
// under mutex). Multi-process copies of Settings are expected and OK.
|
|
//
|
|
// Force C++ linkage even when a parent includes us under extern "C"
|
|
// (e.g. util common_utils.h inside extern "C" blocks).
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#ifdef __cplusplus
|
|
extern "C++" {
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <ctime>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
namespace onion {
|
|
|
|
// Canonical filesystem paths.
|
|
inline constexpr const char *kConfigPathPrimary = "/data/OnionHEN/config.ini";
|
|
inline constexpr const char *kConfigPathShellui = "/user/data/OnionHEN/config.ini";
|
|
|
|
// Semantic config schema. This schema starts at version 1.
|
|
inline constexpr int kSettingsSchemaVersion = 1;
|
|
inline constexpr int kUiLanguageSystem = 0;
|
|
inline constexpr int kUiLanguageZhHans = 1;
|
|
inline constexpr int kUiLanguageEn = 2;
|
|
inline constexpr int kUiLanguageAr = 3;
|
|
inline constexpr int kUiLanguageZhHant = 4;
|
|
inline constexpr int kUiLanguageJa = 5;
|
|
inline constexpr int kUiLanguageFr = 6;
|
|
inline constexpr int kUiLanguageDe = 7;
|
|
inline constexpr int kUiLanguageKo = 8;
|
|
inline constexpr int kUiLanguageEs = 9;
|
|
inline constexpr int kUiLanguagePtBr = 10;
|
|
inline constexpr int kUiLanguageIt = 11;
|
|
inline constexpr int kUiLanguageRu = 12;
|
|
inline constexpr int kUiLanguagePl = 13;
|
|
inline constexpr int kUiLanguageTh = 14;
|
|
inline constexpr int kUiLanguageNl = 15;
|
|
inline constexpr int kUiLanguageFi = 16;
|
|
inline constexpr int kUiLanguageSv = 17;
|
|
inline constexpr int kUiLanguageDa = 18;
|
|
inline constexpr int kUiLanguageNo = 19;
|
|
inline constexpr int kUiLanguageTr = 20;
|
|
inline constexpr int kUiLanguageCs = 21;
|
|
inline constexpr int kUiLanguageHu = 22;
|
|
inline constexpr int kUiLanguageEl = 23;
|
|
inline constexpr int kUiLanguageRo = 24;
|
|
inline constexpr int kUiLanguageVi = 25;
|
|
inline constexpr int kUiLanguageId = 26;
|
|
inline constexpr int kUiLanguageUk = 27;
|
|
inline constexpr int kUiLanguagePtPt = 28;
|
|
inline constexpr int kUiLanguageMax = kUiLanguagePtPt;
|
|
|
|
inline constexpr int kStartupOpenNone = 0;
|
|
inline constexpr int kStartupOpenHomeMenu = 1;
|
|
|
|
// Mirrors onion_log_level from <onion/log.h>. Duplicated rather than included
|
|
// so libonion_settings stays independent of libonion_platform; the processes
|
|
// that bridge the two (see onion_apply_log_settings) static_assert that the
|
|
// values still line up.
|
|
inline constexpr int kCheatsMirrorAuto = 0;
|
|
inline constexpr int kCheatsMirrorGithub = 1;
|
|
inline constexpr int kCheatsMirrorCnb = 2;
|
|
|
|
inline constexpr int kLogLevelOff = 0;
|
|
inline constexpr int kLogLevelError = 1;
|
|
inline constexpr int kLogLevelWarn = 2;
|
|
inline constexpr int kLogLevelInfo = 3;
|
|
inline constexpr int kLogLevelDebug = 4;
|
|
inline constexpr int kLogLevelTrace = 5;
|
|
|
|
/*
|
|
* Default runtime verbosity. Mirrors ONION_LOG_DEFAULT_LEVEL: a debug build
|
|
* defaults to the noisiest level it compiles in, so a payload built for log
|
|
* collection is verbose without anyone editing config.ini first — the reporter
|
|
* is usually not the person who built it. Release stays at info so a normal
|
|
* payload is not chatty.
|
|
*
|
|
* The two are kept in step by a static_assert in log_settings.hpp; an explicit
|
|
* `level=` in config.ini still wins over this.
|
|
*/
|
|
#ifdef NDEBUG
|
|
inline constexpr int kLogLevelDefault = kLogLevelInfo;
|
|
#else
|
|
inline constexpr int kLogLevelDefault = kLogLevelTrace;
|
|
#endif
|
|
|
|
/*
|
|
* Rotation threshold for the file sink, in bytes, per file. The logger keeps
|
|
* the live file plus three backups, so the retained history is 4x this value —
|
|
* that budget, not the per-file size, is what a user is really choosing.
|
|
*
|
|
* Mirrors ONION_LOG_DEFAULT_MAX_BYTES; log_settings.hpp static_asserts that the
|
|
* default still lines up with it.
|
|
*/
|
|
inline constexpr int kLogMaxBytesMin = 64 * 1024; /* 256 KiB total */
|
|
inline constexpr int kLogMaxBytesMax = 64 * 1024 * 1024; /* 256 MiB total */
|
|
inline constexpr int kLogMaxBytesDefault = 768 * 1024; /* 3 MiB total */
|
|
|
|
/** Clamp a requested per-file threshold. 0 or negative means "use default". */
|
|
inline int clamp_log_max_bytes(long long bytes) {
|
|
if (bytes <= 0)
|
|
return kLogMaxBytesDefault;
|
|
if (bytes < kLogMaxBytesMin)
|
|
return kLogMaxBytesMin;
|
|
if (bytes > kLogMaxBytesMax)
|
|
return kLogMaxBytesMax;
|
|
return static_cast<int>(bytes);
|
|
}
|
|
|
|
inline constexpr int kOverlayAlignLeft = 0;
|
|
inline constexpr int kOverlayAlignCenter = 1;
|
|
inline constexpr int kOverlayAlignRight = 2;
|
|
|
|
inline constexpr int kOverlayMetricCount = 6;
|
|
inline constexpr int kOverlayMetricFps = 0;
|
|
inline constexpr int kOverlayMetricCpu = 1;
|
|
inline constexpr int kOverlayMetricGpu = 2;
|
|
inline constexpr int kOverlayMetricMemory = 3;
|
|
inline constexpr int kOverlayMetricIp = 4;
|
|
inline constexpr int kOverlayMetricFan = 5;
|
|
|
|
inline constexpr int kOverlayFontSmall = 0;
|
|
inline constexpr int kOverlayFontMedium = 1;
|
|
inline constexpr int kOverlayFontLarge = 2;
|
|
|
|
inline constexpr int kOverlayFontPtSmall = 14;
|
|
inline constexpr int kOverlayFontPtMedium = 18;
|
|
inline constexpr int kOverlayFontPtLarge = 24;
|
|
|
|
inline constexpr std::array<int, kOverlayMetricCount> kOverlayOrderDefault = {
|
|
kOverlayMetricFps, kOverlayMetricCpu, kOverlayMetricGpu,
|
|
kOverlayMetricMemory, kOverlayMetricIp, kOverlayMetricFan};
|
|
|
|
inline int overlay_font_pt(int font_size) {
|
|
if (font_size == kOverlayFontSmall)
|
|
return kOverlayFontPtSmall;
|
|
if (font_size == kOverlayFontLarge)
|
|
return kOverlayFontPtLarge;
|
|
return kOverlayFontPtMedium;
|
|
}
|
|
|
|
inline const char *overlay_font_size_name(int font_size) {
|
|
if (font_size == kOverlayFontSmall)
|
|
return "small";
|
|
if (font_size == kOverlayFontLarge)
|
|
return "large";
|
|
return "medium";
|
|
}
|
|
|
|
inline const char *overlay_metric_name(int metric) {
|
|
switch (metric) {
|
|
case kOverlayMetricCpu:
|
|
return "cpu";
|
|
case kOverlayMetricGpu:
|
|
return "gpu";
|
|
case kOverlayMetricMemory:
|
|
return "memory";
|
|
case kOverlayMetricIp:
|
|
return "ip";
|
|
case kOverlayMetricFan:
|
|
return "fan";
|
|
case kOverlayMetricFps:
|
|
default:
|
|
return "fps";
|
|
}
|
|
}
|
|
|
|
inline void
|
|
overlay_normalize_order(std::array<int, kOverlayMetricCount> &order) {
|
|
bool seen[kOverlayMetricCount] = {};
|
|
std::array<int, kOverlayMetricCount> out{};
|
|
int n = 0;
|
|
for (int metric : order) {
|
|
if (metric < 0 || metric >= kOverlayMetricCount || seen[metric])
|
|
continue;
|
|
seen[metric] = true;
|
|
out[n++] = metric;
|
|
}
|
|
for (int metric = 0; metric < kOverlayMetricCount; ++metric) {
|
|
if (seen[metric])
|
|
continue;
|
|
out[n++] = metric;
|
|
}
|
|
order = out;
|
|
}
|
|
|
|
inline int overlay_metric_position(
|
|
const std::array<int, kOverlayMetricCount> &order, int metric) {
|
|
for (int i = 0; i < kOverlayMetricCount; ++i) {
|
|
if (order[i] == metric)
|
|
return i + 1;
|
|
}
|
|
return metric + 1;
|
|
}
|
|
|
|
inline void overlay_move_metric(std::array<int, kOverlayMetricCount> &order,
|
|
int metric, int position_1based) {
|
|
overlay_normalize_order(order);
|
|
if (metric < 0 || metric >= kOverlayMetricCount)
|
|
return;
|
|
int from = 0;
|
|
while (from < kOverlayMetricCount && order[from] != metric)
|
|
++from;
|
|
int to = position_1based - 1;
|
|
if (to < 0)
|
|
to = 0;
|
|
if (to >= kOverlayMetricCount)
|
|
to = kOverlayMetricCount - 1;
|
|
if (from >= kOverlayMetricCount || from == to)
|
|
return;
|
|
const int id = order[from];
|
|
if (from < to) {
|
|
for (int i = from; i < to; ++i)
|
|
order[i] = order[i + 1];
|
|
} else {
|
|
for (int i = from; i > to; --i)
|
|
order[i] = order[i - 1];
|
|
}
|
|
order[to] = id;
|
|
}
|
|
|
|
inline constexpr int kFanThresholdMinCelsius = 0;
|
|
inline constexpr int kFanThresholdMaxCelsius = 100;
|
|
inline constexpr int kFanAutomaticThresholdCelsius = 77;
|
|
inline constexpr int kRestModeDelayMinSeconds = 0;
|
|
inline constexpr int kRestModeDelayMaxSeconds = 255;
|
|
inline constexpr int kRestModeDelayDefaultSeconds = 10;
|
|
inline constexpr int clamp_fan_threshold(int celsius) {
|
|
if (celsius < kFanThresholdMinCelsius)
|
|
return kFanThresholdMinCelsius;
|
|
if (celsius > kFanThresholdMaxCelsius)
|
|
return kFanThresholdMaxCelsius;
|
|
return celsius;
|
|
}
|
|
|
|
inline constexpr std::size_t kMaxAppJailbreakExactTitleIds = 20;
|
|
inline constexpr std::size_t kMaxAppJailbreakTitleIdPrefixes = 20;
|
|
|
|
struct AppJailbreakAllowlist {
|
|
std::array<std::string, kMaxAppJailbreakExactTitleIds> exact_title_ids = {
|
|
"ITEM00001", "NPXS39041", "PKGI13337", "PKGI12345", "TOOL00001"};
|
|
std::size_t exact_title_id_count = 5;
|
|
|
|
std::array<std::string, kMaxAppJailbreakTitleIdPrefixes>
|
|
title_id_prefixes = {"LAPY"};
|
|
std::size_t title_id_prefix_count = 1;
|
|
};
|
|
|
|
struct Settings {
|
|
// [startup]
|
|
// Page to open after OnionHEN finishes loading.
|
|
int startup_open_after_load = kStartupOpenNone;
|
|
// Show the contributor thanks toast when OnionHEN starts.
|
|
bool show_boot_thanks = true;
|
|
|
|
// [rest_mode]
|
|
// Extra seconds after Rest Mode trophy SPRX are ready, before Toolbox inject.
|
|
uint64_t rest_mode_delay_seconds = kRestModeDelayDefaultSeconds;
|
|
|
|
// [cheats], [app_jailbreak]
|
|
int cheats_mirror = kCheatsMirrorAuto;
|
|
bool app_jailbreak_enabled = true;
|
|
bool debug_app_jb_msg = false;
|
|
AppJailbreakAllowlist app_jailbreak_allowlist{};
|
|
|
|
// [home_screen], [game_menu]
|
|
bool display_tids = false;
|
|
bool onionhen_game_opts = true;
|
|
|
|
// [cooling]
|
|
bool enable_fan_speed = false;
|
|
int fan_threshold = kFanAutomaticThresholdCelsius;
|
|
|
|
// [overlay]
|
|
/** Master visibility switch for the complete ShellUI game monitor bar. */
|
|
bool overlay_enabled = true;
|
|
/** Show the translucent background panel behind the game monitor bar. */
|
|
bool overlay_background = true;
|
|
bool overlay_ram = true;
|
|
bool overlay_cpu = true;
|
|
bool overlay_gpu = true;
|
|
bool overlay_fps = true;
|
|
bool overlay_ip = false;
|
|
/** Show current fan duty (percent) on the overlay bar. */
|
|
bool overlay_fan = false;
|
|
/** Per-core CPU usage mode on the overlay (id_all_cpu_usage). */
|
|
bool all_cpu_usage = false;
|
|
int overlay_pos = 0; // 0/1 top edge, 2/3 bottom edge
|
|
/** 0 left, 1 center, 2 right. Independent of overlay.edge. */
|
|
int overlay_align = kOverlayAlignCenter;
|
|
/** 0 small, 1 medium, 2 large. Applies to the whole monitor bar. */
|
|
int overlay_font_size = kOverlayFontMedium;
|
|
/** Display order of the six metrics; values are kOverlayMetric*. */
|
|
std::array<int, kOverlayMetricCount> overlay_order = kOverlayOrderDefault;
|
|
|
|
// [shortcuts]
|
|
int cheats_shortcut_opt = 0;
|
|
int toolbox_shortcut_opt = 0;
|
|
|
|
// [kstuff]
|
|
// Load the embedded/override kstuff payload when OnionHEN starts.
|
|
bool kstuff_autoload = true;
|
|
|
|
// [toolbox]
|
|
// 0 = system (default), 1 = zh-Hans, 2 = en, 3 = ar, 4 = zh-Hant,
|
|
// 5 = ja, 6 = fr, 7 = de, 8 = ko, 9 = es, 10 = pt-BR, 11 = it,
|
|
// 12 = ru, 13 = pl
|
|
int ui_lang = kUiLanguageSystem;
|
|
|
|
// [logging]
|
|
// Runtime log threshold, matching onion_log_level (1=error .. 5=trace).
|
|
// Lets a user raise verbosity for a bug report without a debug payload;
|
|
// levels stripped at compile time cannot be re-enabled this way.
|
|
// Defaults to trace in debug builds and info in release — see
|
|
// kLogLevelDefault.
|
|
int log_level = kLogLevelDefault;
|
|
// Per-file rotation threshold in bytes. Raising it is what keeps a TRACE run
|
|
// from evicting its own startup records. Clamped by clamp_log_max_bytes().
|
|
int log_max_bytes = kLogMaxBytesDefault;
|
|
|
|
// Meta
|
|
int schema_version = kSettingsSchemaVersion;
|
|
};
|
|
|
|
// Thread-safe process-local settings (daemon / util IPC + worker threads).
|
|
// ShellUI may keep a plain Settings if UI work is single-threaded; prefer this
|
|
// store when readers and writers can race.
|
|
class SettingsStore {
|
|
public:
|
|
SettingsStore() = default;
|
|
explicit SettingsStore(const Settings &s) : s_(s) {}
|
|
|
|
Settings snapshot() const {
|
|
std::lock_guard<std::mutex> lock(mu_);
|
|
return s_;
|
|
}
|
|
|
|
void store(const Settings &s) {
|
|
std::lock_guard<std::mutex> lock(mu_);
|
|
s_ = s;
|
|
}
|
|
|
|
/** Mutate under lock; returns a copy of the new value. */
|
|
template <typename Fn>
|
|
Settings update(Fn &&fn) {
|
|
std::lock_guard<std::mutex> lock(mu_);
|
|
fn(s_);
|
|
return s_;
|
|
}
|
|
|
|
private:
|
|
mutable std::mutex mu_;
|
|
Settings s_{};
|
|
};
|
|
|
|
// Fill `out` with defaults then overlay values from the first readable config path.
|
|
// Returns true if a file was loaded; false means defaults only (file missing).
|
|
bool settings_load(Settings *out);
|
|
|
|
// Load/save a single explicit path (host tests and tooling).
|
|
bool settings_load_file(const char *path, Settings *out);
|
|
bool settings_save_file(const char *path, const Settings &in);
|
|
|
|
// Canonical toolbox.language token for a stored ui_lang value.
|
|
const char *language_name(int ui_lang);
|
|
|
|
// Serialize full schema to annotated INI text (no I/O).
|
|
std::string settings_serialize(const Settings &in);
|
|
|
|
// Serialize full schema. Writes every path that can be opened for write.
|
|
// Returns true if at least one write succeeded.
|
|
bool settings_save(const Settings &in);
|
|
|
|
// Create default full-schema INI if no config exists on any path.
|
|
// Returns true if a file was created (or already existed after load attempt).
|
|
bool settings_ensure_default();
|
|
|
|
// Path that was last successfully loaded (empty if defaults only).
|
|
const char *settings_last_loaded_path();
|
|
|
|
/**
|
|
* Max st_mtime across both twin config paths (0 if neither exists).
|
|
* Use for daemon reload gating so either path's write invalidates the cache.
|
|
*/
|
|
time_t settings_config_newest_mtime();
|
|
|
|
/**
|
|
* True if any twin path has mtime strictly greater than `since`.
|
|
* When no config file exists, returns false (nothing newer on disk).
|
|
*/
|
|
bool settings_config_is_newer_than(time_t since);
|
|
|
|
} // namespace onion
|
|
|
|
} // extern "C++"
|
|
#endif /* __cplusplus */
|