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