Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -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);
}
}
}