Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 58 additions & 15 deletions Content.Server/Shuttles/Systems/ShuttleSystem.Impact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@
using Robust.Shared.Random;
using System.Numerics;

using Content.Server._Mono.Cleanup;
using Content.Shared._Mono.CCVar;

namespace Content.Server.Shuttles.Systems;

// shuttle impact damage ported from Goobstation (AGPLv3) with agreement of all coders involved
public sealed partial class ShuttleSystem
{
[Dependency] private readonly SpaceCleanupSystem _sweep = default!;

private bool _enabled;
private float _minimumImpactInertia;
private float _minimumImpactVelocity;
Expand All @@ -45,6 +50,11 @@ public sealed partial class ShuttleSystem
// this doesn't update if plating mass is changed but edgecase
private float _platingMass;

// Mono
private float _sweepAggression;
private float _sweepDelay;
private float _sweepRadius;

private const float _sparkChance = 0.2f;
// shuttle mass to consider the neutral point for inertia scaling
private const float _baseShuttleMass = 50f;
Expand Down Expand Up @@ -86,6 +96,11 @@ private void InitializeImpact()
Subs.CVar(_cfg, CCVars.ImpactMassBias, value => _massBias = value, true);
Subs.CVar(_cfg, CCVars.ImpactInertiaScaling, value => _inertiaScaling = value, true);

// Mono
Subs.CVar(_cfg, MonoCVars.ImpactSweepAggression, val => _sweepAggression = val, true);
Subs.CVar(_cfg, MonoCVars.ImpactSweepDelay, val => _sweepDelay = val, true);
Subs.CVar(_cfg, MonoCVars.ImpactSweepRadius, val => _sweepRadius = val, true);

_platingMass = _protoManager.Index(_platingId).Mass;
}

Expand Down Expand Up @@ -192,7 +207,12 @@ private void OnShuttleCollide(EntityUid uid, ShuttleComponent component, ref Sta
var impact = LogImpact.High;
// if impact isn't tiny, log it as extreme
if (toUsEnergy + toOtherEnergy > 2f * _tileBreakEnergyMultiplier * _platingMass)
{
impact = LogImpact.Extreme;

// Mono - also queue cleanup sweeps
_sweep.QueueSweep(ourPoint, TimeSpan.FromSeconds(_sweepDelay), _sweepRadius, _sweepAggression);
}
// TODO: would be nice for it to also log who is piloting the grid(s)
if (CheckShouldLog(args.OurEntity) && CheckShouldLog(args.OtherEntity))
_logger.Add(LogType.ShuttleImpact, impact, $"Shuttle impact of {ToPrettyString(args.OurEntity)} with {ToPrettyString(args.OtherEntity)} at {worldPoint}");
Expand All @@ -210,10 +230,10 @@ private void OnShuttleCollide(EntityUid uid, ShuttleComponent component, ref Sta
&& TryComp<ShipShieldEmitterComponent>(ShipShieldedComponent.Source, out var ShipShieldEmitterComponent)
)
toUsEnergy *= ShipShieldEmitterComponent.CollisionResistanceMultiplier;

if (TryComp<ShipShieldedComponent>(args.OtherEntity, out var OtherShipShieldedComponent) //Other ship collision resistance
&& TryComp<ShipShieldEmitterComponent>(OtherShipShieldedComponent.Source, out var OtherShipShieldEmitterComponent)
)
)
toOtherEnergy *= OtherShipShieldEmitterComponent.CollisionResistanceMultiplier;
// Mono Edit end

Expand Down Expand Up @@ -260,35 +280,58 @@ private void ThrowEntitiesOnGrid(EntityUid gridUid, TransformComponent xform, Ve
var knockdownTime = TimeSpan.FromSeconds(5);

var minsq = _minThrowVelocity * _minThrowVelocity;
// iterate all entities on the grid
// TODO: only iterate non-static entities
var childEnumerator = xform.ChildEnumerator;
while (childEnumerator.MoveNext(out var uid))
{
// don't throw static bodies
if (!_physicsQuery.TryGetComponent(uid, out var physics) || (physics.BodyType & BodyType.Static) != 0)
continue;

// iterate all dynamic entities on the grid
if (!TryComp<BroadphaseComponent>(gridUid, out var lookup) || !_gridQuery.TryComp(gridUid, out var gridComp))
return;

var gridBox = gridComp.LocalAABB;
List<Entity<PhysicsComponent>> list = new();
HashSet<EntityUid> processed = new();
var state = (list, processed, _physicsQuery);
lookup.DynamicTree.QueryAabb(ref state, GridQueryCallback, gridBox, true);
lookup.SundriesTree.QueryAabb(ref state, GridQueryCallback, gridBox, true);

foreach (var ent in list)
{
// don't throw if buckled
if (_buckle.IsBuckled(uid, _buckleQuery.CompOrNull(uid)))
if (_buckle.IsBuckled(ent, _buckleQuery.CompOrNull(ent)))
continue;

// don't throw them if they have magboots
if (movedByPressureQuery.TryComp(uid, out var moved) && !moved.Enabled)
if (movedByPressureQuery.TryComp(ent, out var moved) && !moved.Enabled)
continue;

if (direction.LengthSquared() > minsq)
{
_stuns.TryKnockdown(uid, knockdownTime, true);
_throwing.TryThrow(uid, direction, physics, Transform(uid), _projQuery, direction.Length(), playSound: false);
_stuns.TryKnockdown(ent.Owner, knockdownTime, true);
_throwing.TryThrow(ent, direction, ent.Comp, Transform(ent), _projQuery, direction.Length(), playSound: false);
}
else
{
_physics.ApplyLinearImpulse(uid, direction * physics.Mass, body: physics);
_physics.ApplyLinearImpulse(ent, direction * ent.Comp.Mass, body: ent.Comp);
}
}
}

private static bool GridQueryCallback(
ref (List<Entity<PhysicsComponent>> List, HashSet<EntityUid> Processed, EntityQuery<PhysicsComponent> PhysicsQuery) state,
in EntityUid uid)
{
if (state.Processed.Add(uid) && state.PhysicsQuery.TryComp(uid, out var body))
state.List.Add((uid, body));

return true;
}

private static bool GridQueryCallback(
ref (List<Entity<PhysicsComponent>> List, HashSet<EntityUid> Processed, EntityQuery<PhysicsComponent> PhysicsQuery) state,
in FixtureProxy proxy)
{
var owner = proxy.Entity;
return GridQueryCallback(ref state, in owner);
}

/// <summary>
/// Structure to hold impact tile processing data for batch processing
/// </summary>
Expand Down
19 changes: 12 additions & 7 deletions Content.Server/_Mono/Cleanup/BaseCleanupSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,7 @@ public override void Update(float frameTime)
if (!ShouldEntityCleanup(uid))
continue;

var coord = Transform(uid).Coordinates;
var world = _transform.ToMapCoordinates(coord);
if (_doLog)
Log.Info($"Cleanup deleting entity {ToPrettyString(uid)} at {coord} (world {world})");

_delCount += 1;
QueueDel(uid);
CleanupEnt(uid);
}
return;
}
Expand Down Expand Up @@ -90,5 +84,16 @@ public override void Update(float frameTime)
Log.Debug($"Ran cleanup queue, found: {_checkQueue.Count}, deleting over {_cleanupDeferDuration}");
}

protected void CleanupEnt(EntityUid uid)
{
var coord = Transform(uid).Coordinates;
var world = _transform.ToMapCoordinates(coord);
if (_doLog)
Log.Info($"Cleanup deleting entity {ToPrettyString(uid)} at {coord} (world {world})");

_delCount += 1;
QueueDel(uid);
}

protected abstract bool ShouldEntityCleanup(EntityUid uid);
}
53 changes: 49 additions & 4 deletions Content.Server/_Mono/Cleanup/SpaceCleanupSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Timing;
using System.Reflection;

namespace Content.Server._Mono.Cleanup;
Expand All @@ -21,12 +22,15 @@ namespace Content.Server._Mono.Cleanup;
public sealed class SpaceCleanupSystem : BaseCleanupSystem<PhysicsComponent>
{
[Dependency] private readonly CleanupHelperSystem _cleanup = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private object _manifold = default!;
private MethodInfo _testOverlap = default!;
[Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;

private float _maxDistance;
private float _maxGridDistance;
Expand All @@ -39,6 +43,9 @@ public sealed class SpaceCleanupSystem : BaseCleanupSystem<PhysicsComponent>
private EntityQuery<MindContainerComponent> _mindQuery;
private EntityQuery<PhysicsComponent> _physQuery;

private List<(EntityCoordinates Coord, TimeSpan Time, float Radius, float Aggression)> _sweepQueue = new();
private HashSet<Entity<PhysicsComponent>> _sweepEnts = new();

public override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -68,21 +75,28 @@ public override void Initialize()
}

protected override bool ShouldEntityCleanup(EntityUid uid)
{
return ShouldEntityCleanup(uid, 1f);
}

private bool ShouldEntityCleanup(EntityUid uid, float aggression)
{
var xform = Transform(uid);

var isStuck = false;

var price = 0f;

return !_gridQuery.HasComp(uid)
&& (xform.ParentUid == xform.MapUid // don't delete if on grid
|| (isStuck |= GetWallStuck((uid, xform)))) // or wall-stuck
&& !_htnQuery.HasComp(uid) // handled by MobCleanupSystem
&& !_immuneQuery.HasComp(uid) // handled by GridCleanupSystem
&& !_mindQuery.HasComp(uid) // no deleting anything that can have a mind - should be handled by MobCleanupSystem anyway
&& _pricing.GetPrice(uid) <= _maxPrice
&& (price = (float)_pricing.GetPrice(uid)) <= _maxPrice
&& (isStuck
|| !_cleanup.HasNearbyGrids(xform.Coordinates, _maxGridDistance)
&& !_cleanup.HasNearbyPlayers(xform.Coordinates, _maxDistance));
|| !_cleanup.HasNearbyGrids(xform.Coordinates, _maxGridDistance * aggression * MathF.Sqrt(price / _maxPrice))
&& !_cleanup.HasNearbyPlayers(xform.Coordinates, _maxDistance * aggression * MathF.Sqrt(price / _maxPrice)));
}

private bool GetWallStuck(Entity<TransformComponent> ent)
Expand Down Expand Up @@ -133,4 +147,35 @@ private bool GetWallStuck(Entity<TransformComponent> ent)

return false;
}

public void QueueSweep(EntityCoordinates coordinates, TimeSpan time, float radius, float aggression)
{
_sweepQueue.Add((coordinates, time, radius, aggression));
}

public override void Update(float frameTime)
{
base.Update(frameTime);

for (int i = _sweepQueue.Count - 1; i >= 0; i--)
{
var (coord, time, radius, aggression) = _sweepQueue[i];

if (_timing.CurTime < time)
continue;

_sweepQueue.RemoveAt(i);
if (!coord.IsValid(EntityManager))
continue;

_sweepEnts.Clear();
_lookup.GetEntitiesInRange(_transform.ToMapCoordinates(coord), radius, _sweepEnts, LookupFlags.Dynamic | LookupFlags.Approximate | LookupFlags.Sundries);

foreach (var (uid, body) in _sweepEnts)
{
if (ShouldEntityCleanup(uid, aggression))
CleanupEnt(uid);
}
}
}
}
22 changes: 20 additions & 2 deletions Content.Shared/_Mono/CCVar/CCVars.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public sealed partial class MonoCVars
/// Don't delete non-grids at most this close to a grid.
/// </summary>
public static readonly CVarDef<float> CleanupMaxGridDistance =
CVarDef.Create("mono.cleanup.max_grid_distance", 20.0f, CVar.SERVERONLY);
CVarDef.Create("mono.cleanup.max_grid_distance", 30.0f, CVar.SERVERONLY);

/// <summary>
/// How far away from any players can a mob be until it gets cleaned up.
Expand Down Expand Up @@ -68,7 +68,25 @@ public sealed partial class MonoCVars
/// How much can a spaced entity at most be worth for it to be cleaned up.
/// </summary>
public static readonly CVarDef<float> SpaceCleanupMaxValue =
CVarDef.Create("mono.cleanup.space.max_value", 10000.0f, CVar.SERVERONLY);
CVarDef.Create("mono.cleanup.space.max_value", 3000.0f, CVar.SERVERONLY);

/// <summary>
/// After a shuttle impact, how aggressively to sweep. Makes sweep more willing to delete items close to grids or players.
/// </summary>
public static readonly CVarDef<float> ImpactSweepAggression =
CVarDef.Create("mono.cleanup.impact.aggression", 0.1f, CVar.SERVERONLY);

/// <summary>
/// After a shuttle impact, in how much after the impact to perform the sweep.
/// </summary>
public static readonly CVarDef<float> ImpactSweepDelay =
CVarDef.Create("mono.cleanup.impact.delay", 5.0f, CVar.SERVERONLY);

/// <summary>
/// After a shuttle impact, in how much of a radius to immediately sweep for loose items.
/// </summary>
public static readonly CVarDef<float> ImpactSweepRadius =
CVarDef.Create("mono.cleanup.impact.radius", 60.0f, CVar.SERVERONLY);

#endregion

Expand Down
12 changes: 12 additions & 0 deletions Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@
guides:
- VoltageNetworks
- Power
# Mono
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 150
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic

- type: entity
id: CableHVStack
Expand Down
6 changes: 3 additions & 3 deletions Resources/Prototypes/Entities/Structures/Power/cables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
thresholds:
- trigger:
!type:DamageTrigger
damage: 500
damage: 400
behaviors: #excess damage (nuke?). avoid computational cost of spawning entities.
- !type:DoActsBehavior
acts: [ "Destruction" ]
Expand Down Expand Up @@ -138,7 +138,7 @@
thresholds:
- trigger:
!type:DamageTrigger
damage: 500
damage: 350
behaviors: #excess damage (nuke?). avoid computational cost of spawning entities.
- !type:DoActsBehavior
acts: [ "Destruction" ]
Expand Down Expand Up @@ -193,7 +193,7 @@
thresholds:
- trigger:
!type:DamageTrigger
damage: 500
damage: 250
behaviors: #excess damage (nuke?). avoid computational cost of spawning entities.
- !type:DoActsBehavior
acts: [ "Destruction" ]
Expand Down
Loading
Loading