1
1
#include < amxmodx>
2
- #include < hamsandwich>
3
2
#include < fakemeta>
3
+ #include < hamsandwich>
4
4
#include < reapi>
5
5
6
6
# define PLUGIN " [API] Player Model"
7
7
# define VERSION " 1.0.0"
8
8
# define AUTHOR " Hedgehog Fog"
9
9
10
+ # define ERROR_MSG_NOT_CONNECTED " User %d is not connected"
11
+
10
12
# define MAX_SEQUENCES 101
11
13
12
- new g_iszModelClassname ;
14
+ new g_iszSubModelClassname ;
13
15
14
16
new g_rgszDefaultPlayerModel[MAX_PLAYERS + 1 ][32 ];
15
17
new g_rgszCurrentPlayerModel[MAX_PLAYERS + 1 ][256 ];
16
18
new g_rgszCustomPlayerModel[MAX_PLAYERS + 1 ][256 ];
17
19
new g_rgiPlayerAnimationIndex[MAX_PLAYERS + 1 ];
20
+ new g_pPlayerSubModel[MAX_PLAYERS + 1 ];
18
21
new bool: g_rgbPlayerUseCustomModel[MAX_PLAYERS + 1 ];
19
22
20
23
new Trie: g_itPlayerSequenceModelIndexes = Invalid_Trie;
21
24
new Trie: g_itPlayerSequences = Invalid_Trie;
22
- new g_pPlayerSubModel[MAX_PLAYERS + 1 ];
23
-
24
- new gmsgClCorpse;
25
25
26
26
public plugin_precache () {
27
- g_iszModelClassname = engfunc (EngFunc_AllocString, " info_target" );
27
+ g_iszSubModelClassname = engfunc (EngFunc_AllocString, " info_target" );
28
28
g_itPlayerSequenceModelIndexes = TrieCreate ();
29
29
g_itPlayerSequences = TrieCreate ();
30
30
}
31
31
32
32
public plugin_init () {
33
33
register_plugin (PLUGIN, VERSION, AUTHOR);
34
34
35
- gmsgClCorpse = get_user_msgid (" ClCorpse" );
36
-
37
35
register_forward (FM_SetClientKeyValue, " FMHook_SetClientKeyValue" );
38
36
39
37
RegisterHamPlayer (Ham_Spawn, " HamHook_Player_Spawn_Post" , .Post = 1 );
40
38
RegisterHamPlayer (Ham_Player_PostThink, " HamHook_Player_PostThink_Post" , .Post = 1 );
41
39
42
40
RegisterHookChain (RG_CBasePlayer_SetAnimation, " HC_Player_SetAnimation" );
43
41
44
- register_message (gmsgClCorpse , " Message_ClCorpse" );
42
+ register_message (get_user_msgid ( " ClCorpse " ) , " Message_ClCorpse" );
45
43
}
46
44
47
45
public plugin_natives () {
@@ -57,19 +55,43 @@ public plugin_natives() {
57
55
register_native (" PlayerModel_PrecacheAnimation" , " Native_PrecacheAnimation" );
58
56
}
59
57
58
+ public plugin_end () {
59
+ TrieDestroy (g_itPlayerSequenceModelIndexes);
60
+ TrieDestroy (g_itPlayerSequences);
61
+ }
62
+
63
+ // ANCHOR: Natives
64
+
60
65
public Native_GetPlayerModel (iPluginId, iArgc) {
61
66
new pPlayer = get_param (1 );
67
+
68
+ if (! is_user_connected (pPlayer)) {
69
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
70
+ return ;
71
+ }
72
+
62
73
set_string (2 , g_rgszCustomPlayerModel[pPlayer], get_param (3 ));
63
74
}
64
75
65
76
public Native_GetCurrentPlayerModel (iPluginId, iArgc) {
66
77
new pPlayer = get_param (1 );
78
+
79
+ if (! is_user_connected (pPlayer)) {
80
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
81
+ return ;
82
+ }
83
+
67
84
set_string (2 , g_rgszCurrentPlayerModel[pPlayer], get_param (3 ));
68
85
}
69
86
70
87
public Native_GetPlayerEntity (iPluginId, iArgc) {
71
88
new pPlayer = get_param (1 );
72
89
90
+ if (! is_user_connected (pPlayer)) {
91
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
92
+ return 0 ;
93
+ }
94
+
73
95
if (g_pPlayerSubModel[pPlayer] && @PlayerSubModel_IsActive (g_pPlayerSubModel[pPlayer])) {
74
96
return g_pPlayerSubModel[pPlayer];
75
97
}
@@ -80,27 +102,55 @@ public Native_GetPlayerEntity(iPluginId, iArgc) {
80
102
public bool: Native_HasCustomPlayerModel (iPluginId, iArgc) {
81
103
new pPlayer = get_param (1 );
82
104
105
+ if (! is_user_connected (pPlayer)) {
106
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
107
+ return false ;
108
+ }
109
+
83
110
return g_rgbPlayerUseCustomModel[pPlayer];
84
111
}
85
112
86
113
public Native_SetPlayerModel (iPluginId, iArgc) {
87
114
new pPlayer = get_param (1 );
115
+
116
+ if (! is_user_connected (pPlayer)) {
117
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
118
+ return ;
119
+ }
120
+
88
121
get_string (2 , g_rgszCustomPlayerModel[pPlayer], charsmax (g_rgszCustomPlayerModel[]));
89
122
}
90
123
91
124
public Native_ResetPlayerModel (iPluginId, iArgc) {
92
125
new pPlayer = get_param (1 );
126
+
127
+ if (! is_user_connected (pPlayer)) {
128
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
129
+ return ;
130
+ }
131
+
93
132
@Player_ResetModel (pPlayer);
94
133
}
95
134
96
135
public Native_UpdatePlayerModel (iPluginId, iArgc) {
97
136
new pPlayer = get_param (1 );
137
+
138
+ if (! is_user_connected (pPlayer)) {
139
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
140
+ return ;
141
+ }
142
+
98
143
@Player_UpdateCurrentModel (pPlayer);
99
144
}
100
145
101
146
public Native_SetPlayerSequence (iPluginId, iArgc) {
102
147
new pPlayer = get_param (1 );
103
148
149
+ if (! is_user_connected (pPlayer)) {
150
+ log_error (AMX_ERR_NATIVE, ERROR_MSG_NOT_CONNECTED, pPlayer);
151
+ return 0 ;
152
+ }
153
+
104
154
static szSequence[MAX_RESOURCE_PATH_LENGTH];
105
155
get_string (2 , szSequence, charsmax (szSequence));
106
156
@@ -113,6 +163,8 @@ public Native_PrecacheAnimation(iPluginId, iArgc) {
113
163
return PrecachePlayerAnimation (szAnimation);
114
164
}
115
165
166
+ // ANCHOR: Hooks and Forwards
167
+
116
168
public client_connect (pPlayer) {
117
169
copy (g_rgszCustomPlayerModel[pPlayer], charsmax (g_rgszCustomPlayerModel[]), NULL_STRING);
118
170
copy (g_rgszDefaultPlayerModel[pPlayer], charsmax (g_rgszDefaultPlayerModel[]), NULL_STRING);
@@ -128,19 +180,24 @@ public client_disconnected(pPlayer) {
128
180
}
129
181
}
130
182
131
- public Message_ClCorpse (iMsgId, iMsgDest, pPlayer) {
132
- new pTargetPlayer = get_msg_arg_int (12 );
133
- if (g_rgbPlayerUseCustomModel[pTargetPlayer] || g_rgiPlayerAnimationIndex[pTargetPlayer]) {
134
- set_msg_arg_string (1 , g_rgszCurrentPlayerModel[pTargetPlayer]);
183
+ public FMHook_SetClientKeyValue (pPlayer, const szInfoBuffer[], const szKey[], const szValue[]) {
184
+ if (equal (szKey, " model" )) {
185
+ copy (g_rgszDefaultPlayerModel[pPlayer], charsmax (g_rgszDefaultPlayerModel[]), szValue);
186
+
187
+ if (! equal (g_rgszCurrentPlayerModel[pPlayer], NULL_STRING)) {
188
+ return FMRES_SUPERCEDE;
189
+ }
190
+
191
+ return FMRES_HANDLED;
135
192
}
193
+
194
+ return FMRES_IGNORED;
136
195
}
137
196
138
197
public HamHook_Player_Spawn_Post (pPlayer) {
139
- if (! g_pPlayerSubModel[pPlayer]) {
140
- g_pPlayerSubModel[pPlayer] = @PlayerSubModel_Create (pPlayer);
141
- }
142
-
143
198
@Player_UpdateCurrentModel (pPlayer);
199
+
200
+ return HAM_HANDLED;
144
201
}
145
202
146
203
public HamHook_Player_PostThink_Post (pPlayer) {
@@ -151,25 +208,20 @@ public HamHook_Player_PostThink_Post(pPlayer) {
151
208
return HAM_HANDLED;
152
209
}
153
210
154
- public FMHook_SetClientKeyValue (pPlayer, const szInfoBuffer[], const szKey[], const szValue[]) {
155
- if (equal (szKey, " model" )) {
156
- copy (g_rgszDefaultPlayerModel[pPlayer], charsmax (g_rgszDefaultPlayerModel[]), szValue);
157
-
158
- if (! equal (g_rgszCurrentPlayerModel[pPlayer], NULL_STRING)) {
159
- return FMRES_SUPERCEDE;
160
- }
211
+ public HC_Player_SetAnimation (pPlayer) {
212
+ @Player_UpdateAnimationModel (pPlayer);
213
+ }
161
214
162
- return FMRES_IGNORED;
215
+ public Message_ClCorpse (iMsgId, iMsgDest, pPlayer) {
216
+ new pTargetPlayer = get_msg_arg_int (12 );
217
+ if (@Player_ShouldUseCurrentModel (pTargetPlayer)) {
218
+ set_msg_arg_string (1 , g_rgszCurrentPlayerModel[pTargetPlayer]);
163
219
}
164
-
165
- return FMRES_IGNORED;
166
220
}
167
221
168
- public HC_Player_SetAnimation (pPlayer) {
169
- @Player_UpdateAnimationModel (pPlayer);
170
- }
222
+ // ANCHOR: Methods
171
223
172
- public @Player_UpdateAnimationModel (this) {
224
+ @Player_UpdateAnimationModel (this) {
173
225
static szAnimExt[32 ];
174
226
get_member (this, m_szAnimExtention, szAnimExt, charsmax (szAnimExt));
175
227
@@ -180,34 +232,44 @@ public @Player_UpdateAnimationModel(this) {
180
232
}
181
233
}
182
234
183
- public @Player_UpdateCurrentModel (this) {
235
+ @Player_UpdateCurrentModel (this) {
184
236
new bool: bUsedCustom = g_rgbPlayerUseCustomModel[this];
185
237
186
238
g_rgbPlayerUseCustomModel[this] = ! equal (g_rgszCustomPlayerModel[this], NULL_STRING);
187
239
188
240
if (g_rgbPlayerUseCustomModel[this]) {
189
241
copy (g_rgszCurrentPlayerModel[this], charsmax (g_rgszCurrentPlayerModel[]), g_rgszCustomPlayerModel[this]);
190
- } else {
191
- if (! equal (g_rgszDefaultPlayerModel[this], NULL_STRING)) {
192
- format (g_rgszCurrentPlayerModel[this], charsmax (g_rgszCurrentPlayerModel[]), " models/player/%s /%s .mdl" , g_rgszDefaultPlayerModel[this], g_rgszDefaultPlayerModel[this]);
193
- }
242
+ } else if (! equal (g_rgszDefaultPlayerModel[this], NULL_STRING)) {
243
+ format (g_rgszCurrentPlayerModel[this], charsmax (g_rgszCurrentPlayerModel[]), " models/player/%s /%s .mdl" , g_rgszDefaultPlayerModel[this], g_rgszDefaultPlayerModel[this]);
194
244
}
195
245
196
246
@Player_UpdateModel (this, bUsedCustom && ! g_rgbPlayerUseCustomModel[this]);
197
247
}
198
248
199
- public @Player_UpdateModel (this, bool: bForce) {
200
- if (bForce || (g_rgbPlayerUseCustomModel[this] || g_rgiPlayerAnimationIndex[this])) {
249
+ @Player_UpdateModel (this, bool: bForceUpdate) {
250
+ new iSubModelModelIndex = 0 ;
251
+
252
+ if (bForceUpdate || @Player_ShouldUseCurrentModel (this)) {
201
253
new iAnimationIndex = g_rgiPlayerAnimationIndex[this];
202
254
new iModelIndex = engfunc (EngFunc_ModelIndex, g_rgszCurrentPlayerModel[this]);
203
255
@Player_SetModelIndex (this, iAnimationIndex ? iAnimationIndex : iModelIndex);
204
- set_pev (g_pPlayerSubModel[this], pev_modelindex, iAnimationIndex ? iModelIndex : 0 );
205
- } else {
206
- set_pev (g_pPlayerSubModel[this], pev_modelindex, 0 );
256
+ iSubModelModelIndex = iAnimationIndex ? iModelIndex : 0 ;
257
+ }
258
+
259
+ if (iSubModelModelIndex && ! g_pPlayerSubModel[this]) {
260
+ g_pPlayerSubModel[this] = @PlayerSubModel_Create (this);
261
+ }
262
+
263
+ if (g_pPlayerSubModel[this]) {
264
+ set_pev (g_pPlayerSubModel[this], pev_modelindex, iSubModelModelIndex);
207
265
}
208
266
}
209
267
210
- public @Player_ResetModel (this) {
268
+ bool: @Player_ShouldUseCurrentModel (this) {
269
+ return g_rgbPlayerUseCustomModel[this] || g_rgiPlayerAnimationIndex[this];
270
+ }
271
+
272
+ @Player_ResetModel (this) {
211
273
if (equal (g_rgszDefaultPlayerModel[this], NULL_STRING)) {
212
274
return ;
213
275
}
@@ -219,13 +281,13 @@ public @Player_ResetModel(this) {
219
281
@Player_UpdateCurrentModel (this);
220
282
}
221
283
222
- public @Player_SetModelIndex (this, iModelIndex) {
284
+ @Player_SetModelIndex (this, iModelIndex) {
223
285
set_user_info (this, " model" , " " );
224
286
set_pev (this, pev_modelindex, iModelIndex);
225
287
set_member (this, m_modelIndexPlayer, iModelIndex);
226
288
}
227
289
228
- public @Player_SetSequence (this, const szSequence[]) {
290
+ @Player_SetSequence (this, const szSequence[]) {
229
291
new iAnimationIndex = GetAnimationIndexBySequence (szSequence);
230
292
if (! iAnimationIndex) {
231
293
return - 1 ;
@@ -239,22 +301,22 @@ public @Player_SetSequence(this, const szSequence[]) {
239
301
return iSequence;
240
302
}
241
303
242
- public @PlayerSubModel_Create (pPlayer) {
243
- new this = engfunc (EngFunc_CreateNamedEntity, g_iszModelClassname );
304
+ @PlayerSubModel_Create (pPlayer) {
305
+ new this = engfunc (EngFunc_CreateNamedEntity, g_iszSubModelClassname );
244
306
set_pev (this, pev_movetype, MOVETYPE_FOLLOW);
245
307
set_pev (this, pev_aiment, pPlayer);
246
308
set_pev (this, pev_owner, pPlayer);
247
309
248
310
return this;
249
311
}
250
312
251
- public @PlayerSubModel_Destroy (this) {
313
+ @PlayerSubModel_Destroy (this) {
252
314
set_pev (this, pev_modelindex, 0 );
253
315
set_pev (this, pev_flags, pev (this, pev_flags) | FL_KILLME);
254
316
dllfunc (DLLFunc_Think, this);
255
317
}
256
318
257
- public @PlayerSubModel_Think (this) {
319
+ @PlayerSubModel_Think (this) {
258
320
if (! @PlayerSubModel_IsActive (this)) {
259
321
set_entvar (this, var_effects, get_entvar (this, var_effects) | EF_NODRAW);
260
322
return ;
@@ -275,10 +337,12 @@ public @PlayerSubModel_Think(this) {
275
337
set_entvar (this, var_rendercolor, rgflColor);
276
338
}
277
339
278
- public @PlayerSubModel_IsActive (this) {
340
+ @PlayerSubModel_IsActive (this) {
279
341
return (pev (this, pev_modelindex) > 0 );
280
342
}
281
343
344
+ // ANCHOR: Functions
345
+
282
346
GetAnimationIndexByAnimExt (const szAnimExt[]) {
283
347
static szSequence[32 ];
284
348
format (szSequence, charsmax (szSequence), " ref_aim_%s " , szAnimExt);
0 commit comments