- Renamed a bunch of ObjectProperty-related stuff (ObjectProperty -> SerializableProperty, IPropertyObject -> ISerializableEntity, the "SerializableProperty" attribute -> Serialize).
- Rectangle serialization. - Option to restrict numeric properties to a range of values. - WIP generic ISerializableEntity editor.
This commit is contained in:
+2
-2
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
interface IPropertyObject
|
||||
interface ISerializableEntity
|
||||
{
|
||||
string Name
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
Dictionary<string, ObjectProperty> ObjectProperties
|
||||
Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
}
|
||||
@@ -1,385 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class Editable : System.Attribute
|
||||
{
|
||||
public int MaxLength;
|
||||
|
||||
public Editable(int maxLength = 20)
|
||||
{
|
||||
MaxLength = maxLength;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class InGameEditable : Editable
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class SerializableProperty : System.Attribute
|
||||
{
|
||||
public object defaultValue;
|
||||
public bool isSaveable;
|
||||
|
||||
public SerializableProperty(object defaultValue, bool isSaveable)
|
||||
{
|
||||
this.defaultValue = defaultValue;
|
||||
this.isSaveable = isSaveable;
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectProperty
|
||||
{
|
||||
private readonly PropertyDescriptor propertyDescriptor;
|
||||
private readonly PropertyInfo propertyInfo;
|
||||
private readonly object obj;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return propertyDescriptor.Name; }
|
||||
}
|
||||
|
||||
public AttributeCollection Attributes
|
||||
{
|
||||
get { return propertyDescriptor.Attributes; }
|
||||
}
|
||||
|
||||
public Type PropertyType
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyInfo.PropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectProperty(PropertyDescriptor property, object obj)
|
||||
{
|
||||
this.propertyDescriptor = property;
|
||||
propertyInfo = property.ComponentType.GetProperty(property.Name);
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
public bool TrySetValue(string value)
|
||||
{
|
||||
if (value == null) return false;
|
||||
|
||||
if (propertyDescriptor.PropertyType == typeof(string))
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(float))
|
||||
{
|
||||
float floatVal;
|
||||
if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatVal))
|
||||
{
|
||||
propertyInfo.SetValue(obj, floatVal, null);
|
||||
}
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(bool))
|
||||
{
|
||||
propertyInfo.SetValue(obj, value.ToLowerInvariant() == "true", null);
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(int))
|
||||
{
|
||||
int intVal;
|
||||
if (int.TryParse(value, out intVal))
|
||||
{
|
||||
propertyInfo.SetValue(obj, intVal, null);
|
||||
}
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(Vector2))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToVector2(value));
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(Vector3))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToVector3(value));
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(Vector4))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToVector4(value));
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType == typeof(Color))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToColor(value));
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType.IsEnum)
|
||||
{
|
||||
object enumVal;
|
||||
try
|
||||
{
|
||||
enumVal = Enum.Parse(propertyInfo.PropertyType, value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj + "\" to " + value + " (not a valid " + propertyInfo.PropertyType + ")", e);
|
||||
return false;
|
||||
}
|
||||
propertyInfo.SetValue(obj, enumVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj + "\" to " + value);
|
||||
DebugConsole.ThrowError("(Type not implemented)");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(object value)
|
||||
{
|
||||
if (value == null) return false;
|
||||
if (obj == null || propertyDescriptor == null) return false;
|
||||
try
|
||||
{
|
||||
if (value.GetType() == typeof(string) &&
|
||||
propertyDescriptor.PropertyType == typeof(Vector2))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToVector2(value.ToString()));
|
||||
}
|
||||
else if (value.GetType() == typeof(string) &&
|
||||
propertyDescriptor.PropertyType == typeof(Vector3))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToVector3(value.ToString()));
|
||||
}
|
||||
else if (value.GetType() == typeof(string) &&
|
||||
propertyDescriptor.PropertyType == typeof(Vector4))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToVector4(value.ToString()));
|
||||
}
|
||||
else if (value.GetType() == typeof(string) &&
|
||||
propertyDescriptor.PropertyType == typeof(Color))
|
||||
{
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseToColor(value.ToString()));
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType != value.GetType())
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj.ToString() + "\" to " + value.ToString());
|
||||
DebugConsole.ThrowError("(Non-matching type, should be " + propertyDescriptor.PropertyType + " instead of " + value.GetType() + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(float value)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(bool value)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(int value)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public object GetValue()
|
||||
{
|
||||
if (obj == null || propertyDescriptor == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
return propertyInfo.GetValue(obj, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ObjectProperty> GetProperties<T>(IPropertyObject obj)
|
||||
{
|
||||
List<ObjectProperty> editableProperties = new List<ObjectProperty>();
|
||||
|
||||
foreach (var property in obj.ObjectProperties.Values)
|
||||
{
|
||||
if (property.Attributes.OfType<T>().Any()) editableProperties.Add(property);
|
||||
}
|
||||
|
||||
return editableProperties;
|
||||
}
|
||||
|
||||
public static Dictionary<string, ObjectProperty> GetProperties(IPropertyObject obj)
|
||||
{
|
||||
var properties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();
|
||||
|
||||
Dictionary<string, ObjectProperty> dictionary = new Dictionary<string, ObjectProperty>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
dictionary.Add(property.Name.ToLowerInvariant(), new ObjectProperty(property, obj));
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Sets all serializable properties to their default value
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, ObjectProperty> InitProperties(IPropertyObject obj)
|
||||
{
|
||||
return DeserializeProperties(obj, null);
|
||||
}*/
|
||||
|
||||
public static Dictionary<string, ObjectProperty> DeserializeProperties(IPropertyObject obj, XElement element)
|
||||
{
|
||||
var properties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();
|
||||
|
||||
Dictionary<string, ObjectProperty> dictionary = new Dictionary<string, ObjectProperty>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
ObjectProperty objProperty = new ObjectProperty(property, obj);
|
||||
dictionary.Add(property.Name.ToLowerInvariant(), objProperty);
|
||||
|
||||
//set the value of the property to the default value if there is one
|
||||
foreach (var ini in property.Attributes.OfType<SerializableProperty>())
|
||||
{
|
||||
objProperty.TrySetValue(ini.defaultValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
//go through all the attributes in the xml element
|
||||
//and set the value of the matching property if it is initializable
|
||||
foreach (XAttribute attribute in element.Attributes())
|
||||
{
|
||||
ObjectProperty property = null;
|
||||
if (!dictionary.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out property)) continue;
|
||||
if (!property.Attributes.OfType<SerializableProperty>().Any()) continue;
|
||||
property.TrySetValue(attribute.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public static void SerializeProperties(IPropertyObject obj, XElement element, bool saveIfDefault = false)
|
||||
{
|
||||
var saveProperties = GetProperties<SerializableProperty>(obj);
|
||||
foreach (var property in saveProperties)
|
||||
{
|
||||
object value = property.GetValue();
|
||||
if (value == null) continue;
|
||||
|
||||
if (!saveIfDefault)
|
||||
{
|
||||
//only save
|
||||
// - if the attribute is saveable and it's different from the default value
|
||||
// - or can be changed in-game or in the editor
|
||||
bool save = false;
|
||||
foreach (var attribute in property.Attributes.OfType<SerializableProperty>())
|
||||
{
|
||||
if ((attribute.isSaveable && !attribute.defaultValue.Equals(value)) ||
|
||||
property.Attributes.OfType<Editable>().Any())
|
||||
{
|
||||
save = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!save) continue;
|
||||
}
|
||||
|
||||
string stringValue;
|
||||
if (value.GetType() == typeof(float))
|
||||
{
|
||||
//make sure the decimal point isn't converted to a comma or anything else
|
||||
stringValue = ((float)value).ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (value.GetType() == typeof(Vector2))
|
||||
{
|
||||
Vector2 vector = (Vector2)value;
|
||||
stringValue =
|
||||
vector.X.ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (value.GetType() == typeof(Vector3))
|
||||
{
|
||||
Vector3 vector = (Vector3)value;
|
||||
stringValue =
|
||||
vector.X.ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
vector.Z.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (value.GetType() == typeof(Vector4))
|
||||
{
|
||||
Vector4 vector = (Vector4)value;
|
||||
stringValue =
|
||||
vector.X.ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
vector.Z.ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
vector.W.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (value.GetType() == typeof(Color))
|
||||
{
|
||||
Color color = (Color)value;
|
||||
stringValue =
|
||||
(color.R / 255.0f).ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
(color.G / 255.0f).ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
(color.B / 255.0f).ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
(color.A / 255.0f).ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
stringValue = value.ToString();
|
||||
}
|
||||
|
||||
element.Add(new XAttribute(property.Name.ToLowerInvariant(), stringValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class Editable : Attribute
|
||||
{
|
||||
public int MaxLength;
|
||||
|
||||
public int? MinValueInt, MaxValueInt;
|
||||
public float? MinValueFloat, MaxValueFloat;
|
||||
|
||||
public Editable(int maxLength = 20)
|
||||
{
|
||||
MaxLength = maxLength;
|
||||
}
|
||||
|
||||
public Editable(int? minValue, int? maxValue)
|
||||
{
|
||||
MinValueInt = minValue;
|
||||
MaxValueInt = maxValue;
|
||||
}
|
||||
|
||||
public Editable(float? minValue, float? maxValue)
|
||||
{
|
||||
MinValueFloat = minValue;
|
||||
MaxValueFloat = maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class InGameEditable : Editable
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class Serialize : Attribute
|
||||
{
|
||||
public object defaultValue;
|
||||
public bool isSaveable;
|
||||
|
||||
public Serialize(object defaultValue, bool isSaveable)
|
||||
{
|
||||
this.defaultValue = defaultValue;
|
||||
this.isSaveable = isSaveable;
|
||||
}
|
||||
}
|
||||
|
||||
class SerializableProperty
|
||||
{
|
||||
private static Dictionary<Type, string> supportedTypes = new Dictionary<Type, string>
|
||||
{
|
||||
{ typeof(bool), "bool" },
|
||||
{ typeof(int), "int" },
|
||||
{ typeof(float), "float" },
|
||||
{ typeof(string), "string" },
|
||||
{ typeof(Vector2), "vector2" },
|
||||
{ typeof(Vector3), "vector3" },
|
||||
{ typeof(Vector4), "vector4" },
|
||||
{ typeof(Rectangle), "rectangle" },
|
||||
{ typeof(Color), "color" },
|
||||
};
|
||||
|
||||
private readonly PropertyDescriptor propertyDescriptor;
|
||||
private readonly PropertyInfo propertyInfo;
|
||||
private readonly object obj;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return propertyDescriptor.Name; }
|
||||
}
|
||||
|
||||
public AttributeCollection Attributes
|
||||
{
|
||||
get { return propertyDescriptor.Attributes; }
|
||||
}
|
||||
|
||||
public Type PropertyType
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyInfo.PropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
public SerializableProperty(PropertyDescriptor property, object obj)
|
||||
{
|
||||
this.propertyDescriptor = property;
|
||||
propertyInfo = property.ComponentType.GetProperty(property.Name);
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
public T GetAttribute<T>() where T : Attribute
|
||||
{
|
||||
foreach (Attribute a in Attributes)
|
||||
{
|
||||
if (a is T) return (T)a;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public bool TrySetValue(string value)
|
||||
{
|
||||
if (value == null) return false;
|
||||
|
||||
string typeName;
|
||||
if (!supportedTypes.TryGetValue(propertyDescriptor.PropertyType, out typeName))
|
||||
{
|
||||
if (propertyDescriptor.PropertyType.IsEnum)
|
||||
{
|
||||
object enumVal;
|
||||
try
|
||||
{
|
||||
enumVal = Enum.Parse(propertyInfo.PropertyType, value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj + "\" to " + value + " (not a valid " + propertyInfo.PropertyType + ")", e);
|
||||
return false;
|
||||
}
|
||||
propertyInfo.SetValue(obj, enumVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj + "\" to " + value);
|
||||
DebugConsole.ThrowError("(Type not supported)");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (typeName)
|
||||
{
|
||||
case "bool":
|
||||
propertyInfo.SetValue(obj, value.ToLowerInvariant() == "true", null);
|
||||
break;
|
||||
case "int":
|
||||
int intVal;
|
||||
if (int.TryParse(value, out intVal))
|
||||
{
|
||||
propertyInfo.SetValue(obj, intVal, null);
|
||||
}
|
||||
break;
|
||||
case "float":
|
||||
float floatVal;
|
||||
if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatVal))
|
||||
{
|
||||
propertyInfo.SetValue(obj, floatVal, null);
|
||||
}
|
||||
break;
|
||||
case "string":
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
break;
|
||||
case "vector2":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseVector2(value));
|
||||
break;
|
||||
case "vector3":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseVector3(value));
|
||||
break;
|
||||
case "vector4":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseVector4(value));
|
||||
break;
|
||||
case "color":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseColor(value));
|
||||
break;
|
||||
case "rectangle":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseRect(value));
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(object value)
|
||||
{
|
||||
if (value == null || obj == null || propertyDescriptor == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
string typeName;
|
||||
if (!supportedTypes.TryGetValue(propertyDescriptor.PropertyType, out typeName))
|
||||
{
|
||||
if (propertyDescriptor.PropertyType.IsEnum)
|
||||
{
|
||||
object enumVal;
|
||||
try
|
||||
{
|
||||
enumVal = Enum.Parse(propertyInfo.PropertyType, value.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj + "\" to " + value + " (not a valid " + propertyInfo.PropertyType + ")", e);
|
||||
return false;
|
||||
}
|
||||
propertyInfo.SetValue(obj, enumVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj + "\" to " + value);
|
||||
DebugConsole.ThrowError("(Type not supported)");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.GetType() == typeof(string))
|
||||
{
|
||||
switch (typeName)
|
||||
{
|
||||
case "string":
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
return true;
|
||||
case "vector2":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseVector2((string)value));
|
||||
return true;
|
||||
case "vector3":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseVector3((string)value));
|
||||
return true;
|
||||
case "vector4":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseVector4((string)value));
|
||||
return true;
|
||||
case "color":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseColor((string)value));
|
||||
return true;
|
||||
case "rectangle":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParseColor((string)value));
|
||||
return true;
|
||||
default:
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj.ToString() + "\" to " + value.ToString());
|
||||
DebugConsole.ThrowError("(Cannot convert a string to a " + propertyDescriptor.PropertyType.ToString() + ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (propertyDescriptor.PropertyType != value.GetType())
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the value of the property \"" + Name + "\" of \"" + obj.ToString() + "\" to " + value.ToString());
|
||||
DebugConsole.ThrowError("(Non-matching type, should be " + propertyDescriptor.PropertyType + " instead of " + value.GetType() + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TrySetValue(float value)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(bool value)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySetValue(int value)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyInfo.SetValue(obj, value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public object GetValue()
|
||||
{
|
||||
if (obj == null || propertyDescriptor == null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
return propertyInfo.GetValue(obj, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SerializableProperty> GetProperties<T>(ISerializableEntity obj)
|
||||
{
|
||||
List<SerializableProperty> editableProperties = new List<SerializableProperty>();
|
||||
|
||||
foreach (var property in obj.SerializableProperties.Values)
|
||||
{
|
||||
if (property.Attributes.OfType<T>().Any()) editableProperties.Add(property);
|
||||
}
|
||||
|
||||
return editableProperties;
|
||||
}
|
||||
|
||||
public static Dictionary<string, SerializableProperty> GetProperties(ISerializableEntity obj)
|
||||
{
|
||||
var properties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();
|
||||
|
||||
Dictionary<string, SerializableProperty> dictionary = new Dictionary<string, SerializableProperty>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
dictionary.Add(property.Name.ToLowerInvariant(), new SerializableProperty(property, obj));
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public static Dictionary<string, SerializableProperty> DeserializeProperties(ISerializableEntity obj, XElement element)
|
||||
{
|
||||
var properties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();
|
||||
|
||||
Dictionary<string, SerializableProperty> dictionary = new Dictionary<string, SerializableProperty>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
SerializableProperty objProperty = new SerializableProperty(property, obj);
|
||||
dictionary.Add(property.Name.ToLowerInvariant(), objProperty);
|
||||
|
||||
//set the value of the property to the default value if there is one
|
||||
foreach (var ini in property.Attributes.OfType<Serialize>())
|
||||
{
|
||||
objProperty.TrySetValue(ini.defaultValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
//go through all the attributes in the xml element
|
||||
//and set the value of the matching property if it is initializable
|
||||
foreach (XAttribute attribute in element.Attributes())
|
||||
{
|
||||
SerializableProperty property = null;
|
||||
if (!dictionary.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out property)) continue;
|
||||
if (!property.Attributes.OfType<Serialize>().Any()) continue;
|
||||
property.TrySetValue(attribute.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public static void SerializeProperties(ISerializableEntity obj, XElement element, bool saveIfDefault = false)
|
||||
{
|
||||
var saveProperties = GetProperties<Serialize>(obj);
|
||||
foreach (var property in saveProperties)
|
||||
{
|
||||
object value = property.GetValue();
|
||||
if (value == null) continue;
|
||||
|
||||
if (!saveIfDefault)
|
||||
{
|
||||
//only save
|
||||
// - if the attribute is saveable and it's different from the default value
|
||||
// - or can be changed in-game or in the editor
|
||||
bool save = false;
|
||||
foreach (var attribute in property.Attributes.OfType<Serialize>())
|
||||
{
|
||||
if ((attribute.isSaveable && !attribute.defaultValue.Equals(value)) ||
|
||||
property.Attributes.OfType<Editable>().Any())
|
||||
{
|
||||
save = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!save) continue;
|
||||
}
|
||||
|
||||
string stringValue;
|
||||
string typeName;
|
||||
if (!supportedTypes.TryGetValue(value.GetType(), out typeName))
|
||||
{
|
||||
if (property.PropertyType.IsEnum)
|
||||
{
|
||||
stringValue = value.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to serialize the property \"" + property.Name + "\" of \"" + obj + "\" (type " + property.PropertyType + " not supported)");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (typeName)
|
||||
{
|
||||
case "float":
|
||||
//make sure the decimal point isn't converted to a comma or anything else
|
||||
stringValue = ((float)value).ToString("G", CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case "vector2":
|
||||
stringValue = XMLExtensions.Vector2ToString((Vector2)value);
|
||||
break;
|
||||
case "vector3":
|
||||
stringValue = XMLExtensions.Vector3ToString((Vector3)value);
|
||||
break;
|
||||
case "vector4":
|
||||
stringValue = XMLExtensions.Vector4ToString((Vector4)value);
|
||||
break;
|
||||
case "color":
|
||||
stringValue = XMLExtensions.ColorToString((Color)value);
|
||||
break;
|
||||
case "rectangle":
|
||||
stringValue = XMLExtensions.RectToString((Rectangle)value);
|
||||
break;
|
||||
default:
|
||||
stringValue = value.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
element.Add(new XAttribute(property.Name.ToLowerInvariant(), stringValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace Barotrauma
|
||||
|
||||
string val = element.Attribute(name).Value;
|
||||
|
||||
return ParseToVector2(val);
|
||||
return ParseVector2(val);
|
||||
}
|
||||
|
||||
public static Vector3 GetAttributeVector3(this XElement element, string name, Vector3 defaultValue)
|
||||
@@ -201,7 +201,7 @@ namespace Barotrauma
|
||||
|
||||
string val = element.Attribute(name).Value;
|
||||
|
||||
return ParseToVector3(val);
|
||||
return ParseVector3(val);
|
||||
}
|
||||
|
||||
public static Vector4 GetAttributeVector4(this XElement element, string name, Vector4 defaultValue)
|
||||
@@ -210,7 +210,7 @@ namespace Barotrauma
|
||||
|
||||
string val = element.Attribute(name).Value;
|
||||
|
||||
return ParseToVector4(val);
|
||||
return ParseVector4(val);
|
||||
}
|
||||
|
||||
public static string ElementInnerText(this XElement el)
|
||||
@@ -223,8 +223,40 @@ namespace Barotrauma
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
public static string Vector2ToString(Vector2 vector)
|
||||
{
|
||||
return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static Vector2 ParseToVector2(string stringVector2, bool errorMessages = true)
|
||||
public static string Vector3ToString(Vector3 vector, string format = "G")
|
||||
{
|
||||
return vector.X.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Z.ToString(format, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static string Vector4ToString(Vector4 vector, string format = "G")
|
||||
{
|
||||
return vector.X.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Z.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.W.ToString(format, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static string ColorToString(Color color)
|
||||
{
|
||||
return (color.R / 255.0f).ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
(color.G / 255.0f).ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
(color.B / 255.0f).ToString("G", CultureInfo.InvariantCulture) + "," +
|
||||
(color.A / 255.0f).ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static string RectToString(Rectangle rect)
|
||||
{
|
||||
return rect.X + "," + rect.Y + "," + rect.Width + "," + rect.Height;
|
||||
}
|
||||
|
||||
public static Vector2 ParseVector2(string stringVector2, bool errorMessages = true)
|
||||
{
|
||||
string[] components = stringVector2.Split(',');
|
||||
|
||||
@@ -237,18 +269,13 @@ namespace Barotrauma
|
||||
return vector;
|
||||
}
|
||||
|
||||
Single.TryParse(components[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.X);
|
||||
Single.TryParse(components[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Y);
|
||||
float.TryParse(components[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.X);
|
||||
float.TryParse(components[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Y);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static string Vector2ToString(Vector2 vector)
|
||||
{
|
||||
return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static Vector3 ParseToVector3(string stringVector3, bool errorMessages = true)
|
||||
public static Vector3 ParseVector3(string stringVector3, bool errorMessages = true)
|
||||
{
|
||||
string[] components = stringVector3.Split(',');
|
||||
|
||||
@@ -268,7 +295,7 @@ namespace Barotrauma
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static Vector4 ParseToVector4(string stringVector4, bool errorMessages = true)
|
||||
public static Vector4 ParseVector4(string stringVector4, bool errorMessages = true)
|
||||
{
|
||||
string[] components = stringVector4.Split(',');
|
||||
|
||||
@@ -289,7 +316,7 @@ namespace Barotrauma
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static Color ParseToColor(string stringColor, bool errorMessages = true)
|
||||
public static Color ParseColor(string stringColor, bool errorMessages = true)
|
||||
{
|
||||
string[] strComponents = stringColor.Split(',');
|
||||
|
||||
@@ -311,15 +338,29 @@ namespace Barotrauma
|
||||
return new Color(components[0], components[1], components[2], components[3]);
|
||||
}
|
||||
|
||||
public static string Vector4ToString(Vector4 vector, string format = "G")
|
||||
public static Color ParseRect(string stringColor, bool errorMessages = true)
|
||||
{
|
||||
return vector.X.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Y.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.Z.ToString(format, CultureInfo.InvariantCulture) + "," +
|
||||
vector.W.ToString(format, CultureInfo.InvariantCulture);
|
||||
string[] strComponents = stringColor.Split(',');
|
||||
|
||||
Color color = Color.White;
|
||||
|
||||
if (strComponents.Length < 3)
|
||||
{
|
||||
if (errorMessages) DebugConsole.ThrowError("Failed to parse the string \"" + stringColor + "\" to Color");
|
||||
return Color.White;
|
||||
}
|
||||
|
||||
float[] components = new float[4] { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
for (int i = 0; i < 4 && i < strComponents.Length; i++)
|
||||
{
|
||||
float.TryParse(strComponents[i], NumberStyles.Float, CultureInfo.InvariantCulture, out components[i]);
|
||||
}
|
||||
|
||||
return new Color(components[0], components[1], components[2], components[3]);
|
||||
}
|
||||
|
||||
public static float[] ParseArrayToFloat(string[] stringArray)
|
||||
public static float[] ParseFloatArray(string[] stringArray)
|
||||
{
|
||||
if (stringArray == null || stringArray.Length == 0) return null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user