Make precache logging more concise
[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 <unistd.h>
36
37 #include <extdll.h>
38
39 #include <dllapi.h>
40 #include <meta_api.h>
41
42 #define SAY(pEntity, text) {\
43 MESSAGE_BEGIN( MSG_ONE, GET_USER_MSG_ID(PLID, "SayText", NULL), NULL, pEntity );\
44 WRITE_BYTE( ENTINDEX(pEntity) );\
45 WRITE_STRING( text );\
46 MESSAGE_END();\
47 }
48
49 extern char gGamedir[];
50 int gmsgSayText;
51
52 #define MAXLENGTH_PLAYERNAME 64
53 #define MAXLENGTH_MODELNAME 64
54 #define MAXLENGTH_MODELPATH 256
55 typedef struct {
56 char model[MAXLENGTH_MODELPATH];
57 char bmp[MAXLENGTH_MODELPATH];
58 } precache_paths;
59
60 typedef struct {
61 char playername[MAXLENGTH_PLAYERNAME];
62 char modelname[MAXLENGTH_MODELNAME];
63 precache_paths paths;
64 } precache_entry;
65
66 #define MAX_PRECACHE_COUNT 32
67 precache_entry precache_list[MAX_PRECACHE_COUNT];
68 unsigned short int precache_count = 0;
69
70 bool fileExists(const char* path) {
71 char fullpath[256];
72 snprintf(fullpath, sizeof(fullpath), "%s/%s", &gGamedir[0], path);
73 return access(fullpath, R_OK) == 0;
74 }
75
76 bool addPrecacheEntry(const char* playername, const char* model) {
77 short int i = 0;
78 int streq = 1;
79 while ((i < precache_count) && ((streq = strcmp(precache_list[i].modelname, model)) != 0)) i++;
80 if ((i == precache_count) && (i < MAX_PRECACHE_COUNT) && (streq != 0)) {
81 strncpy(precache_list[i].playername, playername, MAXLENGTH_PLAYERNAME - 1);
82 strncpy(precache_list[i].modelname, model, MAXLENGTH_MODELNAME - 1);
83 // Ensure null-termination
84 precache_list[i].playername[MAXLENGTH_PLAYERNAME - 1] = 0;
85 precache_list[i].modelname[MAXLENGTH_MODELNAME - 1] = 0;
86
87 snprintf(precache_list[i].paths.model, MAXLENGTH_MODELPATH, "models/player/%s/%s.mdl", model, model);
88 snprintf(precache_list[i].paths.bmp, MAXLENGTH_MODELPATH, "models/player/%s/%s.bmp", model, model);
89
90 precache_count++;
91 LOG_MESSAGE(PLID, "Precache entry %d: playername=\"%s\" modelname=\"%s\" paths.model=\"%s\" paths.bmp=\"%s\"", i, precache_list[i].playername, precache_list[i].modelname, precache_list[i].paths.model, precache_list[i].paths.bmp);
92 return true;
93 }
94 else
95 return false;
96 }
97
98 void ClientPutInServer( edict_t *pEntity ) {
99 const char* playername = STRING(pEntity->v.netname);
100 char* modelname = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" );
101 char modelfile[256];
102 snprintf(modelfile, sizeof(modelfile), "models/player/%s/%s.mdl", modelname, modelname);
103 LOG_MESSAGE(PLID, "Player %s is using model %s", playername, modelname);
104 if (fileExists( modelfile )) {
105 LOG_MESSAGE(PLID, "Model %s is present on server", modelname);
106 SAY(pEntity, "Your model is present on the server, it will be precached for the next round!");
107 if (addPrecacheEntry( playername, modelname ))
108 LOG_MESSAGE(PLID, "Added model %s to precache list", modelname);
109 else
110 LOG_MESSAGE(PLID, "Model %s will not be precached - reduntant or precache list is full", modelname);
111 }
112 else {
113 LOG_MESSAGE(PLID, "Unable to precache due to FILE MISSING: %s!", modelfile);
114 SAY(pEntity, "Your model is not present on the server, can't distribute for other players!");
115 }
116 RETURN_META(MRES_IGNORED);
117 }
118
119 void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) {
120 bool hasBMP;
121 LOG_MESSAGE(PLID, "Precaching %d player models", precache_count);
122 for (int i = 0; i < precache_count; i++) {
123 hasBMP = fileExists(precache_list[i].paths.bmp);
124 LOG_MESSAGE(PLID, "Precaching model %s: %s (contributed by %s)",
125 hasBMP ? "(with bmp)" : "(without bmp)",
126 precache_list[i].modelname, precache_list[i].playername);
127 g_engfuncs.pfnPrecacheModel(precache_list[i].paths.model);
128 if (hasBMP)
129 g_engfuncs.pfnPrecacheGeneric(precache_list[i].paths.bmp);
130 }
131 precache_count = 0;
132 RETURN_META(MRES_HANDLED);
133 }
134
135 static DLL_FUNCTIONS gFunctionTable =
136 {
137 NULL, // pfnGameInit
138 NULL, // pfnSpawn
139 NULL, // pfnThink
140 NULL, // pfnUse
141 NULL, // pfnTouch
142 NULL, // pfnBlocked
143 NULL, // pfnKeyValue
144 NULL, // pfnSave
145 NULL, // pfnRestore
146 NULL, // pfnSetAbsBox
147
148 NULL, // pfnSaveWriteFields
149 NULL, // pfnSaveReadFields
150
151 NULL, // pfnSaveGlobalState
152 NULL, // pfnRestoreGlobalState
153 NULL, // pfnResetGlobalState
154
155 NULL, // pfnClientConnect
156 NULL, // pfnClientDisconnect
157 NULL, // pfnClientKill
158 ClientPutInServer, // pfnClientPutInServer
159 NULL, // pfnClientCommand
160 NULL, // pfnClientUserInfoChanged
161 ServerActivate, // pfnServerActivate
162 NULL, // pfnServerDeactivate
163
164 NULL, // pfnPlayerPreThink
165 NULL, // pfnPlayerPostThink
166
167 NULL, // pfnStartFrame
168 NULL, // pfnParmsNewLevel
169 NULL, // pfnParmsChangeLevel
170
171 NULL, // pfnGetGameDescription
172 NULL, // pfnPlayerCustomization
173
174 NULL, // pfnSpectatorConnect
175 NULL, // pfnSpectatorDisconnect
176 NULL, // pfnSpectatorThink
177
178 NULL, // pfnSys_Error
179
180 NULL, // pfnPM_Move
181 NULL, // pfnPM_Init
182 NULL, // pfnPM_FindTextureType
183
184 NULL, // pfnSetupVisibility
185 NULL, // pfnUpdateClientData
186 NULL, // pfnAddToFullPack
187 NULL, // pfnCreateBaseline
188 NULL, // pfnRegisterEncoders
189 NULL, // pfnGetWeaponData
190 NULL, // pfnCmdStart
191 NULL, // pfnCmdEnd
192 NULL, // pfnConnectionlessPacket
193 NULL, // pfnGetHullBounds
194 NULL, // pfnCreateInstancedBaselines
195 NULL, // pfnInconsistentFile
196 NULL, // pfnAllowLagCompensation
197 };
198
199 C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable,
200 int *interfaceVersion)
201 {
202 if(!pFunctionTable) {
203 UTIL_LogPrintf("GetEntityAPI2 called with null pFunctionTable");
204 return(FALSE);
205 }
206 else if(*interfaceVersion != INTERFACE_VERSION) {
207 UTIL_LogPrintf("GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION);
208 //! Tell metamod what version we had, so it can figure out who is out of date.
209 *interfaceVersion = INTERFACE_VERSION;
210 return(FALSE);
211 }
212 memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
213 return(TRUE);
214 }