2021-02-12 01:31:19 -08:00
#nullable enable
2021-03-01 03:11:29 +11:00
using System.Collections.Generic ;
2020-08-13 14:40:27 +02:00
using Content.Server.GameObjects.Components.GUI ;
2020-07-07 00:23:41 +02:00
using Content.Server.GameObjects.Components.Items.Storage ;
2019-09-20 13:42:45 -04:00
using Content.Server.GameObjects.Components.Mobs ;
2021-03-01 03:11:29 +11:00
using Content.Server.GameObjects.Components.Movement ;
2019-11-13 17:37:46 -05:00
using Content.Server.GameObjects.Components.Sound ;
2019-04-05 02:04:34 +02:00
using Content.Shared.Audio ;
2019-11-13 17:37:46 -05:00
using Content.Shared.GameObjects.Components.Inventory ;
2020-05-24 11:40:49 +02:00
using Content.Shared.GameObjects.Components.Movement ;
2021-02-23 07:20:35 +00:00
using Content.Shared.GameObjects.Components.Tag ;
2019-04-05 02:04:34 +02:00
using Content.Shared.Maps ;
2020-05-23 01:23:36 +02:00
using Content.Shared.Physics ;
2021-03-01 03:11:29 +11:00
using Content.Shared.Physics.Controllers ;
2019-04-04 16:18:43 +02:00
using JetBrains.Annotations ;
2019-04-15 21:11:38 -06:00
using Robust.Server.GameObjects ;
2021-02-12 01:31:19 -08:00
using Robust.Shared.Audio ;
2021-02-11 01:13:03 -08:00
using Robust.Shared.GameObjects ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.IoC ;
2019-11-13 17:37:46 -05:00
using Robust.Shared.Log ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.Map ;
2021-03-01 03:11:29 +11:00
using Robust.Shared.Maths ;
using Robust.Shared.Physics ;
using Robust.Shared.Physics.Dynamics ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.Prototypes ;
2019-08-17 21:09:09 +02:00
using Robust.Shared.Random ;
2019-04-04 16:18:43 +02:00
2021-03-01 03:11:29 +11:00
namespace Content.Server.Physics.Controllers
2019-04-04 16:18:43 +02:00
{
2021-03-01 03:11:29 +11:00
public class MoverController : SharedMoverController
2019-04-04 16:18:43 +02:00
{
2020-06-24 02:21:20 +02:00
[Dependency] private readonly IPrototypeManager _prototypeManager = default ! ;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default ! ;
[Dependency] private readonly IMapManager _mapManager = default ! ;
[Dependency] private readonly IRobustRandom _robustRandom = default ! ;
2019-04-04 16:18:43 +02:00
2020-06-24 02:21:20 +02:00
private AudioSystem _audioSystem = default ! ;
2019-04-05 02:04:34 +02:00
private const float StepSoundMoveDistanceRunning = 2 ;
private const float StepSoundMoveDistanceWalking = 1.5f ;
2021-03-01 03:11:29 +11:00
private HashSet < EntityUid > _excludedMobs = new ( ) ;
2019-04-04 16:18:43 +02:00
public override void Initialize ( )
{
2020-06-24 02:21:20 +02:00
base . Initialize ( ) ;
2021-03-01 03:11:29 +11:00
_audioSystem = EntitySystem . Get < AudioSystem > ( ) ;
2019-04-04 16:18:43 +02:00
}
2021-03-01 03:11:29 +11:00
public override void UpdateBeforeSolve ( bool prediction , float frameTime )
2019-04-04 16:18:43 +02:00
{
2021-03-01 03:11:29 +11:00
base . UpdateBeforeSolve ( prediction , frameTime ) ;
_excludedMobs . Clear ( ) ;
foreach ( var ( mobMover , mover , physics ) in ComponentManager . EntityQuery < IMobMoverComponent , IMoverComponent , PhysicsComponent > ( ) )
2019-04-04 16:18:43 +02:00
{
2021-03-01 03:11:29 +11:00
_excludedMobs . Add ( mover . Owner . Uid ) ;
HandleMobMovement ( mover , physics , mobMover ) ;
}
foreach ( var mover in ComponentManager . EntityQuery < ShuttleControllerComponent > ( ) )
{
_excludedMobs . Add ( mover . Owner . Uid ) ;
HandleShuttleMovement ( mover ) ;
}
foreach ( var ( mover , physics ) in ComponentManager . EntityQuery < IMoverComponent , PhysicsComponent > ( true ) )
{
if ( _excludedMobs . Contains ( mover . Owner . Uid ) ) continue ;
HandleKinematicMovement ( mover , physics ) ;
2019-04-04 16:18:43 +02:00
}
}
2021-03-01 03:11:29 +11:00
/ *
* Some thoughts :
* Unreal actually doesn ' t predict vehicle movement at all , it ' s purely server - side which I thought was interesting
* The reason for this is that vehicles change direction very slowly compared to players so you don ' t really have the requirement for quick movement anyway
* As such could probably just look at applying a force / impulse to the shuttle server - side only so it controls like the titanic .
* /
private void HandleShuttleMovement ( ShuttleControllerComponent mover )
2020-06-24 02:21:20 +02:00
{
2021-03-01 03:11:29 +11:00
var gridId = mover . Owner . Transform . GridID ;
if ( ! _mapManager . TryGetGrid ( gridId , out var grid ) | | ! EntityManager . TryGetEntity ( grid . GridEntityId , out var gridEntity ) ) return ;
//TODO: Switch to shuttle component
if ( ! gridEntity . TryGetComponent ( out PhysicsComponent ? physics ) )
2020-07-03 23:32:41 +02:00
{
2021-03-01 03:11:29 +11:00
physics = gridEntity . AddComponent < PhysicsComponent > ( ) ;
physics . BodyStatus = BodyStatus . InAir ;
physics . Mass = 1 ;
physics . CanCollide = true ;
physics . AddFixture ( new Fixture ( physics , new PhysShapeGrid ( grid ) ) ) ;
2020-07-03 23:32:41 +02:00
}
2021-03-01 03:11:29 +11:00
// TODO: Uhh this probably doesn't work but I still need to rip out the entity tree and make RenderingTreeSystem use grids so I'm not overly concerned about breaking shuttles.
physics . ApplyForce ( mover . VelocityDir . walking + mover . VelocityDir . sprinting ) ;
mover . VelocityDir = ( Vector2 . Zero , Vector2 . Zero ) ;
2020-06-24 02:21:20 +02:00
}
2020-05-23 01:23:36 +02:00
2021-03-01 03:11:29 +11:00
protected override void HandleFootsteps ( IMoverComponent mover , IMobMoverComponent mobMover )
2020-06-24 02:21:20 +02:00
{
var transform = mover . Owner . Transform ;
// Handle footsteps.
2021-03-01 03:11:29 +11:00
if ( _mapManager . GridExists ( mobMover . LastPosition . GetGridId ( EntityManager ) ) )
2020-06-24 02:21:20 +02:00
{
// Can happen when teleporting between grids.
2021-03-01 03:11:29 +11:00
if ( ! transform . Coordinates . TryDistance ( EntityManager , mobMover . LastPosition , out var distance ) )
2020-09-06 16:11:53 +02:00
{
2021-03-01 03:11:29 +11:00
mobMover . LastPosition = transform . Coordinates ;
2020-09-06 16:11:53 +02:00
return ;
}
2021-03-01 03:11:29 +11:00
mobMover . StepSoundDistance + = distance ;
2020-05-02 15:02:52 +01:00
}
2020-03-30 01:15:23 +02:00
2021-03-01 03:11:29 +11:00
mobMover . LastPosition = transform . Coordinates ;
2020-06-24 02:21:20 +02:00
float distanceNeeded ;
if ( mover . Sprinting )
2020-05-23 01:23:36 +02:00
{
2020-06-24 02:21:20 +02:00
distanceNeeded = StepSoundMoveDistanceRunning ;
2019-04-04 16:18:43 +02:00
}
else
{
2020-06-24 02:21:20 +02:00
distanceNeeded = StepSoundMoveDistanceWalking ;
2019-04-04 16:18:43 +02:00
}
2021-03-01 03:11:29 +11:00
if ( mobMover . StepSoundDistance > distanceNeeded )
2020-05-23 17:18:32 +02:00
{
2021-03-01 03:11:29 +11:00
mobMover . StepSoundDistance = 0 ;
2020-05-23 17:18:32 +02:00
2021-03-01 03:11:29 +11:00
if ( ! mover . Owner . HasTag ( "FootstepSound" ) | | mover . Owner . Transform . GridID = = GridId . Invalid )
2020-05-23 17:18:32 +02:00
{
2020-06-24 02:21:20 +02:00
return ;
2020-05-23 17:18:32 +02:00
}
2020-06-24 02:21:20 +02:00
if ( mover . Owner . TryGetComponent < InventoryComponent > ( out var inventory )
& & inventory . TryGetSlotItem < ItemComponent > ( EquipmentSlotDefines . Slots . SHOES , out var item )
& & item . Owner . TryGetComponent < FootstepModifierComponent > ( out var modifier ) )
2020-05-23 17:18:32 +02:00
{
2020-06-24 02:21:20 +02:00
modifier . PlayFootstep ( ) ;
2020-05-23 17:18:32 +02:00
}
2020-06-24 02:21:20 +02:00
else
2020-04-18 12:10:50 +02:00
{
2021-02-12 01:31:19 -08:00
PlayFootstepSound ( transform . Coordinates , mover . Sprinting ) ;
2020-04-18 12:10:50 +02:00
}
}
2019-04-04 16:18:43 +02:00
}
2019-04-05 02:04:34 +02:00
2021-02-12 01:31:19 -08:00
private void PlayFootstepSound ( EntityCoordinates coordinates , bool sprinting )
2019-04-05 02:04:34 +02:00
{
// Step one: figure out sound collection prototype.
2020-09-06 16:11:53 +02:00
var grid = _mapManager . GetGrid ( coordinates . GetGridId ( EntityManager ) ) ;
2019-04-28 22:08:27 -07:00
var tile = grid . GetTileRef ( coordinates ) ;
2019-04-05 02:04:34 +02:00
2020-11-22 15:02:39 +01:00
// If the coordinates have a FootstepModifier component
// i.e. component that emit sound on footsteps emit that sound
string? soundCollectionName = null ;
foreach ( var maybeFootstep in grid . GetSnapGridCell ( tile . GridIndices , SnapGridOffset . Center ) )
2019-04-05 02:04:34 +02:00
{
2020-11-22 15:02:39 +01:00
if ( maybeFootstep . Owner . TryGetComponent ( out FootstepModifierComponent ? footstep ) )
2019-04-05 02:04:34 +02:00
{
2020-11-22 15:02:39 +01:00
soundCollectionName = footstep . _soundCollectionName ;
2019-04-05 02:04:34 +02:00
break ;
}
}
2020-11-22 15:02:39 +01:00
// if there is no FootstepModifierComponent, determine sound based on tiles
if ( soundCollectionName = = null )
2019-04-05 02:04:34 +02:00
{
// Walking on a tile.
2020-06-24 02:21:20 +02:00
var def = ( ContentTileDefinition ) _tileDefinitionManager [ tile . Tile . TypeId ] ;
2019-04-05 02:04:34 +02:00
if ( def . FootstepSounds = = null )
{
// Nothing to play, oh well.
return ;
}
2020-06-24 02:21:20 +02:00
2019-04-05 02:04:34 +02:00
soundCollectionName = def . FootstepSounds ;
}
// Ok well we know the position of the
2019-08-10 22:17:49 +10:00
try
{
var soundCollection = _prototypeManager . Index < SoundCollectionPrototype > ( soundCollectionName ) ;
2019-08-17 21:09:09 +02:00
var file = _robustRandom . Pick ( soundCollection . PickFiles ) ;
2021-02-12 01:31:19 -08:00
_audioSystem . PlayAtCoords ( file , coordinates , sprinting ? AudioParams . Default . WithVolume ( 0.75f ) : null ) ;
2019-08-10 22:17:49 +10:00
}
catch ( UnknownPrototypeException )
{
// Shouldn't crash over a sound
Logger . ErrorS ( "sound" , $"Unable to find sound collection for {soundCollectionName}" ) ;
}
2019-04-05 02:04:34 +02:00
}
2021-03-01 03:11:29 +11:00
2019-04-04 16:18:43 +02:00
}
}