Correct misleading message
[pmprecache.git] / dllapi.cpp
1 // vi: set ts=4 sw=4 :
2 // vim: set tw=75 :
3
4 /*
5 * Copyright (c) 2001-2003 Will Day <willday@hpgx.net>
6 *
7 * This file is part of Metamod.
8 *
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.
13 *
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.
18 *
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
22 *
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
31 * version.
32 *
33 */
34
35 #include <extdll.h>
36
37 #include <dllapi.h>
38 #include <meta_api.h>
39
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 );\
44 MESSAGE_END();\
45 }
46
47 extern char gGamedir[];
48 int gmsgSayText;
49
50 #define MAXLENGTH_PLAYERNAME 64
51 #define MAXLENGTH_MODELNAME 64
52 #define MAXLENGTH_MODELPATH 256
53 typedef struct {
54 char model[MAXLENGTH_MODELPATH];
55 char bmp[MAXLENGTH_MODELPATH];
56 char tmdl[MAXLENGTH_MODELPATH];
57 } precache_paths;
58
59 typedef struct {
60 char playername[MAXLENGTH_PLAYERNAME];
61 char modelname[MAXLENGTH_MODELNAME];
62 precache_paths paths;
63 } precache_entry;
64
65 #define MAX_PRECACHE_COUNT 32
66 precache_entry precache_list[MAX_PRECACHE_COUNT];
67 unsigned short int precache_count = 0;
68
69 bool fileExists(char* path) {
70 return g_engfuncs.pfnGetFileSize(path) != -1;
71 }
72
73 bool addPrecacheEntry(const char* playername, const char* model) {
74 short int i = 0;
75 int streq = 1;
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;
83
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);
87
88 // Check if BMP exists
89 if (!fileExists(precache_list[i].paths.bmp))
90 precache_list[i].paths.bmp[0] = 0;
91
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;
97 }
98
99 precache_count++;
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);
101 return true;
102 }
103 else
104 return false;
105 }
106
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" );
110 char modelfile[256];
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);
118 else
119 LOG_MESSAGE(PLID, "Model %s is not added - reduntant or precache list is full", modelname);
120 }
121 else {
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!");
124 }
125 RETURN_META(MRES_IGNORED);
126 }
127
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;
134
135 const char* indicator;
136 if (hasBMP && hasTMDL)
137 indicator = "(with bmp+tmdl)";
138 else if (hasBMP)
139 indicator = "(with bmp)";
140 else if (hasTMDL)
141 indicator = "(with tmdl)";
142 else
143 indicator = "(without bmp)";
144
145 LOG_MESSAGE(PLID, "Precaching model %s: %s (contributed by %s)",
146 indicator,
147 precache_list[i].modelname, precache_list[i].playername);
148
149 g_engfuncs.pfnPrecacheModel(precache_list[i].paths.model);
150
151 if (hasBMP)
152 g_engfuncs.pfnPrecacheGeneric(precache_list[i].paths.bmp);
153
154 if (hasTMDL)
155 g_engfuncs.pfnPrecacheGeneric(precache_list[i].paths.tmdl);
156 }
157 precache_count = 0;
158 RETURN_META(MRES_HANDLED);
159 }
160
161 static DLL_FUNCTIONS gFunctionTable =
162 {
163 NULL, // pfnGameInit
164 NULL, // pfnSpawn
165 NULL, // pfnThink
166 NULL, // pfnUse
167 NULL, // pfnTouch
168 NULL, // pfnBlocked
169 NULL, // pfnKeyValue
170 NULL, // pfnSave
171 NULL, // pfnRestore
172 NULL, // pfnSetAbsBox
173
174 NULL, // pfnSaveWriteFields
175 NULL, // pfnSaveReadFields
176
177 NULL, // pfnSaveGlobalState
178 NULL, // pfnRestoreGlobalState
179 NULL, // pfnResetGlobalState
180
181 NULL, // pfnClientConnect
182 NULL, // pfnClientDisconnect
183 NULL, // pfnClientKill
184 ClientPutInServer, // pfnClientPutInServer
185 NULL, // pfnClientCommand
186 NULL, // pfnClientUserInfoChanged
187 ServerActivate, // pfnServerActivate
188 NULL, // pfnServerDeactivate
189
190 NULL, // pfnPlayerPreThink
191 NULL, // pfnPlayerPostThink
192
193 NULL, // pfnStartFrame
194 NULL, // pfnParmsNewLevel
195 NULL, // pfnParmsChangeLevel
196
197 NULL, // pfnGetGameDescription
198 NULL, // pfnPlayerCustomization
199
200 NULL, // pfnSpectatorConnect
201 NULL, // pfnSpectatorDisconnect
202 NULL, // pfnSpectatorThink
203
204 NULL, // pfnSys_Error
205
206 NULL, // pfnPM_Move
207 NULL, // pfnPM_Init
208 NULL, // pfnPM_FindTextureType
209
210 NULL, // pfnSetupVisibility
211 NULL, // pfnUpdateClientData
212 NULL, // pfnAddToFullPack
213 NULL, // pfnCreateBaseline
214 NULL, // pfnRegisterEncoders
215 NULL, // pfnGetWeaponData
216 NULL, // pfnCmdStart
217 NULL, // pfnCmdEnd
218 NULL, // pfnConnectionlessPacket
219 NULL, // pfnGetHullBounds
220 NULL, // pfnCreateInstancedBaselines
221 NULL, // pfnInconsistentFile
222 NULL, // pfnAllowLagCompensation
223 };
224
225 C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable,
226 int *interfaceVersion)
227 {
228 if(!pFunctionTable) {
229 UTIL_LogPrintf("GetEntityAPI2 called with null pFunctionTable");
230 return(FALSE);
231 }
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;
236 return(FALSE);
237 }
238 memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
239 return(TRUE);
240 }