Refresh Murder Event API

- IPlayerCheckMurderEvent now exists
- You can see if a kill was successful with IPlayerMurderEvent
- You can now see if host authority was requested with Game.IsHostAuthoritive
This commit is contained in:
miniduikboot committed 2023-10-29 00:37:30 +02:00
1 parent 946d7e2164
commit b67ca158ea
8 files changed
+120 -23

No files matched your search

@@ -0,0 +1,27 @@
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Event that allows changing or canceling an upcoming player murder.
/// </summary>
/// Note that this event only triggers if the Host of the Game did not disable server authority.
///
/// If you want to get an event after the murder took place, listen to <see cref="IPlayerMurderEvent"/>.
public interface IPlayerCheckMurderEvent : IPlayerEvent, IEventCancelable
{
/// <summary>
/// Gets the player who got murdered.
/// </summary>
IInnerPlayerControl Victim { get; }
/// <summary>
/// Gets or sets the result of this event.
/// </summary>
/// Its initial value is what would have happened in the normal game flow.
/// - If set to Succeeded, the Victim will die.
/// - If set to FailedProtected, the Victim will be protected with a shield animation and the attacker will have a cooldown set.
MurderResultFlags Result { get; set; }
}
}
@@ -1,12 +1,26 @@
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Event that is called when a player is killed by another player.
/// </summary>
/// This event works regardless of server authority is enabled or not.
///
/// If you want to cancel this kill, listen to <see cref="IPlayerCheckMurderEvent"/>
/// If you want to know about players that were voted out, listed to <see cref="IPlayerExileEvent"/>
public interface IPlayerMurderEvent : IPlayerEvent
{
/// <summary>
/// Gets the player who got murdered.
/// </summary>
IInnerPlayerControl Victim { get; }
/// <summary>
/// Gets the result of the event.
/// </summary>
/// Note that if FailedError or FailedProtected is set, the kill did not take place
MurderResultFlags Result { get; }
}
}
+6
View File
@@ -39,6 +39,12 @@ namespace Impostor.Api.Games
int HostId { get; }
/// <summary>
/// Gets a value indicating whether the Host of the game has requested host authority.
/// </summary>
/// Vanilla Among Us does not request this, but certain client-side mods will.
bool IsHostAuthoritive { get; }
IClientPlayer? GetClientPlayer(int clientId);
T? FindObjectByNetId<T>(uint netId)
@@ -0,0 +1,32 @@
using Impostor.Api.Events.Player;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Server.Events.Player
{
public class PlayerCheckMurderEvent : IPlayerCheckMurderEvent
{
public PlayerCheckMurderEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl, IInnerPlayerControl victim, MurderResultFlags result)
{
Game = game;
ClientPlayer = clientPlayer;
PlayerControl = playerControl;
Victim = victim;
Result = result;
}
public IGame Game { get; }
public IClientPlayer ClientPlayer { get; }
public IInnerPlayerControl PlayerControl { get; }
public IInnerPlayerControl Victim { get; }
public MurderResultFlags Result { get; set; }
public bool IsCancelled { get; set; }
}
}
@@ -1,5 +1,6 @@
using Impostor.Api.Events.Player;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
using Impostor.Api.Net;
using Impostor.Api.Net.Inner.Objects;
@@ -7,12 +8,13 @@ namespace Impostor.Server.Events.Player
{
public class PlayerMurderEvent : IPlayerMurderEvent
{
public PlayerMurderEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl, IInnerPlayerControl victim)
public PlayerMurderEvent(IGame game, IClientPlayer clientPlayer, IInnerPlayerControl playerControl, IInnerPlayerControl victim, MurderResultFlags result)
{
Game = game;
ClientPlayer = clientPlayer;
PlayerControl = playerControl;
Victim = victim;
Result = result;
}
public IGame Game { get; }
@@ -22,5 +24,7 @@ namespace Impostor.Server.Events.Player
public IInnerPlayerControl PlayerControl { get; }
public IInnerPlayerControl Victim { get; }
public MurderResultFlags Result { get; }
}
}
@@ -82,7 +82,7 @@ namespace Impostor.Server.Net.Inner.Objects
await Game.FinishRpcAsync(writer, player.OwnerId);
}
public async ValueTask MurderPlayerAsync(IInnerPlayerControl target, MurderResultFlags result = MurderResultFlags.Succeeded)
public async ValueTask MurderPlayerAsync(IInnerPlayerControl target, MurderResultFlags result)
{
if (!PlayerInfo.IsImpostor)
{
@@ -99,7 +99,7 @@ namespace Impostor.Server.Net.Inner.Objects
throw new ImpostorProtocolException("Tried to murder a player, but target was not alive.");
}
if (result == MurderResultFlags.Succeeded)
if ((result & (MurderResultFlags.FailedError | MurderResultFlags.FailedProtected)) == 0)
{
((InnerPlayerControl)target).Die(DeathReason.Kill);
}
@@ -108,7 +108,7 @@ namespace Impostor.Server.Net.Inner.Objects
Rpc12MurderPlayer.Serialize(writer, target, result);
await Game.FinishRpcAsync(writer);
await _eventManager.CallAsync(new PlayerMurderEvent(Game, Game.GetClientPlayer(OwnerId)!, this, target));
await _eventManager.CallAsync(new PlayerMurderEvent(Game, Game.GetClientPlayer(OwnerId)!, this, target, result));
}
public async ValueTask MurderPlayerAsync(IInnerPlayerControl target)
@@ -696,7 +696,7 @@ namespace Impostor.Server.Net.Inner.Objects
IsMurdering = target;
// Check if host authority mode is on
if (_game.IsHostAuthoritive())
if (_game.IsHostAuthoritive)
{
// Pass the RPC on unharmed, the client will handle it
return true;
@@ -706,8 +706,15 @@ namespace Impostor.Server.Net.Inner.Objects
{
var tgt = (InnerPlayerControl)target;
var result = tgt.IsProtected() ? MurderResultFlags.FailedProtected : MurderResultFlags.Succeeded;
tgt.ProtectedOn = null; // Clear GA protection in all cases
await MurderPlayerAsync(target, result);
var evt = new PlayerCheckMurderEvent(Game, sender, this, target, result);
await _eventManager.CallAsync(evt);
if (!evt.IsCancelled)
{
tgt.ProtectedOn = null; // Clear GA protection in all cases
await MurderPlayerAsync(target, evt.Result);
}
}
return false;
@@ -715,7 +722,7 @@ namespace Impostor.Server.Net.Inner.Objects
private async ValueTask<bool> HandleMurderPlayer(ClientPlayer sender, IInnerPlayerControl? target, MurderResultFlags result)
{
if (!_game.IsHostAuthoritive())
if (!_game.IsHostAuthoritive)
{
if (await sender.Client.ReportCheatAsync(RpcCalls.MurderPlayer, "Client tried to murder directly"))
{
@@ -742,8 +749,12 @@ namespace Impostor.Server.Net.Inner.Objects
if (target != null && !target.PlayerInfo.IsDead)
{
((InnerPlayerControl)target).Die(DeathReason.Kill);
await _eventManager.CallAsync(new PlayerMurderEvent(Game, sender, this, target));
if ((result & (MurderResultFlags.FailedError | MurderResultFlags.FailedProtected)) == 0)
{
((InnerPlayerControl)target).Die(DeathReason.Kill);
}
await _eventManager.CallAsync(new PlayerMurderEvent(Game, sender, this, target, result));
}
IsMurdering = null;
@@ -771,7 +782,7 @@ namespace Impostor.Server.Net.Inner.Objects
}
}
if (_game.IsHostAuthoritive())
if (_game.IsHostAuthoritive)
{
return true;
}
+15 -12
View File
@@ -92,6 +92,21 @@ namespace Impostor.Server.Net.State
public IEnumerable<IClientPlayer> Players => _players.Select(p => p.Value);
public bool IsHostAuthoritive
{
get
{
if (Host == null)
{
return false;
}
else
{
return Host.Client.GameVersion.HasDisableServerAuthorityFlag;
}
}
}
internal GameNet GameNet { get; }
public bool TryGetPlayer(int id, [MaybeNullWhen(false)] out ClientPlayer player)
@@ -145,17 +160,5 @@ namespace Impostor.Server.Net.State
.Select(p => p.Client.Connection)
.Where(c => c != null && c.IsConnected)!;
}
internal bool IsHostAuthoritive()
{
if (Host == null)
{
return false;
}
else
{
return Host.Client.GameVersion.HasDisableServerAuthorityFlag;
}
}
}
}