This commit is contained in:
ByDexter 2026-07-30 01:15:32 +03:00
parent 0e86f54e0a
commit 98f6e65b01
98 changed files with 3391 additions and 397 deletions

View file

@ -65,6 +65,12 @@ namespace src.utils
public static int GetTrackedCount(uint playerIndex) => GetPlayerEntities(playerIndex).Count;
public static uint? GetEntityOwner(uint entityIndex)
{
if (!trackedEntities.TryGetValue(entityIndex, out var data)) return null;
return data.PlayerIndex == SystemOwnerIndex ? null : data.PlayerIndex;
}
public static (int totalTracked, int ownerCount) GetStatistics()
{
return (trackedEntities.Count, trackedEntities.Values.Select(e => e.PlayerIndex).Distinct().Count());

View file

@ -22,10 +22,33 @@ namespace src.utils
private static string defaultLangCode = "en";
private static readonly Dictionary<Skills, string> skillKeys = BuildSkillKeys("");
private static readonly Dictionary<Skills, string> skillDescKeys = BuildSkillKeys("_desc");
private static readonly Dictionary<Skills, string> skillDesc2Keys = BuildSkillKeys("_desc2");
private static Dictionary<Skills, string> BuildSkillKeys(string suffix)
{
var map = new Dictionary<Skills, string>();
foreach (Skills skill in Enum.GetValues<Skills>())
map[skill] = skill.ToString().ToLowerInvariant() + suffix;
return map;
}
private static string SkillKey(Skills skill) => skillKeys.TryGetValue(skill, out var k) ? k : skill.ToString().ToLowerInvariant();
private static string SkillDescKey(Skills skill) => skillDescKeys.TryGetValue(skill, out var k) ? k : skill.ToString().ToLowerInvariant() + "_desc";
private static string SkillDesc2Key(Skills skill) => skillDesc2Keys.TryGetValue(skill, out var k) ? k : skill.ToString().ToLowerInvariant() + "_desc2";
private static readonly ConcurrentDictionary<(Skills Skill, string Lang, double Chance), string> _skillNameCache = [];
private static readonly ConcurrentDictionary<(Skills Skill, string Lang, double Chance), string> _skillDescCache = [];
private const double NoChance = double.NegativeInfinity;
public static void Load()
{
_translations.Clear();
_playersLanguage.Clear();
_skillNameCache.Clear();
_skillDescCache.Clear();
SetLangCode();
LoadAllLanguages();
LoadPlayersLanguage();
@ -77,9 +100,26 @@ namespace src.utils
public static string GetSkillName(this CCSPlayerController player, Skills skill, float? chance = null)
{
string langCode = GetLangCode(player);
bool cacheable = !Illiterate.CheckIlliterateSkill(player);
var cacheKey = (skill, langCode, chance == null ? NoChance : Math.Round((double)chance, 2));
if (cacheable && _skillNameCache.TryGetValue(cacheKey, out var cached))
return cached;
string result = BuildSkillName(player, skill, chance, langCode);
if (cacheable)
_skillNameCache[cacheKey] = result;
return result;
}
private static string BuildSkillName(CCSPlayerController player, Skills skill, float? chance, string langCode)
{
if (chance == null)
{
var translation = GetTranslation(skill.ToString().ToLowerInvariant(), langCode);
var translation = GetTranslation(SkillKey(skill), langCode);
if (!translation.Contains("{0}"))
return translation;
@ -92,7 +132,7 @@ namespace src.utils
}
var value = Math.Round((double)(chance ?? 1), 2);
var skillNameText = GetTranslation(skill.ToString().ToLowerInvariant(), langCode, player, value);
var skillNameText = GetTranslation(SkillKey(skill), langCode, player, value);
if (skillNameText.Contains('%')) skillNameText = skillNameText.Replace(value.ToString(), Math.Round(value * 100, 0).ToString());
return skillNameText;
}
@ -100,9 +140,26 @@ namespace src.utils
public static string GetSkillDescription(this CCSPlayerController player, Skills skill, float? chance = null)
{
string langCode = GetLangCode(player);
bool cacheable = !Illiterate.CheckIlliterateSkill(player);
var cacheKey = (skill, langCode, chance == null ? NoChance : Math.Round((double)chance, 2));
if (cacheable && _skillDescCache.TryGetValue(cacheKey, out var cached))
return cached;
string result = BuildSkillDescription(player, skill, chance, langCode);
if (cacheable)
_skillDescCache[cacheKey] = result;
return result;
}
private static string BuildSkillDescription(CCSPlayerController player, Skills skill, float? chance, string langCode)
{
if (chance == null)
{
var translation = GetTranslation($"{skill.ToString().ToLowerInvariant()}_desc", langCode);
var translation = GetTranslation(SkillDescKey(skill), langCode);
if (!translation.Contains("{0}"))
return translation;
@ -114,12 +171,12 @@ namespace src.utils
return string.Join(' ', filtered);
}
var skillName = $"{skill.ToString().ToLowerInvariant()}_desc2";
var skillName = SkillDesc2Key(skill);
var value = Math.Round((double)(chance ?? 1), 2);
var desc2 = GetTranslation(skillName, langCode, player, value);
var skilLDescription = desc2 == skillName
? player.GetTranslation($"{skill.ToString().ToLowerInvariant()}_desc")
? player.GetTranslation(SkillDescKey(skill))
: desc2.Contains('%') ? desc2.Replace(value.ToString(), Math.Round(value * 100, 0).ToString()) : desc2;
return skilLDescription;
}

View file

@ -12,6 +12,8 @@ namespace src.utils
private static int cachedTick = int.MinValue;
private static List<CCSPlayerController> cachedControllers = [];
private static int cachedBombTick = int.MinValue;
private static CC4? cachedBomb;
private static void EnsureTickCache()
@ -20,7 +22,6 @@ namespace src.utils
if (tick == cachedTick) return;
cachedTick = tick;
cachedControllers = Utilities.GetPlayers();
cachedBomb = Utilities.FindAllEntitiesByDesignerName<CC4>("weapon_c4").FirstOrDefault();
}
public static List<CCSPlayerController> GetTickPlayers()
@ -31,7 +32,13 @@ namespace src.utils
public static CC4? GetTickBomb()
{
EnsureTickCache();
int tick = Server.TickCount;
if (tick != cachedBombTick)
{
cachedBombTick = tick;
cachedBomb = Utilities.FindAllEntitiesByDesignerName<CC4>("weapon_c4").FirstOrDefault();
}
return cachedBomb != null && cachedBomb.IsValid ? cachedBomb : null;
}
@ -62,7 +69,7 @@ namespace src.utils
if (!player.ControllingBot)
return player;
return Utilities.GetPlayers().FirstOrDefault(p =>
return GetTickPlayers().FirstOrDefault(p =>
p != null &&
p.IsValid &&
p.IsBot &&
@ -78,7 +85,7 @@ namespace src.utils
if (!player.IsBot)
return player;
return Utilities.GetPlayers().FirstOrDefault(p =>
return GetTickPlayers().FirstOrDefault(p =>
p != null &&
p.IsValid &&
!p.IsBot &&
@ -91,43 +98,6 @@ namespace src.utils
return playersByIndex.Values;
}
public static IEnumerable<jSkill_PlayerInfo> GetAlivePlayers()
{
return playersByIndex.Values.Where(p =>
{
try
{
var controller = Utilities.GetPlayerFromIndex((int)p.PlayerIndex);
return controller != null && controller.IsValid && controller.PawnIsAlive;
}
catch
{
return false;
}
});
}
public static IEnumerable<jSkill_PlayerInfo> GetPlayersByTeam(CsTeam team)
{
return playersByIndex.Values.Where(p =>
{
try
{
var controller = Utilities.GetPlayerFromIndex((int)p.PlayerIndex);
return controller != null && controller.IsValid && controller.Team == team;
}
catch
{
return false;
}
});
}
public static int GetTeamPlayerCount(CsTeam team)
{
return GetPlayersByTeam(team).Count();
}
public static int GetPlayerCountBySkill(Skills skills)
{
return playersByIndex.Values.Count(p => p.Skill == skills);

View file

@ -322,7 +322,31 @@ namespace src.utils
return !ff && !tae; // same team + FF off -> engine will zero this damage
}
public static bool TakeHealth(CCSPlayerPawn? pawn, int damage)
private static readonly ConcurrentDictionary<uint, (uint AttackerIndex, string? Weapon, int ExpiryTick)> pendingKillCredits = [];
public static void RegisterKillCredit(uint victimIndex, uint attackerIndex, string? weapon = null)
{
pendingKillCredits[victimIndex] = (attackerIndex, weapon, Server.TickCount + 64);
}
public static bool TryConsumeKillCredit(uint victimIndex, out uint attackerIndex, out string? weapon)
{
attackerIndex = 0;
weapon = null;
if (!pendingKillCredits.TryRemove(victimIndex, out var credit)) return false;
if (credit.ExpiryTick < Server.TickCount) return false;
attackerIndex = credit.AttackerIndex;
weapon = credit.Weapon;
return true;
}
public static void ClearKillCredits()
{
pendingKillCredits.Clear();
}
public static bool TakeHealth(CCSPlayerPawn? pawn, int damage, CCSPlayerController? damageAttacker = null, string? damageWeapon = null)
{
if (pawn == null || !pawn.IsValid || pawn.LifeState != (byte)LifeState_t.LIFE_ALIVE)
return false;
@ -363,6 +387,10 @@ namespace src.utils
if (pawn.Health <= 0)
{
if (damageAttacker != null && damageAttacker.IsValid && victim != null && victim.IsValid
&& damageAttacker.Index != victim.Index)
RegisterKillCredit(victim.Index, damageAttacker.Index, damageWeapon);
Server.NextFrame(() =>
{
if (pawn == null || !pawn.IsValid) return;
@ -374,6 +402,29 @@ namespace src.utils
return true;
}
public static void HideCarriedEntities(CCheckTransmitInfo info, CCSPlayerPawn? pawn)
{
if (pawn == null || !pawn.IsValid) return;
var weaponServices = pawn.WeaponServices;
if (weaponServices == null) return;
var activeWeapon = weaponServices.ActiveWeapon?.Value;
if (activeWeapon != null && activeWeapon.IsValid && info.TransmitEntities.Contains(activeWeapon.Index))
info.TransmitEntities.Remove(activeWeapon.Index);
if (weaponServices.MyWeapons == null) return;
foreach (var handle in weaponServices.MyWeapons)
{
var weapon = handle?.Value;
if (weapon == null || !weapon.IsValid) continue;
if (info.TransmitEntities.Contains(weapon.Index))
info.TransmitEntities.Remove(weapon.Index);
}
}
public static void ResetPrintHTML(CCSPlayerController? player)
{
if (player == null || !player.IsValid) return;