Add optional full force client update path
- Updated markdown files. - Added FullForceUpdate as an optional feature. - Jester: Fixes crashes that occur when a skill is being disabled.
This commit is contained in:
parent
559e7be23f
commit
e490b7f3df
20 changed files with 353 additions and 28 deletions
|
|
@ -26,5 +26,23 @@
|
|||
"windows": "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B DA 48 8B F1 48 8D 55",
|
||||
"linux": "55 48 89 E5 41 57 49 89 FF 48 89 F7 41 56 41 55 41 54 53 48 81 EC ? ? ? ? E8"
|
||||
}
|
||||
},
|
||||
"CServerSideClient_m_nDeltaTick": {
|
||||
"offsets": {
|
||||
"windows": 348,
|
||||
"linux": 348
|
||||
}
|
||||
},
|
||||
"INetworkGameServer_Slots": {
|
||||
"offsets": {
|
||||
"windows": 584,
|
||||
"linux": 584
|
||||
}
|
||||
},
|
||||
"INetworkServerService_GetIGameServer": {
|
||||
"offsets": {
|
||||
"windows": 23,
|
||||
"linux": 24
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace src
|
|||
public static readonly ConcurrentDictionary<string, byte> ActiveSkillsThisRound = new();
|
||||
|
||||
public override string ModuleName => "[CS2] [ jRandomSkills ]";
|
||||
public override string ModuleAuthor => "D3X, Juzlus";
|
||||
public override string ModuleAuthor => "D3X (Original), Juzlus (Modifier), ByDexterTR (Contributor)";
|
||||
public override string ModuleDescription => "Plugin adds random skills every round for CS2 by D3X. Modified by Juzlus.";
|
||||
public override string ModuleVersion => "1.2.2.b7";
|
||||
|
||||
|
|
|
|||
|
|
@ -1093,24 +1093,31 @@ namespace src.player
|
|||
if (randomSkill.Skill == Skills.Illiterate)
|
||||
Illiterate.Enable();
|
||||
|
||||
var playerIndex = player.Index;
|
||||
Instance?.AddTimer(.2f, () =>
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
var playerTarget = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
if (playerTarget == null || !playerTarget.IsValid) return;
|
||||
|
||||
if (randomSkill.Display)
|
||||
SkillUtils.PrintToChat(player, $"{ChatColors.DarkRed}{player.GetSkillName(randomSkill.Skill)}{ChatColors.Lime}: {player.GetSkillDescription(randomSkill.Skill)}",
|
||||
border: !Utilities.GetPlayers().Any(p => p != null && p.IsValid && p.Team == player.Team && p != player) ? "tb" : "t");
|
||||
SkillUtils.PrintToChat(playerTarget, $"{ChatColors.DarkRed}{playerTarget.GetSkillName(randomSkill.Skill)}{ChatColors.Lime}: {playerTarget.GetSkillDescription(randomSkill.Skill)}",
|
||||
border: !Utilities.GetPlayers().Any(p => p != null && p.IsValid && p.Team == playerTarget.Team && p != playerTarget) ? "tb" : "t");
|
||||
|
||||
if (SkillsInfo.GetValue<bool>(randomSkill.Skill, "disableOnFreezeTime") && SkillUtils.IsFreezeTime())
|
||||
Instance?.AddTimer(Config.LoadedConfig.SkillTimeBeforeStart, () =>
|
||||
{
|
||||
if (PlayerManager.GetPlayerByIndex(player!.Index)?.Skill != randomSkill.Skill) return;
|
||||
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]);
|
||||
var playerTarget = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
if (playerTarget == null || !playerTarget.IsValid) return;
|
||||
|
||||
if (PlayerManager.GetPlayerByIndex(playerTarget!.Index)?.Skill != randomSkill.Skill) return;
|
||||
Debug.WriteToDebug("Enabling skill after freeze time: " + randomSkill.Skill);
|
||||
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [playerTarget]);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
else
|
||||
{
|
||||
if (PlayerManager.GetPlayerByIndex(player!.Index)?.Skill != randomSkill.Skill) return;
|
||||
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [player]);
|
||||
if (PlayerManager.GetPlayerByIndex(playerTarget!.Index)?.Skill != randomSkill.Skill) return;
|
||||
Debug.WriteToDebug("Enabling skill: " + randomSkill.Skill);
|
||||
Instance?.SkillAction(randomSkill.Skill.ToString(), "EnableSkill", [playerTarget]);
|
||||
}
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
|
|
|
|||
|
|
@ -159,6 +159,8 @@ namespace src.player.skills
|
|||
|
||||
invisiblePlayers.TryAdd(player.Index, 0);
|
||||
SkillUtils.SetPlayerInvisibility(player, .5f);
|
||||
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ namespace src.player.skills
|
|||
|
||||
if (EntityManager.GetPlayerEntities(player.Index, "empty_prop").Count == 0)
|
||||
CreatePlayerPosProp(player);
|
||||
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
private static void CreatePlayerPosProp(CCSPlayerController player)
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ namespace src.player.skills
|
|||
|
||||
SkillUtils.TryGiveWeapon(player, CsItem.SmokeGrenade);
|
||||
SkillUtils.UpdateGrenadeCount(player, CsItem.SmokeGrenade, grenadeLimit);
|
||||
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ namespace src.player.skills
|
|||
|
||||
mainSkillTimer ??= Instance.AddTimer(2.5f, () => UpdateAllTrails(),
|
||||
CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT | CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
private static void UpdateAllTrails()
|
||||
|
|
|
|||
|
|
@ -53,18 +53,17 @@ namespace src.player.skills
|
|||
var jester = GetJesterInfo(player.Index);
|
||||
if (jester == null) return;
|
||||
|
||||
jester.Generation++;
|
||||
jester.Active = false;
|
||||
if (jester.Timer != null)
|
||||
{
|
||||
jester.Timer.Kill();
|
||||
jester.Timer = null;
|
||||
}
|
||||
jester.Timer = null;
|
||||
|
||||
jesters.TryRemove(player.Index, out _);
|
||||
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
SetPlayerColor(player, true);
|
||||
jesters.TryRemove(player.Index, out _);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -154,23 +153,37 @@ namespace src.player.skills
|
|||
|
||||
uint playerIndex = player.Index;
|
||||
|
||||
jesters.TryAdd(playerIndex, new JesterInfo {
|
||||
PlayerIndex = playerIndex,
|
||||
Active = false,
|
||||
Timer = Instance.AddTimer(wait, () => ChangeMode(playerIndex), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE)
|
||||
});
|
||||
if (!jesters.TryGetValue(playerIndex, out var jester))
|
||||
{
|
||||
jester = new JesterInfo
|
||||
{
|
||||
PlayerIndex = playerIndex,
|
||||
Active = false,
|
||||
Generation = 0
|
||||
};
|
||||
|
||||
jesters[playerIndex] = jester;
|
||||
}
|
||||
|
||||
jester.Generation++;
|
||||
int generation = jester.Generation;
|
||||
|
||||
jester.Timer = Instance.AddTimer(wait, () =>
|
||||
{
|
||||
if (!jesters.TryGetValue(playerIndex, out var info))
|
||||
return;
|
||||
|
||||
if (info.Generation != generation)
|
||||
return;
|
||||
|
||||
ChangeMode(playerIndex);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private static void ChangeMode(uint playerIndex, bool? forceActive = null)
|
||||
{
|
||||
if (!jesters.TryGetValue(playerIndex, out var jester)) return;
|
||||
|
||||
if (jester.Timer != null)
|
||||
{
|
||||
jester.Timer?.Kill();
|
||||
jester.Timer = null;
|
||||
}
|
||||
|
||||
var player = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
if (player == null || !player.IsValid || player.LifeState != (byte)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
|
|
@ -194,7 +207,19 @@ namespace src.player.skills
|
|||
var maxTime = SkillsInfo.GetValue<float>(skillName, "maxTime");
|
||||
float wait = (float)Instance.Random.NextDouble() * (maxTime - minTime) + minTime;
|
||||
|
||||
jester.Timer = Instance.AddTimer(wait, () => ChangeMode(playerIndex), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
jester.Generation++;
|
||||
int generation = jester.Generation;
|
||||
|
||||
jester.Timer = Instance.AddTimer(wait, () =>
|
||||
{
|
||||
if (!jesters.TryGetValue(playerIndex, out var info))
|
||||
return;
|
||||
|
||||
if (info.Generation != generation)
|
||||
return;
|
||||
|
||||
ChangeMode(playerIndex);
|
||||
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
}
|
||||
|
||||
private static void SetPlayerColor(CCSPlayerController? player, bool forceDisable = false)
|
||||
|
|
@ -205,9 +230,9 @@ namespace src.player.skills
|
|||
if (pawn == null || !pawn.IsValid) return;
|
||||
|
||||
var jester = GetJesterInfo(player.Index);
|
||||
if (jester == null) return;
|
||||
if (!forceDisable && jester == null) return;
|
||||
|
||||
var color = jester.Active && !forceDisable ? Color.FromArgb(255, 128, 0, 128) : Color.FromArgb(255, 255, 255, 255);
|
||||
var color = jester?.Active == true && !forceDisable ? Color.FromArgb(255, 128, 0, 128) : Color.FromArgb(255, 255, 255, 255);
|
||||
pawn.Render = color;
|
||||
Utilities.SetStateChanged(pawn, "CBaseModelEntity", "m_clrRender");
|
||||
}
|
||||
|
|
@ -249,6 +274,7 @@ namespace src.player.skills
|
|||
{
|
||||
public required uint PlayerIndex { get; set; }
|
||||
public bool Active { get; set; } = false;
|
||||
public int Generation { get; set; } = 0;
|
||||
public Timer? Timer { get; set; } = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,8 @@ namespace src.player.skills
|
|||
|
||||
if (EntityManager.GetPlayerEntities(player.Index, "empty_prop").Count == 0)
|
||||
CreatePlayerPosProp(player);
|
||||
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ namespace src.player.skills
|
|||
public static void EnableSkill(CCSPlayerController _)
|
||||
{
|
||||
Event.EnableTransmit();
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@ namespace src.player.skills
|
|||
|
||||
if (glows.IsEmpty)
|
||||
SetGlowEffectForAll();
|
||||
|
||||
SkillUtils.ForceFullUpdateToAll();
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
|
|
|
|||
107
jRandomSkills - SRC Files/src/utils/CServerSideClient.cs
Normal file
107
jRandomSkills - SRC Files/src/utils/CServerSideClient.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// https://discord.com/channels/1160907911501991946/1508172390863994910/1508180670659166348
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
|
||||
namespace jRandomSkills.src.utils
|
||||
{
|
||||
|
||||
#region Native Structs
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct CUtlMemory<T> where T : unmanaged
|
||||
{
|
||||
public T* m_pMemory;
|
||||
public int m_nAllocationCount;
|
||||
public int m_nGrowSize;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct CUtlVector<T> where T : unmanaged
|
||||
{
|
||||
public int m_Size;
|
||||
public CUtlMemory<T> m_Memory;
|
||||
|
||||
public int Count => m_Size;
|
||||
|
||||
public ref T Element(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_Size)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
if (m_Memory.m_pMemory == null)
|
||||
throw new NullReferenceException("m_pMemory is null. The vector is empty or the GameData offset is outdated.");
|
||||
|
||||
return ref m_Memory.m_pMemory[index];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Network Services
|
||||
|
||||
public class INetworkServerService : NativeObject
|
||||
{
|
||||
private readonly VirtualFunctionWithReturn<nint, nint> GetIGameServerFunc;
|
||||
|
||||
public INetworkServerService() : base(NativeAPI.GetValveInterface(0, "NetworkServerService_001"))
|
||||
{
|
||||
GetIGameServerFunc = new VirtualFunctionWithReturn<nint, nint>(Handle, GameData.GetOffset("INetworkServerService_GetIGameServer"));
|
||||
}
|
||||
|
||||
public INetworkGameServer GetIGameServer()
|
||||
{
|
||||
return new INetworkGameServer(GetIGameServerFunc.Invoke(Handle));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe class INetworkGameServer(nint ptr) : NativeObject(ptr)
|
||||
{
|
||||
private static readonly int SlotsOffset = GameData.GetOffset("INetworkGameServer_Slots");
|
||||
|
||||
private ref CUtlVector<nint> Slots => ref Unsafe.AsRef<CUtlVector<nint>>((void*)(Handle + SlotsOffset));
|
||||
|
||||
public CServerSideClient? GetClientBySlot(int slot)
|
||||
{
|
||||
if (Handle == nint.Zero)
|
||||
return null;
|
||||
|
||||
if (slot < 0 || slot >= Slots.Count || Slots.m_Memory.m_pMemory == null)
|
||||
return null;
|
||||
|
||||
var ptr = Slots.Element(slot);
|
||||
|
||||
if (ptr == nint.Zero)
|
||||
return null;
|
||||
|
||||
return new CServerSideClient(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CServerSideClient
|
||||
|
||||
public unsafe class CServerSideClient(nint ptr) : NativeObject(ptr)
|
||||
{
|
||||
private static readonly int m_nDeltaTick = GameData.GetOffset("CServerSideClient_m_nDeltaTick");
|
||||
|
||||
private ref T Field<T>(int offset) where T : unmanaged
|
||||
{
|
||||
return ref Unsafe.AsRef<T>((void*)(Handle + offset));
|
||||
}
|
||||
|
||||
public int DeltaTick
|
||||
{
|
||||
get => Field<int>(m_nDeltaTick);
|
||||
set => Field<int>(m_nDeltaTick) = value;
|
||||
}
|
||||
|
||||
public void ForceFullUpdate() => DeltaTick = -1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
@ -79,6 +79,7 @@ namespace src.utils
|
|||
public bool SummaryAfterTheRound { get; set; }
|
||||
public bool EnableBotSkills { get; set; }
|
||||
public bool EnableBotKickDebug { get; set; }
|
||||
public bool EnableFullForceUpdate { get; set; }
|
||||
public bool DebugMode { get; set; }
|
||||
public bool PerfMode { get; set; }
|
||||
public string? AlternativeSkillButton { get; set; }
|
||||
|
|
@ -107,6 +108,7 @@ namespace src.utils
|
|||
SummaryAfterTheRound = true;
|
||||
EnableBotSkills = true;
|
||||
EnableBotKickDebug = false;
|
||||
EnableFullForceUpdate = false;
|
||||
DebugMode = false;
|
||||
PerfMode = false;
|
||||
AlternativeSkillButton = null;
|
||||
|
|
|
|||
|
|
@ -333,6 +333,79 @@ namespace src.utils
|
|||
return EntityManager.CreateTrackedTrigger(ownerPlayerIndex, name, radius, pos);
|
||||
}
|
||||
|
||||
public static void ForceFullUpdate(CCSPlayerController player, List<(uint PlayerIndex, QAngle LastAngle)>? batchList = null, INetworkGameServer? networkGameServer = null)
|
||||
{
|
||||
if (!Config.LoadedConfig.EnableFullForceUpdate) return;
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var pawn = player.PlayerPawn?.Value;
|
||||
if (pawn == null || !pawn.IsValid || pawn.AbsOrigin == null) return;
|
||||
|
||||
QAngle lastAngle = new(pawn.V_angle.X, pawn.V_angle.Y, pawn.V_angle.Z);
|
||||
|
||||
networkGameServer ??= new INetworkServerService().GetIGameServer();
|
||||
|
||||
var client = networkGameServer.GetClientBySlot(player.Slot);
|
||||
if (client == null) return;
|
||||
|
||||
client.ForceFullUpdate();
|
||||
// Only skip the angle restore when the captured view is a spawn-time (0,0,0) placeholder;
|
||||
// a genuine angle with a single zero component (e.g. yaw exactly 0) must still be restored.
|
||||
if (lastAngle.X == 0 && lastAngle.Y == 0 && lastAngle.Z == 0) return;
|
||||
|
||||
uint playerIndex = player.Index;
|
||||
|
||||
if (batchList != null)
|
||||
{
|
||||
batchList.Add((playerIndex, lastAngle));
|
||||
return;
|
||||
}
|
||||
|
||||
jRandomSkills.Instance.AddTickTimer(3, () =>
|
||||
{
|
||||
var target = Utilities.GetPlayerFromIndex((int)playerIndex);
|
||||
if (target == null || !target.IsValid) return;
|
||||
|
||||
var targetPawn = target.PlayerPawn?.Value;
|
||||
if (targetPawn == null || !targetPawn.IsValid || targetPawn.AbsOrigin == null) return;
|
||||
|
||||
targetPawn.Look(lastAngle);
|
||||
});
|
||||
}
|
||||
|
||||
private static int lastForceFullUpdateAll = int.MinValue;
|
||||
|
||||
public static void ForceFullUpdateToAll()
|
||||
{
|
||||
if (!Config.LoadedConfig.EnableFullForceUpdate) return;
|
||||
|
||||
int tickCount = Server.TickCount;
|
||||
if (tickCount == lastForceFullUpdateAll) return;
|
||||
|
||||
lastForceFullUpdateAll = tickCount;
|
||||
var playersToRestore = new List<(uint PlayerIndex, QAngle LastAngle)>();
|
||||
|
||||
INetworkGameServer networkGameServer = new INetworkServerService().GetIGameServer();
|
||||
foreach (var player in Utilities.GetPlayers())
|
||||
ForceFullUpdate(player, playersToRestore, networkGameServer);
|
||||
|
||||
if (playersToRestore.Count <= 0) return;
|
||||
|
||||
jRandomSkills.Instance.AddTickTimer(3, () =>
|
||||
{
|
||||
foreach (var item in playersToRestore)
|
||||
{
|
||||
var target = Utilities.GetPlayerFromIndex((int)item.PlayerIndex);
|
||||
if (target == null || !target.IsValid) continue;
|
||||
|
||||
var targetPawn = target.PlayerPawn?.Value;
|
||||
if (targetPawn == null || !targetPawn.IsValid || targetPawn.AbsOrigin == null) continue;
|
||||
|
||||
targetPawn.Look(item.LastAngle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static bool SetHealth(CCSPlayerPawn? pawn, int newHealth, int? maxHealth = null)
|
||||
{
|
||||
if (pawn == null || !pawn.IsValid)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue