Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Footprints Performance Updates #1439

Merged
Merged
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
41 changes: 41 additions & 0 deletions Content.Server/Fluids/EntitySystems/AbsorbentSystem.Footprints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Linq;
using Content.Shared.Chemistry.Components;
using Content.Shared.Fluids;
using Content.Shared.FootPrint;

namespace Content.Server.Fluids.EntitySystems;

public sealed partial class AbsorbentSystem
{
[Dependency] private readonly EntityLookupSystem _lookup = default!;

/// <summary>
/// Tries to clean a number of footprints in a range determined by the component. Returns the number of cleaned footprints.
/// </summary>
private int TryCleanNearbyFootprints(EntityUid user, EntityUid used, Entity<AbsorbentComponent> target, Entity<SolutionComponent> absorbentSoln)
{
var footprintQuery = GetEntityQuery<FootPrintComponent>();
var targetCoords = Transform(target).Coordinates;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
var entities = _lookup.GetEntitiesInRange<FootPrintComponent>(targetCoords, target.Comp.FootprintCleaningRange, LookupFlags.Uncontained);

// Take up to [MaxCleanedFootprints] footprints closest to the target
var cleaned = entities.AsEnumerable()
.Select(uid => (uid, dst: Transform(uid).Coordinates.TryDistance(EntityManager, _transform, targetCoords, out var dst) ? dst : 0f))
.Where(ent => ent.dst > 0f)
.OrderBy(ent => ent.dst)
.Select(ent => (ent.uid, comp: footprintQuery.GetComponent(ent.uid)));

// And try to interact with each one of them, ignoring useDelay
var processed = 0;
foreach (var (uid, footprintComp) in cleaned)
{
if (TryPuddleInteract(user, used, uid, target.Comp, useDelay: null, absorbentSoln))
processed++;

if (processed >= target.Comp.MaxCleanedFootprints)
break;
}

return processed;
}
}
7 changes: 4 additions & 3 deletions Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Numerics;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Popups;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
Expand All @@ -18,15 +17,15 @@
namespace Content.Server.Fluids.EntitySystems;

/// <inheritdoc/>
public sealed class AbsorbentSystem : SharedAbsorbentSystem
public sealed partial class AbsorbentSystem : SharedAbsorbentSystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly PopupSystem _popups = default!;
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
[Dependency] private readonly SharedMeleeWeaponSystem _melee = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly MapSystem _mapSystem = default!;

Expand Down Expand Up @@ -119,6 +118,8 @@ public void Mop(EntityUid user, EntityUid target, EntityUid used, AbsorbentCompo
if (!TryRefillableInteract(user, used, target, component, useDelay, absorberSoln.Value))
return;
}

TryCleanNearbyFootprints(user, used, (target, component), absorberSoln.Value);
}

/// <summary>
Expand Down
88 changes: 49 additions & 39 deletions Content.Server/FootPrint/FootPrintsSystem.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
using System.Linq;
using Content.Server.Atmos.Components;
using Content.Shared.Inventory;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.FootPrint;
using Content.Shared.Standing;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Forensics;
using Robust.Shared.Map;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

namespace Content.Server.FootPrint;


public sealed class FootPrintsSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;

[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;

private EntityQuery<TransformComponent> _transformQuery;
private EntityQuery<MobThresholdsComponent> _mobThresholdQuery;
private EntityQuery<AppearanceComponent> _appearanceQuery;
private EntityQuery<LayingDownComponent> _layingQuery;
private EntityQuery<StandingStateComponent> _standingStateQuery;

public override void Initialize()
{
base.Initialize();

_transformQuery = GetEntityQuery<TransformComponent>();
_mobThresholdQuery = GetEntityQuery<MobThresholdsComponent>();
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
_layingQuery = GetEntityQuery<LayingDownComponent>();
_standingStateQuery = GetEntityQuery<StandingStateComponent>();

SubscribeLocalEvent<FootPrintsComponent, ComponentStartup>(OnStartupComponent);
SubscribeLocalEvent<FootPrintsComponent, MoveEvent>(OnMove);
Expand All @@ -46,62 +46,72 @@ private void OnStartupComponent(EntityUid uid, FootPrintsComponent component, Co

private void OnMove(EntityUid uid, FootPrintsComponent component, ref MoveEvent args)
{
if (component.PrintsColor.A <= 0f
|| !_transformQuery.TryComp(uid, out var transform)
|| !_mobThresholdQuery.TryComp(uid, out var mobThreshHolds)
|| !_map.TryFindGridAt(_transform.GetMapCoordinates((uid, transform)), out var gridUid, out _))
if (component.ContainedSolution.Volume <= 0
|| TryComp<PhysicsComponent>(uid, out var physics) && physics.BodyStatus != BodyStatus.OnGround
|| args.Entity.Comp1.GridUid is not {} gridUid)
return;

var dragging = mobThreshHolds.CurrentThresholdState is MobState.Critical or MobState.Dead
|| _layingQuery.TryComp(uid, out var laying) && laying.IsCrawlingUnder;
var distance = (transform.LocalPosition - component.StepPos).Length();
var newPos = _transform.ToMapCoordinates(args.NewPosition).Position;
var dragging = _standingStateQuery.TryComp(uid, out var standing) && standing.CurrentState == StandingState.Lying;
var distance = (newPos - component.LastStepPos).Length();
var stepSize = dragging ? component.DragSize : component.StepSize;

if (!(distance > stepSize))
if (distance < stepSize)
return;

component.RightStep = !component.RightStep;
// are we on a puddle? we exit, ideally we would exchange liquid and DNA with the puddle but meh, too lazy to do that now.
var entities = _lookup.GetEntitiesIntersecting(uid, LookupFlags.All);
if (entities.Any(HasComp<PuddleFootPrintsComponent>))
return;

// Spawn the footprint
var footprintUid = Spawn(component.StepProtoId, CalcCoords(gridUid, component, args.Component, dragging));
var stepTransform = Transform(footprintUid);
var footPrintComponent = EnsureComp<FootPrintComponent>(footprintUid);

var entity = Spawn(component.StepProtoId, CalcCoords(gridUid, component, transform, dragging));
var footPrintComponent = EnsureComp<FootPrintComponent>(entity);
// transfer owner DNA into the footsteps
var forensics = EntityManager.EnsureComponent<ForensicsComponent>(footprintUid);
if (TryComp<ForensicsComponent>(uid, out var ownerForensics))
forensics.DNAs.UnionWith(ownerForensics.DNAs);

footPrintComponent.PrintOwner = uid;
Dirty(entity, footPrintComponent);
Dirty(footprintUid, footPrintComponent);

if (_appearanceQuery.TryComp(entity, out var appearance))
if (_appearanceQuery.TryComp(footprintUid, out var appearance))
{
_appearance.SetData(entity, FootPrintVisualState.State, PickState(uid, dragging), appearance);
_appearance.SetData(entity, FootPrintVisualState.Color, component.PrintsColor, appearance);
}
var color = component.ContainedSolution.GetColor(_protoMan);
color.A = Math.Max(0.3f, component.ContainedSolution.FillFraction);

if (!_transformQuery.TryComp(entity, out var stepTransform))
return;
_appearance.SetData(footprintUid, FootPrintVisualState.State, PickState(uid, dragging), appearance);
_appearance.SetData(footprintUid, FootPrintVisualState.Color, color, appearance);
}

stepTransform.LocalRotation = dragging
? (transform.LocalPosition - component.StepPos).ToAngle() + Angle.FromDegrees(-90f)
: transform.LocalRotation + Angle.FromDegrees(180f);
? (newPos - component.LastStepPos).ToAngle() + Angle.FromDegrees(-90f)
: args.Component.LocalRotation + Angle.FromDegrees(180f);

component.PrintsColor = component.PrintsColor.WithAlpha(Math.Max(0f, component.PrintsColor.A - component.ColorReduceAlpha));
component.StepPos = transform.LocalPosition;

if (!TryComp<SolutionContainerManagerComponent>(entity, out var solutionContainer)
|| !_solution.ResolveSolution((entity, solutionContainer), footPrintComponent.SolutionName, ref footPrintComponent.Solution, out var solution)
|| string.IsNullOrWhiteSpace(component.ReagentToTransfer) || solution.Volume >= 1)
if (!TryComp<SolutionContainerManagerComponent>(footprintUid, out var solutionContainer)
|| !_solution.ResolveSolution((footprintUid, solutionContainer), footPrintComponent.SolutionName, ref footPrintComponent.Solution, out var solution))
return;

_solution.TryAddReagent(footPrintComponent.Solution.Value, component.ReagentToTransfer, 1, out _);
// Transfer from the component to the footprint
var removedReagents = component.ContainedSolution.SplitSolution(component.FootprintVolume);
_solution.ForceAddSolution(footPrintComponent.Solution.Value, removedReagents);

component.RightStep = !component.RightStep;
component.LastStepPos = newPos;
}

private EntityCoordinates CalcCoords(EntityUid uid, FootPrintsComponent component, TransformComponent transform, bool state)
{
if (state)
return new EntityCoordinates(uid, transform.LocalPosition);
return new(uid, transform.LocalPosition);

var offset = component.RightStep
? new Angle(Angle.FromDegrees(180f) + transform.LocalRotation).RotateVec(component.OffsetPrint)
: new Angle(transform.LocalRotation).RotateVec(component.OffsetPrint);

return new EntityCoordinates(uid, transform.LocalPosition + offset);
return new(uid, transform.LocalPosition + offset);
}

private FootPrintVisuals PickState(EntityUid uid, bool dragging)
Expand Down
48 changes: 22 additions & 26 deletions Content.Server/FootPrint/PuddleFootPrintsSystem.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
using System.Linq;
using Content.Shared.FootPrint;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Fluids;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids.Components;
using Content.Shared.Forensics;
using Robust.Shared.Physics.Events;
using Robust.Shared.Prototypes;


namespace Content.Server.FootPrint;

public sealed class PuddleFootPrintsSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;

public override void Initialize()
Expand All @@ -21,32 +22,27 @@ public override void Initialize()

private void OnStepTrigger(EntityUid uid, PuddleFootPrintsComponent component, ref EndCollideEvent args)
{
if (!TryComp<AppearanceComponent>(uid, out var appearance)
|| !TryComp<PuddleComponent>(uid, out var puddle)
|| !TryComp<FootPrintsComponent>(args.OtherEntity, out var tripper)
|| !TryComp<SolutionContainerManagerComponent>(uid, out var solutionManager)
|| !_solutionContainer.ResolveSolution((uid, solutionManager), puddle.SolutionName, ref puddle.Solution, out var solutions))
return;

var totalSolutionQuantity = solutions.Contents.Sum(sol => (float) sol.Quantity);
var waterQuantity = (from sol in solutions.Contents where sol.Reagent.Prototype == "Water" select (float) sol.Quantity).FirstOrDefault();

if (waterQuantity / (totalSolutionQuantity / 100f) > component.OffPercent || solutions.Contents.Count <= 0)
if (!TryComp<PuddleComponent>(uid, out var puddle) || !TryComp<FootPrintsComponent>(args.OtherEntity, out var tripper))
return;

tripper.ReagentToTransfer =
solutions.Contents.Aggregate((l, r) => l.Quantity > r.Quantity ? l : r).Reagent.Prototype;
// Transfer DNAs from the puddle to the tripper
if (TryComp<ForensicsComponent>(uid, out var puddleForensics))
{
tripper.DNAs.UnionWith(puddleForensics.DNAs);
if(TryComp<ForensicsComponent>(args.OtherEntity, out var tripperForensics))
tripperForensics.DNAs.UnionWith(puddleForensics.DNAs);
}

if (_appearance.TryGetData(uid, PuddleVisuals.SolutionColor, out var color, appearance)
&& _appearance.TryGetData(uid, PuddleVisuals.CurrentVolume, out var volume, appearance))
AddColor((Color) color, (float) volume * component.SizeRatio, tripper);
// Transfer reagents from the puddle to the tripper.
// Ideally it should be a two-way process, but that is too hard to simulate and will have very little effect outside of potassium-water spills.
var quantity = puddle.Solution?.Comp?.Solution?.Volume ?? 0;
var footprintsCapacity = tripper.ContainedSolution.AvailableVolume;

_solutionContainer.RemoveEachReagent(puddle.Solution.Value, 1);
}
if (quantity <= 0 || footprintsCapacity <= 0)
return;

private void AddColor(Color col, float quantity, FootPrintsComponent component)
{
component.PrintsColor = component.ColorQuantity == 0f ? col : Color.InterpolateBetween(component.PrintsColor, col, component.ColorInterpolationFactor);
component.ColorQuantity += quantity;
var transferAmount = FixedPoint2.Min(footprintsCapacity, quantity * component.SizeRatio);
var transferred = _solutionContainer.SplitSolution(puddle.Solution!.Value, transferAmount);
tripper.ContainedSolution.AddSolution(transferred, _protoMan);
}
}
9 changes: 9 additions & 0 deletions Content.Shared/Fluids/AbsorbentComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ public sealed partial class AbsorbentComponent : Component
{
Params = AudioParams.Default.WithVariation(SharedContentAudioSystem.DefaultVariation).WithVolume(-3f),
};

[DataField]
public float FootprintCleaningRange = 0.2f;

/// <summary>
/// How many footprints within <see cref="FootprintCleaningRange"/> can be cleaned at once.
/// </summary>
[DataField]
public int MaxCleanedFootprints = 5;
}
Loading
Loading