1
1
#include < amxmodx>
2
2
#include < hamsandwich>
3
- #include < reapi>
4
3
#include < fakemeta>
4
+ #include < reapi>
5
5
6
6
# define PLUGIN " [API] Player Model"
7
- # define VERSION " 0.9 .0"
7
+ # define VERSION " 1.0 .0"
8
8
# define AUTHOR " Hedgehog Fog"
9
9
10
- new g_rgszPlayerModel[MAX_PLAYERS + 1 ][32 ];
10
+ # define MAX_SEQUENCES 101
11
+
12
+ new g_rgszDefaultPlayerModel[MAX_PLAYERS + 1 ][32 ];
13
+ new g_rgszCurrentPlayerModel[MAX_PLAYERS + 1 ][256 ];
11
14
new g_rgszCustomPlayerModel[MAX_PLAYERS + 1 ][256 ];
15
+ new g_rgiPlayerAnimationIndex[MAX_PLAYERS + 1 ];
16
+
17
+ new Trie: g_itPlayerSequenceModelIndexes = Invalid_Trie;
18
+ new Trie: g_itPlayerSequences = Invalid_Trie;
19
+ new g_pPlayerModel[MAX_PLAYERS + 1 ];
20
+
21
+ new gmsgClCorpse;
22
+
23
+ public plugin_precache () {
24
+ g_itPlayerSequenceModelIndexes = TrieCreate ();
25
+ g_itPlayerSequences = TrieCreate ();
26
+ }
12
27
13
28
public plugin_init () {
14
29
register_plugin (PLUGIN, VERSION, AUTHOR);
15
30
16
- RegisterHamPlayer (Ham_Spawn, " HamHook_Player_Spawn_Post " , .Post = 1 );
31
+ gmsgClCorpse = get_user_msgid ( " ClCorpse " );
17
32
18
33
register_forward (FM_SetClientKeyValue, " FMHook_SetClientKeyValue" );
34
+
35
+ RegisterHamPlayer (Ham_Spawn, " HamHook_Player_Spawn_Post" , .Post = 1 );
36
+ RegisterHamPlayer (Ham_Player_PostThink, " HamHook_Player_PostThink_Post" , .Post = 1 );
37
+
38
+ RegisterHookChain (RG_CBasePlayer_SetAnimation, " HC_Player_SetAnimation" );
39
+
40
+ register_message (gmsgClCorpse, " Message_ClCorpse" );
19
41
}
20
42
21
43
public plugin_natives () {
@@ -24,11 +46,12 @@ public plugin_natives() {
24
46
register_native (" PlayerModel_Set" , " Native_SetPlayerModel" );
25
47
register_native (" PlayerModel_Reset" , " Native_ResetPlayerModel" );
26
48
register_native (" PlayerModel_Update" , " Native_UpdatePlayerModel" );
49
+ register_native (" PlayerModel_PrecacheAnimation" , " Native_PrecacheAnimation" );
50
+ register_native (" PlayerModel_SetSequence" , " Native_SetPlayerSequence" );
27
51
}
28
52
29
53
public Native_GetPlayerModel (iPluginId, iArgc) {
30
54
new pPlayer = get_param (1 );
31
-
32
55
set_string (2 , g_rgszCustomPlayerModel[pPlayer], get_param (3 ));
33
56
}
34
57
@@ -44,23 +67,67 @@ public Native_ResetPlayerModel(iPluginId, iArgc) {
44
67
45
68
public Native_UpdatePlayerModel (iPluginId, iArgc) {
46
69
new pPlayer = get_param (1 );
47
- @Player_UpdateModel (pPlayer);
70
+ @Player_UpdateCurrentModel (pPlayer);
71
+ }
72
+
73
+ public Native_PrecacheAnimation (iPluginId, iArgc) {
74
+ static szAnimation[MAX_RESOURCE_PATH_LENGTH];
75
+ get_string (1 , szAnimation, charsmax (szAnimation));
76
+ PrecachePlayerAnimation (szAnimation);
77
+ }
78
+
79
+ public Native_SetPlayerSequence (iPluginId, iArgc) {
80
+ new pPlayer = get_param (1 );
81
+
82
+ static szSequence[MAX_RESOURCE_PATH_LENGTH];
83
+ get_string (2 , szSequence, charsmax (szSequence));
84
+
85
+ return @Player_SetSequence (pPlayer, szSequence);
48
86
}
49
87
50
88
public client_connect (pPlayer) {
51
89
copy (g_rgszCustomPlayerModel[pPlayer], charsmax (g_rgszCustomPlayerModel[]), NULL_STRING);
52
- copy (g_rgszPlayerModel[pPlayer], charsmax (g_rgszPlayerModel[]), NULL_STRING);
90
+ copy (g_rgszDefaultPlayerModel[pPlayer], charsmax (g_rgszDefaultPlayerModel[]), NULL_STRING);
91
+ }
92
+
93
+ public Message_ClCorpse (iMsgId, iMsgDest, pPlayer) {
94
+ new pTargetPlayer = get_msg_arg_int (12 );
95
+ set_msg_arg_string (1 , g_rgszCurrentPlayerModel[pTargetPlayer]);
53
96
}
54
97
55
98
public HamHook_Player_Spawn_Post (pPlayer) {
56
- @Player_UpdateModel (pPlayer);
99
+ if (! g_pPlayerModel[pPlayer]) {
100
+ new pPlayerModel = engfunc (EngFunc_CreateNamedEntity, engfunc (EngFunc_AllocString, " info_target" ));
101
+ set_pev (pPlayerModel, pev_movetype, MOVETYPE_FOLLOW);
102
+ set_pev (pPlayerModel, pev_aiment, pPlayer);
103
+ g_pPlayerModel[pPlayer] = pPlayerModel;
104
+ }
105
+
106
+ @Player_UpdateCurrentModel (pPlayer);
107
+ }
108
+
109
+ public HamHook_Player_PostThink_Post (pPlayer) {
110
+ if (g_pPlayerModel[pPlayer]) {
111
+ set_entvar (g_pPlayerModel[pPlayer], var_skin, get_entvar (pPlayer, var_skin));
112
+ set_entvar (g_pPlayerModel[pPlayer], var_body, get_entvar (pPlayer, var_body));
113
+ set_entvar (g_pPlayerModel[pPlayer], var_colormap, get_entvar (pPlayer, var_colormap));
114
+ set_entvar (g_pPlayerModel[pPlayer], var_rendermode, get_entvar (pPlayer, var_rendermode));
115
+ set_entvar (g_pPlayerModel[pPlayer], var_renderfx, get_entvar (pPlayer, var_renderfx));
116
+ set_entvar (g_pPlayerModel[pPlayer], var_renderamt, get_entvar (pPlayer, var_renderamt));
117
+
118
+ static rgflColor[3 ];
119
+ get_entvar (pPlayer, var_rendercolor, rgflColor);
120
+ set_entvar (g_pPlayerModel[pPlayer], var_rendercolor, rgflColor);
121
+ }
122
+
123
+ return HAM_HANDLED;
57
124
}
58
125
59
126
public FMHook_SetClientKeyValue (pPlayer, const szInfoBuffer[], const szKey[], const szValue[]) {
60
127
if (equal (szKey, " model" )) {
61
- copy (g_rgszPlayerModel [pPlayer], charsmax (g_rgszPlayerModel []), szValue);
128
+ copy (g_rgszDefaultPlayerModel [pPlayer], charsmax (g_rgszDefaultPlayerModel []), szValue);
62
129
63
- if (! equal (g_rgszCustomPlayerModel [pPlayer], NULL_STRING)) {
130
+ if (! equal (g_rgszCurrentPlayerModel [pPlayer], NULL_STRING)) {
64
131
return FMRES_SUPERCEDE;
65
132
}
66
133
@@ -70,28 +137,142 @@ public FMHook_SetClientKeyValue(pPlayer, const szInfoBuffer[], const szKey[], co
70
137
return FMRES_IGNORED;
71
138
}
72
139
73
- public @Player_UpdateModel (this) {
74
- if (! equal (g_rgszCustomPlayerModel[this], NULL_STRING)) {
75
- new iModelIndex = engfunc (EngFunc_ModelIndex, g_rgszCustomPlayerModel[this]);
76
- set_user_info (this, " model" , " " );
77
- set_pev (this, pev_modelindex, iModelIndex);
78
- set_member (this, m_modelIndexPlayer, iModelIndex);
140
+ public HC_Player_SetAnimation (pPlayer) {
141
+ @Player_UpdateAnimationModel (pPlayer);
142
+ }
143
+
144
+ public @Player_UpdateAnimationModel (this) {
145
+ static szAnimExt[32 ];
146
+ get_member (this, m_szAnimExtention, szAnimExt, charsmax (szAnimExt));
147
+
148
+ new iAnimationIndex = is_user_alive (this) ? GetAnimationIndexByAnimExt (szAnimExt) : 0 ;
149
+ if (iAnimationIndex != g_rgiPlayerAnimationIndex[this]) {
150
+ g_rgiPlayerAnimationIndex[this] = iAnimationIndex;
151
+ @Player_UpdateModel (this);
152
+ }
153
+ }
154
+
155
+ public @Player_UpdateCurrentModel (this) {
156
+ if (equal (g_rgszCustomPlayerModel[this], NULL_STRING)) {
157
+ if (! equal (g_rgszDefaultPlayerModel[this], NULL_STRING)) {
158
+ static szModel[MAX_RESOURCE_PATH_LENGTH];
159
+ format (szModel, charsmax (szModel), " models/player/%s /%s .mdl" , g_rgszDefaultPlayerModel[this], g_rgszDefaultPlayerModel[this]);
160
+ copy (g_rgszCurrentPlayerModel[this], charsmax (g_rgszCurrentPlayerModel[]), szModel);
161
+ }
79
162
} else {
80
- @Player_ResetModel ( this);
163
+ copy (g_rgszCurrentPlayerModel[ this], charsmax (g_rgszCurrentPlayerModel[]), g_rgszCustomPlayerModel[this] );
81
164
}
165
+
166
+ @Player_UpdateModel (this);
167
+ }
168
+
169
+ public @Player_UpdateModel (this) {
170
+ new iAnimationIndex = g_rgiPlayerAnimationIndex[this];
171
+ new iModelIndex = engfunc (EngFunc_ModelIndex, g_rgszCurrentPlayerModel[this]);
172
+ @Player_SetModelIndex (this, iAnimationIndex ? iAnimationIndex : iModelIndex);
173
+ set_pev (g_pPlayerModel[this], pev_modelindex, iAnimationIndex ? iModelIndex : 0 );
82
174
}
83
175
84
176
public @Player_ResetModel (this) {
85
- if (equal (g_rgszPlayerModel [this], NULL_STRING)) {
177
+ if (equal (g_rgszDefaultPlayerModel [this], NULL_STRING)) {
86
178
return ;
87
179
}
88
-
89
- static szPath[MAX_RESOURCE_PATH_LENGTH];
90
- format (szPath, charsmax (szPath), " models/player/%s /%s .mdl" , g_rgszPlayerModel[this], g_rgszPlayerModel[this]);
91
180
92
- new iModelIndex = engfunc (EngFunc_ModelIndex, szPath);
93
- set_user_info (this, " model" , g_rgszPlayerModel[this]);
181
+ copy (g_rgszCustomPlayerModel[this], charsmax (g_rgszCustomPlayerModel[]), NULL_STRING);
182
+ copy (g_rgszCurrentPlayerModel[this], charsmax (g_rgszCurrentPlayerModel[]), NULL_STRING);
183
+ g_rgiPlayerAnimationIndex[this] = 0 ;
184
+
185
+ @Player_UpdateCurrentModel (this);
186
+ }
187
+
188
+ public @Player_SetModelIndex (this, iModelIndex) {
189
+ set_user_info (this, " model" , " " );
94
190
set_pev (this, pev_modelindex, iModelIndex);
95
191
set_member (this, m_modelIndexPlayer, iModelIndex);
96
- copy (g_rgszCustomPlayerModel[this], charsmax (g_rgszCustomPlayerModel[]), NULL_STRING);
192
+ }
193
+
194
+ public @Player_SetSequence (this, const szSequence[]) {
195
+ new iAnimationIndex = GetAnimationIndexBySequence (szSequence);
196
+ if (! iAnimationIndex) {
197
+ return - 1 ;
198
+ }
199
+
200
+ g_rgiPlayerAnimationIndex[this] = iAnimationIndex;
201
+ @Player_UpdateModel (this);
202
+
203
+ new iSequence = GetSequenceIndex (szSequence);
204
+ set_pev (this, pev_sequence, iSequence);
205
+ return iSequence;
206
+ }
207
+
208
+ GetAnimationIndexByAnimExt (const szAnimExt[]) {
209
+ static szSequence[32 ];
210
+ format (szSequence, charsmax (szSequence), " ref_aim_%s " , szAnimExt);
211
+ return GetAnimationIndexBySequence (szSequence);
212
+ }
213
+
214
+ GetAnimationIndexBySequence (const szSequence[]) {
215
+ static iAnimationIndex;
216
+ if (! TrieGetCell (g_itPlayerSequenceModelIndexes, szSequence, iAnimationIndex)) {
217
+ return 0 ;
218
+ }
219
+
220
+ return iAnimationIndex;
221
+ }
222
+
223
+ GetSequenceIndex (const szSequence[]) {
224
+ static iSequence;
225
+ if (! TrieGetCell (g_itPlayerSequences, szSequence, iSequence)) {
226
+ return - 1 ;
227
+ }
228
+
229
+ return iSequence;
230
+ }
231
+
232
+ // Credis: HamletEagle
233
+ PrecachePlayerAnimation (const szAnim[]) {
234
+ new szFilePath[MAX_RESOURCE_PATH_LENGTH];
235
+ format (szFilePath, charsmax (szFilePath), " animations/%s " , szAnim);
236
+
237
+ new iModelIndex = precache_model (szFilePath);
238
+
239
+ new iFile = fopen (szFilePath, " rb" )
240
+ if (! iFile) {
241
+ return 0
242
+ }
243
+
244
+ // Got to "numseq" position of the studiohdr_t structure
245
+ // https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/public/rehlds/studio.h#L68
246
+ fseek (iFile, 164 , SEEK_SET);
247
+
248
+ new iSeqNum;
249
+ fread (iFile, iSeqNum, BLOCK_INT);
250
+
251
+ if (! iSeqNum) {
252
+ return 0 ;
253
+ }
254
+
255
+ new iSeqIndex;
256
+ fread (iFile, iSeqIndex, BLOCK_INT);
257
+ fseek (iFile, iSeqIndex, SEEK_SET);
258
+
259
+ new szLabel[32 ];
260
+ for (new i = 0 ; i < iSeqNum; i++ ) {
261
+ if (i >= MAX_SEQUENCES) {
262
+ log_amx (" Warning! Sequence limit reached for ^" % s^ " . Max sequences %d ." , szFilePath, MAX_SEQUENCES);
263
+ break ;
264
+ }
265
+
266
+ fread_blocks (iFile, szLabel, sizeof (szLabel), BLOCK_CHAR);
267
+ TrieSetCell (g_itPlayerSequenceModelIndexes, szLabel, iModelIndex);
268
+ TrieSetCell (g_itPlayerSequences, szLabel, i);
269
+
270
+ // jump to the end of the studiohdr_t structure
271
+ // https://github.com/dreamstalker/rehlds/blob/65c6ce593b5eabf13e92b03352e4b429d0d797b0/rehlds/public/rehlds/studio.h#L95
272
+ fseek (iFile, 176 - sizeof (szLabel), SEEK_CUR);
273
+ }
274
+
275
+ fclose (iFile);
276
+
277
+ return iModelIndex;
97
278
}
0 commit comments