mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-19 15:51:42 +00:00
Demote InnerGameData, promote InnerPlayerInfo
In 2024.6.18 Innersloth promoted PlayerInfo to its own network object, and gave it to the server. InnerGameData is now a container that holds these players. This commit implements the changes necessary to handle these separate PlayerInfo network objects.
This commit is contained in:
1 parent
615469c6c8
commit
c43fdd2a69
7 files changed
+106
-142
No files matched your search
@@ -1,6 +1,6 @@
|
||||
namespace Impostor.Api.Net.Inner.Objects
|
||||
{
|
||||
public interface IInnerGameData : IInnerNetObject
|
||||
public interface IInnerGameData
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api;
|
||||
using Impostor.Api.Events.Managers;
|
||||
using Impostor.Api.Net;
|
||||
using Impostor.Api.Net.Custom;
|
||||
using Impostor.Api.Net.Inner;
|
||||
using Impostor.Api.Net.Inner.Objects;
|
||||
using Impostor.Api.Net.Messages.Rpcs;
|
||||
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
|
||||
internal partial class InnerGameData : IInnerGameData
|
||||
{
|
||||
private readonly ILogger<InnerGameData> _logger;
|
||||
private readonly IEventManager _eventManager;
|
||||
private readonly ConcurrentDictionary<byte, InnerPlayerInfo> _allPlayers;
|
||||
|
||||
public InnerGameData(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerGameData> logger, IEventManager eventManager, IServiceProvider serviceProvider) : base(customMessageManager, game)
|
||||
{
|
||||
_logger = logger;
|
||||
_eventManager = eventManager;
|
||||
_allPlayers = new ConcurrentDictionary<byte, InnerPlayerInfo>();
|
||||
|
||||
Components.Add(this);
|
||||
Components.Add(ActivatorUtilities.CreateInstance<InnerVoteBanSystem>(serviceProvider, game));
|
||||
}
|
||||
private readonly ConcurrentDictionary<byte, InnerPlayerInfo> _allPlayers = new();
|
||||
|
||||
public int PlayerCount => _allPlayers.Count;
|
||||
|
||||
@@ -46,103 +22,14 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
return _allPlayers.TryGetValue(id, out var player) ? player : null;
|
||||
}
|
||||
|
||||
public override ValueTask<bool> SerializeAsync(IMessageWriter writer, bool initialState)
|
||||
internal bool AddPlayer(InnerPlayerInfo playerInfo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return _allPlayers.TryAdd(playerInfo.PlayerId, playerInfo);
|
||||
}
|
||||
|
||||
public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
|
||||
internal void RemovePlayer(byte playerId)
|
||||
{
|
||||
if (!await ValidateHost(CheatContext.Deserialize, sender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
var inner = reader.ReadMessage();
|
||||
var playerInfo = this.GetPlayerById(inner.Tag);
|
||||
if (playerInfo != null)
|
||||
{
|
||||
playerInfo.Deserialize(inner);
|
||||
}
|
||||
else
|
||||
{
|
||||
playerInfo = new InnerPlayerInfo(inner.Tag);
|
||||
playerInfo.Deserialize(inner);
|
||||
|
||||
if (!_allPlayers.TryAdd(playerInfo.PlayerId, playerInfo))
|
||||
{
|
||||
throw new ImpostorException("Failed to add player to InnerGameData.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
|
||||
{
|
||||
if (!await ValidateHost(call, sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (call)
|
||||
{
|
||||
case RpcCalls.SetTasks:
|
||||
{
|
||||
Rpc29SetTasks.Deserialize(reader, out var playerId, out var taskTypeIds);
|
||||
SetTasks(playerId, taskTypeIds);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return await base.HandleRpcAsync(sender, target, call, reader);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal InnerPlayerInfo? AddPlayer(InnerPlayerControl control)
|
||||
{
|
||||
var playerId = control.PlayerId;
|
||||
var playerInfo = new InnerPlayerInfo(control.PlayerId);
|
||||
|
||||
if (_allPlayers.TryAdd(playerId, playerInfo))
|
||||
{
|
||||
return playerInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void RemovePlayer(InnerPlayerControl control)
|
||||
{
|
||||
_allPlayers.TryRemove(control.PlayerInfo.PlayerId, out _);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
player.Tasks.Add(new TaskInfo(player, _eventManager, taskId++, taskType));
|
||||
}
|
||||
_allPlayers.TryRemove(playerId, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using Impostor.Api.Net.Inner.Objects;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal partial class InnerPlayerInfo : IInnerPlayerInfo
|
||||
internal partial class InnerPlayerInfo : InnerNetObject, IInnerPlayerInfo
|
||||
{
|
||||
IEnumerable<ITaskInfo> IInnerPlayerInfo.Tasks => Tasks;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
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.Utils;
|
||||
using Impostor.Server.Net.State;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
internal partial class InnerPlayerInfo
|
||||
{
|
||||
public InnerPlayerInfo(byte playerId)
|
||||
private readonly ILogger<InnerPlayerInfo> _logger;
|
||||
|
||||
public InnerPlayerInfo(ICustomMessageManager<ICustomRpc> customMessageManager, Game game, ILogger<InnerPlayerInfo> logger) : base(customMessageManager, game)
|
||||
{
|
||||
PlayerId = playerId;
|
||||
Components.Add(this);
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public InnerPlayerControl? Controller { get; internal set; }
|
||||
|
||||
public byte PlayerId { get; }
|
||||
public byte PlayerId { get; internal set; }
|
||||
|
||||
public int ClientId { get; internal set; }
|
||||
|
||||
public string PlayerName { get; internal set; } = string.Empty;
|
||||
|
||||
@@ -32,6 +42,8 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
|
||||
public RoleTypes? RoleType { get; internal set; }
|
||||
|
||||
public RoleTypes? RoleWhenAlive { get; internal set; }
|
||||
|
||||
public bool Disconnected { get; internal set; }
|
||||
|
||||
public bool IsImpostor => RoleType is RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.ImpostorGhost;
|
||||
@@ -71,13 +83,56 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(IMessageWriter writer)
|
||||
public override ValueTask<bool> SerializeAsync(IMessageWriter writer, bool initialState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
writer.Write(PlayerId);
|
||||
writer.WritePacked(ClientId);
|
||||
|
||||
writer.Write((byte)Outfits.Count);
|
||||
foreach (var outfit in Outfits)
|
||||
{
|
||||
writer.Write((byte)outfit.Key);
|
||||
outfit.Value.Serialize(writer);
|
||||
}
|
||||
|
||||
writer.WritePacked(PlayerLevel);
|
||||
|
||||
var flag = 0;
|
||||
if (Disconnected)
|
||||
{
|
||||
flag = (byte)(flag | 1u);
|
||||
}
|
||||
|
||||
if (IsDead)
|
||||
{
|
||||
flag = (byte)(flag | 4u);
|
||||
}
|
||||
|
||||
writer.Write((byte)flag);
|
||||
|
||||
writer.Write((ushort)(RoleType ?? 0));
|
||||
writer.Write(RoleWhenAlive.HasValue);
|
||||
if (RoleWhenAlive.HasValue)
|
||||
{
|
||||
writer.Write((ushort)RoleWhenAlive.Value);
|
||||
}
|
||||
|
||||
writer.Write((byte)Tasks.Count);
|
||||
for (var i = 0; i < Tasks.Count; i++)
|
||||
{
|
||||
Tasks[i].Serialize(writer);
|
||||
}
|
||||
|
||||
writer.Write(string.Empty); // FriendCode
|
||||
writer.Write(string.Empty); // PUID
|
||||
return new ValueTask<bool>(true);
|
||||
}
|
||||
|
||||
public void Deserialize(IMessageReader reader)
|
||||
public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
|
||||
{
|
||||
PlayerId = reader.ReadByte();
|
||||
ClientId = reader.ReadPackedInt32();
|
||||
|
||||
Outfits.Clear();
|
||||
var b = reader.ReadByte();
|
||||
for (var i = 0; i < b; i++)
|
||||
@@ -93,7 +148,15 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
Disconnected = (flag & 1) != 0;
|
||||
IsDead = (flag & 4) != 0;
|
||||
|
||||
_ = (RoleTypes)reader.ReadUInt16(); // ignore the RoleType here and only trust the SetRole rpc
|
||||
// Ignore the RoleType here and only trust the SetRole RPC, as
|
||||
// RoleType is not nullable in vanilla, while Impostor checks game
|
||||
// starts based on assigned roles.
|
||||
_ = (RoleTypes)reader.ReadUInt16();
|
||||
|
||||
if (reader.ReadBoolean())
|
||||
{
|
||||
RoleWhenAlive = (RoleTypes)reader.ReadUInt16();
|
||||
}
|
||||
|
||||
var taskCount = reader.ReadByte();
|
||||
|
||||
@@ -106,6 +169,12 @@ namespace Impostor.Server.Net.Inner.Objects
|
||||
{
|
||||
Tasks[i].Deserialize(reader);
|
||||
}
|
||||
|
||||
// Impostor doesn't expose fields that aren't properly validated
|
||||
reader.ReadString(); // FriendCode
|
||||
reader.ReadString(); // PUID
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ namespace Impostor.Server.Net.State
|
||||
[0] = typeof(InnerSkeldShipStatus),
|
||||
[1] = typeof(InnerMeetingHud),
|
||||
[2] = typeof(InnerLobbyBehaviour),
|
||||
[3] = typeof(InnerGameData),
|
||||
[4] = typeof(InnerPlayerControl),
|
||||
[5] = typeof(InnerMiraShipStatus),
|
||||
[6] = typeof(InnerPolusShipStatus),
|
||||
@@ -43,6 +42,8 @@ namespace Impostor.Server.Net.State
|
||||
[8] = typeof(InnerAirshipStatus),
|
||||
[9] = typeof(InnerHideAndSeekManager),
|
||||
[10] = typeof(InnerNormalGameManager),
|
||||
[11] = typeof(InnerPlayerInfo),
|
||||
[12] = typeof(InnerVoteBanSystem),
|
||||
[13] = typeof(InnerFungleShipStatus),
|
||||
};
|
||||
|
||||
@@ -326,9 +327,17 @@ namespace Impostor.Server.Net.State
|
||||
break;
|
||||
}
|
||||
|
||||
case InnerGameData data:
|
||||
case InnerPlayerInfo playerInfo:
|
||||
{
|
||||
GameNet.GameData = data;
|
||||
if (!GameNet.GameData.AddPlayer(playerInfo))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Could not add PlayerInfo for playerId {PlayerId} with NetId {newId}, already have NetId {oldNetId}",
|
||||
playerInfo.PlayerId,
|
||||
playerInfo.NetId,
|
||||
GameNet.GameData.GetPlayerById(playerInfo.PlayerId)?.NetId);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -358,7 +367,7 @@ namespace Impostor.Server.Net.State
|
||||
}
|
||||
|
||||
// Hook up InnerPlayerControl <-> InnerPlayerControl.PlayerInfo.
|
||||
var playerInfo = GameNet.GameData!.GetPlayerById(control.PlayerId) ?? GameNet.GameData.AddPlayer(control);
|
||||
var playerInfo = GameNet.GameData.GetPlayerById(control.PlayerId);
|
||||
|
||||
if (playerInfo != null)
|
||||
{
|
||||
@@ -402,12 +411,6 @@ namespace Impostor.Server.Net.State
|
||||
break;
|
||||
}
|
||||
|
||||
case InnerGameData:
|
||||
{
|
||||
GameNet.GameData = null;
|
||||
break;
|
||||
}
|
||||
|
||||
case InnerVoteBanSystem:
|
||||
{
|
||||
GameNet.VoteBan = null;
|
||||
@@ -420,13 +423,18 @@ namespace Impostor.Server.Net.State
|
||||
break;
|
||||
}
|
||||
|
||||
case InnerPlayerControl control:
|
||||
case InnerPlayerInfo playerInfo:
|
||||
{
|
||||
if (GameState != GameStates.Started && GameState != GameStates.Starting)
|
||||
{
|
||||
GameNet.GameData?.RemovePlayer(control);
|
||||
GameNet.GameData.RemovePlayer(playerInfo.PlayerId);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case InnerPlayerControl control:
|
||||
{
|
||||
// Remove InnerPlayerControl <-> IClientPlayer.
|
||||
if (TryGetPlayer(control.OwnerId, out var player))
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Impostor.Server.Net.State
|
||||
|
||||
IInnerLobbyBehaviour? IGameNet.LobbyBehaviour => LobbyBehaviour;
|
||||
|
||||
IInnerGameData? IGameNet.GameData => GameData;
|
||||
IInnerGameData IGameNet.GameData => GameData;
|
||||
|
||||
IInnerVoteBanSystem? IGameNet.VoteBan => VoteBan;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Impostor.Server.Net.State
|
||||
|
||||
public InnerLobbyBehaviour? LobbyBehaviour { get; internal set; }
|
||||
|
||||
public InnerGameData? GameData { get; internal set; }
|
||||
public InnerGameData GameData { get; internal set; } = new();
|
||||
|
||||
public InnerVoteBanSystem? VoteBan { get; internal set; }
|
||||
|
||||
|
||||
Reference in new issue
Block a user