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
30
.github/en.md
vendored
30
.github/en.md
vendored
|
|
@ -358,6 +358,36 @@ This plugin uses content from the following projects:
|
|||
|
||||
## 📋 Changelog
|
||||
|
||||
<details>
|
||||
<summary><b>v1.2.2.b7</b></summary>
|
||||
|
||||
- #### General:
|
||||
- ###### Updated the gamedata signatures for the latest CS2 update (build 24134959) and bumped CounterStrikeSharp to 1.0.371. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Fixed a NullReferenceException thrown on weapon pickup when the weapon data pointed at freed schema memory. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### FullFoceUpdate has been changed to an optional setting in the configuration. Enabling it reduces the risk of PVS errors, but places a significant load on the server (disabled by default). [by: [@Juzlus](https://github.com/Juzlus)]
|
||||
|
||||
- #### Skill improvements:
|
||||
- ###### Ghost:
|
||||
- ###### Can now plant the C4. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Free Planter / Short Bomb:
|
||||
- ###### The on-screen bomb countdown now matches the configured detonation time (`mp_c4timer` is set at round start instead of only the blow time being overridden after the plant). [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Rich Boy:
|
||||
- ###### The money bonus now respects `mp_maxmoney` instead of being capped at a hardcoded 16000. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Second Chance:
|
||||
- ###### Now reliably respawns at base on a lethal hit, including fall damage (the revive moved to a pre-damage hook so the death is cancelled before it is committed). [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Shadow:
|
||||
- ###### Fixed a false "no suitable area" when teleporting behind a target at close range. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Radar Hack:
|
||||
- ###### Now reveals enemies only to the skill holder instead of the holder's whole team, and no longer reveals invisible or camouflaged enemies. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### C4 Camouflage:
|
||||
- ###### The disguised bomb carrier no longer appears on the enemy radar. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Hot Bomb:
|
||||
- ###### The "hot bomb" hint no longer shows in a round where nobody has the skill. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Jester:
|
||||
- ###### Fixes crashes that occur when a skill is being disabled. [by: [@Juzlus](https://github.com/Juzlus)]
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.2.2.b6</b></summary>
|
||||
|
||||
|
|
|
|||
30
.github/pl.md
vendored
30
.github/pl.md
vendored
|
|
@ -356,6 +356,36 @@ Plugin korzysta z zawartości następujących projektów:
|
|||
|
||||
## 📋 Lista Zmian
|
||||
|
||||
<details>
|
||||
<summary><b>v1.2.2.b7</b></summary>
|
||||
|
||||
- #### Ogólne:
|
||||
- ###### Zaktualizowano sygnatury gamedata do najnowszej aktualizacji CS2 (build 24134959) oraz zaktualizowano CounterStrikeSharp do wersji 1.0.371. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### FNaprawiono `NullReferenceException` występujący podczas podnoszenia broni, gdy dane broni wskazywały na zwolnioną pamięć schematu. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### `FullForceUpdate` został zmieniony na opcjonalne ustawienie w konfiguracji. Jego włączenie zmniejsza ryzyko błędów PVS, ale powoduje znaczne obciążenie serwera (domyślnie wyłączone). [by: [@Juzlus](https://github.com/Juzlus)]
|
||||
|
||||
- #### Poprawki mocy:
|
||||
- ###### Duszek:
|
||||
- ###### Teraz może podkładać C4. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Samowolka / Krótka Bomba:
|
||||
- ###### Odliczanie bomby wyświetlane na ekranie jest teraz zgodne z ustawionym czasem detonacji (`mp_c4timer`). [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Bogacz:
|
||||
- ###### Bonus za pieniądze teraz respektuje `mp_maxmoney` zamiast być ograniczony na sztywno do wartości 16000. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Druga Szansa:
|
||||
- ###### Teraz niezawodnie odradza gracza w bazie po otrzymaniu śmiertelnego obrażenia, również od obrażeń od upadku. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Cień:
|
||||
- ###### Naprawiono fałszywy komunikat "brak miejsca" podczas teleportacji za cel z bliskiej odległości. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Radarowiec:
|
||||
- ###### Teraz ujawnia przeciwników tylko posiadaczowi mocy zamiast całej jego drużynie oraz nie ujawnia już niewidzialnych ani zamaskowanych przeciwników. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### C4 Kamuflaż:
|
||||
- ###### Niewidzialny gracz niosący bombe nie pojawia się już na radarze przeciwników. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Gorąca bomba:
|
||||
- ###### Podpowiedź dotycząca "gorącej bomby" nie pojawia się już w rundach, w których nikt nie posiada tej mocy. [by: [@ByDexterTR](https://github.com/ByDexterTR)]
|
||||
- ###### Błazen:
|
||||
- ###### Naprawiono crashe występujące podczas wyłączania mocy. [by: [@Juzlus](https://github.com/Juzlus)]
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>v1.2.2.b6</b></summary>
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
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 {
|
||||
if (!jesters.TryGetValue(playerIndex, out var jester))
|
||||
{
|
||||
jester = new JesterInfo
|
||||
{
|
||||
PlayerIndex = playerIndex,
|
||||
Active = false,
|
||||
Timer = Instance.AddTimer(wait, () => ChangeMode(playerIndex), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE)
|
||||
});
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -7,6 +7,7 @@
|
|||
"SummaryAfterTheRound": true,
|
||||
"EnableBotSkills": true,
|
||||
"EnableBotKickDebug": false,
|
||||
"EnableFullForceUpdate": false,
|
||||
"DebugMode": false,
|
||||
"PerfMode": false,
|
||||
"AlternativeSkillButton": null,
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue