mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-20 01:46:11 +00:00
Remove AllowNull from PlayerControl.PlayerInfo
It is possible to spawn invalid network objects without an attached PlayerInfo, and Impostor will throw exceptions everywhere if you happen to spawn one. Officials do allow spawning objects like this, so allow it in Impostor for compatibility reasons
This commit is contained in:
1 parent
fff9713697
commit
e1bd85313a
8 files changed
+250
-49
No files matched your search
@@ -29,7 +29,7 @@ namespace Impostor.Api.Net.Inner.Objects
|
||||
/// Gets the <see cref="IInnerPlayerInfo" /> of the <see cref="IInnerPlayerControl" />.
|
||||
/// Contains metadata about the player.
|
||||
/// </summary>
|
||||
IInnerPlayerInfo PlayerInfo { get; }
|
||||
IInnerPlayerInfo? PlayerInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name of the current <see cref="IInnerPlayerControl" />.
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Impostor.Api.Net.Messages.S2C
|
||||
writer.Write(hostId);
|
||||
writer.Write(player.Client.Name);
|
||||
player.Client.PlatformSpecificData.Serialize(writer);
|
||||
writer.WritePacked(player.Character?.PlayerInfo.PlayerLevel ?? 1);
|
||||
writer.WritePacked(player.Character?.PlayerInfo?.PlayerLevel ?? 1);
|
||||
|
||||
// ProductUserId and FriendCode are not yet known, so set them to an empty string
|
||||
writer.Write(string.Empty);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Impostor.Api.Net.Messages.S2C
|
||||
writer.WritePacked(ply.Client.Id);
|
||||
writer.Write(ply.Client.Name);
|
||||
ply.Client.PlatformSpecificData.Serialize(writer);
|
||||
writer.WritePacked(ply.Character?.PlayerInfo.PlayerLevel ?? 1);
|
||||
writer.WritePacked(ply.Character?.PlayerInfo?.PlayerLevel ?? 1);
|
||||
|
||||
// ProductUserId and FriendCode are not yet known, so set them to an empty string
|
||||
writer.Write(string.Empty);
|
||||
|
||||
@@ -73,9 +73,16 @@ namespace Impostor.Server.Net.Inner
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async ValueTask<bool> ValidateImpostor(CheatContext context, IClientPlayer sender, InnerPlayerInfo playerInfo, bool value = true)
|
||||
protected async ValueTask<bool> ValidateImpostor(CheatContext context, IClientPlayer sender, InnerPlayerInfo? playerInfo, bool value = true)
|
||||
{
|
||||
if (playerInfo.IsImpostor != value)
|
||||
if (playerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, CheatCategory.InvalidObject, "Couldn't check if Impostor, playerInfo not set"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (playerInfo.IsImpostor != value)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, CheatCategory.Role, "Failed impostor check"))
|
||||
{
|
||||
@@ -86,9 +93,16 @@ namespace Impostor.Server.Net.Inner
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async ValueTask<bool> ValidateCanVent(CheatContext context, IClientPlayer sender, InnerPlayerInfo playerInfo, bool value = true)
|
||||
protected async ValueTask<bool> ValidateCanVent(CheatContext context, IClientPlayer sender, InnerPlayerInfo? playerInfo, bool value = true)
|
||||
{
|
||||
if (playerInfo.CanVent != value)
|
||||
if (playerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, CheatCategory.InvalidObject, "Couldn't check if can vent, playerInfo not set"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (playerInfo.CanVent != value)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, CheatCategory.Role, "Failed can vent check"))
|
||||
{
|
||||
@@ -99,9 +113,16 @@ namespace Impostor.Server.Net.Inner
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async ValueTask<bool> ValidateRole(CheatContext context, IClientPlayer sender, InnerPlayerInfo playerInfo, RoleTypes role)
|
||||
protected async ValueTask<bool> ValidateRole(CheatContext context, IClientPlayer sender, InnerPlayerInfo? playerInfo, RoleTypes role)
|
||||
{
|
||||
if (playerInfo.RoleType != role)
|
||||
if (playerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, CheatCategory.InvalidObject, "Couldn't check role, playerInfo not set"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (playerInfo.RoleType != role)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(context, CheatCategory.Role, $"Failed role = {role} check"))
|
||||
{
|
||||
|
||||
@@ -287,7 +287,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
var max = MaxPair(self, out var tie);
|
||||
var exiled = tie ? null : Game.GameNet.GameData!.GetPlayerById(max.Key)?.Controller;
|
||||
|
||||
if (exiled != null)
|
||||
if (exiled != null && exiled.PlayerInfo != null)
|
||||
{
|
||||
exiled.PlayerInfo.LastDeathReason = DeathReason.Exile;
|
||||
await _eventManager.CallAsync(new PlayerExileEvent(Game, Game.GetClientPlayer(exiled!.OwnerId)!, exiled));
|
||||
|
||||
@@ -17,10 +17,15 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
IInnerCustomNetworkTransform IInnerPlayerControl.NetworkTransform => NetworkTransform;
|
||||
|
||||
IInnerPlayerInfo IInnerPlayerControl.PlayerInfo => PlayerInfo;
|
||||
IInnerPlayerInfo? IInnerPlayerControl.PlayerInfo => PlayerInfo;
|
||||
|
||||
public async ValueTask SetNameAsync(string name)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set name, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.PlayerName = name;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetName);
|
||||
@@ -30,6 +35,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask SetColorAsync(ColorType color)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set color, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.Color = color;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetColor);
|
||||
@@ -39,6 +49,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask SetHatAsync(string hatId)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set hat, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.HatId = hatId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetHatStr);
|
||||
@@ -48,6 +63,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask SetPetAsync(string petId)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set pet, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.PetId = petId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetPetStr);
|
||||
@@ -57,6 +77,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask SetSkinAsync(string skinId)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set skin, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.SkinId = skinId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetSkinStr);
|
||||
@@ -66,6 +91,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask SetVisorAsync(string visorId)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set visor, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.VisorId = visorId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetVisorStr);
|
||||
@@ -75,6 +105,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask SetNamePlateAsync(string nameplateId)
|
||||
{
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Cannot set nameplate, PlayerInfo is null");
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.NamePlateId = nameplateId;
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.SetNamePlateStr);
|
||||
@@ -103,7 +138,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
private bool ValidateMurderPlayer(IInnerPlayerControl target, MurderResultFlags result, [NotNullWhen(false)] out string? invalidReason)
|
||||
{
|
||||
if (!PlayerInfo.IsImpostor)
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
invalidReason = "Tried to murder a player, but the murderer didn't have a playerinfo";
|
||||
}
|
||||
else if (!PlayerInfo.IsImpostor)
|
||||
{
|
||||
invalidReason = "Tried to murder a player, but murderer was not an impostor.";
|
||||
}
|
||||
@@ -111,6 +150,10 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
invalidReason = "Tried to murder a player, but murderer was not alive.";
|
||||
}
|
||||
else if (target.PlayerInfo == null)
|
||||
{
|
||||
invalidReason = "Tried to murder a player, but the murderer didn't have a playerinfo";
|
||||
}
|
||||
else if (target.PlayerInfo.IsImpostor)
|
||||
{
|
||||
invalidReason = "Tried to murder a player, but target is an impostor";
|
||||
@@ -159,7 +202,11 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public async ValueTask ProtectPlayerAsync(IInnerPlayerControl target)
|
||||
{
|
||||
if (target.PlayerInfo.IsDead)
|
||||
if (target.PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Tried to exile a player, but target didn't have a playerinfo");
|
||||
}
|
||||
else if (target.PlayerInfo.IsDead)
|
||||
{
|
||||
throw new ImpostorProtocolException("Tried to protect a player that is dead");
|
||||
}
|
||||
@@ -172,13 +219,17 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
((InnerPlayerControl)target).Protect(this);
|
||||
|
||||
using var writer = Game.StartRpc(NetId, RpcCalls.ProtectPlayer);
|
||||
Rpc45ProtectPlayer.Serialize(writer, target, PlayerInfo.CurrentOutfit.Color);
|
||||
Rpc45ProtectPlayer.Serialize(writer, target, PlayerInfo?.CurrentOutfit.Color ?? ColorType.Red);
|
||||
await Game.FinishRpcAsync(writer);
|
||||
}
|
||||
|
||||
public async ValueTask ExileAsync()
|
||||
{
|
||||
if (PlayerInfo.IsDead)
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
throw new ImpostorProtocolException("Tried to exile a player, but target didn't have a playerinfo");
|
||||
}
|
||||
else if (PlayerInfo.IsDead)
|
||||
{
|
||||
throw new ImpostorProtocolException("Tried to exile a player, but target was not alive.");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api;
|
||||
@@ -57,8 +56,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public InnerCustomNetworkTransform NetworkTransform { get; }
|
||||
|
||||
[AllowNull]
|
||||
public InnerPlayerInfo PlayerInfo { get; internal set; }
|
||||
public InnerPlayerInfo? PlayerInfo { get; internal set; }
|
||||
|
||||
internal Queue<string> RequestedPlayerName { get; } = new Queue<string>();
|
||||
|
||||
@@ -385,15 +383,25 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
Rpc44SetRole.Deserialize(reader, out var role, out var _);
|
||||
|
||||
if (role is RoleTypes.ImpostorGhost or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel)
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
PlayerInfo.RoleWhenAlive = PlayerInfo.RoleType;
|
||||
PlayerInfo.IsDead = true;
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetRole, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (role is RoleTypes.ImpostorGhost or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel)
|
||||
{
|
||||
PlayerInfo.RoleWhenAlive = PlayerInfo.RoleType;
|
||||
PlayerInfo.IsDead = true;
|
||||
}
|
||||
|
||||
PlayerInfo.RoleType = role;
|
||||
}
|
||||
|
||||
PlayerInfo.RoleType = role;
|
||||
|
||||
if (Game.GameState == GameStates.Starting && Game.Players.All(clientPlayer => clientPlayer.Character?.PlayerInfo.RoleType != null))
|
||||
if (Game.GameState == GameStates.Starting && Game.Players.All(clientPlayer => clientPlayer.Character?.PlayerInfo?.RoleType != null))
|
||||
{
|
||||
await Game.StartedAsync();
|
||||
}
|
||||
@@ -585,8 +593,19 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
internal void Die(DeathReason reason)
|
||||
{
|
||||
PlayerInfo.IsDead = true;
|
||||
PlayerInfo.LastDeathReason = reason;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
// "Custom Net Objects" aka hacked up PlayerControl objects as popularized by host only mods may trigger this
|
||||
if (!Game.IsHostAuthoritive)
|
||||
{
|
||||
_logger.LogWarning("Tried to kill player that didn't have a PlayerInfo set, this shouldn't happen");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.IsDead = true;
|
||||
PlayerInfo.LastDeathReason = reason;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Protect(InnerPlayerControl guardianAngel)
|
||||
@@ -598,7 +617,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
private async ValueTask HandleCompleteTask(ClientPlayer sender, uint taskId)
|
||||
{
|
||||
var task = PlayerInfo.Tasks.ElementAtOrDefault((int)taskId);
|
||||
TaskInfo? task = null;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.CompleteTask, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
task = PlayerInfo.Tasks.ElementAtOrDefault((int)taskId);
|
||||
}
|
||||
|
||||
if (task != null)
|
||||
{
|
||||
@@ -662,7 +692,10 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
if (sender.IsOwner(this))
|
||||
{
|
||||
if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == name))
|
||||
if (Game.Players.Any(x => x.Character != null &&
|
||||
x.Character != this &&
|
||||
x.Character.PlayerInfo != null &&
|
||||
x.Character.PlayerInfo.PlayerName == name))
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, CheatCategory.NameLimits, "Client sent name that is already used"))
|
||||
{
|
||||
@@ -685,14 +718,20 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
var expected = RequestedPlayerName.Dequeue();
|
||||
var requested = expected;
|
||||
|
||||
if (Game.Players.Any(x => x.Character != null && x.Character != this && x.Character.PlayerInfo.PlayerName == expected))
|
||||
if (Game.Players.Any(x => x.Character != null &&
|
||||
x.Character != this &&
|
||||
x.Character.PlayerInfo != null &&
|
||||
x.Character.PlayerInfo.PlayerName == expected))
|
||||
{
|
||||
var i = 1;
|
||||
while (true)
|
||||
{
|
||||
var text = expected + " " + i;
|
||||
|
||||
if (Game.Players.All(x => x.Character == null || x.Character == this || x.Character.PlayerInfo.PlayerName != text))
|
||||
if (Game.Players.All(x => x.Character == null ||
|
||||
x.Character == this ||
|
||||
x.Character.PlayerInfo == null ||
|
||||
x.Character.PlayerInfo.PlayerName != text))
|
||||
{
|
||||
expected = text;
|
||||
break;
|
||||
@@ -723,7 +762,17 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.PlayerName = name;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetName, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.PlayerName = name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -843,7 +892,17 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.Color = color;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetColor, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.Color = color;
|
||||
}
|
||||
|
||||
// Record the color so it can be restored on the next game
|
||||
if (Game.TryGetPlayer(OwnerId, out var clientPlayer))
|
||||
@@ -866,8 +925,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.HatId = hat;
|
||||
PlayerInfo.CurrentOutfit.HatSequenceId = nextRpcSequenceId;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetHatStr, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.HatId = hat;
|
||||
PlayerInfo.CurrentOutfit.HatSequenceId = nextRpcSequenceId;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -880,8 +949,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.SkinId = skin;
|
||||
PlayerInfo.CurrentOutfit.SkinSequenceId = nextRpcSequenceId;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetSkinStr, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.SkinId = skin;
|
||||
PlayerInfo.CurrentOutfit.SkinSequenceId = nextRpcSequenceId;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -894,8 +973,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.VisorId = visor;
|
||||
PlayerInfo.CurrentOutfit.VisorSequenceId = nextRpcSequenceId;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetVisorStr, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.VisorId = visor;
|
||||
PlayerInfo.CurrentOutfit.VisorSequenceId = nextRpcSequenceId;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -908,8 +997,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.NamePlateId = namePlate;
|
||||
PlayerInfo.CurrentOutfit.NamePlateSequenceId = nextRpcSequenceId;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetNamePlateStr, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.NamePlateId = namePlate;
|
||||
PlayerInfo.CurrentOutfit.NamePlateSequenceId = nextRpcSequenceId;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -922,14 +1021,31 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.PlayerLevel = level;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetLevel, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.PlayerLevel = level;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async ValueTask<bool> HandleCheckMurder(ClientPlayer sender, InnerPlayerControl? target)
|
||||
{
|
||||
if (!PlayerInfo.CanMurder(Game, _dateTimeProvider))
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.CheckMurder, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!PlayerInfo.CanMurder(Game, _dateTimeProvider))
|
||||
{
|
||||
if (IsMurdering == target)
|
||||
{
|
||||
@@ -944,10 +1060,10 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo.LastMurder = _dateTimeProvider.UtcNow - TimeSpan.FromMilliseconds(sender.Client.Connection.AveragePing);
|
||||
IsMurdering = target;
|
||||
PlayerInfo.LastMurder = _dateTimeProvider.UtcNow - TimeSpan.FromMilliseconds(sender.Client.Connection.AveragePing);
|
||||
IsMurdering = target;
|
||||
}
|
||||
|
||||
// Check if host authority mode is on
|
||||
if (_game.IsHostAuthoritive)
|
||||
@@ -1017,7 +1133,7 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
if (target != null && !target.PlayerInfo.IsDead)
|
||||
if (target != null && target.PlayerInfo != null && !target.PlayerInfo.IsDead)
|
||||
{
|
||||
// In host authoritive mode every client has to figure out if the kill was prevented by guardian protection on it's own
|
||||
if ((result & MurderResultFlags.Succeeded) != 0 && target.IsProtected)
|
||||
@@ -1086,8 +1202,18 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo.CurrentOutfit.PetId = pet;
|
||||
PlayerInfo.CurrentOutfit.PetSequenceId = nextRpcSequenceId;
|
||||
if (PlayerInfo == null)
|
||||
{
|
||||
if (await sender.Client.ReportCheatAsync(RpcCalls.SetPetStr, CheatCategory.InvalidObject, "PlayerControl doesn't have PlayerInfo"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInfo.CurrentOutfit.PetId = pet;
|
||||
PlayerInfo.CurrentOutfit.PetSequenceId = nextRpcSequenceId;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,10 @@ namespace Impostor.Server.Net.State
|
||||
/// <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);
|
||||
return Players.Any(p => p.Character != null &&
|
||||
p.Character != exceptBy &&
|
||||
p.Character.PlayerInfo != null &&
|
||||
p.Character.PlayerInfo.CurrentOutfit.Color == color);
|
||||
}
|
||||
|
||||
private ValueTask BroadcastJoinMessage(IMessageWriter message, bool clear, ClientPlayer player)
|
||||
|
||||
Reference in new issue
Block a user