Make artifacts support saving (#14784)

This commit is contained in:
Nemanja
2023-03-23 22:50:24 -04:00
committed by GitHub
parent a0332c2f2e
commit 65acae15c0
7 changed files with 170 additions and 117 deletions

View File

@@ -1,6 +1,7 @@
using System.Linq;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Shared.Xenoarchaeology.XenoArtifacts;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager;
@@ -15,13 +16,15 @@ public sealed partial class ArtifactSystem
private const int MaxEdgesPerNode = 4;
private readonly HashSet<int> _usedNodeIds = new();
/// <summary>
/// Generate an Artifact tree with fully developed nodes.
/// </summary>
/// <param name="artifact"></param>
/// <param name="tree">The tree being generated.</param>
/// <param name="allNodes"></param>
/// <param name="nodeAmount">The amount of nodes it has.</param>
private void GenerateArtifactNodeTree(EntityUid artifact, ref ArtifactTree tree, int nodeAmount)
private void GenerateArtifactNodeTree(EntityUid artifact, ref List<ArtifactNode> allNodes, int nodeAmount)
{
if (nodeAmount < 1)
{
@@ -29,19 +32,36 @@ public sealed partial class ArtifactSystem
return;
}
var uninitializedNodes = new List<ArtifactNode> { new() };
tree.StartNode = uninitializedNodes.First(); //the first node
_usedNodeIds.Clear();
var rootNode = new ArtifactNode
{
Id = GetValidNodeId()
};
var uninitializedNodes = new List<ArtifactNode> { rootNode };
while (uninitializedNodes.Any())
{
GenerateNode(artifact, ref uninitializedNodes, ref tree, nodeAmount);
GenerateNode(artifact, ref uninitializedNodes, ref allNodes, nodeAmount);
}
}
private int GetValidNodeId()
{
var id = _random.Next(10000, 100000);
while (_usedNodeIds.Contains(id))
{
id = _random.Next(10000, 100000);
}
_usedNodeIds.Add(id);
return id;
}
/// <summary>
/// Generate an individual node on the tree.
/// </summary>
private void GenerateNode(EntityUid artifact, ref List<ArtifactNode> uninitializedNodes, ref ArtifactTree tree, int targetNodeAmount)
private void GenerateNode(EntityUid artifact, ref List<ArtifactNode> uninitializedNodes, ref List<ArtifactNode> allNodes, int targetNodeAmount)
{
if (!uninitializedNodes.Any())
return;
@@ -49,13 +69,10 @@ public sealed partial class ArtifactSystem
var node = uninitializedNodes.First();
uninitializedNodes.Remove(node);
//random 5-digit number
node.Id = _random.Next(10000, 100000);
//Generate the connected nodes
var maxEdges = Math.Max(1, targetNodeAmount - tree.AllNodes.Count - uninitializedNodes.Count - 1);
var maxEdges = Math.Max(1, targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1);
maxEdges = Math.Min(maxEdges, MaxEdgesPerNode);
var minEdges = Math.Clamp(targetNodeAmount - tree.AllNodes.Count - uninitializedNodes.Count - 1, 0, 1);
var minEdges = Math.Clamp(targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1, 0, 1);
var edgeAmount = _random.Next(minEdges, maxEdges);
@@ -63,10 +80,11 @@ public sealed partial class ArtifactSystem
{
var neighbor = new ArtifactNode
{
Depth = node.Depth + 1
Depth = node.Depth + 1,
Id = GetValidNodeId()
};
node.Edges.Add(neighbor);
neighbor.Edges.Add(node);
node.Edges.Add(neighbor.Id);
neighbor.Edges.Add(node.Id);
uninitializedNodes.Add(neighbor);
}
@@ -74,13 +92,13 @@ public sealed partial class ArtifactSystem
node.Trigger = GetRandomTrigger(artifact, ref node);
node.Effect = GetRandomEffect(artifact, ref node);
tree.AllNodes.Add(node);
allNodes.Add(node);
}
//yeah these two functions are near duplicates but i don't
//want to implement an interface or abstract parent
private ArtifactTriggerPrototype GetRandomTrigger(EntityUid artifact, ref ArtifactNode node)
private string GetRandomTrigger(EntityUid artifact, ref ArtifactNode node)
{
var allTriggers = _prototype.EnumeratePrototypes<ArtifactTriggerPrototype>()
.Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList();
@@ -91,10 +109,10 @@ public sealed partial class ArtifactSystem
var targetTriggers = allTriggers
.Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList();
return _random.Pick(targetTriggers);
return _random.Pick(targetTriggers).ID;
}
private ArtifactEffectPrototype GetRandomEffect(EntityUid artifact, ref ArtifactNode node)
private string GetRandomEffect(EntityUid artifact, ref ArtifactNode node)
{
var allEffects = _prototype.EnumeratePrototypes<ArtifactEffectPrototype>()
.Where(x => (x.Whitelist?.IsValid(artifact, EntityManager) ?? true) && (!x.Blacklist?.IsValid(artifact, EntityManager) ?? true)).ToList();
@@ -105,7 +123,7 @@ public sealed partial class ArtifactSystem
var targetEffects = allEffects
.Where(x => x.TargetDepth == selectedRandomTargetDepth).ToList();
return _random.Pick(targetEffects);
return _random.Pick(targetEffects).ID;
}
/// <remarks>
@@ -156,14 +174,17 @@ public sealed partial class ArtifactSystem
if (!Resolve(uid, ref component))
return;
if (component.CurrentNode != null)
if (component.CurrentNodeId != null)
{
ExitNode(uid, component);
}
component.CurrentNode = node;
component.CurrentNodeId = node.Id;
var allComponents = node.Effect.Components.Concat(node.Effect.PermanentComponents).Concat(node.Trigger.Components);
var trigger = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
var effect = _prototype.Index<ArtifactEffectPrototype>(node.Effect);
var allComponents = effect.Components.Concat(effect.PermanentComponents).Concat(trigger.Components);
foreach (var (name, entry) in allComponents)
{
var reg = _componentFactory.GetRegistration(name);
@@ -171,7 +192,7 @@ public sealed partial class ArtifactSystem
if (node.Discovered && EntityManager.HasComponent(uid, reg.Type))
{
// Don't re-add permanent components unless this is the first time you've entered this node
if (node.Effect.PermanentComponents.ContainsKey(name))
if (effect.PermanentComponents.ContainsKey(name))
continue;
EntityManager.RemoveComponent(uid, reg.Type);
@@ -187,7 +208,7 @@ public sealed partial class ArtifactSystem
}
node.Discovered = true;
RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNode.Id));
RaiseLocalEvent(uid, new ArtifactNodeEnteredEvent(component.CurrentNodeId.Value));
}
/// <summary>
@@ -198,16 +219,31 @@ public sealed partial class ArtifactSystem
if (!Resolve(uid, ref component))
return;
var node = component.CurrentNode;
if (node == null)
if (component.CurrentNodeId == null)
return;
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
foreach (var name in node.Effect.Components.Keys.Concat(node.Trigger.Components.Keys))
var trigger = _prototype.Index<ArtifactTriggerPrototype>(currentNode.Trigger);
var effect = _prototype.Index<ArtifactEffectPrototype>(currentNode.Effect);
foreach (var name in effect.Components.Keys.Concat(trigger.Components.Keys))
{
var comp = _componentFactory.GetRegistration(name);
EntityManager.RemoveComponentDeferred(uid, comp.Type);
}
component.CurrentNode = null;
component.CurrentNodeId = null;
}
[PublicAPI]
public ArtifactNode GetNodeFromId(int id, ArtifactComponent component)
{
return component.NodeTree.First(x => x.Id == id);
}
[PublicAPI]
public ArtifactNode GetNodeFromId(int id, IEnumerable<ArtifactNode> nodes)
{
return nodes.First(x => x.Id == id);
}
}