ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
using Content.Server.Construction.Components;
|
|
|
|
|
using Content.Shared.Construction;
|
|
|
|
|
using Content.Shared.Construction.Prototypes;
|
|
|
|
|
|
|
|
|
|
namespace Content.Server.Construction
|
|
|
|
|
{
|
2022-02-16 00:23:23 -07:00
|
|
|
public sealed partial class ConstructionSystem
|
ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
{
|
2022-03-25 05:00:39 +01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sets or clears a pathfinding target node for a given construction entity.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="uid">The target entity.</param>
|
|
|
|
|
/// <param name="targetNodeId">The target node to pathfind, or null to clear the current pathfinding node.</param>
|
|
|
|
|
/// <param name="construction">The construction component of the target entity. Will be resolved if null.</param>
|
|
|
|
|
/// <returns>Whether we could set/clear the pathfinding target node.</returns>
|
ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
public bool SetPathfindingTarget(EntityUid uid, string? targetNodeId, ConstructionComponent? construction = null)
|
|
|
|
|
{
|
|
|
|
|
if (!Resolve(uid, ref construction))
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-11-01 16:56:33 +01:00
|
|
|
// Clear current target, just in case.
|
|
|
|
|
ClearPathfinding(uid, construction);
|
|
|
|
|
|
|
|
|
|
// Null means clear pathfinding target only.
|
ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
if (targetNodeId == null)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GetCurrentGraph(uid, construction) is not {} graph)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (GetNodeFromGraph(graph, construction.Node) is not { } node)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (GetNodeFromGraph(graph, targetNodeId) is not {} targetNode)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return UpdatePathfinding(uid, graph, node, targetNode, GetCurrentEdge(uid, construction), construction);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-25 05:00:39 +01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the pathfinding state for the current construction state of an entity.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="uid">The target entity.</param>
|
|
|
|
|
/// <param name="construction">The construction component of the target entity. Will be resolved if null.</param>
|
|
|
|
|
/// <returns>Whether we could update the pathfinding state correctly.</returns>
|
ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
public bool UpdatePathfinding(EntityUid uid, ConstructionComponent? construction = null)
|
|
|
|
|
{
|
|
|
|
|
if (!Resolve(uid, ref construction))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (construction.TargetNode is not {} targetNodeId)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (GetCurrentGraph(uid, construction) is not {} graph
|
|
|
|
|
|| GetNodeFromGraph(graph, construction.Node) is not {} node
|
|
|
|
|
|| GetNodeFromGraph(graph, targetNodeId) is not {} targetNode)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return UpdatePathfinding(uid, graph, node, targetNode, GetCurrentEdge(uid, construction), construction);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-25 05:00:39 +01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Internal version of <see cref="UpdatePathfinding"/>, which expects a valid construction state and
|
|
|
|
|
/// actually performs the pathfinding update logic.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="uid">The target entity.</param>
|
|
|
|
|
/// <param name="graph">The construction graph the entity is at.</param>
|
|
|
|
|
/// <param name="currentNode">The current construction node the entity is at.</param>
|
|
|
|
|
/// <param name="targetNode">The target node we are trying to reach on the graph.</param>
|
|
|
|
|
/// <param name="currentEdge">The current edge the entity is at, or null if none.</param>
|
|
|
|
|
/// <param name="construction">The construction component of the target entity. Will be resolved if null.</param>
|
|
|
|
|
/// <returns>Whether we could update the pathfinding state correctly.</returns>
|
ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
private bool UpdatePathfinding(EntityUid uid, ConstructionGraphPrototype graph,
|
|
|
|
|
ConstructionGraphNode currentNode, ConstructionGraphNode targetNode,
|
|
|
|
|
ConstructionGraphEdge? currentEdge,
|
|
|
|
|
ConstructionComponent? construction = null)
|
|
|
|
|
{
|
|
|
|
|
if (!Resolve(uid, ref construction))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
construction.TargetNode = targetNode.Name;
|
|
|
|
|
|
|
|
|
|
// Check if we reached the target node.
|
|
|
|
|
if (currentNode == targetNode)
|
|
|
|
|
{
|
|
|
|
|
ClearPathfinding(uid, construction);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we don't have a path, generate it.
|
|
|
|
|
if (construction.NodePathfinding == null)
|
|
|
|
|
{
|
|
|
|
|
var path = graph.PathId(currentNode.Name, targetNode.Name);
|
|
|
|
|
|
|
|
|
|
if (path == null || path.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
// No path.
|
|
|
|
|
ClearPathfinding(uid, construction);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
construction.NodePathfinding = new Queue<string>(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the next pathfinding node is the one we're at, dequeue it.
|
|
|
|
|
if (construction.NodePathfinding.Peek() == currentNode.Name)
|
|
|
|
|
{
|
|
|
|
|
construction.NodePathfinding.Dequeue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentEdge != null && construction.TargetEdgeIndex is {} targetEdgeIndex)
|
|
|
|
|
{
|
|
|
|
|
if (currentNode.Edges.Count >= targetEdgeIndex)
|
|
|
|
|
{
|
|
|
|
|
// Target edge is incorrect.
|
|
|
|
|
construction.TargetEdgeIndex = null;
|
|
|
|
|
}
|
|
|
|
|
else if (currentNode.Edges[targetEdgeIndex] != currentEdge)
|
|
|
|
|
{
|
|
|
|
|
// We went the wrong way, clean up!
|
|
|
|
|
ClearPathfinding(uid, construction);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (construction.EdgeIndex == null
|
|
|
|
|
&& construction.TargetEdgeIndex == null
|
|
|
|
|
&& construction.NodePathfinding != null)
|
|
|
|
|
construction.TargetEdgeIndex = (currentNode.GetEdgeIndex(construction.NodePathfinding.Peek()));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-25 05:00:39 +01:00
|
|
|
/// <summary>
|
|
|
|
|
/// Clears the pathfinding targets on a construction entity.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="uid">The target entity.</param>
|
|
|
|
|
/// <param name="construction">The construction component of the target entity. Will be resolved if null.</param>
|
ConstructionGL2 Part 1: ECSification, events and steps. (#5017)
- Completely rewrited the `ConstructionComponent` logic to be ECS, *without* looking too much at the original implementation.
- The original implementation was dirty and unmaintainable, whereas this new implementation is much cleaner, well-organized and maintainable. I've made sure to leave many comments around, explaining what everything does.
- Construction now has a framework for handling events other than `InteractUsing`.
- This means that you can now have CGL steps for things other than inserting items, using tools...
- Construction no longer uses `async` everywhere for `DoAfter`s. Instead it uses events.
- Construction event handling occurs in the `ConstructionSystem` update tick, instead of on event handlers.
- This ensures we can delete/modify entities without worrying about "collection modified while enumerating" exceptions.
- This also means the construction update tick is where all the fun happens, meaning it'll show up on our metrics and give us an idea of how expensive it is/how much tick time is spent in construction.
- `IGraphCondition` and `IGraphAction` have been refactored to take in `EntityUid`, `IEntityManager`, and to not be async.
- Removes nested steps, as they made maintainability significantly worse, and nothing used them yet.
- This fixes #4892 and fixes #4857
Please note, this leaves many things unchanged, as my idea is to split this into multiple PRs. Some unchanged things:
- Initial construction code is the same. In the future, it'll probably use dummy entities.
- Client-side guided steps are the same. In the future, the server will generate the guided steps and send them to clients as needed, caching these in both the server and client to save cycles and bandwidth.
- No new construction graph steps... Yet! :eyes:
2021-10-26 16:38:03 +02:00
|
|
|
public void ClearPathfinding(EntityUid uid, ConstructionComponent? construction = null)
|
|
|
|
|
{
|
|
|
|
|
if (!Resolve(uid, ref construction))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
construction.TargetNode = null;
|
|
|
|
|
construction.TargetEdgeIndex = null;
|
|
|
|
|
construction.NodePathfinding = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|