using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net.Objects;
+using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Net
{
public class PlayerChatEvent : IGameEvent
{
- public PlayerChatEvent(IGame game, InnerPlayerControl playerControl, string message)
+ public PlayerChatEvent(IGame game, IInnerPlayerControl playerControl, string message)
{
Game = game;
PlayerControl = playerControl;
public IGame Game { get; }
- public InnerPlayerControl PlayerControl { get; }
+ public IInnerPlayerControl PlayerControl { get; }
public string Message { get; }
}
using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net.Objects;
+using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Net
{
public class PlayerDestroyedEvent : IGameEvent
{
- public PlayerDestroyedEvent(IGame game, InnerPlayerControl playerControl)
+ public PlayerDestroyedEvent(IGame game, IInnerPlayerControl playerControl)
{
Game = game;
PlayerControl = playerControl;
public IGame Game { get; }
- public InnerPlayerControl PlayerControl { get; }
+ public IInnerPlayerControl PlayerControl { get; }
}
}
\ No newline at end of file
using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net.Objects;
+using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Net
{
public class PlayerSpawnedEvent : IGameEvent
{
- public PlayerSpawnedEvent(IGame game, InnerPlayerControl playerControl)
+ public PlayerSpawnedEvent(IGame game, IInnerPlayerControl playerControl)
{
Game = game;
PlayerControl = playerControl;
public IGame Game { get; }
- public InnerPlayerControl PlayerControl { get; }
+ public IInnerPlayerControl PlayerControl { get; }
}
}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api
-{
- public static class MessageReaderExtensions
- {
- public static T ReadNetObject<T>(this IMessageReader reader, IGame game)
- where T : InnerNetObject
- {
- return game.FindObjectByNetId<T>(reader.ReadPackedUInt32());
- }
- }
-}
\ No newline at end of file
-using Impostor.Api.Innersloth.Net.Objects.Systems;
+using Impostor.Api.Innersloth;
namespace Impostor.Api
{
using System.Linq;
using Impostor.Api.Games.Managers;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
namespace Impostor.Api.Games
{
using System.Net;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
-using Impostor.Api.Innersloth.Data;
-using Impostor.Api.Innersloth.Net;
using Impostor.Api.Net;
+using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Games
IClientPlayer GetClientPlayer(int clientId);
- T FindObjectByNetId<T>(uint netId)
- where T : InnerNetObject;
-
/// <summary>
/// Send the message to all players.
/// </summary>
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public enum AlterGameTags : byte
+ {
+ ChangePrivacy = 1,
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public enum ChatNoteType : byte
+ {
+ DidVote = 0,
+ }
+}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Data
-{
- public enum AlterGameTags : byte
- {
- ChangePrivacy = 1
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Data
-{
- public enum ChatNoteType : byte
- {
- DidVote = 0,
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Data
-{
- public enum DeathReason
- {
- Exile = 0,
- Kill = 1,
- Disconnect = 2
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Data
-{
- public enum DisconnectReason
- {
- ExitGame = 0,
- // The game you tried to join is full.
- // Check with the host to see if you can join next round.
- GameFull = 1,
- // The game you tried to join already started.
- // Check with the host to see if you can join next round.
- GameStarted = 2,
- // Could not find the game you're looking for.
- GameMissing = 3,
- IncorrectGame = 18,
- // For these a message can be given, specifying an empty message shows
- // "An unknown error disconnected you from the server."
- CustomMessage1 = 4,
- Custom = 8,
- // CustomMessage3 = 11,
- // CustomMessage4 = 12,
- // CustomMessage5 = 13,
- // CustomMessage6 = 14,
- // CustomMessage7 = 15,
- // You are running an older version of the game.
- // Please update to play with others.
- IncorrectVersion = 5,
- // You cannot rejoin that room.
- // You were banned
- Banned = 6,
- // You can rejoin if the room hasn't started
- // You were kicked
- Kicked = 7,
- // You were banned for hacking.
- // Please stop.
- Hacking = 10,
- Destroy = 16,
- // You disconnected from the host.
- // If this happens often, check your WiFi strength.
- //
- // You disconnected from the server.
- // If this happens often, check your network strength.
- // This may also be a server issue.
- Error = 17,
- // The server stopped this game. Possibly due to inactivity.
- ServerRequest = 19,
- // The Among Us servers are overloaded.
- // Sorry! Please try again later!
- ServerFull = 20,
- FocusLostBackground = 207,
- IntentionalLeaving = 208,
- FocusLost = 209,
- NewConnection = 210
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-
-namespace Impostor.Api.Innersloth.Data
-{
- [Flags]
- public enum GameKeywords : uint
- {
- All = 0,
- Other = 1,
- Spanish = 2,
- Korean = 4,
- Russian = 8,
- Portuguese = 16,
- Arabic = 32,
- Filipone = 64,
- Polish = 128,
- English = 256
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Data
-{
- public enum GameStates : byte
- {
- NotStarted = 0,
- Started = 1,
- Ended = 2,
- Destroyed = 3
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-
-namespace Impostor.Api.Innersloth.Data
-{
- [Flags]
- public enum MapFlags
- {
- Skeld = 1,
- MiraHQ = 2,
- Polus = 4
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Data
-{
- public static class MapId
- {
- // TODO: Not sure if correct, check
- public const int Skeld = 0;
- public const int MiraHQ = 1;
- public const int Polus = 2;
- }
-}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public enum DeathReason
+ {
+ Exile = 0,
+ Kill = 1,
+ Disconnect = 2,
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public enum DisconnectReason
+ {
+ ExitGame = 0,
+ // The game you tried to join is full.
+ // Check with the host to see if you can join next round.
+ GameFull = 1,
+ // The game you tried to join already started.
+ // Check with the host to see if you can join next round.
+ GameStarted = 2,
+ // Could not find the game you're looking for.
+ GameMissing = 3,
+ IncorrectGame = 18,
+ // For these a message can be given, specifying an empty message shows
+ // "An unknown error disconnected you from the server."
+ CustomMessage1 = 4,
+ Custom = 8,
+ // CustomMessage3 = 11,
+ // CustomMessage4 = 12,
+ // CustomMessage5 = 13,
+ // CustomMessage6 = 14,
+ // CustomMessage7 = 15,
+ // You are running an older version of the game.
+ // Please update to play with others.
+ IncorrectVersion = 5,
+ // You cannot rejoin that room.
+ // You were banned
+ Banned = 6,
+ // You can rejoin if the room hasn't started
+ // You were kicked
+ Kicked = 7,
+ // You were banned for hacking.
+ // Please stop.
+ Hacking = 10,
+ Destroy = 16,
+ // You disconnected from the host.
+ // If this happens often, check your WiFi strength.
+ //
+ // You disconnected from the server.
+ // If this happens often, check your network strength.
+ // This may also be a server issue.
+ Error = 17,
+ // The server stopped this game. Possibly due to inactivity.
+ ServerRequest = 19,
+ // The Among Us servers are overloaded.
+ // Sorry! Please try again later!
+ ServerFull = 20,
+ FocusLostBackground = 207,
+ IntentionalLeaving = 208,
+ FocusLost = 209,
+ NewConnection = 210,
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Impostor.Api.Innersloth
+{
+ [Flags]
+ public enum GameKeywords : uint
+ {
+ All = 0,
+ Other = 1,
+ Spanish = 2,
+ Korean = 4,
+ Russian = 8,
+ Portuguese = 16,
+ Arabic = 32,
+ Filipone = 64,
+ Polish = 128,
+ English = 256,
+ }
+}
\ No newline at end of file
using System;
using System.IO;
-using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public enum GameStates : byte
+ {
+ NotStarted = 0,
+ Started = 1,
+ Ended = 2,
+ Destroyed = 3
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Impostor.Api.Innersloth
+{
+ [Flags]
+ public enum MapFlags
+ {
+ Skeld = 1,
+ MiraHQ = 2,
+ Polus = 4,
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public static class MapId
+ {
+ // TODO: Not sure if correct, check
+ public const int Skeld = 0;
+ public const int MiraHQ = 1;
+ public const int Polus = 2;
+ }
+}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Net
-{
- public static class GameDataTag
- {
- public const byte DataFlag = 1;
- public const byte RpcFlag = 2;
- public const byte SpawnFlag = 4;
- public const byte DespawnFlag = 5;
- public const byte SceneChangeFlag = 6;
- public const byte ReadyFlag = 7;
- public const byte ChangeSettingsFlag = 8;
- }
-}
\ No newline at end of file
+++ /dev/null
-using System.Collections.Generic;
-
-namespace Impostor.Api.Innersloth.Net
-{
- public class GameObject
- {
- public GameObject()
- {
- Components = new List<object>();
- }
-
- protected List<object> Components { get; }
-
- public List<T> GetComponentsInChildren<T>()
- {
- var result = new List<T>();
-
- foreach (var component in Components)
- {
- if (component is T c)
- {
- result.Add(c);
- }
- }
-
- return result;
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Innersloth.Net.Objects;
-using Impostor.Api.Innersloth.Net.Objects.Components;
-
-namespace Impostor.Api.Innersloth.Net
-{
- public interface IGameNet
- {
- InnerLobbyBehaviour LobbyBehaviour { get; }
-
- InnerGameData GameData { get; }
-
- InnerVoteBanSystem VoteBan { get; }
-
- InnerShipStatus ShipStatus { get; }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System.Threading.Tasks;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net
-{
- public abstract class InnerNetObject : GameObject
- {
- private const int HostInheritId = -2;
-
- public uint NetId { get; internal set; }
-
- public int OwnerId { get; internal set; }
-
- public SpawnFlags SpawnFlags { get; internal set; }
-
- public abstract ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader);
-
- public abstract bool Serialize(IMessageWriter writer, bool initialState);
-
- public abstract void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState);
-
- public bool IsOwnedBy(IClientPlayer player)
- {
- return OwnerId == player.Client.Id ||
- (OwnerId == HostInheritId && player.IsHost);
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Numerics;
-using System.Threading.Tasks;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Components
-{
- public class InnerCustomNetworkTransform : InnerNetObject
- {
- private static readonly FloatRange XRange = new FloatRange(-40f, 40f);
- private static readonly FloatRange YRange = new FloatRange(-40f, 40f);
-
- private readonly ILogger<InnerCustomNetworkTransform> _logger;
-
- private ushort _lastSequenceId;
- private Vector2 _targetSyncPosition;
- private Vector2 _targetSyncVelocity;
-
- public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger)
- {
- _logger = logger;
- }
-
- private static bool SidGreaterThan(ushort newSid, ushort prevSid)
- {
- var num = (ushort)(prevSid + (uint) short.MaxValue);
-
- return (int) prevSid < (int) num
- ? newSid > prevSid && newSid <= num
- : newSid > prevSid || newSid <= num;
- }
-
- private static void WriteVector2(IMessageWriter writer, Vector2 vec)
- {
- writer.Write((ushort)(XRange.ReverseLerp(vec.X) * (double) ushort.MaxValue));
- writer.Write((ushort)(YRange.ReverseLerp(vec.Y) * (double) ushort.MaxValue));
- }
-
- private static Vector2 ReadVector2(IMessageReader reader)
- {
- var v1 = reader.ReadUInt16() / (float) ushort.MaxValue;
- var v2 = reader.ReadUInt16() / (float) ushort.MaxValue;
-
- return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2));
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- if (call == RpcCalls.SnapTo)
- {
- SnapTo(ReadVector2(reader), reader.ReadUInt16());
- }
- else
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerCustomNetworkTransform), call);
- }
-
- return default;
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- if (initialState)
- {
- writer.Write(_lastSequenceId);
- WriteVector2(writer, _targetSyncPosition);
- WriteVector2(writer, _targetSyncVelocity);
- return true;
- }
-
- // TODO: DirtyBits == 0 return false.
- _lastSequenceId++;
-
- writer.Write(_lastSequenceId);
- WriteVector2(writer, _targetSyncPosition);
- WriteVector2(writer, _targetSyncVelocity);
- return true;
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- var sequenceId = reader.ReadUInt16();
-
- if (initialState)
- {
- _lastSequenceId = sequenceId;
- _targetSyncPosition = ReadVector2(reader);
- _targetSyncVelocity = ReadVector2(reader);
- }
- else
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client attempted to send unowned {nameof(InnerCustomNetworkTransform)} data");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client attempted to send {nameof(InnerCustomNetworkTransform)} data to a specific player, must be broadcast");
- }
-
- if (!SidGreaterThan(sequenceId, _lastSequenceId))
- {
- return;
- }
-
- _lastSequenceId = sequenceId;
- _targetSyncPosition = ReadVector2(reader);
- _targetSyncVelocity = ReadVector2(reader);
- }
- }
-
- private void SnapTo(Vector2 position, ushort minSid)
- {
- if (SidGreaterThan(minSid, _lastSequenceId))
- {
- return;
- }
-
- _lastSequenceId = minSid;
- _targetSyncPosition = position;
- _targetSyncVelocity = Vector2.Zero;
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Threading.Tasks;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Components
-{
- public class InnerPlayerPhysics : InnerNetObject
- {
- private readonly ILogger<InnerPlayerPhysics> _logger;
-
- public InnerPlayerPhysics(ILogger<InnerPlayerPhysics> logger)
- {
- _logger = logger;
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- if (call != RpcCalls.EnterVent && call != RpcCalls.ExitVent)
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerPhysics), call);
- return default;
- }
-
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {call} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {call} to a specific player instead of broadcast");
- }
-
- if (!sender.Character.PlayerInfo.IsImpostor)
- {
- throw new ImpostorCheatException($"Client sent {call} as crewmate");
- }
-
- var ventId = reader.ReadPackedUInt32();
- var ventEnter = call == RpcCalls.EnterVent;
-
- // TODO: Do stuff.
-
- return default;
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- throw new NotImplementedException();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Components
-{
- public class InnerVoteBanSystem : InnerNetObject
- {
- private readonly ILogger<InnerVoteBanSystem> _logger;
- private readonly Dictionary<int, int[]> _votes;
-
- public InnerVoteBanSystem(ILogger<InnerVoteBanSystem> logger)
- {
- _logger = logger;
- _votes = new Dictionary<int, int[]>();
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- if (call != RpcCalls.AddVote)
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerVoteBanSystem), call);
- return default;
- }
-
- var clientId = reader.ReadInt32();
- if (clientId != sender.Client.Id)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.AddVote)} as other client");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to wrong destinition, must be broadcast");
- }
-
- var targetClientId = reader.ReadInt32();
-
- // TODO: Use.
-
- return default;
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerShipStatus)} as non-host");
- }
-
- var votes = _votes;
- var unknown = reader.ReadByte();
- if (unknown != 0)
- {
- for (var i = 0; i < unknown; i++)
- {
- var v4 = reader.ReadInt32();
- if (v4 == 0)
- {
- break;
- }
-
- if (!votes.TryGetValue(v4, out var v12))
- {
- v12 = new int[3];
- votes[v4] = v12;
- }
-
- for (var j = 0; j < 3; j++)
- {
- v12[j] = reader.ReadPackedInt32();
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using Impostor.Api.Innersloth.Data;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public partial class InnerGameData
- {
- public class PlayerInfo
- {
- public PlayerInfo(byte playerId)
- {
- PlayerId = playerId;
- }
-
- public InnerPlayerControl Controller { get; internal set; }
-
- public byte PlayerId { get; }
-
- public string PlayerName { get; internal set; }
-
- public byte ColorId { get; internal set; }
-
- public uint HatId { get; internal set; }
-
- public uint PetId { get; internal set; }
-
- public uint SkinId { get; internal set; }
-
- public bool Disconnected { get; internal set; }
-
- public bool IsImpostor { get; internal set; }
-
- public bool IsDead { get; internal set; }
-
- public DeathReason LastDeathReason { get; internal set; }
-
- public List<TaskInfo> Tasks { get; internal set; }
-
- public void Serialize(IMessageWriter writer)
- {
- throw new NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader)
- {
- PlayerName = reader.ReadString();
- ColorId = reader.ReadByte();
- HatId = reader.ReadPackedUInt32();
- PetId = reader.ReadPackedUInt32();
- SkinId = reader.ReadPackedUInt32();
- var flag = reader.ReadByte();
- Disconnected = (flag & 1) > 0;
- IsImpostor = (flag & 2) > 0;
- IsDead = (flag & 4) > 0;
- var taskCount = reader.ReadByte();
- Tasks = new List<TaskInfo>();
- for (var i = 0; i < taskCount; i++)
- {
- Tasks.Add(new TaskInfo());
- Tasks[i].Deserialize(reader);
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public partial class InnerGameData
- {
- public class TaskInfo
- {
- public uint Id { get; internal set; }
-
- public bool Complete { get; internal set; }
-
- public void Serialize(IMessageWriter writer)
- {
- writer.WritePacked(Id);
- writer.Write(Complete);
- }
-
- public void Deserialize(IMessageReader reader)
- {
- this.Id = reader.ReadPackedUInt32();
- this.Complete = reader.ReadBoolean();
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net.Objects.Components;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public partial class InnerGameData : InnerNetObject
- {
- private readonly ILogger<InnerGameData> _logger;
- private readonly IGame _game;
- private readonly ConcurrentDictionary<byte, PlayerInfo> _allPlayers;
-
- public InnerGameData(ILogger<InnerGameData> logger, IGame game, IServiceProvider serviceProvider)
- {
- _logger = logger;
- _game = game;
- _allPlayers = new ConcurrentDictionary<byte, PlayerInfo>();
-
- Components.Add(this);
- Components.Add(ActivatorUtilities.CreateInstance<InnerVoteBanSystem>(serviceProvider));
- }
-
- public int PlayerCount => _allPlayers.Count;
-
- public IReadOnlyDictionary<byte, PlayerInfo> Players => _allPlayers;
-
- public PlayerInfo? GetPlayerById(byte id)
- {
- if (id == byte.MaxValue)
- {
- return null;
- }
-
- return _allPlayers.TryGetValue(id, out var player) ? player : null;
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- switch (call)
- {
- case RpcCalls.SetTasks:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} to a specific player instead of broadcast");
- }
-
- var playerId = reader.ReadByte();
- var taskTypeIds = reader.ReadBytesAndSize();
-
- SetTasks(playerId, taskTypeIds);
- break;
- }
-
- case RpcCalls.UpdateGameData:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} to a specific player instead of broadcast");
- }
-
- while (reader.Position < reader.Length)
- {
- var message = reader.ReadMessage();
- var player = GetPlayerById(message.Tag);
- if (player != null)
- {
- player.Deserialize(message);
- }
- else
- {
- var playerInfo = new PlayerInfo(message.Tag);
-
- playerInfo.Deserialize(reader);
-
- if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
- {
- throw new ImpostorException("Failed to add player to InnerGameData.");
- }
- }
- }
-
- break;
- }
-
- default:
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerGameData), call);
- break;
- }
- }
-
- return default;
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerGameData)} as non-host");
- }
-
- if (initialState)
- {
- var num = reader.ReadPackedInt32();
-
- for (var i = 0; i < num; i++)
- {
- var playerId = reader.ReadByte();
- var playerInfo = new PlayerInfo(playerId);
-
- playerInfo.Deserialize(reader);
-
- if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
- {
- throw new ImpostorException("Failed to add player to InnerGameData.");
- }
- }
- }
- else
- {
- throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly.");
- }
- }
-
- internal void AddPlayer(InnerPlayerControl control)
- {
- var playerId = control.PlayerId;
- var playerInfo = new PlayerInfo(control.PlayerId);
-
- if (_allPlayers.TryAdd(playerId, playerInfo))
- {
- control.PlayerInfo = playerInfo;
- }
- }
-
- private void SetTasks(byte playerId, ReadOnlyMemory<byte> taskTypeIds)
- {
- var player = GetPlayerById(playerId);
- if (player == null)
- {
- _logger.LogTrace("Could not set tasks for playerId {0}.", playerId);
- return;
- }
-
- if (player.Disconnected)
- {
- return;
- }
-
- player.Tasks = new List<TaskInfo>(taskTypeIds.Length);
-
- for (var i = 0; i < taskTypeIds.Length; i++)
- {
- player.Tasks.Add(new TaskInfo());
- player.Tasks[i].Id = (uint)i;
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System.Threading.Tasks;
-using Impostor.Api.Games;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public class InnerLobbyBehaviour : InnerNetObject
- {
- private readonly IGame _game;
-
- public InnerLobbyBehaviour(IGame game)
- {
- _game = game;
-
- Components.Add(this);
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
- IMessageReader reader)
- {
- throw new System.NotImplementedException();
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- throw new System.NotImplementedException();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public partial class InnerMeetingHud
- {
- public class PlayerVoteArea
- {
- private const byte VoteMask = 15;
- private const byte ReportedBit = 32;
- private const byte VotedBit = 64;
- private const byte DeadBit = 128;
-
- public PlayerVoteArea(InnerMeetingHud parent, byte targetPlayerId)
- {
- Parent = parent;
- TargetPlayerId = targetPlayerId;
- }
-
- public InnerMeetingHud Parent { get; }
-
- public byte TargetPlayerId { get; }
-
- public bool IsDead { get; private set; }
-
- public bool DidVote { get; private set; }
-
- public bool DidReport { get; private set; }
-
- public sbyte VotedFor { get; private set; }
-
- internal void SetDead(bool didReport, bool isDead)
- {
- DidReport = didReport;
- IsDead = isDead;
- }
-
- public void Deserialize(IMessageReader reader)
- {
- var num = reader.ReadByte();
-
- VotedFor = (sbyte)((num & VoteMask) - 1);
- IsDead = (num & DeadBit) > 0;
- DidVote = (num & VotedBit) > 0;
- DidReport = (num & ReportedBit) > 0;
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using Impostor.Api.Games;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public partial class InnerMeetingHud : InnerNetObject
- {
- private readonly ILogger<InnerMeetingHud> _logger;
- private readonly IGame _game;
- private readonly IGameNet _gameNet;
- private PlayerVoteArea[] _playerStates;
-
- public InnerMeetingHud(ILogger<InnerMeetingHud> logger, IGame game)
- {
- _logger = logger;
- _game = game;
- _gameNet = game.GameNet;
- _playerStates = null;
-
- Components.Add(this);
- }
-
- public byte ReporterId { get; private set; }
-
- private void PopulateButtons(byte reporter)
- {
- _playerStates = _gameNet.GameData.Players
- .Select(x =>
- {
- var area = new PlayerVoteArea(this, x.Key);
- area.SetDead(x.Value.PlayerId == reporter, x.Value.Disconnected || x.Value.IsDead);
- return area;
- })
- .ToArray();
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- switch (call)
- {
- case RpcCalls.Close:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Close)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Close)} to a specific player instead of broadcast");
- }
-
- break;
- }
-
- case RpcCalls.VotingComplete:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.VotingComplete)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.VotingComplete)} to a specific player instead of broadcast");
- }
-
- var states = reader.ReadBytesAndSize();
- var playerId = reader.ReadByte();
- var tie = reader.ReadBoolean();
- break;
- }
-
- case RpcCalls.CastVote:
- {
- var srcPlayerId = reader.ReadByte();
- if (srcPlayerId != sender.Character.PlayerId)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- // Host broadcasts vote to others.
- if (sender.IsHost && target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to a specific player instead of broadcast");
- }
-
- // Player sends vote to host.
- if (target == null || !target.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to wrong destinition, must be host");
- }
-
- var targetPlayerId = reader.ReadByte();
- break;
- }
-
- default:
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerMeetingHud), call);
- break;
- }
- }
-
- return default;
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerMeetingHud)} as non-host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client attempted to send {nameof(InnerMeetingHud)} data to a specific player, must be broadcast");
- }
-
- if (initialState)
- {
- PopulateButtons(0);
-
- foreach (var playerState in _playerStates)
- {
- playerState.Deserialize(reader);
-
- if (playerState.DidReport)
- {
- ReporterId = playerState.TargetPlayerId;
- }
- }
- }
- else
- {
- var num = reader.ReadPackedUInt32();
-
- for (var i = 0; i < _playerStates.Length; i++)
- {
- if ((num & 1 << i) != 0)
- {
- _playerStates[i].Deserialize(reader);
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Threading.Tasks;
-using Impostor.Api.Events.Managers;
-using Impostor.Api.Events.Net;
-using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Data;
-using Impostor.Api.Innersloth.Net.Objects.Components;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public class InnerPlayerControl : InnerNetObject
- {
- private readonly ILogger<InnerPlayerControl> _logger;
- private readonly IEventManager _eventManager;
- private readonly IGame _game;
-
- public InnerPlayerControl(ILogger<InnerPlayerControl> logger, IServiceProvider serviceProvider, IEventManager eventManager, IGame game)
- {
- _logger = logger;
- _eventManager = eventManager;
- _game = game;
-
- Components.Add(this);
- Components.Add(ActivatorUtilities.CreateInstance<InnerPlayerPhysics>(serviceProvider));
- Components.Add(ActivatorUtilities.CreateInstance<InnerCustomNetworkTransform>(serviceProvider));
-
- PlayerId = byte.MaxValue;
- }
-
- public bool IsNew { get; private set; }
-
- public byte PlayerId { get; private set; }
-
- public InnerGameData.PlayerInfo PlayerInfo { get; internal set; }
-
- public override async ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- switch (call)
- {
- // Play an animation.
- case RpcCalls.PlayAnimation:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.PlayAnimation)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.PlayAnimation)} to a specific player instead of broadcast");
- }
-
- var animation = reader.ReadByte();
- break;
- }
-
- // Complete a task.
- case RpcCalls.CompleteTask:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CompleteTask)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CompleteTask)} to a specific player instead of broadcast");
- }
-
- var index = reader.ReadPackedUInt32();
- break;
- }
-
- // Update GameOptions.
- case RpcCalls.SyncSettings:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SyncSettings)} but was not a host");
- }
-
- _game.Options.Deserialize(reader.ReadBytesAndSize());
- break;
- }
-
- // Set Impostors.
- case RpcCalls.SetInfected:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetInfected)} but was not a host");
- }
-
- var length = reader.ReadPackedInt32();
-
- for (var i = 0; i < length; i++)
- {
- var playerId = reader.ReadByte();
- var player = _game.GameNet.GameData.GetPlayerById(playerId);
-
- player.IsImpostor = true;
- }
-
- break;
- }
-
- // Player was voted out.
- case RpcCalls.Exiled:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Exiled)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Exiled)} to a specific player instead of broadcast");
- }
-
- // TODO: Not hit?
- Die(DeathReason.Exile);
- break;
- }
-
- // Validates the player name at the host.
- case RpcCalls.CheckName:
- {
- if (target == null || !target.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckName)} to the wrong player");
- }
-
- var name = reader.ReadString();
- break;
- }
-
- // Update the name of a player.
- case RpcCalls.SetName:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} to a specific player instead of broadcast");
- }
-
- PlayerInfo.PlayerName = reader.ReadString();
- break;
- }
-
- // Validates the color at the host.
- case RpcCalls.CheckColor:
- {
- if (target == null || !target.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckColor)} to the wrong player");
- }
-
- var color = reader.ReadByte();
- break;
- }
-
- // Update the color of a player.
- case RpcCalls.SetColor:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} to a specific player instead of broadcast");
- }
-
- PlayerInfo.ColorId = reader.ReadByte();
- break;
- }
-
- // Update the hat of a player.
- case RpcCalls.SetHat:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to a specific player instead of broadcast");
- }
-
- PlayerInfo.HatId = reader.ReadPackedUInt32();
- break;
- }
-
- case RpcCalls.SetSkin:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetSkin)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to a specific player instead of broadcast");
- }
-
- PlayerInfo.SkinId = reader.ReadPackedUInt32();
- break;
- }
-
- // TODO: (ANTICHEAT) Location check?
- case RpcCalls.ReportDeadBody:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.ReportDeadBody)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.ReportDeadBody)} to a specific player instead of broadcast");
- }
-
- var deadBodyPlayerId = reader.ReadByte();
- break;
- }
-
- // TODO: (ANTICHEAT) Cooldown check?
- case RpcCalls.MurderPlayer:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} to a specific player instead of broadcast");
- }
-
- if (!sender.Character.PlayerInfo.IsImpostor)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} as crewmate");
- }
-
- var player = reader.ReadNetObject<InnerPlayerControl>(_game);
- if (!player.PlayerInfo.IsDead)
- {
- player.Die(DeathReason.Kill);
- }
-
- break;
- }
-
- case RpcCalls.SendChat:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChat)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChat)} to a specific player instead of broadcast");
- }
-
- var chat = reader.ReadString();
-
- await _eventManager.CallAsync(new PlayerChatEvent(_game, this, chat));
- break;
- }
-
- case RpcCalls.StartMeeting:
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.StartMeeting)} but was not a host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.StartMeeting)} to a specific player instead of broadcast");
- }
-
- var playerId = reader.ReadByte();
- var player = _game.GameNet.GameData.GetPlayerById(playerId);
-
- // Meeting started by "player", can also be null.
- break;
- }
-
- case RpcCalls.SetScanner:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetScanner)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetScanner)} to a specific player instead of broadcast");
- }
-
- var on = reader.ReadBoolean();
- var count = reader.ReadByte();
- break;
- }
-
- case RpcCalls.SendChatNote:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChatNote)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChatNote)} to a specific player instead of broadcast");
- }
-
- var playerId = reader.ReadByte();
- var chatNote = (ChatNoteType)reader.ReadByte();
- break;
- }
-
- case RpcCalls.SetPet:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetPet)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetPet)} to a specific player instead of broadcast");
- }
-
- PlayerInfo.PetId = reader.ReadPackedUInt32();
- break;
- }
-
- // TODO: Understand this RPC
- case RpcCalls.SetStartCounter:
- {
- if (!sender.IsOwner(this))
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetStartCounter)} to an unowned {nameof(InnerPlayerControl)}");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetStartCounter)} to a specific player instead of broadcast");
- }
-
- // Used to compare with LastStartCounter.
- var startCounter = reader.ReadPackedUInt32();
-
- // Is either start countdown or byte.MaxValue
- var secondsLeft = reader.ReadByte();
- break;
- }
-
- default:
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerControl), call);
- break;
- }
- }
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerPlayerControl)} as non-host");
- }
-
- if (initialState)
- {
- IsNew = reader.ReadBoolean();
- }
-
- PlayerId = reader.ReadByte();
- }
-
- private void Die(DeathReason reason)
- {
- PlayerInfo.IsDead = true;
- PlayerInfo.LastDeathReason = reason;
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net.Objects.Systems;
-using Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus;
-using Impostor.Api.Net;
-using Impostor.Api.Net.Messages;
-using Microsoft.Extensions.Logging;
-
-namespace Impostor.Api.Innersloth.Net.Objects
-{
- public class InnerShipStatus : InnerNetObject
- {
- private readonly ILogger<InnerShipStatus> _logger;
- private readonly IGame _game;
- private readonly Dictionary<SystemTypes, ISystemType> _systems;
-
- public InnerShipStatus(ILogger<InnerShipStatus> logger, IGame game)
- {
- _logger = logger;
- _game = game;
-
- _systems = new Dictionary<SystemTypes, ISystemType>
- {
- [SystemTypes.Electrical] = new SwitchSystem(),
- [SystemTypes.MedBay] = new MedScanSystem(),
- [SystemTypes.Reactor] = new ReactorSystemType(),
- [SystemTypes.LifeSupp] = new LifeSuppSystemType(),
- [SystemTypes.Security] = new SecurityCameraSystemType(),
- [SystemTypes.Comms] = new HudOverrideSystemType(),
- [SystemTypes.Doors] = new DoorsSystemType(_game),
- };
-
- _systems.Add(SystemTypes.Sabotage, new SabotageSystemType(new[]
- {
- (IActivatable)_systems[SystemTypes.Comms],
- (IActivatable)_systems[SystemTypes.Reactor],
- (IActivatable)_systems[SystemTypes.LifeSupp],
- (IActivatable)_systems[SystemTypes.Electrical],
- }));
-
- Components.Add(this);
- }
-
- public override ValueTask HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
- {
- switch (call)
- {
- case RpcCalls.CloseDoorsOfType:
- {
- if (target == null || !target.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CloseDoorsOfType)} to wrong destinition, must be host");
- }
-
- if (!sender.Character.PlayerInfo.IsImpostor)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CloseDoorsOfType)} as crewmate");
- }
-
- var systemType = (SystemTypes)reader.ReadByte();
-
- break;
- }
-
- case RpcCalls.RepairSystem:
- {
- if (target == null || !target.IsHost)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.RepairSystem)} to wrong destinition, must be host");
- }
-
- if (!sender.Character.PlayerInfo.IsImpostor)
- {
- throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.RepairSystem)} as crewmate");
- }
-
- var systemType = (SystemTypes)reader.ReadByte();
- var player = reader.ReadNetObject<InnerPlayerControl>(_game);
- var amount = reader.ReadByte();
-
- // TODO: Modify data (?)
-
- break;
- }
-
- default:
- {
- _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerShipStatus), call);
- break;
- }
- }
-
- return default;
- }
-
- public override bool Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
- {
- if (!sender.IsHost)
- {
- throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerShipStatus)} as non-host");
- }
-
- if (target != null)
- {
- throw new ImpostorCheatException($"Client attempted to send {nameof(InnerShipStatus)} data to a specific player, must be broadcast");
- }
-
- if (initialState)
- {
- // TODO: (_systems[SystemTypes.Doors] as DoorsSystemType).SetDoors();
- foreach (var systemType in SystemTypeHelpers.AllTypes)
- {
- if (_systems.TryGetValue(systemType, out var system))
- {
- system.Deserialize(reader, true);
- }
- }
- }
- else
- {
- var count = reader.ReadPackedUInt32();
-
- foreach (var systemType in SystemTypeHelpers.AllTypes)
- {
- // TODO: Not sure what is going on here, check.
- if ((count & 1 << (int)(systemType & (SystemTypes.ShipTasks | SystemTypes.Doors))) != 0L)
- {
- if (_systems.TryGetValue(systemType, out var system))
- {
- system.Deserialize(reader, false);
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Net.Objects.Systems
-{
- public interface IActivatable
- {
- bool IsActive { get; }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems
-{
- public interface ISystemType
- {
- void Serialize(IMessageWriter writer, bool initialState);
-
- void Deserialize(IMessageReader reader, bool initialState);
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Data;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class DoorsSystemType : ISystemType
- {
- // TODO: AutoDoors
- private readonly Dictionary<int, bool> _doors;
-
- public DoorsSystemType(IGame game)
- {
- // TODO: Check
- var doorCount = game.Options.MapId switch
- {
- MapId.Skeld => 13,
- MapId.MiraHQ => 2,
- MapId.Polus => 12,
- _ => throw new ArgumentOutOfRangeException()
- };
-
- _doors = new Dictionary<int, bool>(doorCount);
-
- for (var i = 0; i < doorCount; i++)
- {
- _doors.Add(i, false);
- }
- }
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- if (initialState)
- {
- for (var i = 0; i < _doors.Count; i++)
- {
- _doors[i] = reader.ReadBoolean();
- }
- }
- else
- {
- var num = reader.ReadPackedUInt32();
-
- for (var i = 0; i < _doors.Count; i++)
- {
- if ((num & 1 << i) != 0)
- {
- _doors[i] = reader.ReadBoolean();
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class HudOverrideSystemType : ISystemType, IActivatable
- {
- public bool IsActive { get; private set; }
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- IsActive = reader.ReadBoolean();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class LifeSuppSystemType : ISystemType, IActivatable
- {
- public LifeSuppSystemType()
- {
- Countdown = 10000f;
- CompletedConsoles = new HashSet<int>();
- }
-
- public float Countdown { get; private set; }
-
- public HashSet<int> CompletedConsoles { get; }
-
- public bool IsActive => Countdown < 10000.0;
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- Countdown = reader.ReadSingle();
-
- if (reader.Position >= reader.Length)
- {
- return;
- }
-
- CompletedConsoles.Clear(); // TODO: Thread safety
-
- var num = reader.ReadPackedInt32();
-
- for (var i = 0; i < num; i++)
- {
- CompletedConsoles.Add(reader.ReadPackedInt32());
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class MedScanSystem : ISystemType
- {
- public MedScanSystem()
- {
- UsersList = new List<byte>();
- }
-
- public List<byte> UsersList { get; }
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- UsersList.Clear();
-
- var num = reader.ReadPackedInt32();
-
- for (var i = 0; i < num; i++)
- {
- UsersList.Add(reader.ReadByte());
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class ReactorSystemType : ISystemType, IActivatable
- {
- public ReactorSystemType()
- {
- Countdown = 10000f;
- UserConsolePairs = new HashSet<Tuple<byte, byte>>();
- }
-
- public float Countdown { get; private set; }
-
- public HashSet<Tuple<byte, byte>> UserConsolePairs { get; }
-
- public bool IsActive => Countdown < 10000.0;
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- Countdown = reader.ReadSingle();
- UserConsolePairs.Clear(); // TODO: Thread safety
-
- var count = reader.ReadPackedInt32();
-
- for (var i = 0; i < count; i++)
- {
- UserConsolePairs.Add(new Tuple<byte, byte>(reader.ReadByte(), reader.ReadByte()));
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class SabotageSystemType : ISystemType
- {
- private readonly IActivatable[] _specials;
-
- public SabotageSystemType(IActivatable[] specials)
- {
- _specials = specials;
- }
-
- public float Timer { get; set; }
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- Timer = reader.ReadSingle();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class SecurityCameraSystemType : ISystemType
- {
- public byte InUse { get; internal set; }
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- InUse = reader.ReadByte();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Impostor.Api.Net.Messages;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems.ShipStatus
-{
- public class SwitchSystem : ISystemType, IActivatable
- {
- public byte ExpectedSwitches { get; set; }
-
- public byte ActualSwitches { get; set; }
-
- public byte Value { get; set; } = byte.MaxValue;
-
- public bool IsActive { get; }
-
- public void Serialize(IMessageWriter writer, bool initialState)
- {
- throw new System.NotImplementedException();
- }
-
- public void Deserialize(IMessageReader reader, bool initialState)
- {
- ExpectedSwitches = reader.ReadByte();
- ActualSwitches = reader.ReadByte();
- Value = reader.ReadByte();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-using System.Linq;
-
-namespace Impostor.Api.Innersloth.Net.Objects.Systems
-{
- internal class SystemTypeHelpers
- {
- public static readonly SystemTypes[] AllTypes;
- public static readonly string[] Names;
-
- static SystemTypeHelpers()
- {
- AllTypes = Enum.GetValues(typeof(SystemTypes)).Cast<SystemTypes>().ToArray();
- Names = AllTypes.Select(x =>
- {
- return x switch
- {
- SystemTypes.UpperEngine => "Upper Engine",
- SystemTypes.Nav => "Navigations",
- SystemTypes.LifeSupp => "O2",
- SystemTypes.LowerEngine => "Lower Engine",
- SystemTypes.LockerRoom => "Locker Room",
- _ => x.ToString()
- };
- }).ToArray();
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Net.Objects.Systems
-{
- public enum SystemTypes : byte
- {
- Hallway,
- Storage,
- Cafeteria,
- Reactor,
- UpperEngine,
- Nav,
- Admin,
- Electrical,
- LifeSupp,
- Shields,
- MedBay,
- Security,
- Weapons,
- LowerEngine,
- Comms,
- ShipTasks,
- Doors,
- Sabotage,
- Decontamination,
- Launchpad,
- LockerRoom,
- Laboratory,
- Balcony,
- Office,
- Greenhouse,
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Innersloth.Net
-{
- public enum RpcCalls : byte
- {
- PlayAnimation = 0,
- CompleteTask = 1,
- SyncSettings = 2,
- SetInfected = 3,
- Exiled = 4,
- CheckName = 5,
- SetName = 6,
- CheckColor = 7,
- SetColor = 8,
- SetHat = 9,
- SetSkin = 10,
- ReportDeadBody = 11,
- MurderPlayer = 12,
- SendChat = 13,
- StartMeeting = 14,
- SetScanner = 15,
- SendChatNote = 16,
- SetPet = 17,
- SetStartCounter = 18,
- EnterVent = 19,
- ExitVent = 20,
- SnapTo = 21,
- Close = 22,
- VotingComplete = 23,
- CastVote = 24,
- ClearVote = 25,
- AddVote = 26,
- CloseDoorsOfType = 27,
- RepairSystem = 28,
- SetTasks = 29,
- UpdateGameData = 30,
- }
-}
\ No newline at end of file
+++ /dev/null
-using System;
-
-namespace Impostor.Api.Innersloth.Net
-{
- [Flags]
- public enum SpawnFlags : byte
- {
- None = 0,
- IsClientCharacter = 1,
- }
-}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Linq;
+
+namespace Impostor.Api.Innersloth
+{
+ internal class SystemTypeHelpers
+ {
+ public static readonly SystemTypes[] AllTypes;
+ public static readonly string[] Names;
+
+ static SystemTypeHelpers()
+ {
+ AllTypes = Enum.GetValues(typeof(SystemTypes)).Cast<SystemTypes>().ToArray();
+ Names = AllTypes.Select(x =>
+ {
+ return x switch
+ {
+ SystemTypes.UpperEngine => "Upper Engine",
+ SystemTypes.Nav => "Navigations",
+ SystemTypes.LifeSupp => "O2",
+ SystemTypes.LowerEngine => "Lower Engine",
+ SystemTypes.LockerRoom => "Locker Room",
+ _ => x.ToString()
+ };
+ }).ToArray();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Innersloth
+{
+ public enum SystemTypes : byte
+ {
+ Hallway,
+ Storage,
+ Cafeteria,
+ Reactor,
+ UpperEngine,
+ Nav,
+ Admin,
+ Electrical,
+ LifeSupp,
+ Shields,
+ MedBay,
+ Security,
+ Weapons,
+ LowerEngine,
+ Comms,
+ ShipTasks,
+ Doors,
+ Sabotage,
+ Decontamination,
+ Launchpad,
+ LockerRoom,
+ Laboratory,
+ Balcony,
+ Office,
+ Greenhouse,
+ }
+}
\ No newline at end of file
using System.Threading.Tasks;
using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net;
-using Impostor.Api.Innersloth.Net.Objects;
+using Impostor.Api.Net.Inner;
+using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Net
{
/// </summary>
LimboStates Limbo { get; set; }
- InnerPlayerControl Character { get; }
+ IInnerPlayerControl Character { get; }
public bool IsHost { get; }
/// <summary>
- /// Checks if the specified <see cref="InnerNetObject"/> is owned by <see cref="IClientPlayer"/>.
+ /// Checks if the specified <see cref="IInnerNetObject"/> is owned by <see cref="IClientPlayer"/>.
/// </summary>
- /// <param name="netObject">The <see cref="InnerNetObject"/>.</param>
+ /// <param name="netObject">The <see cref="IInnerNetObject"/>.</param>
/// <returns>Returns true if owned by <see cref="IClientPlayer"/>.</returns>
- bool IsOwner(InnerNetObject netObject);
+ bool IsOwner(IInnerNetObject netObject);
ValueTask KickAsync();
--- /dev/null
+using Impostor.Api.Net.Inner.Objects;
+
+namespace Impostor.Api.Net.Inner
+{
+ /// <summary>
+ /// Holds all data that is serialized over the network through GameData packets.
+ /// </summary>
+ public interface IGameNet
+ {
+ IInnerLobbyBehaviour LobbyBehaviour { get; }
+
+ IInnerGameData GameData { get; }
+
+ IInnerVoteBanSystem VoteBan { get; }
+
+ IInnerShipStatus ShipStatus { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Net.Inner
+{
+ public interface IInnerNetObject
+ {
+ public uint NetId { get; }
+
+ public int OwnerId { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Net.Inner.Objects
+{
+ public interface IInnerGameData : IInnerNetObject
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Net.Inner.Objects
+{
+ public interface IInnerLobbyBehaviour : IInnerNetObject
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Net.Inner.Objects
+{
+ public interface IInnerPlayerControl
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Net.Inner.Objects
+{
+ public interface IInnerShipStatus : IInnerNetObject
+ {
+
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Api.Net.Inner.Objects
+{
+ public interface IInnerVoteBanSystem : IInnerNetObject
+ {
+
+ }
+}
\ No newline at end of file
PreSpawn = 1,
NotLimbo = 2,
WaitingForHost = 4,
- All = PreSpawn | NotLimbo | WaitingForHost
+ All = PreSpawn | NotLimbo | WaitingForHost,
}
}
\ No newline at end of file
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Messages.C2S
{
using System;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Messages.S2C
{
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Messages.S2C
{
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Messages.S2C
{
using System.Threading.Tasks;
using Impostor.Api.Events;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
namespace Impostor.Api.Plugins
{
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using System.Threading.Tasks;
using Impostor.Api.Events;
using Impostor.Api.Events.Managers;
using System.Diagnostics;
using System.Linq;
using System.Threading;
-using Impostor.Api.Events;
namespace Impostor.Server.Events.Register
{
--- /dev/null
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.Inner;
+using Impostor.Server.Net.State;
+
+namespace Impostor.Server
+{
+ internal static class MessageReaderExtensions
+ {
+ public static T ReadNetObject<T>(this IMessageReader reader, Game game)
+ where T : InnerNetObject
+ {
+ return game.FindObjectByNetId<T>(reader.ReadPackedUInt32());
+ }
+ }
+}
\ No newline at end of file
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-
+using System.Threading.Tasks;
using Impostor.Server.Net.Redirector;
-namespace Impostor.Server.Extensions
+namespace Impostor.Server
{
public static class NodeLocatorExtensions
{
using Impostor.Api;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
-using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.C2S;
using Impostor.Api.Net.Messages.S2C;
using Impostor.Hazel;
using Impostor.Server.Config;
-using Impostor.Server.Net.Hazel;
using Impostor.Server.Net.Manager;
using Microsoft.Extensions.Logging;
using System;
using Impostor.Api.Net;
-using Impostor.Server.Net.Hazel;
using Microsoft.Extensions.DependencyInjection;
namespace Impostor.Server.Net.Factories
--- /dev/null
+namespace Impostor.Server.Net.Inner
+{
+ public static class GameDataTag
+ {
+ public const byte DataFlag = 1;
+ public const byte RpcFlag = 2;
+ public const byte SpawnFlag = 4;
+ public const byte DespawnFlag = 5;
+ public const byte SceneChangeFlag = 6;
+ public const byte ReadyFlag = 7;
+ public const byte ChangeSettingsFlag = 8;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+namespace Impostor.Server.Net.Inner
+{
+ internal class GameObject
+ {
+ public GameObject()
+ {
+ Components = new List<object>();
+ }
+
+ protected List<object> Components { get; }
+
+ public List<T> GetComponentsInChildren<T>()
+ {
+ var result = new List<T>();
+
+ foreach (var component in Components)
+ {
+ if (component is T c)
+ {
+ result.Add(c);
+ }
+ }
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Threading.Tasks;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Inner;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.State;
+
+namespace Impostor.Server.Net.Inner
+{
+ internal abstract class InnerNetObject : GameObject, IInnerNetObject
+ {
+ private const int HostInheritId = -2;
+
+ public uint NetId { get; internal set; }
+
+ public int OwnerId { get; internal set; }
+
+ public SpawnFlags SpawnFlags { get; internal set; }
+
+ public abstract ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader);
+
+ public abstract bool Serialize(IMessageWriter writer, bool initialState);
+
+ public abstract void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState);
+
+ public bool IsOwnedBy(IClientPlayer player)
+ {
+ return OwnerId == player.Client.Id ||
+ (OwnerId == HostInheritId && player.IsHost);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Numerics;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Innersloth;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects.Components
+{
+ internal class InnerCustomNetworkTransform : InnerNetObject
+ {
+ private static readonly FloatRange XRange = new FloatRange(-40f, 40f);
+ private static readonly FloatRange YRange = new FloatRange(-40f, 40f);
+
+ private readonly ILogger<InnerCustomNetworkTransform> _logger;
+
+ private ushort _lastSequenceId;
+ private Vector2 _targetSyncPosition;
+ private Vector2 _targetSyncVelocity;
+
+ public InnerCustomNetworkTransform(ILogger<InnerCustomNetworkTransform> logger)
+ {
+ _logger = logger;
+ }
+
+ private static bool SidGreaterThan(ushort newSid, ushort prevSid)
+ {
+ var num = (ushort)(prevSid + (uint) short.MaxValue);
+
+ return (int) prevSid < (int) num
+ ? newSid > prevSid && newSid <= num
+ : newSid > prevSid || newSid <= num;
+ }
+
+ private static void WriteVector2(IMessageWriter writer, Vector2 vec)
+ {
+ writer.Write((ushort)(XRange.ReverseLerp(vec.X) * (double) ushort.MaxValue));
+ writer.Write((ushort)(YRange.ReverseLerp(vec.Y) * (double) ushort.MaxValue));
+ }
+
+ private static Vector2 ReadVector2(IMessageReader reader)
+ {
+ var v1 = reader.ReadUInt16() / (float) ushort.MaxValue;
+ var v2 = reader.ReadUInt16() / (float) ushort.MaxValue;
+
+ return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2));
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
+ {
+ if (call == RpcCalls.SnapTo)
+ {
+ SnapTo(ReadVector2(reader), reader.ReadUInt16());
+ }
+ else
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerCustomNetworkTransform), call);
+ }
+
+ return default;
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ if (initialState)
+ {
+ writer.Write(_lastSequenceId);
+ WriteVector2(writer, _targetSyncPosition);
+ WriteVector2(writer, _targetSyncVelocity);
+ return true;
+ }
+
+ // TODO: DirtyBits == 0 return false.
+ _lastSequenceId++;
+
+ writer.Write(_lastSequenceId);
+ WriteVector2(writer, _targetSyncPosition);
+ WriteVector2(writer, _targetSyncVelocity);
+ return true;
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ var sequenceId = reader.ReadUInt16();
+
+ if (initialState)
+ {
+ _lastSequenceId = sequenceId;
+ _targetSyncPosition = ReadVector2(reader);
+ _targetSyncVelocity = ReadVector2(reader);
+ }
+ else
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client attempted to send unowned {nameof(InnerCustomNetworkTransform)} data");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client attempted to send {nameof(InnerCustomNetworkTransform)} data to a specific player, must be broadcast");
+ }
+
+ if (!SidGreaterThan(sequenceId, _lastSequenceId))
+ {
+ return;
+ }
+
+ _lastSequenceId = sequenceId;
+ _targetSyncPosition = ReadVector2(reader);
+ _targetSyncVelocity = ReadVector2(reader);
+ }
+ }
+
+ private void SnapTo(Vector2 position, ushort minSid)
+ {
+ if (SidGreaterThan(minSid, _lastSequenceId))
+ {
+ return;
+ }
+
+ _lastSequenceId = minSid;
+ _targetSyncPosition = position;
+ _targetSyncVelocity = Vector2.Zero;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects.Components
+{
+ internal class InnerPlayerPhysics : InnerNetObject
+ {
+ private readonly ILogger<InnerPlayerPhysics> _logger;
+
+ public InnerPlayerPhysics(ILogger<InnerPlayerPhysics> logger)
+ {
+ _logger = logger;
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
+ {
+ if (call != RpcCalls.EnterVent && call != RpcCalls.ExitVent)
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerPhysics), call);
+ return default;
+ }
+
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {call} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {call} to a specific player instead of broadcast");
+ }
+
+ if (!sender.Character.PlayerInfo.IsImpostor)
+ {
+ throw new ImpostorCheatException($"Client sent {call} as crewmate");
+ }
+
+ var ventId = reader.ReadPackedUInt32();
+ var ventEnter = call == RpcCalls.EnterVent;
+
+ // TODO: Do stuff.
+
+ return default;
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Inner.Objects;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects.Components
+{
+ internal class InnerVoteBanSystem : InnerNetObject, IInnerVoteBanSystem
+ {
+ private readonly ILogger<InnerVoteBanSystem> _logger;
+ private readonly Dictionary<int, int[]> _votes;
+
+ public InnerVoteBanSystem(ILogger<InnerVoteBanSystem> logger)
+ {
+ _logger = logger;
+ _votes = new Dictionary<int, int[]>();
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
+ {
+ if (call != RpcCalls.AddVote)
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerVoteBanSystem), call);
+ return default;
+ }
+
+ var clientId = reader.ReadInt32();
+ if (clientId != sender.Client.Id)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.AddVote)} as other client");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to wrong destinition, must be broadcast");
+ }
+
+ var targetClientId = reader.ReadInt32();
+
+ // TODO: Use.
+
+ return default;
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerShipStatus)} as non-host");
+ }
+
+ var votes = _votes;
+ var unknown = reader.ReadByte();
+ if (unknown != 0)
+ {
+ for (var i = 0; i < unknown; i++)
+ {
+ var v4 = reader.ReadInt32();
+ if (v4 == 0)
+ {
+ break;
+ }
+
+ if (!votes.TryGetValue(v4, out var v12))
+ {
+ v12 = new int[3];
+ votes[v4] = v12;
+ }
+
+ for (var j = 0; j < 3; j++)
+ {
+ v12[j] = reader.ReadPackedInt32();
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Innersloth;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal partial class InnerGameData
+ {
+ public class PlayerInfo
+ {
+ public PlayerInfo(byte playerId)
+ {
+ PlayerId = playerId;
+ }
+
+ public InnerPlayerControl Controller { get; internal set; }
+
+ public byte PlayerId { get; }
+
+ public string PlayerName { get; internal set; }
+
+ public byte ColorId { get; internal set; }
+
+ public uint HatId { get; internal set; }
+
+ public uint PetId { get; internal set; }
+
+ public uint SkinId { get; internal set; }
+
+ public bool Disconnected { get; internal set; }
+
+ public bool IsImpostor { get; internal set; }
+
+ public bool IsDead { get; internal set; }
+
+ public DeathReason LastDeathReason { get; internal set; }
+
+ public List<TaskInfo> Tasks { get; internal set; }
+
+ public void Serialize(IMessageWriter writer)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader)
+ {
+ PlayerName = reader.ReadString();
+ ColorId = reader.ReadByte();
+ HatId = reader.ReadPackedUInt32();
+ PetId = reader.ReadPackedUInt32();
+ SkinId = reader.ReadPackedUInt32();
+ var flag = reader.ReadByte();
+ Disconnected = (flag & 1) > 0;
+ IsImpostor = (flag & 2) > 0;
+ IsDead = (flag & 4) > 0;
+ var taskCount = reader.ReadByte();
+ Tasks = new List<TaskInfo>();
+ for (var i = 0; i < taskCount; i++)
+ {
+ Tasks.Add(new TaskInfo());
+ Tasks[i].Deserialize(reader);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal partial class InnerGameData
+ {
+ public class TaskInfo
+ {
+ public uint Id { get; internal set; }
+
+ public bool Complete { get; internal set; }
+
+ public void Serialize(IMessageWriter writer)
+ {
+ writer.WritePacked(Id);
+ writer.Write(Complete);
+ }
+
+ public void Deserialize(IMessageReader reader)
+ {
+ this.Id = reader.ReadPackedUInt32();
+ this.Complete = reader.ReadBoolean();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Inner.Objects;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.Inner.Objects.Components;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal partial class InnerGameData : InnerNetObject, IInnerGameData
+ {
+ private readonly ILogger<InnerGameData> _logger;
+ private readonly Game _game;
+ private readonly ConcurrentDictionary<byte, PlayerInfo> _allPlayers;
+
+ public InnerGameData(ILogger<InnerGameData> logger, Game game, IServiceProvider serviceProvider)
+ {
+ _logger = logger;
+ _game = game;
+ _allPlayers = new ConcurrentDictionary<byte, PlayerInfo>();
+
+ Components.Add(this);
+ Components.Add(ActivatorUtilities.CreateInstance<InnerVoteBanSystem>(serviceProvider));
+ }
+
+ public int PlayerCount => _allPlayers.Count;
+
+ public IReadOnlyDictionary<byte, PlayerInfo> Players => _allPlayers;
+
+ public PlayerInfo? GetPlayerById(byte id)
+ {
+ if (id == byte.MaxValue)
+ {
+ return null;
+ }
+
+ return _allPlayers.TryGetValue(id, out var player) ? player : null;
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call,
+ IMessageReader reader)
+ {
+ switch (call)
+ {
+ case RpcCalls.SetTasks:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} to a specific player instead of broadcast");
+ }
+
+ var playerId = reader.ReadByte();
+ var taskTypeIds = reader.ReadBytesAndSize();
+
+ SetTasks(playerId, taskTypeIds);
+ break;
+ }
+
+ case RpcCalls.UpdateGameData:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetTasks)} to a specific player instead of broadcast");
+ }
+
+ while (reader.Position < reader.Length)
+ {
+ var message = reader.ReadMessage();
+ var player = GetPlayerById(message.Tag);
+ if (player != null)
+ {
+ player.Deserialize(message);
+ }
+ else
+ {
+ var playerInfo = new PlayerInfo(message.Tag);
+
+ playerInfo.Deserialize(reader);
+
+ if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
+ {
+ throw new ImpostorException("Failed to add player to InnerGameData.");
+ }
+ }
+ }
+
+ break;
+ }
+
+ default:
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerGameData), call);
+ break;
+ }
+ }
+
+ return default;
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerGameData)} as non-host");
+ }
+
+ if (initialState)
+ {
+ var num = reader.ReadPackedInt32();
+
+ for (var i = 0; i < num; i++)
+ {
+ var playerId = reader.ReadByte();
+ var playerInfo = new PlayerInfo(playerId);
+
+ playerInfo.Deserialize(reader);
+
+ if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
+ {
+ throw new ImpostorException("Failed to add player to InnerGameData.");
+ }
+ }
+ }
+ else
+ {
+ throw new NotImplementedException("This shouldn't happen, according to Among Us disassembly.");
+ }
+ }
+
+ internal void AddPlayer(InnerPlayerControl control)
+ {
+ var playerId = control.PlayerId;
+ var playerInfo = new PlayerInfo(control.PlayerId);
+
+ if (_allPlayers.TryAdd(playerId, playerInfo))
+ {
+ control.PlayerInfo = playerInfo;
+ }
+ }
+
+ private void SetTasks(byte playerId, ReadOnlyMemory<byte> taskTypeIds)
+ {
+ var player = GetPlayerById(playerId);
+ if (player == null)
+ {
+ _logger.LogTrace("Could not set tasks for playerId {0}.", playerId);
+ return;
+ }
+
+ if (player.Disconnected)
+ {
+ return;
+ }
+
+ player.Tasks = new List<TaskInfo>(taskTypeIds.Length);
+
+ for (var i = 0; i < taskTypeIds.Length; i++)
+ {
+ player.Tasks.Add(new TaskInfo());
+ player.Tasks[i].Id = (uint)i;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Threading.Tasks;
+using Impostor.Api.Games;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Inner.Objects;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.State;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal class InnerLobbyBehaviour : InnerNetObject, IInnerLobbyBehaviour
+ {
+ private readonly IGame _game;
+
+ public InnerLobbyBehaviour(IGame game)
+ {
+ _game = game;
+
+ Components.Add(this);
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal partial class InnerMeetingHud
+ {
+ public class PlayerVoteArea
+ {
+ private const byte VoteMask = 15;
+ private const byte ReportedBit = 32;
+ private const byte VotedBit = 64;
+ private const byte DeadBit = 128;
+
+ public PlayerVoteArea(InnerMeetingHud parent, byte targetPlayerId)
+ {
+ Parent = parent;
+ TargetPlayerId = targetPlayerId;
+ }
+
+ public InnerMeetingHud Parent { get; }
+
+ public byte TargetPlayerId { get; }
+
+ public bool IsDead { get; private set; }
+
+ public bool DidVote { get; private set; }
+
+ public bool DidReport { get; private set; }
+
+ public sbyte VotedFor { get; private set; }
+
+ internal void SetDead(bool didReport, bool isDead)
+ {
+ DidReport = didReport;
+ IsDead = isDead;
+ }
+
+ public void Deserialize(IMessageReader reader)
+ {
+ var num = reader.ReadByte();
+
+ VotedFor = (sbyte)((num & VoteMask) - 1);
+ IsDead = (num & DeadBit) > 0;
+ DidVote = (num & VotedBit) > 0;
+ DidReport = (num & ReportedBit) > 0;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal partial class InnerMeetingHud : InnerNetObject
+ {
+ private readonly ILogger<InnerMeetingHud> _logger;
+ private readonly Game _game;
+ private readonly GameNet _gameNet;
+ private PlayerVoteArea[] _playerStates;
+
+ public InnerMeetingHud(ILogger<InnerMeetingHud> logger, Game game)
+ {
+ _logger = logger;
+ _game = game;
+ _gameNet = game.GameNet;
+ _playerStates = null;
+
+ Components.Add(this);
+ }
+
+ public byte ReporterId { get; private set; }
+
+ private void PopulateButtons(byte reporter)
+ {
+ _playerStates = _gameNet.GameData.Players
+ .Select(x =>
+ {
+ var area = new PlayerVoteArea(this, x.Key);
+ area.SetDead(x.Value.PlayerId == reporter, x.Value.Disconnected || x.Value.IsDead);
+ return area;
+ })
+ .ToArray();
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call,
+ IMessageReader reader)
+ {
+ switch (call)
+ {
+ case RpcCalls.Close:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Close)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Close)} to a specific player instead of broadcast");
+ }
+
+ break;
+ }
+
+ case RpcCalls.VotingComplete:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.VotingComplete)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.VotingComplete)} to a specific player instead of broadcast");
+ }
+
+ var states = reader.ReadBytesAndSize();
+ var playerId = reader.ReadByte();
+ var tie = reader.ReadBoolean();
+ break;
+ }
+
+ case RpcCalls.CastVote:
+ {
+ var srcPlayerId = reader.ReadByte();
+ if (srcPlayerId != sender.Character.PlayerId)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ // Host broadcasts vote to others.
+ if (sender.IsHost && target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to a specific player instead of broadcast");
+ }
+
+ // Player sends vote to host.
+ if (target == null || !target.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CastVote)} to wrong destinition, must be host");
+ }
+
+ var targetPlayerId = reader.ReadByte();
+ break;
+ }
+
+ default:
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerMeetingHud), call);
+ break;
+ }
+ }
+
+ return default;
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerMeetingHud)} as non-host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client attempted to send {nameof(InnerMeetingHud)} data to a specific player, must be broadcast");
+ }
+
+ if (initialState)
+ {
+ PopulateButtons(0);
+
+ foreach (var playerState in _playerStates)
+ {
+ playerState.Deserialize(reader);
+
+ if (playerState.DidReport)
+ {
+ ReporterId = playerState.TargetPlayerId;
+ }
+ }
+ }
+ else
+ {
+ var num = reader.ReadPackedUInt32();
+
+ for (var i = 0; i < _playerStates.Length; i++)
+ {
+ if ((num & 1 << i) != 0)
+ {
+ _playerStates[i].Deserialize(reader);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Events.Managers;
+using Impostor.Api.Events.Net;
+using Impostor.Api.Innersloth;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Inner.Objects;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.Inner.Objects.Components;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal class InnerPlayerControl : InnerNetObject, IInnerPlayerControl
+ {
+ private readonly ILogger<InnerPlayerControl> _logger;
+ private readonly IEventManager _eventManager;
+ private readonly Game _game;
+
+ public InnerPlayerControl(ILogger<InnerPlayerControl> logger, IServiceProvider serviceProvider, IEventManager eventManager, Game game)
+ {
+ _logger = logger;
+ _eventManager = eventManager;
+ _game = game;
+
+ Components.Add(this);
+ Components.Add(ActivatorUtilities.CreateInstance<InnerPlayerPhysics>(serviceProvider));
+ Components.Add(ActivatorUtilities.CreateInstance<InnerCustomNetworkTransform>(serviceProvider));
+
+ PlayerId = byte.MaxValue;
+ }
+
+ public bool IsNew { get; private set; }
+
+ public byte PlayerId { get; private set; }
+
+ public InnerGameData.PlayerInfo PlayerInfo { get; internal set; }
+
+ public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call,
+ IMessageReader reader)
+ {
+ switch (call)
+ {
+ // Play an animation.
+ case RpcCalls.PlayAnimation:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.PlayAnimation)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.PlayAnimation)} to a specific player instead of broadcast");
+ }
+
+ var animation = reader.ReadByte();
+ break;
+ }
+
+ // Complete a task.
+ case RpcCalls.CompleteTask:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CompleteTask)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CompleteTask)} to a specific player instead of broadcast");
+ }
+
+ var index = reader.ReadPackedUInt32();
+ break;
+ }
+
+ // Update GameOptions.
+ case RpcCalls.SyncSettings:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SyncSettings)} but was not a host");
+ }
+
+ _game.Options.Deserialize(reader.ReadBytesAndSize());
+ break;
+ }
+
+ // Set Impostors.
+ case RpcCalls.SetInfected:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetInfected)} but was not a host");
+ }
+
+ var length = reader.ReadPackedInt32();
+
+ for (var i = 0; i < length; i++)
+ {
+ var playerId = reader.ReadByte();
+ var player = _game.GameNet.GameData.GetPlayerById(playerId);
+
+ player.IsImpostor = true;
+ }
+
+ break;
+ }
+
+ // Player was voted out.
+ case RpcCalls.Exiled:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Exiled)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.Exiled)} to a specific player instead of broadcast");
+ }
+
+ // TODO: Not hit?
+ Die(DeathReason.Exile);
+ break;
+ }
+
+ // Validates the player name at the host.
+ case RpcCalls.CheckName:
+ {
+ if (target == null || !target.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckName)} to the wrong player");
+ }
+
+ var name = reader.ReadString();
+ break;
+ }
+
+ // Update the name of a player.
+ case RpcCalls.SetName:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetName)} to a specific player instead of broadcast");
+ }
+
+ PlayerInfo.PlayerName = reader.ReadString();
+ break;
+ }
+
+ // Validates the color at the host.
+ case RpcCalls.CheckColor:
+ {
+ if (target == null || !target.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CheckColor)} to the wrong player");
+ }
+
+ var color = reader.ReadByte();
+ break;
+ }
+
+ // Update the color of a player.
+ case RpcCalls.SetColor:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetColor)} to a specific player instead of broadcast");
+ }
+
+ PlayerInfo.ColorId = reader.ReadByte();
+ break;
+ }
+
+ // Update the hat of a player.
+ case RpcCalls.SetHat:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to a specific player instead of broadcast");
+ }
+
+ PlayerInfo.HatId = reader.ReadPackedUInt32();
+ break;
+ }
+
+ case RpcCalls.SetSkin:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetSkin)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetHat)} to a specific player instead of broadcast");
+ }
+
+ PlayerInfo.SkinId = reader.ReadPackedUInt32();
+ break;
+ }
+
+ // TODO: (ANTICHEAT) Location check?
+ case RpcCalls.ReportDeadBody:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.ReportDeadBody)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.ReportDeadBody)} to a specific player instead of broadcast");
+ }
+
+ var deadBodyPlayerId = reader.ReadByte();
+ break;
+ }
+
+ // TODO: (ANTICHEAT) Cooldown check?
+ case RpcCalls.MurderPlayer:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} to a specific player instead of broadcast");
+ }
+
+ if (!sender.Character.PlayerInfo.IsImpostor)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.MurderPlayer)} as crewmate");
+ }
+
+ var player = reader.ReadNetObject<InnerPlayerControl>(_game);
+ if (!player.PlayerInfo.IsDead)
+ {
+ player.Die(DeathReason.Kill);
+ }
+
+ break;
+ }
+
+ case RpcCalls.SendChat:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChat)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChat)} to a specific player instead of broadcast");
+ }
+
+ var chat = reader.ReadString();
+
+ await _eventManager.CallAsync(new PlayerChatEvent(_game, this, chat));
+ break;
+ }
+
+ case RpcCalls.StartMeeting:
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.StartMeeting)} but was not a host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.StartMeeting)} to a specific player instead of broadcast");
+ }
+
+ var playerId = reader.ReadByte();
+ var player = _game.GameNet.GameData.GetPlayerById(playerId);
+
+ // Meeting started by "player", can also be null.
+ break;
+ }
+
+ case RpcCalls.SetScanner:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetScanner)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetScanner)} to a specific player instead of broadcast");
+ }
+
+ var on = reader.ReadBoolean();
+ var count = reader.ReadByte();
+ break;
+ }
+
+ case RpcCalls.SendChatNote:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChatNote)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SendChatNote)} to a specific player instead of broadcast");
+ }
+
+ var playerId = reader.ReadByte();
+ var chatNote = (ChatNoteType)reader.ReadByte();
+ break;
+ }
+
+ case RpcCalls.SetPet:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetPet)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetPet)} to a specific player instead of broadcast");
+ }
+
+ PlayerInfo.PetId = reader.ReadPackedUInt32();
+ break;
+ }
+
+ // TODO: Understand this RPC
+ case RpcCalls.SetStartCounter:
+ {
+ if (!sender.IsOwner(this))
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetStartCounter)} to an unowned {nameof(InnerPlayerControl)}");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetStartCounter)} to a specific player instead of broadcast");
+ }
+
+ // Used to compare with LastStartCounter.
+ var startCounter = reader.ReadPackedUInt32();
+
+ // Is either start countdown or byte.MaxValue
+ var secondsLeft = reader.ReadByte();
+ break;
+ }
+
+ default:
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerPlayerControl), call);
+ break;
+ }
+ }
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerPlayerControl)} as non-host");
+ }
+
+ if (initialState)
+ {
+ IsNew = reader.ReadBoolean();
+ }
+
+ PlayerId = reader.ReadByte();
+ }
+
+ private void Die(DeathReason reason)
+ {
+ PlayerInfo.IsDead = true;
+ PlayerInfo.LastDeathReason = reason;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Impostor.Api;
+using Impostor.Api.Innersloth;
+using Impostor.Api.Net;
+using Impostor.Api.Net.Inner.Objects;
+using Impostor.Api.Net.Messages;
+using Impostor.Server.Net.Inner.Objects.Systems;
+using Impostor.Server.Net.Inner.Objects.Systems.ShipStatus;
+using Impostor.Server.Net.State;
+using Microsoft.Extensions.Logging;
+
+namespace Impostor.Server.Net.Inner.Objects
+{
+ internal class InnerShipStatus : InnerNetObject, IInnerShipStatus
+ {
+ private readonly ILogger<InnerShipStatus> _logger;
+ private readonly Game _game;
+ private readonly Dictionary<SystemTypes, ISystemType> _systems;
+
+ public InnerShipStatus(ILogger<InnerShipStatus> logger, Game game)
+ {
+ _logger = logger;
+ _game = game;
+
+ _systems = new Dictionary<SystemTypes, ISystemType>
+ {
+ [SystemTypes.Electrical] = new SwitchSystem(),
+ [SystemTypes.MedBay] = new MedScanSystem(),
+ [SystemTypes.Reactor] = new ReactorSystemType(),
+ [SystemTypes.LifeSupp] = new LifeSuppSystemType(),
+ [SystemTypes.Security] = new SecurityCameraSystemType(),
+ [SystemTypes.Comms] = new HudOverrideSystemType(),
+ [SystemTypes.Doors] = new DoorsSystemType(_game),
+ };
+
+ _systems.Add(SystemTypes.Sabotage, new SabotageSystemType(new[]
+ {
+ (IActivatable)_systems[SystemTypes.Comms],
+ (IActivatable)_systems[SystemTypes.Reactor],
+ (IActivatable)_systems[SystemTypes.LifeSupp],
+ (IActivatable)_systems[SystemTypes.Electrical],
+ }));
+
+ Components.Add(this);
+ }
+
+ public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call,
+ IMessageReader reader)
+ {
+ switch (call)
+ {
+ case RpcCalls.CloseDoorsOfType:
+ {
+ if (target == null || !target.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CloseDoorsOfType)} to wrong destinition, must be host");
+ }
+
+ if (!sender.Character.PlayerInfo.IsImpostor)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.CloseDoorsOfType)} as crewmate");
+ }
+
+ var systemType = (SystemTypes)reader.ReadByte();
+
+ break;
+ }
+
+ case RpcCalls.RepairSystem:
+ {
+ if (target == null || !target.IsHost)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.RepairSystem)} to wrong destinition, must be host");
+ }
+
+ if (!sender.Character.PlayerInfo.IsImpostor)
+ {
+ throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.RepairSystem)} as crewmate");
+ }
+
+ var systemType = (SystemTypes)reader.ReadByte();
+ var player = reader.ReadNetObject<InnerPlayerControl>(_game);
+ var amount = reader.ReadByte();
+
+ // TODO: Modify data (?)
+
+ break;
+ }
+
+ default:
+ {
+ _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerShipStatus), call);
+ break;
+ }
+ }
+
+ return default;
+ }
+
+ public override bool Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Deserialize(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
+ {
+ if (!sender.IsHost)
+ {
+ throw new ImpostorCheatException($"Client attempted to send data for {nameof(InnerShipStatus)} as non-host");
+ }
+
+ if (target != null)
+ {
+ throw new ImpostorCheatException($"Client attempted to send {nameof(InnerShipStatus)} data to a specific player, must be broadcast");
+ }
+
+ if (initialState)
+ {
+ // TODO: (_systems[SystemTypes.Doors] as DoorsSystemType).SetDoors();
+ foreach (var systemType in SystemTypeHelpers.AllTypes)
+ {
+ if (_systems.TryGetValue(systemType, out var system))
+ {
+ system.Deserialize(reader, true);
+ }
+ }
+ }
+ else
+ {
+ var count = reader.ReadPackedUInt32();
+
+ foreach (var systemType in SystemTypeHelpers.AllTypes)
+ {
+ // TODO: Not sure what is going on here, check.
+ if ((count & 1 << (int)(systemType & (SystemTypes.ShipTasks | SystemTypes.Doors))) != 0L)
+ {
+ if (_systems.TryGetValue(systemType, out var system))
+ {
+ system.Deserialize(reader, false);
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Server.Net.Inner.Objects.Systems
+{
+ public interface IActivatable
+ {
+ bool IsActive { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems
+{
+ public interface ISystemType
+ {
+ void Serialize(IMessageWriter writer, bool initialState);
+
+ void Deserialize(IMessageReader reader, bool initialState);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Games;
+using Impostor.Api.Innersloth;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class DoorsSystemType : ISystemType
+ {
+ // TODO: AutoDoors
+ private readonly Dictionary<int, bool> _doors;
+
+ public DoorsSystemType(IGame game)
+ {
+ // TODO: Check
+ var doorCount = game.Options.MapId switch
+ {
+ MapId.Skeld => 13,
+ MapId.MiraHQ => 2,
+ MapId.Polus => 12,
+ _ => throw new ArgumentOutOfRangeException()
+ };
+
+ _doors = new Dictionary<int, bool>(doorCount);
+
+ for (var i = 0; i < doorCount; i++)
+ {
+ _doors.Add(i, false);
+ }
+ }
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ if (initialState)
+ {
+ for (var i = 0; i < _doors.Count; i++)
+ {
+ _doors[i] = reader.ReadBoolean();
+ }
+ }
+ else
+ {
+ var num = reader.ReadPackedUInt32();
+
+ for (var i = 0; i < _doors.Count; i++)
+ {
+ if ((num & 1 << i) != 0)
+ {
+ _doors[i] = reader.ReadBoolean();
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class HudOverrideSystemType : ISystemType, IActivatable
+ {
+ public bool IsActive { get; private set; }
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ IsActive = reader.ReadBoolean();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class LifeSuppSystemType : ISystemType, IActivatable
+ {
+ public LifeSuppSystemType()
+ {
+ Countdown = 10000f;
+ CompletedConsoles = new HashSet<int>();
+ }
+
+ public float Countdown { get; private set; }
+
+ public HashSet<int> CompletedConsoles { get; }
+
+ public bool IsActive => Countdown < 10000.0;
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ Countdown = reader.ReadSingle();
+
+ if (reader.Position >= reader.Length)
+ {
+ return;
+ }
+
+ CompletedConsoles.Clear(); // TODO: Thread safety
+
+ var num = reader.ReadPackedInt32();
+
+ for (var i = 0; i < num; i++)
+ {
+ CompletedConsoles.Add(reader.ReadPackedInt32());
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class MedScanSystem : ISystemType
+ {
+ public MedScanSystem()
+ {
+ UsersList = new List<byte>();
+ }
+
+ public List<byte> UsersList { get; }
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ UsersList.Clear();
+
+ var num = reader.ReadPackedInt32();
+
+ for (var i = 0; i < num; i++)
+ {
+ UsersList.Add(reader.ReadByte());
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class ReactorSystemType : ISystemType, IActivatable
+ {
+ public ReactorSystemType()
+ {
+ Countdown = 10000f;
+ UserConsolePairs = new HashSet<Tuple<byte, byte>>();
+ }
+
+ public float Countdown { get; private set; }
+
+ public HashSet<Tuple<byte, byte>> UserConsolePairs { get; }
+
+ public bool IsActive => Countdown < 10000.0;
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ Countdown = reader.ReadSingle();
+ UserConsolePairs.Clear(); // TODO: Thread safety
+
+ var count = reader.ReadPackedInt32();
+
+ for (var i = 0; i < count; i++)
+ {
+ UserConsolePairs.Add(new Tuple<byte, byte>(reader.ReadByte(), reader.ReadByte()));
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class SabotageSystemType : ISystemType
+ {
+ private readonly IActivatable[] _specials;
+
+ public SabotageSystemType(IActivatable[] specials)
+ {
+ _specials = specials;
+ }
+
+ public float Timer { get; set; }
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ Timer = reader.ReadSingle();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class SecurityCameraSystemType : ISystemType
+ {
+ public byte InUse { get; internal set; }
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ InUse = reader.ReadByte();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Impostor.Api.Net.Messages;
+
+namespace Impostor.Server.Net.Inner.Objects.Systems.ShipStatus
+{
+ public class SwitchSystem : ISystemType, IActivatable
+ {
+ public byte ExpectedSwitches { get; set; }
+
+ public byte ActualSwitches { get; set; }
+
+ public byte Value { get; set; } = byte.MaxValue;
+
+ public bool IsActive { get; }
+
+ public void Serialize(IMessageWriter writer, bool initialState)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Deserialize(IMessageReader reader, bool initialState)
+ {
+ ExpectedSwitches = reader.ReadByte();
+ ActualSwitches = reader.ReadByte();
+ Value = reader.ReadByte();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Impostor.Server.Net.Inner
+{
+ public enum RpcCalls : byte
+ {
+ PlayAnimation = 0,
+ CompleteTask = 1,
+ SyncSettings = 2,
+ SetInfected = 3,
+ Exiled = 4,
+ CheckName = 5,
+ SetName = 6,
+ CheckColor = 7,
+ SetColor = 8,
+ SetHat = 9,
+ SetSkin = 10,
+ ReportDeadBody = 11,
+ MurderPlayer = 12,
+ SendChat = 13,
+ StartMeeting = 14,
+ SetScanner = 15,
+ SendChatNote = 16,
+ SetPet = 17,
+ SetStartCounter = 18,
+ EnterVent = 19,
+ ExitVent = 20,
+ SnapTo = 21,
+ Close = 22,
+ VotingComplete = 23,
+ CastVote = 24,
+ ClearVote = 25,
+ AddVote = 26,
+ CloseDoorsOfType = 27,
+ RepairSystem = 28,
+ SetTasks = 29,
+ UpdateGameData = 30,
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Impostor.Server.Net.Inner
+{
+ [Flags]
+ public enum SpawnFlags : byte
+ {
+ None = 0,
+ IsClientCharacter = 1,
+ }
+}
\ No newline at end of file
using System.Threading;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
-using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net;
using Impostor.Api.Net.Manager;
using Impostor.Api.Net.Messages;
using Impostor.Hazel;
using Impostor.Server.Config;
using Impostor.Server.Net.Factories;
-using Impostor.Server.Net.Hazel;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.Manager
using Impostor.Api.Games;
using Impostor.Api.Games.Managers;
using Impostor.Api.Innersloth;
-using Impostor.Api.Innersloth.Data;
using Impostor.Server.Config;
-using Impostor.Server.Extensions;
using Impostor.Server.Net.Redirector;
using Impostor.Server.Net.State;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
-using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.C2S;
using Impostor.Api.Net.Messages.S2C;
using Impostor.Api.Games;
using Impostor.Api.Net;
+using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Server.Net.State
{
/// <inheritdoc />
IGame IClientPlayer.Game => Game;
+
+ /// <inheritdoc />
+ IInnerPlayerControl IClientPlayer.Character => Character;
}
}
\ No newline at end of file
using System;
using System.Threading;
using System.Threading.Tasks;
-using Impostor.Api.Innersloth.Net;
-using Impostor.Api.Innersloth.Net.Objects;
using Impostor.Api.Net;
+using Impostor.Api.Net.Inner;
+using Impostor.Server.Net.Inner.Objects;
using Microsoft.Extensions.Logging;
namespace Impostor.Server.Net.State
}
/// <inheritdoc />
- public bool IsOwner(InnerNetObject netObject)
+ public bool IsOwner(IInnerNetObject netObject)
{
return Client.Id == netObject.OwnerId;
}
using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Net;
using Impostor.Api.Net;
+using Impostor.Api.Net.Inner;
namespace Impostor.Server.Net.State
{
using System.Threading.Tasks;
using Impostor.Api;
using Impostor.Api.Events.Net;
-using Impostor.Api.Innersloth.Data;
-using Impostor.Api.Innersloth.Net;
-using Impostor.Api.Innersloth.Net.Objects;
-using Impostor.Api.Innersloth.Net.Objects.Components;
+using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.S2C;
using Impostor.Hazel;
+using Impostor.Server.Net.Inner;
+using Impostor.Server.Net.Inner.Objects;
+using Impostor.Server.Net.Inner.Objects.Components;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
var netId = reader.ReadPackedUInt32();
if (_allObjectsFast.TryGetValue(netId, out var obj))
{
- obj.HandleRpc(sender, target, (RpcCalls) reader.ReadByte(), reader);
+ await obj.HandleRpc(sender, target, (RpcCalls) reader.ReadByte(), reader);
}
else
{
using System.Threading;
using System.Threading.Tasks;
using Impostor.Api.Games;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Hazel;
using System.Linq;
using System.Threading.Tasks;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.S2C;
using System.Threading.Tasks;
using Impostor.Api;
using Impostor.Api.Events;
-using Impostor.Api.Innersloth.Data;
+using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Hazel;
using Impostor.Api.Events.Managers;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
-using Impostor.Api.Innersloth.Data;
-using Impostor.Api.Innersloth.Net;
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
using Impostor.Api.Net.Messages.S2C;
--- /dev/null
+using Impostor.Api.Net.Inner;
+using Impostor.Api.Net.Inner.Objects;
+
+namespace Impostor.Server.Net.State
+{
+ /// <inheritdoc />
+ internal partial class GameNet : IGameNet
+ {
+ IInnerLobbyBehaviour IGameNet.LobbyBehaviour => LobbyBehaviour;
+
+ IInnerGameData IGameNet.GameData => GameData;
+
+ IInnerVoteBanSystem IGameNet.VoteBan => VoteBan;
+
+ IInnerShipStatus IGameNet.ShipStatus => ShipStatus;
+ }
+}
\ No newline at end of file
-using Impostor.Api.Innersloth.Net;
-using Impostor.Api.Innersloth.Net.Objects;
-using Impostor.Api.Innersloth.Net.Objects.Components;
+using Impostor.Server.Net.Inner.Objects;
+using Impostor.Server.Net.Inner.Objects.Components;
namespace Impostor.Server.Net.State
{
- /// <summary>
- /// Holds all data that is serialized over the network through GameData packets.
- /// </summary>
- public class GameNet : IGameNet
+ internal partial class GameNet
{
public InnerLobbyBehaviour LobbyBehaviour { get; internal set; }