mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-20 01:46:11 +00:00
Finish up PlayerControl RPCs
This commit is contained in:
1 parent
35792a1641
commit
1b776bfce9
15 files changed
+344
-21
No files matched your search
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Impostor.Api
|
||||
{
|
||||
public class ImpostorCheatException : ImpostorException
|
||||
{
|
||||
public ImpostorCheatException()
|
||||
{
|
||||
}
|
||||
|
||||
protected ImpostorCheatException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ImpostorCheatException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ImpostorCheatException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
<CodeAnalysisRuleSet>ProjectRules.ruleset</CodeAnalysisRuleSet>
|
||||
<LangVersion>9</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Impostor.Api.Innersloth.Data
|
||||
{
|
||||
public enum ChatNoteType : byte
|
||||
{
|
||||
DidVote = 0,
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,8 @@ namespace Impostor.Api.Innersloth.Net
|
||||
|
||||
public SpawnFlags SpawnFlags { get; internal set; }
|
||||
|
||||
public abstract void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader);
|
||||
public abstract void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
|
||||
IMessageReader reader);
|
||||
|
||||
public abstract bool Serialize(IMessageWriter writer, bool initialState);
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ namespace Impostor.Api.Innersloth.Net.Objects.Components
|
||||
return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2));
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
|
||||
{
|
||||
if (call == 0)
|
||||
if (call == RpcCalls.SnapTo)
|
||||
{
|
||||
SnapTo(ReadVector2(reader), reader.ReadUInt16());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ namespace Impostor.Api.Innersloth.Net.Objects.Components
|
||||
{
|
||||
public class InnerPlayerPhysics : InnerNetObject
|
||||
{
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
|
||||
IMessageReader reader)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace Impostor.Api.Innersloth.Net.Objects.Components
|
||||
_votes = new Dictionary<int, int[]>();
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
|
||||
IMessageReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -37,12 +37,17 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerInfo GetPlayerById(byte id)
|
||||
public PlayerInfo? GetPlayerById(byte id)
|
||||
{
|
||||
if (id == byte.MaxValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _allPlayers.TryGetValue(id, out var player) ? player : null;
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
Components.Add(this);
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
|
||||
IMessageReader reader)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
|
||||
IMessageReader reader)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -32,38 +32,49 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
|
||||
public InnerGameData.PlayerInfo PlayerInfo { get; internal set; }
|
||||
|
||||
private void Die(DeathReason reason)
|
||||
{
|
||||
PlayerInfo.IsDead = true;
|
||||
PlayerInfo.LastDeathReason = reason;
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call, IMessageReader reader)
|
||||
{
|
||||
switch (call)
|
||||
{
|
||||
case RpcCalls.PlayAnimation:
|
||||
{
|
||||
// TODO: Figure out checks
|
||||
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)}.");
|
||||
}
|
||||
|
||||
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());
|
||||
Console.WriteLine(_game.Options.PlayerSpeedMod);
|
||||
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++)
|
||||
@@ -80,27 +91,260 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
// Player was voted out.
|
||||
case RpcCalls.Exiled:
|
||||
{
|
||||
if (!sender.IsHost)
|
||||
{
|
||||
throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetInfected)} but was not a host.");
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SetInfected)} to a specific player instead of broadcast.");
|
||||
}
|
||||
|
||||
Console.WriteLine(PlayerInfo.PlayerName + " was voted out.");
|
||||
|
||||
Die(DeathReason.Exile);
|
||||
break;
|
||||
}
|
||||
|
||||
// Validates the player name at the host.
|
||||
case RpcCalls.CheckName:
|
||||
{
|
||||
if (!target.IsHost)
|
||||
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)
|
||||
{
|
||||
// TODO: Uncomment
|
||||
// throw new ImpostorHackException($"Client sent {nameof(RpcCalls.MurderPlayer)} as crewmate.");
|
||||
}
|
||||
|
||||
var player = reader.ReadNetObject<InnerPlayerControl>(_game);
|
||||
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();
|
||||
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.
|
||||
Console.WriteLine("ads");
|
||||
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("InnerPlayerControl: Unknown rpc call {0}", call);
|
||||
break;
|
||||
@@ -121,5 +365,11 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
|
||||
PlayerId = reader.ReadByte();
|
||||
}
|
||||
|
||||
private void Die(DeathReason reason)
|
||||
{
|
||||
PlayerInfo.IsDead = true;
|
||||
PlayerInfo.LastDeathReason = reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,8 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
Components.Add(this);
|
||||
}
|
||||
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer target, RpcCalls call, IMessageReader reader)
|
||||
public override void HandleRpc(IClientPlayer sender, IClientPlayer? target, RpcCalls call,
|
||||
IMessageReader reader)
|
||||
{
|
||||
switch (call)
|
||||
{
|
||||
@@ -56,7 +57,7 @@ namespace Impostor.Api.Innersloth.Net.Objects
|
||||
case RpcCalls.RepairSystem:
|
||||
{
|
||||
var systemType = (SystemTypes)reader.ReadByte();
|
||||
var player = _game.FindObjectByNetId<InnerPlayerControl>(reader.ReadPackedUInt32());
|
||||
var player = reader.ReadNetObject<InnerPlayerControl>(_game);
|
||||
var amount = reader.ReadByte();
|
||||
|
||||
if (systemType == SystemTypes.Sabotage && !player.PlayerInfo.IsImpostor)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Games;
|
||||
using Impostor.Api.Innersloth.Net;
|
||||
using Impostor.Api.Innersloth.Net.Objects;
|
||||
|
||||
namespace Impostor.Api.Net
|
||||
@@ -28,6 +29,13 @@ namespace Impostor.Api.Net
|
||||
|
||||
public bool IsHost { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified <see cref="InnerNetObject"/> is owned by <see cref="IClientPlayer"/>.
|
||||
/// </summary>
|
||||
/// <param name="netObject">The <see cref="InnerNetObject"/>.</param>
|
||||
/// <returns>Returns true if owned by <see cref="IClientPlayer"/>.</returns>
|
||||
bool IsOwner(InnerNetObject netObject);
|
||||
|
||||
ValueTask KickAsync();
|
||||
|
||||
ValueTask BanAsync();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using Impostor.Api.Innersloth.Net;
|
||||
using Impostor.Api.Innersloth.Net.Objects;
|
||||
using Impostor.Api.Net;
|
||||
|
||||
@@ -26,6 +27,12 @@ namespace Impostor.Server.Net.State
|
||||
|
||||
public string Scene { get; internal set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsOwner(InnerNetObject netObject)
|
||||
{
|
||||
return Client.Id == netObject.OwnerId;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask KickAsync()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user