2 Commits

Author SHA1 Message Date
MSWS
faeec955f8 Merge branch 'dev' of github.com:edgegamers/Jailbreak into dev 2025-10-09 10:00:36 -07:00
MSWS
4e94f724e9 refactor: Refactor damage and event handling logic for LRs
- Remove obsolete method overload in `IDamageBlocker.cs` to simplify the interface.
- Simplify logic in `GunToss.cs` by removing initialization and cleanup operations, locale injection, and timer setup for guard status.
- Refactor `LastRequestManager.cs` by:
  - Adding `JetBrains.Annotations` and replacing game event handler attributes for better annotation usage.
  - Streamlining last request event handling by removing redundant tasks and encapsulating utility functions.
  - Suppressing extra damage event broadcasts and improving message clarity.
  - Adjusting round time management logic for last requests.
2025-10-09 09:59:54 -07:00
3 changed files with 14 additions and 224 deletions

View File

@@ -28,6 +28,7 @@ using Jailbreak.Public.Mod.Rainbow;
using Jailbreak.Public.Mod.Rebel;
using Jailbreak.Public.Mod.Weapon;
using Jailbreak.Public.Utils;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using MStatsShared;
@@ -112,14 +113,9 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
basePlugin.RegisterListener<Listeners.OnEntityParentChanged>(OnDrop);
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage,
HookMode.Pre);
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Hook(OnCanAcquire,
HookMode.Pre);
}
public void Dispose() {
VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Unhook(OnCanAcquire,
HookMode.Pre);
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage,
HookMode.Pre);
}
@@ -135,8 +131,6 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
messages.LastRequestEnabled().ToAllChat();
IsLREnabled = true;
API.Stats?.PushStat(new ServerStat("JB_LASTREQUEST_ACTIVATED"));
var cts = Utilities.GetPlayers()
.Count(p => p is { Team: CsTeam.CounterTerrorist, PawnIsAlive: true });
@@ -188,7 +182,6 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
foreach (var survivor in survivors) {
await eco.Grant(survivor, survivor.Team == CsTeam.Terrorist ? 65 : 60,
reason: "LR Reached");
await incrementLRReached(survivor);
}
});
}
@@ -207,16 +200,6 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
prisoner.SetArmor(0);
guard.SetArmor(0);
var prisonerWrapper = new PlayerWrapper(prisoner);
var guardWrapper = new PlayerWrapper(guard);
Task.Run(async () => {
await incrementLRStart(prisonerWrapper);
await incrementLRStart(guardWrapper);
await colorForLR(prisonerWrapper, guardWrapper);
});
messages.InformLastRequest(lr).ToAllChat();
return true;
}
@@ -225,7 +208,6 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
rainbowColorizer.StopRainbow(lr.Prisoner);
rainbowColorizer.StopRainbow(lr.Guard);
if (result is LRResult.GUARD_WIN or LRResult.PRISONER_WIN) {
// RoundUtil.AddTimeRemaining(CV_LR_BONUS_TIME.Value);
addRoundTimeCapped(CV_LR_BONUS_TIME.Value, CV_MAX_TIME_FOR_LR.Value);
messages.LastRequestDecided(lr, result).ToAllChat();
@@ -239,9 +221,6 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
Task.Run(async () => await eco.Grant(wrapper,
wrapper.Team == CsTeam.CounterTerrorist ? 35 : 20, reason: "LR Win"));
}
if (API.Gangs != null)
Task.Run(async () => await incrementLRWin(wrapper));
}
API.Stats?.PushStat(new ServerStat("JB_LASTREQUEST_RESULT",
@@ -275,168 +254,6 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
listener.OnWeaponDrop(owner, weapon);
}
private HookResult OnCanAcquire(DynamicHook hook) {
if (ActiveLRs.Count == 0) return HookResult.Continue;
var player = hook.GetParam<CCSPlayer_ItemServices>(0)
.Pawn.Value.Controller.Value?.As<CCSPlayerController>();
var data = VirtualFunctions.GetCSWeaponDataFromKey.Invoke(-1,
hook.GetParam<CEconItemView>(1).ItemDefinitionIndex.ToString());
if (player == null || !player.IsValid) return HookResult.Continue;
var method = hook.GetParam<AcquireMethod>(2);
if (method != AcquireMethod.PickUp) return HookResult.Continue;
if (ActiveLRs.Any(lr => lr.PreventEquip(player, data))) {
hook.SetReturn(AcquireResult.NotAllowedByMode);
return HookResult.Handled;
}
return HookResult.Continue;
}
private async Task colorForLR(PlayerWrapper a, PlayerWrapper b) {
var playerStats = API.Gangs?.Services.GetService<IPlayerStatManager>();
var gangStats = API.Gangs?.Services.GetService<IGangStatManager>();
var gangs = API.Gangs?.Services.GetService<IGangManager>();
var localizer = API.Gangs?.Services.GetService<IStringLocalizer>();
if (playerStats == null || localizer == null || gangs == null
|| gangStats == null)
return;
var aData = await playerStats.GetForPlayer<LRColor>(a, LRColorPerk.STAT_ID);
var bData = await playerStats.GetForPlayer<LRColor>(b, LRColorPerk.STAT_ID);
LRColor? toApply = null;
PlayerWrapper? higher = null;
higher = await getHigherPlayer(a, b);
if (toApply == null) return;
if (a.Player == null || b.Player == null) return;
var higherGang = await gangs.GetGang(higher.Steam);
if (higherGang == null) return;
var gData =
await gangStats.GetForGang<LRColor>(higherGang, LRColorPerk.STAT_ID);
if ((gData & toApply.Value) == 0) return;
var color = toApply.Value.GetColor();
if (color == null) { // Player picked random, but we need to pick
// the random from their GANG's colors
var gangData =
await playerStats.GetForPlayer<LRColor>(higher, LRColorPerk.STAT_ID);
color = gangData.PickRandomColor();
}
if (color == null) return;
await Server.NextFrameAsync(() => {
if (toApply == LRColor.RAINBOW) {
rainbowColorizer.StartRainbow(a.Player);
rainbowColorizer.StartRainbow(b.Player);
var rmsg = localizer.Get(MSG.PREFIX)
+ $"Your LR will be {IRainbowColorizer.RAINBOW}.";
a.Player.PrintToChat(rmsg);
b.Player.PrintToChat(rmsg);
return;
}
a.Player.SetColor(color.Value);
b.Player.SetColor(color.Value);
var msg = localizer.Get(MSG.PREFIX)
+ $"Your LR will be {color.GetChatColor()}{color.Value.Name}{ChatColors.Grey}.";
a.Player.PrintToChat(msg);
b.Player.PrintToChat(msg);
});
}
private async Task<PlayerWrapper> getHigherPlayer(PlayerWrapper a,
PlayerWrapper b) {
var leaderboard = API.Gangs?.Services.GetService<ILeaderboard>();
var players = API.Gangs?.Services.GetService<IPlayerManager>();
if (leaderboard == null || players == null) return a;
var aGangPlayer = await players.GetPlayer(a.Steam);
var bGangPlayer = await players.GetPlayer(b.Steam);
if (aGangPlayer == null && bGangPlayer != null) return b;
if (aGangPlayer != null && bGangPlayer == null) return a;
if (aGangPlayer == null || bGangPlayer == null) return a;
var aGang = aGangPlayer.GangId;
var bGang = bGangPlayer.GangId;
if (aGang == null && bGang != null) return b;
if (aGang != null && bGang == null) return a;
if (aGang == null || bGang == null) return a;
if (aGang == bGang) return a;
var aRank = await leaderboard.GetPosition(aGang.Value);
var bRank = await leaderboard.GetPosition(bGang.Value);
if (aRank == null && bRank != null) return b;
if (aRank != null && bRank == null) return a;
if (aRank == null || bRank == null) return a;
return aRank < bRank ? a : b;
}
private async Task incrementLRReached(PlayerWrapper player) {
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
if (stats == null) return;
var stat = await getStat(player);
if (stat == null) return;
if (player.Team == CsTeam.Terrorist)
stat.LRsReachedAsT++;
else
stat.LRsReachedAsCt++;
await stats.SetForPlayer(player, LRStat.STAT_ID, stat);
}
private async Task incrementLRStart(PlayerWrapper player) {
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
if (stats == null) return;
var stat = await getStat(player);
if (stat == null) return;
if (player.Team == CsTeam.Terrorist)
stat.TLrs++;
else
stat.CtLrs++;
await stats.SetForPlayer(player, LRStat.STAT_ID, stat);
}
private async Task incrementLRWin(PlayerWrapper player) {
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
if (stats == null) return;
var stat = await getStat(player);
if (stat == null) return;
if (player.Team == CsTeam.Terrorist)
stat.TLrsWon++;
else
stat.CTLrsWon++;
await stats.SetForPlayer(player, LRStat.STAT_ID, stat);
}
private async Task<LRData?> getStat(PlayerWrapper player) {
var stats = API.Gangs?.Services.GetService<IPlayerStatManager>();
if (stats == null) return null;
var data = await stats.GetForPlayer<LRData>(player, LRStat.STAT_ID)
?? new LRData();
return data;
}
public static bool shouldGrantCredits() {
if (API.Gangs == null) return false;
return Utilities.GetPlayers().Count >= CV_MIN_PLAYERS_FOR_CREDITS.Value;
@@ -459,39 +276,43 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
HookResult.Continue;
}
[GameEventHandler]
[UsedImplicitly]
[GameEventHandler(HookMode.Pre)]
public HookResult OnTakeDamage(EventPlayerHurt ev, GameEventInfo info) {
var player = ev.Userid;
var attacker = ev.Attacker;
if (player == null || !player.IsReal()) return HookResult.Continue;
if (player == null || player.Pawn.Value == null) return HookResult.Continue;
if (!ShouldBlockDamage(player, attacker)) return HookResult.Continue;
if (player.PlayerPawn.IsValid) {
var playerPawn = player.PlayerPawn.Value!;
playerPawn.Health = playerPawn.LastHealth;
}
info.DontBroadcast = false;
ev.DmgArmor = ev.DmgHealth = 0;
return HookResult.Handled;
}
[UsedImplicitly]
[GameEventHandler]
public HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) {
foreach (var lr in ActiveLRs.ToList())
EndLastRequest(lr, LRResult.TIMED_OUT);
IsLREnabled = false;
return HookResult.Continue;
}
[UsedImplicitly]
[GameEventHandler]
public HookResult OnRoundStart(EventRoundStart @event, GameEventInfo info) {
IsLREnabledForRound = true;
IsLREnabled = false;
foreach (var player in Utilities.GetPlayers())
MenuManager.CloseActiveMenu(player);
foreach (var lr in ActiveLRs.ToList())
EndLastRequest(lr, LRResult.TIMED_OUT);
ActiveLRs.Clear();
return HookResult.Continue;
}
[UsedImplicitly]
[GameEventHandler]
public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info) {
var player = @event.Userid;
@@ -515,6 +336,7 @@ public class LastRequestManager(ILRLocale messages, IServiceProvider provider)
return HookResult.Continue;
}
[UsedImplicitly]
[GameEventHandler]
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event,
GameEventInfo info) {

View File

@@ -20,11 +20,6 @@ public class GunToss(BasePlugin plugin, ILastRequestManager manager,
IServiceProvider provider, CCSPlayerController prisoner,
CCSPlayerController guard)
: TeleportingRequest(plugin, manager, prisoner, guard), IDropListener {
private readonly List<BeamLine> guardLines = [], prisonerLines = [];
private readonly ILRGunTossLocale locale =
provider.GetRequiredService<ILRGunTossLocale>();
/// <summary>
/// Null if no one has thrown a gun yet, negative if only one has thrown a gun,
/// Positive if both have thrown a gun.
@@ -56,13 +51,6 @@ public class GunToss(BasePlugin plugin, ILastRequestManager manager,
}
if (prisonerTossed && guardTossed) bothThrewTick = Server.TickCount;
if (bothThrewTick > 0)
Plugin.AddTimer(5, () => {
if (State != LRState.ACTIVE) return;
Guard.SetHealth(Math.Min(Guard.PlayerPawn.Value!.Health, 100));
Guard.SetArmor(Math.Min(Guard.PawnArmor, 100));
});
}
public override void Setup() {
@@ -71,13 +59,6 @@ public class GunToss(BasePlugin plugin, ILastRequestManager manager,
Prisoner.RemoveWeapons();
Guard.RemoveWeapons();
Server.NextFrame(() => {
if (!Guard.IsValid) return;
Guard.SetHealth(500);
Guard.SetArmor(500);
});
Plugin.AddTimer(3, Execute);
}
@@ -91,14 +72,7 @@ public class GunToss(BasePlugin plugin, ILastRequestManager manager,
Server.RunOnTick(Server.TickCount + 16, () => State = LRState.ACTIVE);
}
public override void OnEnd(LRResult result) {
State = LRState.COMPLETED;
guardLines.ForEach(l => l.Remove());
guardLines.Clear();
prisonerLines.ForEach(l => l.Remove());
prisonerLines.Clear();
}
public override void OnEnd(LRResult result) { State = LRState.COMPLETED; }
public override bool PreventEquip(CCSPlayerController player,
CCSWeaponBaseVData weapon) {

View File

@@ -7,12 +7,6 @@ namespace Jailbreak.Public.Mod.Damage;
/// taking damage.
/// </summary>
public interface IDamageBlocker {
[Obsolete("Do not use the EventPlayerHurt overload.")]
bool ShouldBlockDamage(CCSPlayerController victim,
CCSPlayerController? attacker, EventPlayerHurt @event) {
return ShouldBlockDamage(victim, attacker);
}
bool ShouldBlockDamage(CCSPlayerController victim,
CCSPlayerController? attacker);
}