diff --git a/Content.Client/GameObjects/Components/Movement/HandTeleporterVisualizer.cs b/Content.Client/GameObjects/Components/Movement/HandTeleporterVisualizer.cs index 8214028483..1be4f0ac86 100644 --- a/Content.Client/GameObjects/Components/Movement/HandTeleporterVisualizer.cs +++ b/Content.Client/GameObjects/Components/Movement/HandTeleporterVisualizer.cs @@ -1,5 +1,6 @@ using System; using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Portal; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Interfaces.GameObjects.Components; diff --git a/Content.Client/GameObjects/Components/Movement/PortalVisualizer.cs b/Content.Client/GameObjects/Components/Movement/PortalVisualizer.cs index 6ce70fc2a3..f7d8e4886e 100644 --- a/Content.Client/GameObjects/Components/Movement/PortalVisualizer.cs +++ b/Content.Client/GameObjects/Components/Movement/PortalVisualizer.cs @@ -1,4 +1,5 @@ using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Portal; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Interfaces.GameObjects.Components; diff --git a/Content.Client/GameObjects/Components/Portal/PortalComponent.cs b/Content.Client/GameObjects/Components/Portal/PortalComponent.cs new file mode 100644 index 0000000000..1dfa71e8e0 --- /dev/null +++ b/Content.Client/GameObjects/Components/Portal/PortalComponent.cs @@ -0,0 +1,10 @@ +using Content.Shared.GameObjects.Components.Portal; +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components.Portal +{ + [RegisterComponent] + public class PortalComponent : SharedPortalComponent + { + } +} diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index 06119019a7..d234452111 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -21,7 +21,6 @@ "HeatResistance", "Teleportable", "ItemTeleporter", - "Portal", "EntityStorage", "Wirecutter", "Screwdriver", diff --git a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs b/Content.Server/GameObjects/Components/Portal/PortalComponent.cs similarity index 64% rename from Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs rename to Content.Server/GameObjects/Components/Portal/PortalComponent.cs index 5ed3700e3f..f177e5bd7a 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs +++ b/Content.Server/GameObjects/Components/Portal/PortalComponent.cs @@ -1,26 +1,22 @@ #nullable enable using System; using System.Collections.Generic; -using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Portal; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; -using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Serialization; using Robust.Shared.Timers; using Robust.Shared.ViewVariables; -namespace Content.Server.GameObjects.Components.Movement +namespace Content.Server.GameObjects.Components.Portal { [RegisterComponent] - public class ServerPortalComponent : SharedPortalComponent + public class PortalComponent : SharedPortalComponent, ICollideBehavior { - [Dependency] private readonly IServerEntityManager _serverEntityManager = default!; - // Potential improvements: Different sounds, // Add Gateways // More efficient form of GetEntitiesIntersecting, @@ -42,10 +38,13 @@ namespace Content.Server.GameObjects.Components.Movement base.ExposeData(serializer); // How long will the portal stay up: 0 is infinite serializer.DataField(ref _aliveTime, "alive_time", 10.0f); + // How long before a specific person can go back into it serializer.DataField(ref _individualPortalCooldown, "individual_cooldown", 2.1f); + // How long before anyone can go in it serializer.DataField(ref _overallPortalCooldown, "overall_cooldown", 2.0f); + serializer.DataField(ref _departureSound, "departure_sound", "/Audio/Effects/teleport_departure.ogg"); serializer.DataField(ref _arrivalSound, "arrival_sound", "/Audio/Effects/teleport_arrival.ogg"); } @@ -54,12 +53,9 @@ namespace Content.Server.GameObjects.Components.Movement { // This will blow up an entity it's attached to base.OnAdd(); - if (Owner.TryGetComponent(out var collide)) - { - //collide.IsHardCollidable = false; - } _state = PortalState.Pending; + if (_aliveTime > 0) { Timer.Spawn(TimeSpan.FromSeconds(_aliveTime), () => Owner.Delete()); @@ -68,16 +64,12 @@ namespace Content.Server.GameObjects.Components.Movement public bool CanBeConnected() { - if (_connectingTeleporter == null) - { - return true; - } - return false; + return _connectingTeleporter == null; } public void TryConnectPortal(IEntity otherPortal) { - if (otherPortal.TryGetComponent(out var connectedPortal) && connectedPortal.CanBeConnected()) + if (otherPortal.TryGetComponent(out var connectedPortal) && connectedPortal.CanBeConnected()) { _connectingTeleporter = otherPortal; connectedPortal._connectingTeleporter = Owner; @@ -87,7 +79,7 @@ namespace Content.Server.GameObjects.Components.Movement public void TryChangeState(PortalState targetState) { - if (Owner == null || Deleted) + if (Deleted) { return; } @@ -102,8 +94,10 @@ namespace Content.Server.GameObjects.Components.Movement private void ReleaseCooldown(IEntity entity) { - if (Owner == null || Deleted) + if (Deleted) + { return; + } if (ImmuneEntities.Contains(entity)) { @@ -111,77 +105,52 @@ namespace Content.Server.GameObjects.Components.Movement } if (_connectingTeleporter != null && - _connectingTeleporter.TryGetComponent(out var otherPortal)) + _connectingTeleporter.TryGetComponent(out var otherPortal)) { otherPortal.ImmuneEntities.Remove(entity); } } - public IEnumerable GetPortableEntities() - { - foreach (var entity in _serverEntityManager.GetEntitiesIntersecting(Owner)) - { - if (IsEntityPortable(entity)) - { - yield return entity; - } - } - } - private bool IsEntityPortable(IEntity entity) { // TODO: Check if it's slotted etc. Otherwise the slot item itself gets ported. - if (!ImmuneEntities.Contains(entity) && entity.HasComponent()) - { - return true; - } - return false; - } - - // TODO: Fix portal updates for performance - public void OnUpdate() - { - if (_onCooldown == false) - { - foreach (var entity in GetPortableEntities()) - { - TryPortalEntity(entity); - break; - } - } + return !ImmuneEntities.Contains(entity) && + entity.HasComponent(); } public void StartCooldown() { - if (_overallPortalCooldown > 0 && _onCooldown == false) - { - _onCooldown = true; - TryChangeState(PortalState.RecentlyTeleported); - if (_connectingTeleporter != null) - { - _connectingTeleporter.TryGetComponent(out var otherPortal); - if (otherPortal != null) - { - otherPortal.TryChangeState(PortalState.RecentlyTeleported); - Timer.Spawn(TimeSpan.FromSeconds(_overallPortalCooldown), () => - { - _onCooldown = false; - TryChangeState(PortalState.Pending); - otherPortal.TryChangeState(PortalState.Pending); - }); - } - } - } - else + if (_overallPortalCooldown <= 0 || _onCooldown) { // Just in case? _onCooldown = false; + return; } + + _onCooldown = true; + TryChangeState(PortalState.RecentlyTeleported); + + if (_connectingTeleporter == null || + !_connectingTeleporter.TryGetComponent(out var otherPortal)) + { + return; + } + + otherPortal.TryChangeState(PortalState.RecentlyTeleported); + + Timer.Spawn(TimeSpan.FromSeconds(_overallPortalCooldown), () => + { + _onCooldown = false; + TryChangeState(PortalState.Pending); + otherPortal.TryChangeState(PortalState.Pending); + }); } public void TryPortalEntity(IEntity entity) { - if (ImmuneEntities.Contains(entity) || _connectingTeleporter == null) + if (ImmuneEntities.Contains(entity) || + _connectingTeleporter == null || + !IsEntityPortable(entity)) { return; } @@ -195,11 +164,20 @@ namespace Content.Server.GameObjects.Components.Movement entity.Transform.Coordinates = position; soundPlayer.PlayAtCoords(_arrivalSound, entity.Transform.Coordinates); TryChangeState(PortalState.RecentlyTeleported); + // To stop spam teleporting. Could potentially look at adding a timer to flush this from the portal ImmuneEntities.Add(entity); - _connectingTeleporter.GetComponent().ImmuneEntities.Add(entity); + _connectingTeleporter.GetComponent().ImmuneEntities.Add(entity); Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => ReleaseCooldown(entity)); StartCooldown(); } + + public void CollideWith(IEntity collidedWith) + { + if (_onCooldown == false) + { + TryPortalEntity(collidedWith); + } + } } } diff --git a/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs b/Content.Server/GameObjects/Components/Portal/TeleportableComponent.cs similarity index 75% rename from Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs rename to Content.Server/GameObjects/Components/Portal/TeleportableComponent.cs index a20b672cc9..5571b955d6 100644 --- a/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs +++ b/Content.Server/GameObjects/Components/Portal/TeleportableComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.GameObjects; -namespace Content.Server.GameObjects.Components.Movement +namespace Content.Server.GameObjects.Components.Portal { [RegisterComponent] public class TeleportableComponent : Component diff --git a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs b/Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs similarity index 93% rename from Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs rename to Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs index 856d81e08b..7ab6c3fd4d 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs +++ b/Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs @@ -1,9 +1,8 @@ #nullable enable using System; using System.Linq; -using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Portal; using Content.Shared.Interfaces.GameObjects.Components; -using Content.Shared.Utility; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; @@ -11,7 +10,6 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -20,11 +18,10 @@ using Robust.Shared.Serialization; using Robust.Shared.Timers; using Robust.Shared.ViewVariables; -namespace Content.Server.GameObjects.Components.Movement +namespace Content.Server.GameObjects.Components.Portal { - [RegisterComponent] - public class ServerTeleporterComponent : Component, IAfterInteract + public class TeleporterComponent : Component, IAfterInteract { [Dependency] private readonly IServerEntityManager _serverEntityManager = default!; [Dependency] private readonly IRobustRandom _spreadRandom = default!; @@ -110,7 +107,7 @@ namespace Content.Server.GameObjects.Components.Movement { // Added this component to avoid stacking portals and causing shenanigans // TODO: Doesn't do a great job of stopping stacking portals for directed - if (entity.HasComponent() || entity.HasComponent()) + if (entity.HasComponent() || entity.HasComponent()) { return; } @@ -154,7 +151,7 @@ namespace Content.Server.GameObjects.Components.Movement // TODO: Check the user's spot? Upside is no stacking TPs but downside is they can't unstuck themselves from walls. foreach (var entity in _serverEntityManager.GetEntitiesIntersecting(user.Transform.MapID, target)) { - if (entity.HasComponent() || entity.HasComponent()) + if (entity.HasComponent() || entity.HasComponent()) { return false; } @@ -231,13 +228,12 @@ namespace Content.Server.GameObjects.Components.Movement // Call Delete here as the teleporter should have control over portal longevity // Departure portal var departurePortal = _serverEntityManager.SpawnEntity("Portal", user.Transform.Coordinates); - departurePortal.TryGetComponent(out var departureComponent); // Arrival portal var arrivalPortal = _serverEntityManager.SpawnEntity("Portal", targetGrid); - if (arrivalPortal.TryGetComponent(out var arrivalComponent)) + if (arrivalPortal.TryGetComponent(out var arrivalComponent)) { - // Connect. TODO: If the OnUpdate in ServerPortalComponent is changed this may need to change as well. + // Connect. arrivalComponent.TryConnectPortal(departurePortal); } } @@ -251,7 +247,6 @@ namespace Content.Server.GameObjects.Components.Movement user.Transform.WorldPosition = vector; soundPlayer.PlayAtCoords(_arrivalSound, user.Transform.Coordinates); } - } } } diff --git a/Content.Server/GameObjects/EntitySystems/PortalSystem.cs b/Content.Server/GameObjects/EntitySystems/PortalSystem.cs deleted file mode 100644 index 08e06fe150..0000000000 --- a/Content.Server/GameObjects/EntitySystems/PortalSystem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Server.GameObjects.Components.Movement; -using JetBrains.Annotations; -using Robust.Shared.GameObjects.Systems; - -namespace Content.Server.GameObjects.EntitySystems -{ - [UsedImplicitly] - internal sealed class PortalSystem : EntitySystem - { - // TODO: Someone refactor portals - public override void Update(float frameTime) - { - foreach (var comp in ComponentManager.EntityQuery()) - { - comp.OnUpdate(); - } - } - } -} diff --git a/Content.Shared/GameObjects/Components/Movement/SharedPortal.cs b/Content.Shared/GameObjects/Components/Movement/SharedPortal.cs deleted file mode 100644 index 8f09903953..0000000000 --- a/Content.Shared/GameObjects/Components/Movement/SharedPortal.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization; - -namespace Content.Shared.GameObjects.Components.Movement -{ - public abstract class SharedPortalComponent : Component { - public override string Name => "Portal"; - } - - [Serializable, NetSerializable] - public enum PortalVisuals - { - State - } - - [Serializable, NetSerializable] - public enum PortalState - { - RecentlyTeleported, - Pending, - UnableToTeleport, - } - -} diff --git a/Content.Shared/GameObjects/Components/Portal/SharedPortalComponent.cs b/Content.Shared/GameObjects/Components/Portal/SharedPortalComponent.cs new file mode 100644 index 0000000000..d2fa86d540 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Portal/SharedPortalComponent.cs @@ -0,0 +1,37 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Portal +{ + public abstract class SharedPortalComponent : Component + { + public override string Name => "Portal"; + + public override void OnAdd() + { + base.OnAdd(); + + if (Owner.TryGetComponent(out var collidable)) + { + collidable.Hard = false; + } + } + } + + [Serializable, NetSerializable] + public enum PortalVisuals + { + State + } + + [Serializable, NetSerializable] + public enum PortalState + { + RecentlyTeleported, + Pending, + UnableToTeleport, + } + +} diff --git a/Content.Shared/GameObjects/Components/Movement/SharedTeleporterComponent.cs b/Content.Shared/GameObjects/Components/Portal/SharedTeleporterComponent.cs similarity index 93% rename from Content.Shared/GameObjects/Components/Movement/SharedTeleporterComponent.cs rename to Content.Shared/GameObjects/Components/Portal/SharedTeleporterComponent.cs index ef166a77fb..b1b71a3492 100644 --- a/Content.Shared/GameObjects/Components/Movement/SharedTeleporterComponent.cs +++ b/Content.Shared/GameObjects/Components/Portal/SharedTeleporterComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Serialization; -namespace Content.Shared.GameObjects.Components.Movement +namespace Content.Shared.GameObjects.Components.Portal { public enum ItemTeleporterState {