mirror of
https://github.com/Impostor/Impostor.git
synced 2026-10-20 01:46:11 +00:00
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:
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; }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user