Build 1.1.4.0
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -10,6 +12,8 @@ namespace Barotrauma
|
||||
{
|
||||
public Identifier VariantOf { get; }
|
||||
|
||||
public T? ParentPrefab { get; set; }
|
||||
|
||||
public void InheritFrom(T parent);
|
||||
}
|
||||
|
||||
@@ -20,8 +24,10 @@ namespace Barotrauma
|
||||
#warning TODO: fix %ModDir% instances in the base element such that they become %ModDir:BaseMod% if necessary
|
||||
return variantElement.Element.CreateVariantXML(baseElement.Element).FromPackage(variantElement.ContentPackage);
|
||||
}
|
||||
|
||||
public static XElement CreateVariantXML(this XElement variantElement, XElement baseElement)
|
||||
|
||||
public delegate void VariantXMLChecker(XElement originalElement, XElement? variantElement, XElement result);
|
||||
|
||||
public static XElement CreateVariantXML(this XElement variantElement, XElement baseElement, VariantXMLChecker? checker = null)
|
||||
{
|
||||
XElement newElement = new XElement(variantElement.Name);
|
||||
newElement.Add(baseElement.Attributes());
|
||||
@@ -31,6 +37,9 @@ namespace Barotrauma
|
||||
|
||||
void ReplaceElement(XElement element, XElement replacement)
|
||||
{
|
||||
XElement originalElement = new XElement(element);
|
||||
|
||||
List<XElement> newElementsFromBase = new List<XElement>(element.Elements());
|
||||
List<XElement> elementsToRemove = new List<XElement>();
|
||||
foreach (XAttribute attribute in replacement.Attributes())
|
||||
{
|
||||
@@ -48,6 +57,7 @@ namespace Barotrauma
|
||||
if (replacementSubElement.Name.ToString().Equals("clear", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
matchingElementFound = true;
|
||||
newElementsFromBase.Clear();
|
||||
elementsToRemove.AddRange(element.Elements());
|
||||
break;
|
||||
}
|
||||
@@ -65,6 +75,7 @@ namespace Barotrauma
|
||||
ReplaceElement(subElement, replacementSubElement);
|
||||
}
|
||||
matchingElementFound = true;
|
||||
newElementsFromBase.Remove(subElement);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
@@ -75,11 +86,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
elementsToRemove.ForEach(e => e.Remove());
|
||||
checker?.Invoke(originalElement, replacement, element);
|
||||
foreach (XElement newElement in newElementsFromBase)
|
||||
{
|
||||
checker?.Invoke(newElement, null, newElement);
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceAttribute(XElement element, XAttribute newAttribute)
|
||||
{
|
||||
XAttribute existingAttribute = element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals(newAttribute.Name.ToString(), StringComparison.OrdinalIgnoreCase));
|
||||
XAttribute? existingAttribute = element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals(newAttribute.Name.ToString(), StringComparison.OrdinalIgnoreCase));
|
||||
if (existingAttribute == null)
|
||||
{
|
||||
element.Add(newAttribute);
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Barotrauma
|
||||
|
||||
public Node? AddNodeAndInheritors(Identifier id)
|
||||
{
|
||||
if (!prefabCollection.TryGet(id, out T? prefab)) { return null; }
|
||||
if (!prefabCollection.TryGet(id, out T? _, requireInheritanceValid: false)) { return null; }
|
||||
|
||||
if (!IdToNode.TryGetValue(id, out var node))
|
||||
{
|
||||
@@ -139,24 +139,25 @@ namespace Barotrauma
|
||||
//all inheritors so let's just return this immediately
|
||||
return node;
|
||||
}
|
||||
|
||||
prefabCollection
|
||||
.Cast<IImplementsVariants<T>>()
|
||||
.Where(p => p.VariantOf == id)
|
||||
.Cast<T>()
|
||||
.ForEach(p =>
|
||||
{
|
||||
var inheritorNode = AddNodeAndInheritors(p.Identifier);
|
||||
if (inheritorNode is null) { return; }
|
||||
RootNodes.Remove(inheritorNode);
|
||||
inheritorNode.Parent = node;
|
||||
node.Inheritors.Add(inheritorNode);
|
||||
});
|
||||
|
||||
var enumerator = prefabCollection.GetEnumerator(requireInheritanceValid: false);
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
T p = enumerator.Current;
|
||||
if (p is not IImplementsVariants<T> implementsVariants || implementsVariants.VariantOf != id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var inheritorNode = AddNodeAndInheritors(p.Identifier);
|
||||
if (inheritorNode is null) { continue; }
|
||||
RootNodes.Remove(inheritorNode);
|
||||
inheritorNode.Parent = node;
|
||||
node.Inheritors.Add(inheritorNode);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private void FindCycles(in Node node, HashSet<Node> uncheckedNodes)
|
||||
private static void FindCycles(in Node node, HashSet<Node> uncheckedNodes)
|
||||
{
|
||||
HashSet<Node> checkedNodes = new HashSet<Node>();
|
||||
List<Node> hierarchyPositions = new List<Node>();
|
||||
@@ -183,24 +184,45 @@ namespace Barotrauma
|
||||
public void InvokeCallbacks()
|
||||
{
|
||||
HashSet<Node> uncheckedNodes = IdToNode.Values.ToHashSet();
|
||||
IdToNode.Values.ForEach(v => FindCycles(v, uncheckedNodes));
|
||||
IdToNode.Values.ForEach(v => PrefabCollection<T>.InheritanceTreeCollection.FindCycles(v, uncheckedNodes));
|
||||
void invokeCallbacksForNode(Node node)
|
||||
{
|
||||
if (!prefabCollection.TryGet(node.Identifier, out var p) ||
|
||||
!(p is IImplementsVariants<T> prefab)) { return; }
|
||||
if (!prefab.VariantOf.IsEmpty && prefabCollection.TryGet(prefab.VariantOf, out T? parent)) { prefab.InheritFrom(parent!); }
|
||||
if (!prefabCollection.TryGet(node.Identifier, out var p, requireInheritanceValid: false) ||
|
||||
p is not IImplementsVariants<T> prefab) { return; }
|
||||
if (!prefab.VariantOf.IsEmpty && prefabCollection.TryGet(prefab.VariantOf, out T? parent, requireInheritanceValid: false))
|
||||
{
|
||||
prefab.InheritFrom(parent);
|
||||
prefab.ParentPrefab = parent;
|
||||
}
|
||||
node.Inheritors.ForEach(invokeCallbacksForNode);
|
||||
}
|
||||
RootNodes.ForEach(invokeCallbacksForNode);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsInheritanceValid(T? prefab)
|
||||
{
|
||||
if (prefab == null) { return false; }
|
||||
return
|
||||
prefab is not IImplementsVariants<T> implementsVariants ||
|
||||
(implementsVariants.VariantOf.IsEmpty || (implementsVariants.ParentPrefab != null && IsInheritanceValid(implementsVariants.ParentPrefab)));
|
||||
}
|
||||
|
||||
private void HandleInheritance(Identifier prefabIdentifier)
|
||||
=> HandleInheritance(prefabIdentifier.ToEnumerable());
|
||||
|
||||
private void HandleInheritance(IEnumerable<Identifier> identifiers)
|
||||
{
|
||||
if (!implementsVariants) { return; }
|
||||
foreach (var id in identifiers)
|
||||
{
|
||||
if (!TryGet(id, out T? prefab, requireInheritanceValid: false)) { continue; }
|
||||
if (prefab is IImplementsVariants<T> implementsVariants && !implementsVariants.VariantOf.IsEmpty)
|
||||
{
|
||||
//reset parent prefab, it'll get set in InvokeCallbacks if the inheritance is valid
|
||||
implementsVariants.ParentPrefab = null;
|
||||
}
|
||||
}
|
||||
InheritanceTreeCollection inheritanceTreeCollection = new InheritanceTreeCollection(this);
|
||||
inheritanceTreeCollection.AddNodesAndInheritors(identifiers);
|
||||
inheritanceTreeCollection.InvokeCallbacks();
|
||||
@@ -213,9 +235,11 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var prefab in prefabs)
|
||||
foreach (var kvp in prefabs)
|
||||
{
|
||||
yield return prefab;
|
||||
var prefab = kvp.Value.ActivePrefab;
|
||||
if (!IsInheritanceValid(prefab)) { continue; }
|
||||
yield return kvp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +255,8 @@ namespace Barotrauma
|
||||
{
|
||||
Prefab.DisallowCallFromConstructor();
|
||||
var prefab = prefabs[identifier].ActivePrefab;
|
||||
if (prefab != null && !IsPrefabOverriddenByFile(prefab))
|
||||
if (prefab != null && !IsPrefabOverriddenByFile(prefab) &&
|
||||
IsInheritanceValid(prefab))
|
||||
{
|
||||
return prefab;
|
||||
}
|
||||
@@ -258,12 +283,17 @@ namespace Barotrauma
|
||||
/// <param name="result">The matching prefab (if one is found)</param>
|
||||
/// <returns>Whether a prefab with the identifier exists or not</returns>
|
||||
public bool TryGet(Identifier identifier, [NotNullWhen(true)] out T? result)
|
||||
{
|
||||
return TryGet(identifier, out result, requireInheritanceValid: true);
|
||||
}
|
||||
|
||||
private bool TryGet(Identifier identifier, [NotNullWhen(true)] out T? result, bool requireInheritanceValid)
|
||||
{
|
||||
Prefab.DisallowCallFromConstructor();
|
||||
if (prefabs.TryGetValue(identifier, out PrefabSelector<T>? selector))
|
||||
if (prefabs.TryGetValue(identifier, out PrefabSelector<T>? selector) && selector.ActivePrefab != null)
|
||||
{
|
||||
result = selector!.ActivePrefab;
|
||||
return true;
|
||||
return !requireInheritanceValid || IsInheritanceValid(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -304,7 +334,7 @@ namespace Barotrauma
|
||||
public bool ContainsKey(Identifier identifier)
|
||||
{
|
||||
Prefab.DisallowCallFromConstructor();
|
||||
return prefabs.ContainsKey(identifier);
|
||||
return TryGet(identifier, out _);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string k) => prefabs.ContainsKey(k.ToIdentifier());
|
||||
@@ -460,6 +490,19 @@ namespace Barotrauma
|
||||
topMostOverrideFile = overrideFiles.Any() ? overrideFiles.First(f1 => overrideFiles.All(f2 => f1.ContentPackage.Index >= f2.ContentPackage.Index)) : null;
|
||||
OnSort?.Invoke();
|
||||
HandleInheritance(this.Select(p => p.Identifier));
|
||||
|
||||
var enumerator = GetEnumerator(requireInheritanceValid: false);
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
T p = enumerator.Current;
|
||||
if (p is IImplementsVariants<T> implementsVariants && !IsInheritanceValid(p))
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Error in content package \"{p.ContentFile.ContentPackage.Name}\": " +
|
||||
$"could not find the prefab \"{implementsVariants.VariantOf}\" the prefab \"{p.Identifier}\" is configured as a variant of.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -467,15 +510,19 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
/// <returns>IEnumerator</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetEnumerator(requireInheritanceValid: true);
|
||||
}
|
||||
|
||||
private IEnumerator<T> GetEnumerator(bool requireInheritanceValid)
|
||||
{
|
||||
Prefab.DisallowCallFromConstructor();
|
||||
foreach (var kpv in prefabs)
|
||||
foreach (var kvp in prefabs)
|
||||
{
|
||||
var prefab = kpv.Value.ActivePrefab;
|
||||
if (prefab != null && !IsPrefabOverriddenByFile(prefab))
|
||||
{
|
||||
yield return prefab;
|
||||
}
|
||||
var prefab = kvp.Value.ActivePrefab;
|
||||
if (prefab == null || IsPrefabOverriddenByFile(prefab)) { continue; }
|
||||
if (requireInheritanceValid && !IsInheritanceValid(prefab)) { continue; }
|
||||
yield return prefab;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +532,7 @@ namespace Barotrauma
|
||||
/// <returns>IEnumerator</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
return GetEnumerator(requireInheritanceValid: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user