Climbing system (#1750)

* Initial commit

* Climbing uses its own controller now

* Missed a check

* Get rid of hands check

* Cleanup

* Get rid of speciescomponent stuff

* Remove unneeded check, add separate case for moving other players.

* Add DoAfter

* IClientDraggable added to ClimbingComponent

* Added some basic integration tests. Renamed ClimbMode to Climbing.

* oops

* Minor fixes

* ffff

* Table fix

* Revamped system so its more predicted, uses proper  logic for de-climbing. Get hype!!!

* Flag check fix

* Distance check and reset numticksblocked

* get rid
This commit is contained in:
nuke
2020-08-19 18:13:22 -04:00
committed by GitHub
parent b7e5aafdbc
commit f4909cdb98
13 changed files with 608 additions and 9 deletions

View File

@@ -0,0 +1,11 @@
using Robust.Shared.GameObjects;
namespace Content.Shared.GameObjects.Components.Movement
{
public interface IClimbable { };
public class SharedClimbableComponent : Component, IClimbable
{
public sealed override string Name => "Climbable";
}
}

View File

@@ -0,0 +1,66 @@
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Physics;
using Robust.Shared.Serialization;
using System;
namespace Content.Shared.GameObjects.Components.Movement
{
public abstract class SharedClimbingComponent : Component, IActionBlocker, ICollideSpecial
{
public sealed override string Name => "Climbing";
public sealed override uint? NetID => ContentNetIDs.CLIMBING;
protected ICollidableComponent Body;
protected bool IsOnClimbableThisFrame = false;
protected bool OwnerIsTransitioning
{
get
{
if (Body.TryGetController<ClimbController>(out var controller))
{
return controller.IsActive;
}
return false;
}
}
public abstract bool IsClimbing { get; set; }
bool IActionBlocker.CanMove() => !OwnerIsTransitioning;
bool IActionBlocker.CanChangeDirection() => !OwnerIsTransitioning;
bool ICollideSpecial.PreventCollide(IPhysBody collided)
{
if (((CollisionGroup)collided.CollisionLayer).HasFlag(CollisionGroup.VaultImpassable) && collided.Entity.HasComponent<IClimbable>())
{
IsOnClimbableThisFrame = true;
return IsClimbing;
}
return false;
}
public override void Initialize()
{
base.Initialize();
Owner.TryGetComponent(out Body);
}
[Serializable, NetSerializable]
protected sealed class ClimbModeComponentState : ComponentState
{
public ClimbModeComponentState(bool climbing) : base(ContentNetIDs.CLIMBING)
{
Climbing = climbing;
}
public bool Climbing { get; }
}
}
}

View File

@@ -54,7 +54,6 @@
public const uint STUNNABLE = 1048;
public const uint HUNGER = 1049;
public const uint THIRST = 1050;
public const uint FLASHABLE = 1051;
public const uint BUCKLE = 1052;
public const uint PROJECTILE = 1053;
@@ -65,6 +64,7 @@
public const uint DO_AFTER = 1058;
public const uint RADIATION_PULSE = 1059;
public const uint BODY_MANAGER = 1060;
public const uint CLIMBING = 1061;
// Net IDs for integration tests.
public const uint PREDICTION_TEST = 10001;

View File

@@ -10,21 +10,13 @@ namespace Content.Shared.GameObjects.EntitySystems
public interface IActionBlocker
{
bool CanMove() => true;
bool CanInteract() => true;
bool CanUse() => true;
bool CanThrow() => true;
bool CanSpeak() => true;
bool CanDrop() => true;
bool CanPickup() => true;
bool CanEmote() => true;
bool CanAttack() => true;
bool CanEquip() => true;

View File

@@ -0,0 +1,87 @@
#nullable enable
using Robust.Shared.Maths;
using Robust.Shared.Physics;
namespace Content.Shared.Physics
{
/// <summary>
/// Movement controller used by the climb system. Lerps the player from A to B.
/// Also does checks to make sure the player isn't blocked.
/// </summary>
public class ClimbController : VirtualController
{
private Vector2? _movingTo = null;
private Vector2 _lastKnownPosition = default;
private int _numTicksBlocked = 0;
/// <summary>
/// If 5 ticks have passed and our position has not changed then something is blocking us.
/// </summary>
public bool IsBlocked => _numTicksBlocked > 5 || _isMovingWrongDirection;
/// <summary>
/// If the controller is currently moving the player somewhere, it is considered active.
/// </summary>
public bool IsActive => _movingTo.HasValue;
private float _initialDist = default;
private bool _isMovingWrongDirection = false;
public void TryMoveTo(Vector2 from, Vector2 to)
{
if (ControlledComponent == null)
{
return;
}
_initialDist = (from - to).Length;
_numTicksBlocked = 0;
_lastKnownPosition = from;
_movingTo = to;
_isMovingWrongDirection = false;
}
public override void UpdateAfterProcessing()
{
base.UpdateAfterProcessing();
if (ControlledComponent == null || _movingTo == null)
{
return;
}
if ((ControlledComponent.Owner.Transform.WorldPosition - _lastKnownPosition).Length <= 0.05f)
{
_numTicksBlocked++;
}
else
{
_numTicksBlocked = 0;
}
_lastKnownPosition = ControlledComponent.Owner.Transform.WorldPosition;
if ((ControlledComponent.Owner.Transform.WorldPosition - _movingTo.Value).Length <= 0.05f)
{
_movingTo = null;
}
if (_movingTo.HasValue)
{
var dist = (_lastKnownPosition - _movingTo.Value).Length;
if (dist > _initialDist)
{
_isMovingWrongDirection = true;
}
var diff = _movingTo.Value - ControlledComponent.Owner.Transform.WorldPosition;
LinearVelocity = diff.Normalized * 5;
}
else
{
LinearVelocity = Vector2.Zero;
}
}
}
}