diff --git a/src/Impostor.Api/Innersloth/MapSpawn.cs b/src/Impostor.Api/Innersloth/MapSpawn.cs deleted file mode 100644 index 3f59f0a8f..000000000 --- a/src/Impostor.Api/Innersloth/MapSpawn.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Numerics; - -namespace Impostor.Api.Innersloth -{ - public class MapSpawn - { - private MapSpawn(float spawnRadius, Vector2 initialSpawnCenter, Vector2 meetingSpawnCenter) - { - SpawnRadius = spawnRadius; - InitialSpawnCenter = initialSpawnCenter; - MeetingSpawnCenter = meetingSpawnCenter; - } - - public static Dictionary Maps { get; } = new Dictionary - { - [MapTypes.Skeld] = new MapSpawn(1.6f, new Vector2(-0.72f, 0.62f), new Vector2(-0.72f, 0.62f)), - [MapTypes.MiraHQ] = new MapSpawn(1.55f, new Vector2(-4.4f, 2.2f), new Vector2(24.043f, 1.72f)), - [MapTypes.Polus] = new MapSpawn(1f, new Vector2(16.64f, -2.46f), new Vector2(17.726f, -16.286f)), - [MapTypes.Airship] = new MapSpawn(0f, new Vector2(-0.66f, -0.5f), new Vector2(-0.66f, -0.5f)), - }; - - public float SpawnRadius { get; } - - public Vector2 InitialSpawnCenter { get; } - - public Vector2 MeetingSpawnCenter { get; } - - public Vector2 GetSpawnLocation(int playerId, int numPlayer, bool initialSpawn) - { - var vector = new Vector2(0, 1); - vector = Rotate(vector, (playerId - 1) * (360f / numPlayer)); - vector *= this.SpawnRadius; - return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f); - } - - private static Vector2 Rotate(Vector2 self, float degrees) - { - var f = 0.017453292f * degrees; - var num = (float)Math.Cos(f); - var num2 = (float)Math.Sin(f); - return new Vector2((self.X * num) - (num2 * self.Y), (self.X * num2) + (num * self.Y)); - } - } -} diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index d1a48a3a0..5df6b8a98 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System.Linq; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Events.Managers; @@ -7,6 +8,7 @@ using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.Rpcs; using Impostor.Server.Events.Player; +using Impostor.Server.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.State; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; @@ -21,6 +23,7 @@ internal partial class InnerCustomNetworkTransform : InnerNetObject private readonly ObjectPool _pool; private ushort _lastSequenceId; + private bool _spawnSnapAllowed; public InnerCustomNetworkTransform(Game game, ILogger logger, InnerPlayerControl playerControl, IEventManager eventManager, ObjectPool pool) : base(game) { @@ -83,13 +86,34 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client { if (call == RpcCalls.SnapTo) { - if (!await ValidateOwnership(call, sender) || !await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) + if (!await ValidateOwnership(call, sender)) { return false; } Rpc21SnapTo.Deserialize(reader, out var position, out var minSid); + if (Game.GameNet.ShipStatus is InnerAirshipStatus airshipStatus) + { + // As part of airship spawning, clients are sending snap to -25 40 for no reason(?), cancelling it works just fine + if (Approximately(position, airshipStatus.PreSpawnLocation)) + { + return false; + } + + if (_spawnSnapAllowed && airshipStatus.SpawnLocations.Any(location => Approximately(position, location))) + { + _spawnSnapAllowed = false; + return true; + } + } + + if (!await ValidateImpostor(call, sender, _playerControl.PlayerInfo)) + { + return false; + } + + // TODO validate vent location await SnapToAsync(sender, position, minSid); return true; } @@ -108,6 +132,11 @@ internal async ValueTask SetPositionAsync(IClientPlayer sender, Vector2 position _pool.Return(playerMovementEvent); } + internal void OnPlayerSpawn() + { + _spawnSnapAllowed = true; + } + private static bool SidGreaterThan(ushort newSid, ushort prevSid) { var num = (ushort)(prevSid + (uint)short.MaxValue); @@ -117,6 +146,12 @@ private static bool SidGreaterThan(ushort newSid, ushort prevSid) : newSid > prevSid || newSid <= num; } + private static bool Approximately(Vector2 a, Vector2 b, float tolerance = 0.1f) + { + var abs = Vector2.Abs(a - b); + return abs.X <= tolerance && abs.Y <= tolerance; + } + private ValueTask SnapToAsync(IClientPlayer sender, Vector2 position, ushort minSid) { if (!SidGreaterThan(minSid, _lastSequenceId)) diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs index 8776a8c49..7f8562809 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerAirshipStatus.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +17,29 @@ public InnerAirshipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(21); + public override float SpawnRadius => throw new NotSupportedException(); + + public override Vector2 InitialSpawnCenter => throw new NotSupportedException(); + + public override Vector2 MeetingSpawnCenter => throw new NotSupportedException(); + + public Vector2 PreSpawnLocation { get; } = new Vector2(-25f, 40f); + + public Vector2[] SpawnLocations { get; } = + { + new Vector2(-0.7f, 8.5f), // Brig + new Vector2(-0.7f, -1.0f), // Engine + new Vector2(15.5f, 0.0f), // MainHall + new Vector2(-7.0f, -11.5f), // Kitchen + new Vector2(20.0f, 10.5f), // Records + new Vector2(33.5f, -1.5f), // CargoBay + }; + + public override Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn) + { + return new Vector2(-25, 40); + } + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs index 04d033fb1..02daf3160 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerMiraShipStatus.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +16,12 @@ public InnerMiraShipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(0); + public override float SpawnRadius => 1.55f; + + public override Vector2 InitialSpawnCenter { get; } = new Vector2(-4.4f, 2.2f); + + public override Vector2 MeetingSpawnCenter { get; } = new Vector2(24.043f, 1.72f); + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs index 7ec077d28..262b313b8 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerPolusShipStatus.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +16,34 @@ public InnerPolusShipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(12); + public override float SpawnRadius => 1f; + + public override Vector2 InitialSpawnCenter { get; } = new Vector2(16.64f, -2.46f); + + public override Vector2 MeetingSpawnCenter { get; } = new Vector2(17.726f, -16.286f); + + public Vector2 MeetingSpawnCenter2 { get; } = new Vector2(-17.7f, -17.5f); + + public override Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn) + { + if (initialSpawn) + { + return base.GetSpawnLocation(player, numPlayers, initialSpawn); + } + + Vector2 position; + if (player.PlayerId < 5) + { + position = this.MeetingSpawnCenter + (new Vector2(1, 0) * player.PlayerId); + } + else + { + position = this.MeetingSpawnCenter2 + (new Vector2(1, 0) * (player.PlayerId - 5)); + } + + return position; + } + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs index 418adef34..dcfa24f08 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerShipStatus.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; @@ -26,6 +27,12 @@ protected InnerShipStatus(Game game) : base(game) public abstract Dictionary Doors { get; } + public abstract float SpawnRadius { get; } + + public abstract Vector2 InitialSpawnCenter { get; } + + public abstract Vector2 MeetingSpawnCenter { get; } + public override ValueTask OnSpawnAsync() { for (var i = 0; i < Doors.Count; i++) @@ -101,10 +108,27 @@ public override async ValueTask HandleRpcAsync(ClientPlayer sender, Client return true; } + public virtual Vector2 GetSpawnLocation(InnerPlayerControl player, int numPlayers, bool initialSpawn) + { + var vector = new Vector2(0, 1); + vector = Rotate(vector, (player.PlayerId - 1) * (360f / numPlayers)); + vector *= this.SpawnRadius; + return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f); + } + protected virtual void AddSystems(Dictionary systems) { systems.Add(SystemTypes.Electrical, new SwitchSystem()); systems.Add(SystemTypes.MedBay, new MedScanSystem()); } + + private static Vector2 Rotate(Vector2 self, float degrees) + { + var f = 0.017453292f * degrees; + var cos = MathF.Cos(f); + var sin = MathF.Sin(f); + + return new Vector2((self.X * cos) - (sin * self.Y), (self.X * sin) + (cos * self.Y)); + } } } diff --git a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs index 12df2f354..9580b7be4 100644 --- a/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs +++ b/src/Impostor.Server/Net/Inner/Objects/ShipStatus/InnerSkeldShipStatus.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Numerics; using Impostor.Api.Innersloth; using Impostor.Api.Net.Inner.Objects.ShipStatus; using Impostor.Server.Net.Inner.Objects.Systems; @@ -15,6 +16,12 @@ public InnerSkeldShipStatus(Game game) : base(game) public override Dictionary Doors { get; } = new Dictionary(13); + public override float SpawnRadius => 1.6f; + + public override Vector2 InitialSpawnCenter { get; } = new Vector2(-0.72f, 0.62f); + + public override Vector2 MeetingSpawnCenter { get; } = new Vector2(-0.72f, 0.62f); + protected override void AddSystems(Dictionary systems) { base.AddSystems(systems); diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs index 74b3c7bba..9a09c1b77 100644 --- a/src/Impostor.Server/Net/State/Game.Data.cs +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -346,6 +346,11 @@ private async ValueTask OnSpawnAsync(InnerNetObject netObj) case InnerMeetingHud meetingHud: { + foreach (var player in _players.Values) + { + player.Character?.NetworkTransform.OnPlayerSpawn(); + } + await _eventManager.CallAsync(new MeetingStartedEvent(this, meetingHud)); break; } diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 823c049f4..20f6c01b2 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -105,10 +105,10 @@ internal async ValueTask StartedAsync() { if (GameState == GameStates.Starting) { - for (var i = 0; i < _players.Values.Count; i++) + foreach (var player in _players.Values) { - var player = _players.Values.ElementAt(i); - await player.Character!.NetworkTransform.SetPositionAsync(player, MapSpawn.Maps[Options.Map].GetSpawnLocation(i, PlayerCount, true), Vector2.Zero); + player.Character?.NetworkTransform.OnPlayerSpawn(); + await player.Character!.NetworkTransform.SetPositionAsync(player, GameNet.ShipStatus!.GetSpawnLocation(player.Character, PlayerCount, true), Vector2.Zero); } GameState = GameStates.Started;