mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-08-01 08:18:20 -04:00
139 lines
3.9 KiB
C#
139 lines
3.9 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace Sandbox;
|
|
|
|
/// <summary>
|
|
/// Configuration for GameObjectSystem properties at a project level.
|
|
/// Specific scenes may override this as well - but will be serialized directly in the scene.
|
|
/// </summary>
|
|
public class SystemsConfig : ConfigData
|
|
{
|
|
/// <summary>
|
|
/// Stores GameObjectSystems to property names to property values
|
|
/// </summary>
|
|
[JsonInclude]
|
|
protected Dictionary<string, Dictionary<string, object>> Systems { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// Quick utility method to get the type name from a TypeDescription
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
private static string GetTypeName( TypeDescription type ) => type.FullName;
|
|
|
|
/// <summary>
|
|
/// Get property value for a specific system type.
|
|
/// Returns the configured value, or a default value for the type if not found.
|
|
/// </summary>
|
|
public object GetPropertyValue( TypeDescription systemType, PropertyDescription property )
|
|
{
|
|
if ( TryGetPropertyValue( systemType, property, out var value ) )
|
|
return value;
|
|
|
|
return GetDefaultValue( property );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the default value for a GameObjectSystem property.
|
|
/// </summary>
|
|
public static object GetDefaultValue( PropertyDescription property )
|
|
{
|
|
if ( property.GetCustomAttribute<DefaultValueAttribute>() is { } defaultValue )
|
|
return defaultValue.Value;
|
|
|
|
var type = property.PropertyType;
|
|
|
|
if ( Nullable.GetUnderlyingType( type ) is { } nullableType )
|
|
type = nullableType;
|
|
|
|
if ( type.IsValueType )
|
|
return Activator.CreateInstance( type );
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Try to get property value for a specific system type.
|
|
/// Returns true if the property was found in the config.
|
|
/// </summary>
|
|
public bool TryGetPropertyValue( TypeDescription systemType, PropertyDescription property, out object value )
|
|
{
|
|
value = null;
|
|
|
|
var typeName = GetTypeName( systemType );
|
|
|
|
if ( !Systems.TryGetValue( typeName, out var properties ) )
|
|
return false;
|
|
|
|
if ( !properties.TryGetValue( property.Name, out var rawValue ) )
|
|
return false;
|
|
|
|
try
|
|
{
|
|
if ( rawValue is JsonElement je )
|
|
{
|
|
value = je.Deserialize( property.PropertyType, Json.options );
|
|
properties[property.Name] = value;
|
|
return true;
|
|
}
|
|
|
|
// If the value is already assignable to the target type, use it directly
|
|
if ( rawValue?.GetType().IsAssignableTo( property.PropertyType ) == true )
|
|
{
|
|
value = rawValue;
|
|
return true;
|
|
}
|
|
|
|
// Handle enums explicitly
|
|
if ( property.PropertyType.IsEnum && rawValue is IConvertible )
|
|
{
|
|
value = Enum.ToObject( property.PropertyType, Convert.ToInt32( rawValue ) );
|
|
properties[property.Name] = value;
|
|
return true;
|
|
}
|
|
|
|
// Only use Convert.ChangeType for primitive/convertible types
|
|
if ( rawValue is IConvertible && property.PropertyType.IsAssignableTo( typeof( IConvertible ) ) )
|
|
{
|
|
value = Convert.ChangeType( rawValue, property.PropertyType );
|
|
properties[property.Name] = value;
|
|
return true;
|
|
}
|
|
|
|
// Fall back to JSON serialization for complex types
|
|
var json = JsonSerializer.Serialize( rawValue, Json.options );
|
|
value = JsonSerializer.Deserialize( json, property.PropertyType, Json.options );
|
|
properties[property.Name] = value;
|
|
return true;
|
|
}
|
|
catch ( Exception ex )
|
|
{
|
|
Log.Warning( $"Removing stale GameObjectSystem config value {typeName}.{property.Name}: {ex.Message}" );
|
|
properties.Remove( property.Name );
|
|
|
|
if ( properties.Count == 0 )
|
|
{
|
|
Systems.Remove( typeName );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set property value for a specific system type
|
|
/// </summary>
|
|
public void SetPropertyValue( TypeDescription systemType, PropertyDescription property, object value )
|
|
{
|
|
var typeName = GetTypeName( systemType );
|
|
|
|
if ( !Systems.ContainsKey( typeName ) )
|
|
{
|
|
Systems[typeName] = new Dictionary<string, object>();
|
|
}
|
|
|
|
Systems[typeName][property.Name] = value;
|
|
}
|
|
}
|