Data-oriented Construction System (#2152)

- Powerful
- Data-oriented
- Approved by PJB
- Powered by node graphs and AI pathfinding
- Coded by the same nerd who brought you atmos

Co-authored-by: Exp <theexp111@gmail.com>
This commit is contained in:
Víctor Aguilera Puerto
2020-10-08 17:41:23 +02:00
committed by GitHub
parent a6647e8de1
commit 745401a41e
261 changed files with 3886 additions and 11986 deletions

View File

@@ -1,8 +1,9 @@
using Content.Shared.Construction;
using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
@@ -11,6 +12,8 @@ namespace Content.Client.GameObjects.Components.Construction
[RegisterComponent]
public class ConstructionGhostComponent : Component, IExamine
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override string Name => "ConstructionGhost";
[ViewVariables] public ConstructionPrototype Prototype { get; set; }
@@ -18,8 +21,13 @@ namespace Content.Client.GameObjects.Components.Construction
void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
{
message.AddText(Loc.GetString("Building: {0}\n", Prototype.Name));
EntitySystem.Get<SharedConstructionSystem>().DoExamine(message, Prototype, 0, inDetailsRange);
message.AddMarkup(Loc.GetString("Building: [color=cyan]{0}[/color]\n", Prototype.Name));
if (!_prototypeManager.TryIndex(Prototype.Graph, out ConstructionGraphPrototype graph)) return;
var startNode = graph.Nodes[Prototype.StartNode];
var path = graph.Path(Prototype.StartNode, Prototype.TargetNode);
var edge = startNode.GetEdge(path[0].Name);
edge.Steps[0].DoExamine(message, inDetailsRange);
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Client.GameObjects.Components.IconSmoothing;
using Content.Shared.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
@@ -35,6 +36,7 @@ namespace Content.Client.GameObjects.Components
Sprite.LayerSetDirOffset(ReinforcedCornerLayers.NW, DirectionOffset.Flip);
Sprite.LayerMapSet(ReinforcedCornerLayers.SW, Sprite.AddLayerState(state0));
Sprite.LayerSetDirOffset(ReinforcedCornerLayers.SW, DirectionOffset.Clockwise);
Sprite.LayerMapSet(ReinforcedWallVisualLayers.Deconstruction, Sprite.AddBlankLayer());
}
internal override void CalculateNewSprite()

View File

@@ -0,0 +1,42 @@
using Content.Shared.GameObjects.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
namespace Content.Client.GameObjects.Components
{
[UsedImplicitly]
public class ReinforcedWallVisualizer : AppearanceVisualizer
{
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
if (component.TryGetData(ReinforcedWallVisuals.DeconstructionStage, out int stage))
{
SetDeconstructionStage(component, stage);
}
}
public void SetDeconstructionStage(AppearanceComponent component, int stage)
{
var entity = component.Owner;
if (!entity.TryGetComponent(out ISpriteComponent sprite)) return;
if (stage < 0)
{
sprite.LayerSetVisible(ReinforcedWallVisualLayers.Deconstruction, false);
return;
}
sprite.LayerSetVisible(ReinforcedWallVisualLayers.Deconstruction, true);
sprite.LayerSetState(ReinforcedWallVisualLayers.Deconstruction, $"reinf_construct-{stage}");
}
}
public enum ReinforcedWallVisualLayers
{
Deconstruction,
}
}

View File

@@ -11,6 +11,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components
{
[RegisterComponent]
[ComponentReference(typeof(SharedStackComponent))]
public class StackComponent : SharedStackComponent, IItemStatus
{
[ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded;

View File

@@ -1,4 +1,5 @@
using Content.Client.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
@@ -9,10 +10,9 @@ using static Content.Client.GameObjects.Components.IconSmoothing.IconSmoothCompo
namespace Content.Client.GameObjects.Components
{
[RegisterComponent]
public sealed class WindowComponent : Component
[ComponentReference(typeof(SharedWindowComponent))]
public sealed class WindowComponent : SharedWindowComponent
{
public override string Name => "Window";
private string _stateBase;
private ISpriteComponent _sprite;
private SnapGridComponent _snapGrid;

View File

@@ -5,6 +5,7 @@ using Content.Client.UserInterface;
using Content.Shared.Construction;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Input;
using Content.Shared.Utility;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.EntitySystems;
@@ -152,11 +153,20 @@ namespace Content.Client.GameObjects.EntitySystems
/// </summary>
public void SpawnGhost(ConstructionPrototype prototype, EntityCoordinates loc, Direction dir)
{
if (GhostPresent(loc))
var user = _playerManager.LocalPlayer?.ControlledEntity;
// This InRangeUnobstructed should probably be replaced with "is there something blocking us in that tile?"
if (user == null || GhostPresent(loc) || !user.InRangeUnobstructed(loc, 20f, ignoreInsideBlocker:prototype.CanBuildInImpassable))
{
return;
}
foreach (var condition in prototype.Conditions)
{
if (!condition.Condition(user, loc, dir))
return;
}
var ghost = _entityManager.SpawnEntity("constructionghost", loc);
var comp = ghost.GetComponent<ConstructionGhostComponent>();
comp.Prototype = prototype;
@@ -204,7 +214,7 @@ namespace Content.Client.GameObjects.EntitySystems
}
/// <summary>
/// Removes a construction ghost entity with the given ID.
/// Removes a construction ghost entity with the given ID.
/// </summary>
public void ClearGhost(int ghostId)
{
@@ -214,5 +224,18 @@ namespace Content.Client.GameObjects.EntitySystems
_ghosts.Remove(ghostId);
}
}
/// <summary>
/// Removes all construction ghosts.
/// </summary>
public void ClearAllGhosts()
{
foreach (var (_, ghost) in _ghosts)
{
ghost.Owner.Delete();
}
_ghosts.Clear();
}
}
}

View File

@@ -131,7 +131,12 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
if (doAfter.BreakOnTargetMove)
{
var targetEntity = _entityManager.GetEntity(doAfter.TargetUid);
if (!_entityManager.TryGetEntity(doAfter.TargetUid, out var targetEntity))
{
// Cancel if the target entity doesn't exist.
doAfterComponent.Cancel(id, currentTime);
continue;
}
if (targetEntity.Transform.Coordinates != doAfter.TargetGrid)
{