Refactor settings types to use scripting API

This commit is contained in:
Wojtek Figat
2021-01-05 14:14:34 +01:00
parent cc8e78b505
commit be319c446d
75 changed files with 955 additions and 1431 deletions

View File

@@ -10,71 +10,73 @@
/// <summary>
/// The game building rendering settings.
/// </summary>
class BuildSettings : public SettingsBase<BuildSettings>
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API BuildSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(BuildSettings);
public:
/// <summary>
/// The maximum amount of assets to include into a single assets package. Asset packages will split into several packages if need to.
/// </summary>
int32 MaxAssetsPerPackage = 1024;
API_FIELD(Attributes="EditorOrder(10), DefaultValue(4096), Limit(1, 32, ushort.MaxValue), EditorDisplay(\"General\", \"Max assets per package\")")
int32 MaxAssetsPerPackage = 4096;
/// <summary>
/// The maximum size of the single assets package (in megabytes). Asset packages will split into several packages if need to.
/// </summary>
API_FIELD(Attributes="EditorOrder(20), DefaultValue(1024), Limit(1, 16, ushort.MaxValue), EditorDisplay(\"General\", \"Max package size (in MB)\")")
int32 MaxPackageSizeMB = 1024;
/// <summary>
/// The game content cooking keycode. Use the same value for a game and DLC packages to support loading them by the build game. Use 0 to randomize it during building.
/// </summary>
API_FIELD(Attributes="EditorOrder(30), DefaultValue(0), Limit(1, 16, ushort.MaxValue), EditorDisplay(\"General\")")
int32 ContentKey = 0;
/// <summary>
/// If checked, the builds produced by the Game Cooker will be treated as for final game distribution (eg. for game store upload). Builds done this way cannot be tested on console devkits (eg. Xbox One, Xbox Scarlett).
/// </summary>
API_FIELD(Attributes="EditorOrder(40), DefaultValue(false), EditorDisplay(\"General\")")
bool ForDistribution = false;
/// <summary>
/// If checked, the output build files won't be packaged for the destination platform. Useful when debugging build from local PC.
/// </summary>
API_FIELD(Attributes="EditorOrder(50), DefaultValue(false), EditorDisplay(\"General\")")
bool SkipPackaging = false;
/// <summary>
/// The list of additional assets to include into build (into root assets set).
/// </summary>
API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Additional Data\")")
Array<AssetReference<Asset>> AdditionalAssets;
/// <summary>
/// The list of additional folders with assets to include into build (into root assets set). Paths relative to the project directory (or absolute).
/// </summary>
API_FIELD(Attributes="EditorOrder(1010), EditorDisplay(\"Additional Data\")")
Array<String> AdditionalAssetFolders;
/// <summary>
/// Disables shaders compiler optimizations in cooked game. Can be used to debug shaders on a target platform or to speed up the shaders compilation time.
/// </summary>
API_FIELD(Attributes="EditorOrder(2000), DefaultValue(false), EditorDisplay(\"Content\", \"Shaders No Optimize\")")
bool ShadersNoOptimize = false;
/// <summary>
/// Enables shader debug data generation for shaders in cooked game (depends on the target platform rendering backend).
/// </summary>
API_FIELD(Attributes="EditorOrder(2010), DefaultValue(false), EditorDisplay(\"Content\")")
bool ShadersGenerateDebugData = false;
public:
// [SettingsBase]
void RestoreDefault() final override
{
MaxAssetsPerPackage = 1024;
MaxPackageSizeMB = 1024;
ContentKey = 0;
ForDistribution = false;
SkipPackaging = false;
AdditionalAssets.Clear();
AdditionalAssetFolders.Clear();
ShadersNoOptimize = false;
ShadersGenerateDebugData = false;
}
/// <summary>
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
/// </summary>
static BuildSettings* Get();
// [SettingsBase]
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override
{
DESERIALIZE(MaxAssetsPerPackage);

View File

@@ -2,6 +2,7 @@
#include "GameSettings.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Physics/PhysicsSettings.h"
#include "Engine/Core/Log.h"
#include "LayersTagsSettings.h"
@@ -17,30 +18,6 @@
#include "Engine/Content/AssetReference.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Engine/Time.h"
String GameSettings::ProductName;
String GameSettings::CompanyName;
String GameSettings::CopyrightNotice;
Guid GameSettings::Icon;
Guid GameSettings::FirstScene;
bool GameSettings::NoSplashScreen = false;
Guid GameSettings::SplashScreen;
Dictionary<String, Guid> GameSettings::CustomSettings;
Array<Settings*> Settings::Containers(32);
#if USE_EDITOR
extern void LoadPlatformSettingsEditor(ISerializable::DeserializeStream& data);
#endif
void TimeSettings::Apply()
{
Time::UpdateFPS = UpdateFPS;
Time::PhysicsFPS = PhysicsFPS;
Time::DrawFPS = DrawFPS;
Time::TimeScale = TimeScale;
}
class GameSettingsService : public EngineService
{
@@ -49,9 +26,6 @@ public:
GameSettingsService()
: EngineService(TEXT("GameSettings"), -70)
{
GameSettings::Icon = Guid::Empty;
GameSettings::FirstScene = Guid::Empty;
GameSettings::SplashScreen = Guid::Empty;
}
bool Init() override
@@ -60,62 +34,141 @@ public:
}
};
IMPLEMENT_SETTINGS_GETTER(BuildSettings, GameCooking);
IMPLEMENT_SETTINGS_GETTER(GraphicsSettings, Graphics);
IMPLEMENT_SETTINGS_GETTER(LayersAndTagsSettings, LayersAndTags);
IMPLEMENT_SETTINGS_GETTER(TimeSettings, Time);
IMPLEMENT_SETTINGS_GETTER(AudioSettings, Audio);
IMPLEMENT_SETTINGS_GETTER(PhysicsSettings, Physics);
IMPLEMENT_SETTINGS_GETTER(InputSettings, Input);
#if !USE_EDITOR
#if PLATFORM_WINDOWS
IMPLEMENT_SETTINGS_GETTER(WindowsPlatformSettings, WindowsPlatform);
#elif PLATFORM_UWP || PLATFORM_XBOX_ONE
IMPLEMENT_SETTINGS_GETTER(UWPPlatformSettings, UWPPlatform);
#elif PLATFORM_LINUX
IMPLEMENT_SETTINGS_GETTER(LinuxPlatformSettings, LinuxPlatform);
#elif PLATFORM_PS4
IMPLEMENT_SETTINGS_GETTER(PS4PlatformSettings, PS4Platform);
#elif PLATFORM_XBOX_SCARLETT
IMPLEMENT_SETTINGS_GETTER(XboxScarlettPlatformSettings, XboxScarlettPlatform);
#elif PLATFORM_ANDROID
IMPLEMENT_SETTINGS_GETTER(AndroidPlatformSettings, AndroidPlatform);
#else
#error Unknown platform
#endif
#endif
GameSettingsService GameSettingsServiceInstance;
AssetReference<JsonAsset> GameSettingsAsset;
GameSettings* GameSettings::Get()
{
if (!GameSettingsAsset)
{
// Load root game settings asset.
// It may be missing in editor during dev but must be ready in the build game.
const auto assetPath = Globals::ProjectContentFolder / TEXT("GameSettings.json");
GameSettingsAsset = Content::LoadAsync<JsonAsset>(assetPath);
if (GameSettingsAsset == nullptr)
{
LOG(Error, "Missing game settings asset.");
return nullptr;
}
if (GameSettingsAsset->WaitForLoaded())
{
return nullptr;
}
if (GameSettingsAsset->InstanceType != GameSettings::TypeInitializer)
{
LOG(Error, "Invalid game settings asset data type.");
return nullptr;
}
}
auto asset = GameSettingsAsset.Get();
if (asset && asset->WaitForLoaded())
asset = nullptr;
return asset ? (GameSettings*)asset->Instance : nullptr;
}
bool GameSettings::Load()
{
// Load main settings asset
auto settings = Get();
if (!settings)
{
return true;
}
// Preload all settings assets
#define PRELOAD_SETTINGS(type) \
{ \
if (settings->type) \
{ \
Content::LoadAsync<JsonAsset>(settings->type); \
} \
else \
{ \
LOG(Warning, "Missing {0} settings", TEXT(#type)); \
} \
}
PRELOAD_SETTINGS(Time);
PRELOAD_SETTINGS(Audio);
PRELOAD_SETTINGS(LayersAndTags);
PRELOAD_SETTINGS(Physics);
PRELOAD_SETTINGS(Input);
PRELOAD_SETTINGS(Graphics);
PRELOAD_SETTINGS(Navigation);
PRELOAD_SETTINGS(GameCooking);
#undef PRELOAD_SETTINGS
// Apply the game settings to the engine
settings->Apply();
return false;
}
void GameSettings::Apply()
{
// TODO: impl this
#define APPLY_SETTINGS(type) \
{ \
type* obj = type::Get(); \
if (obj) \
{ \
obj->Apply(); \
} \
else \
{ \
LOG(Warning, "Missing {0} settings", TEXT(#type)); \
} \
}
APPLY_SETTINGS(TimeSettings);
APPLY_SETTINGS(AudioSettings);
APPLY_SETTINGS(LayersAndTagsSettings);
APPLY_SETTINGS(PhysicsSettings);
APPLY_SETTINGS(InputSettings);
APPLY_SETTINGS(GraphicsSettings);
APPLY_SETTINGS(NavigationSettings);
APPLY_SETTINGS(BuildSettings);
APPLY_SETTINGS(PlatformSettings);
#undef APPLY_SETTINGS
}
void GameSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
// Load properties
ProductName = JsonTools::GetString(stream, "ProductName");
CompanyName = JsonTools::GetString(stream, "CompanyName");
CopyrightNotice = JsonTools::GetString(stream, "CopyrightNotice");
Icon = JsonTools::GetGuid(stream, "Icon");
FirstScene = JsonTools::GetGuid(stream, "FirstScene");
NoSplashScreen = JsonTools::GetBool(stream, "NoSplashScreen", NoSplashScreen);
SplashScreen = JsonTools::GetGuid(stream, "SplashScreen");
CustomSettings.Clear();
#if USE_EDITOR
#define END_POINT(msg) LOG(Warning, msg " Using default values."); return false
#else
#define END_POINT(msg) LOG(Fatal, msg); return true
#endif
#define LOAD_SETTINGS(nodeName, settingsType) \
{ \
Guid id = JsonTools::GetGuid(data, nodeName); \
if (id.IsValid()) \
{ \
AssetReference<JsonAsset> subAsset = Content::LoadAsync<JsonAsset>(id); \
if (subAsset && !subAsset->WaitForLoaded()) \
{ \
settingsType::Instance()->Deserialize(*subAsset->Data, nullptr); \
settingsType::Instance()->Apply(); \
} \
else \
{ LOG(Warning, "Cannot load " nodeName " settings"); } \
} \
else \
{ LOG(Warning, "Missing " nodeName " settings"); } \
}
// Load root game settings asset.
// It may be missing in editor during dev but must be ready in the build game.
const auto assetPath = Globals::ProjectContentFolder / TEXT("GameSettings.json");
AssetReference<JsonAsset> asset = Content::LoadAsync<JsonAsset>(assetPath);
if (asset == nullptr)
{
END_POINT("Missing game settings asset.");
}
if (asset->WaitForLoaded()
|| asset->DataTypeName != TEXT("FlaxEditor.Content.Settings.GameSettings")
|| asset->Data == nullptr)
{
END_POINT("Cannot load game settings asset.");
}
auto& data = *asset->Data;
// Load settings
ProductName = JsonTools::GetString(data, "ProductName");
CompanyName = JsonTools::GetString(data, "CompanyName");
CopyrightNotice = JsonTools::GetString(data, "CopyrightNotice");
Icon = JsonTools::GetGuid(data, "Icon");
FirstScene = JsonTools::GetGuid(data, "FirstScene");
NoSplashScreen = JsonTools::GetBool(data, "NoSplashScreen", NoSplashScreen);
SplashScreen = JsonTools::GetGuid(data, "SplashScreen");
const auto customSettings = data.FindMember("CustomSettings");
if (customSettings != data.MemberEnd())
const auto customSettings = stream.FindMember("CustomSettings");
if (customSettings != stream.MemberEnd())
{
auto& items = customSettings->value;
for (auto it = items.MemberBegin(); it != items.MemberEnd(); ++it)
@@ -129,39 +182,21 @@ bool GameSettings::Load()
}
}
// Load child settings
LOAD_SETTINGS("Time", TimeSettings);
LOAD_SETTINGS("Physics", PhysicsSettings);
LOAD_SETTINGS("LayersAndTags", LayersAndTagsSettings);
LOAD_SETTINGS("Graphics", GraphicsSettings);
LOAD_SETTINGS("GameCooking", BuildSettings);
LOAD_SETTINGS("Input", InputSettings);
LOAD_SETTINGS("Audio", AudioSettings);
LOAD_SETTINGS("Navigation", NavigationSettings);
// Settings containers
DESERIALIZE(Time);
DESERIALIZE(Audio);
DESERIALIZE(LayersAndTags);
DESERIALIZE(Physics);
DESERIALIZE(Input);
DESERIALIZE(Graphics);
DESERIALIZE(Navigation);
DESERIALIZE(GameCooking);
// Load platform settings
#if PLATFORM_WINDOWS
LOAD_SETTINGS("WindowsPlatform", WindowsPlatformSettings);
#endif
#if PLATFORM_UWP
LOAD_SETTINGS("UWPPlatform", UWPPlatformSettings);
#endif
#if PLATFORM_LINUX
LOAD_SETTINGS("LinuxPlatform", LinuxPlatformSettings);
#endif
#if PLATFORM_PS4
LOAD_SETTINGS("PS4Platform", PS4PlatformSettings);
#endif
#if PLATFORM_XBOX_SCARLETT
LOAD_SETTINGS("XboxScarlettPlatform", XboxScarlettPlatformSettings);
#endif
#if PLATFORM_ANDROID
LOAD_SETTINGS("AndroidPlatform", AndroidPlatformSettings);
#endif
#if USE_EDITOR
LoadPlatformSettingsEditor(data);
#endif
return false;
#undef END_POINT
// Per-platform settings containers
DESERIALIZE(WindowsPlatform);
DESERIALIZE(UWPPlatform);
DESERIALIZE(LinuxPlatform);
DESERIALIZE(PS4Platform);
DESERIALIZE(XboxScarlettPlatform);
DESERIALIZE(AndroidPlatform);
}

View File

@@ -2,60 +2,96 @@
#pragma once
#include "Settings.h"
#include "Engine/Core/Types/Guid.h"
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Dictionary.h"
/// <summary>
/// Main engine configuration service. Loads and applies game configuration.
/// The main game engine configuration service. Loads and applies game configuration.
/// </summary>
class GameSettings
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API GameSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(GameSettings);
public:
/// <summary>
/// The product full name.
/// </summary>
static String ProductName;
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"General\")")
String ProductName;
/// <summary>
/// The company full name.
/// </summary>
static String CompanyName;
API_FIELD(Attributes="EditorOrder(10), EditorDisplay(\"General\")")
String CompanyName;
/// <summary>
/// The copyright note used for content signing (eg. source code header).
/// </summary>
static String CopyrightNotice;
API_FIELD(Attributes="EditorOrder(15), EditorDisplay(\"General\")")
String CopyrightNotice;
/// <summary>
/// The default application icon.
/// </summary>
static Guid Icon;
Guid Icon = Guid::Empty;
/// <summary>
/// Reference to the first scene to load on a game startup.
/// </summary>
static Guid FirstScene;
Guid FirstScene = Guid::Empty;
/// <summary>
/// True if skip showing splash screen image on the game startup.
/// </summary>
static bool NoSplashScreen;
bool NoSplashScreen = false;
/// <summary>
/// Reference to the splash screen image to show on a game startup.
/// </summary>
static Guid SplashScreen;
Guid SplashScreen = Guid::Empty;
/// <summary>
/// The custom settings to use with a game. Can be specified by the user to define game-specific options and be used by the external plugins (used as key-value pair).
/// </summary>
static Dictionary<String, Guid> CustomSettings;
Dictionary<String, Guid> CustomSettings;
public:
// Settings containers
Guid Time;
Guid Audio;
Guid LayersAndTags;
Guid Physics;
Guid Input;
Guid Graphics;
Guid Navigation;
Guid GameCooking;
// Per-platform settings containers
Guid WindowsPlatform;
Guid UWPPlatform;
Guid LinuxPlatform;
Guid PS4Platform;
Guid XboxScarlettPlatform;
Guid AndroidPlatform;
public:
/// <summary>
/// Gets the instance of the game settings asset (null if missing). Object returned by this method is always loaded with valid data to use.
/// </summary>
static GameSettings* Get();
/// <summary>
/// Loads the game settings (including other settings such as Physics, Input, etc.).
/// </summary>
/// <returns>True if failed, otherwise false.</returns>
static bool Load();
// [SettingsBase]
void Apply() override;
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override;
};

View File

@@ -9,67 +9,68 @@
/// <summary>
/// Graphics rendering settings.
/// </summary>
class GraphicsSettings : public SettingsBase<GraphicsSettings>
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API GraphicsSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(GraphicsSettings);
public:
/// <summary>
/// Enables rendering synchronization with the refresh rate of the display device to avoid "tearing" artifacts.
/// </summary>
API_FIELD(Attributes="EditorOrder(20), DefaultValue(false), EditorDisplay(\"General\", \"Use V-Sync\")")
bool UseVSync = false;
/// <summary>
/// Anti Aliasing quality setting.
/// </summary>
API_FIELD(Attributes="EditorOrder(1000), DefaultValue(Quality.Medium), EditorDisplay(\"Quality\", \"AA Quality\")")
Quality AAQuality = Quality::Medium;
/// <summary>
/// Screen Space Reflections quality setting.
/// </summary>
API_FIELD(Attributes="EditorOrder(1100), DefaultValue(Quality.Medium), EditorDisplay(\"Quality\", \"SSR Quality\")")
Quality SSRQuality = Quality::Medium;
/// <summary>
/// Screen Space Ambient Occlusion quality setting.
/// </summary>
API_FIELD(Attributes="EditorOrder(1200), DefaultValue(Quality.Medium), EditorDisplay(\"Quality\", \"SSAO Quality\")")
Quality SSAOQuality = Quality::Medium;
/// <summary>
/// Volumetric Fog quality setting.
/// </summary>
API_FIELD(Attributes="EditorOrder(1250), DefaultValue(Quality.High), EditorDisplay(\"Quality\")")
Quality VolumetricFogQuality = Quality::High;
/// <summary>
/// The shadows quality.
/// </summary>
API_FIELD(Attributes="EditorOrder(1300), DefaultValue(Quality.Medium), EditorDisplay(\"Quality\")")
Quality ShadowsQuality = Quality::Medium;
/// <summary>
/// The shadow maps quality (textures resolution).
/// </summary>
API_FIELD(Attributes="EditorOrder(1310), DefaultValue(Quality.Medium), EditorDisplay(\"Quality\")")
Quality ShadowMapsQuality = Quality::Medium;
/// <summary>
/// Enables cascades splits blending for directional light shadows.
/// </summary>
API_FIELD(Attributes="EditorOrder(1320), DefaultValue(false), EditorDisplay(\"Quality\", \"Allow CSM Blending\")")
bool AllowCSMBlending = false;
public:
/// <summary>
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
/// </summary>
static GraphicsSettings* Get();
// [SettingsBase]
void Apply() override;
void RestoreDefault() final override
{
UseVSync = false;
AAQuality = Quality::Medium;
SSRQuality = Quality::Medium;
SSAOQuality = Quality::Medium;
VolumetricFogQuality = Quality::High;
ShadowsQuality = Quality::Medium;
ShadowMapsQuality = Quality::Medium;
AllowCSMBlending = false;
}
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override
{
DESERIALIZE(UseVSync);

View File

@@ -7,8 +7,9 @@
/// <summary>
/// Layers and objects tags settings.
/// </summary>
class LayersAndTagsSettings : public SettingsBase<LayersAndTagsSettings>
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API LayersAndTagsSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(LayersAndTagsSettings);
public:
/// <summary>
@@ -24,43 +25,11 @@ public:
public:
/// <summary>
/// Gets or adds the tag (returns the tag index).
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>The tag index.</returns>
int32 GetOrAddTag(const String& tag)
{
int32 index = Tags.Find(tag);
if (index == INVALID_INDEX)
{
index = Tags.Count();
Tags.Add(tag);
}
return index;
}
/// <summary>
/// Gets the amount of non empty layer names (from the beginning, trims the last ones).
/// </summary>
/// <returns>The layers count.</returns>
int32 GetNonEmptyLayerNamesCount() const
{
int32 result = 31;
while (result >= 0 && Layers[result].IsEmpty())
result--;
return result + 1;
}
public:
static LayersAndTagsSettings* Get();
// [SettingsBase]
void RestoreDefault() override
{
Tags.Clear();
for (int32 i = 0; i < 32; i++)
Layers[i].Clear();
}
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override
{
const auto tags = stream.FindMember("Tags");

View File

@@ -2,81 +2,46 @@
#pragma once
#include "Engine/Core/Singleton.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Serialization/ISerializable.h"
/// <summary>
/// Base class for all global settings containers for the engine. Helps to apply, store and expose properties to engine/game.
/// </summary>
class FLAXENGINE_API Settings
API_CLASS(Abstract) class FLAXENGINE_API SettingsBase : public ISerializable
{
DECLARE_SCRIPTING_TYPE_MINIMAL(SettingsBase);
public:
/// <summary>
/// The settings containers.
/// </summary>
static Array<Settings*> Containers;
/// <summary>
/// Restores the default settings for all the registered containers.
/// </summary>
static void RestoreDefaultAll()
{
for (int32 i = 0; i < Containers.Count(); i++)
Containers[i]->RestoreDefault();
}
private:
// Disable copy/move
Settings(const Settings&) = delete;
Settings& operator=(const Settings&) = delete;
protected:
Settings()
{
Containers.Add(this);
}
public:
virtual ~Settings() = default;
public:
typedef ISerializable::DeserializeStream DeserializeStream;
/// <summary>
/// Applies the settings to the target services.
/// Applies the settings to the target system.
/// </summary>
virtual void Apply()
{
}
/// <summary>
/// Restores the default settings.
/// </summary>
virtual void RestoreDefault() = 0;
public:
/// <summary>
/// Deserializes the settings container.
/// </summary>
/// <param name="stream">The input data stream.</param>
/// <param name="modifier">The deserialization modifier object. Always valid.</param>
virtual void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) = 0;
};
/// <summary>
/// Base class for all global settings containers for the engine. Helps to apply, store and expose properties to engine/game.
/// </summary>
template<class T>
class SettingsBase : public Settings, public Singleton<T>
{
protected:
SettingsBase()
// [ISerializable]
void Serialize(SerializeStream& stream, const void* otherObj) override
{
// Not supported (Editor C# edits settings data)
}
};
// Helper utility define for settings getter implementation code
#define IMPLEMENT_SETTINGS_GETTER(type, field) \
type* type::Get() \
{ \
static type DefaultInstance; \
type* result = &DefaultInstance; \
const auto gameSettings = GameSettings::Get(); \
if (gameSettings) \
{ \
const auto asset = Content::Load<JsonAsset>(gameSettings->field); \
if (asset && asset->Instance && asset->InstanceType == type::TypeInitializer) \
{ \
result = static_cast<type*>(asset->Instance); \
} \
} \
return result; \
}

View File

@@ -3,60 +3,53 @@
#pragma once
#include "Engine/Core/Config/Settings.h"
#include "Engine/Serialization/Serialization.h"
/// <summary>
/// Time and game simulation settings container.
/// </summary>
class TimeSettings : public SettingsBase<TimeSettings>
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API TimeSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(TimeSettings);
public:
/// <summary>
/// The target amount of the game logic updates per second (script updates frequency).
/// </summary>
API_FIELD(Attributes="EditorOrder(1), DefaultValue(30.0f), Limit(0, 1000), EditorDisplay(\"General\", \"Update FPS\")")
float UpdateFPS = 30.0f;
/// <summary>
/// The target amount of the physics simulation updates per second (also fixed updates frequency).
/// </summary>
API_FIELD(Attributes="EditorOrder(2), DefaultValue(60.0f), Limit(0, 1000), EditorDisplay(\"General\", \"Physics FPS\")")
float PhysicsFPS = 60.0f;
/// <summary>
/// The target amount of the frames rendered per second (actual game FPS).
/// </summary>
API_FIELD(Attributes="EditorOrder(3), DefaultValue(60.0f), Limit(0, 1000), EditorDisplay(\"General\", \"Draw FPS\")")
float DrawFPS = 60.0f;
/// <summary>
/// The game time scale factor. Default is 1.
/// </summary>
API_FIELD(Attributes="EditorOrder(10), DefaultValue(1.0f), Limit(0, 1000.0f, 0.1f), EditorDisplay(\"General\")")
float TimeScale = 1.0f;
/// <summary>
/// The maximum allowed delta time (in seconds) for the game logic update step.
/// </summary>
float MaxUpdateDeltaTime = (1.0f / 10.0f);
API_FIELD(Attributes="EditorOrder(20), DefaultValue(0.1f), Limit(0.1f, 1000.0f, 0.01f), EditorDisplay(\"General\")")
float MaxUpdateDeltaTime = 0.1f;
public:
/// <summary>
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
/// </summary>
static TimeSettings* Get();
// [SettingsBase]
void Apply() override;
void RestoreDefault() override
{
UpdateFPS = 30.0f;
PhysicsFPS = 60.0f;
DrawFPS = 60.0f;
TimeScale = 1.0f;
MaxUpdateDeltaTime = 1.0f / 10.0f;
}
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override
{
DESERIALIZE(UpdateFPS);
DESERIALIZE(PhysicsFPS);
DESERIALIZE(DrawFPS);
DESERIALIZE(TimeScale);
DESERIALIZE(MaxUpdateDeltaTime);
}
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override;
};