Skip to content

Commit d658f09

Browse files
authored
[l4d2_static_shotgun_spread] Restore patch central pellet on unload plugin (#913)
* [l4d2_static_shotgun_spread] Restore central bullet on unload - Added deletion of the `central pellet` patch when unloading the plugin. This patch is applied in-game, not in the ASM patch. The value is restored after unloading to prevent logic issues with other server settings. - Added a check for the `central pellet` patch offset. - Removed unnecessary type conversions and improved readability. - Minor plugin refactoring. * Code refactoring * Fix mistake
1 parent c299b61 commit d658f09

1 file changed

Lines changed: 122 additions & 99 deletions

File tree

addons/sourcemod/scripting/l4d2_static_shotgun_spread.sp

Lines changed: 122 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
#include <sourcemod>
55
#include <sourcescramble>
66

7-
#define GAMEDATA_FILE "code_patcher"
8-
#define KEY_SGSPREAD "sgspread"
9-
#define BULLET_MAX_SIZE 4
10-
#define DEBUG 0
7+
#define BULLET_MAX_SIZE 3
8+
#define GAMEDATA_FILE "code_patcher"
9+
#define KEY_SGSPREAD "sgspread"
1110

1211
// Original code & Notes: https://github.com/Jahze/l4d2_plugins/tree/master/spread_patch
1312
// Static Shotgun Spread leverages code_patcher (code_patcher.txt gamedata)
@@ -22,153 +21,177 @@ enum
2221
eWindows = 0,
2322
eLinux,
2423
/* eMac, joke:) */
24+
2525
ePlatform_Size
26-
}
26+
};
2727

2828
int
29-
g_ePlatform;
29+
g_ePlatform = eLinux;
3030

3131
static const int
32-
g_BulletOffsets[ePlatform_Size][BULLET_MAX_SIZE] = {
33-
{ 0xf, 0x21, 0x30, 0x3f }, // Windows
34-
{ 0x11, 0x22, 0x2f, 0x43 } // Linux
32+
g_iBulletOffsets[ePlatform_Size][BULLET_MAX_SIZE] = {
33+
{ 0xf, 0x21, 0x30 }, // Windows
34+
{ 0x11, 0x22, 0x2f } // Linux
3535
},
36-
g_FactorOffset[ePlatform_Size] = {
36+
g_iDegreeOffsets[ePlatform_Size] = {
37+
0x3f, // Windows
38+
0x43 // Linux
39+
},
40+
g_iFactorOffset[ePlatform_Size] = {
3741
0x36, // Windows
3842
0x34 // Linux
3943
},
40-
g_CenterPelletOffset[ePlatform_Size] = {
44+
g_iCenterPelletOffset[ePlatform_Size] = {
4145
-0x36, // Windows
4246
-0x1c // Linux
4347
};
4448

49+
Address
50+
g_pBullets[BULLET_MAX_SIZE] = {Address_Null, ...},
51+
g_pDegree = Address_Null,
52+
g_pFactor = Address_Null,
53+
g_pCenterPellet = Address_Null;
54+
4555
MemoryPatch
46-
g_hPatch_sgspread;
56+
g_hPatchSgSpread = null;
4757

4858
ConVar
49-
hRing1BulletsCvar,
50-
hRing1FactorCvar,
51-
hCenterPelletCvar;
59+
g_hCvarRing1Bullets = null,
60+
g_hCvarRing1Factor = null,
61+
g_hCvarCenterPellet = null;
5262

53-
public Plugin myinfo =
63+
public Plugin myinfo =
5464
{
5565
name = "L4D2 Static Shotgun Spread",
5666
author = "Jahze, Visor, A1m`, Rena",
57-
version = "1.6.1",
67+
version = "1.6.5",
5868
description = "Changes the values in the sgspread patch",
5969
url = "https://github.com/SirPlease/L4D2-Competitive-Rework"
6070
};
6171

6272
public void OnPluginStart()
6373
{
64-
Handle conf = LoadGameConfigFile(GAMEDATA_FILE);
65-
if (conf == null) {
74+
InitGameData();
75+
76+
g_hCvarRing1Bullets = CreateConVar("sgspread_ring1_bullets", "3", "Number of bullets for the first ring, the remaining bullets will be in the second ring.");
77+
g_hCvarRing1Factor = CreateConVar("sgspread_ring1_factor", "2", "Determines how far or closer the bullets will be from the center for the first ring.");
78+
g_hCvarCenterPellet = CreateConVar("sgspread_center_pellet", "1", "Center pellet: 0 - off, 1 - on.", _, true, 0.0, true, 1.0);
79+
80+
InitPlugin();
81+
}
82+
83+
void InitGameData()
84+
{
85+
Handle hConf = LoadGameConfigFile(GAMEDATA_FILE);
86+
if (hConf == null) {
6687
SetFailState("Missing gamedata \"" ... GAMEDATA_FILE ... "\"");
6788
}
68-
69-
g_hPatch_sgspread = MemoryPatch.CreateFromConf(conf, KEY_SGSPREAD);
70-
if (g_hPatch_sgspread == null || !g_hPatch_sgspread.Validate()) {
89+
90+
g_ePlatform = GameConfGetOffset(hConf, "OS");
91+
if (g_ePlatform == -1) {
92+
SetFailState("Failed to retrieve offset \"OS\"");
93+
}
94+
95+
g_hPatchSgSpread = MemoryPatch.CreateFromConf(hConf, KEY_SGSPREAD);
96+
if (g_hPatchSgSpread == null || !g_hPatchSgSpread.Validate()) {
7197
SetFailState("Failed to validate MemoryPatch \"" ... KEY_SGSPREAD ... "\"");
7298
}
73-
74-
if (!g_hPatch_sgspread.Enable()) {
75-
SetFailState("Failed to enable MemoryPatch \"" ... KEY_SGSPREAD ... "\"");
99+
100+
Address pFinalAddr = g_hPatchSgSpread.Address + view_as<Address>(g_iCenterPelletOffset[g_ePlatform]);
101+
int iCurrentValue = LoadFromAddress(pFinalAddr, NumberType_Int8);
102+
if (iCurrentValue != 1) {
103+
SetFailState("Center pellet offset is uncorrect! CheckByte: %x", iCurrentValue);
76104
}
77-
78-
g_ePlatform = GameConfGetOffset(conf, "OS");
79-
if (g_ePlatform == -1) {
80-
SetFailState("Failed to retrieve offset \"OS\"");
105+
106+
if (!g_hPatchSgSpread.Enable()) {
107+
SetFailState("Failed to enable MemoryPatch \"" ... KEY_SGSPREAD ... "\"");
81108
}
82-
83-
delete conf;
84-
85-
hRing1BulletsCvar = CreateConVar("sgspread_ring1_bullets", "3", "Number of bullets for the first ring, the remaining bullets will be in the second ring.");
86-
hRing1FactorCvar = CreateConVar("sgspread_ring1_factor", "2", "Determines how far or closer the bullets will be from the center for the first ring.");
87-
hCenterPelletCvar = CreateConVar("sgspread_center_pellet", "1", "Center pellet: 0 - off, 1 - on.", _, true, 0.0, true, 1.0);
88-
89-
hRing1BulletsCvar.AddChangeHook(OnRing1BulletsChange);
90-
hRing1FactorCvar.AddChangeHook(OnRing1FactorChange);
91-
hCenterPelletCvar.AddChangeHook(OnCenterPelletChange);
92-
93-
HotPatchBullets(hRing1BulletsCvar.IntValue);
94-
HotPatchFactor(hRing1FactorCvar.IntValue);
95-
HotPatchCenterPellet(hCenterPelletCvar.BoolValue);
109+
110+
delete hConf;
96111
}
97112

98-
static void HotPatchCenterPellet(bool newValue)
113+
void InitPlugin()
99114
{
100-
Address pAddr = g_hPatch_sgspread.Address;
101-
102-
int currentValue = LoadFromAddress(pAddr + view_as<Address>(g_CenterPelletOffset[g_ePlatform]), NumberType_Int8);
103-
104-
int bullets = hRing1BulletsCvar.IntValue;
105-
106-
#if DEBUG
107-
static bool IsFirstPatch = false;
108-
if (!IsFirstPatch) {
109-
PrintToServer("Center pellet offset is %s! CheckByte: %x", (currentValue == 0x01) ? "correct ": "uncorrect", currentValue);
110-
PrintToChatAll("Center pellet offset is %s! CheckByte: %x", (currentValue == 0x01) ? "correct ": "uncorrect", currentValue);
111-
IsFirstPatch = true;
115+
for (int i = 0; i < BULLET_MAX_SIZE; i++) {
116+
g_pBullets[i] = g_hPatchSgSpread.Address + view_as<Address>(g_iBulletOffsets[g_ePlatform][i]);
112117
}
113-
#endif
114-
115-
if (!!currentValue == newValue) {
116-
return;
117-
}
118-
119-
StoreToAddress(pAddr + view_as<Address>(g_CenterPelletOffset[g_ePlatform]), view_as<int>(newValue), NumberType_Int8);
120-
121-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][0]), bullets + (1 - view_as<int>(!newValue)), NumberType_Int8);
122-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][1]), bullets + (1 - view_as<int>(!newValue)), NumberType_Int8);
123-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][2]), bullets + (2 - view_as<int>(!newValue)), NumberType_Int8);
118+
119+
g_pDegree = g_hPatchSgSpread.Address + view_as<Address>(g_iDegreeOffsets[g_ePlatform]);
120+
g_pFactor = g_hPatchSgSpread.Address + view_as<Address>(g_iFactorOffset[g_ePlatform]);
121+
g_pCenterPellet = g_hPatchSgSpread.Address + view_as<Address>(g_iCenterPelletOffset[g_ePlatform]);
122+
123+
HotPatchBullets(g_hCvarRing1Bullets.IntValue);
124+
HotPatchFactor(g_hCvarRing1Factor.IntValue);
125+
HotPatchCenterPellet(g_hCvarCenterPellet.BoolValue);
126+
127+
g_hCvarRing1Bullets.AddChangeHook(OnRing1BulletsChange);
128+
g_hCvarRing1Factor.AddChangeHook(OnRing1FactorChange);
129+
g_hCvarCenterPellet.AddChangeHook(OnCenterPelletChange);
124130
}
125131

126-
static void HotPatchBullets(int nBullets)
132+
public void OnPluginEnd()
127133
{
128-
bool centerpellet = !hCenterPelletCvar.BoolValue;
129-
float degree = 0.0;
130-
131-
if (g_ePlatform == eWindows) {
132-
degree = 360.0 / float(nBullets);
133-
} else {
134-
degree = 360.0 / (2.0 * float(nBullets));
134+
if (g_pCenterPellet != Address_Null) {
135+
int iCurrentValue = LoadFromAddress(g_pCenterPellet, NumberType_Int8);
136+
137+
if (iCurrentValue != 1) {
138+
StoreToAddress(g_pCenterPellet, 1, NumberType_Int8);
139+
}
135140
}
136-
137-
Address pAddr = g_hPatch_sgspread.Address;
138-
139-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][0]), nBullets + (1 - view_as<int>(centerpellet)), NumberType_Int8);
140-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][1]), nBullets + (1 - view_as<int>(centerpellet)), NumberType_Int8);
141-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][2]), nBullets + (2 - view_as<int>(centerpellet)), NumberType_Int8);
142-
143-
StoreToAddress(pAddr + view_as<Address>(g_BulletOffsets[g_ePlatform][3]), view_as<int>(degree), NumberType_Int32);
144141
}
145142

146-
static void HotPatchFactor(int factor)
143+
void OnRing1BulletsChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue)
147144
{
148-
Address pAddr = g_hPatch_sgspread.Address;
145+
HotPatchBullets(hConVar.IntValue);
146+
}
149147

150-
if (g_ePlatform == eWindows) {
151-
StoreToAddress(pAddr + view_as<Address>(g_FactorOffset[eWindows]), view_as<int>(float(factor)), NumberType_Int32); //On windows need the float type !!!
152-
return;
148+
void OnRing1FactorChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue)
149+
{
150+
HotPatchFactor(hConVar.IntValue);
151+
}
152+
153+
void OnCenterPelletChange(ConVar hConVar, const char[] sOldValue, const char[] sNewValue)
154+
{
155+
HotPatchCenterPellet(hConVar.BoolValue);
156+
}
157+
158+
void HotPatchBullets(int iBullets)
159+
{
160+
PatchBullets(iBullets, g_hCvarCenterPellet.BoolValue);
161+
162+
float fBullets = float(iBullets);
163+
if (g_ePlatform == eLinux) {
164+
fBullets *= 2.0;
153165
}
154-
155-
StoreToAddress(pAddr + view_as<Address>(g_FactorOffset[eLinux]), factor, NumberType_Int32);
166+
167+
StoreToAddress(g_pDegree, view_as<int>(360.0 / fBullets), NumberType_Int32);
156168
}
157169

158-
void OnRing1BulletsChange(ConVar hCvar, const char[] oldVal, const char[] newVal)
170+
void HotPatchFactor(int iFactor)
159171
{
160-
int nBullets = StringToInt(newVal);
161-
HotPatchBullets(nBullets);
172+
// Asm patch on windows need the float type !
173+
int iSetFactor = (g_ePlatform == eWindows) ? view_as<int>(float(iFactor)) : iFactor;
174+
StoreToAddress(g_pFactor, iSetFactor, NumberType_Int32);
162175
}
163176

164-
void OnRing1FactorChange(ConVar hCvar, const char[] oldVal, const char[] newVal)
177+
void HotPatchCenterPellet(bool bNewValue)
165178
{
166-
int factor = StringToInt(newVal);
167-
HotPatchFactor(factor);
179+
bool iCurrentValue = LoadFromAddress(g_pCenterPellet, NumberType_Int8);
180+
if (iCurrentValue == bNewValue) {
181+
return;
182+
}
183+
184+
StoreToAddress(g_pCenterPellet, view_as<int>(bNewValue), NumberType_Int8);
185+
186+
PatchBullets(g_hCvarRing1Bullets.IntValue, bNewValue);
168187
}
169188

170-
void OnCenterPelletChange(ConVar hCvar, const char[] oldVal, const char[] newVal)
189+
void PatchBullets(int iBullets, bool bCenterPellet)
171190
{
172-
bool value = !!StringToInt(newVal);
173-
HotPatchCenterPellet(value);
191+
int iOffset1 = iBullets + (bCenterPellet ? 1 : 0);
192+
int iOffset2 = iBullets + (bCenterPellet ? 2 : 1);
193+
194+
StoreToAddress(g_pBullets[0], iOffset1, NumberType_Int8);
195+
StoreToAddress(g_pBullets[1], iOffset1, NumberType_Int8);
196+
StoreToAddress(g_pBullets[2], iOffset2, NumberType_Int8);
174197
}

0 commit comments

Comments
 (0)