v1.2.2.b6
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
This commit is contained in:
parent
a0f37ba1a1
commit
25cd8eb989
31 changed files with 202 additions and 79 deletions
|
|
@ -13,10 +13,17 @@ namespace src.player
|
|||
{
|
||||
private static string sessionId = "00000";
|
||||
private static readonly string debugFolder = Path.Combine(Instance.ModuleDirectory, "logs");
|
||||
private static StreamWriter? _writer;
|
||||
private static readonly object _writeLock = new();
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
sessionId = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}";
|
||||
lock (_writeLock) { _writer?.Dispose(); _writer = null; }
|
||||
|
||||
if (Config.LoadedConfig.DebugMode != true)
|
||||
return;
|
||||
|
||||
Instance.RegisterEventHandler<EventPlayerConnectFull>((@event, info) =>
|
||||
{
|
||||
var player = PlayerManager.GetPlayerEvent(@event.Userid);
|
||||
|
|
@ -131,13 +138,25 @@ namespace src.player
|
|||
if (Config.LoadedConfig.DebugMode != true)
|
||||
return;
|
||||
|
||||
// GetAllEntityIndexes();
|
||||
lock (_writeLock)
|
||||
{
|
||||
_writer ??= CreateWriter();
|
||||
_writer?.WriteLine($"[{DateTime.Now:dd.MM.yyyy HH:mm:ss}] {message}");
|
||||
}
|
||||
}
|
||||
|
||||
string filename = $"debug_{sessionId}.txt";
|
||||
string path = Path.Combine(debugFolder, filename);
|
||||
|
||||
Directory.CreateDirectory(debugFolder);
|
||||
File.AppendAllText(path, $"[{DateTime.Now:dd.MM.yyyy HH:mm:ss}] {message}{Environment.NewLine}", System.Text.Encoding.UTF8);
|
||||
private static StreamWriter? CreateWriter()
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(debugFolder);
|
||||
string path = Path.Combine(debugFolder, $"debug_{sessionId}.txt");
|
||||
return new StreamWriter(path, append: true, System.Text.Encoding.UTF8) { AutoFlush = true };
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetAllEntityIndexes()
|
||||
|
|
|
|||
|
|
@ -417,22 +417,50 @@ namespace src.player
|
|||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Skills, string> _skillNames =
|
||||
Enum.GetValues<Skills>().ToDictionary(s => s, s => s.ToString());
|
||||
private static readonly HashSet<Skills> _activeSkillsSet = [];
|
||||
private static readonly List<Skills> _activeSkillsList = [];
|
||||
private static readonly Comparison<Skills> _tickOrderCmp = (a, b) => TickOrder(a).CompareTo(TickOrder(b));
|
||||
private static HashSet<Skills>? _freezeDisabledSkills;
|
||||
|
||||
// AreaReaper and ChillOut depend on other skills' tick results, so they must tick last.
|
||||
private static int TickOrder(Skills s) => s == Skills.AreaReaper ? 2 : s == Skills.ChillOut ? 1 : 0;
|
||||
|
||||
private static HashSet<Skills> BuildFreezeDisabledSkills()
|
||||
{
|
||||
var set = new HashSet<Skills>();
|
||||
foreach (var s in SkillData.Skills)
|
||||
if (SkillsInfo.GetValue<bool>(s.Skill, "disableOnFreezeTime"))
|
||||
set.Add(s.Skill);
|
||||
return set;
|
||||
}
|
||||
|
||||
public static void InvalidateFreezeDisabledCache() => _freezeDisabledSkills = null;
|
||||
|
||||
private static void OnTick()
|
||||
{
|
||||
lock (setLock)
|
||||
{
|
||||
var activeSkills = Instance.SkillPlayer
|
||||
.Where(p => !p.IsDrawing)
|
||||
.Select(p => p.Skill)
|
||||
.Distinct()
|
||||
.OrderBy(skill => skill.ToString() == "AreaReaper")
|
||||
.ThenBy(skill => skill.ToString() == "ChillOut");
|
||||
_activeSkillsSet.Clear();
|
||||
_activeSkillsList.Clear();
|
||||
foreach (var p in Instance.SkillPlayer)
|
||||
{
|
||||
if (p.IsDrawing) continue;
|
||||
if (_activeSkillsSet.Add(p.Skill))
|
||||
_activeSkillsList.Add(p.Skill);
|
||||
}
|
||||
|
||||
foreach (var skill in activeSkills)
|
||||
if (SkillsInfo.GetValue<bool>(skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime())
|
||||
continue;
|
||||
else
|
||||
Instance.SkillAction(skill.ToString(), "OnTick");
|
||||
_activeSkillsList.Sort(_tickOrderCmp);
|
||||
|
||||
bool freeze = SkillUtils.IsFreezeTime();
|
||||
_freezeDisabledSkills ??= BuildFreezeDisabledSkills();
|
||||
|
||||
foreach (var skill in _activeSkillsList)
|
||||
{
|
||||
if (freeze && _freezeDisabledSkills.Contains(skill)) continue;
|
||||
Instance.SkillAction(_skillNames[skill], "OnTick");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -466,7 +494,6 @@ namespace src.player
|
|||
DisplayHUD = true,
|
||||
SkillUsed = false,
|
||||
};
|
||||
Instance.SkillPlayer.Add(playerInfo);
|
||||
PlayerManager.Register(playerInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -502,8 +529,6 @@ namespace src.player
|
|||
|
||||
Instance.SkillAction(skillPlayer.Skill.ToString(), "DisableSkill", [player]);
|
||||
|
||||
var items = Instance.SkillPlayer.ToList();
|
||||
Instance.SkillPlayer = [.. items.Where(p => p.PlayerIndex != player.Index)];
|
||||
PlayerManager.UnregisterPlayer(player.Index);
|
||||
EntityManager.DestroyPlayerEntities(player.Index);
|
||||
|
||||
|
|
@ -606,6 +631,10 @@ namespace src.player
|
|||
var playerInfo = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (playerInfo == null) continue;
|
||||
|
||||
ActiveSkillsThisRound.TryAdd(playerInfo.Skill.ToString(), 0);
|
||||
if (playerInfo.SpecialSkill != noneSkill.Skill)
|
||||
ActiveSkillsThisRound.TryAdd(playerInfo.SpecialSkill.ToString(), 0);
|
||||
|
||||
Instance.SkillAction(playerInfo.Skill.ToString(), "DisableSkill", [player]);
|
||||
|
||||
playerInfo.Skill = noneSkill.Skill;
|
||||
|
|
@ -617,8 +646,9 @@ namespace src.player
|
|||
RestorePlayer(player);
|
||||
}
|
||||
|
||||
foreach (var skill in SkillData.Skills)
|
||||
Instance.SkillAction(skill.Skill.ToString(), "NewRound");
|
||||
foreach (var skillName in ActiveSkillsThisRound.Keys)
|
||||
Instance.SkillAction(skillName, "NewRound");
|
||||
ActiveSkillsThisRound.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -649,6 +679,7 @@ namespace src.player
|
|||
EntityManager.DestroyAllTracked();
|
||||
foreach (var skill in SkillData.Skills)
|
||||
Instance.SkillAction(skill.Skill.ToString(), "NewRound");
|
||||
ActiveSkillsThisRound.Clear();
|
||||
|
||||
playersSkills.Clear();
|
||||
staticSkills.Clear();
|
||||
|
|
@ -657,7 +688,6 @@ namespace src.player
|
|||
tSkill = noneSkill;
|
||||
allSkill = noneSkill;
|
||||
|
||||
Instance.SkillPlayer.Clear();
|
||||
PlayerManager.Clear();
|
||||
|
||||
ConVar.Find("sv_legacy_jump")?.SetValue("1");
|
||||
|
|
@ -1113,7 +1143,7 @@ namespace src.player
|
|||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
Debug.WriteToDebug($"Player {skillPlayer.PlayerName} has got the skill \"{player.GetSkillName(randomSkill.Skill)}\".");
|
||||
skillPlayer.SkillDescriptionHudExpired = DateTime.Now.AddSeconds(Config.LoadedConfig.SkillDescriptionDuration);
|
||||
skillPlayer.SkillDescriptionHudExpired = Config.LoadedConfig.SkillDescriptionDuration == -1 ? DateTime.MaxValue : DateTime.Now.AddSeconds(Config.LoadedConfig.SkillDescriptionDuration);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ namespace src.player
|
|||
{
|
||||
if (player == null || !player.IsValid || player.IsBot) return;
|
||||
|
||||
var skillPlayer = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var skillPlayer = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index);
|
||||
if (skillPlayer == null || !skillPlayer.DisplayHUD) return;
|
||||
|
||||
var now = DateTime.Now;
|
||||
|
|
@ -72,7 +72,7 @@ namespace src.player
|
|||
string skillLine = string.Empty;
|
||||
string remainingLine = string.Empty;
|
||||
|
||||
bool showDescriptionHUD = skillPlayer.SkillDescriptionHudExpired >= now;
|
||||
bool showDescriptionHUD = skillPlayer.SkillDescriptionHudExpired >= now || Config.LoadedConfig.DisplayAlwaysDescription;
|
||||
bool isDescription = true;
|
||||
|
||||
var skills = SkillData.Skills;
|
||||
|
|
@ -99,7 +99,7 @@ namespace src.player
|
|||
{
|
||||
if (player.PawnIsAlive)
|
||||
{
|
||||
var skillInfo = skills.FirstOrDefault(s => s.Skill == skillPlayer.Skill);
|
||||
var skillInfo = SkillData.GetInfo(skillPlayer.Skill);
|
||||
|
||||
if (skillInfo != null)
|
||||
{
|
||||
|
|
@ -139,9 +139,9 @@ namespace src.player
|
|||
var observedSkill = PlayerManager.GetPlayerByIndex(observedEvent.Index);
|
||||
if (observedSkill == null) return;
|
||||
|
||||
var observedSkillInfo = skills.FirstOrDefault(s => s.Skill == observedSkill.Skill);
|
||||
var observedSkillInfo = SkillData.GetInfo(observedSkill.Skill);
|
||||
var observedSpecialInfo = observedSkill.SpecialSkill != Skills.None
|
||||
? skills.FirstOrDefault(s => s.Skill == observedSkill.SpecialSkill)
|
||||
? SkillData.GetInfo(observedSkill.SpecialSkill)
|
||||
: null;
|
||||
|
||||
string primaryName = player.GetSkillName(observedSkill.Skill, observedSkill.SkillChance);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ namespace src.player.skills
|
|||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
decoys.TryAdd(decoy.Index, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace src.player.skills
|
|||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill == skillName)
|
||||
GiveBunnyHop(player);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace src.player.skills
|
|||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo == null) continue;
|
||||
|
||||
var pawn = player.PlayerPawn.Value;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ namespace src.player.skills
|
|||
if (player == null) return;
|
||||
ChangeCamera(player, true);
|
||||
EntityManager.DestroyPlayerEntities(player.Index);
|
||||
cameras.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace src.player.skills
|
|||
foreach (var (info, player) in infoList)
|
||||
{
|
||||
if (player == null) continue;
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
|
||||
var observedPlayer = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == player?.Pawn?.Value?.ObserverServices?.ObserverTarget?.Value?.Handle);
|
||||
var observerInfo = observedPlayer != null ? PlayerManager.GetPlayerByIndex(observedPlayer.Index) : null;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace src.player.skills
|
|||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
grenade.Bounces = 555;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace src.player.skills
|
|||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
Server.NextFrame(() =>
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ namespace src.player.skills
|
|||
if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
|
||||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
Vector pos = new(grenade.AbsOrigin?.X, grenade.AbsOrigin?.Y, grenade.AbsOrigin?.Z);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace src.player.skills
|
|||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
bool isJackalOwner = playerInfo?.Skill == skillName;
|
||||
|
||||
if (!isJackalOwner)
|
||||
|
|
@ -90,6 +90,11 @@ namespace src.player.skills
|
|||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null
|
||||
|| playerPawn.LifeState != (byte)LifeState_t.LIFE_ALIVE || playerPawn.Health <= 0) return; ;
|
||||
|
||||
foreach (var old in EntityManager.GetPlayerEntities(player.Index, "prop_physics_multiplayer"))
|
||||
EntityManager.DestroyEntity(old);
|
||||
foreach (var old in EntityManager.GetPlayerEntities(player.Index, "particle_system"))
|
||||
EntityManager.DestroyEntity(old);
|
||||
|
||||
var relay = EntityManager.CreateTrackedPhysicsProp(player.Index);
|
||||
if (relay == null || !relay.IsValid) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,16 +53,18 @@ namespace src.player.skills
|
|||
var jester = GetJesterInfo(player.Index);
|
||||
if (jester == null) return;
|
||||
|
||||
jester.Active = false;
|
||||
if (jester.Timer != null)
|
||||
{
|
||||
jester.Timer.Kill();
|
||||
jester.Timer = null;
|
||||
}
|
||||
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
if (jester.Timer != null)
|
||||
{
|
||||
jester.Timer?.Kill();
|
||||
jester.Timer = null;
|
||||
}
|
||||
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
SetPlayerColor(player, true);
|
||||
jesters.TryRemove(player.Index, out _);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace src.player.skills
|
|||
if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
|
||||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
nades.TryAdd(grenade.Index, 0);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace src.player.skills
|
|||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
UpdateNinja(player);
|
||||
|
|
@ -50,7 +50,7 @@ namespace src.player.skills
|
|||
var player = @event.Userid;
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
UpdateNinja(player);
|
||||
|
|
@ -118,7 +118,7 @@ namespace src.player.skills
|
|||
|
||||
UpdateNinja(PlayerManager.GetPlayerFromEvent(player));
|
||||
|
||||
var props = EntityManager.GetPlayerEntities(PlayerManager.GetPlayerEvent(player)!.Index, "empty_prop");
|
||||
var props = EntityManager.GetPlayerEntities((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index), "empty_prop");
|
||||
if (props.Count == 0) continue;
|
||||
|
||||
var prop = Utilities.GetEntityFromIndex<CDynamicProp>((int)props[0]);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace src.player.skills
|
|||
var player = Utilities.GetPlayers().FirstOrDefault(p => p.Pawn?.Value != null && p.Pawn.Value.IsValid && p.Pawn.Value.Index == userIndex);
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
um.Recipients.Clear();
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ namespace src.player.skills
|
|||
if (player == null) return;
|
||||
ChangeCamera(player, true);
|
||||
EntityManager.DestroyPlayerEntities(player.Index);
|
||||
cameras.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace src.player.skills
|
|||
if (player == null) return;
|
||||
ChangeCamera(player, true);
|
||||
EntityManager.DestroyPlayerEntities(player.Index);
|
||||
cameras.TryRemove(player.Index, out _);
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ namespace src.player.skills
|
|||
continue;
|
||||
}
|
||||
|
||||
bool isOwner = knifeOwnerIndex == PlayerManager.GetPlayerEvent(player)!.Index;
|
||||
bool isOwner = knifeOwnerIndex == (PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index);
|
||||
bool isObservingOwner = observedPlayerIndex.HasValue && observedPlayerIndex.Value == knifeOwnerIndex;
|
||||
|
||||
if (!isOwner && !isObservingOwner)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace src.player.skills
|
|||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
Server.NextFrame(() =>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace src.player.skills
|
|||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
var observedPlayer = Utilities.GetPlayers().FirstOrDefault(p => p?.Pawn?.Value?.Handle == player?.Pawn?.Value?.ObserverServices?.ObserverTarget?.Value?.Handle);
|
||||
var observerInfo = observedPlayer != null ? PlayerManager.GetPlayerByIndex(observedPlayer.Index) : null;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace src.player.skills
|
|||
if (pawn == null || !pawn.IsValid || pawn.Controller == null || !pawn.Controller.IsValid || pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
|
||||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName || Instance.GameRules == null) return;
|
||||
|
||||
var roundTime = SkillsInfo.GetValue<int>(skillName, "changeRoundTime");
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace src.player.skills
|
|||
if (pawn.Controller.Value == null || !pawn.Controller.Value.IsValid) return;
|
||||
var player = pawn.Controller.Value.As<CCSPlayerController>();
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(PlayerManager.GetPlayerEvent(player)!.Index);
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex((PlayerManager.GetPlayerEvent(player)?.Index ?? player.Index));
|
||||
if (playerInfo?.Skill != skillName) return;
|
||||
|
||||
Server.NextFrame(() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue