00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "server.h"
00030 #include "../common/grid.h"
00031 #include "../ports/system.h"
00032 #include <SDL.h>
00033
00037 static void SV_dprintf (const char *fmt, ...)
00038 {
00039 va_list ap;
00040
00041 va_start(ap, fmt);
00042 Com_vPrintf(fmt, ap);
00043 va_end(ap);
00044 }
00045
00050 static void SV_PlayerPrintf (const player_t * player, int level, const char *fmt, va_list ap)
00051 {
00052 char msg[1024];
00053
00054 if (level == PRINT_NONE)
00055 return;
00056
00057 Q_vsnprintf(msg, sizeof(msg), fmt, ap);
00058
00059 if (player) {
00060 client_t *cl = SV_GetClient(player->num);
00061 SV_ClientPrintf(cl, level, "%s", msg);
00062 } else
00063 Com_Printf("%s", msg);
00064 }
00065
00066 static void SV_error (const char *fmt, ...) __attribute__((noreturn));
00071 static void SV_error (const char *fmt, ...)
00072 {
00073 char msg[1024];
00074 va_list argptr;
00075
00076 va_start(argptr, fmt);
00077 Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
00078 va_end(argptr);
00079
00080 Com_Error(ERR_DROP, "Game Error: %s", msg);
00081 }
00082
00083 static int SV_FindIndex (const char *name, int start, int max, qboolean create)
00084 {
00085 int i;
00086
00087 if (!name || !name[0])
00088 return 0;
00089
00090 for (i = 1; i < max && SV_GetConfigString(start + i)[0] != '\0'; i++) {
00091 const char *configString = SV_GetConfigString(start + i);
00092 if (!strcmp(configString, name))
00093 return i;
00094 }
00095
00096 if (!create)
00097 return 0;
00098
00099 if (i == max)
00100 Com_Error(ERR_DROP, "*Index: overflow '%s' start: %i, max: %i", name, start, max);
00101
00102 SV_SetConfigString(start + i, name);
00103
00104 if (Com_ServerState() != ss_loading) {
00105 struct dbuffer *msg = new_dbuffer();
00106 NET_WriteByte(msg, svc_configstring);
00107 NET_WriteShort(msg, start + i);
00108 NET_WriteString(msg, name);
00109 SV_Multicast(~0, msg);
00110 }
00111
00112 return i;
00113 }
00114
00115 static int SV_ModelIndex (const char *name)
00116 {
00117 return SV_FindIndex(name, CS_MODELS, MAX_MODELS, qtrue);
00118 }
00119
00124 static void SV_SetModel (edict_t * ent, const char *name)
00125 {
00126 if (!name)
00127 Com_Error(ERR_DROP, "SV_SetModel: NULL");
00128
00129 ent->modelindex = SV_ModelIndex(name);
00130
00131
00132 if (name[0] == '*') {
00133 const cBspModel_t *mod = CM_InlineModel(&sv.mapTiles, name);
00134
00135 VectorCopy(mod->mins, ent->mins);
00136 VectorCopy(mod->maxs, ent->maxs);
00137
00138
00139 CM_SetInlineModelOrientation(&sv.mapTiles, name, ent->origin, ent->angles);
00140 }
00141 }
00142
00146 static void SV_Configstring (int index, const char *fmt, ...)
00147 {
00148 char val[MAX_TOKEN_CHARS * MAX_TILESTRINGS];
00149 va_list argptr;
00150
00151 if (index < 0 || index >= MAX_CONFIGSTRINGS)
00152 Com_Error(ERR_DROP, "configstring: bad index %i", index);
00153
00154 va_start(argptr, fmt);
00155 Q_vsnprintf(val, sizeof(val), fmt, argptr);
00156 va_end(argptr);
00157
00158 SV_SetConfigString(index, val);
00159
00160 if (Com_ServerState() != ss_loading) {
00161 struct dbuffer *msg = new_dbuffer();
00162 NET_WriteByte(msg, svc_configstring);
00163 NET_WriteShort(msg, index);
00164 NET_WriteString(msg, val);
00165
00166
00167 SV_Multicast(~0, msg);
00168 }
00169 }
00170
00171 static void SV_WriteChar (char c)
00172 {
00173 NET_WriteChar(sv.pendingEvent.buf, c);
00174 }
00175
00176 static void SV_WriteByte (byte c)
00177 {
00178 NET_WriteByte(sv.pendingEvent.buf, c);
00179 }
00180
00185 static byte* SV_WriteDummyByte (byte c)
00186 {
00187 pending_event_t *p = &sv.pendingEvent;
00188 byte *pos = (byte*) p->buf->end;
00189 NET_WriteByte(p->buf, c);
00190 assert(pos != NULL);
00191 return pos;
00192 }
00193
00194 static void SV_WriteShort (int c)
00195 {
00196 NET_WriteShort(sv.pendingEvent.buf, c);
00197 }
00198
00199 static void SV_WriteLong (int c)
00200 {
00201 NET_WriteLong(sv.pendingEvent.buf, c);
00202 }
00203
00204 static void SV_WriteString (const char *s)
00205 {
00206 NET_WriteString(sv.pendingEvent.buf, s);
00207 }
00208
00209 static void SV_WritePos (const vec3_t pos)
00210 {
00211 NET_WritePos(sv.pendingEvent.buf, pos);
00212 }
00213
00214 static void SV_WriteGPos (const pos3_t pos)
00215 {
00216 NET_WriteGPos(sv.pendingEvent.buf, pos);
00217 }
00218
00219 static void SV_WriteDir (const vec3_t dir)
00220 {
00221 NET_WriteDir(sv.pendingEvent.buf, dir);
00222 }
00223
00224 static void SV_WriteAngle (float f)
00225 {
00226 NET_WriteAngle(sv.pendingEvent.buf, f);
00227 }
00228
00229 static void SV_WriteFormat (const char *format, ...)
00230 {
00231 va_list ap;
00232 va_start(ap, format);
00233 NET_vWriteFormat(sv.pendingEvent.buf, format, ap);
00234 va_end(ap);
00235 }
00236
00237 static int SV_ReadChar (void)
00238 {
00239 return NET_ReadChar(sv.messageBuffer);
00240 }
00241
00242 static int SV_ReadByte (void)
00243 {
00244 return NET_ReadByte(sv.messageBuffer);
00245 }
00246
00247 static int SV_ReadShort (void)
00248 {
00249 return NET_ReadShort(sv.messageBuffer);
00250 }
00251
00252 static int SV_ReadLong (void)
00253 {
00254 return NET_ReadLong(sv.messageBuffer);
00255 }
00256
00257 static int SV_ReadString (char *str, size_t length)
00258 {
00259 return NET_ReadString(sv.messageBuffer, str, length);
00260 }
00261
00262 static void SV_ReadPos (vec3_t pos)
00263 {
00264 NET_ReadPos(sv.messageBuffer, pos);
00265 }
00266
00267 static void SV_ReadGPos (pos3_t pos)
00268 {
00269 NET_ReadGPos(sv.messageBuffer, pos);
00270 }
00271
00272 static void SV_ReadDir (vec3_t vector)
00273 {
00274 NET_ReadDir(sv.messageBuffer, vector);
00275 }
00276
00277 static float SV_ReadAngle (void)
00278 {
00279 return NET_ReadAngle(sv.messageBuffer);
00280 }
00281
00282 static void SV_ReadData (void *buffer, int size)
00283 {
00284 NET_ReadData(sv.messageBuffer, buffer, size);
00285 }
00286
00290 static void SV_ReadFormat (const char *format, ...)
00291 {
00292 va_list ap;
00293
00294 assert(format);
00295 if (!*format)
00296 return;
00297
00298 va_start(ap, format);
00299 NET_vReadFormat(sv.messageBuffer, format, ap);
00300 va_end(ap);
00301 }
00302
00306 static void SV_AbortEvents (void)
00307 {
00308 pending_event_t *p = &sv.pendingEvent;
00309
00310 if (!p->pending)
00311 return;
00312
00313 p->pending = qfalse;
00314 free_dbuffer(p->buf);
00315 p->buf = NULL;
00316 }
00317
00321 static void SV_EndEvents (void)
00322 {
00323 pending_event_t *p = &sv.pendingEvent;
00324
00325 if (!p->pending)
00326 return;
00327
00328 NET_WriteByte(p->buf, EV_NULL);
00329 SV_Multicast(p->playerMask, p->buf);
00330 p->pending = qfalse;
00331
00332 p->buf = NULL;
00333 }
00334
00339 static void SV_AddEvent (unsigned int mask, int eType)
00340 {
00341 pending_event_t *p = &sv.pendingEvent;
00342 Com_DPrintf(DEBUG_EVENTSYS, "Event type: %i (mask %i)\n", eType, mask);
00343
00344
00345 if (p->pending)
00346 SV_EndEvents();
00347
00348
00349 p->pending = qtrue;
00350 p->playerMask = mask;
00351 p->type = eType;
00352 p->buf = new_dbuffer();
00353
00354
00355 NET_WriteByte(p->buf, svc_event);
00356 NET_WriteByte(p->buf, eType);
00357 }
00358
00362 static int SV_GetEvent (void)
00363 {
00364 const pending_event_t *p = &sv.pendingEvent;
00365 if (!p->pending)
00366 return -1;
00367
00368 return p->type;
00369 }
00370
00374 static void *SV_TagAlloc (int size, int tagNum, const char *file, int line)
00375 {
00376 if (tagNum < 0)
00377 tagNum *= -1;
00378
00379 return _Mem_Alloc(size, qtrue, sv.gameSysPool, tagNum, file, line);
00380 }
00381
00382 static void SV_MemFree (void *ptr, const char *file, int line)
00383 {
00384 _Mem_Free(ptr, file, line);
00385 }
00386
00390 static void SV_FreeTags (int tagNum, const char *file, int line)
00391 {
00392 if (tagNum < 0)
00393 tagNum *= -1;
00394
00395 _Mem_FreeTag(sv.gameSysPool, tagNum, file, line);
00396 }
00397
00398 static qboolean SV_TestLine (const vec3_t start, const vec3_t stop, const int levelmask)
00399 {
00400 return TR_TestLine(&sv.mapTiles, start, stop, levelmask);
00401 }
00402
00403 static qboolean SV_TestLineWithEnt (const vec3_t start, const vec3_t stop, const int levelmask, const char **entlist)
00404 {
00405
00406 const qboolean hit = CM_EntTestLine(&sv.mapTiles, start, stop, levelmask, entlist);
00407 return hit;
00408 }
00409
00410 static void SV_RecalcRouting (routing_t *map, const char *name, const char **list)
00411 {
00412 Grid_RecalcRouting(&sv.mapTiles, map, name, list);
00413 }
00414
00415 static void SV_SetInlineModelOrientation (const char *name, const vec3_t origin, const vec3_t angles)
00416 {
00417 CM_SetInlineModelOrientation(&sv.mapTiles, name, origin, angles);
00418 }
00419
00420 static void SV_UnloadGame (void)
00421 {
00422 #ifndef GAME_HARD_LINKED
00423 if (svs.gameLibrary) {
00424 Com_Printf("Unload the game library\n");
00425 SDL_UnloadObject(svs.gameLibrary);
00426 }
00427 #endif
00428 svs.gameLibrary = NULL;
00429 }
00430
00431 #ifndef HARD_LINKED_GAME
00432 static qboolean SV_LoadGame (const char *path)
00433 {
00434 char name[MAX_OSPATH];
00435
00436 Com_sprintf(name, sizeof(name), "%s/game_"CPUSTRING".%s", path, SHARED_EXT);
00437 svs.gameLibrary = SDL_LoadObject(name);
00438 if (!svs.gameLibrary) {
00439 Com_sprintf(name, sizeof(name), "%s/game.%s", path, SHARED_EXT);
00440 svs.gameLibrary = SDL_LoadObject(name);
00441 }
00442
00443 if (svs.gameLibrary) {
00444 Com_Printf("found at '%s'\n", path);
00445 return qtrue;
00446 } else {
00447 Com_Printf("not found at '%s'\n", path);
00448 Com_DPrintf(DEBUG_SYSTEM, "%s\n", SDL_GetError());
00449 return qfalse;
00450 }
00451 }
00452 #endif
00453
00457 static game_export_t *SV_GetGameAPI (game_import_t *parms)
00458 {
00459 #ifndef HARD_LINKED_GAME
00460 void *(*GetGameAPI) (void *);
00461
00462 const char *path;
00463 #endif
00464
00465 if (svs.gameLibrary)
00466 Com_Error(ERR_FATAL, "SV_GetGameAPI without SV_UnloadGame");
00467
00468 #ifndef HARD_LINKED_GAME
00469 Com_Printf("------- Loading game.%s -------\n", SHARED_EXT);
00470
00471 #ifdef PKGLIBDIR
00472 SV_LoadGame(PKGLIBDIR);
00473 #endif
00474
00475
00476 path = NULL;
00477 while (!svs.gameLibrary) {
00478 path = FS_NextPath(path);
00479 if (!path)
00480
00481 return NULL;
00482 else if (SV_LoadGame(path))
00483 break;
00484 }
00485
00486 GetGameAPI = (void *)SDL_LoadFunction(svs.gameLibrary, "GetGameAPI");
00487 if (!GetGameAPI) {
00488 SV_UnloadGame();
00489 return NULL;
00490 }
00491 #endif
00492
00493 return GetGameAPI(parms);
00494 }
00495
00501 void SV_ShutdownGameProgs (void)
00502 {
00503 uint32_t size;
00504
00505 if (!svs.ge)
00506 return;
00507
00508 if (svs.gameThread) {
00509 Com_Printf("Shutdown the game thread\n");
00510 SDL_KillThread(svs.gameThread);
00511 svs.gameThread = NULL;
00512 }
00513
00514 svs.ge->Shutdown();
00515
00516 size = Mem_PoolSize(sv.gameSysPool);
00517 if (size > 0) {
00518 Com_Printf("WARNING: Game memory leak (%u bytes)\n", size);
00519 Cmd_ExecuteString(va("mem_stats %s", sv.gameSysPool->name));
00520 }
00521
00522 Mem_DeletePool(sv.gameSysPool);
00523 sv.gameSysPool = NULL;
00524
00525 SV_UnloadGame();
00526
00527 svs.ge = NULL;
00528 }
00529
00535 int SV_RunGameFrameThread (void *data)
00536 {
00537 do {
00538 SV_RunGameFrame();
00539 } while (!sv.endgame);
00540
00541 return 0;
00542 }
00543
00550 void SV_RunGameFrame (void)
00551 {
00552 SDL_mutexP(svs.serverMutex);
00553
00554 sv.endgame = svs.ge->RunFrame();
00555
00556 SDL_mutexV(svs.serverMutex);
00557 }
00558
00563 void SV_InitGameProgs (void)
00564 {
00565 game_import_t import;
00566
00567
00568
00569
00570
00571 import.BroadcastPrintf = SV_BroadcastPrintf;
00572 import.DPrintf = SV_dprintf;
00573 import.PlayerPrintf = SV_PlayerPrintf;
00574 import.Error = SV_error;
00575
00576 import.Trace = SV_Trace;
00577 import.LinkEdict = SV_LinkEdict;
00578 import.UnlinkEdict = SV_UnlinkEdict;
00579 import.BoxEdicts = SV_AreaEdicts;
00580 import.TouchEdicts = SV_TouchEdicts;
00581
00582 import.TestLine = SV_TestLine;
00583 import.TestLineWithEnt = SV_TestLineWithEnt;
00584 import.GrenadeTarget = Com_GrenadeTarget;
00585
00586 import.MoveCalc = Grid_MoveCalc;
00587 import.MoveStore = Grid_MoveStore;
00588 import.MoveLength = Grid_MoveLength;
00589 import.MoveNext = Grid_MoveNext;
00590 import.GridFloor = Grid_Floor;
00591 import.GetTUsForDirection = Grid_GetTUsForDirection;
00592 import.GridFall = Grid_Fall;
00593 import.GridPosToVec = Grid_PosToVec;
00594 import.GridRecalcRouting = SV_RecalcRouting;
00595
00596 import.ModelIndex = SV_ModelIndex;
00597
00598 import.SetInlineModelOrientation = SV_SetInlineModelOrientation;
00599
00600 import.SetModel = SV_SetModel;
00601
00602 import.ConfigString = SV_Configstring;
00603 import.PositionedSound = SV_StartSound;
00604
00605 import.PointContents = SV_PointContents;
00606 import.GetFootstepSound = SV_GetFootstepSound;
00607 import.GetBounceFraction = SV_GetBounceFraction;
00608 import.LoadModelMinsMaxs = SV_LoadModelMinsMaxs;
00609
00610 import.FS_Gamedir = FS_Gamedir;
00611 import.FS_LoadFile = FS_LoadFile;
00612 import.FS_FreeFile = FS_FreeFile;
00613
00614 import.WriteChar = SV_WriteChar;
00615 import.WriteByte = SV_WriteByte;
00616 import.WriteDummyByte = SV_WriteDummyByte;
00617 import.WriteShort = SV_WriteShort;
00618 import.WriteLong = SV_WriteLong;
00619 import.WriteString = SV_WriteString;
00620 import.WritePos = SV_WritePos;
00621 import.WriteGPos = SV_WriteGPos;
00622 import.WriteDir = SV_WriteDir;
00623 import.WriteAngle = SV_WriteAngle;
00624 import.WriteFormat = SV_WriteFormat;
00625
00626 import.AbortEvents = SV_AbortEvents;
00627 import.EndEvents = SV_EndEvents;
00628 import.AddEvent = SV_AddEvent;
00629 import.GetEvent = SV_GetEvent;
00630
00631 import.ReadChar = SV_ReadChar;
00632 import.ReadByte = SV_ReadByte;
00633 import.ReadShort = SV_ReadShort;
00634 import.ReadLong = SV_ReadLong;
00635 import.ReadString = SV_ReadString;
00636 import.ReadPos = SV_ReadPos;
00637 import.ReadGPos = SV_ReadGPos;
00638 import.ReadDir = SV_ReadDir;
00639 import.ReadAngle = SV_ReadAngle;
00640 import.ReadData = SV_ReadData;
00641 import.ReadFormat = SV_ReadFormat;
00642
00643 import.GetConstInt = Com_GetConstInt;
00644 import.GetConstIntFromNamespace = Com_GetConstIntFromNamespace;
00645 import.GetConstVariable = Com_GetConstVariable;
00646 import.RegisterConstInt = Com_RegisterConstInt;
00647 import.UnregisterConstVariable = Com_UnregisterConstVariable;
00648
00649 import.GetCharacterValues = Com_GetCharacterValues;
00650
00651 import.TagMalloc = SV_TagAlloc;
00652 import.TagFree = SV_MemFree;
00653 import.FreeTags = SV_FreeTags;
00654
00655 import.Cvar_Get = Cvar_Get;
00656 import.Cvar_Set = Cvar_Set;
00657 import.Cvar_String = Cvar_GetString;
00658
00659 import.Cmd_Argc = Cmd_Argc;
00660 import.Cmd_Argv = Cmd_Argv;
00661 import.Cmd_Args = Cmd_Args;
00662 import.AddCommandString = Cbuf_AddText;
00663
00664 import.seed = Sys_Milliseconds();
00665 import.csi = &csi;
00666
00667
00668 import.routingMap = sv.mapData.map;
00669
00670 svs.ge = SV_GetGameAPI(&import);
00671
00672 if (!svs.ge)
00673 Com_Error(ERR_DROP, "failed to load game library");
00674 if (svs.ge->apiversion != GAME_API_VERSION)
00675 Com_Error(ERR_DROP, "game is version %i, not %i", svs.ge->apiversion, GAME_API_VERSION);
00676
00677 sv.gameSysPool = Mem_CreatePool("Server: Game system");
00678
00679 svs.ge->Init();
00680
00681 if (sv_threads->integer)
00682 svs.gameThread = SDL_CreateThread(SV_RunGameFrameThread, NULL);
00683 }