Remove GCQueue (#18820)
This commit is contained in:
@@ -120,7 +120,6 @@ namespace Content.Client.Entry
|
|||||||
_prototypeManager.RegisterIgnore("noiseChannel");
|
_prototypeManager.RegisterIgnore("noiseChannel");
|
||||||
_prototypeManager.RegisterIgnore("spaceBiome");
|
_prototypeManager.RegisterIgnore("spaceBiome");
|
||||||
_prototypeManager.RegisterIgnore("worldgenConfig");
|
_prototypeManager.RegisterIgnore("worldgenConfig");
|
||||||
_prototypeManager.RegisterIgnore("gcQueue");
|
|
||||||
_prototypeManager.RegisterIgnore("gameRule");
|
_prototypeManager.RegisterIgnore("gameRule");
|
||||||
_prototypeManager.RegisterIgnore("worldSpell");
|
_prototypeManager.RegisterIgnore("worldSpell");
|
||||||
_prototypeManager.RegisterIgnore("entitySpell");
|
_prototypeManager.RegisterIgnore("entitySpell");
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent airtight, ref AnchorStateChangedEvent args)
|
private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent airtight, ref AnchorStateChangedEvent args)
|
||||||
{
|
{
|
||||||
var xform = Transform(uid);
|
var xform = args.Transform;
|
||||||
|
|
||||||
if (!TryComp(xform.GridUid, out MapGridComponent? grid))
|
if (!TryComp(xform.GridUid, out MapGridComponent? grid))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using Content.Server.Worldgen.Prototypes;
|
|
||||||
using Content.Server.Worldgen.Systems.GC;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Worldgen.Components.GC;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is used for whether or not a GCable object is "dirty". Firing GCDirtyEvent on the object is the correct way to
|
|
||||||
/// set this up.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[Access(typeof(GCQueueSystem))]
|
|
||||||
public sealed class GCAbleObjectComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Which queue to insert this object into when GCing
|
|
||||||
/// </summary>
|
|
||||||
[DataField("queue", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<GCQueuePrototype>))]
|
|
||||||
public string Queue = default!;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Worldgen.Prototypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is a prototype for a GC queue.
|
|
||||||
/// </summary>
|
|
||||||
[Prototype("gcQueue")]
|
|
||||||
public sealed class GCQueuePrototype : IPrototype
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
[IdDataField]
|
|
||||||
public string ID { get; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How deep the GC queue is at most. If this value is ever exceeded entities get processed automatically regardless of
|
|
||||||
/// tick-time cap.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("depth", required: true)]
|
|
||||||
public int Depth { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum amount of time that can be spent processing this queue.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("maximumTickTime")]
|
|
||||||
public TimeSpan MaximumTickTime { get; } = TimeSpan.FromMilliseconds(1);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The minimum depth before entities in the queue actually get processed for deletion.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("minDepthToProcess", required: true)]
|
|
||||||
public int MinDepthToProcess { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether or not the GC should fire an event on the entity to see if it's eligible to skip the queue.
|
|
||||||
/// Useful for making it so only objects a player has actually interacted with get put in the collection queue.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("trySkipQueue")]
|
|
||||||
public bool TrySkipQueue { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Server.Worldgen.Components;
|
using Content.Server.Worldgen.Components;
|
||||||
using Content.Server.Worldgen.Components.Debris;
|
using Content.Server.Worldgen.Components.Debris;
|
||||||
using Content.Server.Worldgen.Systems.GC;
|
|
||||||
using Content.Server.Worldgen.Tools;
|
using Content.Server.Worldgen.Tools;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -17,7 +16,6 @@ namespace Content.Server.Worldgen.Systems.Debris;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DebrisFeaturePlacerSystem : BaseWorldSystem
|
public sealed class DebrisFeaturePlacerSystem : BaseWorldSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly GCQueueSystem _gc = default!;
|
|
||||||
[Dependency] private readonly NoiseIndexSystem _noiseIndex = default!;
|
[Dependency] private readonly NoiseIndexSystem _noiseIndex = default!;
|
||||||
[Dependency] private readonly PoissonDiskSampler _sampler = default!;
|
[Dependency] private readonly PoissonDiskSampler _sampler = default!;
|
||||||
[Dependency] private readonly TransformSystem _xformSys = default!;
|
[Dependency] private readonly TransformSystem _xformSys = default!;
|
||||||
@@ -35,19 +33,10 @@ public sealed class DebrisFeaturePlacerSystem : BaseWorldSystem
|
|||||||
SubscribeLocalEvent<DebrisFeaturePlacerControllerComponent, WorldChunkUnloadedEvent>(OnChunkUnloaded);
|
SubscribeLocalEvent<DebrisFeaturePlacerControllerComponent, WorldChunkUnloadedEvent>(OnChunkUnloaded);
|
||||||
SubscribeLocalEvent<OwnedDebrisComponent, ComponentShutdown>(OnDebrisShutdown);
|
SubscribeLocalEvent<OwnedDebrisComponent, ComponentShutdown>(OnDebrisShutdown);
|
||||||
SubscribeLocalEvent<OwnedDebrisComponent, MoveEvent>(OnDebrisMove);
|
SubscribeLocalEvent<OwnedDebrisComponent, MoveEvent>(OnDebrisMove);
|
||||||
SubscribeLocalEvent<OwnedDebrisComponent, TryCancelGC>(OnTryCancelGC);
|
|
||||||
SubscribeLocalEvent<SimpleDebrisSelectorComponent, TryGetPlaceableDebrisFeatureEvent>(
|
SubscribeLocalEvent<SimpleDebrisSelectorComponent, TryGetPlaceableDebrisFeatureEvent>(
|
||||||
OnTryGetPlacableDebrisEvent);
|
OnTryGetPlacableDebrisEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles GC cancellation in case the chunk is still loaded.
|
|
||||||
/// </summary>
|
|
||||||
private void OnTryCancelGC(EntityUid uid, OwnedDebrisComponent component, ref TryCancelGC args)
|
|
||||||
{
|
|
||||||
args.Cancelled |= HasComp<LoadedChunkComponent>(component.OwningController);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles debris moving, and making sure it stays parented to a chunk for loading purposes.
|
/// Handles debris moving, and making sure it stays parented to a chunk for loading purposes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -102,12 +91,6 @@ public sealed class DebrisFeaturePlacerSystem : BaseWorldSystem
|
|||||||
private void OnChunkUnloaded(EntityUid uid, DebrisFeaturePlacerControllerComponent component,
|
private void OnChunkUnloaded(EntityUid uid, DebrisFeaturePlacerControllerComponent component,
|
||||||
ref WorldChunkUnloadedEvent args)
|
ref WorldChunkUnloadedEvent args)
|
||||||
{
|
{
|
||||||
foreach (var (_, debris) in component.OwnedDebris)
|
|
||||||
{
|
|
||||||
if (debris is not null)
|
|
||||||
_gc.TryGCEntity(debris.Value); // gonb.
|
|
||||||
}
|
|
||||||
|
|
||||||
component.DoSpawns = true;
|
component.DoSpawns = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server.Worldgen.Components.GC;
|
|
||||||
using Content.Server.Worldgen.Prototypes;
|
|
||||||
using Content.Shared.CCVar;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.Worldgen.Systems.GC;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This handles delayed garbage collection of entities, to avoid overloading the tick in particularly expensive cases.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class GCQueueSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
|
|
||||||
[ViewVariables] private TimeSpan _maximumProcessTime = TimeSpan.Zero;
|
|
||||||
|
|
||||||
[ViewVariables] private readonly Dictionary<string, Queue<EntityUid>> _queues = new();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
_cfg.OnValueChanged(CCVars.GCMaximumTimeMs, s => _maximumProcessTime = TimeSpan.FromMilliseconds(s),
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />CCVars
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
var overallWatch = new Stopwatch();
|
|
||||||
var queueWatch = new Stopwatch();
|
|
||||||
var queues = _queues.ToList();
|
|
||||||
_random.Shuffle(queues); // Avert resource starvation by always processing in random order.
|
|
||||||
overallWatch.Start();
|
|
||||||
foreach (var (pId, queue) in queues)
|
|
||||||
{
|
|
||||||
if (overallWatch.Elapsed > _maximumProcessTime)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var proto = _proto.Index<GCQueuePrototype>(pId);
|
|
||||||
if (queue.Count < proto.MinDepthToProcess)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
queueWatch.Restart();
|
|
||||||
while (queueWatch.Elapsed < proto.MaximumTickTime && queue.Count >= proto.MinDepthToProcess &&
|
|
||||||
overallWatch.Elapsed < _maximumProcessTime)
|
|
||||||
{
|
|
||||||
var e = queue.Dequeue();
|
|
||||||
if (!Deleted(e))
|
|
||||||
{
|
|
||||||
var ev = new TryCancelGC();
|
|
||||||
RaiseLocalEvent(e, ref ev);
|
|
||||||
|
|
||||||
if (!ev.Cancelled)
|
|
||||||
Del(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to GC an entity. This functions as QueueDel if it can't.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="e">Entity to GC.</param>
|
|
||||||
public void TryGCEntity(EntityUid e)
|
|
||||||
{
|
|
||||||
if (!TryComp<GCAbleObjectComponent>(e, out var comp))
|
|
||||||
{
|
|
||||||
QueueDel(e); // not our problem :)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_queues.TryGetValue(comp.Queue, out var queue))
|
|
||||||
{
|
|
||||||
queue = new Queue<EntityUid>();
|
|
||||||
_queues[comp.Queue] = queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var proto = _proto.Index<GCQueuePrototype>(comp.Queue);
|
|
||||||
if (queue.Count > proto.Depth)
|
|
||||||
{
|
|
||||||
QueueDel(e); // whelp, too full.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto.TrySkipQueue)
|
|
||||||
{
|
|
||||||
var ev = new TryGCImmediately();
|
|
||||||
RaiseLocalEvent(e, ref ev);
|
|
||||||
if (!ev.Cancelled)
|
|
||||||
{
|
|
||||||
QueueDel(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
queue.Enqueue(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fired by GCQueueSystem to check if it can simply immediately GC an entity, for example if it was never fully
|
|
||||||
/// loaded.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Cancelled">Whether or not the immediate deletion attempt was cancelled.</param>
|
|
||||||
[ByRefEvent]
|
|
||||||
[PublicAPI]
|
|
||||||
public record struct TryGCImmediately(bool Cancelled = false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fired by GCQueueSystem to check if the collection of the given entity should be cancelled, for example it's chunk
|
|
||||||
/// being loaded again.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Cancelled">Whether or not the deletion attempt was cancelled.</param>
|
|
||||||
[ByRefEvent]
|
|
||||||
[PublicAPI]
|
|
||||||
public record struct TryCancelGC(bool Cancelled = false);
|
|
||||||
|
|
||||||
@@ -41,8 +41,6 @@
|
|||||||
- id: WallRockArtifactFragment
|
- id: WallRockArtifactFragment
|
||||||
prob: 0.01
|
prob: 0.01
|
||||||
orGroup: rock
|
orGroup: rock
|
||||||
- type: GCAbleObject
|
|
||||||
queue: SpaceDebris
|
|
||||||
- type: IFF
|
- type: IFF
|
||||||
flags: HideLabel
|
flags: HideLabel
|
||||||
color: "#d67e27"
|
color: "#d67e27"
|
||||||
|
|||||||
@@ -45,8 +45,6 @@
|
|||||||
prob: 0.2
|
prob: 0.2
|
||||||
- id: SalvageMobSpawner
|
- id: SalvageMobSpawner
|
||||||
prob: 0.7
|
prob: 0.7
|
||||||
- type: GCAbleObject
|
|
||||||
queue: SpaceDebris
|
|
||||||
- type: IFF
|
- type: IFF
|
||||||
flags: HideLabel
|
flags: HideLabel
|
||||||
color: "#88b0d1"
|
color: "#88b0d1"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
- type: gcQueue
|
|
||||||
id: SpaceDebris
|
|
||||||
depth: 512 # So there's a decent bit of time before roids unload.
|
|
||||||
minDepthToProcess: 256
|
|
||||||
Reference in New Issue
Block a user