v1.2.4.b3
#### Compatibility * **CounterStrikeSharp v1.0.375** - after the CS2 update, RayTraceImpl stopped working. All traces now use CounterStrikeSharp's native `Trace` API, so **RayTrace-CSS-API and RayTrace-MM are no longer required**. `RayTraceApi.dll` was removed from the project and the Ray-Trace step was removed from the README install guide. * **Gamedata** - CS2 1.41.8.3 broke the Windows `HEGrenadeProjectile_CreateFunc`, `CMolotovProjectile_CreateFunc` and `SnapViewAngles` signatures, and the Linux `SmokeGrenadeProjectile_CreateFunc` signature. `INetworkGameServer_Slots` moved from 584 to 616 on both platforms; the old value read a garbage size and pointer without throwing. All signatures now match exactly one function on both platforms, and the offsets were confirmed at runtime. #### Skills * **No Recoil** - the client received `weapon_accuracy_nospread`, but the server still applied spread, so the crosshair looked straight while bullets spread. The weapon's spread and inaccuracy values are now also zeroed on the server for that tick. Weapon data is shared per weapon type, so a weapon type is only patched while no other living player holds the same type; the values are restored on the next tick, at map end and on unload. * **Long Zeus** - kills went through suicide, so they did not count as Zeus kills and the ragdoll was marked `world`. The suicide damage is now rewritten to the attacker's Zeus with shock damage, so the engine credits the kill natively (killfeed, kill sound, scoreboard, ragdoll). The victim's body also gets the electric shock effect, which the engine only plays on real Taser hits. * **Long Knife** - long-range slashes now draw a tracer to where they hit. * **Fragile Bomb** - the bomb position was only stored by the `bomb_planted` event, which is sent only to skills active at that moment, so receiving the skill after the plant never detected hits. The planted bomb is now looked up when needed. Hits were also measured from the impact point, so shots passing through the bomb and landing behind it were missed; the bullet's path is now checked instead. * **Tripwire** - wires stayed visible after the skill changed. Beams were hidden from clients in the same tick they were cleared, so the "hide" update never reached the client. Beams are no longer hidden from clients before removal. #### Reliability * **Skill distribution** - an exception thrown during skill assignment aborted the round's distribution silently. It is now caught, logged and retried. Spectators without a pawn no longer count as connected players, which had caused unnecessary retries.
This commit is contained in:
parent
20dafd2a7c
commit
71ef1acbe9
24 changed files with 446 additions and 159 deletions
|
|
@ -7,7 +7,6 @@ using CounterStrikeSharp.API.Modules.Memory;
|
|||
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using RayTraceAPI;
|
||||
using src.player.skills;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
|
@ -98,14 +97,14 @@ namespace src.player
|
|||
{
|
||||
lock (setLock)
|
||||
{
|
||||
bool isWarmup = Instance.GameRules == null || Instance.GameRules.WarmupPeriod == true;
|
||||
bool isWarmup = IsWarmupPeriod();
|
||||
isTransmitRegistered = false;
|
||||
setSkillRetries = 0;
|
||||
SkillUtils.ClearKillCredits();
|
||||
SkillUtils.ClearCurses();
|
||||
Instance.AddTimer(.1f, () => DisableAll(), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
foreach (var player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && !p.IsHLTV && p.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist))
|
||||
foreach (var player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && !p.IsHLTV && InPlayingTeam(p)))
|
||||
{
|
||||
var skillPlayer = PlayerManager.GetPlayerByIndex(player!.Index);
|
||||
if (skillPlayer == null) continue;
|
||||
|
|
@ -115,18 +114,21 @@ namespace src.player
|
|||
|
||||
Instance.RemoveListener<CheckTransmit>(CheckTransmit);
|
||||
int freezetime = SkillUtils.CvarValue("mp_freezetime", 0);
|
||||
freezeTimeEnd = DateTime.Now.AddSeconds(freezetime + (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0));
|
||||
int introDelay = IsTeamIntroPeriod() ? 7 : 0;
|
||||
freezeTimeEnd = DateTime.Now.AddSeconds(freezetime + introDelay);
|
||||
|
||||
setSkillTimer?.Kill();
|
||||
|
||||
if (isWarmup)
|
||||
{
|
||||
setSkillTimer = Instance?.AddTimer(1f, SetSkill, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
Debug.WriteToDebug("RoundStart: warmup, SetSkill scheduled in 1.00s.", DebugCategory.Round);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
float timeToDraw = (Instance?.GameRules?.TeamIntroPeriod == true ? 7 : 0) + Math.Max(freezetime - Config.LoadedConfig.SkillTimeBeforeStart, 0) + .3f;
|
||||
float timeToDraw = introDelay + Math.Max(freezetime - Config.LoadedConfig.SkillTimeBeforeStart, 0) + .3f;
|
||||
setSkillTimer = Instance?.AddTimer(timeToDraw, SetSkill, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
Debug.WriteToDebug($"RoundStart: SetSkill scheduled in {timeToDraw:F2}s (freezetime={freezetime}, intro={introDelay}, timer={(setSkillTimer == null ? "null" : "ok")}).", DebugCategory.Round);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -293,7 +295,22 @@ namespace src.player
|
|||
private static void SetSkill()
|
||||
{
|
||||
long perfStart = PerfLog.Start();
|
||||
SetSkillCore();
|
||||
|
||||
try
|
||||
{
|
||||
SetSkillCore();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteToDebug($"SetSkill threw: {ex}", DebugCategory.Skill);
|
||||
|
||||
if (setSkillRetries < MaxSetSkillRetries)
|
||||
{
|
||||
setSkillRetries++;
|
||||
setSkillTimer = Instance?.AddTimer(.5f, SetSkill, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
PerfLog.End("SetSkill total", perfStart, 2.0);
|
||||
}
|
||||
|
||||
|
|
@ -472,10 +489,46 @@ namespace src.player
|
|||
|
||||
private static int CountConnectedPlayers()
|
||||
{
|
||||
try { return Utilities.GetPlayers().Count(p => p != null && p.IsValid && !p.IsHLTV); }
|
||||
try
|
||||
{
|
||||
return Utilities.GetPlayers().Count(p =>
|
||||
{
|
||||
if (p == null || !p.IsValid || p.IsHLTV) return false;
|
||||
var pawn = p.PlayerPawn?.Value;
|
||||
return pawn != null && pawn.IsValid;
|
||||
});
|
||||
}
|
||||
catch { return 0; }
|
||||
}
|
||||
|
||||
private static bool InPlayingTeam(CCSPlayerController player)
|
||||
{
|
||||
try { return player.Team is CsTeam.CounterTerrorist or CsTeam.Terrorist; }
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
private static bool IsWarmupPeriod()
|
||||
{
|
||||
try
|
||||
{
|
||||
var gameRules = Instance?.GameRules;
|
||||
if (gameRules == null || gameRules.Handle == IntPtr.Zero) return true;
|
||||
return gameRules.WarmupPeriod;
|
||||
}
|
||||
catch { return true; }
|
||||
}
|
||||
|
||||
private static bool IsTeamIntroPeriod()
|
||||
{
|
||||
try
|
||||
{
|
||||
var gameRules = Instance?.GameRules;
|
||||
if (gameRules == null || gameRules.Handle == IntPtr.Zero) return false;
|
||||
return gameRules.TeamIntroPeriod;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
private static void SetSkillCore()
|
||||
{
|
||||
setSkillTimer = null;
|
||||
|
|
@ -484,7 +537,7 @@ namespace src.player
|
|||
if (Instance == null) return;
|
||||
|
||||
// GameRules null = not ready; keep polling so skills land right after warmup ends.
|
||||
if (Instance.GameRules == null || Instance.GameRules.WarmupPeriod == true)
|
||||
if (IsWarmupPeriod())
|
||||
{
|
||||
if (++gameRulesPolls % 10 == 0)
|
||||
Debug.WriteToDebug($"SetSkill waiting: gameRules={(Instance.GameRules == null ? "null" : "warmup")}, poll {gameRulesPolls}.", DebugCategory.Skill);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue