4 using System.Collections.Generic;
5 using System.Globalization;
20 public static class VariantExtensions
22 public delegate
void VariantXMLChecker(XElement originalElement, XElement? variantElement, XElement result);
26 XElement newElement =
new XElement(baseElement);
34 foreach (var subElement
in newElement.Descendants())
36 foreach (var attribute
in subElement.Attributes())
48 ReplaceElement(newElement, variantElement);
50 void ReplaceElement(XElement element, XElement replacement)
52 XElement originalElement =
new XElement(element);
54 List<XElement> newElementsFromBase =
new List<XElement>(element.Elements());
55 List<XElement> elementsToRemove =
new List<XElement>();
56 foreach (XAttribute attribute
in replacement.Attributes())
58 ReplaceAttribute(element, attribute);
60 foreach (XElement replacementSubElement
in replacement.Elements())
62 int index = replacement.Elements().ToList().FindAll(e => e.Name.ToString().Equals(replacementSubElement.Name.ToString(), StringComparison.OrdinalIgnoreCase)).IndexOf(replacementSubElement);
63 System.Diagnostics.Debug.Assert(index > -1);
66 bool matchingElementFound =
false;
68 foreach (var subElement
in element.Elements())
70 if (replacementSubElement.Name.ToString().Equals(
"clear", StringComparison.OrdinalIgnoreCase))
72 matchingElementFound =
true;
73 newElementsFromBase.Clear();
74 elementsToRemove.AddRange(element.Elements());
76 foreach (var elementAfterClear
in replacementSubElement.ElementsAfterSelf())
78 element.Add(elementAfterClear);
83 if (!subElement.Name.ToString().Equals(replacementSubElement.Name.ToString(), StringComparison.OrdinalIgnoreCase)) {
continue; }
86 if (!replacementSubElement.HasAttributes && !replacementSubElement.HasElements)
90 elementsToRemove.Add(subElement);
94 ReplaceElement(subElement, replacementSubElement);
96 matchingElementFound =
true;
97 newElementsFromBase.Remove(subElement);
102 if (!matchingElementFound)
104 element.Add(replacementSubElement);
108 if (cleared) {
break; }
110 elementsToRemove.ForEach(e => e.Remove());
111 checker?.Invoke(originalElement, replacement, element);
112 foreach (XElement newElement
in newElementsFromBase)
114 checker?.Invoke(newElement,
null, newElement);
118 void ReplaceAttribute(XElement element, XAttribute newAttribute)
120 XAttribute? existingAttribute = element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals(newAttribute.Name.ToString(), StringComparison.OrdinalIgnoreCase));
121 if (existingAttribute ==
null)
123 element.Add(newAttribute);
126 float.TryParse(existingAttribute.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out
float value);
127 if (newAttribute.Value.StartsWith(
'*'))
129 string multiplierStr = newAttribute.Value.Substring(1, newAttribute.Value.Length - 1);
130 float.TryParse(multiplierStr, NumberStyles.Any, CultureInfo.InvariantCulture, out
float multiplier);
131 if (multiplierStr.Contains(
'.') || existingAttribute.Value.Contains(
'.'))
133 existingAttribute.Value = (value * multiplier).ToString(
"G", CultureInfo.InvariantCulture);
137 existingAttribute.Value = ((int)(value * multiplier)).ToString();
140 else if (newAttribute.Value.StartsWith(
'+'))
142 string additionStr = newAttribute.Value.Substring(1, newAttribute.Value.Length - 1);
143 float.TryParse(additionStr, NumberStyles.Any, CultureInfo.InvariantCulture, out
float addition);
144 if (additionStr.Contains(
'.') || existingAttribute.Value.Contains(
'.'))
146 existingAttribute.Value = (value + addition).ToString(
"G", CultureInfo.InvariantCulture);
150 existingAttribute.Value = ((int)(value + addition)).ToString();
155 existingAttribute.Value = newAttribute.Value;
const string OtherModDirFmt
ContentPackage? ContentPackage
void InheritFrom(T parent)