5 * Copyright (c) 2001-2003 Will Day <willday@hpgx.net>
7 * This file is part of Metamod.
9 * Metamod is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
14 * Metamod is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Metamod; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * In addition, as a special exception, the author gives permission to
24 * link the code of this program with the Half-Life Game Engine ("HL
25 * Engine") and Modified Game Libraries ("MODs") developed by Valve,
26 * L.L.C ("Valve"). You must obey the GNU General Public License in all
27 * respects for all of the code used other than the HL Engine and MODs
28 * from Valve. If you modify this file, you may extend this exception
29 * to your version of the file, but you are not obligated to do so. If
30 * you do not wish to do so, delete this exception statement from your
40 #define SAY(pEntity, text) {\
41 MESSAGE_BEGIN( MSG_ONE, GET_USER_MSG_ID(PLID, "SayText", NULL), NULL, pEntity );\
42 WRITE_BYTE( ENTINDEX(pEntity) );\
43 WRITE_STRING( text );\
47 extern char gGamedir
[];
50 #define MAXLENGTH_PLAYERNAME 64
51 #define MAXLENGTH_MODELNAME 64
52 #define MAXLENGTH_MODELPATH 256
54 char model
[MAXLENGTH_MODELPATH
];
55 char bmp
[MAXLENGTH_MODELPATH
];
56 char tmdl
[MAXLENGTH_MODELPATH
];
60 char playername
[MAXLENGTH_PLAYERNAME
];
61 char modelname
[MAXLENGTH_MODELNAME
];
65 #define MAX_PRECACHE_COUNT 32
66 precache_entry precache_list
[MAX_PRECACHE_COUNT
];
67 unsigned short int precache_count
= 0;
69 bool fileExists(char* path
) {
70 return g_engfuncs
.pfnGetFileSize(path
) != -1;
73 bool addPrecacheEntry(const char* playername
, const char* model
) {
76 while ((i
< precache_count
) && ((streq
= strcmp(precache_list
[i
].modelname
, model
)) != 0)) i
++;
77 if ((i
== precache_count
) && (i
< MAX_PRECACHE_COUNT
) && (streq
!= 0)) {
78 strncpy(precache_list
[i
].playername
, playername
, MAXLENGTH_PLAYERNAME
- 1);
79 strncpy(precache_list
[i
].modelname
, model
, MAXLENGTH_MODELNAME
- 1);
80 // Ensure null-termination
81 precache_list
[i
].playername
[MAXLENGTH_PLAYERNAME
- 1] = 0;
82 precache_list
[i
].modelname
[MAXLENGTH_MODELNAME
- 1] = 0;
84 snprintf(precache_list
[i
].paths
.model
, MAXLENGTH_MODELPATH
, "models/player/%s/%s.mdl", model
, model
);
85 snprintf(precache_list
[i
].paths
.bmp
, MAXLENGTH_MODELPATH
, "models/player/%s/%s.bmp", model
, model
);
86 snprintf(precache_list
[i
].paths
.tmdl
, MAXLENGTH_MODELPATH
, "models/player/%s/%st.mdl", model
, model
);
88 // Check if BMP exists
89 if (!fileExists(precache_list
[i
].paths
.bmp
))
90 precache_list
[i
].paths
.bmp
[0] = 0;
92 // Check if t.mdl exists, also try alternative path
93 if (!fileExists(precache_list
[i
].paths
.tmdl
)) {
94 snprintf(precache_list
[i
].paths
.tmdl
, MAXLENGTH_MODELPATH
, "models/player/%s/%sT.mdl", model
, model
);
95 if (!fileExists(precache_list
[i
].paths
.tmdl
))
96 precache_list
[i
].paths
.tmdl
[0] = 0;
100 LOG_MESSAGE(PLID
, "Precache entry %d: playername=\"%s\" modelname=\"%s\" paths.model=\"%s\" paths.bmp=\"%s\" paths.tmdl=\"%s\"", i
, precache_list
[i
].playername
, precache_list
[i
].modelname
, precache_list
[i
].paths
.model
, precache_list
[i
].paths
.bmp
, precache_list
[i
].paths
.tmdl
);
107 void ClientPutInServer( edict_t
*pEntity
) {
108 const char* playername
= STRING(pEntity
->v
.netname
);
109 char* modelname
= g_engfuncs
.pfnInfoKeyValue( g_engfuncs
.pfnGetInfoKeyBuffer( pEntity
), "model" );
111 snprintf(modelfile
, sizeof(modelfile
), "models/player/%s/%s.mdl", modelname
, modelname
);
112 LOG_MESSAGE(PLID
, "Player %s is using model %s", playername
, modelname
);
113 if (fileExists( modelfile
)) {
114 LOG_MESSAGE(PLID
, "Model %s is present on server", modelname
);
115 SAY(pEntity
, "Your model is present on the server, it will be precached for the next round!");
116 if (addPrecacheEntry( playername
, modelname
))
117 LOG_MESSAGE(PLID
, "Added model %s to precache list", modelname
);
119 LOG_MESSAGE(PLID
, "Model %s is not added - reduntant or precache list is full", modelname
);
122 LOG_MESSAGE(PLID
, "Unable to precache due to FILE MISSING: %s!", modelfile
);
123 SAY(pEntity
, "Your model is not present on the server, can't distribute for other players!");
125 RETURN_META(MRES_IGNORED
);
128 void ServerActivate(edict_t
*pEdictList
, int edictCount
, int clientMax
) {
129 bool hasBMP
, hasTMDL
;
130 LOG_MESSAGE(PLID
, "Precaching %d player models", precache_count
);
131 for (int i
= 0; i
< precache_count
; i
++) {
132 hasBMP
= strlen(precache_list
[i
].paths
.bmp
) != 0;
133 hasTMDL
= strlen(precache_list
[i
].paths
.tmdl
) != 0;
135 const char* indicator
;
136 if (hasBMP
&& hasTMDL
)
137 indicator
= "(with bmp+tmdl)";
139 indicator
= "(with bmp)";
141 indicator
= "(with tmdl)";
143 indicator
= "(without bmp)";
145 LOG_MESSAGE(PLID
, "Precaching model %s: %s (contributed by %s)",
147 precache_list
[i
].modelname
, precache_list
[i
].playername
);
149 g_engfuncs
.pfnPrecacheModel(precache_list
[i
].paths
.model
);
152 g_engfuncs
.pfnPrecacheGeneric(precache_list
[i
].paths
.bmp
);
155 g_engfuncs
.pfnPrecacheGeneric(precache_list
[i
].paths
.tmdl
);
158 RETURN_META(MRES_HANDLED
);
161 static DLL_FUNCTIONS gFunctionTable
=
172 NULL
, // pfnSetAbsBox
174 NULL
, // pfnSaveWriteFields
175 NULL
, // pfnSaveReadFields
177 NULL
, // pfnSaveGlobalState
178 NULL
, // pfnRestoreGlobalState
179 NULL
, // pfnResetGlobalState
181 NULL
, // pfnClientConnect
182 NULL
, // pfnClientDisconnect
183 NULL
, // pfnClientKill
184 ClientPutInServer
, // pfnClientPutInServer
185 NULL
, // pfnClientCommand
186 NULL
, // pfnClientUserInfoChanged
187 ServerActivate
, // pfnServerActivate
188 NULL
, // pfnServerDeactivate
190 NULL
, // pfnPlayerPreThink
191 NULL
, // pfnPlayerPostThink
193 NULL
, // pfnStartFrame
194 NULL
, // pfnParmsNewLevel
195 NULL
, // pfnParmsChangeLevel
197 NULL
, // pfnGetGameDescription
198 NULL
, // pfnPlayerCustomization
200 NULL
, // pfnSpectatorConnect
201 NULL
, // pfnSpectatorDisconnect
202 NULL
, // pfnSpectatorThink
204 NULL
, // pfnSys_Error
208 NULL
, // pfnPM_FindTextureType
210 NULL
, // pfnSetupVisibility
211 NULL
, // pfnUpdateClientData
212 NULL
, // pfnAddToFullPack
213 NULL
, // pfnCreateBaseline
214 NULL
, // pfnRegisterEncoders
215 NULL
, // pfnGetWeaponData
218 NULL
, // pfnConnectionlessPacket
219 NULL
, // pfnGetHullBounds
220 NULL
, // pfnCreateInstancedBaselines
221 NULL
, // pfnInconsistentFile
222 NULL
, // pfnAllowLagCompensation
225 C_DLLEXPORT
int GetEntityAPI2(DLL_FUNCTIONS
*pFunctionTable
,
226 int *interfaceVersion
)
228 if(!pFunctionTable
) {
229 UTIL_LogPrintf("GetEntityAPI2 called with null pFunctionTable");
232 else if(*interfaceVersion
!= INTERFACE_VERSION
) {
233 UTIL_LogPrintf("GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion
, INTERFACE_VERSION
);
234 //! Tell metamod what version we had, so it can figure out who is out of date.
235 *interfaceVersion
= INTERFACE_VERSION
;
238 memcpy(pFunctionTable
, &gFunctionTable
, sizeof(DLL_FUNCTIONS
));