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);