Performance & stability pass (issue #34 + audit) General: - DisableAll resets only skills active in the previous round instead of all loaded skills (~89ms -> ~5ms) - Removed per-tick LINQ/allocations, O(1) HUD skill lookups, translation substitutions moved to load time - ForceFullUpdate creates the network service once per broadcast; view-angle guard only skips a genuine (0,0,0) placeholder - Debug hooks/logging only active when DebugMode is enabled (single reused writer) - Player skill state unified to a single collection (fixes a rare disconnect race) - Gamedata signatures resolved lazily/isolated; hardened tick/transmit paths against invalid handles - Description HUD honours always-show / -1 duration consistently across all assignment paths Skills: - Jester: fixed the no-damage effect leaking after a mid-round skill change (Thief/Deactivator) - Jackal: fixed trail entities accumulating over a round - Falcon Eye / Third Eye / Spectator: camera state cleared on disable Also: added missing translation keys as untranslated markers across language files. Fixes #34
103 lines
No EOL
4.2 KiB
C#
103 lines
No EOL
4.2 KiB
C#
using CounterStrikeSharp.API;
|
|
using CounterStrikeSharp.API.Core;
|
|
using CounterStrikeSharp.API.Modules.Utils;
|
|
using Microsoft.Extensions.Logging;
|
|
using src.utils;
|
|
using System.Collections.Concurrent;
|
|
using static src.jRandomSkills;
|
|
|
|
namespace src.player.skills
|
|
{
|
|
public class ChillOut : ISkill
|
|
{
|
|
private const Skills skillName = Skills.ChillOut;
|
|
private static readonly ConcurrentDictionary<uint, float> plantingPlayers = [];
|
|
|
|
public static void LoadSkill()
|
|
{
|
|
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
|
}
|
|
|
|
public static void NewRound()
|
|
{
|
|
plantingPlayers.Clear();
|
|
}
|
|
|
|
public static void DisableSkill(CCSPlayerController player)
|
|
{
|
|
if (player == null || !player.IsValid) return;
|
|
plantingPlayers.TryRemove(player.Index, out _);
|
|
SkillUtils.ResetPrintHTML(player);
|
|
}
|
|
|
|
public static void BombAbortplant(EventBombAbortplant @event)
|
|
{
|
|
var user = PlayerManager.GetPlayerEvent(@event.Userid);
|
|
if (!Instance.IsPlayerValid(user)) return;
|
|
|
|
plantingPlayers.TryRemove(user.Index, out _);
|
|
SkillUtils.ResetPrintHTML(user);
|
|
}
|
|
|
|
public static void BombBeginplant(EventBombBeginplant @event)
|
|
{
|
|
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
|
if (!Instance.IsPlayerValid(player)) return;
|
|
|
|
plantingPlayers.TryAdd(player!.Index, Server.CurrentTime);
|
|
|
|
var anyChillOut = PlayerManager.GetAllPlayers().FirstOrDefault(p => p.Skill == skillName);
|
|
if (anyChillOut != null)
|
|
{
|
|
var bombEntities = Utilities.FindAllEntitiesByDesignerName<CC4>("weapon_c4").ToList();
|
|
if (bombEntities.Count != 0)
|
|
{
|
|
var bomb = bombEntities.FirstOrDefault();
|
|
if (bomb != null)
|
|
bomb.ArmedTime = Server.CurrentTime + SkillsInfo.GetValue<float>(skillName, "bombArmedTime");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void BombPlanted(EventBombPlanted @event)
|
|
{
|
|
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
|
if (!Instance.IsPlayerValid(player)) return;
|
|
|
|
plantingPlayers.TryRemove(player!.Index, out _);
|
|
SkillUtils.ResetPrintHTML(player);
|
|
}
|
|
|
|
public static void OnTick()
|
|
{
|
|
float currentTime = Server.CurrentTime;
|
|
float extraTime = SkillsInfo.GetValue<float>(skillName, "bombArmedTime");
|
|
|
|
foreach (var player in Utilities.GetPlayers().Where(p => p.Team == CsTeam.Terrorist))
|
|
{
|
|
if (player == null || !player.IsValid) continue;
|
|
|
|
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
|
if (playerInfo == null) continue;
|
|
|
|
var pawn = player.PlayerPawn.Value;
|
|
if (pawn == null || !pawn.IsValid) continue;
|
|
|
|
if (pawn.WeaponServices == null) continue;
|
|
var activeWeapon = pawn.WeaponServices.ActiveWeapon.Value;
|
|
if (activeWeapon == null || !activeWeapon.IsValid || activeWeapon.DesignerName != "weapon_c4") continue;
|
|
|
|
if (plantingPlayers.TryGetValue(player.Index, out float plantTime))
|
|
{
|
|
float remaining = plantTime + extraTime - currentTime;
|
|
playerInfo.PrintHTML = $"{player.GetTranslation("planter_planting", $"<font color='#00FF00'>{Math.Max(0, remaining):0.0}s</font>")}";
|
|
}
|
|
}
|
|
}
|
|
|
|
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#343deb", CsTeam onlyTeam = CsTeam.CounterTerrorist, bool disableOnFreezeTime = false, bool needsTeammates = false, string requiredPermission = "", int maxPerServer = 1, Rarity rarity = Rarity.Common, float bombArmedTime = 10f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, maxPerServer, rarity)
|
|
{
|
|
public float BombArmedTime { get; set; } = bombArmedTime;
|
|
}
|
|
}
|
|
} |