| --- Initializes global variables `g_FirstTimeUser` and `g_LocalStorageFile` based on the `FirstLoad` flag. | |
| -- If `FirstLoad` is true, `g_FirstTimeUser` is set to false and `g_LocalStorageFile` is set to either "AppData/LocalStorageGed.lua" or "AppData/LocalStorage.lua" depending on the `Platform.ged` flag. | |
| if FirstLoad then | |
| g_FirstTimeUser = false | |
| g_LocalStorageFile = "AppData/" .. (Platform.ged and "LocalStorageGed.lua" or "LocalStorage.lua") | |
| end | |
| -- All Set*Storage functions accept a table, or one of the strings "default" and "invalid" | |
| --- Initializes a storage table with default values. | |
| -- | |
| -- If `storage` is "invalid", it is set to `false`. | |
| -- If `storage` is "default", it is set to an empty table. | |
| -- Otherwise, `storage` is assumed to be a table and its values are set to the defaults in `default`. | |
| -- If `default` has a metatable and `storage` does not have the same class, `storage` is converted to an object of the same class as `default`. | |
| -- | |
| -- @param storage The storage table to initialize, or the string "default" or "invalid". | |
| -- @param default The default values to use for initializing the storage table. | |
| -- @return The initialized storage table. | |
| local function InitWithDefault(storage, default) | |
| assert(storage) | |
| if storage == "invalid" then | |
| storage = false | |
| else | |
| if storage == "default" then | |
| storage = {} | |
| end | |
| assert(type(storage) == "table") | |
| -- Convert the storage from dumb table to object (if needed) | |
| if getmetatable(default) and not ObjectClass(storage) and ObjectClass(default) then | |
| storage = g_Classes[default.class]:new(storage) | |
| end | |
| table.set_defaults(storage, default, "deep") | |
| end | |
| return storage | |
| end | |
| --- Returns a table with default values for option fixup metadata. | |
| -- | |
| -- The returned table has the following fields: | |
| -- - `AppliedOptionFixups`: A table of applied option fixups. | |
| -- - `last_applied_fixup_revision`: The revision of the last applied fixup. | |
| -- | |
| -- @return A table with default option fixup metadata. | |
| function GetDefaultOptionFixupMeta() | |
| return {AppliedOptionFixups={}, last_applied_fixup_revision=0} | |
| end | |
| --- Returns the default account options. | |
| -- | |
| -- @return The default account options. | |
| function GetDefaultAccountOptions() | |
| return DefaultAccountStorage.Options | |
| end | |
| --- Sets the platform-specific default engine options. | |
| -- | |
| -- This function overrides the default engine options with platform-specific defaults. | |
| -- The resulting options are stored in the `PlatformDefaultEngineOptions` global variable. | |
| -- | |
| -- The platform-specific defaults are defined in the `DefaultEngineOptions` table, with keys | |
| -- corresponding to the different platforms (e.g. "steamdeck", "desktop", "xbox_one", etc.). | |
| -- This function checks the current platform and selects the appropriate platform-specific | |
| -- defaults to overwrite the main default options. | |
| -- | |
| -- @function SetPlatformDefaultEngineOptions | |
| -- @return none | |
| function SetPlatformDefaultEngineOptions() | |
| -- Overwrite default options with platform-specific defaults | |
| local result_options = table.copy(DefaultEngineOptions["default_options"]) | |
| if Platform.steamdeck then | |
| table.overwrite(result_options, DefaultEngineOptions["steamdeck"]) | |
| elseif Platform.desktop then | |
| table.overwrite(result_options, DefaultEngineOptions["desktop"]) | |
| elseif Platform.xbox_one and not Platform.xbox_one_x then | |
| table.overwrite(result_options, DefaultEngineOptions["xbox_one"]) | |
| elseif Platform.xbox_one and Platform.xbox_one_x then | |
| table.overwrite(result_options, DefaultEngineOptions["xbox_one_x"]) | |
| elseif Platform.xbox_series and not Platform.xbox_series_x then | |
| table.overwrite(result_options, DefaultEngineOptions["xbox_series_s"]) | |
| elseif Platform.xbox_series and Platform.xbox_series_x then | |
| table.overwrite(result_options, DefaultEngineOptions["xbox_series_x"]) | |
| elseif Platform.ps4 and not Platform.ps4_pro then | |
| table.overwrite(result_options, DefaultEngineOptions["ps4"]) | |
| elseif Platform.ps4 and Platform.ps4_pro then | |
| table.overwrite(result_options, DefaultEngineOptions["ps4_pro"]) | |
| elseif Platform.ps5 then | |
| table.overwrite(result_options, DefaultEngineOptions["ps5"]) | |
| elseif Platform.switch then | |
| table.overwrite(result_options, DefaultEngineOptions["switch"]) | |
| end | |
| PlatformDefaultEngineOptions = result_options | |
| end | |
| --- Returns the default engine options for the current platform. | |
| -- | |
| -- If `platform_overwrites_only` is true, this function will return only the platform-specific | |
| -- overrides of the default engine options, instead of the full set of default options. | |
| -- | |
| -- The platform-specific overrides are defined in the `DefaultEngineOptions` table, with keys | |
| -- corresponding to the different platforms (e.g. "steamdeck", "desktop", "xbox_one", etc.). | |
| -- | |
| -- @param platform_overwrites_only boolean Whether to return only the platform-specific overrides. | |
| -- @return table The default engine options for the current platform. | |
| function GetDefaultEngineOptions(platform_overwrites_only) | |
| if platform_overwrites_only then | |
| if Platform.steamdeck then | |
| return DefaultEngineOptions["steamdeck"] | |
| elseif Platform.desktop then | |
| return DefaultEngineOptions["desktop"] | |
| elseif Platform.xbox_one and not Platform.xbox_one_x then | |
| return DefaultEngineOptions["xbox_one"] | |
| elseif Platform.xbox_one and Platform.xbox_one_x then | |
| return DefaultEngineOptions["xbox_one_x"] | |
| elseif Platform.xbox_series and not Platform.xbox_series_x then | |
| return DefaultEngineOptions["xbox_series_s"] | |
| elseif Platform.xbox_series and Platform.xbox_series_x then | |
| return DefaultEngineOptions["xbox_series_x"] | |
| elseif Platform.ps4 and not Platform.ps4_pro then | |
| return DefaultEngineOptions["ps4"] | |
| elseif Platform.ps4 and Platform.ps4_pro then | |
| return DefaultEngineOptions["ps4_pro"] | |
| elseif Platform.ps5 then | |
| return DefaultEngineOptions["ps5"] | |
| elseif Platform.switch then | |
| return DefaultEngineOptions["switch"] | |
| end | |
| end | |
| return PlatformDefaultEngineOptions | |
| end | |
| --- Returns a table containing the full set of engine options, including both the default options and any | |
| -- user-defined overrides stored in the `EngineOptions` table. | |
| -- | |
| -- This function creates a copy of the default engine options using `GetDefaultEngineOptions()`, and then | |
| -- merges any user-defined overrides from the `EngineOptions` table into the copy using `table.overwrite()`. | |
| -- | |
| -- @return table The full set of engine options, including both defaults and user overrides. | |
| function GetFullEngineOptions() | |
| local defaults = table.copy(GetDefaultEngineOptions()) | |
| return table.overwrite(defaults, EngineOptions) | |
| end | |
| --- Returns a table containing the full set of account options, including both the default options and any | |
| -- user-defined overrides stored in the `AccountStorage.Options` table. | |
| -- | |
| -- This function creates a copy of the default account options using `GetDefaultAccountOptions()`, and then | |
| -- merges any user-defined overrides from the `AccountStorage.Options` table into the copy using `table.overwrite()`. | |
| -- | |
| -- @return table The full set of account options, including both defaults and user overrides. | |
| function GetFullAccountOptions() | |
| local defaults = table.copy(GetDefaultAccountOptions()) | |
| return table.overwrite(defaults, AccountStorage.Options) | |
| end | |
| --- Sets the default engine options as the metatable for the `EngineOptions` table. | |
| -- | |
| -- This allows the `EngineOptions` table to use the default options as a fallback, so that only the | |
| -- options with a different value than the default need to be stored on disk. Any missing options | |
| -- in `EngineOptions` will automatically use the default value from `GetDefaultEngineOptions()`. | |
| -- | |
| -- This is used to efficiently store and load the engine options, as the full set of options does | |
| -- not need to be serialized. | |
| function SetDefaultEngineOptionsMetaTable() | |
| setmetatable(EngineOptions, {__index=GetDefaultEngineOptions()}) | |
| end | |
| --- Initializes the default engine options and sets up the metatable for the `EngineOptions` table. | |
| -- | |
| -- This code block is executed on the first load of the file. It sets up the default engine options in the | |
| -- `DefaultEngineOptions` table, which includes various video, audio, gameplay, and display settings. | |
| -- | |
| -- The `DefaultEngineOptions` table also includes platform-specific overrides for certain settings, such as | |
| -- resolution, fullscreen mode, and graphics API. | |
| -- | |
| -- Additionally, this code sets up the metatable for the `EngineOptions` table, which allows the `EngineOptions` | |
| -- table to use the default options as a fallback. This means that only the options with a different value than | |
| -- the default need to be stored on disk, which improves efficiency when storing and loading the engine options. | |
| if FirstLoad then | |
| --[[ | |
| DefaultEngineOptions["default_options"] are the main engine option defaults. They are set | |
| as a __index metatable to EngineOptions. This allows only the options with a different value | |
| than the default to be saved on disk while any missing option fallbacks to the default value. | |
| See SetDefaultEngineOptionsMetaTable(). | |
| Some of the defaults (Display options mainly) are used very early to initialize the engine in | |
| InitRenderEngine() through LuaVars in the config. It's good to know that at that point only a | |
| few lua files have been executed and there are no lua classes or game-specific options yet. | |
| The other keys in DefaultEngineOptions (other than "default_options") specify | |
| platform-specific overwrites of the default values. | |
| ]] | |
| DefaultEngineOptions = {default_options={ -- Video | |
| VideoPreset="High", Antialiasing="TAA", Upscaling="Off", ResolutionPercent="100", Shadows="High", Textures="High", | |
| Anisotropy="4x", Terrain="High", Effects="High", Lights="High", Postprocess="High", Bloom="On", EyeAdaptation="On", | |
| Vignette="On", ChromaticAberration="On", SSAO="On", SSR="High", ViewDistance="High", ObjectDetail="High", | |
| FPSCounter="Off", Sharpness=const.DefaultSharpness or "Low", -- Audio | |
| MasterVolume=const.MasterDefaultVolume or 500, Music=const.MusicDefaultVolume or 300, | |
| Voice=const.VoiceDefaultVolume or 1000, Sound=const.SoundDefaultVolume or 650, | |
| Ambience=const.AmbienceDefaultVolume or 1000, UI=const.UIDefaultVolume or 1000, MuteWhenMinimized=true, | |
| RadioStation=const.MusicDefaultRadioStation or "", -- Gameplay | |
| CameraShake="On", -- Display | |
| FullscreenMode=0, Resolution=point(1920, 1080), Vsync=true, GraphicsApi=GetDefaultGraphicsApi(), | |
| GraphicsAdapterIndex=0, MaxFps="240", DisplayAreaMargin=0, UIScale=100, Brightness=500, | |
| -- Engine option fixup metadata | |
| fixups_meta=GetDefaultOptionFixupMeta()}, -- Platform overwrites | |
| desktop={Resolution=Platform.developer and point(1920, 1080) or false, FullscreenMode=Platform.developer and 0 or 1}, | |
| xbox_one={Resolution=point(1920, 1080), FullscreenMode=1, Vsync=true, GraphicsApi="d3d12", VideoPreset="XboxOne"}, | |
| xbox_one_x={Resolution=point(2560, 1440), FullscreenMode=1, Vsync=true, GraphicsApi="d3d12", | |
| VideoPreset="XboxOneX"}, | |
| xbox_series_s={Resolution=point(2560, 1440), FullscreenMode=1, Vsync=true, GraphicsApi="d3d12", | |
| VideoPreset="XboxSeriesS"}, | |
| xbox_series_x={Resolution=point(3840, 2160), FullscreenMode=1, Vsync=true, GraphicsApi="d3d12", | |
| VideoPreset="XboxSeriesXQuality"}, | |
| ps4={Resolution=point(1920, 1080), FullscreenMode=1, Vsync=true, GraphicsApi="gnm", VideoPreset="PS4"}, | |
| ps4_pro={Resolution=point(2240, 1260), FullscreenMode=1, Vsync=true, GraphicsApi="gnm", VideoPreset="PS4Pro"}, | |
| ps5={Resolution=point(3840, 2160), FullscreenMode=1, Vsync=true, GraphicsApi="agc", VideoPreset="PS5Quality"}, | |
| switch={Resolution=point(1280, 720), FullscreenMode=1, Vsync=true, FPSCounter="Off", UIScale=100, | |
| GraphicsApi="NVN", VideoPreset="Switch"}, | |
| steamdeck={Resolution=false, FullscreenMode=1, MaxFps="30", UIScale=const.MaxUserUIScaleHighRes, | |
| VideoPreset="SteamDeck"}} | |
| -- Some additional settings are inited in options.lua | |
| DefaultAccountStorage = {Shortcuts={}, achievements={unlocked={}, progress={}, target={}}, tips={current_tip=0}, | |
| Options={ -- Account | |
| Gamepad=(Platform.console or Platform.steamdeck) and true or false, -- Gameplay | |
| -- Subtitles = true, | |
| -- Colorblind = false, | |
| Language="Auto", -- Account option fixup metadata | |
| fixups_meta=GetDefaultOptionFixupMeta()}, LoadMods={}, PlayStationStartedActivities={}} | |
| DefaultLocalStorage = {id_old_rect={}, dlgBugReport={}, MovieRecord={}, editor={}, FilteredCategories={}, | |
| LockedCategories={}} | |
| PlatformDefaultEngineOptions = {} | |
| SetPlatformDefaultEngineOptions() | |
| EngineOptions = {} | |
| SetDefaultEngineOptionsMetaTable() | |
| end | |
| --- | |
| --- Sets the account storage for the current session. | |
| --- | |
| --- @param storage table The account storage to set. | |
| --- | |
| function SetAccountStorage(storage) | |
| storage = InitWithDefault(storage, DefaultAccountStorage) | |
| AccountStorage = storage | |
| Msg("AccountStorageChanged") | |
| end | |
| --- | |
| --- Initializes the local storage for the application. | |
| --- | |
| --- If the local storage file does not exist, it creates a new local storage table using the `DefaultLocalStorage` table. | |
| --- If the local storage file exists, it reads the contents of the file and initializes the local storage table. | |
| --- If the local storage table is empty or corrupted, it creates a new local storage table using the `DefaultLocalStorage` table. | |
| --- If the local storage table contains developer settings, it moves them to a separate `Developer` table. | |
| --- If the local storage table's `LuaRevision` is 0 and the platform is not in developer mode, it creates a new local storage table using the `DefaultLocalStorage` table. | |
| --- | |
| --- @return table The initialized local storage table. | |
| --- | |
| function InitLocalStorage() | |
| end | |
| local function InitLocalStorage() | |
| if not io.exists(g_LocalStorageFile) then | |
| return InitWithDefault("default", DefaultLocalStorage) | |
| end | |
| local fenv = LuaValueEnv() | |
| local t = dofile(g_LocalStorageFile, fenv) | |
| assert(not t or type(t) == "table") | |
| if not t then | |
| g_FirstTimeUser = true | |
| end | |
| t = InitWithDefault(t or "default", DefaultLocalStorage) | |
| -- move developer settings outside of options | |
| if t.Options and not t.Developer then | |
| t.Developer = {General=t.Options.General, EditorHiddenTextOptions=t.Options.EditorHiddenTextOptions, | |
| MapStartup=t.Options.MapStartup} | |
| t.Options.General = nil | |
| t.Options.EditorHiddenTextOptions = nil | |
| t.Options.MapStartup = nil | |
| end | |
| t.LuaRevision = t.LuaRevision or 0 | |
| if not Platform.developer and t.LuaRevision == 0 then | |
| t = InitWithDefault("default", DefaultLocalStorage) | |
| end | |
| return t | |
| end | |
| --- | |
| --- Sets the account storage to `false` on first load. | |
| --- | |
| --- This is likely used to initialize the account storage to a default value on the first run of the application. | |
| --- | |
| if FirstLoad then | |
| AccountStorage = false | |
| end | |
| --- | |
| --- Saves the current engine options to the local storage file. | |
| --- | |
| --- This function is responsible for persisting the current engine options to the local storage file. It first updates the `LuaRevision` field in the `LocalStorage` table, then generates a Lua code string representing the `LocalStorage` table and writes it to the local storage file asynchronously. | |
| --- | |
| --- If the write operation fails, this function will print an error message and return `false` along with the error message. Otherwise, it will return `true`. | |
| --- | |
| --- @return boolean, string? True if the save operation was successful, false and an error message if it failed. | |
| --- | |
| function SaveEngineOptions() | |
| Msg("EngineOptionsSaved") | |
| return SaveLocalStorage() | |
| end | |
| --- | |
| --- Initializes the local storage for the application on first load. | |
| --- | |
| --- This code block is executed when the application is loaded for the first time. It performs the following actions: | |
| --- | |
| --- 1. Checks if the local storage file exists. If not, it initializes the local storage with the default values. | |
| --- 2. Loads the local storage from the file and initializes it with the default values if necessary. | |
| --- 3. Moves the developer settings outside of the options table. | |
| --- 4. Sets the `LuaRevision` field in the local storage table. | |
| --- 5. If the `LuaRevision` is 0 and the application is not in developer mode, it resets the local storage to the default values. | |
| --- 6. Assigns the initialized local storage table to the `LocalStorage` global variable. | |
| --- 7. Sets the `EngineOptions` global variable to the `Options` field of the `LocalStorage` table. | |
| --- 8. Calls the `SetDefaultEngineOptionsMetaTable()` function to set the default metadata for the `EngineOptions` table. | |
| --- | |
| if FirstLoad then | |
| DefaultLocalStorage.Options = EngineOptions | |
| LocalStorage = InitLocalStorage() | |
| EngineOptions = LocalStorage.Options | |
| SetDefaultEngineOptionsMetaTable() | |
| end | |
| --- | |
| --- Saves the current local storage table to the local storage file. | |
| --- | |
| --- This function is responsible for persisting the current local storage table to the local storage file. It first updates the `LuaRevision` field in the `LocalStorage` table, then generates a Lua code string representing the `LocalStorage` table and writes it to the local storage file asynchronously. | |
| --- | |
| --- If the write operation fails, this function will print an error message and return `false` along with the error message. Otherwise, it will return `true`. | |
| --- | |
| --- @return boolean, string? True if the save operation was successful, false and an error message if it failed. | |
| --- | |
| function SaveLocalStorage() | |
| LocalStorage.LuaRevision = LuaRevision | |
| local code = pstr("return ", 1024) | |
| TableToLuaCode(LocalStorage, nil, code) | |
| ThreadLockKey(g_LocalStorageFile) | |
| local err = AsyncStringToFile(g_LocalStorageFile, code, -2, 0) | |
| ThreadUnlockKey(g_LocalStorageFile) | |
| if err then | |
| print("once", "Failed to save a storage table to", g_LocalStorageFile, ":", err) | |
| return false, err | |
| end | |
| return true | |
| end | |
| --- | |
| --- Saves the local storage after a short delay. | |
| --- | |
| --- This function is used to delay the saving of the local storage to avoid potential performance issues. It calls the `SaveLocalStorage()` function after a short delay of 0 seconds. | |
| --- | |
| --- @return boolean, string? True if the save operation was successful, false and an error message if it failed. | |
| --- | |
| function SaveLocalStorageDelayed() | |
| DelayedCall(0, SaveLocalStorage) | |
| end | |