4 using System.Collections.Generic;
5 using System.Globalization;
20 public static class VariantExtensions
24 #warning TODO: fix %ModDir% instances in the base element such that they become %ModDir:BaseMod% if necessary
28 public delegate
void VariantXMLChecker(XElement originalElement, XElement? variantElement, XElement result);
30 public static XElement CreateVariantXML(
this XElement variantElement, XElement baseElement, VariantXMLChecker? checker =
null)
32 XElement newElement =
new XElement(variantElement.Name);
33 newElement.Add(baseElement.Attributes());
34 newElement.Add(baseElement.Elements());
36 ReplaceElement(newElement, variantElement);
38 void ReplaceElement(XElement element, XElement replacement)
40 XElement originalElement =
new XElement(element);
42 List<XElement> newElementsFromBase =
new List<XElement>(element.Elements());
43 List<XElement> elementsToRemove =
new List<XElement>();
44 foreach (XAttribute attribute
in replacement.Attributes())
46 ReplaceAttribute(element, attribute);
48 foreach (XElement replacementSubElement
in replacement.Elements())
50 int index = replacement.Elements().ToList().FindAll(e => e.Name.ToString().Equals(replacementSubElement.Name.ToString(), StringComparison.OrdinalIgnoreCase)).IndexOf(replacementSubElement);
51 System.Diagnostics.Debug.Assert(index > -1);
54 bool matchingElementFound =
false;
55 foreach (var subElement
in element.Elements())
57 if (replacementSubElement.Name.ToString().Equals(
"clear", StringComparison.OrdinalIgnoreCase))
59 matchingElementFound =
true;
60 newElementsFromBase.Clear();
61 elementsToRemove.AddRange(element.Elements());
64 if (!subElement.Name.ToString().Equals(replacementSubElement.Name.ToString(), StringComparison.OrdinalIgnoreCase)) {
continue; }
67 if (!replacementSubElement.HasAttributes && !replacementSubElement.HasElements)
71 elementsToRemove.Add(subElement);
75 ReplaceElement(subElement, replacementSubElement);
77 matchingElementFound =
true;
78 newElementsFromBase.Remove(subElement);
83 if (!matchingElementFound)
85 element.Add(replacementSubElement);
88 elementsToRemove.ForEach(e => e.Remove());
89 checker?.Invoke(originalElement, replacement, element);
90 foreach (XElement newElement
in newElementsFromBase)
92 checker?.Invoke(newElement,
null, newElement);
96 void ReplaceAttribute(XElement element, XAttribute newAttribute)
98 XAttribute? existingAttribute = element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals(newAttribute.Name.ToString(), StringComparison.OrdinalIgnoreCase));
99 if (existingAttribute ==
null)
101 element.Add(newAttribute);
104 float.TryParse(existingAttribute.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out
float value);
105 if (newAttribute.Value.StartsWith(
'*'))
107 string multiplierStr = newAttribute.Value.Substring(1, newAttribute.Value.Length - 1);
108 float.TryParse(multiplierStr, NumberStyles.Any, CultureInfo.InvariantCulture, out
float multiplier);
109 if (multiplierStr.Contains(
'.') || existingAttribute.Value.Contains(
'.'))
111 existingAttribute.Value = (value * multiplier).ToString(
"G", CultureInfo.InvariantCulture);
115 existingAttribute.Value = ((int)(value * multiplier)).ToString();
118 else if (newAttribute.Value.StartsWith(
'+'))
120 string additionStr = newAttribute.Value.Substring(1, newAttribute.Value.Length - 1);
121 float.TryParse(additionStr, NumberStyles.Any, CultureInfo.InvariantCulture, out
float addition);
122 if (additionStr.Contains(
'.') || existingAttribute.Value.Contains(
'.'))
124 existingAttribute.Value = (value + addition).ToString(
"G", CultureInfo.InvariantCulture);
128 existingAttribute.Value = ((int)(value + addition)).ToString();
133 existingAttribute.Value = newAttribute.Value;
ContentPackage? ContentPackage
readonly XElement Element
void InheritFrom(T parent)