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