sv_game.c (8425B)
1 /* 2 Copyright (C) 1997-2001 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // sv_game.c -- interface to the game dll 21 22 #include "server.h" 23 24 game_export_t *ge; 25 26 27 /* 28 =============== 29 PF_Unicast 30 31 Sends the contents of the mutlicast buffer to a single client 32 =============== 33 */ 34 void PF_Unicast (edict_t *ent, qboolean reliable) 35 { 36 int p; 37 client_t *client; 38 39 if (!ent) 40 return; 41 42 p = NUM_FOR_EDICT(ent); 43 if (p < 1 || p > maxclients->value) 44 return; 45 46 client = svs.clients + (p-1); 47 48 if (reliable) 49 SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize); 50 else 51 SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize); 52 53 SZ_Clear (&sv.multicast); 54 } 55 56 57 /* 58 =============== 59 PF_dprintf 60 61 Debug print to server console 62 =============== 63 */ 64 void PF_dprintf (char *fmt, ...) 65 { 66 char msg[1024]; 67 va_list argptr; 68 69 va_start (argptr,fmt); 70 vsprintf (msg, fmt, argptr); 71 va_end (argptr); 72 73 Com_Printf ("%s", msg); 74 } 75 76 77 /* 78 =============== 79 PF_cprintf 80 81 Print to a single client 82 =============== 83 */ 84 void PF_cprintf (edict_t *ent, int level, char *fmt, ...) 85 { 86 char msg[1024]; 87 va_list argptr; 88 int n; 89 90 if (ent) 91 { 92 n = NUM_FOR_EDICT(ent); 93 if (n < 1 || n > maxclients->value) 94 Com_Error (ERR_DROP, "cprintf to a non-client"); 95 } 96 97 va_start (argptr,fmt); 98 vsprintf (msg, fmt, argptr); 99 va_end (argptr); 100 101 if (ent) 102 SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg); 103 else 104 Com_Printf ("%s", msg); 105 } 106 107 108 /* 109 =============== 110 PF_centerprintf 111 112 centerprint to a single client 113 =============== 114 */ 115 void PF_centerprintf (edict_t *ent, char *fmt, ...) 116 { 117 char msg[1024]; 118 va_list argptr; 119 int n; 120 121 n = NUM_FOR_EDICT(ent); 122 if (n < 1 || n > maxclients->value) 123 return; // Com_Error (ERR_DROP, "centerprintf to a non-client"); 124 125 va_start (argptr,fmt); 126 vsprintf (msg, fmt, argptr); 127 va_end (argptr); 128 129 MSG_WriteByte (&sv.multicast,svc_centerprint); 130 MSG_WriteString (&sv.multicast,msg); 131 PF_Unicast (ent, true); 132 } 133 134 135 /* 136 =============== 137 PF_error 138 139 Abort the server with a game error 140 =============== 141 */ 142 void PF_error (char *fmt, ...) 143 { 144 char msg[1024]; 145 va_list argptr; 146 147 va_start (argptr,fmt); 148 vsprintf (msg, fmt, argptr); 149 va_end (argptr); 150 151 Com_Error (ERR_DROP, "Game Error: %s", msg); 152 } 153 154 155 /* 156 ================= 157 PF_setmodel 158 159 Also sets mins and maxs for inline bmodels 160 ================= 161 */ 162 void PF_setmodel (edict_t *ent, char *name) 163 { 164 int i; 165 cmodel_t *mod; 166 167 if (!name) 168 Com_Error (ERR_DROP, "PF_setmodel: NULL"); 169 170 i = SV_ModelIndex (name); 171 172 // ent->model = name; 173 ent->s.modelindex = i; 174 175 // if it is an inline model, get the size information for it 176 if (name[0] == '*') 177 { 178 mod = CM_InlineModel (name); 179 VectorCopy (mod->mins, ent->mins); 180 VectorCopy (mod->maxs, ent->maxs); 181 SV_LinkEdict (ent); 182 } 183 184 } 185 186 /* 187 =============== 188 PF_Configstring 189 190 =============== 191 */ 192 void PF_Configstring (int index, char *val) 193 { 194 if (index < 0 || index >= MAX_CONFIGSTRINGS) 195 Com_Error (ERR_DROP, "configstring: bad index %i\n", index); 196 197 if (!val) 198 val = ""; 199 200 // change the string in sv 201 strcpy (sv.configstrings[index], val); 202 203 if (sv.state != ss_loading) 204 { // send the update to everyone 205 SZ_Clear (&sv.multicast); 206 MSG_WriteChar (&sv.multicast, svc_configstring); 207 MSG_WriteShort (&sv.multicast, index); 208 MSG_WriteString (&sv.multicast, val); 209 210 SV_Multicast (vec3_origin, MULTICAST_ALL_R); 211 } 212 } 213 214 215 216 void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);} 217 void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);} 218 void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);} 219 void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);} 220 void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);} 221 void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);} 222 void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);} 223 void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);} 224 void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);} 225 226 227 /* 228 ================= 229 PF_inPVS 230 231 Also checks portalareas so that doors block sight 232 ================= 233 */ 234 qboolean PF_inPVS (vec3_t p1, vec3_t p2) 235 { 236 int leafnum; 237 int cluster; 238 int area1, area2; 239 byte *mask; 240 241 leafnum = CM_PointLeafnum (p1); 242 cluster = CM_LeafCluster (leafnum); 243 area1 = CM_LeafArea (leafnum); 244 mask = CM_ClusterPVS (cluster); 245 246 leafnum = CM_PointLeafnum (p2); 247 cluster = CM_LeafCluster (leafnum); 248 area2 = CM_LeafArea (leafnum); 249 if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) 250 return false; 251 if (!CM_AreasConnected (area1, area2)) 252 return false; // a door blocks sight 253 return true; 254 } 255 256 257 /* 258 ================= 259 PF_inPHS 260 261 Also checks portalareas so that doors block sound 262 ================= 263 */ 264 qboolean PF_inPHS (vec3_t p1, vec3_t p2) 265 { 266 int leafnum; 267 int cluster; 268 int area1, area2; 269 byte *mask; 270 271 leafnum = CM_PointLeafnum (p1); 272 cluster = CM_LeafCluster (leafnum); 273 area1 = CM_LeafArea (leafnum); 274 mask = CM_ClusterPHS (cluster); 275 276 leafnum = CM_PointLeafnum (p2); 277 cluster = CM_LeafCluster (leafnum); 278 area2 = CM_LeafArea (leafnum); 279 if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) 280 return false; // more than one bounce away 281 if (!CM_AreasConnected (area1, area2)) 282 return false; // a door blocks hearing 283 284 return true; 285 } 286 287 void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume, 288 float attenuation, float timeofs) 289 { 290 if (!entity) 291 return; 292 SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs); 293 } 294 295 //============================================== 296 297 /* 298 =============== 299 SV_ShutdownGameProgs 300 301 Called when either the entire server is being killed, or 302 it is changing to a different game directory. 303 =============== 304 */ 305 void SV_ShutdownGameProgs (void) 306 { 307 if (!ge) 308 return; 309 ge->Shutdown (); 310 Sys_UnloadGame (); 311 ge = NULL; 312 } 313 314 /* 315 =============== 316 SV_InitGameProgs 317 318 Init the game subsystem for a new map 319 =============== 320 */ 321 void SCR_DebugGraph (float value, int color); 322 323 void SV_InitGameProgs (void) 324 { 325 game_import_t import; 326 327 // unload anything we have now 328 if (ge) 329 SV_ShutdownGameProgs (); 330 331 332 // load a new game dll 333 import.multicast = SV_Multicast; 334 import.unicast = PF_Unicast; 335 import.bprintf = SV_BroadcastPrintf; 336 import.dprintf = PF_dprintf; 337 import.cprintf = PF_cprintf; 338 import.centerprintf = PF_centerprintf; 339 import.error = PF_error; 340 341 import.linkentity = SV_LinkEdict; 342 import.unlinkentity = SV_UnlinkEdict; 343 import.BoxEdicts = SV_AreaEdicts; 344 import.trace = SV_Trace; 345 import.pointcontents = SV_PointContents; 346 import.setmodel = PF_setmodel; 347 import.inPVS = PF_inPVS; 348 import.inPHS = PF_inPHS; 349 import.Pmove = Pmove; 350 351 import.modelindex = SV_ModelIndex; 352 import.soundindex = SV_SoundIndex; 353 import.imageindex = SV_ImageIndex; 354 355 import.configstring = PF_Configstring; 356 import.sound = PF_StartSound; 357 import.positioned_sound = SV_StartSound; 358 359 import.WriteChar = PF_WriteChar; 360 import.WriteByte = PF_WriteByte; 361 import.WriteShort = PF_WriteShort; 362 import.WriteLong = PF_WriteLong; 363 import.WriteFloat = PF_WriteFloat; 364 import.WriteString = PF_WriteString; 365 import.WritePosition = PF_WritePos; 366 import.WriteDir = PF_WriteDir; 367 import.WriteAngle = PF_WriteAngle; 368 369 import.TagMalloc = Z_TagMalloc; 370 import.TagFree = Z_Free; 371 import.FreeTags = Z_FreeTags; 372 373 import.cvar = Cvar_Get; 374 import.cvar_set = Cvar_Set; 375 import.cvar_forceset = Cvar_ForceSet; 376 377 import.argc = Cmd_Argc; 378 import.argv = Cmd_Argv; 379 import.args = Cmd_Args; 380 import.AddCommandString = Cbuf_AddText; 381 382 import.DebugGraph = SCR_DebugGraph; 383 import.SetAreaPortalState = CM_SetAreaPortalState; 384 import.AreasConnected = CM_AreasConnected; 385 386 ge = (game_export_t *)Sys_GetGameAPI (&import); 387 388 if (!ge) 389 Com_Error (ERR_DROP, "failed to load game DLL"); 390 if (ge->apiversion != GAME_API_VERSION) 391 Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion, 392 GAME_API_VERSION); 393 394 ge->Init (); 395 } 396