Merge branch 'master' into 2020-08-19-firelocks

This commit is contained in:
Víctor Aguilera Puerto
2020-08-21 16:51:50 +02:00
212 changed files with 3718 additions and 462 deletions

View File

@@ -0,0 +1,55 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Serialization;
using System;
using System.Text.RegularExpressions;
namespace Content.Shared.GameObjects.Components.Disposal
{
public class SharedDisposalRouterComponent : Component
{
public override string Name => "DisposalRouter";
public static readonly Regex TagRegex = new Regex("^[a-zA-Z0-9, ]*$", RegexOptions.Compiled);
[Serializable, NetSerializable]
public class DisposalRouterUserInterfaceState : BoundUserInterfaceState
{
public readonly string Tags;
public DisposalRouterUserInterfaceState(string tags)
{
Tags = tags;
}
}
[Serializable, NetSerializable]
public class UiActionMessage : BoundUserInterfaceMessage
{
public readonly UiAction Action;
public readonly string Tags = "";
public UiActionMessage(UiAction action, string tags)
{
Action = action;
if (Action == UiAction.Ok)
{
Tags = tags.Substring(0, Math.Min(tags.Length, 150));
}
}
}
[Serializable, NetSerializable]
public enum UiAction
{
Ok
}
[Serializable, NetSerializable]
public enum DisposalRouterUiKey
{
Key
}
}
}

View File

@@ -0,0 +1,56 @@
#nullable enable
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Serialization;
using System;
using System.Text.RegularExpressions;
namespace Content.Shared.GameObjects.Components.Disposal
{
public class SharedDisposalTaggerComponent : Component
{
public override string Name => "DisposalTagger";
public static readonly Regex TagRegex = new Regex("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled);
[Serializable, NetSerializable]
public class DisposalTaggerUserInterfaceState : BoundUserInterfaceState
{
public readonly string Tag;
public DisposalTaggerUserInterfaceState(string tag)
{
Tag = tag;
}
}
[Serializable, NetSerializable]
public class UiActionMessage : BoundUserInterfaceMessage
{
public readonly UiAction Action;
public readonly string Tag = "";
public UiActionMessage(UiAction action, string tag)
{
Action = action;
if (Action == UiAction.Ok)
{
Tag = tag.Substring(0, Math.Min(tag.Length, 30));
}
}
}
[Serializable, NetSerializable]
public enum UiAction
{
Ok
}
[Serializable, NetSerializable]
public enum DisposalTaggerUiKey
{
Key
}
}
}

View File

@@ -17,15 +17,18 @@ namespace Content.Shared.GameObjects.Components.Medical
public readonly EntityUid? Entity;
public readonly Dictionary<DamageClass, int> DamageClasses;
public readonly Dictionary<DamageType, int> DamageTypes;
public readonly bool IsScanned;
public MedicalScannerBoundUserInterfaceState(
EntityUid? entity,
Dictionary<DamageClass, int> damageClasses,
Dictionary<DamageType, int> damageTypes)
Dictionary<DamageType, int> damageTypes,
bool isScanned)
{
Entity = entity;
DamageClasses = damageClasses;
DamageTypes = damageTypes;
IsScanned = isScanned;
}
public bool HasDamage()
@@ -56,5 +59,24 @@ namespace Content.Shared.GameObjects.Components.Medical
Green,
Yellow,
}
[Serializable, NetSerializable]
public enum UiButton
{
ScanDNA,
}
[Serializable, NetSerializable]
public class UiButtonPressedMessage : BoundUserInterfaceMessage
{
public readonly UiButton Button;
public UiButtonPressedMessage(UiButton button)
{
Button = button;
}
}
}
}

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

@@ -56,7 +56,7 @@ namespace Content.Shared.GameObjects.Components.Movement
{
get
{
if (Owner.TryGetComponent(out MovementSpeedModifierComponent component))
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? component))
{
return component.CurrentWalkSpeed;
}
@@ -69,7 +69,7 @@ namespace Content.Shared.GameObjects.Components.Movement
{
get
{
if (Owner.TryGetComponent(out MovementSpeedModifierComponent component))
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? component))
{
return component.CurrentSprintSpeed;
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Serialization;
@@ -108,7 +108,7 @@ namespace Content.Shared.GameObjects.Components.PDA
[NetSerializable, Serializable]
public enum PDAVisuals
{
ScreenLit,
FlashlightLit,
}
[NetSerializable, Serializable]

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

@@ -179,7 +179,7 @@ namespace Content.Shared.GameObjects.EntitySystems
}
private static bool TryGetAttachedComponent<T>(ICommonSession? session, [MaybeNullWhen(false)] out T component)
where T : IComponent
where T : class, IComponent
{
component = default;
@@ -188,7 +188,7 @@ namespace Content.Shared.GameObjects.EntitySystems
if (ent == null || !ent.IsValid())
return false;
if (!ent.TryGetComponent(out T comp))
if (!ent.TryGetComponent(out T? comp))
return false;
component = comp;

View File

@@ -12,20 +12,8 @@ namespace Content.Shared.GameObjects.Verbs
/// To add a global verb to all entities,
/// define it and mark it with <see cref="GlobalVerbAttribute"/>
/// </remarks>
public abstract class GlobalVerb
public abstract class GlobalVerb : VerbBase
{
/// <summary>
/// If true, this verb requires the user to be within
/// <see cref="VerbUtility.InteractionRange"/> meters from the entity on which this verb resides.
/// </summary>
public virtual bool RequireInteractionRange => true;
/// <summary>
/// If true, this verb requires both the user and the entity on which
/// this verb resides to be in the same container or no container.
/// </summary>
public virtual bool BlockedByContainers => true;
/// <summary>
/// Gets the visible verb data for the user.
/// </summary>

View File

@@ -12,21 +12,8 @@ namespace Content.Shared.GameObjects.Verbs
/// and mark it with <see cref="VerbAttribute"/>
/// </remarks>
[UsedImplicitly]
public abstract class Verb
public abstract class Verb : VerbBase
{
/// <summary>
/// If true, this verb requires the user to be inside within
/// <see cref="VerbUtility.InteractionRange"/> meters from the entity on which this verb resides.
/// </summary>
public virtual bool RequireInteractionRange => true;
/// <summary>
/// If true, this verb requires both the user and the entity on which
/// this verb resides to be in the same container or no container.
/// OR the user can be the entity's container
/// </summary>
public virtual bool BlockedByContainers => true;
/// <summary>
/// Gets the visible verb data for the user.
/// </summary>

View File

@@ -0,0 +1,18 @@
namespace Content.Shared.GameObjects.Verbs
{
public abstract class VerbBase
{
/// <summary>
/// If true, this verb requires the user to be inside within
/// <see cref="VerbUtility.InteractionRange"/> meters from the entity on which this verb resides.
/// </summary>
public virtual bool RequireInteractionRange => true;
/// <summary>
/// If true, this verb requires both the user and the entity on which
/// this verb resides to be in the same container or no container.
/// OR the user can be the entity's container
/// </summary>
public virtual bool BlockedByContainers => true;
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Robust.Shared.Containers;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
@@ -50,6 +51,21 @@ namespace Content.Shared.GameObjects.Verbs
}
}
public static bool VerbAccessChecks(IEntity user, IEntity target, VerbBase verb)
{
if (verb.RequireInteractionRange && !InVerbUseRange(user, target))
{
return false;
}
if (verb.BlockedByContainers && !VerbContainerCheck(user, target))
{
return false;
}
return true;
}
public static bool InVerbUseRange(IEntity user, IEntity target)
{
var distanceSquared = (user.Transform.WorldPosition - target.Transform.WorldPosition)
@@ -60,5 +76,19 @@ namespace Content.Shared.GameObjects.Verbs
}
return true;
}
public static bool VerbContainerCheck(IEntity user, IEntity target)
{
if (!user.IsInSameOrNoContainer(target))
{
if (!ContainerHelpers.TryGetContainer(target, out var container) ||
container.Owner != user)
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,89 @@
#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;
}
ControlledComponent.WakeBody();
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.1f)
{
_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;
}
}
}
}

View File

@@ -54,6 +54,31 @@ namespace Content.Shared
}
}
protected class MsgTickerLateJoinStatus : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgTickerLateJoinStatus);
public bool Disallowed { get; set; }
public MsgTickerLateJoinStatus(INetChannel channel) : base(NAME, GROUP) { }
#endregion
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
Disallowed = buffer.ReadBoolean();
}
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
buffer.Write(Disallowed);
}
}
protected class MsgTickerLobbyStatus : NetMessage
{
#region REQUIRED
@@ -166,13 +191,13 @@ namespace Content.Shared
#endregion
/// <summary>
/// The Players Ready (SessionID:ready)
/// The Status of the Player in the lobby (ready, observer, ...)
/// </summary>
public Dictionary<NetSessionId, bool> PlayerReady { get; set; }
public Dictionary<NetSessionId, PlayerStatus> PlayerStatus { get; set; }
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
PlayerReady = new Dictionary<NetSessionId, bool>();
PlayerStatus = new Dictionary<NetSessionId, PlayerStatus>();
var length = buffer.ReadInt32();
for (int i = 0; i < length; i++)
{
@@ -183,16 +208,16 @@ namespace Content.Shared
{
serializer.DeserializeDirect(stream, out sessionID);
}
var ready = buffer.ReadBoolean();
PlayerReady.Add(sessionID, ready);
var status = (PlayerStatus)buffer.ReadByte();
PlayerStatus.Add(sessionID, status);
}
}
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
var serializer = IoCManager.Resolve<IRobustSerializer>();
buffer.Write(PlayerReady.Count);
foreach (var p in PlayerReady)
buffer.Write(PlayerStatus.Count);
foreach (var p in PlayerStatus)
{
using (var stream = new MemoryStream())
{
@@ -201,7 +226,7 @@ namespace Content.Shared
stream.TryGetBuffer(out var segment);
buffer.Write(segment);
}
buffer.Write(p.Value);
buffer.Write((byte)p.Value);
}
}
}
@@ -213,7 +238,6 @@ namespace Content.Shared
public string PlayerICName;
public string Role;
public bool Antag;
}
protected class MsgRoundEndMessage : NetMessage
@@ -228,6 +252,7 @@ namespace Content.Shared
#endregion
public string GamemodeTitle;
public string RoundEndText;
public TimeSpan RoundDuration;
@@ -238,6 +263,7 @@ namespace Content.Shared
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
GamemodeTitle = buffer.ReadString();
RoundEndText = buffer.ReadString();
var hours = buffer.ReadInt32();
var mins = buffer.ReadInt32();
@@ -264,6 +290,7 @@ namespace Content.Shared
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
buffer.Write(GamemodeTitle);
buffer.Write(RoundEndText);
buffer.Write(RoundDuration.Hours);
buffer.Write(RoundDuration.Minutes);
buffer.Write(RoundDuration.Seconds);
@@ -280,6 +307,13 @@ namespace Content.Shared
}
}
public enum PlayerStatus : byte
{
NotReady = 0,
Ready,
Observer,
}
}
}