The real movement refactor (#9645)
* The real movement refactor * ref events * Jetpack cleanup * a * Vehicles partially working * Balance tweaks * Restore some shitcode * AAAAAAAA * Even more prediction * ECS compstate trying to fix this * yml * vehicles kill me * Don't lock keys * a * Fix problem * Fix sounds * shuttle inputs * Shuttle controls * space brakes * Keybinds * Fix merge * Handle shutdown * Fix keys * Bump friction * fix buckle offset * Fix relay and friction * Fix jetpack turning * contexts amirite
This commit is contained in:
@@ -41,12 +41,6 @@ namespace Content.Server.AI.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: IMover refffaaccctttooorrr
|
||||
if (_entities.HasComponent<IMoverComponent>(entId))
|
||||
{
|
||||
_entities.RemoveComponent<IMoverComponent>(entId);
|
||||
}
|
||||
|
||||
var comp = _entities.AddComponent<UtilityAi>(entId);
|
||||
var behaviorManager = IoCManager.Resolve<INpcBehaviorManager>();
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Content.Server.AI.Steering
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void Unregister(EntityUid entity)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(entity, out SharedPlayerInputMoverComponent? controller))
|
||||
if (EntityManager.TryGetComponent(entity, out InputMoverComponent? controller))
|
||||
{
|
||||
controller.CurTickSprintMovement = Vector2.Zero;
|
||||
}
|
||||
@@ -231,11 +231,11 @@ namespace Content.Server.AI.Steering
|
||||
_listIndex = (_listIndex + 1) % _agentLists.Count;
|
||||
}
|
||||
|
||||
private void SetDirection(SharedPlayerInputMoverComponent component, Vector2 value)
|
||||
private void SetDirection(InputMoverComponent component, Vector2 value)
|
||||
{
|
||||
component.CurTickSprintMovement = value;
|
||||
component._lastInputTick = _timing.CurTick;
|
||||
component._lastInputSubTick = ushort.MaxValue;
|
||||
component.LastInputTick = _timing.CurTick;
|
||||
component.LastInputSubTick = ushort.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -250,7 +250,7 @@ namespace Content.Server.AI.Steering
|
||||
{
|
||||
// Main optimisation to be done below is the redundant calls and adding more variables
|
||||
if (Deleted(entity) ||
|
||||
!EntityManager.TryGetComponent(entity, out SharedPlayerInputMoverComponent? controller) ||
|
||||
!EntityManager.TryGetComponent(entity, out InputMoverComponent? controller) ||
|
||||
!controller.CanMove ||
|
||||
!TryComp(entity, out TransformComponent? xform) ||
|
||||
xform.GridUid == null)
|
||||
|
||||
@@ -18,12 +18,12 @@ namespace Content.Server.Body.Systems
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<BodyComponent, RelayMoveInputEvent>(OnRelayMoveInput);
|
||||
SubscribeLocalEvent<BodyComponent, MoveInputEvent>(OnRelayMoveInput);
|
||||
SubscribeLocalEvent<BodyComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
||||
SubscribeLocalEvent<BodyComponent, BeingMicrowavedEvent>(OnBeingMicrowaved);
|
||||
}
|
||||
|
||||
private void OnRelayMoveInput(EntityUid uid, BodyComponent component, RelayMoveInputEvent args)
|
||||
private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveInputEvent args)
|
||||
{
|
||||
if (EntityManager.TryGetComponent<MobStateComponent>(uid, out var mobState) &&
|
||||
mobState.IsDead() &&
|
||||
|
||||
@@ -40,8 +40,7 @@ namespace Content.Server.Body.Systems
|
||||
Comp<GhostOnMoveComponent>(newEntity).MustBeDead = true;
|
||||
|
||||
// TODO: This is an awful solution.
|
||||
if (!EntityManager.HasComponent<IMoverComponent>(newEntity))
|
||||
EntityManager.AddComponent<SharedDummyInputMoverComponent>(newEntity);
|
||||
EnsureComp<InputMoverComponent>(newEntity);
|
||||
|
||||
oldMind.Mind?.TransferTo(newEntity);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Content.Server.Buckle.Components
|
||||
_buckledTo = value;
|
||||
_buckleTime = _gameTiming.CurTime;
|
||||
_sysMan.GetEntitySystem<ActionBlockerSystem>().UpdateCanMove(Owner);
|
||||
Dirty(_entMan);
|
||||
Dirty(EntMan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,33 +99,6 @@ namespace Content.Server.Buckle.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reattaches this entity to the strap, modifying its position and rotation.
|
||||
/// </summary>
|
||||
/// <param name="strap">The strap to reattach to.</param>
|
||||
public void ReAttach(StrapComponent strap)
|
||||
{
|
||||
var ownTransform = _entMan.GetComponent<TransformComponent>(Owner);
|
||||
var strapTransform = _entMan.GetComponent<TransformComponent>(strap.Owner);
|
||||
|
||||
ownTransform.AttachParent(strapTransform);
|
||||
ownTransform.LocalRotation = Angle.Zero;
|
||||
|
||||
switch (strap.Position)
|
||||
{
|
||||
case StrapPosition.None:
|
||||
break;
|
||||
case StrapPosition.Stand:
|
||||
EntitySystem.Get<StandingStateSystem>().Stand(Owner);
|
||||
break;
|
||||
case StrapPosition.Down:
|
||||
EntitySystem.Get<StandingStateSystem>().Down(Owner, false, false);
|
||||
break;
|
||||
}
|
||||
|
||||
ownTransform.LocalPosition = strap.BuckleOffset;
|
||||
}
|
||||
|
||||
public bool CanBuckle(EntityUid user, EntityUid to, [NotNullWhen(true)] out StrapComponent? strap)
|
||||
{
|
||||
var popupSystem = EntitySystem.Get<SharedPopupSystem>();
|
||||
@@ -136,7 +109,7 @@ namespace Content.Server.Buckle.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_entMan.TryGetComponent(to, out strap))
|
||||
if (!EntMan.TryGetComponent(to, out strap))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -160,7 +133,7 @@ namespace Content.Server.Buckle.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (!_entMan.HasComponent<HandsComponent>(user))
|
||||
if (!EntMan.HasComponent<HandsComponent>(user))
|
||||
{
|
||||
popupSystem.PopupEntity(Loc.GetString("buckle-component-no-hands-message"), user, Filter.Entities(user));
|
||||
return false;
|
||||
@@ -176,10 +149,10 @@ namespace Content.Server.Buckle.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
var parent = _entMan.GetComponent<TransformComponent>(to).Parent;
|
||||
var parent = EntMan.GetComponent<TransformComponent>(to).Parent;
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent == _entMan.GetComponent<TransformComponent>(user))
|
||||
if (parent == EntMan.GetComponent<TransformComponent>(user))
|
||||
{
|
||||
var message = Loc.GetString(Owner == user
|
||||
? "buckle-component-cannot-buckle-message"
|
||||
@@ -224,7 +197,7 @@ namespace Content.Server.Buckle.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
if(_entMan.TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||
if(EntMan.TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||
appearance.SetData(BuckleVisuals.Buckled, true);
|
||||
|
||||
ReAttach(strap);
|
||||
@@ -236,10 +209,10 @@ namespace Content.Server.Buckle.Components
|
||||
UpdateBuckleStatus();
|
||||
|
||||
var ev = new BuckleChangeEvent() { Buckling = true, Strap = BuckledTo.Owner, BuckledEntity = Owner };
|
||||
_entMan.EventBus.RaiseLocalEvent(ev.BuckledEntity, ev, false);
|
||||
_entMan.EventBus.RaiseLocalEvent(ev.Strap, ev, false);
|
||||
EntMan.EventBus.RaiseLocalEvent(ev.BuckledEntity, ev, false);
|
||||
EntMan.EventBus.RaiseLocalEvent(ev.Strap, ev, false);
|
||||
|
||||
if (_entMan.TryGetComponent(Owner, out SharedPullableComponent? ownerPullable))
|
||||
if (EntMan.TryGetComponent(Owner, out SharedPullableComponent? ownerPullable))
|
||||
{
|
||||
if (ownerPullable.Puller != null)
|
||||
{
|
||||
@@ -247,7 +220,7 @@ namespace Content.Server.Buckle.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (_entMan.TryGetComponent(to, out SharedPullableComponent? toPullable))
|
||||
if (EntMan.TryGetComponent(to, out SharedPullableComponent? toPullable))
|
||||
{
|
||||
if (toPullable.Puller == Owner)
|
||||
{
|
||||
@@ -292,7 +265,7 @@ namespace Content.Server.Buckle.Components
|
||||
return false;
|
||||
}
|
||||
// If the strap is a vehicle and the rider is not the person unbuckling, return.
|
||||
if (_entMan.TryGetComponent<VehicleComponent>(oldBuckledTo.Owner, out var vehicle) &&
|
||||
if (EntMan.TryGetComponent<VehicleComponent>(oldBuckledTo.Owner, out var vehicle) &&
|
||||
vehicle.Rider != user)
|
||||
return false;
|
||||
}
|
||||
@@ -312,11 +285,11 @@ namespace Content.Server.Buckle.Components
|
||||
xform.Coordinates = oldBuckledXform.Coordinates.Offset(oldBuckledTo.UnbuckleOffset);
|
||||
}
|
||||
|
||||
if(_entMan.TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||
if(EntMan.TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||
appearance.SetData(BuckleVisuals.Buckled, false);
|
||||
|
||||
if (_entMan.HasComponent<KnockedDownComponent>(Owner)
|
||||
| (_entMan.TryGetComponent<MobStateComponent>(Owner, out var mobState) && mobState.IsIncapacitated()))
|
||||
if (EntMan.HasComponent<KnockedDownComponent>(Owner)
|
||||
| (EntMan.TryGetComponent<MobStateComponent>(Owner, out var mobState) && mobState.IsIncapacitated()))
|
||||
{
|
||||
EntitySystem.Get<StandingStateSystem>().Down(Owner);
|
||||
}
|
||||
@@ -334,8 +307,8 @@ namespace Content.Server.Buckle.Components
|
||||
SoundSystem.Play(oldBuckledTo.UnbuckleSound.GetSound(), Filter.Pvs(Owner), Owner);
|
||||
|
||||
var ev = new BuckleChangeEvent() { Buckling = false, Strap = oldBuckledTo.Owner, BuckledEntity = Owner };
|
||||
_entMan.EventBus.RaiseLocalEvent(Owner, ev, false);
|
||||
_entMan.EventBus.RaiseLocalEvent(oldBuckledTo.Owner, ev, false);
|
||||
EntMan.EventBus.RaiseLocalEvent(Owner, ev, false);
|
||||
EntMan.EventBus.RaiseLocalEvent(oldBuckledTo.Owner, ev, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -386,8 +359,8 @@ namespace Content.Server.Buckle.Components
|
||||
int? drawDepth = null;
|
||||
|
||||
if (BuckledTo != null &&
|
||||
_entMan.GetComponent<TransformComponent>(BuckledTo.Owner).LocalRotation.GetCardinalDir() == Direction.North &&
|
||||
_entMan.TryGetComponent<SpriteComponent>(BuckledTo.Owner, out var spriteComponent))
|
||||
EntMan.GetComponent<TransformComponent>(BuckledTo.Owner).LocalRotation.GetCardinalDir() == Direction.North &&
|
||||
EntMan.TryGetComponent<SpriteComponent>(BuckledTo.Owner, out var spriteComponent))
|
||||
{
|
||||
drawDepth = spriteComponent.DrawDepth - 1;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,10 @@ namespace Content.Server.Buckle.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedStrapComponent))]
|
||||
public sealed class StrapComponent : SharedStrapComponent, ISerializationHooks
|
||||
public sealed class StrapComponent : SharedStrapComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private readonly HashSet<EntityUid> _buckledEntities = new();
|
||||
|
||||
/// <summary>
|
||||
/// The angle in degrees to rotate the player by when they get strapped
|
||||
/// </summary>
|
||||
@@ -28,13 +26,6 @@ namespace Content.Server.Buckle.Components
|
||||
[ViewVariables] [DataField("size")] private int _size = 100;
|
||||
private int _occupiedSize;
|
||||
|
||||
/// <summary>
|
||||
/// The buckled entity will be offset by this amount from the center of the strap object.
|
||||
/// If this offset it too big, it will be clamped to <see cref="MaxBuckleDistance"/>
|
||||
/// </summary>
|
||||
[DataField("buckleOffset", required: false)]
|
||||
public Vector2 BuckleOffsetUnclamped = Vector2.Zero;
|
||||
|
||||
private bool _enabled = true;
|
||||
|
||||
/// <summary>
|
||||
@@ -51,38 +42,11 @@ namespace Content.Server.Buckle.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The distance above which a buckled entity will be automatically unbuckled.
|
||||
/// Don't change it unless you really have to
|
||||
/// </summary>
|
||||
[DataField("maxBuckleDistance", required: false)]
|
||||
public float MaxBuckleDistance = 0.1f;
|
||||
|
||||
/// <summary>
|
||||
/// You can specify the offset the entity will have after unbuckling.
|
||||
/// </summary>
|
||||
[DataField("unbuckleOffset", required: false)]
|
||||
public Vector2 UnbuckleOffset = Vector2.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and clamps the buckle offset to MaxBuckleDistance
|
||||
/// </summary>
|
||||
public Vector2 BuckleOffset => Vector2.Clamp(
|
||||
BuckleOffsetUnclamped,
|
||||
Vector2.One * -MaxBuckleDistance,
|
||||
Vector2.One * MaxBuckleDistance);
|
||||
|
||||
/// <summary>
|
||||
/// The entity that is currently buckled here, synced from <see cref="BuckleComponent.BuckledTo"/>
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<EntityUid> BuckledEntities => _buckledEntities;
|
||||
|
||||
/// <summary>
|
||||
/// The change in position to the strapped mob
|
||||
/// </summary>
|
||||
[DataField("position")]
|
||||
public StrapPosition Position { get; } = StrapPosition.None;
|
||||
|
||||
/// <summary>
|
||||
/// The sound to be played when a mob is buckled
|
||||
/// </summary>
|
||||
@@ -138,7 +102,7 @@ namespace Content.Server.Buckle.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_buckledEntities.Add(buckle.Owner))
|
||||
if (!BuckledEntities.Add(buckle.Owner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -154,6 +118,7 @@ namespace Content.Server.Buckle.Components
|
||||
appearance.SetData("StrapState", true);
|
||||
}
|
||||
|
||||
Dirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -164,7 +129,7 @@ namespace Content.Server.Buckle.Components
|
||||
/// <param name="buckle">The component to remove</param>
|
||||
public void Remove(BuckleComponent buckle)
|
||||
{
|
||||
if (_buckledEntities.Remove(buckle.Owner))
|
||||
if (BuckledEntities.Remove(buckle.Owner))
|
||||
{
|
||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<AppearanceComponent>(Owner, out var appearance))
|
||||
{
|
||||
@@ -172,6 +137,7 @@ namespace Content.Server.Buckle.Components
|
||||
}
|
||||
|
||||
_occupiedSize -= buckle.Size;
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +152,7 @@ namespace Content.Server.Buckle.Components
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
foreach (var entity in _buckledEntities.ToArray())
|
||||
foreach (var entity in BuckledEntities.ToArray())
|
||||
{
|
||||
if (entManager.TryGetComponent<BuckleComponent>(entity, out var buckle))
|
||||
{
|
||||
@@ -194,13 +160,9 @@ namespace Content.Server.Buckle.Components
|
||||
}
|
||||
}
|
||||
|
||||
_buckledEntities.Clear();
|
||||
BuckledEntities.Clear();
|
||||
_occupiedSize = 0;
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
return new StrapComponentState(Position);
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public override bool DragDropOn(DragDropEvent eventArgs)
|
||||
|
||||
@@ -2,11 +2,13 @@ using Content.Server.Buckle.Components;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Buckle;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Server.Buckle.Systems
|
||||
{
|
||||
@@ -20,20 +22,21 @@ namespace Content.Server.Buckle.Systems
|
||||
UpdatesAfter.Add(typeof(InteractionSystem));
|
||||
UpdatesAfter.Add(typeof(InputSystem));
|
||||
|
||||
SubscribeLocalEvent<BuckleComponent, MoveEvent>(MoveEvent);
|
||||
|
||||
SubscribeLocalEvent<StrapComponent, RotateEvent>(RotateEvent);
|
||||
|
||||
SubscribeLocalEvent<StrapComponent, ComponentGetState>(OnStrapGetState);
|
||||
SubscribeLocalEvent<StrapComponent, EntInsertedIntoContainerMessage>(ContainerModifiedStrap);
|
||||
|
||||
SubscribeLocalEvent<StrapComponent, EntRemovedFromContainerMessage>(ContainerModifiedStrap);
|
||||
|
||||
SubscribeLocalEvent<BuckleComponent, MoveEvent>(MoveEvent);
|
||||
SubscribeLocalEvent<BuckleComponent, InteractHandEvent>(HandleInteractHand);
|
||||
|
||||
SubscribeLocalEvent<BuckleComponent, GetVerbsEvent<InteractionVerb>>(AddUnbuckleVerb);
|
||||
SubscribeLocalEvent<BuckleComponent, InsertIntoEntityStorageAttemptEvent>(OnEntityStorageInsertAttempt);
|
||||
}
|
||||
|
||||
private void OnStrapGetState(EntityUid uid, StrapComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new StrapComponentState(component.Position, component.BuckleOffset, component.BuckledEntities, component.MaxBuckleDistance);
|
||||
}
|
||||
|
||||
private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsEvent<InteractionVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || !component.Buckled)
|
||||
@@ -80,21 +83,6 @@ namespace Content.Server.Buckle.Systems
|
||||
buckle.TryUnbuckle(buckle.Owner, true);
|
||||
}
|
||||
|
||||
private void RotateEvent(EntityUid uid, StrapComponent strap, ref RotateEvent ev)
|
||||
{
|
||||
// On rotation of a strap, reattach all buckled entities.
|
||||
// This fixes buckle offsets and draw depths.
|
||||
foreach (var buckledEntity in strap.BuckledEntities)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(buckledEntity, out BuckleComponent? buckled))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
buckled.ReAttach(strap);
|
||||
Dirty(buckled);
|
||||
}
|
||||
}
|
||||
|
||||
private void ContainerModifiedStrap(EntityUid uid, StrapComponent strap, ContainerModifiedMessage message)
|
||||
{
|
||||
foreach (var buckledEntity in strap.BuckledEntities)
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Content.Server.Disposal.Tube
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DisposalTubeComponent, PhysicsBodyTypeChangedEvent>(BodyTypeChanged);
|
||||
SubscribeLocalEvent<DisposalTubeComponent, RelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<DisposalTubeComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<DisposalTubeComponent, BreakageEventArgs>(OnBreak);
|
||||
SubscribeLocalEvent<DisposalTaggerComponent, GetVerbsEvent<InteractionVerb>>(AddOpenUIVerbs);
|
||||
SubscribeLocalEvent<DisposalRouterComponent, GetVerbsEvent<InteractionVerb>>(AddOpenUIVerbs);
|
||||
@@ -65,7 +65,7 @@ namespace Content.Server.Disposal.Tube
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnRelayMovement(EntityUid uid, DisposalTubeComponent component, RelayMovementEntityEvent args)
|
||||
private void OnRelayMovement(EntityUid uid, DisposalTubeComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||
{
|
||||
if (_gameTiming.CurTime < component.LastClang + DisposalTubeComponent.ClangDelay)
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
||||
// Shouldn't need re-anchoring.
|
||||
SubscribeLocalEvent<DisposalUnitComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||
// TODO: Predict me when hands predicted
|
||||
SubscribeLocalEvent<DisposalUnitComponent, RelayMovementEntityEvent>(HandleMovement);
|
||||
SubscribeLocalEvent<DisposalUnitComponent, ContainerRelayMovementEntityEvent>(HandleMovement);
|
||||
SubscribeLocalEvent<DisposalUnitComponent, PowerChangedEvent>(HandlePowerChange);
|
||||
|
||||
// Component lifetime
|
||||
@@ -376,7 +376,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMovement(EntityUid uid, DisposalUnitComponent component, RelayMovementEntityEvent args)
|
||||
private void HandleMovement(EntityUid uid, DisposalUnitComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||
{
|
||||
var currentTime = GameTiming.CurTime;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Content.Server.Ghost
|
||||
SubscribeLocalEvent<GhostComponent, MindRemovedMessage>(OnMindRemovedMessage);
|
||||
SubscribeLocalEvent<GhostComponent, MindUnvisitedMessage>(OnMindUnvisitedMessage);
|
||||
|
||||
SubscribeLocalEvent<GhostOnMoveComponent, RelayMoveInputEvent>(OnRelayMoveInput);
|
||||
SubscribeLocalEvent<GhostOnMoveComponent, MoveInputEvent>(OnRelayMoveInput);
|
||||
|
||||
SubscribeNetworkEvent<GhostWarpsRequestEvent>(OnGhostWarpsRequest);
|
||||
SubscribeNetworkEvent<GhostReturnToBodyRequest>(OnGhostReturnToBodyRequest);
|
||||
@@ -77,7 +77,7 @@ namespace Content.Server.Ghost
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRelayMoveInput(EntityUid uid, GhostOnMoveComponent component, RelayMoveInputEvent args)
|
||||
private void OnRelayMoveInput(EntityUid uid, GhostOnMoveComponent component, ref MoveInputEvent args)
|
||||
{
|
||||
// Let's not ghost if our mind is visiting...
|
||||
if (EntityManager.HasComponent<VisitingMindComponent>(uid)) return;
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Content.Server.Medical.CrewMonitoring
|
||||
// the monitor. But in the special case where the monitor IS a player (i.e., admin ghost), we base it off
|
||||
// the players eye rotation. We don't know what that is for sure, but we know their last grid angle, which
|
||||
// should work well enough?
|
||||
if (TryComp(uid, out IMoverComponent? mover))
|
||||
if (TryComp(uid, out InputMoverComponent? mover))
|
||||
worldRot = mover.LastGridAngle;
|
||||
else if (_mapManager.TryGetGrid(xform.GridUid, out var grid))
|
||||
worldRot = grid.WorldRotation;
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Content.Server.Medical
|
||||
|
||||
SubscribeLocalEvent<MedicalScannerComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<MedicalScannerComponent, ActivateInWorldEvent>(OnActivated);
|
||||
SubscribeLocalEvent<MedicalScannerComponent, RelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<MedicalScannerComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<MedicalScannerComponent, GetVerbsEvent<InteractionVerb>>(AddInsertOtherVerb);
|
||||
SubscribeLocalEvent<MedicalScannerComponent, GetVerbsEvent<AlternativeVerb>>(AddAlternativeVerbs);
|
||||
SubscribeLocalEvent<MedicalScannerComponent, DestructionEventArgs>(OnDestroyed);
|
||||
@@ -65,7 +65,7 @@ namespace Content.Server.Medical
|
||||
UpdateUserInterface(uid, scannerComponent);
|
||||
}
|
||||
|
||||
private void OnRelayMovement(EntityUid uid, MedicalScannerComponent scannerComponent, RelayMovementEntityEvent args)
|
||||
private void OnRelayMovement(EntityUid uid, MedicalScannerComponent scannerComponent, ref ContainerRelayMovementEntityEvent args)
|
||||
{
|
||||
if (!_blocker.CanInteract(args.Entity, scannerComponent.Owner))
|
||||
return;
|
||||
|
||||
@@ -44,13 +44,12 @@ namespace Content.Server.Mind.Commands
|
||||
|
||||
public static void MakeSentient(EntityUid uid, IEntityManager entityManager)
|
||||
{
|
||||
if(entityManager.HasComponent<AiControllerComponent>(uid))
|
||||
entityManager.RemoveComponent<AiControllerComponent>(uid);
|
||||
|
||||
entityManager.RemoveComponent<AiControllerComponent>(uid);
|
||||
|
||||
entityManager.EnsureComponent<MindComponent>(uid);
|
||||
entityManager.EnsureComponent<SharedPlayerInputMoverComponent>(uid);
|
||||
entityManager.EnsureComponent<SharedPlayerMobMoverComponent>(uid);
|
||||
entityManager.EnsureComponent<InputMoverComponent>(uid);
|
||||
entityManager.EnsureComponent<MobMoverComponent>(uid);
|
||||
entityManager.EnsureComponent<MovementSpeedModifierComponent>(uid);
|
||||
entityManager.EnsureComponent<SharedSpeechComponent>(uid);
|
||||
entityManager.EnsureComponent<SharedEmotingComponent>(uid);
|
||||
entityManager.EnsureComponent<ExaminerComponent>(uid);
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
using Content.Server.Cargo.Components;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Content.Shared.Vehicle.Components;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Physics.Controllers
|
||||
{
|
||||
@@ -18,14 +15,8 @@ namespace Content.Server.Physics.Controllers
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly ShuttleSystem _shuttle = default!;
|
||||
[Dependency] private readonly ThrusterSystem _thruster = default!;
|
||||
/// <summary>
|
||||
/// These mobs will get skipped over when checking which mobs
|
||||
/// should be moved. Prediction is handled elsewhere by
|
||||
/// cancelling the movement attempt in the shared and
|
||||
/// client namespace.
|
||||
/// </summary>
|
||||
private HashSet<EntityUid> _excludedMobs = new();
|
||||
private Dictionary<ShuttleComponent, List<(PilotComponent, IMoverComponent, TransformComponent)>> _shuttlePilots = new();
|
||||
|
||||
private Dictionary<ShuttleComponent, List<(PilotComponent, InputMoverComponent, TransformComponent)>> _shuttlePilots = new();
|
||||
|
||||
protected override Filter GetSoundPlayers(EntityUid mover)
|
||||
{
|
||||
@@ -40,31 +31,166 @@ namespace Content.Server.Physics.Controllers
|
||||
public override void UpdateBeforeSolve(bool prediction, float frameTime)
|
||||
{
|
||||
base.UpdateBeforeSolve(prediction, frameTime);
|
||||
_excludedMobs.Clear();
|
||||
|
||||
foreach (var (mobMover, mover, physics, xform) in EntityManager.EntityQuery<IMobMoverComponent, IMoverComponent, PhysicsComponent, TransformComponent>())
|
||||
var bodyQuery = GetEntityQuery<PhysicsComponent>();
|
||||
var relayQuery = GetEntityQuery<RelayInputMoverComponent>();
|
||||
|
||||
foreach (var (mover, xform) in EntityQuery<InputMoverComponent, TransformComponent>())
|
||||
{
|
||||
_excludedMobs.Add(mover.Owner);
|
||||
HandleMobMovement(mover, physics, mobMover, xform, frameTime);
|
||||
if (relayQuery.TryGetComponent(mover.Owner, out var relayed) && relayed != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PhysicsComponent? body = null;
|
||||
|
||||
if (mover.ToParent && relayQuery.HasComponent(xform.ParentUid))
|
||||
{
|
||||
if (!bodyQuery.TryGetComponent(xform.ParentUid, out body)) continue;
|
||||
}
|
||||
else if (!bodyQuery.TryGetComponent(mover.Owner, out body))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HandleMobMovement(mover, body, xform, frameTime);
|
||||
}
|
||||
|
||||
HandleShuttleMovement(frameTime);
|
||||
HandleVehicleMovement();
|
||||
}
|
||||
|
||||
foreach (var (mover, physics) in EntityManager.EntityQuery<IMoverComponent, PhysicsComponent>(true))
|
||||
public (Vector2 Strafe, float Rotation, float Brakes) GetPilotVelocityInput(PilotComponent component)
|
||||
{
|
||||
if (!Timing.InSimulation)
|
||||
{
|
||||
if (_excludedMobs.Contains(mover.Owner)) continue;
|
||||
|
||||
HandleKinematicMovement(mover, physics);
|
||||
// Outside of simulation we'll be running client predicted movement per-frame.
|
||||
// So return a full-length vector as if it's a full tick.
|
||||
// Physics system will have the correct time step anyways.
|
||||
ResetSubtick(component);
|
||||
ApplyTick(component, 1f);
|
||||
return (component.CurTickStrafeMovement, component.CurTickRotationMovement, component.CurTickBraking);
|
||||
}
|
||||
|
||||
float remainingFraction;
|
||||
|
||||
if (Timing.CurTick > component.LastInputTick)
|
||||
{
|
||||
component.CurTickStrafeMovement = Vector2.Zero;
|
||||
component.CurTickRotationMovement = 0f;
|
||||
component.CurTickBraking = 0f;
|
||||
remainingFraction = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingFraction = (ushort.MaxValue - component.LastInputSubTick) / (float) ushort.MaxValue;
|
||||
}
|
||||
|
||||
ApplyTick(component, remainingFraction);
|
||||
|
||||
// Logger.Info($"{curDir}{walk}{sprint}");
|
||||
return (component.CurTickStrafeMovement, component.CurTickRotationMovement, component.CurTickBraking);
|
||||
}
|
||||
|
||||
private void ResetSubtick(PilotComponent component)
|
||||
{
|
||||
if (Timing.CurTick <= component.LastInputTick) return;
|
||||
|
||||
component.CurTickStrafeMovement = Vector2.Zero;
|
||||
component.CurTickRotationMovement = 0f;
|
||||
component.CurTickBraking = 0f;
|
||||
component.LastInputTick = Timing.CurTick;
|
||||
component.LastInputSubTick = 0;
|
||||
}
|
||||
|
||||
protected override void HandleShuttleInput(EntityUid uid, ShuttleButtons button, ushort subTick, bool state)
|
||||
{
|
||||
if (!TryComp<PilotComponent>(uid, out var pilot) || pilot.Console == null) return;
|
||||
|
||||
ResetSubtick(pilot);
|
||||
|
||||
if (subTick >= pilot.LastInputSubTick)
|
||||
{
|
||||
var fraction = (subTick - pilot.LastInputSubTick) / (float) ushort.MaxValue;
|
||||
|
||||
ApplyTick(pilot, fraction);
|
||||
pilot.LastInputSubTick = subTick;
|
||||
}
|
||||
|
||||
var buttons = pilot.HeldButtons;
|
||||
|
||||
if (state)
|
||||
{
|
||||
buttons |= button;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttons &= ~button;
|
||||
}
|
||||
|
||||
pilot.HeldButtons = buttons;
|
||||
}
|
||||
|
||||
private void ApplyTick(PilotComponent component, float fraction)
|
||||
{
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var rot = 0;
|
||||
int brake;
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.StrafeLeft) != 0x0)
|
||||
{
|
||||
x -= 1;
|
||||
}
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.StrafeRight) != 0x0)
|
||||
{
|
||||
x += 1;
|
||||
}
|
||||
|
||||
component.CurTickStrafeMovement.X += x * fraction;
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.StrafeUp) != 0x0)
|
||||
{
|
||||
y += 1;
|
||||
}
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.StrafeDown) != 0x0)
|
||||
{
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
component.CurTickStrafeMovement.Y += y * fraction;
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.RotateLeft) != 0x0)
|
||||
{
|
||||
rot -= 1;
|
||||
}
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.RotateRight) != 0x0)
|
||||
{
|
||||
rot += 1;
|
||||
}
|
||||
|
||||
component.CurTickRotationMovement += rot * fraction;
|
||||
|
||||
if ((component.HeldButtons & ShuttleButtons.Brake) != 0x0)
|
||||
{
|
||||
brake = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
brake = 0;
|
||||
}
|
||||
|
||||
component.CurTickBraking += brake * fraction;
|
||||
}
|
||||
|
||||
private void HandleShuttleMovement(float frameTime)
|
||||
{
|
||||
var newPilots = new Dictionary<ShuttleComponent, List<(PilotComponent Pilot, IMoverComponent Mover, TransformComponent ConsoleXform)>>();
|
||||
var newPilots = new Dictionary<ShuttleComponent, List<(PilotComponent Pilot, InputMoverComponent Mover, TransformComponent ConsoleXform)>>();
|
||||
|
||||
// We just mark off their movement and the shuttle itself does its own movement
|
||||
foreach (var (pilot, mover) in EntityManager.EntityQuery<PilotComponent, SharedPlayerInputMoverComponent>())
|
||||
foreach (var (pilot, mover) in EntityManager.EntityQuery<PilotComponent, InputMoverComponent>())
|
||||
{
|
||||
var consoleEnt = pilot.Console?.Owner;
|
||||
|
||||
@@ -76,8 +202,6 @@ namespace Content.Server.Physics.Controllers
|
||||
|
||||
if (!TryComp<TransformComponent>(consoleEnt, out var xform)) continue;
|
||||
|
||||
_excludedMobs.Add(mover.Owner);
|
||||
|
||||
var gridId = xform.GridUid;
|
||||
// This tries to see if the grid is a shuttle and if the console should work.
|
||||
if (!_mapManager.TryGetGrid(gridId, out var grid) ||
|
||||
@@ -86,7 +210,7 @@ namespace Content.Server.Physics.Controllers
|
||||
|
||||
if (!newPilots.TryGetValue(shuttleComponent, out var pilots))
|
||||
{
|
||||
pilots = new List<(PilotComponent, IMoverComponent, TransformComponent)>();
|
||||
pilots = new List<(PilotComponent, InputMoverComponent, TransformComponent)>();
|
||||
newPilots[shuttleComponent] = pilots;
|
||||
}
|
||||
|
||||
@@ -113,37 +237,57 @@ namespace Content.Server.Physics.Controllers
|
||||
var linearInput = Vector2.Zero;
|
||||
var angularInput = 0f;
|
||||
|
||||
switch (shuttle.Mode)
|
||||
foreach (var (pilot, _, consoleXform) in pilots)
|
||||
{
|
||||
case ShuttleMode.Cruise:
|
||||
foreach (var (pilot, mover, consoleXform) in pilots)
|
||||
var pilotInput = GetPilotVelocityInput(pilot);
|
||||
|
||||
// On the one hand we could just make it relay inputs to brake
|
||||
// but uhh may be disorienting? n
|
||||
if (pilotInput.Brakes > 0f)
|
||||
{
|
||||
if (body.LinearVelocity.Length > 0f)
|
||||
{
|
||||
var sprint = mover.VelocityDir.sprinting;
|
||||
var force = body.LinearVelocity.Normalized * pilotInput.Brakes / body.InvMass * 3f;
|
||||
var impulse = force * body.InvMass * frameTime;
|
||||
|
||||
if (sprint.Equals(Vector2.Zero)) continue;
|
||||
|
||||
var offsetRotation = consoleXform.LocalRotation;
|
||||
|
||||
linearInput += offsetRotation.RotateVec(new Vector2(0f, sprint.Y));
|
||||
angularInput += sprint.X;
|
||||
if (impulse.Length > body.LinearVelocity.Length)
|
||||
{
|
||||
body.LinearVelocity = Vector2.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
body.ApplyLinearImpulse(-force * frameTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ShuttleMode.Strafing:
|
||||
// No angular input possible
|
||||
foreach (var (pilot, mover, consoleXform) in pilots)
|
||||
|
||||
if (body.AngularVelocity != 0f)
|
||||
{
|
||||
var sprint = mover.VelocityDir.sprinting;
|
||||
var force = body.AngularVelocity * pilotInput.Brakes / body.InvI * 2f;
|
||||
var impulse = force * body.InvI * frameTime;
|
||||
|
||||
if (sprint.Equals(Vector2.Zero)) continue;
|
||||
|
||||
var offsetRotation = consoleXform.LocalRotation;
|
||||
sprint = offsetRotation.RotateVec(sprint);
|
||||
|
||||
linearInput += sprint;
|
||||
if (MathF.Abs(impulse) > MathF.Abs(body.AngularVelocity))
|
||||
{
|
||||
body.AngularVelocity = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
body.ApplyAngularImpulse(-force * frameTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pilotInput.Strafe.Length > 0f)
|
||||
{
|
||||
var offsetRotation = consoleXform.LocalRotation;
|
||||
linearInput += offsetRotation.RotateVec(pilotInput.Strafe);
|
||||
}
|
||||
|
||||
if (pilotInput.Rotation != 0f)
|
||||
{
|
||||
angularInput += pilotInput.Rotation;
|
||||
}
|
||||
}
|
||||
|
||||
var count = pilots.Count;
|
||||
@@ -224,8 +368,7 @@ namespace Content.Server.Physics.Controllers
|
||||
totalForce += force;
|
||||
}
|
||||
|
||||
var dragForce = body.LinearVelocity * (totalForce.Length / _shuttle.ShuttleMaxLinearSpeed);
|
||||
body.ApplyLinearImpulse((totalForce - dragForce) * frameTime);
|
||||
body.ApplyLinearImpulse(totalForce * frameTime);
|
||||
}
|
||||
|
||||
if (MathHelper.CloseTo(angularInput, 0f))
|
||||
@@ -263,26 +406,5 @@ namespace Content.Server.Physics.Controllers
|
||||
(ftl.State & (FTLState.Starting | FTLState.Travelling | FTLState.Arriving)) != 0x0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add mobs riding vehicles to the list of mobs whose input
|
||||
/// should be ignored.
|
||||
/// </summary>
|
||||
private void HandleVehicleMovement()
|
||||
{
|
||||
// TODO: Nuke this code. It's on my list.
|
||||
foreach (var (rider, mover) in EntityQuery<RiderComponent, SharedPlayerInputMoverComponent>())
|
||||
{
|
||||
if (rider.Vehicle == null) continue;
|
||||
_excludedMobs.Add(mover.Owner);
|
||||
|
||||
if (!_excludedMobs.Add(rider.Vehicle.Owner)) continue;
|
||||
|
||||
if (!TryComp<IMoverComponent>(rider.Vehicle.Owner, out var vehicleMover) ||
|
||||
!TryComp<PhysicsComponent>(rider.Vehicle.Owner, out var vehicleBody) ||
|
||||
rider.Vehicle.Owner.IsWeightless(vehicleBody, mapManager: _mapManager, entityManager: EntityManager)) continue;
|
||||
|
||||
HandleKinematicMovement(vehicleMover, vehicleBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,13 @@ public sealed class EscapeInventorySystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CanEscapeInventoryComponent, RelayMoveInputEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<CanEscapeInventoryComponent, MoveInputEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<CanEscapeInventoryComponent, UpdateCanMoveEvent>(OnMoveAttempt);
|
||||
SubscribeLocalEvent<CanEscapeInventoryComponent, EscapeDoAfterComplete>(OnEscapeComplete);
|
||||
SubscribeLocalEvent<CanEscapeInventoryComponent, EscapeDoAfterCancel>(OnEscapeFail);
|
||||
}
|
||||
|
||||
private void OnRelayMovement(EntityUid uid, CanEscapeInventoryComponent component, RelayMoveInputEvent args)
|
||||
private void OnRelayMovement(EntityUid uid, CanEscapeInventoryComponent component, ref MoveInputEvent args)
|
||||
{
|
||||
//Prevents the user from creating multiple DoAfters if they're already resisting.
|
||||
if (component.IsResisting == true)
|
||||
|
||||
@@ -21,13 +21,13 @@ public sealed class ResistLockerSystem : EntitySystem
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ResistLockerComponent, RelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<ResistLockerComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<ResistLockerComponent, ResistDoAfterComplete>(OnDoAfterComplete);
|
||||
SubscribeLocalEvent<ResistLockerComponent, ResistDoAfterCancelled>(OnDoAfterCancelled);
|
||||
SubscribeLocalEvent<ResistLockerComponent, EntRemovedFromContainerMessage>(OnRemovedFromContainer);
|
||||
}
|
||||
|
||||
private void OnRelayMovement(EntityUid uid, ResistLockerComponent component, RelayMovementEntityEvent args)
|
||||
private void OnRelayMovement(EntityUid uid, ResistLockerComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||
{
|
||||
if (component.IsResisting)
|
||||
return;
|
||||
|
||||
@@ -8,9 +8,6 @@ namespace Content.Server.Shuttles.Components
|
||||
[ViewVariables]
|
||||
public bool Enabled = true;
|
||||
|
||||
[ViewVariables]
|
||||
public ShuttleMode Mode = ShuttleMode.Cruise;
|
||||
|
||||
/// <summary>
|
||||
/// The cached thrust available for each cardinal direction
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Server.Cargo.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Shuttles.Components;
|
||||
@@ -38,7 +37,6 @@ namespace Content.Server.Shuttles.Systems
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, PowerChangedEvent>(OnConsolePowerChange);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, AnchorStateChangedEvent>(OnConsoleAnchorChange);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, ActivatableUIOpenAttemptEvent>(OnConsoleUIOpenAttempt);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleModeRequestMessage>(OnModeRequest);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, ShuttleConsoleDestinationMessage>(OnDestinationMessage);
|
||||
SubscribeLocalEvent<ShuttleConsoleComponent, BoundUIClosedEvent>(OnConsoleUIClose);
|
||||
|
||||
@@ -47,6 +45,13 @@ namespace Content.Server.Shuttles.Systems
|
||||
|
||||
SubscribeLocalEvent<PilotComponent, MoveEvent>(HandlePilotMove);
|
||||
SubscribeLocalEvent<PilotComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<PilotComponent, ComponentGetStateAttemptEvent>(OnGetStateAttempt);
|
||||
}
|
||||
|
||||
private void OnGetStateAttempt(EntityUid uid, PilotComponent component, ref ComponentGetStateAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled || !TryComp<ActorComponent>(uid, out var actor) || actor.PlayerSession != args.Player)
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnDestinationMessage(EntityUid uid, ShuttleConsoleComponent component, ShuttleConsoleDestinationMessage args)
|
||||
@@ -184,64 +189,6 @@ namespace Content.Server.Shuttles.Systems
|
||||
args.State = new PilotComponentState(component.Console?.Owner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Client is requesting a change in the shuttle's driving mode.
|
||||
/// </summary>
|
||||
private void OnModeRequest(EntityUid uid, ShuttleConsoleComponent component, ShuttleModeRequestMessage args)
|
||||
{
|
||||
var consoleUid = uid;
|
||||
|
||||
if (TryComp<CargoPilotConsoleComponent>(uid, out var cargoPilot) && cargoPilot.Entity != null)
|
||||
{
|
||||
consoleUid = cargoPilot.Entity.Value;
|
||||
}
|
||||
|
||||
if (args.Session.AttachedEntity is not { } player ||
|
||||
!TryComp<PilotComponent>(player, out var pilot) ||
|
||||
!TryComp<ShuttleConsoleComponent>(consoleUid, out var console) ||
|
||||
!TryComp<TransformComponent>(consoleUid, out var consoleXform)) return;
|
||||
|
||||
// Can't check console pilots as it may be remotely piloted!
|
||||
if (!component.SubscribedPilots.Contains(pilot) ||
|
||||
!TryComp<ShuttleComponent>(consoleXform.GridUid, out var shuttle)) return;
|
||||
|
||||
SetShuttleMode(args.Mode, console, shuttle);
|
||||
UpdateState(component);
|
||||
|
||||
if (uid != consoleUid)
|
||||
{
|
||||
UpdateState(console);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the shuttle's movement mode. Does minimal revalidation.
|
||||
/// </summary>
|
||||
private void SetShuttleMode(ShuttleMode mode, ShuttleConsoleComponent consoleComponent,
|
||||
ShuttleComponent shuttleComponent, TransformComponent? consoleXform = null)
|
||||
{
|
||||
// Re-validate
|
||||
if (!this.IsPowered(consoleComponent.Owner, EntityManager) ||
|
||||
!Resolve(consoleComponent.Owner, ref consoleXform) ||
|
||||
!consoleXform.Anchored ||
|
||||
consoleXform.GridUid != Transform(shuttleComponent.Owner).GridUid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
shuttleComponent.Mode = mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ShuttleMode.Strafing:
|
||||
break;
|
||||
case ShuttleMode.Cruise:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the position and angle of all dockingcomponents.
|
||||
/// </summary>
|
||||
@@ -286,7 +233,6 @@ namespace Content.Server.Shuttles.Systems
|
||||
var range = radar?.MaxRange ?? 0f;
|
||||
|
||||
TryComp<ShuttleComponent>(consoleXform?.GridUid, out var shuttle);
|
||||
var mode = shuttle?.Mode ?? ShuttleMode.Cruise;
|
||||
|
||||
var destinations = new List<(EntityUid, string, bool)>();
|
||||
var ftlState = FTLState.Available;
|
||||
@@ -342,7 +288,6 @@ namespace Content.Server.Shuttles.Systems
|
||||
?.SetState(new ShuttleConsoleBoundInterfaceState(
|
||||
ftlState,
|
||||
ftlTime,
|
||||
mode,
|
||||
destinations,
|
||||
range,
|
||||
consoleXform?.Coordinates,
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Content.Server.Storage.EntitySystems
|
||||
SubscribeLocalEvent<ServerStorageComponent, EntRemovedFromContainerMessage>(OnStorageItemRemoved);
|
||||
|
||||
SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb);
|
||||
SubscribeLocalEvent<EntityStorageComponent, RelayMovementEntityEvent>(OnRelayMovement);
|
||||
SubscribeLocalEvent<EntityStorageComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
|
||||
|
||||
SubscribeLocalEvent<StorageFillComponent, MapInitEvent>(OnStorageFillMapInit);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace Content.Server.Storage.EntitySystems
|
||||
UpdateStorageUI(uid, storageComp);
|
||||
}
|
||||
|
||||
private void OnRelayMovement(EntityUid uid, EntityStorageComponent component, RelayMovementEntityEvent args)
|
||||
private void OnRelayMovement(EntityUid uid, EntityStorageComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||
{
|
||||
if (!EntityManager.HasComponent<HandsComponent>(args.Entity))
|
||||
return;
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
using Content.Shared.Vehicle.Components;
|
||||
using Content.Shared.Vehicle;
|
||||
using Content.Shared.Toggleable;
|
||||
using Content.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.Vehicle
|
||||
{
|
||||
/// <summary>
|
||||
/// Controls all the vehicle horns.
|
||||
/// </summary>
|
||||
public sealed class HonkSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<VehicleComponent, HonkActionEvent>(OnHonk);
|
||||
SubscribeLocalEvent<VehicleComponent, ToggleActionEvent>(OnSirenToggle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This fires when the rider presses the honk action
|
||||
/// </summary>
|
||||
private void OnHonk(EntityUid uid, VehicleComponent vehicle, HonkActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
if (vehicle.HornSound != null)
|
||||
{
|
||||
SoundSystem.Play(vehicle.HornSound.GetSound(), Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.1f).WithVolume(8f));
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For vehicles with horn sirens (like the secway) this uses different logic that makes the siren
|
||||
/// loop instead of using a normal honk.
|
||||
/// </summary>
|
||||
private void OnSirenToggle(EntityUid uid, VehicleComponent vehicle, ToggleActionEvent args)
|
||||
{
|
||||
if (args.Handled || !vehicle.HornIsLooping)
|
||||
return;
|
||||
|
||||
if (!vehicle.LoopingHornIsPlaying)
|
||||
{
|
||||
vehicle.SirenPlayingStream?.Stop();
|
||||
vehicle.LoopingHornIsPlaying = true;
|
||||
if (vehicle.HornSound != null)
|
||||
vehicle.SirenPlayingStream = SoundSystem.Play(vehicle.HornSound.GetSound(), Filter.Pvs(uid), uid, AudioParams.Default.WithLoop(true).WithVolume(1.8f));
|
||||
return;
|
||||
}
|
||||
vehicle.SirenPlayingStream?.Stop();
|
||||
vehicle.LoopingHornIsPlaying = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using Content.Server.Buckle.Components;
|
||||
using Content.Shared.Vehicle.Components;
|
||||
using Content.Shared.MobState;
|
||||
using Content.Server.Standing;
|
||||
using Content.Shared.Hands;
|
||||
|
||||
namespace Content.Server.Vehicle
|
||||
{
|
||||
public sealed class RiderSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<RiderComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
|
||||
SubscribeLocalEvent<RiderComponent, FellDownEvent>(OnFallDown);
|
||||
SubscribeLocalEvent<RiderComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick the rider off the vehicle if they press q / drop the virtual item
|
||||
/// </summary>
|
||||
private void OnVirtualItemDeleted(EntityUid uid, RiderComponent component, VirtualItemDeletedEvent args)
|
||||
{
|
||||
if (args.BlockingEntity == component.Vehicle?.Owner)
|
||||
{
|
||||
UnbuckleFromVehicle(uid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick the rider off the vehicle if they get stunned
|
||||
/// </summary>
|
||||
private void OnFallDown(EntityUid uid, RiderComponent rider, FellDownEvent args)
|
||||
{
|
||||
UnbuckleFromVehicle(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick the rider off the vehicle if they go into crit or die.
|
||||
/// </summary>
|
||||
private void OnMobStateChanged(EntityUid uid, RiderComponent rider, MobStateChangedEvent args)
|
||||
{
|
||||
if (args.Component.IsCritical() || args.Component.IsDead())
|
||||
{
|
||||
UnbuckleFromVehicle(uid);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnbuckleFromVehicle(EntityUid uid)
|
||||
{
|
||||
if (!TryComp<BuckleComponent>(uid, out var buckle))
|
||||
return;
|
||||
|
||||
buckle.TryUnbuckle(uid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
Content.Server/Vehicle/VehicleSystem.Rider.cs
Normal file
92
Content.Server/Vehicle/VehicleSystem.Rider.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Content.Server.Buckle.Components;
|
||||
using Content.Shared.Vehicle.Components;
|
||||
using Content.Shared.MobState;
|
||||
using Content.Server.Standing;
|
||||
using Content.Shared.Hands;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Server.Vehicle
|
||||
{
|
||||
public sealed partial class VehicleSystem
|
||||
{
|
||||
private void InitializeRider()
|
||||
{
|
||||
SubscribeLocalEvent<RiderComponent, ComponentStartup>(OnRiderStartup);
|
||||
SubscribeLocalEvent<RiderComponent, ComponentShutdown>(OnRiderShutdown);
|
||||
SubscribeLocalEvent<RiderComponent, MetaFlagRemoveAttemptEvent>(OnRiderRemoval);
|
||||
SubscribeLocalEvent<RiderComponent, ComponentGetState>(OnRiderGetState);
|
||||
SubscribeLocalEvent<RiderComponent, ComponentGetStateAttemptEvent>(OnRiderGetStateAttempt);
|
||||
SubscribeLocalEvent<RiderComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
|
||||
SubscribeLocalEvent<RiderComponent, FellDownEvent>(OnFallDown);
|
||||
SubscribeLocalEvent<RiderComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
}
|
||||
|
||||
private void OnRiderRemoval(EntityUid uid, RiderComponent component, ref MetaFlagRemoveAttemptEvent args)
|
||||
{
|
||||
if ((args.ToRemove & MetaDataFlags.EntitySpecific) != 0x0)
|
||||
args.ToRemove = MetaDataFlags.None;
|
||||
}
|
||||
|
||||
private void OnRiderStartup(EntityUid uid, RiderComponent component, ComponentStartup args)
|
||||
{
|
||||
_metadata.AddFlag(uid, MetaDataFlags.EntitySpecific);
|
||||
}
|
||||
|
||||
private void OnRiderShutdown(EntityUid uid, RiderComponent component, ComponentShutdown args)
|
||||
{
|
||||
_metadata.RemoveFlag(uid, MetaDataFlags.EntitySpecific);
|
||||
}
|
||||
|
||||
private void OnRiderGetStateAttempt(EntityUid uid, RiderComponent component, ref ComponentGetStateAttemptEvent args)
|
||||
{
|
||||
if (uid != args.Player.AttachedEntity)
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnRiderGetState(EntityUid uid, RiderComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new RiderComponentState()
|
||||
{
|
||||
Entity = component.Vehicle,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick the rider off the vehicle if they press q / drop the virtual item
|
||||
/// </summary>
|
||||
private void OnVirtualItemDeleted(EntityUid uid, RiderComponent component, VirtualItemDeletedEvent args)
|
||||
{
|
||||
if (args.BlockingEntity == component.Vehicle)
|
||||
{
|
||||
UnbuckleFromVehicle(uid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick the rider off the vehicle if they get stunned
|
||||
/// </summary>
|
||||
private void OnFallDown(EntityUid uid, RiderComponent rider, FellDownEvent args)
|
||||
{
|
||||
UnbuckleFromVehicle(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kick the rider off the vehicle if they go into crit or die.
|
||||
/// </summary>
|
||||
private void OnMobStateChanged(EntityUid uid, RiderComponent rider, MobStateChangedEvent args)
|
||||
{
|
||||
if (args.Component.IsCritical() || args.Component.IsDead())
|
||||
{
|
||||
UnbuckleFromVehicle(uid);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnbuckleFromVehicle(EntityUid uid)
|
||||
{
|
||||
if (!TryComp<BuckleComponent>(uid, out var buckle))
|
||||
return;
|
||||
|
||||
buckle.TryUnbuckle(uid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server.Buckle.Components;
|
||||
using Content.Shared.Vehicle.Components;
|
||||
using Content.Shared.Vehicle;
|
||||
using Content.Shared.Buckle.Components;
|
||||
@@ -5,44 +6,64 @@ using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Pulling.Components;
|
||||
using Content.Server.Light.Components;
|
||||
using Content.Server.Buckle.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Server.Mind.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||
|
||||
namespace Content.Server.Vehicle
|
||||
{
|
||||
public sealed class VehicleSystem : EntitySystem
|
||||
public sealed partial class VehicleSystem : SharedVehicleSystem
|
||||
{
|
||||
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _modifier = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!;
|
||||
[Dependency] private readonly SharedMoverController _mover = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||
[Dependency] private readonly RiderSystem _riderSystem = default!;
|
||||
|
||||
private const string KeySlot = "key_slot";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
InitializeRider();
|
||||
|
||||
SubscribeLocalEvent<VehicleComponent, HonkActionEvent>(OnHonk);
|
||||
SubscribeLocalEvent<VehicleComponent, BuckleChangeEvent>(OnBuckleChange);
|
||||
SubscribeLocalEvent<VehicleComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<VehicleComponent, MoveEvent>(OnMove);
|
||||
SubscribeLocalEvent<VehicleComponent, EntInsertedIntoContainerMessage>(OnEntInserted);
|
||||
SubscribeLocalEvent<VehicleComponent, EntRemovedFromContainerMessage>(OnEntRemoved);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This fires when the rider presses the honk action
|
||||
/// </summary>
|
||||
private void OnHonk(EntityUid uid, VehicleComponent vehicle, HonkActionEvent args)
|
||||
{
|
||||
if (args.Handled || vehicle.HornSound == null)
|
||||
return;
|
||||
|
||||
// TODO: Need audio refactor maybe, just some way to null it when the stream is over.
|
||||
// For now better to just not loop to keep the code much cleaner.
|
||||
vehicle.HonkPlayingStream?.Stop();
|
||||
vehicle.HonkPlayingStream = SoundSystem.Play(vehicle.HornSound.GetSound(), Filter.Pvs(uid), uid, vehicle.HornSound.Params);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This just controls whether the wheels are turning.
|
||||
/// </summary>
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
foreach (var (vehicle, mover) in EntityQuery<VehicleComponent, SharedPlayerInputMoverComponent>())
|
||||
foreach (var (vehicle, mover) in EntityQuery<VehicleComponent, InputMoverComponent>())
|
||||
{
|
||||
if (mover.VelocityDir.sprinting == Vector2.Zero)
|
||||
if (_mover.GetVelocityInput(mover).Sprinting == Vector2.Zero)
|
||||
{
|
||||
UpdateAutoAnimate(vehicle.Owner, false);
|
||||
continue;
|
||||
@@ -50,103 +71,63 @@ namespace Content.Server.Vehicle
|
||||
UpdateAutoAnimate(vehicle.Owner, true);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the initial appearance / sound, then stores the initial buckle offset and resets it.
|
||||
/// </summary>
|
||||
private void OnComponentInit(EntityUid uid, VehicleComponent component, ComponentInit args)
|
||||
{
|
||||
UpdateDrawDepth(uid, 2);
|
||||
_ambientSound.SetAmbience(uid, false);
|
||||
if (!TryComp<StrapComponent>(uid, out var strap))
|
||||
return;
|
||||
|
||||
component.BaseBuckleOffset = strap.BuckleOffset;
|
||||
strap.BuckleOffsetUnclamped = Vector2.Zero; //You're going to align these facing east, so...
|
||||
}
|
||||
/// <summary>
|
||||
/// Give the user the rider component if they're buckling to the vehicle,
|
||||
/// otherwise remove it.
|
||||
/// </summary>
|
||||
private void OnBuckleChange(EntityUid uid, VehicleComponent component, BuckleChangeEvent args)
|
||||
{
|
||||
// Send an event that our vehicle buckle changed
|
||||
if (TryComp<MindComponent>(args.BuckledEntity, out var mind) && mind.Mind != null && mind.Mind.TryGetSession(out var session))
|
||||
RaiseNetworkEvent(new BuckledToVehicleEvent(uid, args.BuckledEntity, args.Buckling), Filter.SinglePlayer(session));
|
||||
|
||||
// Add Rider
|
||||
if (args.Buckling)
|
||||
{
|
||||
// Add a virtual item to rider's hand, unbuckle if we can't.
|
||||
if (!_virtualItemSystem.TrySpawnVirtualItemInHand(uid, args.BuckledEntity))
|
||||
{
|
||||
_riderSystem.UnbuckleFromVehicle(args.BuckledEntity);
|
||||
UnbuckleFromVehicle(args.BuckledEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up the rider and vehicle with each other
|
||||
EnsureComp<SharedPlayerInputMoverComponent>(uid);
|
||||
EnsureComp<InputMoverComponent>(uid);
|
||||
var rider = EnsureComp<RiderComponent>(args.BuckledEntity);
|
||||
component.Rider = args.BuckledEntity;
|
||||
rider.Vehicle = component;
|
||||
|
||||
var relay = EnsureComp<RelayInputMoverComponent>(args.BuckledEntity);
|
||||
relay.RelayEntity = uid;
|
||||
rider.Vehicle = uid;
|
||||
component.HasRider = true;
|
||||
|
||||
// Handle pulling
|
||||
RemComp<SharedPullableComponent>(args.BuckledEntity);
|
||||
RemComp<SharedPullableComponent>(uid);
|
||||
|
||||
// Let this open doors if it has the key in it
|
||||
if (component.HasKey)
|
||||
{
|
||||
_tagSystem.AddTag(uid, "DoorBumpOpener");
|
||||
}
|
||||
// Update appearance stuff, add actions
|
||||
UpdateBuckleOffset(Transform(uid), component);
|
||||
UpdateDrawDepth(uid, GetDrawDepth(Transform(uid), component.NorthOnly));
|
||||
|
||||
if (TryComp<ActionsComponent>(args.BuckledEntity, out var actions) && TryComp<UnpoweredFlashlightComponent>(uid, out var flashlight))
|
||||
{
|
||||
_actionsSystem.AddAction(args.BuckledEntity, flashlight.ToggleAction, uid, actions);
|
||||
}
|
||||
|
||||
if (component.HornSound != null)
|
||||
{
|
||||
_actionsSystem.AddAction(args.BuckledEntity, component.HornAction, uid, actions);
|
||||
}
|
||||
_itemSlotsSystem.SetLock(uid, component.Name, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove rider
|
||||
|
||||
// Clean up actions and virtual items
|
||||
_actionsSystem.RemoveProvidedActions(args.BuckledEntity, uid);
|
||||
_virtualItemSystem.DeleteInHandsMatching(args.BuckledEntity, uid);
|
||||
// Go back to old pullable behavior
|
||||
_tagSystem.RemoveTag(uid, "DoorBumpOpener");
|
||||
EnsureComp<SharedPullableComponent>(args.BuckledEntity);
|
||||
EnsureComp<SharedPullableComponent>(uid);
|
||||
|
||||
// Entity is no longer riding
|
||||
RemComp<RiderComponent>(args.BuckledEntity);
|
||||
RemComp<RelayInputMoverComponent>(args.BuckledEntity);
|
||||
|
||||
// Reset component
|
||||
component.HasRider = false;
|
||||
component.Rider = null;
|
||||
_itemSlotsSystem.SetLock(uid, component.Name, false);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Every time the vehicle moves we update its visual and buckle positions.
|
||||
/// Not the most beautiful thing but it works.
|
||||
/// </summary>
|
||||
private void OnMove(EntityUid uid, VehicleComponent component, ref MoveEvent args)
|
||||
{
|
||||
// This first check is just for safety
|
||||
if (!HasComp<SharedPlayerInputMoverComponent>(uid))
|
||||
{
|
||||
UpdateAutoAnimate(uid, false);
|
||||
return;
|
||||
}
|
||||
// The random check means the vehicle will stop after a few tiles without a key or without a rider
|
||||
if ((!component.HasRider || !component.HasKey) && _random.Prob(0.015f))
|
||||
{
|
||||
RemComp<SharedPlayerInputMoverComponent>(uid);
|
||||
UpdateAutoAnimate(uid, false);
|
||||
}
|
||||
UpdateBuckleOffset(args.Component, component);
|
||||
UpdateDrawDepth(uid, GetDrawDepth(args.Component, component.NorthOnly));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -155,29 +136,19 @@ namespace Content.Server.Vehicle
|
||||
/// </summary>
|
||||
private void OnEntInserted(EntityUid uid, VehicleComponent component, EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != KeySlot ||
|
||||
!_tagSystem.HasTag(args.Entity, "VehicleKey")) return;
|
||||
|
||||
// Enable vehicle
|
||||
var inVehicle = AddComp<InVehicleComponent>(args.Entity);
|
||||
inVehicle.Vehicle = component;
|
||||
|
||||
if (_tagSystem.HasTag(args.Entity, "VehicleKey"))
|
||||
{
|
||||
// Return if the slot is not the key slot
|
||||
// That slot ID should be inherited from basevehicle in the .yml
|
||||
if (args.Container.ID != "key_slot")
|
||||
{
|
||||
return;
|
||||
}
|
||||
component.HasKey = true;
|
||||
|
||||
// This lets the vehicle move
|
||||
EnsureComp<SharedPlayerInputMoverComponent>(uid);
|
||||
// This lets the vehicle open doors
|
||||
if (component.HasRider)
|
||||
_tagSystem.AddTag(uid, "DoorBumpOpener");
|
||||
|
||||
component.HasKey = true;
|
||||
|
||||
// Audiovisual feedback
|
||||
_ambientSound.SetAmbience(uid, true);
|
||||
}
|
||||
// Audiovisual feedback
|
||||
_ambientSound.SetAmbience(uid, true);
|
||||
_tagSystem.AddTag(uid, "DoorBumpOpener");
|
||||
_modifier.RefreshMovementSpeedModifiers(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -185,84 +156,13 @@ namespace Content.Server.Vehicle
|
||||
/// </summary>
|
||||
private void OnEntRemoved(EntityUid uid, VehicleComponent component, EntRemovedFromContainerMessage args)
|
||||
{
|
||||
RemComp<InVehicleComponent>(args.Entity);
|
||||
if (args.Container.ID != KeySlot || !RemComp<InVehicleComponent>(args.Entity)) return;
|
||||
|
||||
if (_tagSystem.HasTag(args.Entity, "VehicleKey"))
|
||||
{
|
||||
component.HasKey = false;
|
||||
_ambientSound.SetAmbience(uid, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Depending on which direction the vehicle is facing,
|
||||
/// change its draw depth. Vehicles can choose between special drawdetph
|
||||
/// when facing north or south. East and west are easy.
|
||||
/// </summary>
|
||||
private int GetDrawDepth(TransformComponent xform, bool northOnly)
|
||||
{
|
||||
if (northOnly)
|
||||
{
|
||||
return xform.LocalRotation.Degrees switch
|
||||
{
|
||||
< 135f => 5,
|
||||
<= 225f => 2,
|
||||
_ => 5
|
||||
};
|
||||
}
|
||||
return xform.LocalRotation.Degrees switch
|
||||
{
|
||||
< 45f => 5,
|
||||
<= 315f => 2,
|
||||
_ => 5
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the buckle offset based on what direction the vehicle is facing and
|
||||
/// teleport any buckled entities to it. This is the most crucial part of making
|
||||
/// buckled vehicles work.
|
||||
/// </summary>
|
||||
private void UpdateBuckleOffset(TransformComponent xform, VehicleComponent component)
|
||||
{
|
||||
if (!TryComp<StrapComponent>(component.Owner, out var strap))
|
||||
return;
|
||||
strap.BuckleOffsetUnclamped = xform.LocalRotation.Degrees switch
|
||||
{
|
||||
< 45f => (0, component.SouthOverride),
|
||||
<= 135f => component.BaseBuckleOffset,
|
||||
< 225f => (0, component.NorthOverride),
|
||||
<= 315f => (component.BaseBuckleOffset.X * -1, component.BaseBuckleOffset.Y),
|
||||
_ => (0, component.SouthOverride)
|
||||
};
|
||||
|
||||
foreach (var buckledEntity in strap.BuckledEntities)
|
||||
{
|
||||
var buckleXform = Transform(buckledEntity);
|
||||
buckleXform.LocalPosition = strap.BuckleOffset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the draw depth for the sprite.
|
||||
/// </summary>
|
||||
private void UpdateDrawDepth(EntityUid uid, int drawDepth)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
|
||||
appearance.SetData(VehicleVisuals.DrawDepth, drawDepth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether the vehicle's base layer is animating or not.
|
||||
/// </summary>
|
||||
private void UpdateAutoAnimate(EntityUid uid, bool autoAnimate)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
appearance.SetData(VehicleVisuals.AutoAnimate, autoAnimate);
|
||||
// Disable vehicle
|
||||
component.HasKey = false;
|
||||
_ambientSound.SetAmbience(uid, false);
|
||||
_tagSystem.RemoveTag(uid, "DoorBumpOpener");
|
||||
_modifier.RefreshMovementSpeedModifiers(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace Content.Server.Zombies
|
||||
_popupSystem.PopupEntity(Loc.GetString("zombie-transform", ("target", target)), target, Filter.Pvs(target));
|
||||
|
||||
//Make it sentient if it's an animal or something
|
||||
if (!HasComp<SharedDummyInputMoverComponent>(target)) //this component is cursed and fucks shit up
|
||||
if (!HasComp<InputMoverComponent>(target)) //this component is cursed and fucks shit up
|
||||
MakeSentientCommand.MakeSentient(target, EntityManager);
|
||||
|
||||
//Make the zombie not die in the cold. Good for space zombies
|
||||
|
||||
Reference in New Issue
Block a user