File: server\sv_game.c

    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         
  204         if (sv.state != ss_loading)
  205         {       // send the update to everyone
  206                 SZ_Clear (&sv.multicast);
  207                 MSG_WriteChar (&sv.multicast, svc_configstring);
  208                 MSG_WriteShort (&sv.multicast, index);
  209                 MSG_WriteString (&sv.multicast, val);
  210 
  211                 SV_Multicast (vec3_origin, MULTICAST_ALL_R);
  212         }
  213 }
  214 
  215 
  216 
  217 void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
  218 void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
  219 void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
  220 void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
  221 void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
  222 void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
  223 void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
  224 void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
  225 void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
  226 
  227 
  228 /*
  229 =================
  230 PF_inPVS
  231 
  232 Also checks portalareas so that doors block sight
  233 =================
  234 */
  235 qboolean PF_inPVS (vec3_t p1, vec3_t p2)
  236 {
  237         int             leafnum;
  238         int             cluster;
  239         int             area1, area2;
  240         byte    *mask;
  241 
  242         leafnum = CM_PointLeafnum (p1);
  243         cluster = CM_LeafCluster (leafnum);
  244         area1 = CM_LeafArea (leafnum);
  245         mask = CM_ClusterPVS (cluster);
  246 
  247         leafnum = CM_PointLeafnum (p2);
  248         cluster = CM_LeafCluster (leafnum);
  249         area2 = CM_LeafArea (leafnum);
  250         if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
  251                 return false;
  252         if (!CM_AreasConnected (area1, area2))
  253                 return false;           // a door blocks sight
  254         return true;
  255 }
  256 
  257 
  258 /*
  259 =================
  260 PF_inPHS
  261 
  262 Also checks portalareas so that doors block sound
  263 =================
  264 */
  265 qboolean PF_inPHS (vec3_t p1, vec3_t p2)
  266 {
  267         int             leafnum;
  268         int             cluster;
  269         int             area1, area2;
  270         byte    *mask;
  271 
  272         leafnum = CM_PointLeafnum (p1);
  273         cluster = CM_LeafCluster (leafnum);
  274         area1 = CM_LeafArea (leafnum);
  275         mask = CM_ClusterPHS (cluster);
  276 
  277         leafnum = CM_PointLeafnum (p2);
  278         cluster = CM_LeafCluster (leafnum);
  279         area2 = CM_LeafArea (leafnum);
  280         if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
  281                 return false;           // more than one bounce away
  282         if (!CM_AreasConnected (area1, area2))
  283                 return false;           // a door blocks hearing
  284 
  285         return true;
  286 }
  287 
  288 void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
  289     float attenuation, float timeofs)
  290 {
  291         if (!entity)
  292                 return;
  293         SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
  294 }
  295 
  296 //==============================================
  297 
  298 /*
  299 ===============
  300 SV_ShutdownGameProgs
  301 
  302 Called when either the entire server is being killed, or
  303 it is changing to a different game directory.
  304 ===============
  305 */
  306 void SV_ShutdownGameProgs (void)
  307 {
  308         if (!ge)
  309                 return;
  310         ge->Shutdown ();
  311         Sys_UnloadGame ();
  312         ge = NULL;
  313 }
  314 
  315 /*
  316 ===============
  317 SV_InitGameProgs
  318 
  319 Init the game subsystem for a new map
  320 ===============
  321 */
  322 void SCR_DebugGraph (float value, int color);
  323 
  324 void SV_InitGameProgs (void)
  325 {
  326         game_import_t   import;
  327 
  328         // unload anything we have now
  329         if (ge)
  330                 SV_ShutdownGameProgs ();
  331 
  332 
  333         // load a new game dll
  334         import.multicast = SV_Multicast;
  335         import.unicast = PF_Unicast;
  336         import.bprintf = SV_BroadcastPrintf;
  337         import.dprintf = PF_dprintf;
  338         import.cprintf = PF_cprintf;
  339         import.centerprintf = PF_centerprintf;
  340         import.error = PF_error;
  341 
  342         import.linkentity = SV_LinkEdict;
  343         import.unlinkentity = SV_UnlinkEdict;
  344         import.BoxEdicts = SV_AreaEdicts;
  345         import.trace = SV_Trace;
  346         import.pointcontents = SV_PointContents;
  347         import.setmodel = PF_setmodel;
  348         import.inPVS = PF_inPVS;
  349         import.inPHS = PF_inPHS;
  350         import.Pmove = Pmove;
  351 
  352         import.modelindex = SV_ModelIndex;
  353         import.soundindex = SV_SoundIndex;
  354         import.imageindex = SV_ImageIndex;
  355 
  356         import.configstring = PF_Configstring;
  357         import.sound = PF_StartSound;
  358         import.positioned_sound = SV_StartSound;
  359 
  360         import.WriteChar = PF_WriteChar;
  361         import.WriteByte = PF_WriteByte;
  362         import.WriteShort = PF_WriteShort;
  363         import.WriteLong = PF_WriteLong;
  364         import.WriteFloat = PF_WriteFloat;
  365         import.WriteString = PF_WriteString;
  366         import.WritePosition = PF_WritePos;
  367         import.WriteDir = PF_WriteDir;
  368         import.WriteAngle = PF_WriteAngle;
  369 
  370         import.TagMalloc = Z_TagMalloc;
  371         import.TagFree = Z_Free;
  372         import.FreeTags = Z_FreeTags;
  373 
  374         import.cvar = Cvar_Get;
  375         import.cvar_set = Cvar_Set;
  376         import.cvar_forceset = Cvar_ForceSet;
  377 
  378         import.argc = Cmd_Argc;
  379         import.argv = Cmd_Argv;
  380         import.args = Cmd_Args;
  381         import.AddCommandString = Cbuf_AddText;
  382 
  383         import.DebugGraph = SCR_DebugGraph;
  384         import.SetAreaPortalState = CM_SetAreaPortalState;
  385         import.AreasConnected = CM_AreasConnected;
  386 
  387         ge = (game_export_t *)Sys_GetGameAPI (&import);
  388 
  389         if (!ge)
  390                 Com_Error (ERR_DROP, "failed to load game DLL");
  391         if (ge->apiversion != GAME_API_VERSION)
  392                 Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
  393                 GAME_API_VERSION);
  394 
  395         ge->Init ();
  396 }
  397 
  398