3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
6 using System.Collections.Immutable;
7 using System.ComponentModel;
8 using System.Globalization;
10 using System.Reflection;
11 using System.Xml.Linq;
21 [AttributeUsage(AttributeTargets.Property)]
43 public Serialize(
object defaultValue,
IsPropertySaveable isSaveable,
string description =
"",
string translationTextTag =
"",
bool alwaysUseInstanceValues =
false)
53 [AttributeUsage(AttributeTargets.Property)]
54 public sealed
class Header : Attribute
58 public Header(
string text =
"",
string localizedTextTag =
null)
60 Text = localizedTextTag !=
null ? TextManager.Get(localizedTextTag) : text;
66 private static readonly ImmutableDictionary<Type, string> supportedTypes =
new Dictionary<Type, string>
68 { typeof(
bool),
"bool" },
69 { typeof(
int),
"int" },
70 { typeof(
float),
"float" },
71 { typeof(
string),
"string" },
72 { typeof(Identifier),
"identifier" },
75 { typeof(Point),
"point" },
76 { typeof(Vector2),
"vector2" },
77 { typeof(Vector3),
"vector3" },
78 { typeof(Vector4),
"vector4" },
80 { typeof(Color),
"color" },
81 { typeof(
string[]),
"stringarray" },
82 { typeof(Identifier[]),
"identifierarray" }
83 }.ToImmutableDictionary();
85 private static readonly Dictionary<Type, Dictionary<Identifier, SerializableProperty>> cachedProperties =
86 new Dictionary<Type, Dictionary<Identifier, SerializableProperty>>();
87 public readonly
string Name;
98 PropertyInfo =
property.ComponentType.GetProperty(property.Name);
108 if (a is T)
return (T)a;
114 public void SetValue(
object parentObject,
object val)
121 if (value ==
null) {
return false; }
123 if (!supportedTypes.TryGetValue(
PropertyType, out
string typeName))
130 enumVal = Enum.Parse(
PropertyInfo.PropertyType, value,
true);
134 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value} (not a valid {PropertyInfo.PropertyType})", e);
143 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value}", e);
149 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value} (Type \"{PropertyType.Name}\" not supported)");
160 bool boolValue = value.ToIdentifier() ==
"true";
161 if (TrySetBoolValueWithoutReflection(parentObject, boolValue)) {
return true; }
165 if (
int.TryParse(value, out
int intVal))
167 if (TrySetFloatValueWithoutReflection(parentObject, intVal)) {
return true; }
176 if (
float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out
float floatVal))
178 if (TrySetFloatValueWithoutReflection(parentObject, floatVal)) {
return true; }
190 PropertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint(value));
193 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2(value));
196 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseVector3(value));
199 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseVector4(value));
202 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseColor(value));
205 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseRect(value,
true));
208 PropertyInfo.SetValue(parentObject, value.ToIdentifier());
210 case "languageidentifier":
211 PropertyInfo.SetValue(parentObject, value.ToLanguageIdentifier());
213 case "localizedstring":
217 PropertyInfo.SetValue(parentObject, ParseStringArray(value));
219 case "identifierarray":
220 PropertyInfo.SetValue(parentObject, ParseIdentifierArray(value));
226 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value}", e);
233 private static string[] ParseStringArray(
string stringArrayValues)
235 return string.IsNullOrEmpty(stringArrayValues) ? Array.Empty<
string>() : stringArrayValues.Split(
';');
238 private static Identifier[] ParseIdentifierArray(
string stringArrayValues)
240 return ParseStringArray(stringArrayValues).ToIdentifiers();
245 if (value ==
null || parentObject ==
null ||
PropertyInfo ==
null)
return false;
249 if (!supportedTypes.TryGetValue(
PropertyType, out
string typeName))
256 enumVal = Enum.Parse(
PropertyInfo.PropertyType, value.ToString(),
true);
260 DebugConsole.ThrowError(
261 $
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value} (not a valid {PropertyInfo.PropertyType})", e);
269 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value} (Type \"{PropertyType.Name}\" not supported)");
277 if (value.GetType() == typeof(
string))
285 PropertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint((
string)value));
288 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2((
string)value));
291 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseVector3((
string)value));
294 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseVector4((
string)value));
297 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseColor((
string)value));
300 PropertyInfo.SetValue(parentObject, XMLExtensions.ParseRect((
string)value,
false));
303 PropertyInfo.SetValue(parentObject,
new Identifier((
string)value));
305 case "languageidentifier":
306 PropertyInfo.SetValue(parentObject, ((
string)value).ToLanguageIdentifier());
308 case "localizedstring":
312 PropertyInfo.SetValue(parentObject, ParseStringArray((
string)value));
314 case "identifierarray":
315 PropertyInfo.SetValue(parentObject, ParseIdentifierArray((
string)value));
318 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value}");
319 DebugConsole.ThrowError($
"(Cannot convert a string to a {PropertyType})");
325 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value}");
326 DebugConsole.ThrowError(
"(Non-matching type, should be " +
PropertyType +
" instead of " + value.GetType() +
")");
335 DebugConsole.ThrowError($
"Failed to set the value of the property \"{Name}\" of \"{parentObject}\" to {value}", e);
343 DebugConsole.ThrowError($
"Error in SerializableProperty.TrySetValue (Property: {PropertyInfo.Name})", e);
352 if (TrySetFloatValueWithoutReflection(parentObject, value)) {
return true; }
355 catch (TargetInvocationException e)
357 DebugConsole.ThrowError(
"Exception thrown by the target of SerializableProperty.TrySetValue", e.InnerException);
362 DebugConsole.ThrowError($
"Error in SerializableProperty.TrySetValue (Property: {PropertyInfo.Name})", e);
373 if (TrySetBoolValueWithoutReflection(parentObject, value)) {
return true; }
376 catch (TargetInvocationException e)
378 DebugConsole.ThrowError(
"Exception thrown by the target of SerializableProperty.TrySetValue", e.InnerException);
383 DebugConsole.ThrowError($
"Error in SerializableProperty.TrySetValue (Property: {PropertyInfo.Name})", e);
393 if (TrySetFloatValueWithoutReflection(parentObject, value)) {
return true; }
396 catch (TargetInvocationException e)
398 DebugConsole.ThrowError(
"Exception thrown by the target of SerializableProperty.TrySetValue", e.InnerException);
403 DebugConsole.ThrowError($
"Error in SerializableProperty.TrySetValue (Property: {PropertyInfo.Name})", e);
411 if (parentObject ==
null ||
PropertyInfo ==
null) {
return false; }
413 var value = TryGetValueWithoutReflection(parentObject);
414 if (value !=
null) {
return value; }
420 catch (TargetInvocationException e)
422 DebugConsole.ThrowError(
"Exception thrown by the target of SerializableProperty.GetValue", e.InnerException);
427 DebugConsole.ThrowError(
"Error in SerializableProperty.GetValue", e);
434 if (parentObject ==
null ||
PropertyInfo ==
null) {
return 0.0f; }
436 if (TryGetFloatValueWithoutReflection(parentObject, out
float value))
449 return (
float)
PropertyInfo.GetValue(parentObject,
null);
452 catch (TargetInvocationException e)
454 DebugConsole.ThrowError(
"Exception thrown by the target of SerializableProperty.GetValue", e.InnerException);
459 DebugConsole.ThrowError(
"Error in SerializableProperty.GetValue", e);
466 if (parentObject ==
null ||
PropertyInfo ==
null) {
return false; }
468 if (TryGetBoolValueWithoutReflection(parentObject, out
bool value))
477 catch (TargetInvocationException e)
479 DebugConsole.ThrowError(
"Exception thrown by the target of SerializableProperty.GetValue", e.InnerException);
484 DebugConsole.ThrowError(
"Error in SerializableProperty.GetValue", e);
491 if (type.IsEnum) {
return "Enum"; }
492 if (!supportedTypes.TryGetValue(type, out
string typeName))
499 private readonly ImmutableDictionary<Identifier, Func<object, object>> valueGetters =
500 new Dictionary<Identifier, Func<object, object>>()
502 {
"Voltage".ToIdentifier(), (obj) => obj is
Powered p ? p.
Voltage : (
object)
null},
506 {
"FissionRate".ToIdentifier(), (obj) => obj is
Reactor r ? r.
FissionRate : (
object)
null},
507 {
"OxygenFlow".ToIdentifier(), (obj) => obj is
Vent v ? v.
OxygenFlow : (
object)
null},
509 "CurrFlow".ToIdentifier(),
514 {
"CurrentVolume".ToIdentifier(), (obj) => obj is
Engine e ? e.
CurrentVolume : (
object)
null},
516 {
"Oxygen".ToIdentifier(), (obj) => obj is Character c ? c.Oxygen : (
object)
null},
517 {
"Health".ToIdentifier(), (obj) => obj is Character c ? c.Health : (
object)
null},
518 {
"OxygenAvailable".ToIdentifier(), (obj) => obj is Character c ? c.OxygenAvailable : (
object)
null},
519 {
"PressureProtection".ToIdentifier(), (obj) => obj is Character c ? c.PressureProtection : (
object)
null},
520 {
"IsDead".ToIdentifier(), (obj) => obj is Character c ? c.IsDead : (
object)
null},
521 {
"IsHuman".ToIdentifier(), (obj) => obj is Character c ? c.IsHuman : (
object)
null},
523 {
"Condition".ToIdentifier(), (obj) => obj is Item i ? i.Condition : (
object)
null},
524 {
"ContainerIdentifier".ToIdentifier(), (obj) => obj is Item i ? i.ContainerIdentifier : (
object)
null},
525 {
"PhysicsBodyActive".ToIdentifier(), (obj) => obj is Item i ? i.PhysicsBodyActive : (
object)
null},
526 }.ToImmutableDictionary();
531 private object TryGetValueWithoutReflection(
object parentObject)
535 if (TryGetFloatValueWithoutReflection(parentObject, out
float value)) {
return value; }
539 if (TryGetBoolValueWithoutReflection(parentObject, out
bool value)) {
return value; }
543 if (TryGetStringValueWithoutReflection(parentObject, out
string value)) {
return value; }
551 private bool TryGetFloatValueWithoutReflection(
object parentObject, out
float value)
558 if (parentObject is
Powered powered) { value = powered.Voltage;
return true; }
563 if (parentObject is
Powered powered) { value = powered.RelativeVoltage;
return true; }
568 if (parentObject is
Powered powered) { value = powered.CurrPowerConsumption;
return true; }
573 if (parentObject is
PowerContainer powerContainer) { value = powerContainer.Charge;
return true; }
578 if (parentObject is
PowerContainer powerContainer) { value = powerContainer.ChargePercentage;
return true; }
583 if (parentObject is
PowerContainer powerContainer) { value = powerContainer.RechargeRatio;
return true; }
587 {
if (parentObject is
Reactor reactor) { value = reactor.AvailableFuel;
return true; } }
590 {
if (parentObject is
Reactor reactor) { value = reactor.FissionRate;
return true; } }
593 {
if (parentObject is
Reactor reactor) { value = reactor.Temperature;
return true; } }
596 if (parentObject is
Vent vent) { value = vent.OxygenFlow;
return true; }
599 {
if (parentObject is
Pump pump) { value = pump.CurrFlow;
return true; } }
600 if (parentObject is
OxygenGenerator oxygenGenerator) { value = oxygenGenerator.CurrFlow;
return true; }
603 {
if (parentObject is
Engine engine) { value = engine.CurrentBrokenVolume;
return true; } }
604 {
if (parentObject is
Pump pump) { value = pump.CurrentBrokenVolume;
return true; } }
607 {
if (parentObject is
Engine engine) { value = engine.CurrentVolume;
return true; } }
610 {
if (parentObject is Character character) { value = character.Oxygen;
return true; } }
611 {
if (parentObject is Hull hull) { value = hull.Oxygen;
return true; } }
614 {
if (parentObject is Character character) { value = character.Health;
return true; } }
617 {
if (parentObject is Character character) { value = character.OxygenAvailable;
return true; } }
619 case nameof(
Character.PressureProtection):
620 {
if (parentObject is Character character) { value = character.PressureProtection;
return true; } }
622 case nameof(
Item.Condition):
623 {
if (parentObject is Item item) { value = item.Condition;
return true; } }
626 {
if (parentObject is Character character) { value = character.SpeedMultiplier;
return true; } }
628 case nameof(
Character.PropulsionSpeedMultiplier):
629 {
if (parentObject is Character character) { value = character.PropulsionSpeedMultiplier;
return true; } }
631 case nameof(
Character.LowPassMultiplier):
632 {
if (parentObject is Character character) { value = character.LowPassMultiplier;
return true; } }
634 case nameof(
Character.HullOxygenPercentage):
636 if (parentObject is Character character)
638 value = character.HullOxygenPercentage;
641 else if (parentObject is Item item)
643 value = item.HullOxygenPercentage;
649 {
if (parentObject is
Door door) { value = door.Stuck;
return true; } }
658 private bool TryGetBoolValueWithoutReflection(
object parentObject, out
bool value)
664 if (parentObject is
ItemComponent ic) { value = ic.IsActive;
return true; }
667 if (parentObject is
PowerTransfer powerTransfer) { value = powerTransfer.Overload;
return true; }
670 if (parentObject is
MotionSensor motionSensor) { value = motionSensor.MotionDetected;
return true; }
673 {
if (parentObject is Character character) { value = character.IsDead;
return true; } }
676 {
if (parentObject is Character character) { value = character.IsHuman;
return true; } }
679 {
if (parentObject is
LightComponent lightComponent) { value = lightComponent.IsOn;
return true; } }
681 case nameof(
Item.PhysicsBodyActive):
683 if (parentObject is Item item) { value = item.PhysicsBodyActive;
return true; }
687 if (parentObject is
DockingPort dockingPort) { value = dockingPort.Docked;
return true; }
690 if (parentObject is
Reactor reactor) { value = reactor.TemperatureCritical;
return true; }
693 if (parentObject is
TriggerComponent trigger) { value = trigger.TriggerActive;
return true; }
696 if (parentObject is
Controller controller) { value = controller.State;
return true; }
700 if (parentObject is Character character)
702 value = character.InWater;
705 else if (parentObject is Item item)
707 value = item.InWater;
713 if (parentObject is
Rope rope) { value = rope.Snapped;
return true; }
722 private bool TryGetStringValueWithoutReflection(
object parentObject, out
string value)
727 case nameof(
Item.ContainerIdentifier):
729 if (parentObject is Item item) { value = item.ContainerIdentifier.Value;
return true; }
739 private bool TrySetFloatValueWithoutReflection(
object parentObject,
float value)
743 case nameof(
Item.Condition):
744 {
if (parentObject is Item item) { item.Condition = value;
return true; } }
747 if (parentObject is
Powered powered) { powered.Voltage = value;
return true; }
750 if (parentObject is
PowerContainer powerContainer) { powerContainer.Charge = value;
return true; }
753 if (parentObject is
Reactor reactor) { reactor.AvailableFuel = value;
return true; }
756 {
if (parentObject is Character character) { character.Oxygen = value;
return true; } }
759 {
if (parentObject is Character character) { character.OxygenAvailable = value;
return true; } }
761 case nameof(
Character.PressureProtection):
762 {
if (parentObject is Character character) { character.PressureProtection = value;
return true; } }
764 case nameof(
Character.LowPassMultiplier):
765 {
if (parentObject is Character character) { character.LowPassMultiplier = value;
return true; } }
768 {
if (parentObject is Character character) { character.StackSpeedMultiplier(value);
return true; } }
771 {
if (parentObject is Character character) { character.StackHealthMultiplier(value);
return true; } }
773 case nameof(
Character.PropulsionSpeedMultiplier):
774 {
if (parentObject is Character character) { character.PropulsionSpeedMultiplier = value;
return true; } }
776 case nameof(
Character.ObstructVisionAmount):
777 {
if (parentObject is Character character) { character.ObstructVisionAmount = value;
return true; } }
779 case nameof(
Item.Scale):
780 {
if (parentObject is Item item) { item.Scale = value;
return true; } }
788 private bool TrySetBoolValueWithoutReflection(
object parentObject,
bool value)
793 {
if (parentObject is Character character) { character.ObstructVision = value;
return true; } }
796 {
if (parentObject is Character character) { character.HideFace = value;
return true; } }
799 {
if (parentObject is Character character) { character.UseHullOxygen = value;
return true; } }
802 {
if (parentObject is
LightComponent lightComponent) { lightComponent.IsOn = value;
return true; } }
805 {
if (parentObject is
ItemComponent ic) { ic.IsActive = value;
return true; } }
813 List<SerializableProperty> editableProperties =
new List<SerializableProperty>();
814 foreach (var property
in obj.SerializableProperties.Values)
816 if (property.Attributes.OfType<T>().Any()) editableProperties.Add(property);
819 return editableProperties;
822 public static Dictionary<Identifier, SerializableProperty>
GetProperties(
object obj)
824 Type objType = obj.GetType();
825 if (cachedProperties.ContainsKey(objType))
827 return cachedProperties[objType];
830 var properties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();
831 Dictionary<Identifier, SerializableProperty> dictionary =
new Dictionary<Identifier, SerializableProperty>();
832 foreach (var property
in properties)
835 dictionary.Add(serializableProperty.Name.ToIdentifier(), serializableProperty);
838 cachedProperties[objType] = dictionary;
843 public static Dictionary<Identifier, SerializableProperty>
DeserializeProperties(
object obj, XElement element =
null)
845 Dictionary<Identifier, SerializableProperty> dictionary =
GetProperties(obj);
847 foreach (var property
in dictionary.Values)
850 foreach (var ini
in property.Attributes.OfType<
Serialize>())
852 property.TrySetValue(obj, ini.DefaultValue);
861 foreach (XAttribute attribute
in element.Attributes())
863 if (!dictionary.TryGetValue(attribute.NameAsIdentifier(), out
SerializableProperty property)) {
continue; }
864 if (!property.Attributes.OfType<
Serialize>().Any()) {
continue; }
865 property.TrySetValue(obj, attribute.Value);
874 var saveProperties = GetProperties<Serialize>(obj);
875 foreach (var property
in saveProperties)
877 object value =
property.GetValue(obj);
878 if (value ==
null)
continue;
886 foreach (var attribute
in property.Attributes.OfType<
Serialize>())
888 if ((attribute.IsSaveable ==
IsPropertySaveable.Yes && !attribute.DefaultValue.Equals(value)) ||
889 (!ignoreEditable && property.Attributes.OfType<
Editable>().Any()))
900 if (!supportedTypes.TryGetValue(value.GetType(), out
string typeName))
902 if (property.PropertyType.IsEnum)
904 stringValue = value.ToString();
908 DebugConsole.ThrowError(
"Failed to serialize the property \"" + property.Name +
"\" of \"" + obj +
"\" (type " + property.PropertyType +
" not supported)");
918 stringValue = ((float)value).ToString(
"G", CultureInfo.InvariantCulture);
921 stringValue = XMLExtensions.PointToString((Point)value);
924 stringValue = XMLExtensions.Vector2ToString((Vector2)value);
927 stringValue = XMLExtensions.Vector3ToString((Vector3)value);
930 stringValue = XMLExtensions.Vector4ToString((Vector4)value);
933 stringValue = XMLExtensions.ColorToString((Color)value);
936 stringValue = XMLExtensions.RectToString((
Rectangle)value);
939 string[] stringArray = (
string[])value;
940 stringValue = stringArray !=
null ?
string.Join(
';', stringArray) :
"";
942 case "identifierarray":
943 Identifier[] identifierArray = (Identifier[])value;
944 stringValue = identifierArray !=
null ?
string.Join(
';', identifierArray) :
"";
947 stringValue = value.ToString();
951 element.GetAttribute(property.Name)?.Remove();
952 element.SetAttributeValue(property.Name, stringValue);
965 foreach (var subElement
in configElement.Elements())
967 if (!subElement.Name.ToString().Equals(
"upgrade", StringComparison.OrdinalIgnoreCase)) {
continue; }
968 var upgradeVersion =
new Version(subElement.GetAttributeString(
"gameversion",
"0.0.0.0"));
969 if (subElement.GetAttributeBool(
"campaignsaveonly",
false))
975 if (savedVersion >= upgradeVersion) {
continue; }
977 foreach (XAttribute attribute
in subElement.Attributes())
979 var attributeName = attribute.NameAsIdentifier();
980 if (attributeName ==
"gameversion" || attributeName ==
"campaignsaveonly") {
continue; }
982 if (attributeName ==
"refreshrect")
986 if (!structure.ResizeHorizontal)
988 structure.Rect = structure.DefaultRect =
new Rectangle(structure.Rect.X, structure.Rect.Y,
989 (
int)structure.Prefab.ScaledSize.X,
990 structure.Rect.Height);
992 if (!structure.ResizeVertical)
994 structure.Rect = structure.DefaultRect =
new Rectangle(structure.Rect.X, structure.Rect.Y,
995 structure.Rect.Width,
996 (
int)structure.Prefab.ScaledSize.Y);
999 else if (entity is
Item item)
1001 if (!item.ResizeHorizontal)
1003 item.Rect = item.DefaultRect =
new Rectangle(item.Rect.X, item.Rect.Y,
1004 (
int)(item.Prefab.Size.X * item.Prefab.Scale),
1007 if (!item.ResizeVertical)
1009 item.Rect = item.DefaultRect =
new Rectangle(item.Rect.X, item.Rect.Y,
1011 (
int)(item.Prefab.Size.Y * item.Prefab.Scale));
1016 if (entity.SerializableProperties.TryGetValue(attributeName, out
SerializableProperty property))
1018 FixValue(property, entity, attribute);
1021 component.ParseMsg();
1024 else if (entity is
Item item1)
1030 FixValue(componentProperty, component, attribute);
1042 if (attribute.Value.Length > 0 && attribute.Value[0] ==
'*')
1044 float.TryParse(attribute.Value.Substring(1), NumberStyles.Float, CultureInfo.InvariantCulture, out
float multiplier);
1048 property.TrySetValue(parentObject, (
int)(((
int)property.
GetValue(parentObject)) * multiplier));
1052 property.TrySetValue(parentObject, (
float)property.
GetValue(parentObject) * multiplier);
1056 property.TrySetValue(parentObject, (Vector2)property.
GetValue(parentObject) * multiplier);
1060 property.TrySetValue(parentObject, ((Point)property.
GetValue(parentObject)).Multiply(multiplier));
1063 else if (attribute.Value.Length > 0 && attribute.Value[0] ==
'+')
1067 float.TryParse(attribute.Value.Substring(1), NumberStyles.Float, CultureInfo.InvariantCulture, out
float addition);
1068 property.TrySetValue(parentObject, (
int)(((
int)property.
GetValue(parentObject)) + addition));
1072 float.TryParse(attribute.Value.Substring(1), NumberStyles.Float, CultureInfo.InvariantCulture, out
float addition);
1073 property.TrySetValue(parentObject, (
float)property.
GetValue(parentObject) + addition);
1077 var addition = XMLExtensions.ParseVector2(attribute.Value.Substring(1));
1078 property.TrySetValue(parentObject, (Vector2)property.
GetValue(parentObject) + addition);
1082 var addition = XMLExtensions.ParsePoint(attribute.Value.Substring(1));
1083 property.TrySetValue(parentObject, ((Point)property.
GetValue(parentObject)) + addition);
1088 property.TrySetValue(parentObject, attribute.Value);
1092 if (entity is
Item item2)
1094 var componentElement = subElement.FirstElement();
1095 if (componentElement ==
null) {
continue; }
1096 ItemComponent itemComponent = item2.Components.FirstOrDefault(c => c.Name == componentElement.Name.ToString());
1097 if (itemComponent ==
null) {
continue; }
1098 foreach (XAttribute attribute
in componentElement.Attributes())
1100 var attributeName = attribute.NameAsIdentifier();
1101 if (itemComponent.SerializableProperties.TryGetValue(attributeName, out
SerializableProperty property))
1103 FixValue(property, itemComponent, attribute);
1106 foreach (var element
in componentElement.Elements())
1108 switch (element.Name.ToString().ToLowerInvariant())
1110 case "requireditem":
1111 case "requireditems":
1112 itemComponent.RequiredItems.Clear();
1113 itemComponent.DisabledRequiredItems.Clear();
1115 itemComponent.SetRequiredItems(element, allowEmpty:
true);
1120 (componentElement.GetChildElement(
"containable") !=
null || componentElement.GetChildElement(
"subcontainer") !=
null))
1122 itemContainer.ReloadContainableRestrictions(componentElement);
static GameSession?? GameSession
static readonly Version Version
float CurrentBrokenVolume
The base class for components holding the different functionalities of the item
float RelativeVoltage
Essentially Voltage / MinVoltage (= how much of the minimum required voltage has been satisfied),...
float CurrPowerConsumption
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
bool TrySetValue(object parentObject, string value)
readonly AttributeCollection Attributes
void SetValue(object parentObject, object val)
SerializableProperty(PropertyDescriptor property)
readonly PropertyInfo PropertyInfo
static string GetSupportedTypeName(Type type)
readonly Type PropertyType
float GetFloatValue(object parentObject)
object GetValue(object parentObject)
bool TrySetValue(object parentObject, object value)
static void UpgradeGameVersion(ISerializableEntity entity, ContentXElement configElement, Version savedVersion)
Upgrade the properties of an entity saved with an older version of the game. Properties that should b...
static List< SerializableProperty > GetProperties< T >(ISerializableEntity obj)
bool TrySetValue(object parentObject, float value)
bool TrySetValue(object parentObject, int value)
bool GetBoolValue(object parentObject)
bool TrySetValue(object parentObject, bool value)
static Dictionary< Identifier, SerializableProperty > GetProperties(object obj)
static void SerializeProperties(ISerializableEntity obj, XElement element, bool saveIfDefault=false, bool ignoreEditable=false)
readonly bool OverridePrefabValues
bool AlwaysUseInstanceValues
If set to true, the instance values saved in a submarine file will always override the prefab values,...
readonly IsPropertySaveable IsSaveable
readonly Identifier TranslationTextTag
Serialize(object defaultValue, IsPropertySaveable isSaveable, string description="", string translationTextTag="", bool alwaysUseInstanceValues=false)
Makes the property serializable to/from XML
readonly object DefaultValue
Dictionary< Identifier, SerializableProperty > SerializableProperties
@ Character
Characters only