mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-28 19:43:50 +00:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4452621cd3 | ||
|
|
53209aa78f | ||
|
|
c729d26ff6 | ||
|
|
e2157b0a6f | ||
|
|
ad18eda32f | ||
|
|
efda5bcef2 | ||
|
|
6a947457a5 | ||
|
|
a3c6ca77c1 | ||
|
|
9f3f826b17 | ||
|
|
36671ba1ba | ||
|
|
ace97ddc1d | ||
|
|
4dc4c90e8b | ||
|
|
9379c05676 | ||
|
|
ef98f4d20e | ||
|
|
9f6947b484 | ||
|
|
76ae1a3385 | ||
|
|
3c8a002d6e |
No files matched your search
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>11</LangVersion>
|
||||
<VersionPrefix>1.10.1</VersionPrefix>
|
||||
<VersionPrefix>1.10.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
<EnforceCodeStyleInBuild Condition="$(MSBuildProjectName)!='Hazel'">true</EnforceCodeStyleInBuild>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
|
||||
@@ -59,15 +59,15 @@ namespace Impostor.Api.Innersloth.Customization
|
||||
internal set => SetField(ref _namePlateId, value);
|
||||
}
|
||||
|
||||
internal byte HatSequenceId { get; set; } = 0;
|
||||
private byte HatSequenceId { get; set; } = 0;
|
||||
|
||||
internal byte PetSequenceId { get; set; } = 0;
|
||||
private byte PetSequenceId { get; set; } = 0;
|
||||
|
||||
internal byte SkinSequenceId { get; set; } = 0;
|
||||
private byte SkinSequenceId { get; set; } = 0;
|
||||
|
||||
internal byte VisorSequenceId { get; set; } = 0;
|
||||
private byte VisorSequenceId { get; set; } = 0;
|
||||
|
||||
internal byte NamePlateSequenceId { get; set; } = 0;
|
||||
private byte NamePlateSequenceId { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a player outfit is complete or whether it needs to receive additional cosmetics.
|
||||
|
||||
@@ -1439,9 +1439,6 @@
|
||||
"CookFish": 3431,
|
||||
"PrepVegetables": 3432,
|
||||
"MushroomMixupName": 3433,
|
||||
"EosAccountSilentMergeFail": 3434,
|
||||
"AskForEosAccount": 3435,
|
||||
"KwsCreateFail": 3436,
|
||||
"GameType": 3500,
|
||||
"GameTypeError": 3501,
|
||||
"GameTypeClassic": 3502,
|
||||
@@ -1482,15 +1479,5 @@
|
||||
"QCLobbyRolePhantoms": 3537,
|
||||
"QCSelfWasTracking": 3538,
|
||||
"QCSelfGoingToNoisemaker": 3539,
|
||||
"QCSelfSawRoleInLocation": 3540,
|
||||
"QCCoreSettings": 3541,
|
||||
"QCRolesGalore": 3542,
|
||||
"QCPitchDark": 3543,
|
||||
"QCFlashlight": 3544,
|
||||
"QCPleaseWait": 3545,
|
||||
"QCWaitMinute": 3546,
|
||||
"QCLobbyClosing": 3547,
|
||||
"QCChangeCosmetics": 3548,
|
||||
"QCWaitingPlayers": 3549,
|
||||
"QCLetsWaitPlayers": 3550
|
||||
"QCSelfSawRoleInLocation": 3540
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dumpostorVersion": "1.0.1",
|
||||
"gameVersion": "2024.10.29",
|
||||
"gameVersion": "2024.6.18",
|
||||
"platformType": "StandaloneItch"
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ namespace Impostor.Api.Net.Messages
|
||||
public const byte SetActivePodType = 21;
|
||||
public const byte QueryPlatformIds = 22;
|
||||
public const byte QueryLobbyInfo = 23;
|
||||
public const byte EndGameHostMigration = 24;
|
||||
|
||||
private static readonly Dictionary<byte, string> FlagCache;
|
||||
|
||||
|
||||
@@ -4,13 +4,15 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc29SetTasks
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, ReadOnlyMemory<byte> taskTypeIds)
|
||||
public static void Serialize(IMessageWriter writer, byte playerId, ReadOnlyMemory<byte> taskTypeIds)
|
||||
{
|
||||
writer.Write(playerId);
|
||||
writer.Write(taskTypeIds);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out ReadOnlyMemory<byte> taskTypeIds)
|
||||
public static void Deserialize(IMessageReader reader, out byte playerId, out ReadOnlyMemory<byte> taskTypeIds)
|
||||
{
|
||||
playerId = reader.ReadByte();
|
||||
taskTypeIds = reader.ReadBytesAndSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc39SetHatStr
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, string hat, byte nextRpcSequenceId)
|
||||
public static void Serialize(IMessageWriter writer, string hat)
|
||||
{
|
||||
writer.Write(hat);
|
||||
writer.Write(nextRpcSequenceId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out string hat, out byte nextRpcSequenceId)
|
||||
public static void Deserialize(IMessageReader reader, out string hat)
|
||||
{
|
||||
hat = reader.ReadString();
|
||||
nextRpcSequenceId = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,14 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc40SetSkinStr
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, string skin, byte nextRpcSequenceId)
|
||||
public static void Serialize(IMessageWriter writer, string skin)
|
||||
{
|
||||
writer.Write(skin);
|
||||
writer.Write(nextRpcSequenceId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out string skin, out byte nextRpcSequenceId)
|
||||
public static void Deserialize(IMessageReader reader, out string skin)
|
||||
{
|
||||
skin = reader.ReadString();
|
||||
nextRpcSequenceId = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,14 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc41SetPetStr
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, string pet, byte nextRpcSequenceId)
|
||||
public static void Serialize(IMessageWriter writer, string pet)
|
||||
{
|
||||
writer.Write(pet);
|
||||
writer.Write(nextRpcSequenceId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out string pet, out byte nextRpcSequenceId)
|
||||
public static void Deserialize(IMessageReader reader, out string pet)
|
||||
{
|
||||
pet = reader.ReadString();
|
||||
nextRpcSequenceId = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,14 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc42SetVisorStr
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, string visor, byte nextRpcSequenceId)
|
||||
public static void Serialize(IMessageWriter writer, string visor)
|
||||
{
|
||||
writer.Write(visor);
|
||||
writer.Write(nextRpcSequenceId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out string visor, out byte nextRpcSequenceId)
|
||||
public static void Deserialize(IMessageReader reader, out string visor)
|
||||
{
|
||||
visor = reader.ReadString();
|
||||
nextRpcSequenceId = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,14 @@ namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc43SetNamePlateStr
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, string namePlate, byte nextRpcSequenceId)
|
||||
public static void Serialize(IMessageWriter writer, string namePlate)
|
||||
{
|
||||
writer.Write(namePlate);
|
||||
writer.Write(nextRpcSequenceId);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out string namePlate, out byte nextRpcSequenceId)
|
||||
public static void Deserialize(IMessageReader reader, out string namePlate)
|
||||
{
|
||||
namePlate = reader.ReadString();
|
||||
nextRpcSequenceId = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc62CheckVanish
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, float maxDuration)
|
||||
{
|
||||
writer.Write(maxDuration);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out float maxDuration)
|
||||
{
|
||||
maxDuration = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc63StartVanish
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc64CheckAppear
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, bool shouldAnimate)
|
||||
{
|
||||
writer.Write(shouldAnimate);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out bool shouldAnimate)
|
||||
{
|
||||
shouldAnimate = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Impostor.Api.Net.Messages.Rpcs
|
||||
{
|
||||
public static class Rpc65StartAppear
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, bool shouldAnimate)
|
||||
{
|
||||
writer.Write(shouldAnimate);
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out bool shouldAnimate)
|
||||
{
|
||||
shouldAnimate = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Impostor.Api.Games;
|
||||
|
||||
namespace Impostor.Api.Net.Messages.S2C
|
||||
{
|
||||
public class Message24EndGameHostMigrationS2C
|
||||
{
|
||||
public static void Serialize(IMessageWriter writer, GameCode gameCode, int hostClientId)
|
||||
{
|
||||
writer.StartMessage(MessageFlags.EndGameHostMigration);
|
||||
gameCode.Serialize(writer);
|
||||
writer.Write(hostClientId);
|
||||
writer.EndMessage();
|
||||
}
|
||||
|
||||
public static void Deserialize(IMessageReader reader, out GameCode gameCode, out int hostClientId)
|
||||
{
|
||||
gameCode = reader.ReadInt32();
|
||||
hostClientId = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,27 +82,14 @@ namespace Impostor.Server.Net
|
||||
return false;
|
||||
}
|
||||
|
||||
var supportCode = Random.Shared.Next(0, 999_999).ToString("000-000");
|
||||
_logger.LogWarning("Client {Name} ({Id}) was caught cheating: [{Context}-{Category}] {Message}", Name, Id, context.Name, category, message);
|
||||
|
||||
_logger.LogWarning("Client {Name} ({Id}) was caught cheating: [{SupportCode}] [{Context}-{Category}] {Message}", Name, Id, supportCode, context.Name, category, message);
|
||||
|
||||
if (Player is { } player)
|
||||
if (_antiCheatConfig.BanIpFromGame)
|
||||
{
|
||||
if (_antiCheatConfig.BanIpFromGame)
|
||||
{
|
||||
player.Game.BanIp(Connection.EndPoint.Address);
|
||||
}
|
||||
|
||||
await player.Game.HandleRemovePlayer(Id, DisconnectReason.Hacking);
|
||||
Player?.Game.BanIp(Connection.EndPoint.Address);
|
||||
}
|
||||
|
||||
var disconnectMessage =
|
||||
$"""
|
||||
You have been caught cheating and were {(_antiCheatConfig.BanIpFromGame ? "banned" : "kicked")} from the lobby.
|
||||
For questions, contact your server admin and share the following code: {supportCode}.
|
||||
""";
|
||||
|
||||
await DisconnectAsync(DisconnectReason.Custom, disconnectMessage);
|
||||
await DisconnectAsync(DisconnectReason.Hacking, context.Name + ": " + message);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -361,9 +348,7 @@ namespace Impostor.Server.Net
|
||||
{
|
||||
if (Player != null)
|
||||
{
|
||||
// The client never sends over the real disconnect reason so we always assume ExitGame
|
||||
var isRemote = reason == "The remote sent a disconnect request";
|
||||
await Player.Game.HandleRemovePlayer(Id, isRemote ? DisconnectReason.ExitGame : DisconnectReason.Error);
|
||||
await Player.Game.HandleRemovePlayer(Id, DisconnectReason.ExitGame);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Impostor.Server.Net.Inner
|
||||
|
||||
public SpawnFlags SpawnFlags { get; internal set; }
|
||||
|
||||
public virtual bool IsDirty { get; internal set; }
|
||||
|
||||
public bool IsOwnedBy(IClientPlayer player)
|
||||
{
|
||||
return OwnerId == player.Client.Id ||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api;
|
||||
using Impostor.Api.Net.Inner;
|
||||
using Impostor.Api.Net.Messages.Rpcs;
|
||||
using Impostor.Server.Events.Player;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal partial class InnerGameData
|
||||
{
|
||||
public partial class TaskInfo
|
||||
{
|
||||
public async ValueTask CompleteAsync()
|
||||
{
|
||||
if (_playerInfo.Controller == null)
|
||||
{
|
||||
throw new ImpostorException("Can't complete a task that doesn't have a player assigned");
|
||||
}
|
||||
|
||||
var player = _playerInfo.Controller;
|
||||
|
||||
if (Complete)
|
||||
{
|
||||
throw new ImpostorException("Can't complete a task that is already completed");
|
||||
}
|
||||
|
||||
Complete = true;
|
||||
|
||||
// Send RPC.
|
||||
using var writer = player.Game.StartRpc(player.NetId, RpcCalls.CompleteTask);
|
||||
Rpc01CompleteTask.Serialize(writer, Id);
|
||||
await player.Game.FinishRpcAsync(writer);
|
||||
|
||||
// Notify plugins.
|
||||
await _eventManager.CallAsync(new PlayerCompletedTaskEvent(player.Game, player.Game.GetClientPlayer(player.OwnerId)!, player, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Innersloth.Maps;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal partial class InnerGameData
|
||||
{
|
||||
public partial class TaskInfo : ITaskInfo
|
||||
{
|
||||
private readonly InnerPlayerInfo _playerInfo;
|
||||
private readonly IEventManager _eventManager;
|
||||
|
||||
public TaskInfo(InnerPlayerInfo playerInfo, IEventManager eventManager, uint id, TaskData? task)
|
||||
{
|
||||
_playerInfo = playerInfo;
|
||||
_eventManager = eventManager;
|
||||
Id = id;
|
||||
Task = task;
|
||||
}
|
||||
|
||||
public uint Id { get; internal set; }
|
||||
|
||||
public TaskData? Task { 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)
|
||||
{
|
||||
Id = reader.ReadPackedUInt32();
|
||||
Complete = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,9 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.PlayerName = name;
|
||||
|
||||
// TODO check playerinfo ownership
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetName);
|
||||
Rpc06SetName.Serialize(writer, PlayerInfo.NetId, name);
|
||||
writer.Write(name);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
@@ -40,8 +41,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.HatId = hatId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetHatStr);
|
||||
Rpc39SetHatStr.Serialize(writer, hatId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetHatStr));
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetHat);
|
||||
Rpc39SetHatStr.Serialize(writer, hatId);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
@@ -49,8 +50,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.PetId = petId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetPetStr);
|
||||
Rpc41SetPetStr.Serialize(writer, petId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetPetStr));
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetPet);
|
||||
Rpc41SetPetStr.Serialize(writer, petId);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
@@ -58,26 +59,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.SkinId = skinId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetSkinStr);
|
||||
Rpc40SetSkinStr.Serialize(writer, skinId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetSkinStr));
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
public async ValueTask SetVisorAsync(string visorId)
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.VisorId = visorId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetVisorStr);
|
||||
Rpc42SetVisorStr.Serialize(writer, visorId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetVisorStr));
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
public async ValueTask SetNamePlateAsync(string nameplateId)
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.NamePlateId = nameplateId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetNamePlateStr);
|
||||
Rpc43SetNamePlateStr.Serialize(writer, nameplateId, PlayerInfo.GetNextRpcSequenceId(RpcCalls.SetNamePlateStr));
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetSkin);
|
||||
Rpc40SetSkinStr.Serialize(writer, skinId);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
@@ -166,19 +149,5 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
// Notify plugins.
|
||||
await _eventManager.CallAsync(new PlayerExileEvent(Game, Game.GetClientPlayer(OwnerId)!, this));
|
||||
}
|
||||
|
||||
public async ValueTask StartVanishAsync()
|
||||
{
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.StartVanish);
|
||||
Rpc63StartVanish.Serialize(writer);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
public async ValueTask StartAppearAsync(bool shouldAnimate)
|
||||
{
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.StartAppear);
|
||||
Rpc65StartAppear.Serialize(writer, shouldAnimate);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,8 +203,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc39SetHatStr.Deserialize(reader, out var hat, out var nextRpcSequenceId);
|
||||
return await HandleSetHat(sender, hat, nextRpcSequenceId);
|
||||
Rpc39SetHatStr.Deserialize(reader, out var hat);
|
||||
return await HandleSetHat(sender, hat);
|
||||
}
|
||||
|
||||
case RpcCalls.SetSkinStr:
|
||||
@@ -215,8 +215,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc40SetSkinStr.Deserialize(reader, out var skin, out var nextRpcSequenceId);
|
||||
return await HandleSetSkin(sender, skin, nextRpcSequenceId);
|
||||
Rpc40SetSkinStr.Deserialize(reader, out var skin);
|
||||
return await HandleSetSkin(sender, skin);
|
||||
}
|
||||
|
||||
case RpcCalls.SetVisorStr:
|
||||
@@ -227,8 +227,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc42SetVisorStr.Deserialize(reader, out var visor, out var nextRpcSequenceId);
|
||||
return await HandleSetVisor(sender, visor, nextRpcSequenceId);
|
||||
Rpc42SetVisorStr.Deserialize(reader, out var visor);
|
||||
return await HandleSetVisor(sender, visor);
|
||||
}
|
||||
|
||||
case RpcCalls.SetNamePlateStr:
|
||||
@@ -238,8 +238,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc43SetNamePlateStr.Deserialize(reader, out var namePlate, out var nextRpcSequenceId);
|
||||
return await HandleSetNamePlate(sender, namePlate, nextRpcSequenceId);
|
||||
Rpc43SetNamePlateStr.Deserialize(reader, out var namePlate);
|
||||
return await HandleSetNamePlate(sender, namePlate);
|
||||
}
|
||||
|
||||
case RpcCalls.SetLevel:
|
||||
@@ -251,7 +251,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
|
||||
Rpc38SetLevel.Deserialize(reader, out var level);
|
||||
return await HandleSetLevel(sender, level);
|
||||
return true;
|
||||
}
|
||||
|
||||
case RpcCalls.ReportDeadBody:
|
||||
@@ -335,8 +335,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc41SetPetStr.Deserialize(reader, out var pet, out var nextRpcSequenceId);
|
||||
return await HandleSetPet(sender, pet, nextRpcSequenceId);
|
||||
Rpc41SetPetStr.Deserialize(reader, out var pet);
|
||||
return await HandleSetPet(sender, pet);
|
||||
}
|
||||
|
||||
case RpcCalls.SetStartCounter:
|
||||
@@ -392,6 +392,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
|
||||
PlayerInfo.RoleType = role;
|
||||
PlayerInfo.IsDirty = true;
|
||||
|
||||
if (Game.GameState == GameStates.Starting && Game.Players.All(clientPlayer => clientPlayer.Character?.PlayerInfo.RoleType != null))
|
||||
{
|
||||
@@ -511,7 +512,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc55CheckShapeshift.Deserialize(reader, Game, out var playerControl, out _);
|
||||
Rpc55CheckShapeshift.Deserialize(reader, Game, out var playerControl, out var shouldAnimate);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -526,56 +527,6 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
break;
|
||||
}
|
||||
|
||||
case RpcCalls.CheckVanish:
|
||||
{
|
||||
if (!await ValidateOwnership(call, sender) ||
|
||||
!await ValidateRole(call, sender, PlayerInfo, RoleTypes.Phantom) ||
|
||||
!await ValidateCmd(call, sender, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc62CheckVanish.Deserialize(reader, out var maxDuration);
|
||||
return await HandleCheckVanish(sender, maxDuration);
|
||||
}
|
||||
|
||||
case RpcCalls.StartVanish:
|
||||
{
|
||||
if (!await ValidateHost(call, sender) ||
|
||||
!await ValidateBroadcast(call, sender, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc63StartVanish.Deserialize(reader);
|
||||
return await HandleStartVanish(sender);
|
||||
}
|
||||
|
||||
case RpcCalls.CheckAppear:
|
||||
{
|
||||
if (!await ValidateOwnership(call, sender) ||
|
||||
!await ValidateRole(call, sender, PlayerInfo, RoleTypes.Phantom) ||
|
||||
!await ValidateCmd(call, sender, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc64CheckAppear.Deserialize(reader, out var shouldAnimate);
|
||||
return await HandleCheckAppear(sender, shouldAnimate);
|
||||
}
|
||||
|
||||
case RpcCalls.StartAppear:
|
||||
{
|
||||
if (!await ValidateHost(call, sender) ||
|
||||
!await ValidateBroadcast(call, sender, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Rpc65StartAppear.Deserialize(reader, out var shouldAnimate);
|
||||
return await HandleStartAppear(sender, shouldAnimate);
|
||||
}
|
||||
|
||||
default:
|
||||
return await base.HandleRpcAsync(sender, target, call, reader);
|
||||
}
|
||||
@@ -587,6 +538,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
PlayerInfo.IsDead = true;
|
||||
PlayerInfo.LastDeathReason = reason;
|
||||
PlayerInfo.IsDirty = true;
|
||||
}
|
||||
|
||||
internal void Protect(InnerPlayerControl guardianAngel)
|
||||
@@ -611,6 +563,23 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask HandleSetInfected(ReadOnlyMemory<byte> infectedIds)
|
||||
{
|
||||
for (var i = 0; i < infectedIds.Length; i++)
|
||||
{
|
||||
var player = Game.GameNet.GameData!.GetPlayerById(infectedIds.Span[i]);
|
||||
if (player != null)
|
||||
{
|
||||
// player.IsImpostor = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Game.GameState == GameStates.Starting)
|
||||
{
|
||||
await Game.StartedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleCheckName(ClientPlayer sender, string name)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started)
|
||||
@@ -683,7 +652,6 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
if (RequestedPlayerName.Any())
|
||||
{
|
||||
var expected = RequestedPlayerName.Dequeue();
|
||||
var requested = expected;
|
||||
|
||||
if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == expected))
|
||||
{
|
||||
@@ -704,10 +672,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
if (name != expected)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(
|
||||
RpcCalls.SetName,
|
||||
CheatCategory.NameLimits,
|
||||
$"Client sent SetName with incorrect name, got '{name}', requested '{requested}', expected '{expected}'"))
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, CheatCategory.NameLimits, "Client sent SetName with incorrect name"))
|
||||
{
|
||||
await SetNameAsync(expected);
|
||||
return false;
|
||||
@@ -738,9 +703,9 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
if ((byte)color >= ColorsCount)
|
||||
if ((byte)color > ColorsCount)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.CheckColor, CheatCategory.ProtocolExtension, "Client sent unknown color"))
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.CheckColor, CheatCategory.ColorLimits, "Client sent invalid color"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -761,17 +726,9 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
if ((byte)color >= ColorsCount)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, CheatCategory.ProtocolExtension, "Client sent unknown color"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sender.IsOwner(this))
|
||||
{
|
||||
if (Game.IsColorUsed(color, this))
|
||||
if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.CurrentOutfit.Color == color))
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, CheatCategory.ColorLimits, "Client sent a color that is already used"))
|
||||
{
|
||||
@@ -783,56 +740,35 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
if (RequestedColorId.Any())
|
||||
{
|
||||
var requested = RequestedColorId.Dequeue();
|
||||
var expected = RequestedColorId.Dequeue();
|
||||
|
||||
if (Game.IsColorUsed(color, this))
|
||||
for (var colorOffset = 0; colorOffset <= ColorsCount; colorOffset++)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, CheatCategory.ColorLimits, "Client selected a color that is already used"))
|
||||
var possibleColor = (ColorType)((byte)(expected + colorOffset) % ColorsCount);
|
||||
if (!Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.CurrentOutfit.Color == possibleColor))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var startFrom = requested;
|
||||
|
||||
// Among Us wraps to the front if all colors between the requested and the final color are in use, check for this
|
||||
if (requested > color)
|
||||
{
|
||||
// Among Us wrapped, so check all colors between requested and the final color
|
||||
for (var c = requested; (byte)c < ColorsCount; c++)
|
||||
{
|
||||
if (!Game.IsColorUsed(c, this))
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(
|
||||
RpcCalls.SetColor,
|
||||
CheatCategory.ColorLimits,
|
||||
$"Client skipped color {c} that could be used, but wrapped instead. Player requested {requested} but was given {color}"))
|
||||
{
|
||||
await SetColorAsync(c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
expected = possibleColor;
|
||||
break;
|
||||
}
|
||||
|
||||
// Start checking from the first color, fallthrough to normal case
|
||||
startFrom = ColorType.Red;
|
||||
}
|
||||
|
||||
// Check all colors between the requested color and the assigned color
|
||||
for (var c = startFrom; c < color; c++)
|
||||
{
|
||||
if (!Game.IsColorUsed(c, this))
|
||||
if (colorOffset == ColorsCount)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(
|
||||
RpcCalls.SetColor,
|
||||
CheatCategory.ColorLimits,
|
||||
$"Client skipped color {c} that could be used. Player requested {requested} but was given {color}"))
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, CheatCategory.ColorLimits, "Client sent SetColor but all colors are already in use"))
|
||||
{
|
||||
await SetColorAsync(c);
|
||||
await SetColorAsync(expected);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (color != expected)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, CheatCategory.ColorLimits, "Client sent SetColor with incorrect color"))
|
||||
{
|
||||
await SetColorAsync(expected);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -848,71 +784,54 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetHat(ClientPlayer sender, string hat, byte nextRpcSequenceId)
|
||||
private async ValueTask<bool> HandleSetHat(ClientPlayer sender, string hat)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started &&
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetHatStr, CheatCategory.GameFlow, "Client tried to change hat while not in lobby"))
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetHat, CheatCategory.GameFlow, "Client tried to change hat while not in lobby"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.HatId = hat;
|
||||
PlayerInfo.CurrentOutfit.HatSequenceId = nextRpcSequenceId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetSkin(ClientPlayer sender, string skin, byte nextRpcSequenceId)
|
||||
private async ValueTask<bool> HandleSetSkin(ClientPlayer sender, string skin)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started &&
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetSkinStr, CheatCategory.GameFlow, "Client tried to change skin while not in lobby"))
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetSkin, CheatCategory.GameFlow, "Client tried to change skin while not in lobby"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.SkinId = skin;
|
||||
PlayerInfo.CurrentOutfit.SkinSequenceId = nextRpcSequenceId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetVisor(ClientPlayer sender, string visor, byte nextRpcSequenceId)
|
||||
private async ValueTask<bool> HandleSetVisor(ClientPlayer sender, string visor)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started &&
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetVisorStr, CheatCategory.GameFlow, "Client tried to change visor while not in lobby"))
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetVisor, CheatCategory.GameFlow, "Client tried to change visor while not in lobby"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.VisorId = visor;
|
||||
PlayerInfo.CurrentOutfit.VisorSequenceId = nextRpcSequenceId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetNamePlate(ClientPlayer sender, string namePlate, byte nextRpcSequenceId)
|
||||
private async ValueTask<bool> HandleSetNamePlate(ClientPlayer sender, string skin)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started &&
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetNamePlateStr, CheatCategory.GameFlow, "Client tried to change skin while not in lobby"))
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetNamePlate, CheatCategory.GameFlow, "Client tried to change skin while not in lobby"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.NamePlateId = namePlate;
|
||||
PlayerInfo.CurrentOutfit.NamePlateSequenceId = nextRpcSequenceId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetLevel(ClientPlayer sender, uint level)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started &&
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetLevel, CheatCategory.GameFlow, "Client tried to set level while not in game"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.PlayerLevel = level;
|
||||
PlayerInfo.CurrentOutfit.NamePlateId = skin;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1039,7 +958,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
if (!await ValidateRole(RpcCalls.ProtectPlayer, sender, PlayerInfo, RoleTypes.GuardianAngel))
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
((InnerPlayerControl)target).Protect(this);
|
||||
@@ -1061,16 +980,15 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
await _eventManager.CallAsync(new PlayerStartMeetingEvent(Game, Game.GetClientPlayer(this.OwnerId)!, this, deadPlayer));
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleSetPet(ClientPlayer sender, string pet, byte nextRpcSequenceId)
|
||||
private async ValueTask<bool> HandleSetPet(ClientPlayer sender, string pet)
|
||||
{
|
||||
if (Game.GameState == GameStates.Started &&
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetPetStr, CheatCategory.GameFlow, "Client tried to change pet while not in lobby"))
|
||||
await sender.Client.ReportCheatAsync(RpcCalls.SetPet, CheatCategory.GameFlow, "Client tried to change pet while not in lobby"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.PetId = pet;
|
||||
PlayerInfo.CurrentOutfit.PetSequenceId = nextRpcSequenceId;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1092,61 +1010,5 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleCheckVanish(ClientPlayer sender, float maxDuration)
|
||||
{
|
||||
// TODO: Check if operation is taking place during lobby/meetings
|
||||
// TODO: Check that the player unvanished before the maximum duration is reached
|
||||
// If the game is host authoritive, the RPC is handled by the host, otherwise by the server
|
||||
if (_game.IsHostAuthoritive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await StartVanishAsync();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleStartVanish(ClientPlayer sender)
|
||||
{
|
||||
if (!_game.IsHostAuthoritive)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.StartVanish, CheatCategory.GameFlow, "Client tried to send StartVanish directly"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleCheckAppear(ClientPlayer sender, bool shouldAnimate)
|
||||
{
|
||||
// If the game is host authoritive, the RPC is handled by the host, otherwise by the server
|
||||
if (_game.IsHostAuthoritive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await StartAppearAsync(shouldAnimate);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleStartAppear(ClientPlayer sender, bool shouldAnimate)
|
||||
{
|
||||
if (!_game.IsHostAuthoritive)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.StartAppear, CheatCategory.GameFlow, "Client tried to send StartAppear directly"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Innersloth.Customization;
|
||||
using Impostor.Api.Innersloth.GameOptions;
|
||||
using Impostor.Api.Net;
|
||||
using Impostor.Api.Net.Custom;
|
||||
using Impostor.Api.Net.Inner;
|
||||
using Impostor.Api.Net.Messages.Rpcs;
|
||||
using Impostor.Api.Utils;
|
||||
using Impostor.Server.Net.State;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -18,13 +15,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal partial class InnerPlayerInfo
|
||||
{
|
||||
private readonly IEventManager _eventManager;
|
||||
private readonly ILogger<InnerPlayerInfo> _logger;
|
||||
|
||||
public InnerPlayerInfo(ICustomMessageManager<ICustomRpc> customMessageManager, IEventManager eventManager, Game game, ILogger<InnerPlayerInfo> logger) : base(customMessageManager, game)
|
||||
public InnerPlayerInfo(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerPlayerInfo> logger) : base(customMessageManager, game)
|
||||
{
|
||||
Components.Add(this);
|
||||
_eventManager = eventManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -51,20 +46,26 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public bool Disconnected { get; internal set; }
|
||||
|
||||
public bool IsImpostor => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.ImpostorGhost or RoleTypes.Phantom;
|
||||
public bool IsImpostor => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.ImpostorGhost;
|
||||
|
||||
public bool CanVent => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Phantom or RoleTypes.Engineer;
|
||||
public bool CanVent => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Engineer;
|
||||
|
||||
public bool IsDead { get; internal set; }
|
||||
|
||||
public DeathReason LastDeathReason { get; internal set; }
|
||||
|
||||
public List<TaskInfo> Tasks { get; internal set; } = new List<TaskInfo>(0);
|
||||
public List<InnerGameData.TaskInfo> Tasks { get; internal set; } = new List<InnerGameData.TaskInfo>(0);
|
||||
|
||||
public DateTimeOffset LastMurder { get; set; }
|
||||
|
||||
public uint PlayerLevel { get; internal set; }
|
||||
|
||||
public override bool IsDirty
|
||||
{
|
||||
get => CurrentOutfit.IsDirty;
|
||||
internal set => CurrentOutfit.IsDirty = value;
|
||||
}
|
||||
|
||||
public bool CanMurder(IGame game, IDateTimeProvider dateTimeProvider)
|
||||
{
|
||||
if (!IsImpostor)
|
||||
@@ -181,80 +182,5 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
|
||||
{
|
||||
switch (call)
|
||||
{
|
||||
case RpcCalls.SetTasks:
|
||||
Rpc29SetTasks.Deserialize(reader, out var taskTypeIds);
|
||||
SetTasks(taskTypeIds);
|
||||
break;
|
||||
|
||||
default:
|
||||
return await base.HandleRpcAsync(sender, target, call, reader);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetTasks(ReadOnlyMemory<byte> taskTypeIds)
|
||||
{
|
||||
if (Disconnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Tasks = new List<TaskInfo>(taskTypeIds.Length);
|
||||
|
||||
var taskId = 0u;
|
||||
foreach (var taskTypeId in taskTypeIds.Span)
|
||||
{
|
||||
var mapTasks = Game.GameNet!.ShipStatus?.Data.Tasks;
|
||||
var taskType = (mapTasks != null && mapTasks.ContainsKey(taskTypeId)) ? mapTasks[taskTypeId] : null;
|
||||
Tasks.Add(new TaskInfo(this, _eventManager, taskId++, taskType));
|
||||
}
|
||||
}
|
||||
|
||||
public byte GetNextRpcSequenceId(RpcCalls rpc)
|
||||
{
|
||||
var defaultOutfit = this.Outfits[PlayerOutfitType.Default];
|
||||
|
||||
byte nextRpcSequenceId = 0;
|
||||
const byte SequenceIdAddition = 5;
|
||||
|
||||
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
|
||||
switch (rpc)
|
||||
{
|
||||
case RpcCalls.SetHatStr:
|
||||
defaultOutfit.HatSequenceId += SequenceIdAddition;
|
||||
nextRpcSequenceId = defaultOutfit.HatSequenceId;
|
||||
break;
|
||||
case RpcCalls.SetSkinStr:
|
||||
defaultOutfit.SkinSequenceId += SequenceIdAddition;
|
||||
nextRpcSequenceId = defaultOutfit.SkinSequenceId;
|
||||
break;
|
||||
case RpcCalls.SetPetStr:
|
||||
defaultOutfit.PetSequenceId += SequenceIdAddition;
|
||||
nextRpcSequenceId = defaultOutfit.PetSequenceId;
|
||||
break;
|
||||
case RpcCalls.SetVisorStr:
|
||||
defaultOutfit.VisorSequenceId += SequenceIdAddition;
|
||||
nextRpcSequenceId = defaultOutfit.VisorSequenceId;
|
||||
break;
|
||||
case RpcCalls.SetNamePlateStr:
|
||||
defaultOutfit.NamePlateSequenceId += SequenceIdAddition;
|
||||
nextRpcSequenceId = defaultOutfit.NamePlateSequenceId;
|
||||
break;
|
||||
default:
|
||||
_logger.LogError(
|
||||
"{NextRpcSequenceIdName} was called for an RPC it doesn\'t know how to handle: {Rpc}",
|
||||
nameof(GetNextRpcSequenceId),
|
||||
rpc);
|
||||
break;
|
||||
}
|
||||
|
||||
return nextRpcSequenceId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Innersloth.Maps;
|
||||
using Impostor.Api.Net.Inner;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
using Impostor.Api.Net.Messages.Rpcs;
|
||||
using Impostor.Server.Events.Player;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal class TaskInfo : ITaskInfo
|
||||
{
|
||||
private readonly InnerPlayerInfo _playerInfo;
|
||||
private readonly IEventManager _eventManager;
|
||||
|
||||
public TaskInfo(InnerPlayerInfo playerInfo, IEventManager eventManager, uint id, TaskData? task)
|
||||
{
|
||||
_playerInfo = playerInfo;
|
||||
_eventManager = eventManager;
|
||||
Id = id;
|
||||
Task = task;
|
||||
}
|
||||
|
||||
public uint Id { get; internal set; }
|
||||
|
||||
public TaskData? Task { 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)
|
||||
{
|
||||
Id = reader.ReadPackedUInt32();
|
||||
Complete = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
public async ValueTask CompleteAsync()
|
||||
{
|
||||
if (_playerInfo.Controller == null)
|
||||
{
|
||||
throw new ImpostorException("Can't complete a task that doesn't have a player assigned");
|
||||
}
|
||||
|
||||
var player = _playerInfo.Controller;
|
||||
|
||||
if (Complete)
|
||||
{
|
||||
throw new ImpostorException("Can't complete a task that is already completed");
|
||||
}
|
||||
|
||||
Complete = true;
|
||||
|
||||
// Send RPC.
|
||||
using var writer = player.Game.StartRpc(player.NetId, RpcCalls.CompleteTask);
|
||||
Rpc01CompleteTask.Serialize(writer, Id);
|
||||
await player.Game.FinishRpcAsync(writer);
|
||||
|
||||
// Notify plugins.
|
||||
await _eventManager.CallAsync(new PlayerCompletedTaskEvent(player.Game, player.Game.GetClientPlayer(player.OwnerId)!, player, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,6 @@ internal class CompatibilityManager : ICompatibilityManager
|
||||
{
|
||||
new GameVersion(2024, 3, 1), // 2024.6.18
|
||||
new GameVersion(2024, 4, 1), // 2024.8.13
|
||||
new GameVersion(2024, 4, 2), // 2024.9.4
|
||||
new GameVersion(2024, 8, 10), // 2024.10.29
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -261,10 +261,9 @@ namespace Impostor.Server.Net.State
|
||||
if (scene != "OnlineGame")
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Player {PlayerName} ({ClientId}) tried to send SceneChangeFlag with disallowed scene \"{Scene}\".",
|
||||
"Player {0} ({1}) tried to send SceneChangeFlag with disallowed scene.",
|
||||
sender.Client.Name,
|
||||
sender.Client.Id,
|
||||
scene);
|
||||
sender.Client.Id);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -327,6 +326,17 @@ namespace Impostor.Server.Net.State
|
||||
}
|
||||
}
|
||||
|
||||
// Check for dirty netobjects
|
||||
foreach (var netObject in _allObjectsFast.Values)
|
||||
{
|
||||
if (netObject.IsDirty && netObject.OwnerId == ServerOwned)
|
||||
{
|
||||
_logger.LogTrace("Sending over {Type} {NetId}", netObject.GetType().Name, netObject.NetId);
|
||||
await SendObjectData(netObject);
|
||||
netObject.IsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -392,6 +402,13 @@ namespace Impostor.Server.Net.State
|
||||
{
|
||||
playerInfo.Controller = control;
|
||||
control.PlayerInfo = playerInfo;
|
||||
|
||||
// Reset PlayerInfo
|
||||
playerInfo.RoleType = null;
|
||||
playerInfo.RoleWhenAlive = null;
|
||||
playerInfo.Tasks.Clear();
|
||||
playerInfo.IsDead = false;
|
||||
playerInfo.IsDirty = true;
|
||||
}
|
||||
|
||||
if (player != null)
|
||||
@@ -511,18 +528,6 @@ namespace Impostor.Server.Net.State
|
||||
await SendObjectSpawnAsync(playerInfo);
|
||||
}
|
||||
|
||||
private async ValueTask DespawnPlayerInfoAsync(InnerPlayerInfo playerInfo)
|
||||
{
|
||||
if (playerInfo.OwnerId == ServerOwned)
|
||||
{
|
||||
_logger.LogDebug("Despawning PlayerInfo {nid}", playerInfo.NetId);
|
||||
GameNet.GameData.RemovePlayer(playerInfo.PlayerId);
|
||||
RemoveNetObject(playerInfo);
|
||||
|
||||
await SendObjectDespawnAsync(playerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private bool AddNetObject(InnerNetObject obj)
|
||||
{
|
||||
if (_allObjectsFast.ContainsKey(obj.NetId))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Games;
|
||||
@@ -44,12 +43,6 @@ namespace Impostor.Server.Net.State
|
||||
player.Value.Limbo = LimboStates.PreSpawn;
|
||||
}
|
||||
|
||||
// Delete all PlayerInfo objects
|
||||
foreach (var playerInfo in GameNet.GameData.Players.Values.ToArray())
|
||||
{
|
||||
await DespawnPlayerInfoAsync(playerInfo);
|
||||
}
|
||||
|
||||
await _eventManager.CallAsync(new GameEndedEvent(this, gameOverReason));
|
||||
}
|
||||
|
||||
|
||||
@@ -135,12 +135,22 @@ namespace Impostor.Server.Net.State
|
||||
await FinishGameDataAsync(writer, targetClientId);
|
||||
}
|
||||
|
||||
private async ValueTask SendObjectDespawnAsync(InnerNetObject obj, int? targetClientId = null)
|
||||
private ValueTask SendObjectDespawn(InnerNetObject obj, int? targetClientId = null)
|
||||
{
|
||||
using var writer = StartGameData(targetClientId);
|
||||
writer.StartMessage(GameDataTag.DespawnFlag);
|
||||
writer.WritePacked(obj.NetId);
|
||||
writer.EndMessage();
|
||||
return FinishGameDataAsync(writer, targetClientId);
|
||||
}
|
||||
|
||||
private async ValueTask SendObjectData(InnerNetObject obj, int? targetClientId = null)
|
||||
{
|
||||
using var writer = StartGameData(targetClientId);
|
||||
writer.StartMessage(GameDataTag.DataFlag);
|
||||
writer.WritePacked(obj.NetId);
|
||||
await obj.SerializeAsync(writer, false);
|
||||
writer.EndMessage();
|
||||
await FinishGameDataAsync(writer, targetClientId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,21 @@ namespace Impostor.Server.Net.State
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up the PlayerInfo if we own it and we're still in the lobby
|
||||
if (GameState == GameStates.NotStarted)
|
||||
// Clean up the PlayerInfo if we own it
|
||||
foreach (var playerInfo in GameNet.GameData.Players.Values)
|
||||
{
|
||||
if (GameNet.GameData.PlayersByClientId.TryGetValue(playerId, out var playerInfo))
|
||||
if (playerInfo.ClientId == playerId)
|
||||
{
|
||||
await DespawnPlayerInfoAsync(playerInfo);
|
||||
if (playerInfo.OwnerId == ServerOwned)
|
||||
{
|
||||
_logger.LogInformation("Destroying PlayerInfo {nid}", playerInfo.NetId);
|
||||
GameNet.GameData.RemovePlayer(playerInfo.PlayerId);
|
||||
RemoveNetObject(playerInfo);
|
||||
|
||||
await SendObjectDespawn(playerInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,8 @@ using Impostor.Api.Config;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Innersloth;
|
||||
using Impostor.Api.Innersloth.Customization;
|
||||
using Impostor.Api.Innersloth.GameOptions;
|
||||
using Impostor.Api.Net;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
using Impostor.Api.Net.Manager;
|
||||
using Impostor.Api.Net.Messages.S2C;
|
||||
using Impostor.Server.Events;
|
||||
@@ -133,15 +131,6 @@ namespace Impostor.Server.Net.State
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Check if there are players using a color.</summary>
|
||||
/// <param name="color">The color to check for.</param>
|
||||
/// <param name="exceptBy">Exempt a player from being checked.</param>
|
||||
/// <returns>True if there is player other than exceptBy that uses that color.</returns>
|
||||
internal bool IsColorUsed(ColorType color, IInnerPlayerControl? exceptBy = null)
|
||||
{
|
||||
return Players.Any(p => p.Character != null && p.Character != exceptBy && p.Character.PlayerInfo.CurrentOutfit.Color == color);
|
||||
}
|
||||
|
||||
private ValueTask BroadcastJoinMessage(IMessageWriter message, bool clear, ClientPlayer player)
|
||||
{
|
||||
Message01JoinGameS2C.SerializeJoin(message, clear, Code, player, HostId);
|
||||
|
||||
Reference in new issue
Block a user