1
0
Fork 0
forked from fte/fteqw

Fix up some obscure builds.

This commit is contained in:
Shpoike 2023-03-27 18:22:00 +01:00
parent 8c8a4eaf0e
commit 1ce399e969
19 changed files with 86 additions and 41 deletions

View file

@ -1404,7 +1404,7 @@ void CL_CheckForResend (void)
}
else
{
CL_ConnectAbort ("No route to host, giving up\n");
CL_ConnectAbort ("Unable to connect to %s, giving up\n", cls.servername);
NET_CloseClient();
}

View file

@ -978,10 +978,9 @@ qboolean CL_CheckOrEnqueDownloadFile (const char *filename, const char *localnam
if (flags & DLLF_ALLOWWEB)
{
extern cvar_t sv_dlURL;
const char *dlURL = InfoBuf_ValueForKey(&cl.serverinfo, "sv_dlURL");
if (!*dlURL)
dlURL = sv_dlURL.string;
dlURL = fs_dlURL.string;
flags &= ~(DLLF_TRYWEB|DLLF_ALLOWWEB);
if (*dlURL && (flags & DLLF_NONGAME) && !strncmp(filename, "package/", 8))
{ //filename is something like: package/GAMEDIR/foo.pk3

View file

@ -1512,20 +1512,32 @@ static int QDECL V_DepthSortTwoEntities(const void *p1,const void *p2)
}
void V_DepthSortEntities(float *vieworg)
{
int i;
int i, j;
vec3_t disp;
for (i = 0; i < cl_numvisedicts; i++)
{
if (cl_visedicts[i].flags & RF_WEAPONMODEL)
{ //weapon models have their own extra matrix thing going on. don't mess up because of it.
cl_visedicts[i].angles[0] = 0;
//however, qsort is not stable so hide ordering in here so they still come out with the same ordering, at least with respect to each other.
cl_visedicts[i].angles[0] = -1-i;
continue;
}
if (cl_visedicts[i].rtype == RT_MODEL && cl_visedicts[i].model && cl_visedicts[i].model->type == mod_brush)
{
VectorAdd(cl_visedicts[i].model->maxs, cl_visedicts[i].model->mins, disp);
VectorMA(cl_visedicts[i].origin, 0.5, disp, disp);
VectorSubtract(disp, vieworg, disp);
if (1)
{ //by nearest point.
for (j=0 ; j<3 ; j++)
{
disp[j] = vieworg[j] - cl_visedicts[i].origin[j];
disp[j] -= bound(cl_visedicts[i].model->mins[j], disp[j], cl_visedicts[i].model->maxs[j]);
}
}
else
{ //by midpoint...
VectorAdd(cl_visedicts[i].model->maxs, cl_visedicts[i].model->mins, disp);
VectorMA(cl_visedicts[i].origin, 0.5, disp, disp);
VectorSubtract(disp, vieworg, disp);
}
}
else
{
@ -2181,7 +2193,7 @@ void R_DrawNameTags(void)
}
else
#endif
if (w && w->progs && svs.gametype == GT_PROGS)
if (w && w->progs && w->progs->saveent)
{
int best = 0;
float bestscore = 0, score = 0;

View file

@ -33,6 +33,11 @@ static cvar_t fs_gamepath = CVARAFD ("fs_gamepath"/*q3ish*/, "", "fs_gamedir"/
static cvar_t fs_basepath = CVARAFD ("fs_basepath"/*q3*/, "", "fs_basedir"/*q2*/, CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2/Q3 compat. System path of the base directory.");
static cvar_t fs_homepath = CVARAFD ("fs_homepath"/*q3ish*/, "", "fs_homedir"/*q2ish*/, CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2/Q3 compat. System path of the base directory.");
static cvar_t dpcompat_ignoremodificationtimes = CVARAFD("fs_packageprioritisation", "1", "dpcompat_ignoremodificationtimes", CVAR_NOUNSAFEEXPAND|CVAR_NOSAVE, "Favours the package that is:\n0: Most recently modified\n1: Is alphabetically last (favour z over a, 9 over 0).");
#ifdef FTE_TARGET_WEB
cvar_t fs_dlURL = CVARAFD(/*ioq3*/"sv_dlURL", "", /*dp*/"sv_curl_defaulturl", CVAR_SERVERINFO|CVAR_NOSAVE, "Provides clients with an external url from which they can obtain pk3s/packages from an external http server instead of having to download over udp.");
#else
cvar_t fs_dlURL = CVARAFD(/*ioq3*/"sv_dlURL", "", /*dp*/"sv_curl_defaulturl", CVAR_SERVERINFO|CVAR_ARCHIVE, "Provides clients with an external url from which they can obtain pk3s/packages from an external http server instead of having to download over udp.");
#endif
int active_fs_cachetype;
static int fs_referencetype;
int fs_finds;
@ -7717,6 +7722,7 @@ void COM_InitFilesystem (void)
Cvar_Register(&fs_gamepath, "Filesystem");
Cvar_Register(&fs_basepath, "Filesystem");
Cvar_Register(&fs_homepath, "Filesystem");
Cvar_Register(&fs_dlURL, "Filesystem");
COM_InitHomedir(NULL);

View file

@ -27,6 +27,7 @@ extern int fs_hash_files; //for tracking efficiency. no functional use.
extern qboolean fs_readonly; //if true, fopen(, "w") should always fail.
extern void *fs_thread_mutex;
extern float fs_accessed_time;
extern cvar_t fs_dlURL;
struct searchpath_s;
struct searchpathfuncs_s

View file

@ -69,7 +69,6 @@ struct cminfo_s;
void CM_Init(void);
static qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits);
static qboolean VARGS CM_AreasConnected (struct model_s *mod, unsigned int area1, unsigned int area2);
static size_t CM_WriteAreaBits (struct model_s *mod, qbyte *buffer, size_t buffersize, int area, qboolean merge);
static qbyte *CM_ClusterPVS (struct model_s *mod, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge);
@ -82,9 +81,12 @@ static void CM_SetAreaPortalState (model_t *mod, unsigned int portalnum, unsigne
static size_t CM_SaveAreaPortalBlob (model_t *mod, void **data);
static size_t CM_LoadAreaPortalBlob (model_t *mod, void *ptr, size_t ptrsize);
#ifdef HAVE_SERVER
static unsigned int Q23BSP_FatPVS(model_t *mod, const vec3_t org, pvsbuffer_t *buffer, qboolean merge);
static qboolean Q23BSP_EdictInFatPVS(model_t *mod, const struct pvscache_s *ent, const qbyte *pvs, const int *areas);
static void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, const float *mins, const float *maxs);
static qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits);
#endif
#ifdef HAVE_CLIENT
static void CM_PrepareFrame(model_t *mod, refdef_t *refdef, int area, int viewclusters[2], pvsbuffer_t *vis, qbyte **entvis_out, qbyte **surfvis_out);
@ -4123,7 +4125,7 @@ static void CM_OpenAllPortals(model_t *mod, char *ents) //this is a compleate ha
#endif
#if defined(HAVE_SERVER) && defined(Q3BSPS)
#if defined(Q3BSPS)
static void CalcClusterPHS(cminfo_t *prv, int cluster)
{
int j, k, l, index;
@ -4167,6 +4169,8 @@ static void CalcClusterPHS(cminfo_t *prv, int cluster)
}
prv->phscalced[cluster>>3] |= 1<<(cluster&7);
}
#endif
#if defined(HAVE_SERVER) && defined(Q3BSPS)
static void CMQ3_CalcPHS (model_t *mod)
{
cminfo_t *prv = (cminfo_t*)mod->meshinfo;
@ -5197,12 +5201,14 @@ static int CM_PointLeafnum_r (model_t *mod, const vec3_t p, int num)
return -1 - num;
}
#ifdef HAVE_SERVER
static int CM_PointLeafnum (model_t *mod, const vec3_t p)
{
if (!mod || mod->loadstate != MLS_LOADED)
return 0; // sound may call this without map loaded
return CM_PointLeafnum_r (mod, p, 0);
}
#endif
static int CM_PointCluster (model_t *mod, const vec3_t p, int *area)
{
@ -6884,6 +6890,7 @@ static qbyte *CM_ClusterPHS (model_t *mod, int cluster, pvsbuffer_t *buffer)
return buffer->buffer;
}
#ifdef HAVE_SERVER
static unsigned int SV_Q2BSP_FatPVS (model_t *mod, const vec3_t org, pvsbuffer_t *result, qboolean merge)
{
int leafs[64];
@ -7053,6 +7060,7 @@ static void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, cons
}
}
}
#endif
/*
===============================================================================
@ -7314,6 +7322,7 @@ static size_t CM_LoadAreaPortalBlob (model_t *mod, void *ptr, size_t ptrsize)
return 0;
}
#ifdef HAVE_SERVER
/*
=============
CM_HeadnodeVisible
@ -7344,6 +7353,7 @@ static qboolean CM_HeadnodeVisible (model_t *mod, int nodenum, const qbyte *visb
return true;
return CM_HeadnodeVisible(mod, node->childnum[1], visbits);
}
#endif
static unsigned int Q2BSP_PointContents(model_t *mod, const vec3_t axis[3], const vec3_t p)
{

View file

@ -72,6 +72,10 @@ Note: testing this stuff is a pain when eg browsers do NOT support DTLS1.0 any m
#define SECPKG_ATTR_DTLS_MTU 34
#endif
#ifndef CRYPT_ARCHIVABLE
#define CRYPT_ARCHIVABLE 0x00004000
#endif
//hungarian ensures we hit no macros.
static struct

View file

@ -5531,6 +5531,7 @@ void FTENET_TCP_PrintStatus(ftenet_generic_connection_t *gcon)
static qboolean FTENET_TCP_KillStream(ftenet_tcp_connection_t *con, ftenet_tcp_stream_t *st, const char *reason)
{ //some sort of error. kill the connection info (will be cleaned up later)
#ifdef HAVE_HTTPSV
if (st->clienttype == TCPC_WEBRTC_CLIENT && st->clientstream && !strcmp(st->webrtc.resource, st->webrtc.resource))
{
qbyte msg[256];
@ -5541,6 +5542,7 @@ static qboolean FTENET_TCP_KillStream(ftenet_tcp_connection_t *con, ftenet_tcp_s
FTENET_TCP_WebSocket_Splurge(st, WS_PACKETTYPE_BINARYFRAME, msg, 3+strlen(msg+3));
}
#endif
#ifdef HAVE_EPOLL
if (st->socketnum != INVALID_SOCKET)
@ -6312,6 +6314,7 @@ static qboolean FTENET_TCP_GetPacket(ftenet_generic_connection_t *gcon)
}
FTENET_TCP_Flush(con, st);
#ifdef HAVE_HTTPSV
if (st->clienttype==TCPC_WEBRTC_CLIENT && st->webrtc.target.type!=NA_INVALID && st->webrtc.resendtime < timeval && st->clientstream)
{
if (st->webrtc.offer)
@ -6385,6 +6388,7 @@ static qboolean FTENET_TCP_GetPacket(ftenet_generic_connection_t *gcon)
else
st->webrtc.resendtime = timeval + 30;
}
#endif
}
if (con->generic.thesocket != INVALID_SOCKET && con->active < 256)

View file

@ -971,7 +971,7 @@ static qhandle_t QDECL Plug_FS_Open(const char *fname, qhandle_t *outhandle, int
#ifndef WEBCLIENT
f = NULL;
#else
Con_DPrintf("Plugin %s requesting %s\n", currentplug->name, fname);
Con_Printf("Plugin %s requesting %s\n", currentplug->name, fname);
handle = Plug_NewStreamHandle(STREAM_WEB);
pluginstreamarray[handle].dl = HTTP_CL_Get(fname, NULL, Plug_DownloadComplete);
pluginstreamarray[handle].dl->user_num = handle;
@ -2033,10 +2033,15 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
InfoBuf_ValueForKey,
Info_ValueForKey,
Info_SetValueForKey,
#ifdef HAVE_SERVER
SV_DropClient,
SV_ExtractFromUserinfo,
SV_ChallengePasses,
#else
NULL,
NULL,
NULL,
#endif
};
if (structsize == sizeof(funcs))
return &funcs;

View file

@ -3942,7 +3942,7 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
for (j=0 ; j<3 ; j++)
{
eorg[j] = org[j] - ent->v->origin[j];
eorg[j] -= bound(ent->v->mins[j], org[j], ent->v->maxs[j]);
eorg[j] -= bound(ent->v->mins[j], eorg[j], ent->v->maxs[j]);
}
}
else
@ -3972,7 +3972,7 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
for (j=0 ; j<3 ; j++)
{
eorg[j] = org[j] - ent->v->origin[j];
eorg[j] -= bound(ent->v->mins[j], org[j], ent->v->maxs[j]);
eorg[j] -= bound(ent->v->mins[j], eorg[j], ent->v->maxs[j]);
}
}
else

View file

@ -11,7 +11,7 @@ struct q3gamecode_s
void (*SendAuthPacket)(struct ftenet_connections_s *socket, netadr_t *gameserver);
void (*SendConnectPacket)(struct ftenet_connections_s *socket, netadr_t *to, int challenge, int qport, infobuf_t *userinfo);
void (*Established)(void);
void (*VARGS SendClientCommand)(const char *fmt, ...) LIKEPRINTF(1);
void (VARGS *SendClientCommand)(const char *fmt, ...) LIKEPRINTF(1);
void (*SendCmd)(struct ftenet_connections_s *socket, struct usercmd_s *cmd, unsigned int movesequence, double gametime);
int (*ParseServerMessage) (sizebuf_t *msg);
void (*Disconnect) (struct ftenet_connections_s *socket); //disconnects from the server, killing all connection+cgame state.

View file

@ -78,11 +78,6 @@ extern cvar_t password;
#endif
cvar_t spectator_password = CVARF("spectator_password", "", CVAR_NOUNSAFEEXPAND); // password for entering as a sepctator
#ifdef FTE_TARGET_WEB
cvar_t sv_dlURL = CVARAFD(/*ioq3*/"sv_dlURL", "", /*dp*/"sv_curl_defaulturl", CVAR_SERVERINFO|CVAR_NOSAVE, "Provides clients with an external url from which they can obtain pk3s/packages from an external http server instead of having to download over udp.");
#else
cvar_t sv_dlURL = CVARAFD(/*ioq3*/"sv_dlURL", "", /*dp*/"sv_curl_defaulturl", CVAR_SERVERINFO|CVAR_ARCHIVE, "Provides clients with an external url from which they can obtain pk3s/packages from an external http server instead of having to download over udp.");
#endif
cvar_t allow_download = CVARAD("allow_download", "1", /*q3*/"sv_allowDownload", "If 1, permits downloading. Set to 0 to unconditionally block *ALL* downloads from this server. You may wish to set sv_dlURL if you wish clients to still be able to download content.");
cvar_t allow_download_skins = CVARD("allow_download_skins", "1", "0 blocks downloading of any file in the skins/ directory");
cvar_t allow_download_models = CVARD("allow_download_models", "1", "0 blocks downloading of any file in the progs/ or models/ directory");
@ -5898,7 +5893,6 @@ void SV_InitLocal (void)
Cvar_Register (&filterban, cvargroup_servercontrol);
Cvar_Register (&sv_dlURL, cvargroup_serverpermissions);
Cvar_Register (&allow_download, cvargroup_serverpermissions);
Cvar_Register (&allow_download_skins, cvargroup_serverpermissions);
Cvar_Register (&allow_download_models, cvargroup_serverpermissions);

View file

@ -67,6 +67,7 @@ cvar_t dpcompat_noretouchground = CVARD( "dpcompat_noretouchground", "0", "Preve
cvar_t sv_sound_watersplash = CVAR( "sv_sound_watersplash", "misc/h2ohit1.wav");
cvar_t sv_sound_land = CVAR( "sv_sound_land", "demon/dland2.wav");
cvar_t sv_stepheight = CVARAFD("pm_stepheight", "", /*dp*/"sv_stepheight", CVAR_SERVERINFO, "If empty, the value "STRINGIFY(PM_DEFAULTSTEPHEIGHT)" will be used instead. This is the size of the step you can step up or down.");
extern cvar_t sv_nqplayerphysics;
cvar_t pm_ktjump = CVARF("pm_ktjump", "", CVAR_SERVERINFO);
cvar_t pm_bunnyspeedcap = CVARFD("pm_bunnyspeedcap", "", CVAR_SERVERINFO, "0 or 1, ish. If the player is traveling faster than this speed while turning, their velocity will be gracefully reduced to match their current maxspeed. You can still rocket-jump to gain high velocity, but turning will reduce your speed back to the max. This can be used to disable bunny hopping.");
@ -154,8 +155,6 @@ void WPhys_CheckVelocity (world_t *w, wedict_t *ent)
{
int i;
#ifdef HAVE_SERVER
extern cvar_t sv_nqplayerphysics;
if (sv_nqplayerphysics.ival)
{ //bound axially (like vanilla)
for (i=0 ; i<3 ; i++)
@ -690,9 +689,9 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
//float oldsolid;
pushed_t *p;
vec3_t org, org2, move2, forward, right, up;
short yawchange;
yawchange = (amove[PITCH]||amove[ROLL])?0:ANGLE2SHORT(amove[YAW]);
#ifdef HAVE_SERVER
short yawchange = (amove[PITCH]||amove[ROLL])?0:ANGLE2SHORT(amove[YAW]);
#endif
pushed_p = pushed;
@ -771,8 +770,10 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
// try moving the contacted entity
VectorAdd (check->v->origin, move, check->v->origin);
VectorAdd (check->v->angles, amove, check->v->angles);
if (check->entnum>0&&(check->entnum)<=sv.allocated_client_slots)
#ifdef HAVE_SERVER
if (w == &sv.world && check->entnum>0&&(check->entnum)<=sv.allocated_client_slots)
svs.clients[check->entnum-1].baseangles[YAW] += yawchange;
#endif
// figure movement due to the pusher's amove
VectorSubtract (check->v->origin, pusher->v->origin, org);
@ -874,8 +875,10 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
VectorCopy (p->angles, p->ent->v->angles);
World_LinkEdict (w, p->ent, false);
if (p->ent->entnum>0&&(p->ent->entnum)<=sv.allocated_client_slots)
#ifdef HAVE_SERVER
if (w==&sv.world && p->ent->entnum>0&&(p->ent->entnum)<=sv.allocated_client_slots)
svs.clients[p->ent->entnum-1].baseangles[YAW] -= yawchange;
#endif
}
return false;
}
@ -1222,8 +1225,10 @@ A moving object that doesn't obey physics
static void WPhys_Physics_Noclip (world_t *w, wedict_t *ent)
{
vec3_t end;
#ifdef HAVE_SERVER
trace_t trace;
wedict_t *impact;
#endif
// regular thinking
if (!WPhys_RunThink (w, ent))
@ -1232,7 +1237,7 @@ static void WPhys_Physics_Noclip (world_t *w, wedict_t *ent)
VectorMA (ent->v->angles, host_frametime, ent->v->avelocity, ent->v->angles);
VectorMA (ent->v->origin, host_frametime, ent->v->velocity, end);
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
//allow spectators to no-clip through portals without bogging down sock's mods.
if (ent->entnum > 0 && ent->entnum <= sv.allocated_client_slots && w == &sv.world)
{
@ -2420,7 +2425,6 @@ void World_Physics_Frame(world_t *w)
int i;
qboolean retouch;
wedict_t *ent;
extern cvar_t sv_nqplayerphysics;
w->framenum++;
@ -2460,7 +2464,7 @@ void World_Physics_Frame(world_t *w)
if (retouch)
World_LinkEdict (w, ent, true); // force retouch even for stationary
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (i > 0 && i <= sv.allocated_client_slots && w == &sv.world)
{
if (!svs.clients[i-1].isindependant)
@ -2509,7 +2513,7 @@ void World_Physics_Frame(world_t *w)
*w->g.force_retouch-=1;
}
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
/*
================
SV_Physics
@ -2524,7 +2528,6 @@ qboolean SV_Physics (void)
double trueframetime = host_frametime;
double maxtic = sv_maxtic.value;
double mintic = sv_mintic.value;
extern cvar_t sv_nqplayerphysics;
if (sv_nqplayerphysics.ival)
if (mintic < 0.013)
mintic = 0.013; //NQ physics can't cope with low rates and just generally bugs out.

View file

@ -3175,7 +3175,6 @@ qboolean SV_FindRemotePackage(const char *package, char *url, size_t urlsize)
//or something.
extern cvar_t sv_dlURL;
vfsfile_t *f;
char line[512];
@ -3209,9 +3208,9 @@ qboolean SV_FindRemotePackage(const char *package, char *url, size_t urlsize)
VFS_CLOSE(f);
}
if (*sv_dlURL.string)
if (*fs_dlURL.string)
{ //a fallback, though the above mechanism allows for a wildcard for all.
Q_strncatz(sv_dlURL.string, package, urlsize);
Q_strncatz(fs_dlURL.string, package, urlsize);
Q_strncatz(url, package, urlsize);
return true;
}

View file

@ -499,8 +499,8 @@ typedef struct //for collision stuff
F(void, SetInfoKey, (char *s, const char *key, const char *value, int maxsize));
//server things, shouldn't really be here but small. null in client-only builds
F(void, DropClient, (client_t *drop));
F(void, ExtractFromUserinfo,(client_t *cl, qboolean verbose));
F(void, DropClient, (struct client_s *drop));
F(void, ExtractFromUserinfo,(struct client_s *cl, qboolean verbose));
F(qboolean, ChallengePasses, (int challenge));
#define plugworldfuncs_name "World"
} plugworldfuncs_t;

View file

@ -1565,7 +1565,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
break;
*/
#if 1//def BOTLIB_STATIC
#ifdef HAVE_SERVER
case UI_PC_ADD_GLOBAL_DEFINE:
return botlib->PC_AddGlobalDefine(VM_POINTER(arg[0]));
case UI_PC_LOAD_SOURCE:
@ -1837,7 +1837,9 @@ void UI_Start (void)
uimenu.release = UI_Release;
uimenu.lowpriority = true;
#ifdef HAVE_SERVER
SV_InitBotLib();
#endif
uivm = vmfuncs->Create("ui", cvarfuncs->GetFloat("com_gamedirnativecode")?UI_SystemCallsNative:NULL, "vm/ui", UI_SystemCallsVM);
if (uivm)
{

View file

@ -423,6 +423,7 @@ void UI_Stop (void);
qboolean UI_OpenMenu(void);
void UI_Reset(void);
#ifdef HAVE_SERVER
void SVQ3_ShutdownGame(qboolean restarting);
qboolean SVQ3_InitGame(server_static_t *server_state_static, server_t *server_state, qboolean restart);
qboolean SVQ3_ConsoleCommand(void);
@ -436,3 +437,4 @@ void SVQ3_SendMessage(struct client_s *client);
qboolean SVQ3_RestartGamecode(void);
void SVQ3_ServerinfoChanged(const char *key);
#endif
#endif

View file

@ -16,8 +16,10 @@ double realtime;
struct netprim_s msg_nullnetprim;
#endif
#ifdef HAVE_SERVER
//mostly for access to sv.state or svs.sockets
q3serverstate_t sv3;
#endif
//this file contains q3 netcode related things.
//field info, netchan, and the WriteBits stuff (which should probably be moved to common.c with the others)

View file

@ -56,7 +56,7 @@ typedef struct //merge?
#ifdef HAVE_SERVER
typedef struct
{
world_t *world;
@ -77,3 +77,5 @@ typedef struct
} q3serverstate_t;
extern q3serverstate_t sv3;
#undef CALCAREAGRIDBOUNDS
#endif