Skip to content

Commit

Permalink
Add prediction to Spill Container verb, add dummy TrySpill methods to…
Browse files Browse the repository at this point in the history
… shared (space-wizards#25813)

* Moved abstract spill methods to shared; added prediction to spill container verb.

* Rerun tests

* Requested changes

* Note Client behavior in Spill method docs
  • Loading branch information
Tayrtahn committed Mar 29, 2024
1 parent 19caf1d commit 4cd2fbd
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 87 deletions.
38 changes: 37 additions & 1 deletion Content.Client/Fluids/PuddleSystem.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Content.Client.IconSmoothing;
using Content.Shared.Chemistry.Components;
using Content.Shared.Fluids;
using Content.Shared.Fluids.Components;
using Robust.Client.GameObjects;
using Robust.Shared.Map;

namespace Content.Client.Fluids;

Expand All @@ -21,7 +23,7 @@ private void OnPuddleAppearance(EntityUid uid, PuddleComponent component, ref Ap
if (args.Sprite == null)
return;

float volume = 1f;
var volume = 1f;

if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
{
Expand Down Expand Up @@ -64,4 +66,38 @@ private void OnPuddleAppearance(EntityUid uid, PuddleComponent component, ref Ap
args.Sprite.Color *= baseColor;
}
}

#region Spill

// Maybe someday we'll have clientside prediction for entity spawning, but not today.
// Until then, these methods do nothing on the client.
/// <inheritdoc/>
public override bool TrySplashSpillAt(EntityUid uid, EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true, EntityUid? user = null)
{
puddleUid = EntityUid.Invalid;
return false;
}

/// <inheritdoc/>
public override bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
{
puddleUid = EntityUid.Invalid;
return false;
}

/// <inheritdoc/>
public override bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true, TransformComponent? transformComponent = null)
{
puddleUid = EntityUid.Invalid;
return false;
}

/// <inheritdoc/>
public override bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true, bool tileReact = true)
{
puddleUid = EntityUid.Invalid;
return false;
}

#endregion Spill
}
7 changes: 0 additions & 7 deletions Content.Server/Fluids/Components/PreventSpillerComponent.cs

This file was deleted.

62 changes: 2 additions & 60 deletions Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
Expand All @@ -8,33 +7,27 @@
using Content.Shared.Clothing.Components;
using Content.Shared.CombatMode.Pacification;
using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory.Events;
using Content.Shared.Popups;
using Content.Shared.Spillable;
using Content.Shared.Throwing;
using Content.Shared.Verbs;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Player;

namespace Content.Server.Fluids.EntitySystems;

public sealed partial class PuddleSystem
{
[Dependency] private readonly OpenableSystem _openable = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;

protected override void InitializeSpillable()
{
base.InitializeSpillable();

SubscribeLocalEvent<SpillableComponent, LandEvent>(SpillOnLand);
// Openable handles the event if it's closed
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: [typeof(OpenableSystem)]);
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
Expand Down Expand Up @@ -134,7 +127,7 @@ private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
return;

if (_openable.IsClosed(entity.Owner))
if (Openable.IsClosed(entity.Owner))
return;

if (args.User != null)
Expand All @@ -153,7 +146,7 @@ private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
private void OnAttemptPacifiedThrow(Entity<SpillableComponent> ent, ref AttemptPacifiedThrowEvent args)
{
// Don’t care about closed containers.
if (_openable.IsClosed(ent))
if (Openable.IsClosed(ent))
return;

// Don’t care about empty containers.
Expand All @@ -163,57 +156,6 @@ private void OnAttemptPacifiedThrow(Entity<SpillableComponent> ent, ref AttemptP
args.Cancel("pacified-cannot-throw-spill");
}

private void AddSpillVerb(Entity<SpillableComponent> entity, ref GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution))
return;

if (_openable.IsClosed(args.Target))
return;

if (solution.Volume == FixedPoint2.Zero)
return;

if (_entityManager.HasComponent<PreventSpillerComponent>(args.User))
return;


Verb verb = new()
{
Text = Loc.GetString("spill-target-verb-get-data-text")
};

// TODO VERB ICONS spill icon? pouring out a glass/beaker?
if (entity.Comp.SpillDelay == null)
{
var target = args.Target;
verb.Act = () =>
{
var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
TrySpillAt(Transform(target).Coordinates, puddleSolution, out _);
};
}
else
{
var user = args.User;
verb.Act = () =>
{
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner)
{
BreakOnDamage = true,
BreakOnMove = true,
NeedHand = true,
});
};
}
verb.Impact = LogImpact.Medium; // dangerous reagent reaction are logged separately.
verb.DoContactInteraction = true;
args.Verbs.Add(verb);
}

private void OnDoAfter(Entity<SpillableComponent> entity, ref SpillDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Target == null)
Expand Down
27 changes: 8 additions & 19 deletions Content.Server/Fluids/EntitySystems/PuddleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly ReactiveSystem _reactive = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
Expand Down Expand Up @@ -551,11 +550,8 @@ public Solution GetOverflowSolution(EntityUid uid, PuddleComponent? puddle = nul

#region Spill

/// <summary>
/// First splashes reagent on reactive entities near the spilling entity, then spills the rest regularly to a
/// puddle. This is intended for 'destructive' spills, like when entities are destroyed or thrown.
/// </summary>
public bool TrySplashSpillAt(EntityUid uid,
/// <inheritdoc/>
public override bool TrySplashSpillAt(EntityUid uid,
EntityCoordinates coordinates,
Solution solution,
out EntityUid puddleUid,
Expand Down Expand Up @@ -600,11 +596,8 @@ public bool TrySplashSpillAt(EntityUid uid,
return TrySpillAt(coordinates, solution, out puddleUid, sound);
}

/// <summary>
/// Spills solution at the specified coordinates.
/// Will add to an existing puddle if present or create a new one if not.
/// </summary>
public bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
/// <inheritdoc/>
public override bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
{
if (solution.Volume == 0)
{
Expand All @@ -622,10 +615,8 @@ public bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out Ent
return TrySpillAt(_map.GetTileRef(gridUid.Value, mapGrid, coordinates), solution, out puddleUid, sound);
}

/// <summary>
/// <see cref="TrySpillAt(Robust.Shared.Map.EntityCoordinates,Content.Shared.Chemistry.Components.Solution,out Robust.Shared.GameObjects.EntityUid,bool)"/>
/// </summary>
public bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true,
/// <inheritdoc/>
public override bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true,
TransformComponent? transformComponent = null)
{
if (!Resolve(uid, ref transformComponent, false))
Expand All @@ -637,10 +628,8 @@ public bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid
return TrySpillAt(transformComponent.Coordinates, solution, out puddleUid, sound: sound);
}

/// <summary>
/// <see cref="TrySpillAt(Robust.Shared.Map.EntityCoordinates,Content.Shared.Chemistry.Components.Solution,out Robust.Shared.GameObjects.EntityUid,bool)"/>
/// </summary>
public bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true,
/// <inheritdoc/>
public override bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true,
bool tileReact = true)
{
if (solution.Volume <= 0)
Expand Down
12 changes: 12 additions & 0 deletions Content.Shared/Fluids/Components/PreventSpillerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Robust.Shared.GameStates;

namespace Content.Shared.Fluids.Components;

/// <summary>
/// Blocks this entity's ability to spill solution containing entities via the verb menu.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class PreventSpillerComponent : Component
{

}
6 changes: 6 additions & 0 deletions Content.Shared/Fluids/Components/SpillableComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

namespace Content.Shared.Fluids.Components;

/// <summary>
/// Makes a solution contained in this entity spillable.
/// Spills can occur when a container with this component overflows,
/// is used to melee attack something, is equipped (see <see cref="SpillWorn"/>),
/// lands after being thrown, or has the Spill verb used.
/// </summary>
[RegisterComponent]
public sealed partial class SpillableComponent : Component
{
Expand Down
60 changes: 60 additions & 0 deletions Content.Shared/Fluids/SharedPuddleSystem.Spillable.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Spillable;
using Content.Shared.Verbs;
using Content.Shared.Weapons.Melee;

namespace Content.Shared.Fluids;

public abstract partial class SharedPuddleSystem
{
[Dependency] protected readonly SharedOpenableSystem Openable = default!;

protected virtual void InitializeSpillable()
{
SubscribeLocalEvent<SpillableComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
}

private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
Expand All @@ -21,4 +30,55 @@ private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent arg
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
}
}

private void AddSpillVerb(Entity<SpillableComponent> entity, ref GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;

if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution))
return;

if (Openable.IsClosed(args.Target))
return;

if (solution.Volume == FixedPoint2.Zero)
return;

if (HasComp<PreventSpillerComponent>(args.User))
return;


Verb verb = new()
{
Text = Loc.GetString("spill-target-verb-get-data-text")
};

// TODO VERB ICONS spill icon? pouring out a glass/beaker?
if (entity.Comp.SpillDelay == null)
{
var target = args.Target;
verb.Act = () =>
{
var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
TrySpillAt(Transform(target).Coordinates, puddleSolution, out _);
};
}
else
{
var user = args.User;
verb.Act = () =>
{
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner)
{
BreakOnDamage = true,
BreakOnMove = true,
NeedHand = true,
});
};
}
verb.Impact = LogImpact.Medium; // dangerous reagent reaction are logged separately.
verb.DoContactInteraction = true;
args.Verbs.Add(verb);
}
}
Loading

0 comments on commit 4cd2fbd

Please sign in to comment.