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