From 8197e0875f5eb386cb7f1c87b47cada47e33badc Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 2 Jul 2019 04:12:20 +0000 Subject: [PATCH] Track areas properly, so we don't bug out when a client has multiple cameras in different areas. Fix up r_ignoreentpvs 0 to check areas properly. checkpvs builtin can no longer mess up area checks elsewhere. Write out foo.db files for release builds, in the hopes of at least getting function names from release-build crashes. Implement _skyroom worldspawn field, still needs a few tweaks though. Try to fix android surface-related crashes, AGAIN. Separate parsing of connect requests, in preparation for formal logins (and removal of the old ranking code). A few tweaks to try to improve compatibility with q3 mods. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5484 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 20 +- engine/client/cl_cg.c | 29 +- engine/client/cl_ents.c | 75 +- engine/client/cl_main.c | 28 +- engine/client/cl_ui.c | 9 +- engine/client/client.h | 4 +- engine/client/clq3_parse.c | 44 +- engine/client/clq3defs.h | 20 +- engine/client/m_items.c | 9 +- engine/client/m_mp3.c | 8 + engine/client/m_options.c | 1 + engine/client/menu.c | 8 +- engine/client/merged.h | 1 + engine/client/r_surf.c | 16 +- engine/client/render.h | 3 +- engine/client/sys_droid.c | 40 +- engine/client/view.c | 10 + engine/client/wad.c | 5 + engine/common/bothdefs.h | 1 + engine/common/bspfile.h | 4 +- engine/common/cmd.c | 1 - engine/common/com_mesh.c | 14 +- engine/common/com_mesh.h | 2 +- engine/common/gl_q2bsp.c | 91 +- engine/common/mathlib.c | 10 +- engine/common/mathlib.h | 11 +- engine/common/pmove.c | 2 +- engine/common/pr_bgcmd.c | 24 +- engine/common/pr_common.h | 2 +- engine/common/protocol.h | 1 + engine/common/q1bsp.c | 38 +- engine/common/q3common.c | 22 + engine/common/sys_linux_threads.c | 2 +- engine/common/vm.h | 13 + engine/common/world.h | 8 +- .../src/com/fteqw/FTENativeActivity.java | 6 +- engine/gl/gl_alias.c | 7 +- engine/gl/gl_backend.c | 6 +- engine/gl/gl_heightmap.c | 28 +- engine/gl/gl_hlmdl.c | 12 +- engine/gl/gl_model.h | 51 +- engine/gl/gl_rlight.c | 8 +- engine/gl/gl_rmain.c | 3 +- engine/gl/gl_shader.c | 9 +- engine/gl/gl_shadow.c | 38 +- engine/gl/gl_warp.c | 29 +- engine/gl/glquake.h | 3 +- engine/gl/model_hl.h | 2 +- engine/gl/shader.h | 7 +- engine/server/pr_cmds.c | 40 +- engine/server/progs.h | 1 - engine/server/q3g_public.h | 4 +- engine/server/server.h | 63 +- engine/server/sv_cluster.c | 162 ++- engine/server/sv_ents.c | 24 +- engine/server/sv_init.c | 8 + engine/server/sv_main.c | 983 +++++++++--------- engine/server/sv_send.c | 12 +- engine/server/sv_sql.c | 79 +- engine/server/sv_sql.h | 6 +- engine/server/svq3_game.c | 108 +- engine/server/world.c | 10 +- engine/vk/vk_backend.c | 8 +- engine/vk/vkrenderer.h | 2 +- 64 files changed, 1336 insertions(+), 959 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index e7faddd5..b6a87d6b 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1006,7 +1006,7 @@ ifeq ($(FTE_TARGET),nacl) CC= CXX= - STRIP= + STRIP=@echo SKIP: strip NACLLIBC=glibc ifeq ($(NARCH),x86_32) CC=$(NACL_SDK_ROOT)/toolchain/$(MYOS)_x86_$(NACLLIBC)/bin/i686-nacl-gcc -DNACL -m32 @@ -1187,7 +1187,7 @@ ifeq ($(FTE_TARGET),vc) JPEGLIB=libs/jpeg.lib endif endif - STRIP=@echo strip + STRIP=@echo SKIP: strip EXEPOSTFIX=.exe CC=PATH="C:\Program Files (x86)\$(MSVCDIR)\Common7\IDE" "$(MSVCPATH)cl" $(SDKINC) $(MSVCINC) -D_CRT_SECURE_NO_WARNINGS @@ -1640,7 +1640,7 @@ ifeq ($(FTE_TARGET),web) #SV_LDFLAGS= - STRIP=echo + STRIP=@echo SKIP: strip #GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) cd_null.o #GL_LDFLAGS=$(GLLDFLAGS) GLB_DIR=gl_web @@ -1786,9 +1786,21 @@ DO_LD ?= $(DO_ECHO) $(LDCC) -o $@ $(LTO_LD) $(WCFLAGS) $(BRANDFLAGS) $(CFLAGS) $(OUT_DIR)/$(EXE_NAME): $(PRECOMPHEADERS) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS), $($(ol))),$(if $(findstring ltox,$(fn)),,$(OUT_DIR)/$(fn))) $(DO_LD) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS) $(LTO_END), $($(ol))),$(if $(findstring ltox,$(fn)),$(subst ltox,-x ,$(fn)),$(NATIVE_OUT_DIR)/$(fn)) ) $(LDFLAGS) +$(OUT_DIR)/$(EXE_NAME).db: $(PRECOMPHEADERS) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS), $($(ol))),$(if $(findstring ltox,$(fn)),,$(OUT_DIR)/$(fn))) + $(DO_LD) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS) $(LTO_END), $($(ol))),$(if $(findstring ltox,$(fn)),$(subst ltox,-x ,$(fn)),$(NATIVE_OUT_DIR)/$(fn)) ) $(LDFLAGS) + +ifeq (,$(findstring SKIP,$(STRIP))) +#link to a .db file +#then strip its debug data to the non-.db release binary +_out-rel: $(ARCH_PREDEP) + @$(MAKE) $(OUT_DIR)/$(EXE_NAME).db EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(RELEASE_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(RELEASE_LDFLAGS)" OBJS="$(OBJS)" + @$(STRIP) $(STRIPFLAGS) $(OUT_DIR)/$(EXE_NAME).db -o $(OUT_DIR)/$(EXE_NAME) +else +#STRIP macro won't work, don't do the .db thing and don't expect strip -o to work. _out-rel: $(ARCH_PREDEP) @$(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(RELEASE_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(RELEASE_LDFLAGS)" OBJS="$(OBJS)" - $(STRIP) $(STRIPFLAGS) $(OUT_DIR)/$(EXE_NAME) + @echo not stripping $(OUT_DIR)/$(EXE_NAME) +endif _out-dbg: $(ARCH_PREDEP) @$(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(DEBUG_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(DEBUG_LDFLAGS)" OBJS="$(OBJS)" diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index dd3ab94d..93b062de 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -313,15 +313,6 @@ int CG_GetGameState(gameState_t *gs) return sizeof(gameState_t); } -typedef struct { - int serverTime; - int angles[3]; - int buttons; - qbyte weapon; // weapon - signed char forwardmove, rightmove, upmove; -} q3usercmd_t; -#define CMD_BACKUP countof(cl.outframes) -#define CMD_MASK (CMD_BACKUP-1) static int CGQ3_GetCurrentCmdNumber(void) { //Q3 sequences are 1-based, so 1<=idx<=latestsequence are valid //FTE's sequences are 0-based, so 0<=idx= cl.movesequence) Host_EndGame("CLQ3_GetUserCmd: %i >= %i", cmdNumber, cl.movesequence); - if (cl.movesequence - (cmdNumber+1) > CMD_BACKUP) + if (cl.movesequence - (cmdNumber+1) > Q3CMD_BACKUP) return false; //note: frames and commands are desynced in q3. - cmd = &cl.outframes[(cmdNumber) & CMD_MASK].cmd[0]; + cmd = &cl.outframes[(cmdNumber) & Q3CMD_MASK].cmd[0]; ucmd->angles[0] = cmd->angles[0]; ucmd->angles[1] = cmd->angles[1]; ucmd->angles[2] = cmd->angles[2]; @@ -359,31 +350,32 @@ static qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd) static vm_t *cgvm; extern int keycatcher; -char bigconfigstring[65536]; qboolean CG_GetServerCommand(int cmdnum) { + static char bigconfigstring[65536]; + //quote from cgame code: // get the gamestate from the client system, which will have the // new configstring already integrated - char *str = ccs.serverCommands[cmdnum & TEXTCMD_MASK]; + char *str = ccs.serverCommands[cmdnum & Q3TEXTCMD_MASK]; Con_DPrintf("Dispaching %s\n", str); Cmd_TokenizeString(str, false, false); if (!strcmp(Cmd_Argv(0), "bcs0")) - { + { //start Q_snprintfz(bigconfigstring, sizeof(bigconfigstring), "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2)); return false; } if (!strcmp(Cmd_Argv(0), "bcs1")) - { + { //continuation Q_strncatz(bigconfigstring, Cmd_Argv(2), sizeof(bigconfigstring)); return false; } if (!strcmp(Cmd_Argv(0), "bcs2")) - { + { //end Q_strncatz(bigconfigstring, Cmd_Argv(2), sizeof(bigconfigstring)); Q_strncatz(bigconfigstring, "\"", sizeof(bigconfigstring)); Cmd_TokenizeString(bigconfigstring, false, false); @@ -1154,9 +1146,8 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con VM_LONG(ret) = Sys_Milliseconds(); break; case CG_REAL_TIME: - //really local time - VM_LONG(ret) = Sys_Milliseconds(); - break; + VALIDATEPOINTER(arg[0], sizeof(q3time_t)); + return Q3VM_GetRealtime(VM_POINTER(arg[0])); case CG_SNAPVECTOR: // ( float *v ) VALIDATEPOINTER(arg[0], sizeof(vec3_t)); diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index e4e2f046..0406356a 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2622,7 +2622,7 @@ void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qbo { // int oldents = cl_numvisedicts; // cl_numvisedicts = 0; - r_refdef.scenevis = NULL; + r_refdef.scenevis = NULL; BE_DrawWorld(NULL); cl_numstris = 0; // cl_numvisedicts = oldents; @@ -3277,7 +3277,7 @@ void CL_ClearLerpEntsParticleState(void) } } -void CL_LinkStaticEntities(void *pvs) +void CL_LinkStaticEntities(void *pvs, int *areas) { int i; entity_t *ent; @@ -3347,7 +3347,7 @@ void CL_LinkStaticEntities(void *pvs) } /*pvs test*/ - if (pvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &stat->ent.pvscache, pvs)) + if (pvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &stat->ent.pvscache, pvs, areas)) continue; @@ -3376,6 +3376,43 @@ void CL_LinkStaticEntities(void *pvs) } } +//returns cos(angle) +static float CompareAngles (const vec3_t angles1, const vec3_t angles2) +{ + float angle; + vec3_t dir1, dir2; + + angle = angles1[YAW] * (M_PI*2 / 360); + dir1[1] = sin(angle); + dir1[0] = cos(angle); + if (angles1[PITCH]) + { + angle = angles1[PITCH] * (M_PI*2 / 360); + dir1[2] = -sin(angle); + angle = cos(angle); + dir1[0] *= angle; + dir1[1] *= angle; + } + else + dir1[2] = 0; + + angle = angles2[YAW] * (M_PI*2 / 360); + dir2[1] = sin(angle); + dir2[0] = cos(angle); + if (angles2[PITCH]) + { + angle = angles2[PITCH] * (M_PI*2 / 360); + dir2[2] = -sin(angle); + angle = cos(angle); + dir2[0] *= angle; + dir2[1] *= angle; + } + else + dir2[2] = 0; + + return DotProduct(dir1,dir2); +} + /* =============== CL_LinkPacketEntities @@ -3395,6 +3432,7 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp int oldpnum, newpnum; float *snew__origin; float *sold__origin; + float cos_theta; int oldsequence; extern cvar_t r_nolerp; @@ -3520,14 +3558,17 @@ static void CL_TransitionPacketEntities(int newsequence, packet_entities_t *newp snew__origin = snew->u.q1.predorg; sold__origin = sold->u.q1.predorg; + cos_theta = 1; //don't cut off lerping when the player spins too fast. } else { snew__origin = snew->origin; sold__origin = sold->origin; + cos_theta = CompareAngles(sold->angles, snew->angles); } + VectorSubtract(snew__origin, sold__origin, move); - if (DotProduct(move, move) > 200*200 || snew->modelindex != sold->modelindex || ((sold->effects ^ snew->effects) & EF_TELEPORT_BIT)) + if (DotProduct(move, move) > 200*200 || cos_theta < 0.707 || snew->modelindex != sold->modelindex || ((sold->effects ^ snew->effects) & EF_TELEPORT_BIT)) { isnew = true; //disable lerping (and indirectly trails) // VectorClear(move); @@ -3857,6 +3898,8 @@ void CL_LinkPacketEntities (void) int modelflags; struct itemtimer_s *timer, **timerlink; float timestep = cl.time-cl.lastlinktime; + extern cvar_t r_ignoreentpvs; + vec3_t absmin, absmax; cl.lastlinktime = cl.time; timestep = bound(0, timestep, 0.1); @@ -3919,12 +3962,6 @@ void CL_LinkPacketEntities (void) le = &cl.lerpents[state->number]; ent = &cl_visedicts[cl_numvisedicts]; - ent->pvscache.num_leafs = 0; -#if defined(Q2BSPS) || defined(Q3BSPS) || defined(TERRAIN) - ent->pvscache.areanum = 0; - ent->pvscache.areanum2 = 0; - ent->pvscache.headnode = 0; -#endif ent->rtype = RT_MODEL; ent->playerindex = -1; @@ -4097,6 +4134,24 @@ void CL_LinkPacketEntities (void) else model2 = NULL; + + if (r_ignoreentpvs.ival || !model) + { + ent->pvscache.num_leafs = 0; +#if defined(Q2BSPS) || defined(Q3BSPS) || defined(TERRAIN) + ent->pvscache.areanum = 0; + ent->pvscache.areanum2 = 0; + ent->pvscache.headnode = 0; +#endif + } + else + { + /*bsp model size*/ + VectorAdd(model->mins, ent->origin, absmin); + VectorAdd(model->maxs, ent->origin, absmax); + cl.worldmodel->funcs.FindTouchedLeafs(cl.worldmodel, &ent->pvscache, absmin, absmax); + } + cl_numvisedicts++; ent->forcedshader = NULL; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 0b2e0d4d..37a3c27a 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -637,7 +637,8 @@ void CL_SendConnectPacket (netadr_t *to, int mtu, //fixme: we shouldn't cycle these so much connectinfo.qport = qport.value; - Cvar_SetValue(&qport, (connectinfo.qport+1)&0xffff); + if (connectinfo.adr.type != NA_LOOPBACK) + Cvar_SetValue(&qport, (connectinfo.qport+1)&0xffff); if (connectinfo.protocol == CP_QUAKE2 && (connectinfo.subprotocol == PROTOCOL_VERSION_R1Q2 || connectinfo.subprotocol == PROTOCOL_VERSION_Q2PRO)) connectinfo.qport &= 0xff; @@ -759,11 +760,16 @@ void CL_CheckForResend (void) extern cvar_t dpcompat_nopreparse; #endif extern cvar_t sv_guidhash; + + if (connectinfo.time && realtime - connectinfo.time < 1.0) + return; memset(&connectinfo, 0, sizeof(connectinfo)); + connectinfo.time = realtime; Q_strncpyz (cls.servername, "internalserver", sizeof(cls.servername)); Cvar_ForceSet(&cl_servername, cls.servername); if (!NET_StringToAdr(cls.servername, 0, &connectinfo.adr)) return; //erk? + if (*cl_disconnectreason.string) Cvar_Set(&cl_disconnectreason, ""); connectinfo.trying = true; @@ -967,35 +973,35 @@ void CL_CheckForResend (void) net_from = connectinfo.adr; Cmd_TokenizeString (va("connect %i %i %i \"\\name\\unconnected\"", NQ_NETCHAN_VERSION, 0, SV_NewChallenge()), false, false); - SVC_DirectConnect(); + SVC_DirectConnect(0); } else if (connectinfo.subprotocol == CPNQ_BJP3) { net_from = connectinfo.adr; Cmd_TokenizeString (va("connect %i %i %i \"\\name\\unconnected\\mod\\%i\"", NQ_NETCHAN_VERSION, 0, SV_NewChallenge(), PROTOCOL_VERSION_BJP3), false, false); - SVC_DirectConnect(); + SVC_DirectConnect(0); } else if (connectinfo.subprotocol == CPNQ_FITZ666) { net_from = connectinfo.adr; Cmd_TokenizeString (va("connect %i %i %i \"\\name\\unconnected\\mod\\%i\"", NQ_NETCHAN_VERSION, 0, SV_NewChallenge(), PROTOCOL_VERSION_FITZ), false, false); - SVC_DirectConnect(); + SVC_DirectConnect(0); } else if (proquakeangles) { net_from = connectinfo.adr; Cmd_TokenizeString (va("connect %i %i %i \"\\name\\unconnected\\mod\\1\"", NQ_NETCHAN_VERSION, 0, SV_NewChallenge()), false, false); - SVC_DirectConnect(); + SVC_DirectConnect(0); } else if (1) { net_from = connectinfo.adr; Q_snprintfz(net_message.data, net_message.maxsize, "xxxxconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\0x%x\\name\\%s", SV_NewChallenge(), name.string); Cmd_TokenizeString (net_message.data+4, false, false); - SVC_DirectConnect(); + SVC_DirectConnect(0); } else CL_ConnectToDarkPlaces("", &connectinfo.adr); @@ -5954,7 +5960,17 @@ double Host_Frame (double time) #ifndef CLIENTONLY if (isDedicated) //someone changed it. + { + if (sv.state) + { + float ohft = host_frametime; + RSpeedRemark(); + SV_Frame(); + RSpeedEnd(RSPEED_SERVER); + host_frametime = ohft; + } return 0; + } #endif cls.framecount++; diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 706cf6a1..496004e3 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -101,7 +101,8 @@ int Script_Read(int handle, struct pc_token_s *token) } } sc->filestack[sc->stackdepth-1] = s; - + if (com_tokentype == TTP_LINEENDING) + continue; //apparently we shouldn't stop on linebreaks if (!strcmp(readstring, "#include")) { @@ -188,7 +189,7 @@ int Script_Read(int handle, struct pc_token_s *token) } // Con_Printf("Found %s (%i, %i)\n", token->string, token->type, token->subtype); - return !!*token->string || com_tokentype == TTP_STRING; + return com_tokentype != TTP_EOF; } int Script_LoadFile(char *filename) @@ -1236,8 +1237,8 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case UI_REAL_TIME: - VM_FLOAT(ret) = realtime; - break; + VALIDATEPOINTER(arg[0], sizeof(q3time_t)); + return Q3VM_GetRealtime(VM_POINTER(arg[0])); #ifdef CL_MASTER case UI_LAN_GETSERVERCOUNT: //LAN Get server count diff --git a/engine/client/client.h b/engine/client/client.h index 78fd869a..d97e330b 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -330,7 +330,7 @@ typedef struct dlight_s float coronascale; unsigned int flags; - char cubemapname[64]; + char cubemapname[MAX_QPATH]; char *customstyle; int coronaocclusionquery; @@ -1370,7 +1370,7 @@ void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, vec3_t orientationup, struct m // void CL_SetSolidPlayers (void); void CL_SetUpPlayerPrediction(qboolean dopred); -void CL_LinkStaticEntities(void *pvs); +void CL_LinkStaticEntities(void *pvs, int *areas); void CL_TransitionEntities (void); /*call at the start of the frame*/ void CL_EmitEntities (void); void CL_ClearProjectiles (void); diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index d9fe7fc4..6ba7c29f 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -8,9 +8,6 @@ #include "clq3defs.h" -#define CMD_BACKUP UPDATE_BACKUP -#define CMD_MASK UPDATE_MASK - #define SHOWSTRING(s) if(cl_shownet.value==2)Con_Printf ("%s\n", s); #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); #define SHOWNET2(x, y) if(cl_shownet.value==2)Con_Printf ("%3i:%3i:%s\n", msg_readcount-1, y, x); @@ -86,14 +83,14 @@ void CLQ3_ParseServerCommand(void) ccs.lastServerCommandNum++; - if( number > ccs.lastServerCommandNum+TEXTCMD_MASK-1 ) + if( number > ccs.lastServerCommandNum+Q3TEXTCMD_MASK-1 ) { Con_Printf("Warning: Lost %i reliable serverCommands\n", number - ccs.lastServerCommandNum ); } // archive the command to be processed by cgame later - Q_strncpyz( ccs.serverCommands[number & TEXTCMD_MASK], string, sizeof( ccs.serverCommands[0] ) ); + Q_strncpyz( ccs.serverCommands[number & Q3TEXTCMD_MASK], string, sizeof( ccs.serverCommands[0] ) ); } /* @@ -333,9 +330,9 @@ void CLQ3_ParseSnapshot(void) // Find last usercmd server has processed and calculate snap.ping snap.ping = 3; - for (i=cls.netchan.outgoing_sequence-1 ; i>cls.netchan.outgoing_sequence-CMD_BACKUP ; i--) + for (i=cls.netchan.outgoing_sequence-1 ; i>cls.netchan.outgoing_sequence-Q3CMD_BACKUP ; i--) { - frame = &cl.outframes[i & CMD_MASK]; + frame = &cl.outframes[i & Q3CMD_MASK]; if (frame->server_message_num == snap.deltaFrame) { snap.ping = Sys_Milliseconds() - frame->client_time; @@ -641,7 +638,6 @@ void CLQ3_ParseGameState(void) } -#define TEXTCMD_BACKUP 64 void CLQ3_ParseServerMessage (void) { int cmd; @@ -661,9 +657,9 @@ void CLQ3_ParseServerMessage (void) // read last client command number server received ccs.lastClientCommandNum = MSG_ReadLong(); - if( ccs.lastClientCommandNum <= ccs.numClientCommands - TEXTCMD_BACKUP ) + if( ccs.lastClientCommandNum <= ccs.numClientCommands - Q3TEXTCMD_BACKUP ) { - ccs.lastClientCommandNum = ccs.numClientCommands - TEXTCMD_BACKUP + 1; + ccs.lastClientCommandNum = ccs.numClientCommands - Q3TEXTCMD_BACKUP + 1; } else if( ccs.lastClientCommandNum > ccs.numClientCommands ) { @@ -749,7 +745,7 @@ qboolean CLQ3_Netchan_Process(void) // calculate bitmask bitmask = (sequence ^ cls.challenge) & 0xff; - string = ccs.clientCommands[lastClientCommandNum & TEXTCMD_MASK]; + string = ccs.clientCommands[lastClientCommandNum & Q3TEXTCMD_MASK]; #ifndef Q3_NOENCRYPT // decrypt the packet @@ -800,7 +796,7 @@ void CL_Netchan_Transmit( int length, const qbyte *data ) // calculate bitmask bitmask = (lastSequence ^ serverid ^ cls.challenge) & 0xff; - string = ccs.serverCommands[lastServerCommandNum & TEXTCMD_MASK]; + string = ccs.serverCommands[lastServerCommandNum & Q3TEXTCMD_MASK]; #ifndef Q3_NOENCRYPT // encrypt the packet @@ -887,10 +883,10 @@ void VARGS CLQ3_SendClientCommand(const char *fmt, ...) ccs.numClientCommands++; // check if server will lose some of our clientCommands - if(ccs.numClientCommands - ccs.lastClientCommandNum >= TEXTCMD_BACKUP) + if(ccs.numClientCommands - ccs.lastClientCommandNum >= Q3TEXTCMD_BACKUP) Host_EndGame("Client command overflow"); - Q_strncpyz(ccs.clientCommands[ccs.numClientCommands & TEXTCMD_MASK], command, sizeof(ccs.clientCommands[0])); + Q_strncpyz(ccs.clientCommands[ccs.numClientCommands & Q3TEXTCMD_MASK], command, sizeof(ccs.clientCommands[0])); Con_DPrintf("Sending %s\n", command); } @@ -934,13 +930,13 @@ void CLQ3_SendCmd(usercmd_t *cmd) if (Key_Dest_Has(~kdm_game) || (keycatcher&3)) cmd->buttons |= 2; //add in the 'at console' button - cl.outframes[cl.movesequence&CMD_MASK].cmd[0] = *cmd; + cl.outframes[cl.movesequence&Q3CMD_MASK].cmd[0] = *cmd; cl.movesequence++; //FIXME: q3 generates a new command every video frame, but a new packet at a more limited rate. //FIXME: we should return here if its not yet time for a network frame. - frame = &cl.outframes[cls.netchan.outgoing_sequence & CMD_MASK]; + frame = &cl.outframes[cls.netchan.outgoing_sequence & Q3CMD_MASK]; frame->cmd_sequence = cl.movesequence; frame->server_message_num = ccs.serverMessageNum; frame->server_time = cl.gametime; @@ -960,7 +956,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) { MSG_WriteBits(&msg, clcq3_clientCommand, 8); MSG_WriteBits(&msg, i, 32); - string = ccs.clientCommands[i & TEXTCMD_MASK]; + string = ccs.clientCommands[i & Q3TEXTCMD_MASK]; while(*string) MSG_WriteBits(&msg, *string++, 8); MSG_WriteBits(&msg, 0, 8); @@ -969,12 +965,12 @@ void CLQ3_SendCmd(usercmd_t *cmd) i = cls.netchan.outgoing_sequence; i -= bound(0, cl_c2sdupe.ival, 5); //extra age, if desired i--; - if (i < cls.netchan.outgoing_sequence-CMD_MASK) - i = cls.netchan.outgoing_sequence-CMD_MASK; - oldframe = &cl.outframes[i & CMD_MASK]; + if (i < cls.netchan.outgoing_sequence-Q3CMD_MASK) + i = cls.netchan.outgoing_sequence-Q3CMD_MASK; + oldframe = &cl.outframes[i & Q3CMD_MASK]; cmdcount = cl.movesequence - oldframe->cmd_sequence; - if (cmdcount > CMD_MASK) - cmdcount = CMD_MASK; + if (cmdcount > Q3CMD_MASK) + cmdcount = Q3CMD_MASK; // begin a client move command, if any if (cmdcount) @@ -989,7 +985,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) MSG_WriteBits(&msg, cmdcount, 8); // calculate key - string = ccs.serverCommands[ccs.lastServerCommandNum & TEXTCMD_MASK]; + string = ccs.serverCommands[ccs.lastServerCommandNum & Q3TEXTCMD_MASK]; key = ccs.fs_key ^ ccs.serverMessageNum ^ StringKey(string, 32); //note that q3 uses timestamps so sequences are not important @@ -997,7 +993,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) from = &nullcmd; for (i = cl.movesequence-cmdcount; i < cl.movesequence; i++) { - to = &cl.outframes[i&CMD_MASK].cmd[0]; + to = &cl.outframes[i&Q3CMD_MASK].cmd[0]; MSG_Q3_WriteDeltaUsercmd( &msg, key, from, to ); from = to; } diff --git a/engine/client/clq3defs.h b/engine/client/clq3defs.h index 0ccb5f5d..8a65c7cf 100644 --- a/engine/client/clq3defs.h +++ b/engine/client/clq3defs.h @@ -202,12 +202,22 @@ typedef struct frame_s { int serverTime; } q3frame_t; +typedef struct { + int serverTime; + int angles[3]; + int buttons; + qbyte weapon; // weapon + signed char forwardmove, rightmove, upmove; +} q3usercmd_t; +#define Q3CMD_BACKUP 64 //number of q3usercmd_ts that the client can queue before acks +#define Q3CMD_MASK (Q3CMD_BACKUP-1) + #define Q3MAX_PARSE_ENTITIES 2048 #define Q3PARSE_ENTITIES_MASK (Q3MAX_PARSE_ENTITIES-1) #define MAX_STRING_CHARS 1024 -#define TEXTCMD_BACKUP 64 // size of reliable text commands buffer, must be power of two -#define TEXTCMD_MASK (TEXTCMD_BACKUP-1) +#define Q3TEXTCMD_BACKUP 64 //number of reliable text commands that can be queued, must be power of two +#define Q3TEXTCMD_MASK (Q3TEXTCMD_BACKUP-1) #define MAX_Q3_CONFIGSTRINGS 1024 #define CFGSTR_SYSINFO 1 @@ -238,8 +248,8 @@ typedef struct { q3entityState_t baselines[MAX_GENTITIES]; - char clientCommands[TEXTCMD_BACKUP][MAX_STRING_CHARS]; - char serverCommands[TEXTCMD_BACKUP][MAX_STRING_CHARS]; + char clientCommands[Q3TEXTCMD_BACKUP][MAX_STRING_CHARS]; + char serverCommands[Q3TEXTCMD_BACKUP][MAX_STRING_CHARS]; } ClientConnectionState_t; extern ClientConnectionState_t ccs; @@ -299,7 +309,7 @@ typedef struct { typedef struct { glyphInfo_t glyphs [GLYPHS_PER_FONT]; float glyphScale; - char name[MAX_QPATH]; + char name[OLD_MAX_QPATH]; } fontInfo_t; void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 09135e4c..41310156 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -2126,7 +2126,14 @@ static int M_Main_AddExtraOptions(menu_t *mainm, int y) else if (PM_CanInstall("qi")) {MC_AddConsoleCommandQBigFont(mainm, 72, y, "Get Quake Injector", "pkg reset; pkg add qi; pkg apply\n"); y += 20;} if (Cmd_Exists("menu_download")) - {MC_AddConsoleCommandQBigFont(mainm, 72, y, "Updates ", "menu_download\n"); y += 20;} + { +#ifdef WEBCLIENT + MC_AddConsoleCommandQBigFont(mainm, 72, y, "Updates ", "menu_download\n"); y += 20; +#else + MC_AddConsoleCommandQBigFont(mainm, 72, y, "Packages ", "menu_download\n"); +#endif + y += 20; + } return y; } diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 856ae10b..5663f409 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -2239,6 +2239,13 @@ static qboolean Media_Roq_DecodeFrame (cin_t *cin, qboolean nosound, qboolean fo return true; } +void Media_Roq_GetSize(struct cin_s *cin, int *width, int *height, float *aspect) +{ + *width = cin->roq.roqfilm->width; + *height = cin->roq.roqfilm->height; + *aspect = (float)cin->roq.roqfilm->width/cin->roq.roqfilm->height; +} + static cin_t *Media_RoQ_TryLoad(char *name) { cin_t *cin; @@ -2251,6 +2258,7 @@ static cin_t *Media_RoQ_TryLoad(char *name) cin = Z_Malloc(sizeof(cin_t)); cin->decodeframe = Media_Roq_DecodeFrame; cin->shutdown = Media_Roq_Shutdown; + cin->getsize = Media_Roq_GetSize; cin->roq.roqfilm = roqfilm; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 0ee06720..371321ce 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -855,6 +855,7 @@ const char *presetexec[] = "seta r_coronas 0;" "seta r_shadow_realtime_dlight 0;" "seta r_shadow_realtime_world 0;" + "seta r_shadow_realtime_dlight_shadows 1;" "seta r_glsl_offsetmapping 0;" "seta vid_hardwaregamma 3;" //people benchmarking against other engines with fte using glsl gamma and the other not is annoying as fuck. // "seta gl_detail 0;" diff --git a/engine/client/menu.c b/engine/client/menu.c index 89daed93..a79995b5 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -1238,9 +1238,6 @@ void M_Init_Internal (void) Cmd_AddCommand ("help", M_Menu_Help_f); Cmd_AddCommand ("menu_quit", M_Menu_Quit_f); Cmd_AddCommand ("menu_mods", M_Menu_Mods_f); -#ifndef MINIMAL - Cmd_AddCommandAD ("modelviewer", M_Menu_ModelViewer_f, M_Menu_ModelViewer_c, "View a model..."); -#endif #ifdef CL_MASTER Cmd_AddCommand ("menu_slist", M_Menu_ServerList2_f); @@ -1298,6 +1295,7 @@ void M_DeInit_Internal (void) Cmd_RemoveCommand ("menu_keys"); Cmd_RemoveCommand ("help"); Cmd_RemoveCommand ("menu_quit"); + Cmd_RemoveCommand ("menu_mods"); #ifdef CL_MASTER Cmd_RemoveCommand ("menu_slist"); @@ -1325,6 +1323,7 @@ void M_DeInit_Internal (void) Cmd_RemoveCommand ("menu_lighting"); Cmd_RemoveCommand ("menu_textures"); Cmd_RemoveCommand ("menu_particles"); + Cmd_RemoveCommand ("menu_network"); Cmd_RemoveCommand ("menu_main"); //I've moved main to last because that way tab gives us main and not quit. @@ -1377,6 +1376,9 @@ void M_Init (void) //downloads menu needs sandboxing, so cannot be provided by qc. #ifdef PACKAGEMANAGER Cmd_AddCommand ("menu_download", Menu_DownloadStuff_f); +#endif +#ifndef MINIMAL + Cmd_AddCommandAD ("modelviewer", M_Menu_ModelViewer_f, M_Menu_ModelViewer_c, "View a model..."); #endif //demo menu is allowed to see outside of the quakedir. you can't replicate that in qc's sandbox. Cmd_AddCommand ("menu_demo", M_Menu_Demos_f); diff --git a/engine/client/merged.h b/engine/client/merged.h index 471c306d..c0699bb1 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -170,6 +170,7 @@ enum mlverbosity_e MLV_ERROR }; +extern struct model_s *mod_known; //for evil people that want to do evil indexing. const char *Mod_GetEntitiesString(struct model_s *mod); void Mod_SetEntitiesStringLen(struct model_s *mod, const char *str, size_t strsize); void Mod_SetEntitiesString(struct model_s *mod, const char *str, qboolean docopy); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index c1cab7d3..ada3957a 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2648,6 +2648,7 @@ void Surf_SetupFrame(void) R_UpdateHDR(r_refdef.vieworg); } + r_viewarea = 0; viewcontents = 0; if (r_refdef.flags & RDF_NOWORLDMODEL) { @@ -2661,6 +2662,7 @@ void Surf_SetupFrame(void) else if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) { leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg); + r_viewarea = leaf->area; viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, pvsorg); r_viewcluster = r_viewcluster2 = leaf->cluster; @@ -3210,6 +3212,7 @@ void Surf_DrawWorld (void) { //surfvis vs entvis - the key difference is that surfvis is surfaces while entvis is volume. though surfvis should be frustum culled also for lighting. entvis doesn't care. qbyte *surfvis, *entvis; + int areas[2]; RSpeedLocals(); if (r_refdef.flags & RDF_NOWORLDMODEL) @@ -3351,9 +3354,11 @@ void Surf_DrawWorld (void) RSpeedEnd(RSPEED_WORLDNODE); - CL_LinkStaticEntities(entvis); + areas[0] = 1; + areas[1] = r_viewarea; + CL_LinkStaticEntities(entvis, areas); TRACE(("dbg: calling R_DrawParticles\n")); - if (!r_refdef.recurse) + if (!r_refdef.recurse && !(r_refdef.flags & RDF_DISABLEPARTICLES)) P_DrawParticles (); TRACE(("dbg: calling BE_DrawWorld\n")); @@ -3471,11 +3476,14 @@ void Surf_DrawWorld (void) RSpeedEnd(RSPEED_WORLDNODE); + areas[0] = 1; + areas[1] = r_viewarea; + r_refdef.sceneareas = areas; if (!(r_refdef.flags & RDF_NOWORLDMODEL)) { - CL_LinkStaticEntities(entvis); + CL_LinkStaticEntities(entvis, r_refdef.sceneareas); TRACE(("dbg: calling R_DrawParticles\n")); - if (!r_refdef.recurse) + if (!r_refdef.recurse && !(r_refdef.flags & RDF_DISABLEPARTICLES)) P_DrawParticles (); } diff --git a/engine/client/render.h b/engine/client/render.h index 9f03fa30..df73b8ed 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -283,6 +283,7 @@ typedef struct float m_projection_view[16]; //projection matrix for the viewmodel. because people are weird. float m_view[16]; qbyte *scenevis; /*this is the vis that's currently being draw*/ + int *sceneareas; /*this is the area info for the camera (should normally be count+one area, but could be two areas near an opaque water plane)*/ mplane_t frustum[MAXFRUSTUMPLANES]; int frustum_numworldplanes; //all but far, which isn't culled because this wouldn't cover the entire screen. @@ -324,7 +325,7 @@ extern struct texture_s *r_notexture_mip; extern entity_t r_worldentity; -void BE_GenModelBatches(struct batch_s **batches, const struct dlight_s *dl, unsigned int bemode, qbyte *worldpvs); //if dl, filters based upon the dlight. +void BE_GenModelBatches(struct batch_s **batches, const struct dlight_s *dl, unsigned int bemode, const qbyte *worldpvs, const int *worldareas); //if dl, filters based upon the dlight. //gl_alias.c void R_GAliasFlushSkinCache(qboolean final); diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 2e1ebc63..a273d55d 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -49,7 +49,9 @@ static qboolean sys_wantshutdown; static JavaVM* sys_javavm; static jobject *sys_activity; static jobject *sys_cursurface; //surface we're currently trying to draw to +static jobject *sys_cursholder; //silly android junk static jobject *sys_newsurface; //surface we're meant to be switching our gl context to +static jobject *sys_newsholder; //silly android junk static void *sys_mainthread; static void *sys_mainconditional; @@ -663,10 +665,13 @@ static int FTEDroid_MainThread(void *arg) if (r_forcevidrestart) { ANativeWindow *oldwnd = NULL; + jobject oldholder = NULL; jobject oldsurf = NULL; JNIEnv *env = NULL; if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &env, NULL)) { + oldholder = sys_cursholder; + sys_cursholder = (*env)->NewGlobalRef(env, sys_newsholder); oldsurf = sys_cursurface; sys_cursurface = (*env)->NewGlobalRef(env, sys_newsurface); @@ -687,10 +692,12 @@ static int FTEDroid_MainThread(void *arg) LOGI("Video Restarted...\n"); //main thread can wake up now. - if (oldsurf) - (*env)->DeleteGlobalRef(env, oldsurf); if (oldwnd) ANativeWindow_release(oldwnd); + if (oldsurf) + (*env)->DeleteGlobalRef(env, oldsurf); + if (oldholder) + (*env)->DeleteGlobalRef(env, oldholder); if (env) (*sys_javavm)->DetachCurrentThread(sys_javavm); @@ -752,6 +759,25 @@ static int FTEDroid_MainThread(void *arg) if (sleeptime) Sys_Sleep(sleeptime); } + + //don't permanently hold these when there's no active activity. + //(hopefully there's no gl context active right now...) + JNIEnv *env = NULL; + if (JNI_OK == (*sys_javavm)->AttachCurrentThread(sys_javavm, &env, NULL)) + { + if (sys_nativewindow) + ANativeWindow_release(sys_nativewindow); + sys_nativewindow = NULL; + if (sys_cursurface) + (*env)->DeleteGlobalRef(env, sys_cursurface); + sys_cursurface = NULL; + if (sys_cursholder) + (*env)->DeleteGlobalRef(env, sys_cursholder); + sys_cursholder = NULL; + if (env) + (*sys_javavm)->DetachCurrentThread(sys_javavm); + } + return 0; } @@ -1171,7 +1197,7 @@ static jboolean FTENativeActivity_startup(JNIEnv *jni, jobject this, jstring ext return false; } -static void FTENativeActivity_surfacechange(JNIEnv *env, jobject this, jboolean teardown, jboolean recreate, jobject surface) +static void FTENativeActivity_surfacechange(JNIEnv *env, jobject this, jboolean teardown, jboolean recreate, jobject holder, jobject surface) { if (!(*env)->IsSameObject(env, this, sys_activity)) { @@ -1193,6 +1219,9 @@ static void FTENativeActivity_surfacechange(JNIEnv *env, jobject this, jboolean if (sys_newsurface) (*env)->DeleteGlobalRef(env, sys_newsurface); sys_newsurface = surface?(*env)->NewGlobalRef(env, surface):NULL; + if (sys_newsholder) + (*env)->DeleteGlobalRef(env, sys_newsholder); + sys_newsholder = holder?(*env)->NewGlobalRef(env, holder):NULL; //and wake up then Sys_ConditionWait(sys_mainconditional); //and we're done... @@ -1217,6 +1246,9 @@ static void FTENativeActivity_shutdown(JNIEnv *env, jobject this) (*env)->DeleteGlobalRef(env, sys_newsurface); sys_newsurface = NULL; + + (*env)->DeleteGlobalRef(env, sys_newsholder); + sys_newsholder = NULL; (*env)->DeleteGlobalRef(env, sys_activity); sys_activity = NULL; @@ -1237,7 +1269,7 @@ static void FTENativeActivity_openfile(JNIEnv *env, jobject this, jstring filena static JNINativeMethod methods[] = { // {"startup", "(Ljava/lang/String;Ljava/lang/String;)Z", FTENativeActivity_startup}, //creates our 'main' thread too - {"surfacechange", "(ZZLandroid/view/Surface;)V", FTENativeActivity_surfacechange}, //syncs + {"surfacechange", "(ZZLandroid/view/SurfaceHolder;Landroid/view/Surface;)V", FTENativeActivity_surfacechange}, //syncs {"shutdown", "()V", FTENativeActivity_shutdown}, //joins 'main' thread. {"openfile", "(Ljava/lang/String;)V", FTENativeActivity_openfile}, diff --git a/engine/client/view.c b/engine/client/view.c index 6274fb91..b602428f 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -103,6 +103,8 @@ cvar_t crosshaircorrect = CVARFD("crosshaircorrect", "0", CVAR_SEMICHEAT, "Move cvar_t crosshairimage = CVARD("crosshairimage", "", "Enables the use of an external/custom crosshair image"); cvar_t crosshairalpha = CVAR("crosshairalpha", "1"); +cvar_t v_skyroom_origin = CVARD("r_skyroom_origin", "", "Specifies the center position of the skyroom's view. Skyrooms are drawn instead of skyboxes (typically with their own skybox around them). Entities in skyrooms will be drawn only when r_ignoreentpvs is 0. Can also be set with the _skyroom worldspawn key. This is overriden by csqc's VF_SKYROOM_CAMERA."); + static cvar_t gl_cshiftpercent = CVAR("gl_cshiftpercent", "100"); cvar_t gl_cshiftenabled = CVARFD("gl_polyblend", "1", CVAR_ARCHIVE, "Controls whether temporary whole-screen colour changes should be honoured or not. Change gl_cshiftpercent if you want to adjust the intensity.\nThis does not affect v_cshift commands sent from the server."); cvar_t gl_cshiftborder = CVARD("gl_polyblend_edgesize", "128", "This constrains colour shifts to the edge of the screen, with the value specifying the size of those borders."); @@ -1615,6 +1617,13 @@ void V_CalcRefdef (playerview_t *pv) VectorMA(r_refdef.vieworg, v_gunkick.value, pv->punchorigin, r_refdef.vieworg); } + if (*v_skyroom_origin.string) + { + r_refdef.skyroom_enabled = true; + r_refdef.skyroom_pos[0] = v_skyroom_origin.vec4[0]; + r_refdef.skyroom_pos[1] = v_skyroom_origin.vec4[1]; + r_refdef.skyroom_pos[2] = v_skyroom_origin.vec4[2]; + } if (chase_active.ival && cls.allow_cheats) //cheat restriction might be lifted some time when any wallhacks are solved. { @@ -2572,6 +2581,7 @@ void V_Init (void) Cvar_Register (&v_kickpitch, VIEWVARS); Cvar_Register (&v_deathtilt, VIEWVARS); + Cvar_Register (&v_skyroom_origin, VIEWVARS); Cvar_Register (&scr_autoid, VIEWVARS); Cvar_Register (&scr_autoid_team, VIEWVARS); diff --git a/engine/client/wad.c b/engine/client/wad.c index 8f2de264..81a5db74 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -885,6 +885,11 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in Cvar_LockFromServer(&r_telealpha, token); Cvar_LockFromServer(&r_telestyle, "1"); } + else if (!strcmp("skyroom", key)) // for Quake mappers that lack the proper tools + { + extern cvar_t v_skyroom_origin; + Cvar_LockFromServer(&v_skyroom_origin, token); + } else if (!strcmp("skyname", key)) // for HalfLife maps { Q_strncpyz(skyname, token, sizeof(skyname)); diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 68d95108..5deb001c 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -801,6 +801,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_QPATH 128 // max length of a quake game pathname #define MAX_OSPATH 1024 // max length of a filesystem pathname (260 on windows, but needs to be longer for utf8) +#define OLD_MAX_QPATH 64 // it was baked into various file formats, which is unfortunate. #define ON_EPSILON 0.1 // point on plane side epsilon diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index fc921c84..f2639c54 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -788,7 +788,7 @@ typedef struct typedef struct { - char shadername[64]; + char shadername[OLD_MAX_QPATH]; int surfflags; int contents; } dq3shader_t; @@ -828,7 +828,7 @@ typedef struct struct Q3FOG { - char shadername[64] ; + char shadername[OLD_MAX_QPATH] ; int brushnum; int visibleside; }; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index d61ddf84..8c0565e0 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2930,7 +2930,6 @@ void Cmd_ExecuteString (const char *text, int level) //a number of things check for seats if nothing else, and security says is safer to do this than to be in doubt. int olev = Cmd_ExecLevel; Cmd_ExecuteStringGlobalsAreEvil(text, level); - Cmd_ExecLevel = level; Cmd_ExecLevel = olev; } diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 0d8401be..ec5afe13 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1010,7 +1010,7 @@ typedef struct float frac[FRAME_BLENDS*2]; //weight of this animation (1 if lerpcount is 1) float *pose[FRAME_BLENDS*2]; //pointer to the raw frame data for bone 0. } skellerps_t; -static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion_s *fs, int numbones, galiasinfo_t *inf) +static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestateregion_s *fs, int numbones, const galiasinfo_t *inf) { int frame1; //signed, because frametime might be negative... int frame2; @@ -1129,7 +1129,7 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion /* finds the various blend info. returns number of bone blocks used. */ -static int Alias_FindRawSkelData(galiasinfo_t *inf, framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone) +static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone) { int bonegroup; int cbone = 0; @@ -1220,7 +1220,7 @@ static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *r only writes targetbuffer if needed. the return value is the only real buffer result. assumes that all blended types are the same. probably buggy, but meh. */ -static const float *Alias_GetBoneInformation(galiasinfo_t *inf, framestate_t *framestate, skeltype_t targettype, float *targetbuffer, float *targetbufferalt, size_t maxbufferbones) +static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate_t *framestate, skeltype_t targettype, float *targetbuffer, float *targetbufferalt, size_t maxbufferbones) { skellerps_t lerps[FS_COUNT], *lerp; size_t numgroups; @@ -2215,7 +2215,7 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qbool #endif -static float PlaneNearest(vec3_t normal, vec3_t mins, vec3_t maxs) +static float PlaneNearest(const vec3_t normal, const vec3_t mins, const vec3_t maxs) { float result; #if 0 @@ -2235,7 +2235,7 @@ static float PlaneNearest(vec3_t normal, vec3_t mins, vec3_t maxs) } void CLQ1_DrawLine(shader_t *shader, vec3_t v1, vec3_t v2, float r, float g, float b, float a); -static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace) +static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numindexes, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, trace_t *fte_restrict trace) { qboolean impacted = false; int i, j; @@ -2412,7 +2412,7 @@ static qboolean Mod_Trace_Trisoup(vecV_t *posedata, index_t *indexes, int numind } //The whole reason why model loading is supported in the server. -static qboolean Mod_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentsmask, trace_t *trace) +static qboolean Mod_Trace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int contentsmask, trace_t *trace) { galiasinfo_t *mod = Mod_Extradata(model); @@ -8166,7 +8166,7 @@ static galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *mod else if (!strcmp(token, "numJoints")) { if (numjoints) - MD5ERROR0PARAM("MD5MESH: numMeshes was already declared"); + MD5ERROR0PARAM("MD5MESH: numJoints was already declared"); buffer = COM_ParseOut(buffer, token, sizeof(token)); numjoints = atoi(token); if (numjoints <= 0) diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 15b07cd8..79f2ef79 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -224,7 +224,7 @@ typedef struct modplugfuncs_s void (QDECL *ConcatTransforms) (const float in1[3][4], const float in2[3][4], float out[3][4]); void (QDECL *M3x4_Invert) (const float *in1, float *out); - void (QDECL *VectorAngles)(float *forward, float *up, float *result, qboolean meshpitch); + void (QDECL *VectorAngles)(const float *forward, const float *up, float *result, qboolean meshpitch); void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); void (QDECL *GenMatrixPosQuat4Scale)(const vec3_t pos, const vec4_t quat, const vec3_t scale, float result[12]); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index b4a954af..f60e4988 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -57,16 +57,16 @@ void Mod_LoadEntities (model_t *loadmodel, qbyte *mod_base, lump_t *l); extern void BuildLightMapGammaTable (float g, float c); #if defined(Q2BSPS) || defined(Q3BSPS) -static qboolean CM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace); -static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); -static unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p); -static int CM_PointCluster (model_t *mod, vec3_t p); +static qboolean CM_NativeTrace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace); +static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs); +static unsigned int Q2BSP_PointContents(model_t *mod, const vec3_t axis[3], const vec3_t p); +static int CM_PointCluster (model_t *mod, const vec3_t p, int *area); struct cminfo_s; static struct bihnode_s *CM_BuildBIH (model_t *mod, struct cminfo_s *prv); static unsigned int CM_PointContentsBIH (const struct bihnode_s *fte_restrict node, const vec3_t p); #endif -float RadiusFromBounds (vec3_t mins, vec3_t maxs) +float RadiusFromBounds (const vec3_t mins, const vec3_t maxs) { int i; vec3_t corner; @@ -4236,8 +4236,6 @@ static void GLR_Q2BSP_StainNode (mnode_t *node, float *parms) #endif -void GLQ2BSP_LightPointValues(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); - /* ================== CM_LoadMap @@ -4870,8 +4868,8 @@ mplane_t box_planes[6]; model_t box_model; q2cbrush_t box_brush; q2cbrushside_t box_sides[6]; -static qboolean BM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace); -static unsigned int BM_NativeContents(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs) +static qboolean BM_NativeTrace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace); +static unsigned int BM_NativeContents(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs) { unsigned int j; q2cbrushside_t *brushside = box_sides; @@ -4947,7 +4945,7 @@ To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being compared directly. =================== */ -static void CM_SetTempboxSize (vec3_t mins, vec3_t maxs) +static void CM_SetTempboxSize (const vec3_t mins, const vec3_t maxs) { box_planes[0].dist = maxs[0]; box_planes[1].dist = maxs[1]; @@ -4957,7 +4955,7 @@ static void CM_SetTempboxSize (vec3_t mins, vec3_t maxs) box_planes[5].dist = -mins[2]; } -model_t *CM_TempBoxModel(vec3_t mins, vec3_t maxs) +model_t *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs) { CM_SetTempboxSize(mins, maxs); return &box_model; @@ -4969,7 +4967,7 @@ CM_PointLeafnum_r ================== */ -static int CM_PointLeafnum_r (model_t *mod, vec3_t p, int num) +static int CM_PointLeafnum_r (model_t *mod, const vec3_t p, int num) { float d; mnode_t *node; @@ -4993,18 +4991,23 @@ static int CM_PointLeafnum_r (model_t *mod, vec3_t p, int num) return -1 - num; } -int CM_PointLeafnum (model_t *mod, vec3_t p) +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); } -static int CM_PointCluster (model_t *mod, vec3_t p) +static int CM_PointCluster (model_t *mod, const vec3_t p, int *area) { + int leaf; if (!mod || mod->loadstate != MLS_LOADED) return 0; // sound may call this without map loaded - return CM_LeafCluster(mod, CM_PointLeafnum_r (mod, p, 0)); + + leaf = CM_PointLeafnum_r (mod, p, 0); + if (area) + *area = CM_LeafArea(mod, leaf); + return CM_LeafCluster(mod, leaf); } /* @@ -5016,7 +5019,7 @@ Fills in a list of all the leafs touched */ int leaf_count, leaf_maxcount; int *leaf_list; -float *leaf_mins, *leaf_maxs; +const float *leaf_mins, *leaf_maxs; int leaf_topnode; static void CM_BoxLeafnums_r (model_t *mod, int nodenum) @@ -5057,7 +5060,7 @@ static void CM_BoxLeafnums_r (model_t *mod, int nodenum) } } -static int CM_BoxLeafnums_headnode (model_t *mod, vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode) +static int CM_BoxLeafnums_headnode (model_t *mod, const vec3_t mins, const vec3_t maxs, int *list, int listsize, int headnode, int *topnode) { leaf_list = list; leaf_count = 0; @@ -5075,7 +5078,7 @@ static int CM_BoxLeafnums_headnode (model_t *mod, vec3_t mins, vec3_t maxs, int return leaf_count; } -int CM_BoxLeafnums (model_t *mod, vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode) +int CM_BoxLeafnums (model_t *mod, const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *topnode) { return CM_BoxLeafnums_headnode (mod, mins, maxs, list, listsize, mod->hulls[0].firstclipnode, topnode); @@ -5089,7 +5092,7 @@ CM_PointContents ================== */ -int CM_PointContents (model_t *mod, vec3_t p) +int CM_PointContents (model_t *mod, const vec3_t p) { cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i, j, contents; @@ -5146,7 +5149,7 @@ int CM_PointContents (model_t *mod, vec3_t p) return contents; } -unsigned int CM_NativeContents(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs) +unsigned int CM_NativeContents(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs) { cminfo_t *prv = (cminfo_t*)model->meshinfo; int contents; @@ -5210,7 +5213,7 @@ Handles offseting and rotation of the end points for moving and rotating entities ================== */ -int CM_TransformedPointContents (model_t *mod, vec3_t p, int headnode, vec3_t origin, vec3_t angles) +int CM_TransformedPointContents (model_t *mod, const vec3_t p, int headnode, const vec3_t origin, const vec3_t angles) { vec3_t p_l; vec3_t temp; @@ -6699,8 +6702,8 @@ static struct bihnode_s *CM_BuildBIH (model_t *mod, cminfo_t *prv) CM_BoxTrace ================== */ -static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, - vec3_t mins, vec3_t maxs, qboolean capsule, +static trace_t CM_BoxTrace (model_t *mod, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, qboolean capsule, int brushmask) { int i; @@ -6897,7 +6900,7 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end, return trace_trace; } -static qboolean BM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) +static qboolean BM_NativeTrace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) { int i; memset (trace, 0, sizeof(*trace)); @@ -6941,7 +6944,7 @@ static qboolean BM_NativeTrace(model_t *model, int forcehullnum, framestate_t *f } return trace->fraction != 1; } -static qboolean CM_NativeTrace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) +static qboolean CM_NativeTrace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int contents, trace_t *trace) { if (axis) { @@ -7200,7 +7203,7 @@ qbyte *CM_ClusterPHS (model_t *mod, int cluster, pvsbuffer_t *buffer) return buffer->buffer; } -static unsigned int SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *result, qboolean merge) +static unsigned int SV_Q2BSP_FatPVS (model_t *mod, const vec3_t org, pvsbuffer_t *result, qboolean merge) { int leafs[64]; int i, j, count; @@ -7249,7 +7252,7 @@ static unsigned int SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *res } static int clientarea; -unsigned int Q23BSP_FatPVS(model_t *mod, vec3_t org, pvsbuffer_t *buffer, qboolean merge) +unsigned int Q23BSP_FatPVS(model_t *mod, const vec3_t org, pvsbuffer_t *fte_restrict buffer, qboolean merge) {//fixme: this doesn't add areas int leafnum; leafnum = CM_PointLeafnum (mod, org); @@ -7258,21 +7261,29 @@ unsigned int Q23BSP_FatPVS(model_t *mod, vec3_t org, pvsbuffer_t *buffer, qboole return SV_Q2BSP_FatPVS (mod, org, buffer, merge); } -qboolean Q23BSP_EdictInFatPVS(model_t *mod, pvscache_t *ent, qbyte *pvs) +qboolean Q23BSP_EdictInFatPVS(model_t *mod, const pvscache_t *ent, const qbyte *pvs, const int *areas) { int i,l; int nullarea = (mod->fromgame == fg_quake2)?0:-1; - if (clientarea == ent->areanum) + if (areas) { - if (clientarea == nullarea) - return false; - } - else if (!CM_AreasConnected (mod, clientarea, ent->areanum)) - { // doors can legally straddle two areas, so - // we may need to check another one - if (ent->areanum2 == nullarea - || !CM_AreasConnected (mod, clientarea, ent->areanum2)) - return false; // blocked by a door + for (i = 1; ; i++) + { + if (i > areas[0]) + return false; //none of the camera's areas could see the entity + if (areas[i] == ent->areanum) + { + if (areas[i] != nullarea) + break; + //else entity is fully outside the world, invisible to all... + } + else if (CM_AreasConnected (mod, areas[i], ent->areanum)) + break; + // doors can legally straddle two areas, so + // we may need to check another one + else if (ent->areanum2 != nullarea && CM_AreasConnected (mod, areas[i], ent->areanum2)) + break; + } } if (ent->num_leafs == -1) @@ -7564,7 +7575,7 @@ Returns true if any leaf under headnode has a cluster that is potentially visible ============= */ -qboolean CM_HeadnodeVisible (model_t *mod, int nodenum, qbyte *visbits) +qboolean CM_HeadnodeVisible (model_t *mod, int nodenum, const qbyte *visbits) { int leafnum; int cluster; @@ -7587,7 +7598,7 @@ qboolean CM_HeadnodeVisible (model_t *mod, int nodenum, qbyte *visbits) return CM_HeadnodeVisible(mod, node->childnum[1], visbits); } -unsigned int Q2BSP_PointContents(model_t *mod, vec3_t axis[3], vec3_t p) +unsigned int Q2BSP_PointContents(model_t *mod, const vec3_t axis[3], const vec3_t p) { int pc; pc = CM_PointContents (mod, p); diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 7411246c..dd5d7b8a 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -167,7 +167,7 @@ BoxOnPlaneSide Returns 1, 2, or 1 + 2 ================== */ -int VARGS BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p) +int VARGS BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, const mplane_t *p) { float dist1, dist2; int sides; @@ -291,7 +291,7 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up) CrossProduct(right, forward, up); } -void QDECL VectorAngles(float *forward, float *up, float *result, qboolean meshpitch) //up may be NULL +void QDECL VectorAngles(const float *forward, const float *up, float *result, qboolean meshpitch) //up may be NULL { float yaw, pitch, roll; @@ -583,7 +583,7 @@ void QDECL R_ConcatTransforms (const float in1[3][4], const float in2[3][4], flo } //R_ConcatTransforms where there's no offset values, and a transposed axis -void R_ConcatTransformsAxis (float in1[3][3], float in2[3][4], float out[3][4]) +void R_ConcatTransformsAxis (const float in1[3][3], const float in2[3][4], float out[3][4]) { out[0][0] = in1[0][0] * in2[0][0] + in1[1][0] * in2[1][0] + in1[2][0] * in2[2][0]; @@ -1910,7 +1910,7 @@ vec_t QDECL VectorNormalize2 (const vec3_t v, vec3_t out) return length; } -float ColorNormalize (vec3_t in, vec3_t out) +float ColorNormalize (const vec3_t in, vec3_t out) { float f = max (max (in[0], in[1]), in[2]); @@ -1928,7 +1928,7 @@ float ColorNormalize (vec3_t in, vec3_t out) return f; } -void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up) +void MakeNormalVectors (const vec3_t forward, vec3_t right, vec3_t up) { float d; diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 2e8ea787..720af553 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -129,17 +129,17 @@ typedef struct { void AddPointToBounds (const vec3_t v, vec3_t mins, vec3_t maxs); float anglemod (float a); void QDECL AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -void QDECL VectorAngles (float *forward, float *up, float *angles, qboolean meshpitch); //up may be NULL +void QDECL VectorAngles (const float *forward, const float *up, float *angles, qboolean meshpitch); //up may be NULL void VARGS BOPS_Error (void); -int VARGS BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); +int VARGS BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, const struct mplane_s *plane); void ClearBounds (vec3_t mins, vec3_t maxs); -float ColorNormalize (vec3_t in, vec3_t out); +float ColorNormalize (const vec3_t in, vec3_t out); void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); void FloorDivMod (double numer, double denom, int *quotient, int *rem); int GreatestCommonDivisor (int i1, int i2); fixed16_t Invert24To16 (fixed16_t val); vec_t Length (const vec3_t v); -void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up); +void MakeNormalVectors (const vec3_t forward, vec3_t right, vec3_t up); float Q_rsqrt(float number); /* @@ -205,7 +205,8 @@ int Q_log2 (int val); void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4]); void QDECL R_ConcatTransforms (const matrix3x4 in1, const matrix3x4 in2, matrix3x4 out); -void R_ConcatTransformsAxis (float in1[3][3], float in2[3][4], float out[3][4]); +void R_ConcatTransformsAxis (const float in1[3][3], const float in2[3][4], float out[3][4]); +void PerpendicularVector(vec3_t dst, const vec3_t src); void RotatePointAroundVector (vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); void RotateLightVector(const vec3_t *axis, const vec3_t origin, const vec3_t lightpoint, vec3_t result); int VectorCompare (const vec3_t v1, const vec3_t v2); diff --git a/engine/common/pmove.c b/engine/common/pmove.c index b29f050c..e1e4c6d6 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -1291,7 +1291,7 @@ static void PM_NudgePosition (void) VectorCopy (pmove.safeorigin, pmove.origin); else VectorCopy (base, pmove.origin); -// Com_DPrintf ("NudgePosition: stuck\n"); +// Con_DPrintf ("NudgePosition: stuck\n"); } /* diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 7e030e0c..7f754f5f 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -5,6 +5,9 @@ #if !defined(CLIENTONLY) || defined(CSQC_DAT) || defined(MENU_DAT) #include "pr_common.h" +#ifdef SQL +#include "sv_sql.h" +#endif #include @@ -1122,26 +1125,28 @@ void QCBUILTIN PF_getsurfacepointattribute(pubprogfuncs_t *prinst, struct global } } -pvsbuffer_t qcpvs; //#240 float(vector viewpos, entity viewee) checkpvs (FTE_QC_CHECKPVS) //note: this requires a correctly setorigined entity. void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { world_t *world = prinst->parms->user; + model_t *worldmodel = world->worldmodel; float *viewpos = G_VECTOR(OFS_PARM0); wedict_t *ent = G_WEDICT(prinst, OFS_PARM1); + int cluster; + int qcpvsarea[2]; + qbyte *pvs; - if (!world->worldmodel || world->worldmodel->loadstate != MLS_LOADED) + if (!worldmodel || worldmodel->loadstate != MLS_LOADED) G_FLOAT(OFS_RETURN) = false; - else if (!world->worldmodel->funcs.FatPVS) + else if (!worldmodel->funcs.FatPVS) G_FLOAT(OFS_RETURN) = true; else { - //FIXME: Make all alternatives of FatPVS not recalulate the pvs. - //and yeah, this is overkill what with the whole fat thing and all. - world->worldmodel->funcs.FatPVS(world->worldmodel, viewpos, &qcpvs, false); - - G_FLOAT(OFS_RETURN) = world->worldmodel->funcs.EdictInFatPVS(world->worldmodel, &ent->pvsinfo, qcpvs.buffer); + qcpvsarea[0] = 1; + cluster = worldmodel->funcs.ClusterForPoint(worldmodel, viewpos, &qcpvsarea[1]); + pvs = worldmodel->funcs.ClusterPVS(worldmodel, cluster, NULL, PVM_FAST); + G_FLOAT(OFS_RETURN) = worldmodel->funcs.EdictInFatPVS(worldmodel, &ent->pvsinfo, pvs, qcpvsarea); } } @@ -6423,6 +6428,9 @@ void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored) #endif #ifdef TEXTEDITOR Editor_ProgsKilled(progs); +#endif +#ifdef SQL + SQL_KillServers(progs); #endif tokenize_flush(); } diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 202a95b2..db6a487f 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -637,7 +637,7 @@ typedef struct void (QDECL *ReleaseCollisionMesh) (wedict_t *ed); void (QDECL *LinkEdict)(world_t *w, wedict_t *ed, qboolean touchtriggers); - void (QDECL *VectorAngles)(float *forward, float *up, float *result, qboolean meshpitch); + void (QDECL *VectorAngles)(const float *forward, const float *up, float *result, qboolean meshpitch); void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); } rbeplugfuncs_t; #define RBEPLUGFUNCS_VERSION 1 diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 7eda0e70..e9947892 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -1360,6 +1360,7 @@ typedef struct q1usercmd_s #define RDF_ANTIALIAS (1u<<20) //fxaa, or possibly even just fsaa #define RDF_RENDERSCALE (1u<<21) #define RDF_SCENEGAMMA (1u<<22) +#define RDF_DISABLEPARTICLES (1u<<23) //mostly for skyrooms #define RDF_ALLPOSTPROC (RDF_BLOOM|RDF_FISHEYE|RDF_WATERWARP|RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_SCENEGAMMA) //these flags require rendering to an fbo for the various different post-processing shaders. diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 8ccea730..dfc24660 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -671,7 +671,7 @@ void Q1BSP_CheckHullNodes(hull_t *hull) } -static int Q1_ModelPointContents (mnode_t *node, vec3_t p) +static int Q1_ModelPointContents (mnode_t *node, const vec3_t p) { float d; mplane_t *plane; @@ -694,7 +694,7 @@ SV_HullPointContents ================== */ -static int Q1_HullPointContents (hull_t *hull, int num, vec3_t p) +static int Q1_HullPointContents (hull_t *hull, int num, const vec3_t p) { float d; mclipnode_t *node; @@ -754,7 +754,7 @@ struct rhtctx_s mclipnode_t *clipnodes; mplane_t *planes; }; -static int Q1BSP_RecursiveHullTrace (struct rhtctx_s *ctx, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) +static int Q1BSP_RecursiveHullTrace (struct rhtctx_s *ctx, int num, float p1f, float p2f, const vec3_t p1, const vec3_t p2, trace_t *trace) { mclipnode_t *node; mplane_t *plane; @@ -873,7 +873,7 @@ reenter: return rht_impact; } -qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, unsigned int hitcontents, trace_t *trace) +qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, const vec3_t p1, const vec3_t p2, unsigned int hitcontents, trace_t *trace) { if (VectorEquals(p1, p2)) { @@ -1222,7 +1222,7 @@ static void Q1BSP_InsertBrush(mnode_t *node, mbrush_t *brush, vec3_t bmins, vec3 } } } -static void Q1BSP_RecursiveBrushCheck (struct traceinfo_s *traceinfo, mnode_t *node, float p1f, float p2f, vec3_t p1, vec3_t p2) +static void Q1BSP_RecursiveBrushCheck (struct traceinfo_s *traceinfo, mnode_t *node, float p1f, float p2f, const vec3_t p1, const vec3_t p2) { mplane_t *plane; float t1, t2; @@ -1366,13 +1366,13 @@ static unsigned int Q1BSP_TranslateContents(int contents) } } -int Q1BSP_HullPointContents(hull_t *hull, vec3_t p) +int Q1BSP_HullPointContents(hull_t *hull, const vec3_t p) { return Q1BSP_TranslateContents(Q1_HullPointContents(hull, hull->firstclipnode, p)); } #ifdef Q1BSPS -unsigned int Q1BSP_PointContents(model_t *model, vec3_t axis[3], vec3_t point) +unsigned int Q1BSP_PointContents(model_t *model, const vec3_t axis[3], const vec3_t point) { int contents; if (axis) @@ -1513,7 +1513,7 @@ void Q1BSP_LoadBrushes(model_t *model, bspx_header_t *bspx, void *mod_base) model->engineflags |= MDLF_HASBRUSHES; } -hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t maxs, vec3_t offset) +hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, const vec3_t mins, const vec3_t maxs, vec3_t offset) { hull_t *hull; vec3_t size; @@ -1559,7 +1559,7 @@ hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t m VectorSubtract (hull->clip_mins, mins, offset); return hull; } -qboolean Q1BSP_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, trace_t *trace) +qboolean Q1BSP_Trace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, trace_t *trace) { hull_t *hull; vec3_t start_l, end_l; @@ -1779,7 +1779,7 @@ Server only functions static qbyte *Q1BSP_ClusterPVS (model_t *model, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge); //does the recursive work of Q1BSP_FatPVS -static void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node, pvsbuffer_t *pvsbuffer) +static void SV_Q1BSP_AddToFatPVS (model_t *mod, const vec3_t org, mnode_t *node, pvsbuffer_t *pvsbuffer) { mplane_t *plane; float d; @@ -1818,7 +1818,7 @@ Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the given point. ============= */ -static unsigned int Q1BSP_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean add) +static unsigned int Q1BSP_FatPVS (model_t *mod, const vec3_t org, pvsbuffer_t *pvsbuffer, qboolean add) { if (pvsbuffer->buffersize < mod->pvsbytes) pvsbuffer->buffer = BZ_Realloc(pvsbuffer->buffer, pvsbuffer->buffersize=mod->pvsbytes); @@ -1829,10 +1829,12 @@ static unsigned int Q1BSP_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *pvsbuff } #endif -static qboolean Q1BSP_EdictInFatPVS(model_t *mod, struct pvscache_s *ent, qbyte *pvs) +static qboolean Q1BSP_EdictInFatPVS(model_t *mod, const struct pvscache_s *ent, const qbyte *pvs, const int *areas) { int i; + //if (areas)areas[0] is the area count... but q1bsp has no areas so we ignore it entirely. + if (ent->num_leafs < 0) return true; //it's in too many leafs for us to cope with. Just trivially accept it. @@ -1850,7 +1852,7 @@ SV_FindTouchedLeafs Links the edict to the right leafs so we can get it's potential visability. =============== */ -static void Q1BSP_RFindTouchedLeafs (model_t *wm, struct pvscache_s *ent, mnode_t *node, float *mins, float *maxs) +static void Q1BSP_RFindTouchedLeafs (model_t *wm, struct pvscache_s *ent, mnode_t *node, const float *mins, const float *maxs) { mplane_t *splitplane; mleaf_t *leaf; @@ -1891,7 +1893,7 @@ static void Q1BSP_RFindTouchedLeafs (model_t *wm, struct pvscache_s *ent, mnode_ if (sides & 2) Q1BSP_RFindTouchedLeafs (wm, ent, node->children[1], mins, maxs); } -static void Q1BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, float *mins, float *maxs) +static void Q1BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, const float *mins, const float *maxs) { ent->num_leafs = 0; if (mins && maxs) @@ -2085,7 +2087,7 @@ mleaf_t *Q1BSP_LeafForPoint (model_t *model, vec3_t p) return model->leafs + Q1BSP_LeafnumForPoint(model, p); } -static void Q1BSP_ClustersInSphere_Union(mleaf_t *firstleaf, vec3_t center, float radius, mnode_t *node, qbyte *out, qbyte *unionwith) +static void Q1BSP_ClustersInSphere_Union(mleaf_t *firstleaf, const vec3_t center, float radius, mnode_t *node, qbyte *out, qbyte *unionwith) { //this is really for rtlights. float t1, t2; mplane_t *plane; @@ -2129,7 +2131,7 @@ static void Q1BSP_ClustersInSphere_Union(mleaf_t *firstleaf, vec3_t center, floa continue; } } -static qbyte *Q1BSP_ClustersInSphere(model_t *mod, vec3_t center, float radius, pvsbuffer_t *pvsbuffer, qbyte *unionwith) +static qbyte *Q1BSP_ClustersInSphere(model_t *mod, const vec3_t center, float radius, pvsbuffer_t *fte_restrict pvsbuffer, const qbyte *unionwith) { if (!mod) Sys_Error ("Mod_PointInLeaf: bad model"); @@ -2145,7 +2147,7 @@ static qbyte *Q1BSP_ClustersInSphere(model_t *mod, vec3_t center, float radius, //returns the leaf number, which is used as a direct bit index into the pvs. //-1 for invalid -static int Q1BSP_ClusterForPoint (model_t *model, vec3_t p) +static int Q1BSP_ClusterForPoint (model_t *model, const vec3_t p, int *area) { mnode_t *node; float d; @@ -2155,6 +2157,8 @@ static int Q1BSP_ClusterForPoint (model_t *model, vec3_t p) { Sys_Error ("Mod_PointInLeaf: bad model"); } + if (area) + *area = 0; //no areas with q1bsp. if (!model->nodes) return -1; diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 1d3bc678..567c45bd 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -1722,4 +1722,26 @@ void MSG_Q3_ReadDeltaUsercmd(int key, const usercmd_t *from, usercmd_t *to) } } +qint64_t Q3VM_GetRealtime(q3time_t *qtime) +{ //this is useful mostly for saved games, or other weird stuff. + time_t t = time(NULL); + if (qtime) + { + struct tm *tm = localtime(&t); + if (tm) + { + qtime->tm_sec = tm->tm_sec; + qtime->tm_hour = tm->tm_hour; + qtime->tm_mday = tm->tm_mday; + qtime->tm_mon = tm->tm_mon; + qtime->tm_year = tm->tm_year; + qtime->tm_wday = tm->tm_wday; + qtime->tm_yday = tm->tm_yday; + qtime->tm_isdst = tm->tm_isdst; + } + else + memset(qtime, 0, sizeof(*qtime)); + } + return t; +} #endif diff --git a/engine/common/sys_linux_threads.c b/engine/common/sys_linux_threads.c index 64c07eba..1697fa86 100644 --- a/engine/common/sys_linux_threads.c +++ b/engine/common/sys_linux_threads.c @@ -371,7 +371,7 @@ pubsubserver_t *Sys_ForkServer(void) DL_DeThread(); #endif #ifdef SQL - SQL_KillServers(); //FIXME: this is bad... + SQL_KillServers(NULL); //FIXME: this is bad... #endif //FIXME: we should probably use posix_atfork for those. diff --git a/engine/common/vm.h b/engine/common/vm.h index 74264f29..989a09ae 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -124,4 +124,17 @@ typedef struct { int VMQ3_Cvar_Register(q3vmcvar_t *v, char *name, char *defval, int flags); int VMQ3_Cvar_Update(q3vmcvar_t *v); +typedef struct { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +} q3time_t; +qint64_t Q3VM_GetRealtime(q3time_t *qtime); + #endif diff --git a/engine/common/world.h b/engine/common/world.h index c68756ca..955e2277 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -361,14 +361,14 @@ typedef struct q2edict_s q2edict_t; void VARGS WorldQ2_LinkEdict(world_t *w, q2edict_t *ent); void VARGS WorldQ2_UnlinkEdict(world_t *w, q2edict_t *ent); -int VARGS WorldQ2_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, q2edict_t **list, +int VARGS WorldQ2_AreaEdicts (world_t *w, const vec3_t mins, const vec3_t maxs, q2edict_t **list, int maxcount, int areatype); trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict); #endif #if defined(Q2BSPS) || defined(Q3BSPS) -unsigned int Q23BSP_FatPVS(model_t *mod, vec3_t org, pvsbuffer_t *buffer, qboolean merge); -qboolean Q23BSP_EdictInFatPVS(model_t *mod, struct pvscache_s *ent, qbyte *pvs); -void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, float *mins, float *maxs); +unsigned int Q23BSP_FatPVS(model_t *mod, const vec3_t org, pvsbuffer_t *buffer, qboolean merge); +qboolean Q23BSP_EdictInFatPVS(model_t *mod, const struct pvscache_s *ent, const qbyte *pvs, const int *areas); +void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, const float *mins, const float *maxs); #endif diff --git a/engine/droid/src/com/fteqw/FTENativeActivity.java b/engine/droid/src/com/fteqw/FTENativeActivity.java index 76b6466b..ca78a9ea 100644 --- a/engine/droid/src/com/fteqw/FTENativeActivity.java +++ b/engine/droid/src/com/fteqw/FTENativeActivity.java @@ -10,7 +10,7 @@ public class FTENativeActivity extends android.app.Activity implements android.v //Native functions and stuff private native boolean startup(String externalDataPath, String libraryPath); private native void openfile(String url); - private native void surfacechange(boolean teardown, boolean restart, android.view.Surface surface); + private native void surfacechange(boolean teardown, boolean restart, android.view.SurfaceHolder holder, android.view.Surface surface); private native void shutdown(); private static native void keypress(int devid, boolean down, int androidkey, int unicode); @@ -48,11 +48,11 @@ public class FTENativeActivity extends android.app.Activity implements android.v } public void surfaceChanged(android.view.SurfaceHolder holder, int format, int width, int height) { - surfacechange(true, true, holder.getSurface()); + surfacechange(true, true, holder, holder.getSurface()); } public void surfaceDestroyed(android.view.SurfaceHolder holder) { - surfacechange(true, false, null); + surfacechange(true, false, null, null); } //OnGlobalLayoutListener methods diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 322c16fd..34354811 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -2745,7 +2745,7 @@ static void BE_GenPolyBatches(batch_t **batches) } void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches); void PR_Route_Visualise(void); -void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode, qbyte *worldpvs) +void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode, const qbyte *worldpvs, const int *worldareas) { int i; entity_t *ent; @@ -2757,7 +2757,10 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo extern cvar_t r_ignoreentpvs; //legacy value is 1... if (r_ignoreentpvs.ival) + { worldpvs = NULL; + worldareas = NULL; + } /*clear the batch list*/ for (i = 0; i < SHADER_SORT_COUNT; i++) @@ -2809,7 +2812,7 @@ void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemo } #endif - if (worldpvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &ent->pvscache, worldpvs)) + if (worldpvs && !cl.worldmodel->funcs.EdictInFatPVS(cl.worldmodel, &ent->pvscache, worldpvs, worldareas)) continue; switch(ent->rtype) diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 6c2328b3..40934085 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -5583,12 +5583,12 @@ batch_t *GLBE_GetTempBatch(void) /*called from shadowmapping code*/ #ifdef RTLIGHTS -void GLBE_BaseEntTextures(qbyte *worldpvs) +void GLBE_BaseEntTextures(const qbyte *worldpvs, const int *worldareas) { batch_t *batches[SHADER_SORT_COUNT]; batch_t **ob = shaderstate.mbatches; shaderstate.mbatches = batches; - BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode, worldpvs); + BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode, worldpvs, worldareas); GLBE_SubmitMeshes(NULL, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1); GLBE_SelectEntity(&r_worldentity); shaderstate.mbatches = ob; @@ -6255,7 +6255,7 @@ void GLBE_DrawWorld (batch_t **worldbatches) } //memset(batches, 0, sizeof(batches)); - BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD, r_refdef.scenevis); + BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD, r_refdef.scenevis, r_refdef.sceneareas); R_GenDlightBatches(batches); shaderstate.curentity = &r_worldentity; // if (cl.paused || cls.state < ca_active) diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index b6737c28..529f779a 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -2836,7 +2836,7 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h) Terr_RebuildMesh(ctx->wmodel, s, x, y); } - if (ctx->pvs && !ctx->wmodel->funcs.EdictInFatPVS(ctx->wmodel, &s->pvscache, ctx->pvs)) + if (ctx->pvs && !ctx->wmodel->funcs.EdictInFatPVS(ctx->wmodel, &s->pvscache, ctx->pvs, NULL)) return; //this section isn't in any visible bsp leafs if (s->numents) @@ -3200,7 +3200,7 @@ void Terrain_ClipDecal(fragmentdecal_t *dec, float *center, float radius, model_ #endif -unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t org) +unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, const vec3_t org) { float x, y; float z, tz; @@ -3283,7 +3283,7 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t return contents; } -unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org) +unsigned int Heightmap_PointContents(model_t *model, const vec3_t axis[3], const vec3_t org) { heightmap_t *hm = model->terrain; unsigned int cont; @@ -3324,7 +3324,7 @@ unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org) return cont; } -unsigned int Heightmap_NativeBoxContents(model_t *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t org, vec3_t mins, vec3_t maxs) +unsigned int Heightmap_NativeBoxContents(model_t *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t org, const vec3_t mins, const vec3_t maxs) { heightmap_t *hm = model->terrain; return Heightmap_PointContentsHM(hm, mins[2], org); @@ -4000,7 +4000,7 @@ Why is recursion good? Obviously, we don't care all that much about 1 */ -qboolean Heightmap_Trace(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) +qboolean Heightmap_Trace(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t mataxis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) { vec2_t pos; vec2_t frac; @@ -4271,7 +4271,7 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, framestate_t * return trace->fraction < 1; } -qboolean Heightmap_Trace_Test(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) +qboolean Heightmap_Trace_Test(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t mataxis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) { qboolean ret = Heightmap_Trace(model, hulloverride, framestate, mataxis, start, end, mins, maxs, capsule, against, trace); @@ -4301,7 +4301,7 @@ typedef struct int id; int min[3], max[3]; } hmpvsent_t; -unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean add) +unsigned int Heightmap_FatPVS (model_t *mod, const vec3_t org, pvsbuffer_t *fte_restrict pvsbuffer, qboolean add) { //embed the org onto the pvs hmpvs_t *hmpvs; @@ -4314,12 +4314,12 @@ unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *pvsbuffer } #ifndef CLIENTONLY -qboolean Heightmap_EdictInFatPVS (model_t *mod, struct pvscache_s *edict, qbyte *pvsdata) +qboolean Heightmap_EdictInFatPVS (model_t *mod, const struct pvscache_s *edict, const qbyte *pvsdata, const int *areas) { heightmap_t *hm = mod->terrain; int o[3], i; - hmpvs_t *hmpvs = (hmpvs_t*)pvsdata; - hmpvsent_t *hmed = (hmpvsent_t*)edict; + const hmpvs_t *hmpvs = (const hmpvs_t*)pvsdata; + const hmpvsent_t *hmed = (const hmpvsent_t*)edict; if (!hm->culldistance) return true; @@ -4338,7 +4338,7 @@ qboolean Heightmap_EdictInFatPVS (model_t *mod, struct pvscache_s *edict, qbyte return DotProduct(o,o) < hm->culldistance; } -void Heightmap_FindTouchedLeafs (model_t *mod, pvscache_t *ent, float *mins, float *maxs) +void Heightmap_FindTouchedLeafs (model_t *mod, pvscache_t *ent, const float *mins, const float *maxs) { hmpvsent_t *hmed = (hmpvsent_t*)ent; @@ -4347,7 +4347,7 @@ void Heightmap_FindTouchedLeafs (model_t *mod, pvscache_t *ent, float *mins, flo } #endif -void Heightmap_LightPointValues (model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +void Heightmap_LightPointValues (model_t *mod, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { res_diffuse[0] = 128; res_diffuse[1] = 128; @@ -4373,8 +4373,10 @@ qbyte *Heightmap_ClusterPVS (model_t *model, int num, pvsbuffer_t *buffer, pvsme // static qbyte heightmappvs = 255; // return &heightmappvs; } -int Heightmap_ClusterForPoint (model_t *model, vec3_t point) +int Heightmap_ClusterForPoint (model_t *model, const vec3_t point, int *area) { + if (*area) + *area = 0; return -1; } diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 1cffb81f..46819d9a 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -25,8 +25,8 @@ Nor will it work 100% */ -qboolean HLMDL_Trace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace); -unsigned int HLMDL_Contents (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); +qboolean HLMDL_Trace (struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p1, const vec3_t p2, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace); +unsigned int HLMDL_Contents (struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs); void QuaternionGLMatrix(float x, float y, float z, float w, vec4_t *GLM) { @@ -921,7 +921,7 @@ int HLMDL_GetAttachment(model_t *mod, int tagnum, float *resultmatrix) return -1; } -static int HLMDL_GetBoneData_Internal(hlmodel_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result) +static int HLMDL_GetBoneData_Internal(hlmodel_t *model, int firstbone, int lastbone, const framestate_t *fstate, float *result) { int b, cbone, bgroup; @@ -939,7 +939,7 @@ static int HLMDL_GetBoneData_Internal(hlmodel_t *model, int firstbone, int lastb } return cbone; } -int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, framestate_t *fstate, float *result) +int HLMDL_GetBoneData(model_t *mod, int firstbone, int lastbone, const framestate_t *fstate, float *result) { return HLMDL_GetBoneData_Internal(Mod_Extradata(mod), firstbone, lastbone, fstate, result); } @@ -966,7 +966,7 @@ qboolean HLMDL_FrameInfoForNum(model_t *mod, int surfaceidx, int seqnum, char ** -qboolean HLMDL_Trace (model_t *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) +qboolean HLMDL_Trace (model_t *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p1, const vec3_t p2, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) { hlmodel_t *hm = Mod_Extradata(model); float *relbones; @@ -1140,7 +1140,7 @@ nextbrush: return trace->truefraction != 1; } -unsigned int HLMDL_Contents (model_t *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs) +unsigned int HLMDL_Contents (model_t *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs) { trace_t tr; HLMDL_Trace(model, hulloverride, framestate, axis, p, p, mins, maxs, false, ~0, &tr); diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 46a7aa90..60348cb4 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -230,42 +230,35 @@ typedef struct qbyte *buffer; //reallocated if needed. size_t buffersize; } pvsbuffer_t; -#if 1 -typedef char *pvsmerge_t; -#define PVM_FAST ((char*)0) -#define PVM_MERGE ((char*)1) -#define PVM_REPLACE ((char*)2) -#else typedef enum { PVM_FAST, PVM_MERGE, //merge the pvs bits into the provided buffer PVM_REPLACE,//return value is guarenteed to be the provided buffer. } pvsmerge_t; -#endif typedef struct { //model is being purged from memory. void (*PurgeModel) (struct model_s *mod); - unsigned int (*PointContents) (struct model_s *model, vec3_t axis[3], vec3_t p); - unsigned int (*BoxContents) (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); + unsigned int (*PointContents) (struct model_s *model, const vec3_t axis[3], const vec3_t p); + unsigned int (*BoxContents) (struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs); //deals with whatever is native for the bsp (gamecode is expected to distinguish this). - qboolean (*NativeTrace) (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace); - unsigned int (*NativeContents)(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p, vec3_t mins, vec3_t maxs); + qboolean (*NativeTrace) (struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p1, const vec3_t p2, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace); + unsigned int (*NativeContents)(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p, const vec3_t mins, const vec3_t maxs); - unsigned int (*FatPVS) (struct model_s *model, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean merge); - qboolean (*EdictInFatPVS) (struct model_s *model, struct pvscache_s *edict, qbyte *pvs); - void (*FindTouchedLeafs) (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs); //edict system as opposed to q2 game dll system. + unsigned int (*FatPVS) (struct model_s *model, const vec3_t org, pvsbuffer_t *pvsbuffer, qboolean merge); + qboolean (*EdictInFatPVS) (struct model_s *model, const struct pvscache_s *edict, const qbyte *pvs, const int *areas); //areas[0] is the count of accepted areas, if valid. + void (*FindTouchedLeafs) (struct model_s *model, struct pvscache_s *ent, const vec3_t cullmins, const vec3_t cullmaxs); //edict system as opposed to q2 game dll system. - void (*LightPointValues) (struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); + void (*LightPointValues) (struct model_s *model, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); void (*StainNode) (struct mnode_s *node, float *parms); void (*MarkLights) (struct dlight_s *light, int bit, struct mnode_s *node); - int (*ClusterForPoint) (struct model_s *model, vec3_t point); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs). + int (*ClusterForPoint) (struct model_s *model, const vec3_t point, int *areaout); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs). qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge); - qbyte *(*ClustersInSphere) (struct model_s *model, vec3_t point, float radius, pvsbuffer_t *pvsbuffer, qbyte *unionwith); + qbyte *(*ClustersInSphere) (struct model_s *model, const vec3_t point, float radius, pvsbuffer_t *pvsbuffer, const qbyte *fte_restrict unionwith); } modelfuncs_t; @@ -571,8 +564,8 @@ size_t Fragment_ClipPlaneToBrush(vecV_t *points, size_t maxpoints, void *planes, void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangent2, float size, unsigned int surfflagmask, unsigned int surflagmatch, void (*callback)(void *ctx, vec3_t *fte_restrict points, size_t numpoints, shader_t *shader), void *ctx); void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node); -void GLQ1BSP_LightPointValues(struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); -qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, vec3_t p1, vec3_t p2, unsigned int hitcontents, struct trace_s *trace); +void GLQ1BSP_LightPointValues(struct model_s *model, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); +qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, const vec3_t p1, const vec3_t p2, unsigned int hitcontents, struct trace_s *trace); /* ============================================================================== @@ -1077,7 +1070,7 @@ typedef struct model_s #endif // __MODEL__ -float RadiusFromBounds (vec3_t mins, vec3_t maxs); +float RadiusFromBounds (const vec3_t mins, const vec3_t maxs); // @@ -1093,8 +1086,8 @@ void Terr_FinishTerrain(model_t *model); void Terr_PurgeTerrainModel(model_t *hm, qboolean lightmapsonly, qboolean lightmapreusable); void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force); //call this after loading a bsp qboolean Terrain_LocateSection(const char *name, flocation_t *loc); //used on servers to generate sections for download. -qboolean Heightmap_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace); -unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org); +qboolean Heightmap_Trace(model_t *model, int forcehullnum, const framestate_t *framestate, const vec3_t axis[3], const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace); +unsigned int Heightmap_PointContents(model_t *model, const vec3_t axis[3], const vec3_t org); struct fragmentdecal_s; void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model); qboolean Terr_DownloadedSection(char *fname); @@ -1122,22 +1115,22 @@ void CM_InitBoxHull (void); void CM_Init(void); qboolean CM_SetAreaPortalState (struct model_s *mod, int portalnum, qboolean open); -qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, qbyte *visbits); +qboolean CM_HeadnodeVisible (struct model_s *mod, int nodenum, const qbyte *visbits); qboolean VARGS CM_AreasConnected (struct model_s *mod, unsigned int area1, unsigned int area2); int CM_ClusterBytes (struct model_s *mod); int CM_LeafContents (struct model_s *mod, int leafnum); int CM_LeafCluster (struct model_s *mod, int leafnum); int CM_LeafArea (struct model_s *mod, int leafnum); int CM_WriteAreaBits (struct model_s *mod, qbyte *buffer, int area, qboolean merge); -int CM_PointLeafnum (struct model_s *mod, vec3_t p); +int CM_PointLeafnum (struct model_s *mod, const vec3_t p); qbyte *CM_ClusterPVS (struct model_s *mod, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge); qbyte *CM_ClusterPHS (struct model_s *mod, int cluster, pvsbuffer_t *buffer); -int CM_BoxLeafnums (struct model_s *mod, vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode); -int CM_PointContents (struct model_s *mod, vec3_t p); -int CM_TransformedPointContents (struct model_s *mod, vec3_t p, int headnode, vec3_t origin, vec3_t angles); -int CM_HeadnodeForBox (struct model_s *mod, vec3_t mins, vec3_t maxs); +int CM_BoxLeafnums (struct model_s *mod, const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *topnode); +int CM_PointContents (struct model_s *mod, const vec3_t p); +int CM_TransformedPointContents (struct model_s *mod, const vec3_t p, int headnode, const vec3_t origin, const vec3_t angles); +int CM_HeadnodeForBox (struct model_s *mod, const vec3_t mins, const vec3_t maxs); //struct trace_s CM_TransformedBoxTrace (struct model_s *mod, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int brushmask, vec3_t origin, vec3_t angles); -struct model_s *CM_TempBoxModel(vec3_t mins, vec3_t maxs); +struct model_s *CM_TempBoxModel(const vec3_t mins, const vec3_t maxs); //for gamecode to control portals/areas void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index d3cf78bd..c860da00 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -2301,7 +2301,7 @@ LIGHT SAMPLING mplane_t *lightplane; vec3_t lightspot; -static void GLQ3_AddLatLong(qbyte latlong[2], vec3_t dir, float mag) +static void GLQ3_AddLatLong(const qbyte latlong[2], vec3_t dir, float mag) { float lat = (float)latlong[0] * (2 * M_PI)*(1.0 / 255.0); float lng = (float)latlong[1] * (2 * M_PI)*(1.0 / 255.0); @@ -2310,7 +2310,7 @@ static void GLQ3_AddLatLong(qbyte latlong[2], vec3_t dir, float mag) dir[2] += mag * cos ( lat ); } -void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +void GLQ3_LightGrid(model_t *mod, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { q3lightgridinfo_t *lg = (q3lightgridinfo_t *)cl.worldmodel->lightgrid; int index[8]; @@ -2585,7 +2585,7 @@ int R_LightPoint (vec3_t p) #ifdef PEXT_LIGHTSTYLECOL -static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start, vec3_t end) +static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t start, const vec3_t end) { static float l[6]; float *r; @@ -2813,7 +2813,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, vec3_t start #endif -void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) +void GLQ1BSP_LightPointValues(model_t *model, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir) { vec3_t end; float *r; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index d1a0c578..afb802d4 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1068,7 +1068,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], d += 0.1; //an epsilon on the far side VectorMA(point, d, plane.normal, point); - clust = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, point); + clust = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, point, NULL); if (i == batch->firstmesh) r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, &newvis, PVM_REPLACE); else @@ -1145,7 +1145,6 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], { //q3-style portal, where a single entity provides orientation+two origins float d; vec3_t paxis[3], porigin, vaxis[3], vorg; - void PerpendicularVector( vec3_t dst, const vec3_t src ); oplane = plane; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 01f42f4a..ee9dd8db 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -3174,7 +3174,11 @@ static void Shaderpass_RGBGen (parsestate_t *ps, char **ptr) else if (!Q_stricmp (token, "oneMinusEntity")) pass->rgbgen = RGB_GEN_ONE_MINUS_ENTITY; else if (!Q_stricmp (token, "vertex")) + { pass->rgbgen = RGB_GEN_VERTEX_LIGHTING; + if (pass->alphagen == ALPHA_GEN_UNDEFINED) //matches Q3, and is a perf gain, even if its inconsistent. + pass->alphagen = ALPHA_GEN_VERTEX; + } else if (!Q_stricmp (token, "oneMinusVertex")) pass->rgbgen = RGB_GEN_ONE_MINUS_VERTEX; else if (!Q_stricmp (token, "lightingDiffuse")) @@ -4524,7 +4528,7 @@ void Shader_Readpass (parsestate_t *ps) pass->anim_frames[0] = r_nulltex; pass->anim_numframes = 0; pass->rgbgen = RGB_GEN_UNKNOWN; - pass->alphagen = ALPHA_GEN_IDENTITY; + pass->alphagen = ALPHA_GEN_UNDEFINED; pass->tcgen = TC_GEN_UNSPECIFIED; pass->numtcmods = 0; pass->stagetype = ST_AMBIENT; @@ -4554,6 +4558,9 @@ void Shader_Readpass (parsestate_t *ps) } } + if (pass->alphagen == ALPHA_GEN_UNDEFINED) + pass->alphagen = ALPHA_GEN_IDENTITY; + //if there was no texgen, then its too late now. if (!pass->numMergedPasses) pass->numMergedPasses = 1; diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 45fdd6c3..9fdacd09 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -1578,7 +1578,7 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb, NULL); else { - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); + clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin, NULL); //FIXME: track the lights area lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); if (cl.worldmodel->funcs.ClustersInSphere) @@ -1649,7 +1649,7 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi sh_shadowframe++; { - int cluster = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); + int cluster = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin, NULL); if (cluster >= 0) sh_shmesh->litleaves[cluster>>3] |= 1<<(cluster&7); } @@ -2237,7 +2237,7 @@ static void Sh_LightFrustumPlanes(dlight_t *l, vec3_t axis[3], vec4_t *planes, i //culling for the face happens in the caller. //these faces should thus match Sh_LightFrustumPlanes -static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, float proj[16], qbyte *lightpvs) +static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowmesh_t *smesh, int face, int smsize, float proj[16], const qbyte *lightpvs) { vec3_t t1,t2,t3; texture_t *tex; @@ -2379,7 +2379,7 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm break; #ifdef GLQUAKE case QR_OPENGL: - GLBE_BaseEntTextures(lightpvs); + GLBE_BaseEntTextures(lightpvs, NULL); if (lighttype & LSHADER_ORTHO) qglDisable(GL_DEPTH_CLAMP_ARB); @@ -2387,17 +2387,17 @@ static void Sh_GenShadowFace(dlight_t *l, vec3_t axis[3], int lighttype, shadowm #endif #ifdef D3D9QUAKE case QR_DIRECT3D9: - D3D9BE_BaseEntTextures(lightpvs); + D3D9BE_BaseEntTextures(lightpvs, NULL); break; #endif #ifdef D3D11QUAKE case QR_DIRECT3D11: - D3D11BE_BaseEntTextures(lightpvs); + D3D11BE_BaseEntTextures(lightpvs, NULL); break; #endif #ifdef VKQUAKE case QR_VULKAN: - VKBE_BaseEntTextures(lightpvs); + VKBE_BaseEntTextures(lightpvs, NULL); break; #endif } @@ -2616,7 +2616,7 @@ qboolean Sh_GenerateShadowMap(dlight_t *l, int lighttype) else { int clus; - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin); + clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin, NULL); lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); //FIXME: surely we can use the phs for this? @@ -2732,12 +2732,12 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb else { int clus; - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin); + clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin, NULL); lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); //FIXME: surely we can use the phs for this? if (cl.worldmodel->funcs.ClustersInSphere) lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, l->origin, l->radius, &lvisb2, lvis); - + //FIXME: check areas if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. { RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); @@ -2856,22 +2856,22 @@ static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour, qbyte *pvs) break; #ifdef GLQUAKE case QR_OPENGL: - GLBE_BaseEntTextures(pvs); + GLBE_BaseEntTextures(pvs, NULL); break; #endif #ifdef VKQUAKE case QR_VULKAN: - VKBE_BaseEntTextures(pvs); + VKBE_BaseEntTextures(pvs, NULL); break; #endif #ifdef D3D9QUAKE case QR_DIRECT3D9: - D3D9BE_BaseEntTextures(pvs); + D3D9BE_BaseEntTextures(pvs, NULL); break; #endif #ifdef D3D11QUAKE case QR_DIRECT3D11: - D3D11BE_BaseEntTextures(pvs); + D3D11BE_BaseEntTextures(pvs, NULL); break; #endif } @@ -3159,7 +3159,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], } else { - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); + clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin, NULL); //FIXME: check areas lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); // if (cl.worldmodel->funcs.ClustersInSphere) // lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, lvis); @@ -3388,7 +3388,7 @@ qboolean Sh_CullLight(dlight_t *dl, qbyte *vvis) int clus; qbyte *lvis; - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); + clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin, NULL); lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); // if (cl.worldmodel->funcs.ClustersInSphere) // lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, lvis); @@ -3433,12 +3433,12 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, NULL); else { - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); + clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin, NULL); lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); } SHM_BuildShadowMesh(dl, lvis, SMT_SHADOWLESS); - + //FIXME: check areas if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. { RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); @@ -3645,7 +3645,7 @@ void Sh_PreGenerateLights(void) lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, NULL); else { //other lights only want to use the source leaf's pvs (clamped by the sphere) - leaf = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); + leaf = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin, NULL); lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, leaf, &lvisb, PVM_FAST); if (cl.worldmodel->funcs.ClustersInSphere) lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, lvis); diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index a69b8784..4ab4f3a0 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -131,24 +131,12 @@ qboolean R_DrawSkyroom(shader_t *skyshader) if (!r_refdef.skyroom_enabled || r_refdef.recurse >= R_MAX_RECURSE-1) return false; - if (skyshader->numpasses) - { - shaderpass_t *pass = skyshader->passes; - if (pass->shaderbits & SBITS_ATEST_BITS) //alphatests - ; - else if (pass->shaderbits & SBITS_MASK_BITS) //colormasks - ; - else if ((pass->shaderbits & SBITS_BLEND_BITS) != 0 && (pass->shaderbits & SBITS_BLEND_BITS) != (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO)) //blendfunc - ; - else - return false; //that shader looks like its opaque. - } - oldrefdef = r_refdef; r_refdef.recurse+=1; r_refdef.externalview = true; r_refdef.skyroom_enabled = false; + r_refdef.flags |= RDF_DISABLEPARTICLES; /*work out where the camera should be (use the same angles)*/ VectorCopy(r_refdef.skyroom_pos, r_refdef.vieworg); @@ -231,8 +219,21 @@ qboolean R_DrawSkyChain (batch_t *batch) skyboxtex = NULL; if (R_DrawSkyroom(skyshader)) - { + { //don't obscure the skyroom if the sky shader is opaque. + qboolean opaque = false; if (skyshader->numpasses) + { + shaderpass_t *pass = skyshader->passes; + if (pass->shaderbits & SBITS_ATEST_BITS) //alphatests + ; + else if (pass->shaderbits & SBITS_MASK_BITS) //colormasks + ; + else if ((pass->shaderbits & SBITS_BLEND_BITS) != 0 && (pass->shaderbits & SBITS_BLEND_BITS) != (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO)) //blendfunc + ; + else + opaque = true; //that shader looks like its opaque. + } + if (!opaque) GL_DrawSkySphere(batch, skyshader); } else if (skyboxtex && TEXVALID(*skyboxtex)) diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 07b6c58a..87bf635d 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -318,6 +318,7 @@ extern vec3_t r_origin; // extern refdef_t r_refdef; extern unsigned int r_viewcontents; +int r_viewarea; extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; //q2 extern texture_t *r_notexture_mip; extern int d_lightstylevalue[256]; // 8.8 fraction of base light value @@ -406,7 +407,7 @@ void R_InitFlashblends(void); #ifdef GLQUAKE void GLR_MarkQ2Lights (dlight_t *light, int bit, mnode_t *node); #endif -void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); +void GLQ3_LightGrid(model_t *mod, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); qboolean R_LoadRTLights(void); qboolean R_ImportRTLights(const char *entlump); diff --git a/engine/gl/model_hl.h b/engine/gl/model_hl.h index 26a826dc..d3e8fd15 100644 --- a/engine/gl/model_hl.h +++ b/engine/gl/model_hl.h @@ -336,7 +336,7 @@ qboolean HLMDL_GetModelEvent(model_t *model, int animation, int eventidx, float int HLMDL_GetNumBones(model_t *mod, qboolean tagstoo); int HLMDL_GetBoneParent(model_t *mod, int bonenum); const char *HLMDL_GetBoneName(model_t *mod, int bonenum); -int HLMDL_GetBoneData(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result); +int HLMDL_GetBoneData(model_t *model, int firstbone, int lastbone, const framestate_t *fstate, float *result); int HLMDL_GetAttachment(model_t *model, int tagnum, float *resultmatrix); #ifndef SERVERONLY diff --git a/engine/gl/shader.h b/engine/gl/shader.h index e01f3b87..ea7de0c9 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -217,6 +217,7 @@ typedef struct shaderpass_s { shaderfunc_t rgbgen_func; enum { + ALPHA_GEN_UNDEFINED, ALPHA_GEN_ENTITY, ALPHA_GEN_WAVE, ALPHA_GEN_PORTAL, @@ -990,9 +991,9 @@ void GLBE_PolyOffsetStencilShadow(qboolean foobar); void GLBE_PolyOffsetStencilShadow(void); #endif //Called from shadowmapping code into backend -void GLBE_BaseEntTextures(qbyte *worldpvs); -void D3D9BE_BaseEntTextures(qbyte *worldpvs); -void D3D11BE_BaseEntTextures(qbyte *worldpvs); +void GLBE_BaseEntTextures(const qbyte *worldpvs, const int *worldareas); +void D3D9BE_BaseEntTextures(const qbyte *worldpvs, const int *worldareas); +void D3D11BE_BaseEntTextures(const qbyte *worldpvs, const int *worldareas); //prebuilds shadow volumes void Sh_PreGenerateLights(void); //Draws lights, called from the backend diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 5ae8e2d9..e0397995 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -852,10 +852,6 @@ void PR_Deinit(void) World_Destroy(&sv.world); -#ifdef SQL - SQL_KillServers(); -#endif - //clear out function pointers (so changing game modes cannot lead to confusions) memset(&gfuncs, 0, sizeof(gfuncs)); SpectatorConnect = 0; @@ -863,14 +859,6 @@ void PR_Deinit(void) SpectatorDisconnect = 0; } -void PR_Shutdown(void) -{ - PR_Deinit(); -#ifdef SQL - SQL_DeInit(); -#endif -} - void PR_LoadGlabalStruct(qboolean muted) { static float svphysicsmode = 2; @@ -1989,10 +1977,6 @@ void Q_InitProgs(qboolean cinematic) Con_Printf(CON_ERROR"Running without gamecode\n"); } -#ifdef SQL - SQL_KillServers(); // TODO: is this the best placement for this? -#endif - if (oldprnum >= 0) f = PR_FindFunction (svprogfuncs, "AddAddonProgs", oldprnum); else @@ -3901,7 +3885,7 @@ void PF_newcheckclient (pubprogfuncs_t *prinst, world_t *w) w->lastcheckpvs = NULL; else { - cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, checkorg); + cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, checkorg, NULL); w->lastcheckpvs = sv.world.worldmodel->funcs.ClusterPVS (sv.world.worldmodel, cluster, &checkpvsbuffer, PVM_FAST); } @@ -3956,7 +3940,7 @@ int PF_checkclient_Internal (pubprogfuncs_t *prinst) if (w->lastcheckpvs) { - clust = w->worldmodel->funcs.ClusterForPoint(w->worldmodel, view); + clust = w->worldmodel->funcs.ClusterForPoint(w->worldmodel, view, NULL); if ( (clust<0) || !(w->lastcheckpvs[clust>>3] & (1<<(clust&7)) ) ) { return 0; @@ -6488,7 +6472,7 @@ void QCBUILTIN PF_sqlconnect (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl if (!driver[0]) driver = sql_driver.string; - G_FLOAT(OFS_RETURN) = SQL_NewServer(driver, paramstr); + G_FLOAT(OFS_RETURN) = SQL_NewServer(prinst, driver, paramstr); } void QCBUILTIN PF_sqldisconnect (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -6497,7 +6481,7 @@ void QCBUILTIN PF_sqldisconnect (pubprogfuncs_t *prinst, struct globalvars_s *pr if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { SQL_Disconnect(server); @@ -6555,7 +6539,7 @@ void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_ if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { queryrequest_t *qreq; @@ -6597,7 +6581,7 @@ void QCBUILTIN PF_sqlclosequery (pubprogfuncs_t *prinst, struct globalvars_s *pr if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { qreq = SQL_GetQueryRequest(server, G_FLOAT(OFS_PARM1)); @@ -6621,7 +6605,7 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_ if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2)); @@ -6653,7 +6637,7 @@ void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_ if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { if (G_FLOAT(OFS_PARM2) < 0) @@ -6729,7 +6713,7 @@ void QCBUILTIN PF_sqlreadblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (SQL_Available()) { - server = SQL_GetServer(serveridx, false); + server = SQL_GetServer(prinst, serveridx, false); if (server) { qres = SQL_GetQueryResult(server, queryidx, row); @@ -6791,7 +6775,7 @@ void QCBUILTIN PF_sqlerror (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), true); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), true); if (server) { if (svprogfuncs->callargc == 2) @@ -6825,7 +6809,7 @@ void QCBUILTIN PF_sqlescape (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { toescape = PR_GetStringOfs(prinst, OFS_PARM1); @@ -6847,7 +6831,7 @@ void QCBUILTIN PF_sqlversion (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl if (SQL_Available()) { - server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); + server = SQL_GetServer(prinst, G_FLOAT(OFS_PARM0), false); if (server) { RETURN_TSTRING(SQL_Info(server)); diff --git a/engine/server/progs.h b/engine/server/progs.h index c9db5995..bd34e4b2 100644 --- a/engine/server/progs.h +++ b/engine/server/progs.h @@ -28,7 +28,6 @@ void SVQ1_CvarChanged(cvar_t *var); #define NewGetEdictFieldValue GetEdictFieldValue void Q_SetProgsParms(qboolean forcompiler); void PR_Deinit(void); //server shutting down -void PR_Shutdown(void); //server quitting void PR_LoadGlabalStruct(qboolean muted); void Q_InitProgs(qboolean cinematic); void PR_SpawnInitialEntities(const char *file); diff --git a/engine/server/q3g_public.h b/engine/server/q3g_public.h index 78f19e4f..49149dd4 100644 --- a/engine/server/q3g_public.h +++ b/engine/server/q3g_public.h @@ -400,7 +400,9 @@ typedef enum { BOTLIB_PC_LOAD_SOURCE, BOTLIB_PC_FREE_SOURCE, BOTLIB_PC_READ_TOKEN, - BOTLIB_PC_SOURCE_FILE_AND_LINE + BOTLIB_PC_SOURCE_FILE_AND_LINE, + + G_DEFAULTCASEWARNINGDISABLE //note: not an allowed index, just exists to prevent clang from warning about the default case. } q3ggameImport_t; diff --git a/engine/server/server.h b/engine/server/server.h index b34fa54b..d5a5a2e2 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -448,6 +448,23 @@ enum #define STUFFCMD_BROADCAST ( 1<<2) // everyone sees it. #define STUFFCMD_UNRELIABLE ( 1<<3) // someone might not see it. oh well. +enum serverprotocols_e +{ + SCP_BAD, //don't send (a bot) + SCP_QUAKEWORLD, + SCP_QUAKE2, + SCP_QUAKE3, + //all the below are considered netquake clients. + SCP_NETQUAKE, + //bjp1, bjp2 + SCP_BJP3, //16bit angles,model+sound indexes. nothing else (assume raised ent limits too). + SCP_FITZ666, + //dp5 + SCP_DARKPLACES6, + SCP_DARKPLACES7 //extra prediction stuff + //note, nq is nq+ +}; + typedef struct client_s { client_conn_state_t state; @@ -660,21 +677,7 @@ typedef struct client_s unsigned int max_net_clients; /*max number of player slots supported by the client */ unsigned int maxmodels; /*max models supported by whatever the protocol is*/ - enum { - SCP_BAD, //don't send (a bot) - SCP_QUAKEWORLD, - SCP_QUAKE2, - SCP_QUAKE3, - //all the below are considered netquake clients. - SCP_NETQUAKE, - //bjp1, bjp2 - SCP_BJP3, //16bit angles,model+sound indexes. nothing else (assume raised ent limits too). - SCP_FITZ666, - //dp5 - SCP_DARKPLACES6, - SCP_DARKPLACES7 //extra prediction stuff - //note, nq is nq+ - } protocol; + enum serverprotocols_e protocol; unsigned int supportedprotocols; qboolean proquake_angles_hack; //expect 16bit client->server angles . @@ -1145,7 +1148,29 @@ char *SV_PlayerPublicAddress(client_t *cl); qboolean SVC_GetChallenge (qboolean respond_dp); int SV_NewChallenge (void); -client_t *SVC_DirectConnect(void); +void SVC_DirectConnect(int expectedreliablesequence); +typedef struct +{ + enum serverprotocols_e protocol; //protocol used to talk to this client. +#ifdef NQPROT + qboolean proquakeanglehack; //specifies that the client will expect proquake angles if we give a proquake CCREP_ACCEPT response. + unsigned int expectedreliablesequence; //required for nq connection cookies (like tcp's syn cookies). + unsigned int supportedprotocols; //1<cursize; @@ -289,7 +307,7 @@ void MSV_MapCluster_f(void) }; Con_Printf("Opening database \"%s\"\n", sqlparams[3]); - sv.logindatabase = SQL_NewServer("sqlite", sqlparams); + sv.logindatabase = SQL_NewServer(&sv, "sqlite", sqlparams); if (sv.logindatabase == -1) #endif { @@ -1097,7 +1115,7 @@ void SSV_InitiatePlayerTransfer(client_t *cl, const char *newserver) #ifdef SQL #include "sv_sql.h" -int pendinglookups = 0; +static int pendinglookups = 0; struct logininfo_s { netadr_t clientaddr; @@ -1113,11 +1131,11 @@ void MSV_UpdatePlayerStats(unsigned int playerid, unsigned int serverid, int num { #ifdef SQL queryrequest_t *req; - sqlserver_t *srv; + sqlserver_t *srv = SQL_GetServer(&sv, sv.logindatabase, false); static char hex[16] = "0123456789abcdef"; char sql[2048], *sqle; union{float *f;qbyte *b;} blob; - if (sv.logindatabase != -1) + if (srv) { Q_snprintfz(sql, sizeof(sql), "UPDATE accounts SET stats=x'"); sqle = sql+strlen(sql); @@ -1128,9 +1146,7 @@ void MSV_UpdatePlayerStats(unsigned int playerid, unsigned int serverid, int num } Q_snprintfz(sqle, sizeof(sql)-(sqle-sql), "', serverid=%u WHERE playerid = %u;", serverid, playerid); - srv = SQL_GetServer(sv.logindatabase, false); - if (srv) - SQL_NewQuery(srv, SV_IgnoreSQLResult, sql, &req); + SQL_NewQuery(srv, SV_IgnoreSQLResult, sql, &req); } #endif } @@ -1199,81 +1215,121 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv #ifdef SQL qboolean MSV_ClusterLoginSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof) { - sqlserver_t *sql = SQL_GetServer(req->srvid, true); + sqlserver_t *sql = SQL_GetServer(&sv, req->srvid, true); queryresult_t *res = SQL_GetQueryResult(sql, req->num, 0); - struct logininfo_s *info = req->user.thread; + svconnectinfo_t *info = req->user.thread; char *s; int playerid, serverid; char *statsblob; size_t blobsize; - res = SQL_GetQueryResult(sql, req->num, 0); - if (!res) + //we only expect one row. if its a continuation then don't bug out + if (!firstrow) { - playerid = 0; - statsblob = NULL; - blobsize = 0; - serverid = 0; + res = SQL_GetQueryResult(sql, req->num, 0); + if (!res) + { + playerid = 0; + statsblob = NULL; + blobsize = 0; + serverid = 0; + } + else + { + s = SQL_ReadField(sql, res, 0, 0, true, NULL); + playerid = atoi(s); + + statsblob = SQL_ReadField(sql, res, 0, 2, true, &blobsize); + + s = SQL_ReadField(sql, res, 0, 1, true, NULL); + serverid = s?atoi(s):0; + } + + net_from = info->adr; //okay, that's a bit stupid, rewrite rejectmessage to accept an arg? + if (!playerid) + SV_RejectMessage(info->protocol, "Bad username or password.\n"); + else if (sv.state == ss_clustermode) + MSV_ClusterLoginReply(NULL, serverid, playerid, Info_ValueForKey(info->userinfo, "name"), info->guid, &info->adr, statsblob, blobsize); + else + SV_DoDirectConnect(info); + Z_Free(info); + req->user.thread = NULL; + pendinglookups--; } - else - { - s = SQL_ReadField(sql, res, 0, 0, true, NULL); - playerid = atoi(s); - - statsblob = SQL_ReadField(sql, res, 0, 2, true, &blobsize); - - s = SQL_ReadField(sql, res, 0, 1, true, NULL); - serverid = s?atoi(s):0; - } - - net_from = info->clientaddr; //okay, that's a bit stupid, rewrite rejectmessage to accept an arg? - if (!playerid) - SV_RejectMessage(SCP_QUAKEWORLD, "Bad username or password.\n"); - else - MSV_ClusterLoginReply(NULL, serverid, playerid, info->name, info->guid, &info->clientaddr, statsblob, blobsize); - Z_Free(info); - pendinglookups--; return false; } #endif +qboolean MSV_IgnoreSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof) +{ + return false; +} +void MSV_OpenUserDatabase(void) +{ +#if 0 + sqlserver_t *sql; + const char *sqlparams[] = + { + "", + "", + "", + "login", + }; + + Con_Printf("Opening database \"%s\"\n", sqlparams[3]); + sv.logindatabase = SQL_NewServer(&sv, "sqlite", sqlparams); + + //create a the accounts table, so we don't end up with unusable databases. + sql = SQL_GetServer(&sv, sv.logindatabase, false); + if (sql) + { + SQL_NewQuery(sql, MSV_IgnoreSQLResult, + "CREATE TABLE IF NOT EXISTS accounts(" + "playerid INTEGER PRIMARY KEY," + "name TEXT NOT NULL UNIQUE," + "password TEXT," + "serverid INTEGER," + "parms BLOB," + "parmstring TEXT" + ");", NULL); + } +#endif +} + //returns true to block entry to this server. extern int nextuserid; -qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize) +qboolean MSV_ClusterLogin(svconnectinfo_t *info) { - if (sv.state != ss_clustermode) - return false; - /*if (!*guid) { SV_RejectMessage(SCP_QUAKEWORLD, "No guid info, please set cl_sendguid to 1.\n"); return false; }*/ - #ifdef SQL if (sv.logindatabase != -1) { char escname[64], escpasswd[64]; - struct logininfo_s *info; sqlserver_t *sql; queryrequest_t *req; if (pendinglookups > 10) - return true; - sql = SQL_GetServer(sv.logindatabase, false); + return true; //don't spam requests if we're getting dos-spammed. + sql = SQL_GetServer(&sv, sv.logindatabase, false); if (!sql) - return true; - SQL_Escape(sql, Info_ValueForKey(userinfo, "name"), escname, sizeof(escname)); - SQL_Escape(sql, Info_ValueForKey(userinfo, "password"), escpasswd, sizeof(escpasswd)); - if (SQL_NewQuery(sql, MSV_ClusterLoginSQLResult, va("SELECT playerid,serverid,stats FROM accounts WHERE name='%s' AND password='%s';", escname, escpasswd), &req) != -1) + return true; //connection was killed? o.O + SQL_Escape(sql, Info_ValueForKey(info->userinfo, "name"), escname, sizeof(escname)); + SQL_Escape(sql, Info_ValueForKey(info->userinfo, "password"), escpasswd, sizeof(escpasswd)); + if (SQL_NewQuery(sql, MSV_ClusterLoginSQLResult, va("SELECT playerid,serverid,parms,parmstring FROM accounts WHERE name='%s' AND password='%s';", escname, escpasswd), &req) != -1) { pendinglookups++; - req->user.thread = info = Z_Malloc(sizeof(*info)); - Q_strncpyz(info->guid, guid, sizeof(info->guid)); - info->clientaddr = net_from; + req->user.thread = Z_Malloc(sizeof(*info)); + memcpy(req->user.thread, info, sizeof(*info)); } } else #endif + if (sv.state != ss_clustermode) + return false; + else /* if (0) { char tmpbuf[256]; @@ -1286,7 +1342,7 @@ qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize) return true; } else*/ - MSV_ClusterLoginReply(NULL, 0, ++nextuserid, Info_ValueForKey(userinfo, "name"), guid, &net_from, NULL, 0); + MSV_ClusterLoginReply(NULL, 0, ++nextuserid, Info_ValueForKey(info->userinfo, "name"), info->guid, &net_from, NULL, 0); return true; } #endif diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 67bf4d37..358f9312 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -33,6 +33,7 @@ typedef struct int numents; edict_t *ent[SV_PVS_CAMERAS]; //ents in this list are always sent, even if the server thinks that they are invisible. vec3_t org[SV_PVS_CAMERAS]; + int area[1+SV_PVS_CAMERAS]; pvsbuffer_t pvs; } pvscamera_t; @@ -2695,7 +2696,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t * continue; // ignore if not touching a PV leaf - if (cameras && !sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &ent->pvsinfo, cameras->pvs.buffer)) + if (cameras && !sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &ent->pvsinfo, cameras->pvs.buffer, &cameras->numents)) continue; if (!((int)clent->xv->dimension_see & ((int)ent->xv->dimension_seen | (int)ent->xv->dimension_ghost))) @@ -3690,13 +3691,13 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t } else { - if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)tracecullent)->pvsinfo, cameras->pvs.buffer)) + if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)tracecullent)->pvsinfo, cameras->pvs.buffer, cameras->area)) continue; } } else { - if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, cameras->pvs.buffer)) + if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, cameras->pvs.buffer, cameras->area)) continue; tracecullent = ent; } @@ -3710,14 +3711,14 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t { //FIXME: this lookup should be cachable or something. if (client->edict) - cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, client->edict->v->origin); + cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, client->edict->v->origin, NULL); //ignore areas, can hear through doors. else cluster = -1; //mvd if (cluster >= 0) { mask = phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5); - cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, ent->v->origin); + cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, ent->v->origin, NULL); if (cluster >= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) ) { continue; @@ -3859,6 +3860,7 @@ void SV_AddCameraEntity(pvscamera_t *cameras, edict_t *ent, vec3_t viewofs) { int i; vec3_t org; + int area; for (i = 0; i < cameras->numents; i++) { @@ -3871,6 +3873,17 @@ void SV_AddCameraEntity(pvscamera_t *cameras, edict_t *ent, vec3_t viewofs) else VectorCopy (ent->v->origin, org); + sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, org, &area); + for (i = 1; ; i++) + { + if (i > cameras->area[0]) + { //reached the end of the known count. add it now. + cameras->area[++cameras->area[0]] = area; + break; + } + if (cameras->area[i] == area) + break; //already have a camera in this area, don't make stuff slow with dupes. + } sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org, &cameras->pvs, cameras->numents!=0); if (cameras->numents < SV_PVS_CAMERAS) { @@ -3882,6 +3895,7 @@ void SV_AddCameraEntity(pvscamera_t *cameras, edict_t *ent, vec3_t viewofs) void SV_Snapshot_SetupPVS(client_t *client, pvscamera_t *camera) { + camera->area[0] = 0; camera->numents = 0; for (; client; client = client->controlled) { diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 9c0fe734..a2f5be95 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -20,6 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "pr_common.h" +#ifdef SQL +#include "sv_sql.h" +#endif #ifndef CLIENTONLY extern int total_loading_size, current_loading_size, loading_stage; char *T_GetString(int num); @@ -798,6 +801,9 @@ void SV_WipeServerState(void) for (i = 0; i < sizeof(sv.strings) / sizeof(sv.strings.ptrs[0]); i++) Z_Free(ptrs[i]); } +#ifdef SQL + SQL_KillServers(&sv); +#endif memset (&sv, 0, sizeof(sv)); sv.logindatabase = -1; } @@ -1103,6 +1109,8 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, sv.state = ss_loading; +MSV_OpenUserDatabase(); + sv.world.max_edicts = pr_maxedicts.value; if (sv.world.max_edicts > MAX_EDICTS) sv.world.max_edicts = MAX_EDICTS; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 13129ad9..79b0dc13 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -20,6 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "netinc.h" #include "fs.h" //for updates +#ifdef SQL +#include "sv_sql.h" +#endif #include #ifndef CLIENTONLY #define Q2EDICT_NUM(i) (q2edict_t*)((char *)ge->edicts+(i)*ge->edict_size) @@ -200,10 +203,6 @@ vfsfile_t *sv_fraglogfile; void SV_AcceptClient (netadr_t *adr, int userid, char *userinfo); void PRH2_SetPlayerClass(client_t *cl, int classnum, qboolean fromqc); -#ifdef SQL -void PR_SQLCycle(void); -#endif - int nextuserid; //============================================================================ @@ -1827,7 +1826,7 @@ static qboolean SV_ChallengeRecent(void) } #endif -void VARGS SV_RejectMessage(int protocol, char *format, ...) +void VARGS SV_RejectMessage(enum serverprotocols_e protocol, char *format, ...) { va_list argptr; char string[8192]; @@ -2333,24 +2332,8 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id) return cl; } -/* -================== -SVC_DirectConnect - -A connection request that did not come from the master -================== -arguments must be tokenized first -Q3: connect "\key\val" -DP: connect\key\val -QW: connect $VER $QPORT $CHALLENGE "\key\val" -SS: connect2 $VER $QPORT $CHALLENGE "\key\val" "\key\val" -NQ: hacked to take the form of QW, but with protocol version 3. -extension flags follow it. -*/ -client_t *SVC_DirectConnect(void) +void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info) { - char userinfo[MAX_SPLITS][2048]; - netadr_t adr; int i; client_t *cl, *newcl; client_t temp; @@ -2362,27 +2345,10 @@ client_t *SVC_DirectConnect(void) char *s; int clients, spectators; qboolean spectator; - int qport; - int version; - int challenge; -#ifdef HUFFNETWORK - int huffcrc = 0; - extern cvar_t net_compress; -#endif - int mtu = 0; - char guid[128] = ""; - char basic[80]; + char basic[80]; qboolean redirect = false; qboolean preserveparms = false; - int numssclients = 1; - - int protocol; - qboolean proquakeanglehack = false; - unsigned int supportedprotocols = 0; - - unsigned int protextsupported=0; - unsigned int protextsupported2=0; #ifdef NQPROT extern cvar_t sv_protocol_nq; #endif @@ -2391,410 +2357,81 @@ client_t *SVC_DirectConnect(void) char *name; char adrbuf[MAX_ADR_SIZE]; - if (*Cmd_Argv(1) == '\\') - { //connect "\key\val" -#ifndef QWOVERQ3 - SV_RejectMessage (SCP_QUAKE3, "This is not a q3 server: %s\n", version_string()); - Con_TPrintf ("* rejected connect from q3 client\n"); - return NULL; -#else - //this is used by q3 (note, we already decrypted the huffman connection packet in a hack) - if (!sv_listen_q3.ival) - { - SV_RejectMessage (SCP_QUAKE3, "Server is not accepting quake3 clients at this time: %s\n", version_string()); - Con_TPrintf ("* rejected connect from q3 client\n"); - return NULL; - } - numssclients = 1; - protocol = SCP_QUAKE3; + net_from = info->adr; //SV_AcceptMessage+SV_RejectMessage are lame. - Q_strncpyz (userinfo[0], Cmd_Argv(1), sizeof(userinfo[0])-1); - - switch (atoi(Info_ValueForKey(userinfo[0], "protocol"))) - { - case 68: //regular q3 1.32 - break; -// case 43: //q3 1.11 (most 'recent' demo) -// break; - default: - SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string()); - Con_TPrintf ("* rejected connect from incompatable client\n"); - return NULL; - } - - s = Info_ValueForKey(userinfo[0], "challenge"); - challenge = atoi(s); - - s = Info_ValueForKey(userinfo[0], "qport"); - qport = atoi(s); - - s = Info_ValueForKey(userinfo[0], "name"); - if (!*s) - Info_SetValueForKey(userinfo[0], "name", "UnnamedQ3", sizeof(userinfo[0])); - -#ifdef HUFFNETWORK - huffcrc = HUFFCRC_QUAKE3; -#endif -#endif - } - else if (*(Cmd_Argv(0)+7) == '\\') - { //DP has the userinfo attached directly to the end of the connect command - if (!sv_listen_dp.value && net_from.type != NA_LOOPBACK) - { - if (!sv_listen_nq.value) - SV_RejectMessage (SCP_DARKPLACES6, "Server is not accepting darkplaces clients at this time.\n", version_string()); - Con_TPrintf ("* rejected connect from dp client\n"); - return NULL; - } - if (progstype == PROG_H2) - { - if (!sv_listen_nq.value) - SV_RejectMessage (SCP_DARKPLACES6, "NQ protocols are not supported with hexen2 gamecode.\n", version_string()); - Con_TPrintf ("* rejected connect from dp client (because of hexen2)\n"); - return NULL; - } - Q_strncpyz (userinfo[0], net_message.data + 11, sizeof(userinfo[0])-1); - - if (strcmp(Info_ValueForKey(userinfo[0], "protocol"), "darkplaces 3")) - { - SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string()); - Con_TPrintf ("* rejected connect from incompatible client\n"); - return NULL; - } - //it's a darkplaces client. - - s = Info_ValueForKey(userinfo[0], "protocols"); - - while(s && *s) - { - static const struct - { - char *name; - unsigned int bits; - } dpnames[] = - { - {"FITZ", 1u< MAX_SPLITS) - { - SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string()); - Con_TPrintf ("* rejected connect from broken client\n"); - return NULL; - } - } - - version = atoi(Cmd_Argv(1)); - if (version >= 31 && version <= 34) - { - numssclients = 1; - protocol = SCP_QUAKE2; - } - else if (version == 3) - { - numssclients = 1; - protocol = SCP_NETQUAKE; //because we can - switch(atoi(Info_ValueForKey(Cmd_Argv(4), "mod"))) - { - case 1: - proquakeanglehack = true; - break; -#ifdef NQPROT - case PROTOCOL_VERSION_FITZ: - case PROTOCOL_VERSION_RMQ: - protocol = SCP_FITZ666; - break; - case PROTOCOL_VERSION_BJP3: - protocol = SCP_BJP3; - proquakeanglehack = true; - break; -#endif - } - } - else if (version != PROTOCOL_VERSION_QW) - { - SV_RejectMessage (SCP_BAD, "Server is protocol version %i, received %i\n", PROTOCOL_VERSION_QW, version); - Con_TPrintf ("* rejected connect from version %i\n", version); - return NULL; - } - else - protocol = SCP_QUAKEWORLD; - - qport = atoi(Cmd_Argv(2)); - - challenge = atoi(Cmd_Argv(3)); - - // note an extra qbyte is needed to replace spectator key - for (i = 0; i < numssclients; i++) - { - Q_strncpyz (userinfo[i], Cmd_Argv(4+i), sizeof(userinfo[i])-1); - - if (protocol == SCP_NETQUAKE) - Info_RemoveKey(userinfo[i], "mod"); //its served its purpose. - } - } - -#ifdef HAVE_DTLS - if (net_enable_dtls.ival > 2 && (net_from.prot == NP_DGRAM || net_from.prot == NP_STREAM || net_from.prot == NP_WS)) - { - SV_RejectMessage (protocol, "This server requires the use of DTLS/TLS/WSS.\n"); - return NULL; - } -#endif - - { - char *banreason = SV_BannedReason(&net_from); - if (banreason) - { - if (*banreason) - SV_RejectMessage (protocol, "You were banned.\nReason: %s\n", banreason); - else - SV_RejectMessage (protocol, "You were banned.\n"); - return NULL; - } - } - - if (protocol == SCP_QUAKEWORLD) //readd? - { - if (!sv_listen_qw.value && net_from.type != NA_LOOPBACK) - { - SV_RejectMessage (protocol, "QuakeWorld protocols are not permitted on this server.\n"); - Con_TPrintf ("* rejected connect from quakeworld\n"); - return NULL; - } - } - - if (net_from.type == NA_LOOPBACK) //normal rules don't apply - ; - else - { - // see if the challenge is valid - if (!SV_ChallengePasses(challenge)) - { - if (sv_listen_dp.ival && !challenge && protocol == SCP_QUAKEWORLD) - { - //dp replies with 'challenge'. which vanilla quakeworld interprets as: c - //so just silence that error. - return NULL; - } - SV_RejectMessage (protocol, "Bad challenge.\n"); - return NULL; - } - } - - if (sv_banproxies.ival) - { - //FIXME: allow them to spectate but not join - if (*Info_ValueForKey(userinfo[0], "*qwfwd")) - { - SV_RejectMessage (protocol, "Proxies are not permitted on this server.\n"); - Con_TPrintf ("* rejected connect from qwfwd proxy\n"); - return NULL; - } - if (*Info_ValueForKey(userinfo[0], "Qizmo")) - { - SV_RejectMessage (protocol, "Proxies are not permitted on this server.\n"); - Con_TPrintf ("* rejected connect from qizmo proxy\n"); - return NULL; - } - if (*Info_ValueForKey(userinfo[0], "*qtv")) - { - SV_RejectMessage (protocol, "Proxies are not permitted on this server.\n"); - Con_TPrintf ("* rejected connect from qtv proxy (udp)\n"); - return NULL; - } - } - - while(!msg_badread) - { - Cmd_TokenizeString(MSG_ReadStringLine(), false, false); - switch(Q_atoi(Cmd_Argv(0))) - { - case PROTOCOL_VERSION_FTE1: - if (protocol == SCP_QUAKEWORLD || protocol == SCP_QUAKE2) - { - protextsupported = Q_atoi(Cmd_Argv(1)); - Con_DPrintf("Client supports 0x%x fte extensions\n", protextsupported); - } - break; - case PROTOCOL_VERSION_FTE2: - if (protocol == SCP_QUAKEWORLD) - { - protextsupported2 = Q_atoi(Cmd_Argv(1)); - Con_DPrintf("Client supports 0x%x fte2 extensions\n", protextsupported2); - } - break; - case PROTOCOL_VERSION_HUFFMAN: -#ifdef HUFFNETWORK - huffcrc = Q_atoi(Cmd_Argv(1)); - Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc); - if (!net_compress.ival || !Huff_CompressionCRC(huffcrc)) - { - SV_RejectMessage (protocol, "Compression should not have been enabled.\n"); //buggy/exploiting client. can also happen from timing when changing the setting, but whatever - Con_TPrintf ("* rejected - bad compression state\n"); - return NULL; - } -#endif - break; - case PROTOCOL_VERSION_FRAGMENT: - mtu = Q_atoi(Cmd_Argv(1)) & ~7; - if (mtu < 64) - mtu = 0; - Con_DPrintf("Client supports fragmentation. mtu %i.\n", mtu); - break; - case PROTOCOL_INFO_GUID: - Q_strncpyz(guid, Cmd_Argv(1), sizeof(guid)); - Con_DPrintf("GUID %s\n", Cmd_Argv(1)); - break; - } - } - msg_badread=false; - - if (!*guid) - NET_GetConnectionCertificate(svs.sockets, &net_from, QCERT_PEERFINGERPRINT, guid, sizeof(guid)); - - /*allow_splitscreen applies only to non-local clients, so that clients have only one enabler*/ - if (!sv_allow_splitscreen.ival && net_from.type != NA_LOOPBACK) - numssclients = 1; - - if (!(protextsupported & PEXT_SPLITSCREEN)) - numssclients = 1; - - if (MSV_ClusterLogin(guid, userinfo[0], sizeof(userinfo[0]))) - return NULL; // check for password or spectator_password if (svprogfuncs) { - s = Info_ValueForKey (userinfo[0], "spectator"); + s = Info_ValueForKey (info->userinfo, "spectator"); if (s[0] && strcmp(s, "0")) { if (spectator_password.string[0] && stricmp(spectator_password.string, "none") && strcmp(spectator_password.string, s) ) { // failed - Con_TPrintf ("%s:spectator password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &net_from)); - SV_RejectMessage (protocol, "requires a spectator password\n\n"); - return NULL; + Con_TPrintf ("%s:spectator password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); + SV_RejectMessage (info->protocol, "requires a spectator password\n\n"); + return; } - Info_RemoveKey (userinfo[0], "spectator"); // remove key - Info_SetValueForStarKey (userinfo[0], "*spectator", "1", sizeof(userinfo[0])); + Info_RemoveKey (info->userinfo, "spectator"); // remove key + Info_SetValueForStarKey (info->userinfo, "*spectator", "1", sizeof(info->userinfo)); spectator = true; } else { - s = Info_ValueForKey (userinfo[0], "password"); + s = Info_ValueForKey (info->userinfo, "password"); if (password.string[0] && stricmp(password.string, "none") && strcmp(password.string, s) ) { - Con_TPrintf ("%s:password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &net_from)); - SV_RejectMessage (protocol, "server requires a password\n\n"); - return NULL; + Con_TPrintf ("%s:password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); + SV_RejectMessage (info->protocol, "server requires a password\n\n"); + return; } spectator = false; - Info_RemoveKey (userinfo[0], "password"); // remove passwd - Info_RemoveKey (userinfo[0], "*spectator"); // remove key + Info_RemoveKey (info->userinfo, "password"); // remove passwd + Info_RemoveKey (info->userinfo, "*spectator"); // remove key } } else spectator = false;//q2 does all of it's checks internally, and deals with spectator ship too - adr = net_from; - nextuserid++; // so every client gets a unique id - newcl = &temp; memset (newcl, 0, sizeof(client_t)); #ifdef NQPROT - if (!supportedprotocols && protocol == SCP_NETQUAKE) + if (!info->supportedprotocols && info->protocol == SCP_NETQUAKE) { //NQ protocols lack stuff like protocol extensions. //its the wild west where nothing is known about the client and everything breaks. + //we defer the assumption to the sv_protocol_nq cvar (only for clients that don't report their known protocols) if (!strcmp(sv_protocol_nq.string, "fitz")) - protocol = SCP_FITZ666; + info->protocol = SCP_FITZ666; else if (!strcmp(sv_protocol_nq.string, "bjp") || !strcmp(sv_protocol_nq.string, "bjp3")) - protocol = SCP_BJP3; + info->protocol = SCP_BJP3; else if (!strcmp(sv_protocol_nq.string, "dpp6") || !strcmp(sv_protocol_nq.string, "dp6")) - protocol = SCP_DARKPLACES6; + info->protocol = SCP_DARKPLACES6; else if (!strcmp(sv_protocol_nq.string, "dpp7") || !strcmp(sv_protocol_nq.string, "dp7")) - protocol = SCP_DARKPLACES7; + info->protocol = SCP_DARKPLACES7; else if (!strcmp(sv_protocol_nq.string, "id") || !strcmp(sv_protocol_nq.string, "vanilla")) - protocol = SCP_NETQUAKE; + info->protocol = SCP_NETQUAKE; else switch(sv_protocol_nq.ival) { case PROTOCOL_VERSION_RMQ: case PROTOCOL_VERSION_FITZ: - protocol = SCP_FITZ666; + info->protocol = SCP_FITZ666; break; case PROTOCOL_VERSION_BJP3: - protocol = SCP_BJP3; + info->protocol = SCP_BJP3; break; case 15: - protocol = SCP_NETQUAKE; + info->protocol = SCP_NETQUAKE; break; case PROTOCOL_VERSION_DP6: - protocol = SCP_DARKPLACES6; + info->protocol = SCP_DARKPLACES6; break; case PROTOCOL_VERSION_DP7: - protocol = SCP_DARKPLACES7; + info->protocol = SCP_DARKPLACES7; break; default: Con_Printf("sv_protocol_nq set incorrectly\n"); @@ -2803,15 +2440,15 @@ client_t *SVC_DirectConnect(void) break; } } + newcl->supportedprotocols = info->supportedprotocols; + newcl->proquake_angles_hack = info->proquakeanglehack; #endif - newcl->userid = nextuserid; - newcl->supportedprotocols = supportedprotocols; - newcl->fteprotocolextensions = protextsupported; - newcl->fteprotocolextensions2 = protextsupported2; - newcl->proquake_angles_hack = proquakeanglehack; - newcl->protocol = protocol; - Q_strncpyz(newcl->guid, guid, sizeof(newcl->guid)); + newcl->userid = ++nextuserid; + newcl->fteprotocolextensions = info->ftepext1; + newcl->fteprotocolextensions2 = info->ftepext2; + newcl->protocol = info->protocol; + Q_strncpyz(newcl->guid, info->guid, sizeof(newcl->guid)); // Con_TPrintf("%s:%s:connect\n", sv.name, NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); @@ -2820,49 +2457,54 @@ client_t *SVC_DirectConnect(void) { if (cl->state == cs_free || cl->state == cs_loadzombie) continue; - if (NET_CompareBaseAdr (&adr, &cl->netchan.remote_address) - && ((protocol == SCP_QUAKEWORLD && cl->netchan.qport == qport) || adr.port == cl->netchan.remote_address.port )) + if (NET_CompareBaseAdr (&info->adr, &cl->netchan.remote_address) + && ((info->protocol == SCP_QUAKEWORLD && cl->netchan.qport == info->qport) || info->adr.port == cl->netchan.remote_address.port )) { if (realtime - cl->connection_started < sv_reconnectlimit.value) { - Con_Printf ("%s:reconnect rejected: too soon\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); - return NULL; + Con_Printf ("%s:reconnect rejected: too soon\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); + return; } if (cl->state == cs_connected) { - if (cl->protocol != protocol) + if (cl->protocol != info->protocol) { - Con_TPrintf("%s: diff prot connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); - return NULL; + Con_TPrintf("%s: diff prot connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); + return; } else - Con_TPrintf("%s:dup connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf("%s:dup connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); } /*else if (cl->state == cs_zombie) { Con_Printf ("%s:reconnect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); }*/ else - Con_TPrintf ("%s:%s:reconnect\n", svs.name, NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf ("%s:%s:reconnect\n", svs.name, NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); + +#if 1 + //wait for timeout before the player can reuse that address:port combo. clients should pick a new port on reconnect if they want to connect instantly. + return; +#else //silently drop the old connection, without causing the old client to get a disconnect or anything stupid like that. - return NULL; cl->protocol = SCP_BAD; SV_DropClient (cl); - cl->protocol = protocol; + cl->protocol = info->protocol; break; +#endif } } - name = Info_ValueForKey (userinfo[0], "name"); + name = Info_ValueForKey (info->userinfo, "name"); - if (sv.world.worldmodel && protocol == SCP_QUAKEWORLD &&!atoi(Info_ValueForKey (userinfo[0], "iknow"))) + if (sv.world.worldmodel && info->protocol == SCP_QUAKEWORLD &&!atoi(Info_ValueForKey (info->userinfo, "iknow"))) { if (sv.world.worldmodel->fromgame == fg_halflife && !(newcl->fteprotocolextensions & PEXT_HLBSP)) { - if (atof(Info_ValueForKey (userinfo[0], "*FuhQuake")) < 0.3) + if (atof(Info_ValueForKey (info->userinfo, "*FuhQuake")) < 0.3) { - SV_RejectMessage (protocol, "The server is using a halflife level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n"); + SV_RejectMessage (info->protocol, "The server is using a halflife level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n"); // Con_Printf("player %s was dropped due to incompatible client\n", name); // return; } @@ -2870,7 +2512,7 @@ client_t *SVC_DirectConnect(void) #ifdef PEXT_Q2BSP else if (sv.world.worldmodel->fromgame == fg_quake2 && !(newcl->fteprotocolextensions & PEXT_Q2BSP)) { - SV_RejectMessage (protocol, "The server is using a q2bsp-format level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n"); + SV_RejectMessage (info->protocol, "The server is using a q2bsp-format level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n"); // Con_Printf("player %s was dropped due to incompatible client\n", name); // return; } @@ -2878,7 +2520,7 @@ client_t *SVC_DirectConnect(void) #ifdef PEXT_Q3BSP else if (sv.world.worldmodel->fromgame == fg_quake3 && !(newcl->fteprotocolextensions & PEXT_Q3BSP)) { - SV_RejectMessage (protocol, "The server is using a q3bsp-format level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n"); + SV_RejectMessage (info->protocol, "The server is using a q3bsp-format level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n"); // Con_Printf("player %s was dropped due to incompatible client\n", name); // return; } @@ -2899,7 +2541,7 @@ client_t *SVC_DirectConnect(void) if (!sv.allocated_client_slots) { Con_Printf("Apparently, there are no client slots allocated. This shouldn't be happening\n"); - return NULL; + return; } for (i=0,cl=svs.clients ; iname, name) || !*cl->name) && (!*cl->guid || !strcmp(guid, cl->guid))) || sv.allocated_client_slots <= 1) //named, or first come first serve. + if (((!strcmp(cl->name, name) || !*cl->name) && (!*cl->guid || !strcmp(info->guid, cl->guid))) || sv.allocated_client_slots <= 1) //named, or first come first serve. { if (cl->istobeloaded) Con_DPrintf("%s:Using loadzombie\n", svs.name); @@ -2936,13 +2578,13 @@ client_t *SVC_DirectConnect(void) { if (SSV_IsSubServer()) { - SV_RejectMessage (protocol, "Direct connections are not permitted.\n"); + SV_RejectMessage (info->protocol, "Direct connections are not permitted.\n"); Con_TPrintf ("* rejected direct connection\n"); - return NULL; + return; } /*single player logic*/ - if (sv.allocated_client_slots == 1 && net_from.type == NA_LOOPBACK) + if (sv.allocated_client_slots == 1 && info->adr.type == NA_LOOPBACK) if (svs.clients[0].state >= cs_connected) { Con_Printf("Kicking %s to make space for local client\n", svs.clients[0].name); @@ -2991,28 +2633,28 @@ client_t *SVC_DirectConnect(void) { if (!svprogfuncs) { - SV_RejectMessage (protocol, "\nserver is full\n\n"); - Con_TPrintf ("%s:full connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + SV_RejectMessage (info->protocol, "\nserver is full\n\n"); + Con_TPrintf ("%s:full connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); } else { if (spectator && spectators >= maxspectators.ival) { - SV_RejectMessage (protocol, "\nserver is full (%i of %i spectators)\n\n", spectators, maxspectators.ival); - Con_TPrintf ("%s:full connect (spectators)\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + SV_RejectMessage (info->protocol, "\nserver is full (%i of %i spectators)\n\n", spectators, maxspectators.ival); + Con_TPrintf ("%s:full connect (spectators)\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); } else if (!spectator && clients >= maxclients.ival) { - SV_RejectMessage (protocol, "\nserver is full (%i of %i players)\n\n", clients, maxclients.ival); - Con_TPrintf ("%s:full connect (players)\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + SV_RejectMessage (info->protocol, "\nserver is full (%i of %i players)\n\n", clients, maxclients.ival); + Con_TPrintf ("%s:full connect (players)\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); } else { - SV_RejectMessage (protocol, "\nserver is full (%i of %i connections)\n\n", clients+spectators, sv.allocated_client_slots); - Con_TPrintf ("%s:full connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + SV_RejectMessage (info->protocol, "\nserver is full (%i of %i connections)\n\n", clients+spectators, sv.allocated_client_slots); + Con_TPrintf ("%s:full connect\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); } } - return NULL; + return; } } @@ -3045,11 +2687,11 @@ client_t *SVC_DirectConnect(void) case GT_LUA: #endif case GT_PROGS: - if (protocol == SCP_QUAKE2) + if (info->protocol == SCP_QUAKE2) { - SV_RejectMessage(protocol, "This is a Quake server."); + SV_RejectMessage(info->protocol, "This is a Quake server."); Con_DPrintf ("* Rejected q2 client.\n"); - return NULL; + return; } if (svprogfuncs) @@ -3062,12 +2704,12 @@ client_t *SVC_DirectConnect(void) temp.edict = ent; { - const char *reject = SV_CheckRejectConnection(&adr, userinfo[0], protocol, protextsupported, protextsupported2, guid); + const char *reject = SV_CheckRejectConnection(&info->adr, info->userinfo, info->protocol, info->ftepext1, info->ftepext2, info->guid); if (reject) { - SV_RejectMessage(protocol, "%s", reject); + SV_RejectMessage(info->protocol, "%s", reject); Con_DPrintf ("* Game rejected a connection.\n"); - return NULL; + return; } } @@ -3075,28 +2717,28 @@ client_t *SVC_DirectConnect(void) #ifdef Q2SERVER case GT_QUAKE2: - if (protocol != SCP_QUAKE2) + if (info->protocol != SCP_QUAKE2) { - SV_RejectMessage(protocol, "This is a Quake2 server."); + SV_RejectMessage(info->protocol, "This is a Quake2 server."); Con_DPrintf ("* Rejected non-q2 client.\n"); - return NULL; + return; } q2ent = Q2EDICT_NUM(edictnum); temp.edict = NULL; temp.q2edict = q2ent; - if (!ge->ClientConnect(q2ent, userinfo[0])) + if (!ge->ClientConnect(q2ent, info->userinfo)) { - const char *reject = Info_ValueForKey(userinfo[0], "rejmsg"); + const char *reject = Info_ValueForKey(info->userinfo, "rejmsg"); if (*reject) - SV_RejectMessage(protocol, "%s\nConnection Refused.", reject); + SV_RejectMessage(info->protocol, "%s\nConnection Refused.", reject); else - SV_RejectMessage(protocol, "Connection Refused."); + SV_RejectMessage(info->protocol, "Connection Refused."); Con_DPrintf ("Game rejected a connection.\n"); - return NULL; + return; } - ge->ClientUserinfoChanged(q2ent, userinfo[0]); + ge->ClientUserinfoChanged(q2ent, info->userinfo); break; @@ -3114,16 +2756,16 @@ client_t *SVC_DirectConnect(void) temp.name = newcl->name; temp.team = newcl->team; - + InfoSync_Clear(&newcl->infosync); *newcl = temp; newcl->userinfo.ChangeCB = svs.info.ChangeCB; newcl->userinfo.ChangeCTX = &svs.clients[i].userinfo; - InfoBuf_FromString(&newcl->userinfo, userinfo[0], false); + InfoBuf_FromString(&newcl->userinfo, info->userinfo, false); // NET_AdrToStringResolve(&adr, SV_UserDNSResolved, NULL, newcl-svs.clients, newcl->userid); - newcl->challenge = challenge; + newcl->challenge = info->challenge; newcl->zquake_extensions = atoi(InfoBuf_ValueForKey(&newcl->userinfo, "*z_ext")); InfoBuf_SetStarKey(&newcl->userinfo, "*z_ext", ""); if (*InfoBuf_ValueForKey(&newcl->userinfo, "*fuhquake")) //fuhquake doesn't claim to support z_ext but does look at our z_ext serverinfo key. @@ -3143,43 +2785,44 @@ client_t *SVC_DirectConnect(void) if (pext_ezquake_nochunks.ival) { newcl->fteprotocolextensions &= ~PEXT_CHUNKEDDOWNLOADS; - Con_TPrintf("%s: ignoring ezquake chunked downloads extension.\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf("%s: ignoring ezquake chunked downloads extension.\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); } } if (newcl->zquake_extensions & (Z_EXT_PF_SOLID|Z_EXT_PF_ONGROUND)) { if (newcl->fteprotocolextensions & PEXT_HULLSIZE) - Con_TPrintf("%s: ignoring ezquake hullsize extension (conflicts with z_ext_pf_onground).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf("%s: ignoring ezquake hullsize extension (conflicts with z_ext_pf_onground).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); if (newcl->fteprotocolextensions & PEXT_SCALE) - Con_TPrintf("%s: ignoring ezquake scale extension (conflicts with z_ext_pf_solid).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf("%s: ignoring ezquake scale extension (conflicts with z_ext_pf_solid).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); if (newcl->fteprotocolextensions & PEXT_FATNESS) - Con_TPrintf("%s: ignoring ezquake fatness extension (conflicts with z_ext_pf_solid).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf("%s: ignoring ezquake fatness extension (conflicts with z_ext_pf_solid).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); if (newcl->fteprotocolextensions & PEXT_TRANS) - Con_TPrintf("%s: ignoring ezquake transparency extension (buggy on players, conflicts with z_ext_pf_solid).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr)); + Con_TPrintf("%s: ignoring ezquake transparency extension (buggy on players, conflicts with z_ext_pf_solid).\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr)); newcl->fteprotocolextensions &= ~(PEXT_HULLSIZE|PEXT_TRANS|PEXT_SCALE|PEXT_FATNESS); } } - Netchan_Setup (NS_SERVER, &newcl->netchan, &adr, qport); + Netchan_Setup (NS_SERVER, &newcl->netchan, &info->adr, info->qport); #ifdef HUFFNETWORK - if (huffcrc) - newcl->netchan.compresstable = Huff_CompressionCRC(huffcrc); + if (info->huffcrc) + newcl->netchan.compresstable = Huff_CompressionCRC(info->huffcrc); else #endif newcl->netchan.compresstable = NULL; - newcl->netchan.pext_fragmentation = mtu?true:false; + newcl->netchan.pext_fragmentation = info->mtu?true:false; //this is the upper bound of the mtu, if its too high we'll get EMSGSIZE and we'll reduce it. //however, if it drops below newcl->netchan.message.maxsize then we'll start to see undeliverable reliables, which means dropped clients. newcl->netchan.mtu = MAX_DATAGRAM; //vanilla qw clients are assumed to have an mtu of this size. - if (mtu >= 64) + if (info->mtu >= 64) { //if we support application fragmenting, then we can send massive reliables without too much issue - newcl->netchan.mtu = mtu; + newcl->netchan.mtu = info->mtu; newcl->netchan.message.maxsize = sizeof(newcl->netchan.message_buf); } - else //otherwise we can't fragment the packets, and the only way to honour the mtu is to send less data. yay for more round-trips. - { - mtu = atoi(Info_ValueForKey (userinfo[0], "mtu")); + else + { //otherwise we can't fragment the packets, and the only way to honour the mtu is to send less data. yay for more round-trips. + int mtu; + mtu = atoi(Info_ValueForKey (info->userinfo, "mtu")); if (mtu) newcl->netchan.mtu = mtu; //locked mtu size, because not everyone has a working connection (we need icmp would-fragment responses for mtu detection) else //if its not set then use some 'safe' fallback. @@ -3190,7 +2833,7 @@ client_t *SVC_DirectConnect(void) } Con_DLPrintf(2, "MTU size: %i - %i\n", newcl->netchan.message.maxsize, newcl->netchan.mtu); - newcl->protocol = protocol; + newcl->protocol = info->protocol; #ifdef NQPROT newcl->netchan.isnqprotocol = ISNQCLIENT(newcl); #endif @@ -3202,7 +2845,7 @@ client_t *SVC_DirectConnect(void) #endif newcl->datagram.allowoverflow = true; newcl->datagram.data = newcl->datagram_buf; - if (mtu >= 64) + if (info->mtu >= 64) newcl->datagram.maxsize = sizeof(newcl->datagram_buf); else newcl->datagram.maxsize = MAX_DATAGRAM; @@ -3237,9 +2880,9 @@ client_t *SVC_DirectConnect(void) { if (rank_needlogin.value) { - SV_RejectMessage (protocol, "Bad password/username\nThis server requires logins. Please see the serverinfo for website and info on how to register.\n"); + SV_RejectMessage (info->protocol, "Bad password/username\nThis server requires logins. Please see the serverinfo for website and info on how to register.\n"); newcl->state = cs_free; - return NULL; + return; } // SV_OutOfBandPrintf (isquake2client, adr, "\nWARNING: You have not got a place on the ranking system, probably because a user with the same name has already connected and your pwds differ.\n\n"); @@ -3252,12 +2895,12 @@ client_t *SVC_DirectConnect(void) rankstats_t rs; if (!Rank_GetPlayerStats(newcl->rankid, &rs)) { - SV_RejectMessage (protocol, "Rankings/Account system failed\n"); + SV_RejectMessage (info->protocol, "Rankings/Account system failed\n"); Con_TPrintf("banned player %s is trying to connect\n", newcl->name); newcl->name[0] = 0; InfoBuf_Clear(&newcl->userinfo, true); newcl->state = cs_free; - return NULL; + return; } if (rs.flags1 & RANK_MUTED) @@ -3299,13 +2942,13 @@ client_t *SVC_DirectConnect(void) else //measure this guy in minuites. s = va(langtext("Welcome back %s. You have previously spent %i mins connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/60)); - SV_OutOfBandPrintf (protocol == SCP_QUAKE2, &adr, s); + SV_OutOfBandPrintf (info->protocol == SCP_QUAKE2, &info->adr, s); } else if (!preserveparms) { SV_GetNewSpawnParms(newcl); - SV_OutOfBandTPrintf (protocol == SCP_QUAKE2, &adr, newcl->language, "Welcome %s. Your time on this server is being logged and ranked\n", newcl->name, (int)rs.timeonserver); + SV_OutOfBandTPrintf (info->protocol == SCP_QUAKE2, &info->adr, newcl->language, "Welcome %s. Your time on this server is being logged and ranked\n", newcl->name, (int)rs.timeonserver); } //else loaded players already have their initial parms set } @@ -3342,9 +2985,7 @@ client_t *SVC_DirectConnect(void) newcl->state = cs_connected; newcl->sendinfo = true; - if (redirect) - numssclients = 1; - else + if (!redirect) { for (i = 0; i < sizeof(sv_motd)/sizeof(sv_motd[0]); i++) { @@ -3371,17 +3012,7 @@ client_t *SVC_DirectConnect(void) //only advertise PEXT_SPLITSCREEN when splitscreen is allowed, to avoid spam. this might mean people need to reconnect after its enabled. oh well. if (!sv_allow_splitscreen.ival && newcl->netchan.remote_address.type != NA_LOOPBACK) - { newcl->fteprotocolextensions &= ~PEXT_SPLITSCREEN; - if (numssclients > 1) - SV_PrintToClient(newcl, PRINT_HIGH, "Splitscreen is disabled on this server\n"); - } - else - { - for (clients = 1; clients < numssclients; clients++) - SV_AddSplit(newcl, userinfo[clients], clients); - } - newcl->controller = NULL; #ifdef PEXT_CSQC @@ -3416,7 +3047,367 @@ client_t *SVC_DirectConnect(void) IPLog_Add(NET_AdrToString(adrbuf,sizeof(adrbuf), &newcl->netchan.remote_address), newcl->name); #endif - return newcl; +#ifdef NQPROT + newcl->netchan.incoming_reliable_sequence = info->expectedreliablesequence; +#endif +} + +/* +================== +SVC_DirectConnect + +A connection request that did not come from the master +================== +arguments must be tokenized first +Q3: connect "\key\val" +DP: connect\key\val +QW: connect $VER $QPORT $CHALLENGE "\key\val" +NQ: hacked to take the form of QW, but with protocol version 3. +UNSUPPORTED FTEQW/Splitscreen: connect2 $VER $QPORT $CHALLENGE "\key\val" "\key\val" +extension flags follow it. +*/ +void SVC_DirectConnect(int expectedreliablesequence) +{ + int version; +#ifdef HUFFNETWORK + extern cvar_t net_compress; +#endif + + svconnectinfo_t info; +#ifdef NQPROT + extern cvar_t sv_protocol_nq; + info.proquakeanglehack = false; + info.supportedprotocols = 0; + info.expectedreliablesequence = expectedreliablesequence; +#endif + + info.mtu = 0; + info.ftepext1 = 0; + info.ftepext2 = 0; + *info.guid = 0; + + if (*Cmd_Argv(1) == '\\') + { //q3: connect "\key\val" +#ifndef QWOVERQ3 + SV_RejectMessage (SCP_QUAKE3, "This is not a q3 server: %s\n", version_string()); + Con_TPrintf ("* rejected connect from q3 client\n"); + return; +#else + const char *s; + //this is used by q3 (note, we already decrypted the huffman connection packet in a hack) + if (!sv_listen_q3.ival) + { + SV_RejectMessage (SCP_QUAKE3, "Server is not accepting quake3 clients at this time: %s\n", version_string()); + Con_TPrintf ("* rejected connect from q3 client\n"); + return NULL; + } + numssclients = 1; + protocol = SCP_QUAKE3; + + Q_strncpyz (userinfo, Cmd_Argv(1), sizeof(userinfo)-1); + + switch (atoi(Info_ValueForKey(userinfo, "protocol"))) + { + case 68: //regular q3 1.32 + break; +// case 43: //q3 1.11 (most 'recent' demo) +// break; + default: + SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string()); + Con_TPrintf ("* rejected connect from incompatable client\n"); + return NULL; + } + + s = Info_ValueForKey(userinfo, "challenge"); + challenge = atoi(s); + + s = Info_ValueForKey(userinfo, "qport"); + qport = atoi(s); + + s = Info_ValueForKey(userinfo, "name"); + if (!*s) + Info_SetValueForKey(userinfo, "name", "UnnamedQ3", sizeof(userinfo)); + +#ifdef HUFFNETWORK + huffcrc = HUFFCRC_QUAKE3; +#endif +#endif + } +#ifdef NQPROT + else if (*(Cmd_Argv(0)+7) == '\\') + { //DP has the userinfo attached directly to the end of the connect command + const char *s; + if (!sv_listen_dp.value && net_from.type != NA_LOOPBACK) + { + if (!sv_listen_nq.value) + SV_RejectMessage (SCP_DARKPLACES6, "Server is not accepting darkplaces clients at this time.\n", version_string()); + Con_TPrintf ("* rejected connect from dp client\n"); + return; + } + if (progstype == PROG_H2) + { + if (!sv_listen_nq.value) + SV_RejectMessage (SCP_DARKPLACES6, "NQ protocols are not supported with hexen2 gamecode.\n", version_string()); + Con_TPrintf ("* rejected connect from dp client (because of hexen2)\n"); + return; + } + Q_strncpyz (info.userinfo, net_message.data + 11, sizeof(info.userinfo)-1); + + if (strcmp(Info_ValueForKey(info.userinfo, "protocol"), "darkplaces 3")) + { + SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string()); + Con_TPrintf ("* rejected connect from incompatible client\n"); + return; + } + //it's a darkplaces client. + + s = Info_ValueForKey(info.userinfo, "protocols"); + + while(s && *s) + { + static const struct + { + char *name; + unsigned int bits; + } dpnames[] = + { + {"FITZ", 1u<= 31 && version <= 34) + info.protocol = SCP_QUAKE2; +#ifdef NQPROT + else if (version == 3) + { + info.protocol = SCP_NETQUAKE; //because we can + switch(atoi(Info_ValueForKey(Cmd_Argv(4), "mod"))) + { + case 1: + info.proquakeanglehack = true; + break; + case PROTOCOL_VERSION_FITZ: + case PROTOCOL_VERSION_RMQ: + info.protocol = SCP_FITZ666; + break; + case PROTOCOL_VERSION_BJP3: + info.protocol = SCP_BJP3; + info.proquakeanglehack = true; + break; + } + } +#endif + else if (version == PROTOCOL_VERSION_QW) + info.protocol = SCP_QUAKEWORLD; + else + { + SV_RejectMessage (SCP_BAD, "Server is protocol version %i, received %i\n", PROTOCOL_VERSION_QW, version); + Con_TPrintf ("* rejected connect from version %i\n", version); + return; + } + + info.qport = atoi(Cmd_Argv(2)); + + info.challenge = atoi(Cmd_Argv(3)); + + // note an extra qbyte is needed to replace spectator key + Q_strncpyz (info.userinfo, Cmd_Argv(4), sizeof(info.userinfo)-1); + if (info.protocol == SCP_NETQUAKE) + Info_RemoveKey(info.userinfo, "mod"); //its served its purpose. + } + +#ifdef HAVE_DTLS + if (net_enable_dtls.ival > 2 && (net_from.prot == NP_DGRAM || net_from.prot == NP_STREAM || net_from.prot == NP_WS)) + { + SV_RejectMessage (info.protocol, "This server requires the use of DTLS/TLS/WSS.\n"); + return; + } +#endif + + { + char *banreason = SV_BannedReason(&net_from); + if (banreason) + { + if (*banreason) + SV_RejectMessage (info.protocol, "You were banned.\nReason: %s\n", banreason); + else + SV_RejectMessage (info.protocol, "You were banned.\n"); + return; + } + } + + if (info.protocol == SCP_QUAKEWORLD) //readd? + { + if (!sv_listen_qw.value && net_from.type != NA_LOOPBACK) + { + SV_RejectMessage (info.protocol, "QuakeWorld protocols are not permitted on this server.\n"); + Con_TPrintf ("* rejected connect from quakeworld\n"); + return; + } + } + + if (net_from.type == NA_LOOPBACK) //normal rules don't apply + ; + else + { + // see if the challenge is valid + if (!SV_ChallengePasses(info.challenge)) + { + if (sv_listen_dp.ival && !info.challenge && info.protocol == SCP_QUAKEWORLD) + { + //dp replies with 'challenge'. which vanilla quakeworld interprets as: c + //so just silence that error. + return; + } + SV_RejectMessage (info.protocol, "Bad challenge.\n"); + return; + } + } + + if (sv_banproxies.ival) + { + //FIXME: allow them to spectate but not join + if (*Info_ValueForKey(info.userinfo, "*qwfwd")) + { + SV_RejectMessage (info.protocol, "Proxies are not permitted on this server.\n"); + Con_TPrintf ("* rejected connect from qwfwd proxy\n"); + return; + } + if (*Info_ValueForKey(info.userinfo, "Qizmo")) + { + SV_RejectMessage (info.protocol, "Proxies are not permitted on this server.\n"); + Con_TPrintf ("* rejected connect from qizmo proxy\n"); + return; + } + if (*Info_ValueForKey(info.userinfo, "*qtv")) + { + SV_RejectMessage (info.protocol, "Proxies are not permitted on this server.\n"); + Con_TPrintf ("* rejected connect from qtv proxy (udp)\n"); + return; + } + } + + while(!msg_badread) + { + Cmd_TokenizeString(MSG_ReadStringLine(), false, false); + switch(Q_atoi(Cmd_Argv(0))) + { + case PROTOCOL_VERSION_FTE1: + if (info.protocol == SCP_QUAKEWORLD || info.protocol == SCP_QUAKE2) + { + info.ftepext1 = Q_atoi(Cmd_Argv(1)); + Con_DPrintf("Client supports 0x%x fte extensions\n", info.ftepext1); + } + break; + case PROTOCOL_VERSION_FTE2: + if (info.protocol == SCP_QUAKEWORLD) + { + info.ftepext2 = Q_atoi(Cmd_Argv(1)); + Con_DPrintf("Client supports 0x%x fte2 extensions\n", info.ftepext2); + } + break; + case PROTOCOL_VERSION_HUFFMAN: +#ifdef HUFFNETWORK + info.huffcrc = Q_atoi(Cmd_Argv(1)); + Con_DPrintf("Client supports huffman compression. crc 0x%x\n", info.huffcrc); + if (!net_compress.ival || !Huff_CompressionCRC(info.huffcrc)) + { + SV_RejectMessage (info.protocol, "Compression should not have been enabled.\n"); //buggy/exploiting client. can also happen from timing when changing the setting, but whatever + Con_TPrintf ("* rejected - bad compression state\n"); + return; + } +#endif + break; + case PROTOCOL_VERSION_FRAGMENT: + info.mtu = Q_atoi(Cmd_Argv(1)) & ~7; + if (info.mtu < 64) + info.mtu = 0; + Con_DPrintf("Client supports fragmentation. mtu %i.\n", info.mtu); + break; + case PROTOCOL_INFO_GUID: + Q_strncpyz(info.guid, Cmd_Argv(1), sizeof(info.guid)); + Con_DPrintf("GUID %s\n", Cmd_Argv(1)); + break; + } + } + msg_badread=false; + + if (!info.guid) + NET_GetConnectionCertificate(svs.sockets, &net_from, QCERT_PEERFINGERPRINT, info.guid, sizeof(info.guid)); + + info.adr = net_from; + if (MSV_ClusterLogin(&info)) + return; + + SV_DoDirectConnect(&info); } static int dehex(int i) @@ -3855,7 +3846,7 @@ qboolean SV_ConnectionlessPacket (void) } else { - SVC_DirectConnect (); + SVC_DirectConnect (0); return true; } } @@ -4003,7 +3994,6 @@ qboolean SVNQ_ConnectionlessPacket(void) numnonnops++; if (msg_readcount+17 <= net_message.cursize && !strncmp("challengeconnect ", &net_message.data[msg_readcount], 17)) { - client_t *newcl; if (sv_showconnectionlessmessages.ival) Con_Printf("CCREQ_CONNECT_COOKIE\n"); Cmd_TokenizeString(MSG_ReadStringLine(), false, false); @@ -4011,9 +4001,7 @@ qboolean SVNQ_ConnectionlessPacket(void) str = va("connect %i %i %s \"\\name\\unconnected\\mod\\%s\\modver\\%s\\flags\\%s\\password\\%s\"", NQ_NETCHAN_VERSION, 0, Cmd_Argv(1), Cmd_Argv(2), Cmd_Argv(3), Cmd_Argv(4), Cmd_Argv(5)); Cmd_TokenizeString (str, false, false); - newcl = SVC_DirectConnect(); - if (newcl) - newcl->netchan.incoming_reliable_sequence = sequence; + SVC_DirectConnect(sequence); /*if there is anything else in the packet, we don't actually care. its reliable, so they'll resend*/ return true; @@ -4164,7 +4152,7 @@ qboolean SVNQ_ConnectionlessPacket(void) str = va("connect %i %i %i \"\\name\\unconnected\\mod\\%i\\modver\\%i\\flags\\%i\\password\\%i\"", NQ_NETCHAN_VERSION, 0, SV_NewChallenge(), mod, modver, flags, passwd); Cmd_TokenizeString (str, false, false); - SVC_DirectConnect(); + SVC_DirectConnect(0); } } return true; @@ -5044,15 +5032,16 @@ float SV_Frame (void) MSV_PollSlaves(); #endif +#ifdef SQL + SQL_ServerCycle(); +#endif + if (sv.state < ss_active || !sv.world.worldmodel) { #ifdef SUBSERVERS if (sv.state == ss_clustermode) { isidle = !SV_ReadPackets (&delay); -#ifdef SQL - PR_SQLCycle(); -#endif SV_SendClientMessages (); } #endif @@ -5138,10 +5127,6 @@ float SV_Frame (void) //this is the q2 frame number found in the q2 protocol. each packet should contain a new frame or interpolation gets confused sv.framenum++; -#ifdef SQL - PR_SQLCycle(); -#endif - #ifdef SERVER_DEMO_PLAYBACK while(SV_ReadMVD()); #endif diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 9d6a66e2..9ce3291c 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -781,7 +781,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int mask = NULL; else { - cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); + cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL); if (cluster >= 0) mask = sv.world.worldmodel->phs + cluster*sv.world.worldmodel->pvsbytes; else @@ -792,7 +792,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int case MULTICAST_PVS_R: reliable = true; // intentional fallthrough case MULTICAST_PVS: - cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); + cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL); if (cluster >= 0) mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST); else @@ -877,7 +877,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int { vec3_t pos; VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos); - cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos); + cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos, NULL); if (cluster>= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) ) { // Con_Printf ("PVS supressed multicast\n"); @@ -1042,7 +1042,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, const char *reliableinfokey, mask = NULL; else { - cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); + cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL); if (cluster >= 0) mask = sv.world.worldmodel->phs + cluster * sv.world.worldmodel->pvsbytes; else @@ -1053,7 +1053,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, const char *reliableinfokey, case MULTICAST_PVS_R: reliable = true; // intentional fallthrough case MULTICAST_PVS: - cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); + cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin, NULL); if (cluster >= 0) mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST); else @@ -1127,7 +1127,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, const char *reliableinfokey, { vec3_t pos; VectorAdd(split->edict->v->origin, split->edict->v->view_ofs, pos); - cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos); + cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos, NULL); if (cluster>= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) ) { // Con_Printf ("PVS supressed multicast\n"); diff --git a/engine/server/sv_sql.c b/engine/server/sv_sql.c index a62b3d96..c1a60648 100644 --- a/engine/server/sv_sql.c +++ b/engine/server/sv_sql.c @@ -166,10 +166,14 @@ queryrequest_t *SQL_PullRequest(sqlserver_t *server, qboolean lock) return qreq; } -sqlserver_t **sqlservers; -int sqlservercount; -int sqlavailable; -int sqlinited; +struct +{ + void *owner; + sqlserver_t *handle; +} *sqlservers; +static int sqlservercount; +static int sqlavailable; +static int sqlinited; #ifdef USE_SQLITE //this is to try to sandbox sqlite so it can only edit the file its originally opened with. @@ -506,15 +510,17 @@ int sql_serverworker(void *sref) return 0; } -sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives) +sqlserver_t *SQL_GetServer (void *owner, int serveridx, qboolean inactives) { if (serveridx < 0 || serveridx >= sqlservercount) return NULL; - if (!sqlservers[serveridx]) + if (owner && sqlservers[serveridx].owner != owner) return NULL; - if (!inactives && sqlservers[serveridx]->active == false) + if (!sqlservers[serveridx].handle) return NULL; - return sqlservers[serveridx]; + if (!inactives && sqlservers[serveridx].handle->active == false) + return NULL; + return sqlservers[serveridx].handle; } queryrequest_t *SQL_GetQueryRequest (sqlserver_t *server, int queryidx) @@ -801,7 +807,7 @@ void SQL_CleanupServer(sqlserver_t *server) Z_Free(server); } -int SQL_NewServer(const char *driver, const char **paramstr) +int SQL_NewServer(void *owner, const char *driver, const char **paramstr) { sqlserver_t *server; int serverref; @@ -851,13 +857,13 @@ int SQL_NewServer(const char *driver, const char **paramstr) { serverref = 0; sqlservercount = 1; - sqlservers = (sqlserver_t **)BZ_Malloc(sizeof(sqlserver_t *)); + sqlservers = BZ_Malloc(sizeof(*sqlservers)); } else { serverref = sqlservercount; sqlservercount++; - sqlservers = (sqlserver_t **)BZ_Realloc(sqlservers, sizeof(sqlserver_t *) * sqlservercount); + sqlservers = BZ_Realloc(sqlservers, sizeof(*sqlservers) * sqlservercount); } // assemble server structure @@ -883,7 +889,8 @@ int SQL_NewServer(const char *driver, const char **paramstr) // string should be null-terminated due to Z_Malloc } - sqlservers[serverref] = server; + sqlservers[serverref].owner = owner; + sqlservers[serverref].handle = server; server->driver = (sqldrv_t)drvchoice; server->querynum = 1; @@ -944,11 +951,13 @@ int SQL_NewQuery(sqlserver_t *server, qboolean (*callback)(queryrequest_t *req, SQL_PushRequest(server, qreq); Sys_ConditionSignal(server->requestcondv); - *reqout = qreq; + if (reqout) + *reqout = qreq; return querynum; } - *reqout = NULL; + if (reqout) + *reqout = NULL; return -1; } @@ -1079,7 +1088,7 @@ void SQL_Status_f(void) queryrequest_t *qreq; queryresult_t *qres; - sqlserver_t *server = sqlservers[i]; + sqlserver_t *server = sqlservers[i].handle; if (!server) continue; @@ -1168,7 +1177,7 @@ void SQL_Kill_f (void) return; } - server = SQL_GetServer(atoi(Cmd_Argv(1)), false); + server = SQL_GetServer(NULL, atoi(Cmd_Argv(1)), false); if (server) { server->active = false; @@ -1179,7 +1188,7 @@ void SQL_Kill_f (void) void SQL_Killall_f (void) { - SQL_KillServers(); + SQL_KillServers(NULL); } void SQL_ServerCycle (void) @@ -1188,7 +1197,7 @@ void SQL_ServerCycle (void) for (i = 0; i < sqlservercount; i++) { - sqlserver_t *server = sqlservers[i]; + sqlserver_t *server = sqlservers[i].handle; queryresult_t *qres; queryrequest_t *qreq; @@ -1244,7 +1253,7 @@ void SQL_ServerCycle (void) if (server->terminated) { - sqlservers[i] = NULL; + sqlservers[i].handle = NULL; SQL_CleanupServer(server); continue; } @@ -1294,28 +1303,36 @@ void SQL_Init(void) Cvar_Register(&sql_defaultdb, SQLCVAROPTIONS); } -void SQL_KillServers(void) +void SQL_KillServers(void *owner) { int i; - for (i = 0; i < sqlservercount; i++) + for (i = sqlservercount; i-- > 0; ) { - sqlserver_t *server = sqlservers[i]; - sqlservers[i] = NULL; - if (!server) - continue; - SQL_CleanupServer(server); + if (!owner || sqlservers[i].owner == owner) + { + sqlserver_t *server = sqlservers[i].handle; + sqlservers[i].handle = NULL; + sqlservers[i].owner = NULL; + if (server) + SQL_CleanupServer(server); + + if (sqlservercount == i+1) + sqlservercount--; + } + } + if (!sqlservercount) + { + if (sqlservers) + Z_Free(sqlservers); + sqlservers = NULL; } - if (sqlservers) - Z_Free(sqlservers); - sqlservers = NULL; - sqlservercount = 0; } void SQL_DeInit(void) { sqlavailable = 0; - SQL_KillServers(); + SQL_KillServers(NULL); sqlinited = false; #ifdef USE_MYSQL diff --git a/engine/server/sv_sql.h b/engine/server/sv_sql.h index 182bce17..b05f147b 100644 --- a/engine/server/sv_sql.h +++ b/engine/server/sv_sql.h @@ -95,10 +95,10 @@ typedef struct sqlserver_s /* prototypes */ void SQL_Init(void); -void SQL_KillServers(void); +void SQL_KillServers(void *owner); void SQL_DeInit(void); -sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives); +sqlserver_t *SQL_GetServer (void *owner, int serveridx, qboolean inactives); queryrequest_t *SQL_GetQueryRequest (sqlserver_t *server, int queryidx); queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx, int row); //void SQL_DeallocResult(sqlserver_t *server, queryresult_t *qres); @@ -107,7 +107,7 @@ void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres); void SQL_CloseRequest(sqlserver_t *server, queryrequest_t *qres, qboolean force); void SQL_CloseAllResults(sqlserver_t *server); char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields, size_t *resultsize); -int SQL_NewServer(const char *driver, const char **paramstr); +int SQL_NewServer(void *owner, const char *driver, const char **paramstr); int SQL_NewQuery(sqlserver_t *server, qboolean (*callback)(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof), const char *str, queryrequest_t **reqout); //callback will be called on the main thread once the result is back void SQL_Disconnect(sqlserver_t *server); void SQL_Escape(sqlserver_t *server, const char *src, char *dst, int dstlen); diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 74229cc2..2c8ffd03 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -723,14 +723,6 @@ static qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_ maxs1[0] >= mins2[0] && maxs1[1] >= mins2[1] && maxs1[2] >= mins2[2]); } -typedef struct { - int serverTime; - int angles[3]; - int buttons; - qbyte weapon; // weapon - signed char forwardmove, rightmove, upmove; -} q3usercmd_t; -#define CMD_MASK Q3UPDATE_MASK static qboolean SVQ3_GetUserCmd(int clientnumber, q3usercmd_t *ucmd) { usercmd_t *cmd; @@ -768,7 +760,7 @@ void SVQ3_SendServerCommand(client_t *cl, char *str) } cl->server_command_sequence++; - Q_strncpyz(cl->server_commands[cl->server_command_sequence & TEXTCMD_MASK], str, sizeof(cl->server_commands[0])); + Q_strncpyz(cl->server_commands[cl->server_command_sequence & Q3TEXTCMD_MASK], str, sizeof(cl->server_commands[0])); } void SVQ3_SendConfigString(client_t *dest, int num, char *string) @@ -839,7 +831,7 @@ static int SVQ3_BotGetConsoleMessage( int client, char *buf, int size ) return false; cl->server_command_ack++; - index = cl->server_command_ack & TEXTCMD_MASK; + index = cl->server_command_ack & Q3TEXTCMD_MASK; if ( !cl->server_commands[index][0] ) return false; @@ -861,11 +853,55 @@ static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open) CMQ3_SetAreaPortalState(sv.world.worldmodel, se->areanum, se->areanum2, open); } +static qboolean SV_InPVS(vec3_t p1, vec3_t p2) +{ + model_t *worldmodel = sv.world.worldmodel; + + if (!worldmodel || worldmodel->loadstate != MLS_LOADED) + return false; //still loading, don't give bad results. + else if (!worldmodel->funcs.FatPVS) + return true; //no pvs info, assume everything is visible + else + { +#if 1 + int l1 = CM_PointLeafnum(worldmodel, p1); + int l2 = CM_PointLeafnum(worldmodel, p2); + int c1 = CM_LeafCluster(worldmodel, l1); + int c2 = CM_LeafCluster(worldmodel, l2); + qbyte *pvs; + if (c1 < 0 || c2 < 0) + return (c1<0); //outside can see in, inside cannot (normally) see out. + pvs = CM_ClusterPVS(worldmodel, c1, NULL, PVM_FAST); + if (pvs[c2>>3] & (1<<(c2&7))) + { + int a1 = CM_LeafArea(worldmodel, l1); + int a2 = CM_LeafArea(worldmodel, l2); + if (CM_AreasConnected(worldmodel, a1, a2)) + return true; + } + return false; +#else + const qbyte *mask; + int c1 = worldmodel->funcs.ClusterForPoint(worldmodel, p1); + int c2 = worldmodel->funcs.ClusterForPoint(worldmodel, p2); + if (c1 < 0 || c2 < 0) + return true; //one is outside of the world, so can see inside. + mask = worldmodel->funcs.ClusterPVS(worldmodel, c1, NULL, PVM_FAST); + if (mask[c2>>3] & (1<<(c2&7))) + { + //FIXME: check areas/portals too + return true; //visible + } + return false; //nope. :( +#endif + } +} + #define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, const qintptr_t *arg) { int ret = 0; - switch(fn) + switch((q3ggameImport_t)fn) { case G_PRINT: // ( const char *string ); Con_Printf("%s", (char*)VM_POINTER(arg[0])); @@ -946,16 +982,17 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co case G_FS_FOPEN_FILE: //fopen if ((int)arg[1] + 4 >= mask || VM_POINTER(arg[1]) < offset) break; //out of bounds. - VM_LONG(ret) = VM_fopen(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), 0); + ret = VM_fopen(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2]), 0); break; case G_FS_READ: //fread if ((int)arg[0] + VM_LONG(arg[1]) >= mask || VM_POINTER(arg[0]) < offset) break; //out of bounds. - VM_FRead(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), 0); + ret = VM_FRead(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), 0); break; case G_FS_WRITE: //fwrite + ret = VM_FWrite(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), 0); break; case G_FS_FCLOSE_FILE: //fclose VM_fclose(VM_LONG(arg[0]), 0); @@ -1081,8 +1118,8 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co return !!mapentspointer; case G_REAL_TIME: // 41 - VM_FLOAT(ret) = realtime; - return ret; + VALIDATEPOINTER(arg[0], sizeof(q3time_t)); + return Q3VM_GetRealtime(VM_POINTER(arg[0])); case G_SNAPVECTOR: { float *fp = (float *)VM_POINTER( arg[0] ); @@ -1566,9 +1603,30 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co #endif + case G_IN_PVS: + return SV_InPVS(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + case G_AREAS_CONNECTED: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_AREAS_CONNECTED"); return ret; + case G_DEBUG_POLYGON_CREATE: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_DEBUG_POLYGON_CREATE"); return ret; + case G_DEBUG_POLYGON_DELETE: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_DEBUG_POLYGON_DELETE"); return ret; + case G_IN_PVS_IGNORE_PORTALS: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_IN_PVS_IGNORE_PORTALS"); return ret; + case G_MATRIXMULTIPLY: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_MATRIXMULTIPLY"); return ret; + case G_ANGLEVECTORS: + VALIDATEPOINTER(arg[1], sizeof(vec3_t)); + VALIDATEPOINTER(arg[2], sizeof(vec3_t)); + VALIDATEPOINTER(arg[3], sizeof(vec3_t)); + AngleVectors(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_POINTER(arg[3])); + break; + case G_PERPENDICULARVECTOR: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_PERPENDICULARVECTOR"); return ret; + VALIDATEPOINTER(arg[1], sizeof(vec3_t)); + PerpendicularVector(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + break; + case G_FS_SEEK: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_FS_SEEK"); return ret; + return VM_FSeek(arg[0], arg[1], arg[2], 0); + + //case G_DEFAULTCASEWARNINGDISABLE: NOT A REAL VALUE // notimplemented: default: - Con_Printf("builtin %i is not implemented\n", (int)fn); + Con_Printf("Q3Game: builtin %i is not known\n", (int)fn); } return ret; } @@ -2709,7 +2767,7 @@ static void SVQ3_WriteServerCommandsToClient(client_t *client, sizebuf_t *msg) { MSG_WriteBits(msg, svcq3_serverCommand, 8); MSG_WriteBits(msg, i, 32); - str = client->server_commands[i & TEXTCMD_MASK]; + str = client->server_commands[i & Q3TEXTCMD_MASK]; len = strlen(str); for (j = 0; j <= len; j++) MSG_WriteBits(msg, str[j], 8); @@ -2905,7 +2963,7 @@ static qboolean SVQ3_Netchan_Process(client_t *client) // calculate bitmask bitmask = (serverid ^ lastSequence ^ client->challenge) & 0xff; - string = client->server_commands[lastServerCommandNum & TEXTCMD_MASK]; + string = client->server_commands[lastServerCommandNum & Q3TEXTCMD_MASK]; #ifndef Q3_NOENCRYPT // decrypt the packet @@ -3003,7 +3061,7 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta) return; // was dropped // calculate key for usercmd decryption - string = client->server_commands[client->server_command_ack & TEXTCMD_MASK]; + string = client->server_commands[client->server_command_ack & Q3TEXTCMD_MASK]; key = client->last_sequence ^ fs_key ^ StringKey(string, 32); // read delta sequenced usercmds @@ -3219,8 +3277,8 @@ void SVQ3_ParseClientMessage(client_t *client) // read last server command number client received client->server_command_ack = MSG_ReadBits(32); - if( client->server_command_ack <= client->server_command_sequence - TEXTCMD_BACKUP ) - client->server_command_ack = client->server_command_sequence - TEXTCMD_BACKUP + 1; //too old + if( client->server_command_ack <= client->server_command_sequence - Q3TEXTCMD_BACKUP ) + client->server_command_ack = client->server_command_sequence - Q3TEXTCMD_BACKUP + 1; //too old else if( client->server_command_ack > client->server_command_sequence ) client->server_command_ack = client->server_command_sequence; //client is from the future? o.O make fatal? @@ -3341,8 +3399,11 @@ void SVQ3_NewMapConnects(void) if (svs.clients[i].state < cs_connected) continue; - ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD); - if (ret || (gametype->value == 2 && svs.clients[i].protocol == SCP_BAD)) + if (gametype->value == 2 && svs.clients[i].protocol == SCP_BAD) + ret = true; + else + ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD); + if (ret) { SV_DropClient(&svs.clients[i]); } @@ -3461,6 +3522,7 @@ int SVQ3_AddBot(void) cl->state = cs_spawned; memset(&cl->netchan.remote_address, 0, sizeof(cl->netchan.remote_address)); + GENTITY_FOR_NUM(cl-svs.clients)->s.number = cl-svs.clients; return cl - svs.clients; } diff --git a/engine/server/world.c b/engine/server/world.c index 029cdbf0..82662e40 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -138,7 +138,7 @@ qboolean World_BoxTrace(struct model_s *model, int hulloverride, int frame, vec3 VectorCopy (p2, trace->endpos); return Q1BSP_RecursiveHullCheck (hull, hull->firstclipnode, p1, p2, against, trace); } -qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) +qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p1, const vec3_t p2, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int against, struct trace_s *trace) { //bbox vs capsule (NYI) //capsule vs capsule (NYI) @@ -196,7 +196,7 @@ qboolean World_CapsuleTrace(struct model_s *model, int hulloverride, framestate_ } return false; } -model_t *World_CapsuleForBox(vec3_t mins, vec3_t maxs) +model_t *World_CapsuleForBox(const vec3_t mins, const vec3_t maxs) { VectorCopy(mins, mod_capsule.mins); VectorCopy(maxs, mod_capsule.maxs); @@ -1068,7 +1068,7 @@ void WorldQ2_Q1BSP_LinkEdict(world_t *w, q2edict_t *ent) #if defined(Q2BSPS) || defined(Q3BSPS) -void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, float *mins, float *maxs) +void Q23BSP_FindTouchedLeafs(model_t *model, struct pvscache_s *ent, const float *mins, const float *maxs) { #define MAX_TOTAL_ENT_LEAFS 128 int leafs[MAX_TOTAL_ENT_LEAFS]; @@ -1536,7 +1536,7 @@ int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list, int #endif #ifdef Q2SERVER -float *area_mins, *area_maxs; +const float *area_mins, *area_maxs; q2edict_t **area_q2list; int area_count, area_maxcount; int area_type; @@ -1598,7 +1598,7 @@ static void WorldQ2_AreaEdicts_r (areanode_t *node) WorldQ2_AreaEdicts_r ( node->children[1] ); } -int VARGS WorldQ2_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, q2edict_t **list, +int VARGS WorldQ2_AreaEdicts (world_t *w, const vec3_t mins, const vec3_t maxs, q2edict_t **list, int maxcount, int areatype) { area_mins = mins; diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 66e78528..c237b54a 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -5478,7 +5478,7 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist d += 0.1; //an epsilon on the far side VectorMA(point, d, plane.normal, point); - clust = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, point); + clust = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, point, NULL); if (i == batch->firstmesh) r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, &newvis, PVM_REPLACE); else @@ -5790,10 +5790,10 @@ void VKBE_SubmitMeshes (batch_t **worldbatches, batch_t **blist, int first, int #ifdef RTLIGHTS //FIXME: needs context for threading -void VKBE_BaseEntTextures(qbyte *scenepvs) +void VKBE_BaseEntTextures(const qbyte *scenepvs, const int *sceneareas) { batch_t *batches[SHADER_SORT_COUNT]; - BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode, scenepvs); + BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode, scenepvs, sceneareas); VKBE_SubmitMeshes(NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_SEETHROUGH+1); VKBE_SelectEntity(&r_worldentity); } @@ -6245,7 +6245,7 @@ void VKBE_DrawWorld (batch_t **worldbatches) shaderstate.curdlight = NULL; //fixme: figure out some way to safely orphan this data so that we can throw the rest to a worker. - BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD, r_refdef.scenevis); + BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD, r_refdef.scenevis, r_refdef.sceneareas); BE_UploadLightmaps(false); if (r_refdef.scenevis) diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 888b071b..6634e6e4 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -465,7 +465,7 @@ void VKBE_VBO_Data(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray); void VKBE_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray, void **vbomem, void **ebomem); void VKBE_VBO_Destroy(vboarray_t *vearray, void *mem); void VKBE_Scissor(srect_t *rect); -void VKBE_BaseEntTextures(qbyte *scenepvs); +void VKBE_BaseEntTextures(const qbyte *scenepvs, const int *sceneareas); struct vk_shadowbuffer; struct vk_shadowbuffer *VKBE_GenerateShadowBuffer(vecV_t *verts, int numverts, index_t *indicies, int numindicies, qboolean istemp);