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