mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-10 02:41:18 +03:00
* What sitting on code does to a branch + no mo owner v2 * Replacing ViewVariables with AutoNetworkedField + Missed One V2 * Removing Virtual Methods & Renaming ForensicsSystem to SharedForensicsSystem (Also made it abstract) V2 * IProduceWidgets Review Changes & some of my own V2 * Lil Cleanup V2 * Part 1 of Review Changes (Only thing left is the BUI stuff and the constructor) V2 * It now WORKS!!! (Still needs the BUI and constuctor changes, ill figure it out later) * Test (Removal of ServerSide VomitSystem.cs) * Ok... * Moved System BloodstreamSystem.cs to SharedBloodstreamSystem.cs & deleted client BloodStreamSystem.cs to make SharedBloodstreamSystem.cs sealed. (No Unregistered errors) * Prediction * Fix? * No mo log error? * Revert "No mo log error?" This reverts commit 50c15a3deab6af9dffd7baed45820bae5558e41f. * Constructor going up * No ForensicScannerBoundUserInterface.cs (It doesnt wanna scan anymore but it doesnt crash) * For Conflicts * Guh * Yea * Organization & no ErrorHell (maybe) * Dirtying * Dirtying take 2 * Revert "Dirtying take 2" This reverts commit 5735012e21f43808db3ae010fce268eac24d0583. * the dirties dont do much here * For Conflict * Readded * Another Conflict Commit Fix * Conflict Fix Thrice * Empty Space * Keep it simple * Add it back in * Move BloodstreamSystem stuff thats causing the error back to system. This'll prob fix the conflict * Conflict fix? * Trust the fix * Looked at other prediction PR's, they had better code. * To not mix up the system in client * Removing Conflict * For conflict * For the conflic fix, will be removed later * Scuffed Fix * Removal & Adding the Decouple * Took some HEAVY pointers from SirWarocks work. The Roadblock has been CLEARED, DOAFTERS WORK NOW!! * Cleanup & Optimizing, mostly comps. * More Optimization, most of this is just imported Warock Code, his QOL included. Did not want to remove SolutionDNA's tho, mostly due to a Log.Debug in OnPrint. * Forgot that the Print Refreshes, more of Warocks work. * Removing Loc.GetString * All of BloodStream to Shared, hopefully no errors. * Sketchy Dirty Removed * Removed Timer.Spawn, added FrameUpdate cause anything else only updated when the window opened, & a bit of cleanup. * No mo Mispredict * GenerateDnaEvent Predicted * Forgot the user * I knew it was real, bloodstutter is REAL and now GONE. * Cant dirty NewEntityBloodData due to potential stutter, so its safer to put it all back into server. again... * Clearer * Thank you leahcat, no more identity leak. * Routine Maintenance * sealing the class * it checks for this now?! * While im here, FileScope Namespaces & removing unused namespaces * Update Attribute Type (SirWarock Import), it works and is much easier to read. * Forever Fixing Conflicts * Readonly Genocide & Partial Maxing * LGTM, BloodstreamSystem moved to SharedBloodstreamSystem! * Sohn * If OG Github back push this commit * One Billionth Commit Fix * Removed client/server stuff * Made implicit * NewLine & comment on why AutoGenCompState is true * Updatin the rest of the Popups to use Entity * I think that's what they meant? It looks cleaner at least. * Mass Attribute for LocalEvents that are safe to change. * Putting it back as abstract * maybe? * Guhh, rolling back empty client/server of BloodStream * Removed Client/Server BloodstreamSystems, changed access modifier from protected to private, & renamed SharedBloodstreamSystem to BloodstreamSystem * From Protected to Private * Removed comment & made it explicit on what changed to true * Guh, hopefully thats all of it... * Forgot * Review * Test Push * Line 316 in SharedForensicsSystem was causing the errors, better to play it safe * Review Changes * Update Content.Shared/Forensics/Events.cs Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com> * The only thing SolutionDNAs does is search and clears itself. I see no reason to keep it * The print.disabled didnt properly disable when cleared. So ill just use the old if check * Figured out the rest of the SubscribeLocalEvents and networking BloodData cause its fully in Shared --------- Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com>
258 lines
9.9 KiB
C#
258 lines
9.9 KiB
C#
using Content.Shared.Actions;
|
|
using Content.Shared.Actions.Components;
|
|
using Content.Shared.Administration.Logs;
|
|
using Content.Shared.Alert;
|
|
using Content.Shared.Body.Components;
|
|
using Content.Shared.Body.Systems;
|
|
using Content.Shared.Chemistry;
|
|
using Content.Shared.Chemistry.Components;
|
|
using Content.Shared.Chemistry.EntitySystems;
|
|
using Content.Shared.Cloning.Events;
|
|
using Content.Shared.Coordinates;
|
|
using Content.Shared.Database;
|
|
using Content.Shared.FixedPoint;
|
|
using Content.Shared.Fluids.Components;
|
|
using Content.Shared.Gravity;
|
|
using Content.Shared.Mobs;
|
|
using Content.Shared.Movement.Systems;
|
|
using Content.Shared.Slippery;
|
|
using Content.Shared.Toggleable;
|
|
using Content.Shared.Trigger.Components.Effects;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Physics.Events;
|
|
using Robust.Shared.Physics.Systems;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Shared.Rootable;
|
|
|
|
/// <summary>
|
|
/// Adds an action to toggle rooting to the ground, primarily for the Diona species.
|
|
/// Being rooted prevents weighlessness and slipping, but causes any floor contents to transfer its reagents to the bloodstream.
|
|
/// </summary>
|
|
public sealed partial class RootableSystem : EntitySystem
|
|
{
|
|
[Dependency] private AlertsSystem _alerts = default!;
|
|
[Dependency] private IGameTiming _timing = default!;
|
|
[Dependency] private ISharedAdminLogManager _logger = default!;
|
|
[Dependency] private MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
|
[Dependency] private ReactiveSystem _reactive = default!;
|
|
[Dependency] private SharedActionsSystem _actions = default!;
|
|
[Dependency] private SharedAudioSystem _audio = default!;
|
|
[Dependency] private BloodstreamSystem _blood = default!;
|
|
[Dependency] private SharedGravitySystem _gravity = default!;
|
|
[Dependency] private SharedPhysicsSystem _physics = default!;
|
|
[Dependency] private SharedSolutionContainerSystem _solutionContainer = default!;
|
|
|
|
[Dependency] private EntityQuery<PuddleComponent> _puddleQuery = default!;
|
|
[Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<RootableComponent, MapInitEvent>(OnRootableMapInit);
|
|
SubscribeLocalEvent<RootableComponent, ComponentShutdown>(OnRootableShutdown);
|
|
SubscribeLocalEvent<RootableComponent, StartCollideEvent>(OnStartCollide);
|
|
SubscribeLocalEvent<RootableComponent, EndCollideEvent>(OnEndCollide);
|
|
SubscribeLocalEvent<RootableComponent, ToggleActionEvent>(OnRootableToggle);
|
|
SubscribeLocalEvent<RootableComponent, MobStateChangedEvent>(OnMobStateChanged);
|
|
SubscribeLocalEvent<RootableComponent, IsWeightlessEvent>(OnIsWeightless);
|
|
SubscribeLocalEvent<RootableComponent, SlipAttemptEvent>(OnSlipAttempt);
|
|
SubscribeLocalEvent<RootableComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeed);
|
|
SubscribeLocalEvent<RootableComponent, CloningEvent>(OnCloning);
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
var query = EntityQueryEnumerator<RootableComponent, BloodstreamComponent>();
|
|
var curTime = _timing.CurTime;
|
|
while (query.MoveNext(out var uid, out var rooted, out var bloodstream))
|
|
{
|
|
if (!rooted.Rooted || rooted.PuddleEntity == null || curTime < rooted.NextUpdate || !_puddleQuery.TryComp(rooted.PuddleEntity, out var puddleComp))
|
|
continue;
|
|
|
|
rooted.NextUpdate += rooted.TransferFrequency;
|
|
Dirty(uid, rooted);
|
|
PuddleReact((uid, rooted, bloodstream), (rooted.PuddleEntity.Value, puddleComp!));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if the puddle is set up properly and if so, moves on to reacting.
|
|
/// </summary>
|
|
private void PuddleReact(Entity<RootableComponent, BloodstreamComponent> ent, Entity<PuddleComponent> puddleEntity)
|
|
{
|
|
if (!_solutionContainer.ResolveSolution(puddleEntity.Owner, puddleEntity.Comp.SolutionName, ref puddleEntity.Comp.Solution, out var solution) ||
|
|
solution.Contents.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ReactWithEntity(ent, puddleEntity, solution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempt to transfer an amount of the solution to the ent's bloodstream.
|
|
/// </summary>
|
|
private void ReactWithEntity(Entity<RootableComponent, BloodstreamComponent> ent, Entity<PuddleComponent> puddleEntity, Solution solution)
|
|
{
|
|
if (!_solutionContainer.ResolveSolution(ent.Owner, ent.Comp2.BloodSolutionName, ref ent.Comp2.BloodSolution, out var bloodSolution) || bloodSolution.AvailableVolume <= 0)
|
|
return;
|
|
|
|
var availableTransfer = FixedPoint2.Min(solution.Volume, ent.Comp1.TransferRate);
|
|
var transferAmount = FixedPoint2.Min(availableTransfer, bloodSolution.AvailableVolume);
|
|
var transferSolution = _solutionContainer.SplitSolution(puddleEntity.Comp.Solution!.Value, transferAmount);
|
|
|
|
_reactive.DoEntityReaction(ent, transferSolution, ReactionMethod.Ingestion);
|
|
|
|
// Log solution addition by puddle.
|
|
if (_blood.TryAddToBloodstream((ent, ent.Comp2), transferSolution))
|
|
_logger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(ent):target} absorbed puddle {SharedSolutionContainerSystem.ToPrettyString(transferSolution)}");
|
|
}
|
|
|
|
private void OnCloning(Entity<RootableComponent> ent, ref CloningEvent args)
|
|
{
|
|
if (!args.Settings.EventComponents.Contains(Factory.GetRegistration(ent.Comp.GetType()).Name))
|
|
return;
|
|
|
|
// Make sure to set the datafields before adding the component so that the correct action gets spawned on map init.
|
|
var cloneComp = Factory.GetComponent<RootableComponent>();
|
|
cloneComp.Action = ent.Comp.Action;
|
|
cloneComp.RootedAlert = ent.Comp.RootedAlert;
|
|
cloneComp.TransferRate = ent.Comp.TransferRate;
|
|
cloneComp.TransferFrequency = ent.Comp.TransferFrequency;
|
|
cloneComp.SpeedModifier = ent.Comp.SpeedModifier;
|
|
cloneComp.RootSound = ent.Comp.RootSound;
|
|
AddComp(args.CloneUid, cloneComp, true);
|
|
}
|
|
|
|
private void OnRootableMapInit(Entity<RootableComponent> ent, ref MapInitEvent args)
|
|
{
|
|
if (!TryComp(ent, out ActionsComponent? comp))
|
|
return;
|
|
|
|
ent.Comp.NextUpdate = _timing.CurTime;
|
|
Dirty(ent);
|
|
_actions.AddAction(ent, ref ent.Comp.ActionEntity, ent.Comp.Action, component: comp);
|
|
}
|
|
|
|
private void OnRootableShutdown(Entity<RootableComponent> ent, ref ComponentShutdown args)
|
|
{
|
|
if (!TryComp(ent, out ActionsComponent? comp))
|
|
return;
|
|
|
|
var actions = new Entity<ActionsComponent?>(ent, comp);
|
|
_actions.RemoveAction(actions, ent.Comp.ActionEntity);
|
|
_alerts.ClearAlert(ent.Owner, ent.Comp.RootedAlert);
|
|
}
|
|
|
|
private void OnRootableToggle(Entity<RootableComponent> ent, ref ToggleActionEvent args)
|
|
{
|
|
args.Handled = TryToggleRooting((ent, ent));
|
|
}
|
|
|
|
private void OnMobStateChanged(Entity<RootableComponent> ent, ref MobStateChangedEvent args)
|
|
{
|
|
if (ent.Comp.Rooted)
|
|
TryToggleRooting((ent, ent));
|
|
}
|
|
|
|
public bool TryToggleRooting(Entity<RootableComponent?> ent)
|
|
{
|
|
if (!Resolve(ent, ref ent.Comp))
|
|
return false;
|
|
|
|
ent.Comp.Rooted = !ent.Comp.Rooted;
|
|
_movementSpeedModifier.RefreshMovementSpeedModifiers(ent.Owner);
|
|
_gravity.RefreshWeightless(ent.Owner);
|
|
|
|
if (ent.Comp.Rooted)
|
|
{
|
|
_alerts.ShowAlert(ent.Owner, ent.Comp.RootedAlert);
|
|
var curTime = _timing.CurTime;
|
|
if (curTime > ent.Comp.NextUpdate)
|
|
ent.Comp.NextUpdate = curTime;
|
|
}
|
|
else
|
|
{
|
|
_alerts.ClearAlert(ent.Owner, ent.Comp.RootedAlert);
|
|
}
|
|
|
|
_audio.PlayPredicted(ent.Comp.RootSound, ent.Owner.ToCoordinates(), ent);
|
|
Dirty(ent);
|
|
|
|
return true;
|
|
}
|
|
|
|
private void OnIsWeightless(Entity<RootableComponent> ent, ref IsWeightlessEvent args)
|
|
{
|
|
if (args.Handled || !ent.Comp.Rooted)
|
|
return;
|
|
|
|
// Do not cancel weightlessness if the person is in off-grid.
|
|
if (!_gravity.EntityOnGravitySupportingGridOrMap(ent.Owner))
|
|
return;
|
|
|
|
args.IsWeightless = false;
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnSlipAttempt(Entity<RootableComponent> ent, ref SlipAttemptEvent args)
|
|
{
|
|
if (!ent.Comp.Rooted)
|
|
return;
|
|
|
|
if (args.SlipCausingEntity != null && HasComp<DamageOnTriggerComponent>(args.SlipCausingEntity))
|
|
return;
|
|
|
|
args.NoSlip = true;
|
|
}
|
|
|
|
private void OnStartCollide(Entity<RootableComponent> ent, ref StartCollideEvent args)
|
|
{
|
|
if (!_puddleQuery.HasComp(args.OtherEntity))
|
|
return;
|
|
|
|
ent.Comp.PuddleEntity = args.OtherEntity;
|
|
|
|
if (ent.Comp.NextUpdate < _timing.CurTime) // To prevent constantly moving to new puddles resetting the timer.
|
|
ent.Comp.NextUpdate = _timing.CurTime;
|
|
|
|
Dirty(ent);
|
|
}
|
|
|
|
private void OnEndCollide(Entity<RootableComponent> ent, ref EndCollideEvent args)
|
|
{
|
|
if (ent.Comp.PuddleEntity != args.OtherEntity)
|
|
return;
|
|
|
|
var exists = Exists(args.OtherEntity);
|
|
|
|
if (!_physicsQuery.TryComp(ent, out var body))
|
|
return;
|
|
|
|
foreach (var entContact in _physics.GetContactingEntities(ent, body))
|
|
{
|
|
if (exists && entContact == args.OtherEntity)
|
|
continue;
|
|
|
|
if (!_puddleQuery.HasComponent(entContact))
|
|
continue;
|
|
|
|
ent.Comp.PuddleEntity = ent;
|
|
return; // New puddle found, no need to continue.
|
|
}
|
|
|
|
ent.Comp.PuddleEntity = null;
|
|
Dirty(ent);
|
|
}
|
|
|
|
private void OnRefreshMovementSpeed(Entity<RootableComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
|
|
{
|
|
if (ent.Comp.Rooted)
|
|
args.ModifySpeed(ent.Comp.SpeedModifier);
|
|
}
|
|
}
|