diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 541ff9d9..780c2115 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -520,7 +520,7 @@ static float vlen(vec3_t v) // returns true if weapon model should be drawn in camera mode qboolean Cam_DrawViewModel(playerview_t *pv) { - if (cl.spectator) + if (pv->spectator) { if (pv->cam_state == CAM_EYECAM && cl_chasecam.ival) return true; @@ -536,7 +536,7 @@ qboolean Cam_DrawViewModel(playerview_t *pv) int Cam_TrackNum(playerview_t *pv) { - if (cl.spectator && pv->cam_state == CAM_EYECAM) + if (pv->spectator && pv->cam_state == CAM_EYECAM) return pv->cam_spec_track; return -1; } @@ -822,7 +822,7 @@ void Cam_Track(playerview_t *pv, usercmd_t *cmd) vec3_t vec; float len; - if (!cl.spectator || !cl.worldmodel) //can happen when the server changes level + if (!pv->spectator || !cl.worldmodel) //can happen when the server changes level return; if (autotrackmode != TM_USER && pv->cam_state == CAM_FREECAM) @@ -976,7 +976,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd) if (cls.state != ca_active) return; - if (!cl.spectator && (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)) // only in spectator mode + if (!pv->spectator && (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)) // only in spectator mode return; if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) @@ -1197,7 +1197,7 @@ void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg) return; } - if (!cl.spectator) + if (!pv->spectator) { Con_Printf("Not spectating.\n"); return; diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 90d80ecc..4c151739 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1159,7 +1159,7 @@ static void CLQW_RecordServerData(sizebuf_t *buf) if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS) { MSG_WriteByte (buf, cl.allocated_client_slots); - MSG_WriteByte (buf, cl.splitclients | (cl.spectator?128:0)); + MSG_WriteByte (buf, cl.splitclients); for (i = 0; i < cl.splitclients; i++) MSG_WriteByte (buf, cl.playerview[i].playernum); } @@ -1167,7 +1167,7 @@ static void CLQW_RecordServerData(sizebuf_t *buf) { for (i = 0; i < cl.splitclients; i++) { - if (cl.spectator) + if (cl.playerview[i].spectator) MSG_WriteByte (buf, cl.playerview[i].playernum | 128); else MSG_WriteByte (buf, cl.playerview[i].playernum); @@ -1544,7 +1544,7 @@ void CL_Record_f (void) } else { //automagically generate a name - if (cl.spectator) + if (cl.playerview[0].spectator) { // FIXME: if tracking a player, use his name fname = va ("spec_%s_%s", TP_PlayerName(), diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 0976cbe3..b0f7ec1c 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -1658,7 +1658,8 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o( } else { -// Con_Printf("Update %i\n", read); + if (cl_shownet.ival > 3) + Con_Printf("Update %i\n", read); DP5_ParseDelta(to, newpack); to->sequence = cls.netchan.incoming_sequence; to->inactiveflag = 0; @@ -3780,6 +3781,7 @@ void CL_LinkPacketEntities (void) le = &cl.lerpents[timer->entnum]; if (le->sequence != cl.lerpentssequence) continue; +// VectorCopy(le->origin, timer->origin); } R_AddItemTimer(timer->origin, cl.time*90 + timer->origin[0] + timer->origin[1] + timer->origin[2], timer->radius, (cl.time - timer->start) / timer->duration, timer->rgb); } @@ -4716,7 +4718,7 @@ guess_pm_type: for (i = 0; i < cl.splitclients; i++) { playerview_t *pv = &cl.playerview[i]; - if ((cl.spectator?pv->cam_spec_track:pv->playernum) == num) + if ((pv->spectator?pv->cam_spec_track:pv->playernum) == num) { pv->stats[STAT_WEAPONFRAME] = state->weaponframe; pv->statsf[STAT_WEAPONFRAME] = state->weaponframe; @@ -5290,7 +5292,7 @@ void CL_LinkViewModel(void) ent.flags |= RF_WEAPONMODEL|RF_DEPTHHACK|RF_NOSHADOW; plnum = -1; - if (cl.spectator) + if (pv->spectator) plnum = Cam_TrackNum(pv); if (plnum == -1) plnum = r_refdef.playerview->playernum; @@ -5520,13 +5522,6 @@ void CL_SetUpPlayerPrediction(qboolean dopred) CL_PredictUsercmd (0, j+1, state, &exact, &state->command); VectorCopy (exact.origin, pplayer->origin); } - - if (cl.spectator) - { -// if (!Cam_DrawPlayer(0, j)) -// VectorCopy(pplayer->origin, cl.simorg[0]); - - } } } } diff --git a/engine/client/cl_ignore.c b/engine/client/cl_ignore.c index f92f9f0b..d87548fc 100644 --- a/engine/client/cl_ignore.c +++ b/engine/client/cl_ignore.c @@ -120,6 +120,7 @@ static void Display_Ignorelist(void) int i; int x; qboolean foundone; + playerview_t *pv = &cl.playerview[0]; x = 0; foundone = false; @@ -172,7 +173,7 @@ static void Display_Ignorelist(void) if (ignore_opponents.ival) Con_Printf("\x02" "Opponents are Ignored\n"); - if (ignore_spec.ival == 2 || (ignore_spec.ival == 1 && !cl.spectator)) + if (ignore_spec.ival == 2 || (ignore_spec.ival == 1 && !pv->spectator)) Con_Printf ("\x02" "Spectators are Ignored\n"); if (ignore_qizmo_spec.ival) @@ -573,7 +574,8 @@ void Ignore_Flood_Add(player_info_t *sender, const char *s) qboolean Ignore_Message(const char *sendername, const char *s, int flags) { - int slot, i; + int slot, i; + playerview_t *pv = &cl.playerview[0]; if (!ignore_mode.ival && (flags & 2)) return false; @@ -581,7 +583,7 @@ qboolean Ignore_Message(const char *sendername, const char *s, int flags) if (ignore_spec.ival == 2 && (flags == 4 || (flags == 8 && ignore_mode.ival))) return true; - else if (ignore_spec.ival == 1 && (flags == 4) && !cl.spectator) + else if (ignore_spec.ival == 1 && (flags == 4) && !pv->spectator) return true; if (!sendername) @@ -595,10 +597,10 @@ qboolean Ignore_Message(const char *sendername, const char *s, int flags) if (ignore_opponents.ival && ( (int) ignore_opponents.ival == 1 || - (cls.state >= ca_connected && /*!cl.standby &&*/ !cls.demoplayback && !cl.spectator) // match? + (cls.state >= ca_connected && /*!cl.standby &&*/ !cls.demoplayback && !pv->spectator) // match? ) && - flags == 1 && !cl.spectator && slot != cl.playerview[0].playernum && - (!cl.teamplay || strcmp(cl.players[slot].team, cl.players[cl.playerview[0].playernum].team)) + flags == 1 && !pv->spectator && slot != pv->playernum && + (!cl.teamplay || strcmp(cl.players[slot].team, cl.players[pv->playernum].team)) ) { return true; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 631139a3..35a70b19 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -273,7 +273,7 @@ void IN_JumpDown (void) int pnum = CL_TargettedSplit(false); - + playerview_t *pv = &cl.playerview[pnum]; condition = (cls.state == ca_active && cl_smartjump.ival && !prox_inmenu.ival); @@ -283,14 +283,14 @@ void IN_JumpDown (void) else #endif #ifdef QUAKESTATS - if (condition && cl.playerview[pnum].stats[STAT_HEALTH] > 0 && !cls.demoplayback && !cl.spectator && - (cls.protocol==CP_NETQUAKE || cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playerview[pnum].playernum].messagenum == cl.validsequence) + if (condition && cl.playerview[pnum].stats[STAT_HEALTH] > 0 && !cls.demoplayback && !pv->spectator && + (cls.protocol==CP_NETQUAKE || cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[pv->playernum].messagenum == cl.validsequence) && cl.playerview[pnum].waterlevel >= 2 && (!cl.teamfortress || !(in_forward.state[pnum] & 1)) ) KeyDown(&in_up); else #endif - if (condition && cl.spectator && cl.playerview[pnum].cam_state == CAM_FREECAM) + if (condition && pv->spectator && pv->cam_state == CAM_FREECAM) KeyDown(&in_up); else KeyDown(&in_jump); @@ -1404,6 +1404,7 @@ void CL_UpdateSeats(void) targ = MAX_SPLITS; if (cl.splitclients < targ) { + char *ver; char buffer[2048]; char newinfo[2048]; Q_strncpyz(newinfo, cls.userinfo[cl.splitclients], sizeof(newinfo)); @@ -1423,6 +1424,14 @@ void CL_UpdateSeats(void) if (!*Info_ValueForKey(newinfo, "skin")) //give players the same skin by default, because we can. q2 cares for teams. qw might as well (its not like anyone actually uses them thanks to enemy-skin forcing). Info_SetValueForKey(newinfo, "skin", Info_ValueForKey(cls.userinfo[0], "skin"), sizeof(newinfo)); +#ifdef SVNREVISION + if (strcmp(STRINGIFY(SVNREVISION), "-")) + ver = va("%s v%i.%02i %s", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR, STRINGIFY(SVNREVISION)); + else +#endif + ver = va("%s v%i.%02i", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR); + Info_SetValueForKey(newinfo, "*ver", ver, sizeof(newinfo)); + CL_SendClientCommand(true, "addseat %i %s", cl.splitclients, COM_QuotedString(newinfo, buffer, sizeof(buffer), false)); } else if (cl.splitclients > targ) @@ -1736,6 +1745,7 @@ void CL_SendCmd (double frametime, qboolean mainloop) } for (plnum = 0; plnum < cl.splitclients; plnum++) { + playerview_t *pv = &cl.playerview[plnum]; cmd = &cl.outframes[i].cmd[plnum]; memset(cmd, 0, sizeof(*cmd)); @@ -1758,12 +1768,12 @@ void CL_SendCmd (double frametime, qboolean mainloop) VectorClear(mousemovements[plnum]); // if we are spectator, try autocam - if (cl.spectator) - Cam_Track(&cl.playerview[plnum], cmd); + if (pv->spectator) + Cam_Track(pv, cmd); CL_FinishMove(cmd, cmd->msec, plnum); - Cam_FinishMove(&cl.playerview[plnum], cmd); + Cam_FinishMove(pv, cmd); #ifdef CSQC_DAT CSQC_Input_Frame(plnum, cmd); @@ -1772,7 +1782,6 @@ void CL_SendCmd (double frametime, qboolean mainloop) if (cls.state == ca_active) { player_state_t *from, *to; - playerview_t *pv = &cl.playerview[plnum]; from = &cl.inframes[cl.ackedmovesequence & UPDATE_MASK].playerstate[pv->playernum]; to = &cl.inframes[cl.movesequence & UPDATE_MASK].playerstate[pv->playernum]; CL_PredictUsercmd(pv->playernum, pv->viewentity, from, to, &cl.outframes[cl.ackedmovesequence & UPDATE_MASK].cmd[plnum]); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 9a7233fc..5604e869 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1657,6 +1657,7 @@ This is also called on Host_Error, so it shouldn't cause any errors void CL_Disconnect (void) { qbyte final[12]; + int i; connectinfo.trying = false; @@ -1741,7 +1742,8 @@ void CL_Disconnect (void) COM_FlushTempoaryPacks(); r_worldentity.model = NULL; - cl.spectator = 0; + for (i = 0; i < cl.splitclients; i++) + cl.playerview[i].spectator = 0; cl.sendprespawn = false; cl.intermissionmode = IM_NONE; cl.oldgametime = 0; @@ -2033,9 +2035,18 @@ void CL_CheckServerInfo(void) unsigned int allowed; #ifdef QUAKESTATS int oldstate; +#endif +#ifndef CLIENTONLY + extern cvar_t sv_cheats; #endif int oldteamplay; - qboolean spectating = cl.spectator && cl.spectator != 2; //spectator 2 = spectator-with-scores, considered to be players. this means we don't want to allow spec cheats while they're inactive, because that would be weird. + qboolean spectating = true; + int i; + + //spectator 2 = spectator-with-scores, considered to be players. this means we don't want to allow spec cheats while they're inactive, because that would be weird. + for (i = 0; i < cl.splitclients; i++) + if (cl.playerview[i].spectator != 1) + spectating = false; oldteamplay = cl.teamplay; cl.teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); @@ -2073,7 +2084,8 @@ void CL_CheckServerInfo(void) #ifndef CLIENTONLY //allow cheats in single player regardless of sv_cheats. - if (sv.state == ss_active && sv.allocated_client_slots == 1) + //(also directly read the sv_cheats cvar to avoid issues with nq protocols that don't support serverinfo. + if ((sv.state == ss_active && sv.allocated_client_slots == 1) || sv_cheats.ival) cls.allow_cheats = true; #endif @@ -3074,6 +3086,7 @@ void CL_ConnectionlessPacket (void) COM_Parse(s); if (!strcmp(com_token, "ccept")) { + /*this is a DP server... but we don't know which version nor nq protocol*/ Con_Printf ("accept\n"); if (cls.state == ca_connected) return; //we're already connected. don't do it again! @@ -3090,10 +3103,9 @@ void CL_ConnectionlessPacket (void) CL_ParseEstablished(); Con_DPrintf ("CL_EstablishConnection: connected to %s\n", cls.servername); - /*this is a DP server... but we don't know which version*/ cls.netchan.isnqprotocol = true; cls.protocol = CP_NETQUAKE; - cls.protocol_nq = CPNQ_ID; + cls.protocol_nq = CPNQ_ID; //assume vanilla protocol until we know better. cls.proquake_angles_hack = false; cls.challenge = connectinfo.challenge; connectinfo.trying = false; @@ -3846,14 +3858,12 @@ void CL_ServerInfo_f(void) } #endif -/* -#ifdef WEBCLIENT +#ifdef FTPCLIENT void CL_FTP_f(void) { FTP_Client_Command(Cmd_Args(), NULL); } #endif -*/ //fixme: make a cvar void CL_Fog_f(void) @@ -3930,6 +3940,7 @@ void CL_Status_f(void) switch(cls.protocol) { + default: case CP_UNKNOWN: Con_Printf("Unknown protocol\n"); break; @@ -4230,9 +4241,9 @@ void CL_Init (void) Cvar_Register (&qtvcl_forceversion1, cl_controlgroup); Cvar_Register (&qtvcl_eztvextensions, cl_controlgroup); -//#ifdef WEBCLIENT -// Cmd_AddCommand ("ftp", CL_FTP_f); -//#endif +#ifdef FTPCLIENT + Cmd_AddCommand ("ftp", CL_FTP_f); +#endif Cmd_AddCommandD ("changing", CL_Changing_f, "Part of network protocols. This command should not be used manually."); Cmd_AddCommand ("disconnect", CL_Disconnect_f); @@ -5538,7 +5549,7 @@ double Host_Frame (double time) extern cvar_t scr_chatmodecvar, r_stereo_method; if (scr_chatmodecvar.ival && cl.intermissionmode == IM_NONE) - scr_chatmode = (cl.spectator&&cl.splitclients<2&&cls.state == ca_active)?2:1; + scr_chatmode = (cl.playerview[0].spectator&&cl.splitclients<2&&cls.state == ca_active)?2:1; else scr_chatmode = 0; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 9b2ea76e..8070fa65 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3086,18 +3086,19 @@ static void CLQW_ParseServerData (void) { cl.playerview[j].playernum = cl.allocated_client_slots + j; cl.playerview[j].viewentity = 0; //free floating. + cl.playerview[j].spectator = true; for (i = 0; i < UPDATE_BACKUP; i++) { cl.inframes[i].playerstate[cl.playerview[j].playernum].pm_type = PM_SPECTATOR; cl.inframes[i].playerstate[cl.playerview[j].playernum].messagenum = 1; } } - cl.spectator = true; cl.splitclients = 1; } else if (cls.fteprotocolextensions2 & PEXT2_MAXPLAYERS) { + qboolean spec = false; cl.allocated_client_slots = MSG_ReadByte(); if (cl.allocated_client_slots > MAX_CLIENTS) { @@ -3109,13 +3110,14 @@ static void CLQW_ParseServerData (void) cl.splitclients = MSG_ReadByte(); if (cl.splitclients & 128) { - cl.spectator = true; + spec = true; cl.splitclients &= ~128; } if (cl.splitclients > MAX_SPLITS) Host_EndGame("Server sent us too many alternate clients\n"); for (pnum = 0; pnum < cl.splitclients; pnum++) { + cl.playerview[pnum].spectator = true; if (cls.z_ext & Z_EXT_VIEWHEIGHT) cl.playerview[pnum].viewheight = 0; cl.playerview[pnum].playernum = MSG_ReadByte(); @@ -3137,9 +3139,11 @@ static void CLQW_ParseServerData (void) cl.playerview[clnum].playernum = pnum; if (cl.playerview[clnum].playernum & 128) { - cl.spectator = true; + cl.playerview[clnum].spectator = true; cl.playerview[clnum].playernum &= ~128; } + else + cl.playerview[clnum].spectator = false; if (cl.playerview[clnum].playernum >= cl.allocated_client_slots) Host_EndGame("unsupported local player slot\n"); @@ -3309,8 +3313,8 @@ static void CLQ2_ParseServerData (void) // parse player entity number cl.playerview[0].playernum = MSG_ReadShort (); cl.playerview[0].viewentity = cl.playerview[0].playernum+1; + cl.playerview[0].spectator = false; cl.splitclients = 1; - cl.spectator = false; cl.numq2visibleweapons = 1; //give it a default. cl.q2visibleweapons[0] = "weapon.md2"; @@ -4884,7 +4888,7 @@ void CL_NewTranslation (int slot) bottom = player->rbottomcolor; if (cl.splitclients < 2 && !(cl.fpd & FPD_NO_FORCE_COLOR)) //no colour/skin forcing in splitscreen. { - if (cl.teamplay && cl.spectator) + if (cl.teamplay && cl.playerview[0].spectator) { local = Cam_TrackNum(&cl.playerview[0]); if (local < 0) @@ -4977,11 +4981,14 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player) player->colourised = TP_FindColours(player->name); // If it's us - if (slot == cl.playerview[0].playernum && player->name[0]) + for (i = 0; i < cl.splitclients; i++) + if (slot == cl.playerview[i].playernum) + break; + if (i < cl.splitclients && player->name[0]) { - if (cl.spectator != player->spectator) + if (cl.playerview[i].spectator != player->spectator) { - cl.spectator = player->spectator; + cl.playerview[i].spectator = player->spectator; for (i = 0; i < cl.splitclients; i++) { Cam_Unlock(&cl.playerview[i]); @@ -4993,7 +5000,7 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player) Skin_FlushPlayers(); } - else if (cl.teamplay && cl.spectator && slot == Cam_TrackNum(&cl.playerview[0])) //skin forcing cares about the team of the guy we're tracking. + else if (cl.teamplay && cl.playerview[0].spectator && slot == Cam_TrackNum(&cl.playerview[0])) //skin forcing cares about the team of the guy we're tracking. Skin_FlushPlayers(); else if (cls.state == ca_active) Skin_Find (player); @@ -6104,7 +6111,8 @@ static void CL_ParseWeaponStats(void) static void CL_ParseItemTimer(void) { - float timeout = atof(Cmd_Argv(0)); + //it [cur/]duration x y z radius 0xRRGGBB "timername" owningent + float timeout;// = atof(Cmd_Argv(0)); vec3_t org = { atof(Cmd_Argv(1)), atof(Cmd_Argv(2)), atof(Cmd_Argv(3))}; @@ -6113,6 +6121,15 @@ static void CL_ParseItemTimer(void) // char *timername = Cmd_Argv(6); unsigned int entnum = strtoul(Cmd_Argv(7), NULL, 0); struct itemtimer_s *timer; + float start = cl.time; + char *e; + timeout = strtod(Cmd_Argv(0), &e); + if (*e == '/') + { + start += timeout; + timeout = atof(e+1); + start -= timeout; + } if (!timeout) timeout = FLT_MAX; @@ -6121,7 +6138,12 @@ static void CL_ParseItemTimer(void) for (timer = cl.itemtimers; timer; timer = timer->next) { - if (VectorCompare(timer->origin, org) && timer->entnum == entnum && entnum) + if (entnum) + { + if (timer->entnum == entnum) + break; + } + else if (VectorCompare(timer->origin, org)) break; } if (!timer) @@ -6137,8 +6159,8 @@ static void CL_ParseItemTimer(void) timer->radius = radius; timer->duration = timeout; timer->entnum = entnum; - timer->start = cl.time; - timer->end = cl.time + timer->duration; + timer->start = start; + timer->end = start + timer->duration; timer->rgb[0] = ((rgb>>16)&0xff)/255.0; timer->rgb[1] = ((rgb>> 8)&0xff)/255.0; timer->rgb[2] = ((rgb )&0xff)/255.0; @@ -6931,7 +6953,7 @@ void CLQW_ParseServerMessage (void) if (cl.intermissionmode == IM_NONE) { TP_ExecTrigger ("f_mapend", false); - if (cl.spectator) + if (cl.playerview[destsplit].spectator) TP_ExecTrigger ("f_specmapend", true); cl.completed_time = cl.gametime; } diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 65043586..0cd5c407 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -449,7 +449,7 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state void CL_CatagorizePosition (playerview_t *pv, float *org) { //fixme: in nq, we are told by the server and should skip this, which avoids needing to know the player's size. - if (cl.spectator) + if (pv->spectator) { pv->onground = false; // in air return; @@ -912,7 +912,7 @@ void CL_PredictMovePNum (int seat) pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD); - if (!cl.spectator && (pv->cam_state != CAM_FREECAM || pv->cam_spec_track != -1)) //just in case + if (!pv->spectator && (pv->cam_state != CAM_FREECAM || pv->cam_spec_track != -1)) //just in case { if (pv->cam_state != CAM_FREECAM) pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 56ac0cf2..17f2d614 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -712,9 +712,6 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font) void SCR_CheckDrawCenterString (void) { -#ifdef QUAKEHUD - extern qboolean sb_showscores; -#endif int pnum; cprint_t *p; @@ -731,7 +728,7 @@ void SCR_CheckDrawCenterString (void) continue; //should probably allow the console with a scissor region or something. #ifdef QUAKEHUD - if (sb_showscores) //this was annoying + if (cl.playerview[pnum].sb_showscores) //this was annoying continue; #endif @@ -3066,7 +3063,7 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) } else if (cl.intermissionmode != IM_NONE) { - Sbar_IntermissionOverlay (); + Sbar_IntermissionOverlay (r_refdef.playerview); } else { diff --git a/engine/client/client.h b/engine/client/client.h index 31991f19..13c14999 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -599,6 +599,7 @@ struct playerview_s { int playernum; //cl.players index for this player. qboolean nolocalplayer; //inhibit use of qw-style players, predict based on entities. + qboolean spectator; #ifdef PEXT_SETVIEW int viewentity; //view is attached to this entity. #endif @@ -610,12 +611,16 @@ struct playerview_s float item_gettime[32]; // cl.time of aquiring item, for blinking float faceanimtime; // use anim frame if cl.time < this +#ifdef QUAKEHUD + qboolean sb_showscores; + qboolean sb_showteamscores; #ifdef HEXEN2 int sb_hexen2_cur_item;//hexen2 hud float sb_hexen2_item_time; qboolean sb_hexen2_extra_info;//show the extra stuff qboolean sb_hexen2_infoplaque; #endif +#endif // the client maintains its own idea of view angles, which are @@ -752,7 +757,7 @@ typedef struct // render a frame yet int movesequence; // client->server frames - int spectator; +// int spectator; int autotrack_hint; //the latest hint from the mod, might be negative for invalid. int autotrack_killer; //if someone kills the guy we're tracking, this is the guy we should switch to. diff --git a/engine/client/keys.c b/engine/client/keys.c index 51cd46d9..63a7a2ff 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -768,7 +768,7 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info) if (*cl.players[player].ip) Con_Footerf(con, true, "\n%s", cl.players[player].ip); - if (cl.spectator || cls.demoplayback) + if (cl.playerview[0].spectator || cls.demoplayback) { //we're spectating, or an mvd Con_Footerf(con, true, " ^[Spectate\\player\\%i\\action\\spec^]", player); @@ -803,7 +803,7 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info) //hey look! its you! - if (cl.spectator || cls.demoplayback) + if (cl.playerview[i].spectator || cls.demoplayback) { //need join option here or something } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 854078a6..c19dff8b 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -246,7 +246,7 @@ static void CSQC_ChangeLocalPlayer(int seat) { if (csqc_playerview->viewentity) *csqcg.player_localentnum = csqc_playerview->viewentity; - else if (cl.spectator && Cam_TrackNum(csqc_playerview) >= 0) + else if (csqc_playerview->spectator && Cam_TrackNum(csqc_playerview) >= 0) *csqcg.player_localentnum = Cam_TrackNum(csqc_playerview) + 1; else if (csqc_playerview == &csqc_nullview) *csqcg.player_localentnum = 0; @@ -2185,7 +2185,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars #ifdef PLUGINS Plug_SBar (r_refdef.playerview); #else - if (Sbar_ShouldDraw()) + if (Sbar_ShouldDraw(r_refdef.playerview)) { SCR_TileClear (sb_lines); Sbar_Draw (r_refdef.playerview); @@ -2203,7 +2203,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars } else if (cl.intermissionmode != IM_NONE) { - Sbar_IntermissionOverlay (); + Sbar_IntermissionOverlay (r_refdef.playerview); } } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 3ac934c6..19a582f7 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -39,7 +39,6 @@ model_t *currentmodel; uploadfmt_t lightmap_fmt; //bgra32, rgba32, rgb24, lum8 int lightmap_bytes; // 1, 3 or 4 -qboolean lightmap_bgra; size_t maxblocksize; vec3_t *blocknormals; @@ -903,8 +902,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, if (currentmodel->deluxdata) Surf_BuildDeluxMap(currentmodel, surf, deluxdest, lmwidth, blocknormals); -#ifdef PEXT_LIGHTSTYLECOL - if (lightmap_bytes == 4 || lightmap_bytes == 3) + if (lightmap_fmt != TF_LUM8) { // set to full bright if no light data if (ambient < 0) @@ -1078,40 +1076,22 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, if (!r_stains.value || !surf->stained) stainsrc = NULL; - if (lightmap_bytes == 4) + switch(lightmap_fmt) { - if (lightmap_bgra) - { - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgra4_os, stainsrc, lmwidth); - } - else - { - /*if (!r_stains.value || !surf->stained) - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgba4, NULL); - else - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgba4, stainsrc); - */ - } - } - else if (lightmap_bytes == 3) - { - if (lightmap_bgra) - { - /* - if (!r_stains.value || !surf->stained) - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgr3, NULL); - else - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgr3, stainsrc); - */ - } - else - { - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgb3_os, stainsrc, lmwidth); - } + default: + Sys_Error("Bad lightmap_fmt\n"); + case TF_BGRA32: + Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgra4_os, stainsrc, lmwidth); + break; +// case TF_RGBA32: +// Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgba4, stainsrc, lmwidth); +// break; + case TF_RGB24: + Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgb3_os, stainsrc, lmwidth); + break; } } else -#endif { // set to full bright if no light data if (!surf->samples || !currentmodel->lightdata) @@ -1206,8 +1186,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte if (wmodel->deluxdata) Surf_BuildDeluxMap(wmodel, surf, deluxdest, lmwidth, blocknormals); -#ifdef PEXT_LIGHTSTYLECOL - if (lightmap_bytes == 4 || lightmap_bytes == 3) + if (lightmap_fmt != TF_LUM8) { // set to full bright if no light data if (ambient < 0) @@ -1377,40 +1356,20 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, qbyte if (!r_stains.value || !surf->stained) stainsrc = NULL; - if (lightmap_bytes == 4) + switch(lightmap_fmt) { - if (lightmap_bgra) - { - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgra4_os, stainsrc, lmwidth); - } - else - { - /*if (!r_stains.value || !surf->stained) - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgba4, NULL); - else - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgba4, stainsrc); - */ - } - } - else if (lightmap_bytes == 3) - { - if (lightmap_bgra) - { - /* - if (!r_stains.value || !surf->stained) - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgr3, NULL); - else - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgr3, stainsrc); - */ - } - else - { - Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgb3_os, stainsrc, lmwidth); - } + default: + Sys_Error("Bad lightmap_fmt\n"); + break; + case TF_BGRA32: + Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, bgra4_os, stainsrc, lmwidth); + break; + case TF_RGB24: + Surf_StoreLightmap(dest, blocklights, smax, tmax, shift, rgb3_os, stainsrc, lmwidth); + break; } } else -#endif { // set to full bright if no light data if (!surf->samples || !wmodel->lightdata) @@ -3305,58 +3264,44 @@ void Surf_Clear(model_t *mod) //pick fastest mode for lightmap data void Surf_LightmapMode(void) { - lightmap_bgra = true; - switch(qrenderer) { default: - case QR_SOFTWARE: +// case QR_VULKAN: +// case QR_SOFTWARE: +// case QR_DIRECT3D8: +// case QR_DIRECT3D9: +// case QR_DIRECT3D11: lightmap_fmt = TF_BGRA32; - lightmap_bytes = 4; - lightmap_bgra = true; break; -#ifdef D3DQUAKE - case QR_DIRECT3D8: - case QR_DIRECT3D9: - case QR_DIRECT3D11: - /*always bgra, hope your card supports it*/ - lightmap_fmt = TF_BGRA32; - lightmap_bytes = 4; - lightmap_bgra = true; - break; -#endif #ifdef GLQUAKE case QR_OPENGL: /*favour bgra if the gpu supports it, otherwise use rgb only if it'll be used*/ - lightmap_bgra = false; if (gl_config.gles) - { - //rgb is a supported format, where bgr or rgbx are not. - lightmap_fmt = TF_RGB24; - lightmap_bytes = 3; - lightmap_bgra = false; - } + lightmap_fmt = TF_RGB24; //rgb24 is a guarenteed supported format, where bgr24 or rgbx32 are not. else if (gl_config.glversion >= 1.2) - { - /*the more common case*/ - lightmap_fmt = TF_BGRA32; - lightmap_bytes = 4; - lightmap_bgra = true; - } + lightmap_fmt = TF_BGRA32; //the more common case else if (cl.worldmodel->fromgame == fg_quake3 || (cl.worldmodel->engineflags & MDLF_RGBLIGHTING) || cl.worldmodel->deluxdata || r_loadlits.value) - { - lightmap_fmt = TF_RGB24; - lightmap_bgra = false; - lightmap_bytes = 3; - } + lightmap_fmt = TF_RGB24; //ooold gl driver, but we need rgb lighting else - { - lightmap_fmt = TF_LUM8; - lightmap_bytes = 1; - } + lightmap_fmt = TF_LUM8; //oldskool! break; #endif } + + switch(lightmap_fmt) + { + default: + case TF_BGRA32: + lightmap_bytes = 4; + break; + case TF_RGB24: + lightmap_bytes = 3; + break; + case TF_LUM8: + lightmap_bytes = 1; + break; + } } //needs to be followed by a BE_UploadAllLightmaps at some point @@ -3374,6 +3319,8 @@ int Surf_NewLightmaps(int count, int width, int height, qboolean deluxe) Con_Print("WARNING: Deluxemapping with odd number of lightmaps\n"); } + Sys_LockMutex(com_resourcemutex); + i = numlightmaps + count; lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(i)); while(i > first) @@ -3416,6 +3363,8 @@ int Surf_NewLightmaps(int count, int width, int height, qboolean deluxe) numlightmaps += count; + Sys_UnlockMutex(com_resourcemutex); + return first; } int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe) @@ -3549,45 +3498,45 @@ void Surf_BuildModelLightmaps (model_t *m) src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*3; if (m->lightdata) { - if (lightmap_bgra && lightmap_bytes == 4) + switch(lightmap_fmt) { + default: + Sys_Error("Bad lightmap_fmt\n"); + break; + case TF_BGRA32: for (j = min((m->lightdatasize-i*m->lightmaps.width*m->lightmaps.height*3)/3,m->lightmaps.width*m->lightmaps.height); j > 0; j--, dst += 4, src += 3) - //for (j = 0; j < m->lightmaps.width*m->lightmaps.height; j++, dst += 4, src += 3) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; dst[3] = 255; } - } - else if (!lightmap_bgra && lightmap_bytes == 4) - { + break; + /*case TF_RGBA32: for (j = min((m->lightdatasize-i*m->lightmaps.width*m->lightmaps.height*3)/3,m->lightmaps.width*m->lightmaps.height); j > 0; j--, dst += 4, src += 3) - //for (j = 0; j < m->lightmaps.width*m->lightmaps.height; j++, dst += 4, src += 3) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = 255; } - } - else if (lightmap_bgra && lightmap_bytes == 3) - { + break; + case TF_BGR24: for (j = 0; j < m->lightmaps.width*m->lightmaps.height; j++, dst += 3, src += 3) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; } - } - else if (!lightmap_bgra && lightmap_bytes == 3) - { + break;*/ + case TF_RGB24: for (j = 0; j < m->lightmaps.width*m->lightmaps.height; j++, dst += 3, src += 3) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; } + break; } } } diff --git a/engine/client/render.h b/engine/client/render.h index 45a73351..0158cea5 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -360,8 +360,8 @@ extern lightmapinfo_t **lightmap; extern int numlightmaps; //extern texid_t *lightmap_textures; //extern texid_t *deluxmap_textures; -extern int lightmap_bytes; // 1, 3, or 4 -extern qboolean lightmap_bgra; /*true=bgra, false=rgba*/ +extern int lightmap_bytes; // 1, 3, or 4 +extern uploadfmt_t lightmap_fmt; //bgra32, rgba32, rgb24, lum8 void QDECL Surf_RebuildLightmap_Callback (struct cvar_s *var, char *oldvalue); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index c67aa7fb..4bcd4576 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -118,9 +118,6 @@ static int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_P static apic_t *hsb_items[2]; //end hipnotic -qboolean sb_showscores; -qboolean sb_showteamscores; - static qboolean sbarfailed; #ifdef HEXEN2 static qboolean sbar_hexen2; @@ -131,15 +128,15 @@ float sbar_rect_left; int sb_lines; // scan lines to draw -void Sbar_DeathmatchOverlay (int start); -void Sbar_TeamOverlay (void); +void Sbar_DeathmatchOverlay (playerview_t *pv, int start); +void Sbar_TeamOverlay (playerview_t *pv); static void Sbar_MiniDeathmatchOverlay (playerview_t *pv); void Sbar_ChatModeOverlay(playerview_t *pv); static int Sbar_PlayerNum(playerview_t *pv) { int num; - num = cl.spectator?Cam_TrackNum(pv):-1; + num = pv->spectator?Cam_TrackNum(pv):-1; if (num < 0) num = pv->playernum; return num; @@ -716,7 +713,8 @@ Tab key down */ void Sbar_ShowTeamScores (void) { - if (sb_showteamscores) + int seat = CL_TargettedSplit(false); + if (cl.playerview[seat].sb_showteamscores) return; #ifdef CSQC_DAT @@ -724,7 +722,7 @@ void Sbar_ShowTeamScores (void) return; #endif - sb_showteamscores = true; + cl.playerview[seat].sb_showteamscores = true; sb_updates = 0; } @@ -737,7 +735,8 @@ Tab key up */ void Sbar_DontShowTeamScores (void) { - sb_showteamscores = false; + int seat = CL_TargettedSplit(false); + cl.playerview[seat].sb_showteamscores = false; sb_updates = 0; #ifdef CSQC_DAT @@ -755,13 +754,14 @@ Tab key down */ void Sbar_ShowScores (void) { + int seat = CL_TargettedSplit(false); if (scr_scoreboard_teamscores.ival) { Sbar_ShowTeamScores(); return; } - if (sb_showscores) + if (cl.playerview[seat].sb_showscores) return; #ifdef CSQC_DAT @@ -769,7 +769,7 @@ void Sbar_ShowScores (void) return; #endif - sb_showscores = true; + cl.playerview[seat].sb_showscores = true; sb_updates = 0; } @@ -893,13 +893,14 @@ Tab key up */ void Sbar_DontShowScores (void) { + int seat = CL_TargettedSplit(false); if (scr_scoreboard_teamscores.ival) { Sbar_DontShowTeamScores(); return; } - sb_showscores = false; + cl.playerview[seat].sb_showscores = false; sb_updates = 0; #ifdef CSQC_DAT @@ -2166,7 +2167,7 @@ void Sbar_DrawNormal (playerview_t *pv) , pv->stats[STAT_AMMO] <= 10); } -qboolean Sbar_ShouldDraw (void) +qboolean Sbar_ShouldDraw (playerview_t *pv) { #ifdef TEXTEDITOR extern qboolean editoractive; @@ -2182,7 +2183,7 @@ qboolean Sbar_ShouldDraw (void) #endif #ifdef VM_UI - if (UI_DrawStatusBar((sb_showscores?1:0) + (sb_showteamscores?2:0))>0) + if (UI_DrawStatusBar((pv->sb_showscores?1:0) + (pv->sb_showteamscores?2:0))>0) return false; if (UI_MenuState()) return false; @@ -2195,10 +2196,9 @@ qboolean Sbar_ShouldDraw (void) return true; } -void Sbar_DrawScoreboard (void) +void Sbar_DrawScoreboard (playerview_t *pv) { - int pnum; - int deadcount=0; + qboolean isdead; if (cls.protocol == CP_QUAKE2) return; @@ -2214,31 +2214,27 @@ void Sbar_DrawScoreboard (void) } #endif - for (pnum = 0; pnum < cl.splitclients; pnum++) + isdead = false; + if (pv->spectator && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) { - if (cl.spectator && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) - { - int t = cl.playerview[pnum].cam_spec_track; - if (t < 0 || !CAM_ISLOCKED(&cl.playerview[pnum])) - continue; - if (cl.players[t].statsf[STAT_HEALTH] <= 0) - deadcount++; - } - else if (!cl.spectator && cl.playerview[pnum].statsf[STAT_HEALTH] <= 0) - deadcount++; + int t = pv->cam_spec_track; + if (t >= 0 && CAM_ISLOCKED(pv) && cl.players[t].statsf[STAT_HEALTH] <= 0) + isdead = true; } + else if (!pv->spectator && pv->statsf[STAT_HEALTH] <= 0) + isdead = true; - if (deadcount == cl.splitclients)// && !cl.spectator) + if (isdead)// && !cl.spectator) { - if (cl.teamplay > 0 && !sb_showscores) - Sbar_TeamOverlay(); + if (cl.teamplay > 0 && !pv->sb_showscores) + Sbar_TeamOverlay(pv); else - Sbar_DeathmatchOverlay (0); + Sbar_DeathmatchOverlay (pv, 0); } - else if (sb_showscores) - Sbar_DeathmatchOverlay (0); - else if (sb_showteamscores) - Sbar_TeamOverlay(); + else if (pv->sb_showscores) + Sbar_DeathmatchOverlay (pv, 0); + else if (pv->sb_showteamscores) + Sbar_TeamOverlay(pv); else return; @@ -2563,7 +2559,7 @@ static void Sbar_DrawTeamStatus(playerview_t *pv) y = -32; track = Cam_TrackNum(pv); - if (track == -1 || !cl.spectator) + if (track == -1 || !pv->spectator) track = pv->playernum; for (p = 0; p < cl.allocated_client_slots; p++) @@ -2730,7 +2726,7 @@ extern cvar_t show_speed_y; t = Sys_DoubleTime(); if ((t - lastupstime) >= 1.0/20) { - if (cl.spectator) + if (pv->spectator) track = Cam_TrackNum(pv); else track = -1; @@ -2865,7 +2861,7 @@ void Sbar_Draw (playerview_t *pv) // main area if (sb_lines > 0) { - if (cl.spectator) + if (pv->spectator) { if (pv->cam_state == CAM_FREECAM || pv->cam_state == CAM_PENDING) { @@ -2879,7 +2875,7 @@ void Sbar_Draw (playerview_t *pv) } else { - if (sb_showscores || sb_showteamscores || pv->stats[STAT_HEALTH] <= 0) + if (pv->sb_showscores || pv->sb_showteamscores || pv->stats[STAT_HEALTH] <= 0) Sbar_SoloScoreboard (); // else if (cls.gamemode != GAME_DEATHMATCH) // Sbar_CoopScoreboard (); @@ -2894,7 +2890,7 @@ void Sbar_Draw (playerview_t *pv) } } } - else if (sb_showscores || sb_showteamscores || (pv->stats[STAT_HEALTH] <= 0 && cl.splitclients == 1)) + else if (pv->sb_showscores || pv->sb_showteamscores || (pv->stats[STAT_HEALTH] <= 0 && cl.splitclients == 1)) { if (pv == cl.playerview) { @@ -2915,7 +2911,7 @@ void Sbar_Draw (playerview_t *pv) // top line if (sb_lines > 24) { - if (!cl.spectator || pv->cam_state == CAM_WALLCAM || pv->cam_state == CAM_EYECAM) + if (!pv->spectator || pv->cam_state == CAM_WALLCAM || pv->cam_state == CAM_EYECAM) Sbar_DrawInventory (pv); else if (cl_sbar.ival) Sbar_DrawPic (0, -24, 320, 24, sb_scorebar); //make sure we don't get HoM @@ -3006,7 +3002,7 @@ team frags added by Zoid ================== */ -void Sbar_TeamOverlay (void) +void Sbar_TeamOverlay (playerview_t *pv) { mpic_t *pic; int i, k; @@ -3015,8 +3011,8 @@ void Sbar_TeamOverlay (void) team_t *tm; int plow, phigh, pavg; int pw,ph; - playerview_t *pv = r_refdef.playerview; + vrect_t gr = r_refdef.grect; int rank_width = 320-32*2; int startx; int trackplayer; @@ -3027,11 +3023,11 @@ void Sbar_TeamOverlay (void) // request new ping times every two second if (!cl.teamplay) { - Sbar_DeathmatchOverlay(0); + Sbar_DeathmatchOverlay(pv, 0); return; } - y = 0; + y = gr.y; if (scr_scoreboard_drawtitle.ival) { @@ -3039,12 +3035,12 @@ void Sbar_TeamOverlay (void) if (pic && R_GetShaderSizes(pic, &pw, &ph, false)>0) { k = (pw * 24) / ph; - R2D_ScalePic ((vid.width-k)/2, 0, k, 24, pic); + R2D_ScalePic (gr.x+(gr.width-k)/2, y, k, 24, pic); } y += 24; } - x = l = (vid.width - 320)/2 + 36; + x = l = gr.x + (gr.width - 320)/2 + 36; startx = x; @@ -3099,7 +3095,7 @@ void Sbar_TeamOverlay (void) // sort the teams Sbar_SortTeams(pv); - if (cl.spectator) + if (pv->spectator) trackplayer = Cam_TrackNum(pv); else trackplayer = pv->playernum; @@ -3184,7 +3180,7 @@ void Sbar_TeamOverlay (void) } else y += 8; - Sbar_DeathmatchOverlay(y); + Sbar_DeathmatchOverlay(pv, y-gr.y); } /* @@ -3287,7 +3283,7 @@ enum }; #define ADDCOLUMN(id) showcolumns |= (1<cam_spec_track && pv->cam_state != CAM_FREECAM) || - (!cl.spectator && k == pv->playernum)) + if ((pv->spectator && k == pv->cam_spec_track && pv->cam_state != CAM_FREECAM) || + (!pv->spectator && k == pv->playernum)) { Font_BeginString(font_default, x, y, &px, &py); Font_DrawChar ( px, py, CON_WHITEMASK, 16 | 0xe000); @@ -3812,12 +3807,11 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv) } -void Sbar_CoopIntermission (void) +void Sbar_CoopIntermission (playerview_t *pv) { mpic_t *pic; int dig; int num; - int pnum = 0; //should be the same for all players. sbar_rect.width = vid.width; sbar_rect.height = vid.height; @@ -3842,13 +3836,13 @@ void Sbar_CoopIntermission (void) R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 278,(sbar_rect.height - 200)/2 + 64, 16, 24, sb_nums[0][num%10]); //it is assumed that secrits/monsters are going to be constant for any player... - Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 104, cl.playerview[pnum].stats[STAT_SECRETS], 4, 0, false); + Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_SECRETS], 4, 0, false); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230, (sbar_rect.height - 200)/2 + 104, 16, 24, sb_slash); - Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 104, cl.playerview[pnum].stats[STAT_TOTALSECRETS], 4, 0, true); + Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 104, pv->stats[STAT_TOTALSECRETS], 4, 0, true); - Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 144, cl.playerview[pnum].stats[STAT_MONSTERS], 4, 0, false); + Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 230 - 24*4, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_MONSTERS], 4, 0, false); R2D_ScalePicAtlas ((sbar_rect.width - 320)/2 + 230,(sbar_rect.height - 200)/2 + 144, 16, 24, sb_slash); - Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 144, cl.playerview[pnum].stats[STAT_TOTALMONSTERS], 4, 0, true); + Sbar_IntermissionNumber ((sbar_rect.width - 320)/2 + 254, (sbar_rect.height - 200)/2 + 144, pv->stats[STAT_TOTALMONSTERS], 4, 0, true); } /* ================== @@ -3856,7 +3850,7 @@ Sbar_IntermissionOverlay ================== */ -void Sbar_IntermissionOverlay (void) +void Sbar_IntermissionOverlay (playerview_t *pv) { #ifdef VM_UI if (UI_DrawIntermission()>0) @@ -3866,10 +3860,10 @@ void Sbar_IntermissionOverlay (void) Sbar_Start(); if (!cls.deathmatch) - Sbar_CoopIntermission(); - else if (cl.teamplay > 0 && !sb_showscores) - Sbar_TeamOverlay (); + Sbar_CoopIntermission(pv); + else if (cl.teamplay > 0 && !pv->sb_showscores) + Sbar_TeamOverlay (pv); else - Sbar_DeathmatchOverlay (0); + Sbar_DeathmatchOverlay (pv, 0); } #endif diff --git a/engine/client/sbar.h b/engine/client/sbar.h index 75192f18..47f397d0 100644 --- a/engine/client/sbar.h +++ b/engine/client/sbar.h @@ -33,12 +33,12 @@ qboolean Sbar_UpdateTeamStatus(struct player_info_s *player, char *status); void Sbar_Changed (void); // call whenever any of the client stats represented on the sbar changes -qboolean Sbar_ShouldDraw(void); +qboolean Sbar_ShouldDraw(playerview_t *pv); void Sbar_Draw (playerview_t *pv); //uses the current r_refdef.grect -void Sbar_DrawScoreboard (void); +void Sbar_DrawScoreboard (playerview_t *pv); // called every frame by screen -void Sbar_IntermissionOverlay (void); +void Sbar_IntermissionOverlay (playerview_t *pv); // called each frame after the level has been completed void Sbar_FinaleOverlay (void); diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 9617ec78..c318a242 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -4,10 +4,9 @@ This is based on Jogi's OpenAL support. Much of it is stripped, to try and get it clean/compliant. -Missing features: -FIXME: listener velocity calculations (currently ugly). -FIXME: does not track entity velocities, so no dopler (awkward, quake doesn't move playing sounds at all). -FIXME: a capture device would be useful (voice chat). +Emscripten/WebAudio is buggy or limited. +This means we force distance models and use hacks to avoid bugs in browsers. +We also have no doppler with WebAudio. */ #ifdef AVAIL_OPENAL diff --git a/engine/client/valid.c b/engine/client/valid.c index ab5d6d37..80570dfe 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -627,7 +627,7 @@ void Validation_Auto_Response(int playernum, char *s) Validation_Version(); versionresponsetime = Sys_DoubleTime() + 5; } - else if (cl.spectator) + else if (cl.playerview[0].spectator) return; else if (!strncmp(s, "server", 6) && serverresponsetime < Sys_DoubleTime()) //respond to it. { diff --git a/engine/client/view.c b/engine/client/view.c index cc254451..50958a99 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -160,7 +160,7 @@ float V_CalcBob (playerview_t *pv, qboolean queryold) float hspeed, bob; vec3_t hvel; - if (cl.spectator) + if (pv->spectator) return 0; if (cl_bobcycle.value <= 0 || cl.intermissionmode != IM_NONE) @@ -1477,9 +1477,9 @@ void V_CalcRefdef (playerview_t *pv) } #ifdef QUAKESTATS - if (pv->stats[STAT_HEALTH] < 0 && (!cl.spectator || pv->cam_state == CAM_EYECAM) && v_deathtilt.value) // PF_GIB will also set PF_DEAD + if (pv->stats[STAT_HEALTH] < 0 && (!pv->spectator || pv->cam_state == CAM_EYECAM) && v_deathtilt.value) // PF_GIB will also set PF_DEAD { - if (!cl.spectator || cl_chasecam.ival) + if (!pv->spectator || cl_chasecam.ival) r_refdef.viewangles[ROLL] = 80*v_deathtilt.value; // dead view angle } else @@ -1980,7 +1980,7 @@ void R_DrawNameTags(void) } } - if (((!cl.spectator && !cls.demoplayback) || !scr_autoid.ival) && (!cl.teamplay || !scr_autoid_team.ival)) + if (((!r_refdef.playerview->spectator && !cls.demoplayback) || !scr_autoid.ival) && (!cl.teamplay || !scr_autoid_team.ival)) return; if (cls.state != ca_active || !cl.validsequence || cl.intermissionmode != IM_NONE) return; @@ -2029,13 +2029,13 @@ void R_DrawNameTags(void) if (!cl.teamplay || !scr_autoid_team.ival) isteam = false; - else if ((cl.teamfortress && !cl.spectator) || cls.protocol == CP_NETQUAKE) //teamfortress should go by their colours instead, because spies. primarily this is to allow enemy spies to appear through walls as well as your own team (note that the qc will also need tinfo stuff for tf, to avoid issues with just checking player names). + else if ((cl.teamfortress && !r_refdef.playerview->spectator) || cls.protocol == CP_NETQUAKE) //teamfortress should go by their colours instead, because spies. primarily this is to allow enemy spies to appear through walls as well as your own team (note that the qc will also need tinfo stuff for tf, to avoid issues with just checking player names). isteam = cl.players[i].rbottomcolor == ourcolour; else isteam = !strcmp(cl.players[i].team, ourteam); if (!isteam) - if ((!cl.spectator && !cls.demoplayback) || !scr_autoid.ival) + if ((!r_refdef.playerview->spectator && !cls.demoplayback) || !scr_autoid.ival) continue; //only show our team when playing, too cheaty otherwise. SCR_DrawAutoID(nametagorg[i], &cl.players[i], isteam); diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 5ab01f41..2b06e536 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -704,7 +704,8 @@ done: static char *Skin_To_TFSkin (char *myskin) { - if (!cl.teamfortress || cl.spectator || Q_strncasecmp(myskin, "tf_", 3)) + playerview_t *pv = &cl.playerview[SP]; + if (!cl.teamfortress || pv->spectator || Q_strncasecmp(myskin, "tf_", 3)) { Q_strncpyz(macro_buf, myskin, sizeof(macro_buf)); } @@ -732,9 +733,10 @@ static char *Macro_TF_Skin (void) //Spike: added these: static char *Macro_ConnectionType (void) { + playerview_t *pv = &cl.playerview[SP]; if (!cls.state) return "disconnected"; - if (cl.spectator) + if (pv->spectator) return "spectator"; return "connected"; } @@ -878,6 +880,7 @@ static void CountNearbyPlayers(qboolean dead) player_state_t *state; player_info_t *info; static int lastframecount = -1; + playerview_t *pv = &cl.playerview[SP]; if (cls.framecount == lastframecount) return; @@ -885,7 +888,7 @@ static void CountNearbyPlayers(qboolean dead) vars.numenemies = vars.numfriendlies = 0; - if (!cl.spectator && !dead) + if (!pv->spectator && !dead) vars.numfriendlies++; if (!cl.oldparsecount || !cl.parsecount || cls.state < ca_active) @@ -894,7 +897,7 @@ static void CountNearbyPlayers(qboolean dead) state = cl.inframes[cl.oldparsecount & UPDATE_MASK].playerstate; info = cl.players; for (i = 0; i < cl.allocated_client_slots; i++, info++, state++) { - if (i != cl.playerview[SP].playernum && state->messagenum == cl.oldparsecount && !info->spectator && !ISDEAD(state->frame)) { + if (i != pv->playernum && state->messagenum == cl.oldparsecount && !info->spectator && !ISDEAD(state->frame)) { if (cl.teamplay && !strcmp(info->team, TP_PlayerTeam())) vars.numfriendlies++; else @@ -2183,6 +2186,7 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr) int flags; player_info_t *player; char *name; + playerview_t *pv = &cl.playerview[SP]; *offset = 0; *plr = NULL; @@ -2275,9 +2279,9 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr) !strncmp(name, s+1, len)) { // no team messages in teamplay 0, except for our own - if (cl.spectator) + if (pv->spectator) { - unsigned int track = Cam_TrackNum(&cl.playerview[SP]); + unsigned int track = Cam_TrackNum(pv); if (i == track || ( cl.teamplay && !strcmp(cl.players[track].team, player->team)) ) { @@ -2286,8 +2290,8 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr) } else { - if (i == cl.playerview[SP].playernum || ( cl.teamplay && - !strcmp(cl.players[cl.playerview[SP].playernum].team, player->team)) ) + if (i == pv->playernum || ( cl.teamplay && + !strcmp(cl.players[pv->playernum].team, player->team)) ) { flags |= TPM_TEAM; } @@ -2814,8 +2818,9 @@ static qboolean CheckTrigger (void) int i, count; player_info_t *player; char *myteam; + playerview_t *pv = &cl.playerview[SP]; - if (cl.spectator) + if (pv->spectator) return false; if (tp_forceTriggers.ival) @@ -2825,9 +2830,9 @@ static qboolean CheckTrigger (void) return false; count = 0; - myteam = cl.players[cl.playerview[SP].playernum].team; + myteam = cl.players[pv->playernum].team; for (i = 0, player= cl.players; i < cl.allocated_client_slots; i++, player++) { - if (player->name[0] && !player->spectator && i != cl.playerview[SP].playernum && !strcmp(player->team, myteam)) + if (player->name[0] && !player->spectator && i != pv->playernum && !strcmp(player->team, myteam)) count++; } @@ -2890,13 +2895,14 @@ static void TP_ItemTaken (char *s, int flag, vec3_t org, int entnum, item_t *ite void TP_ParsePlayerInfo(player_state_t *oldstate, player_state_t *state, player_info_t *info) { #ifndef QUAKETC + playerview_t *pv = &cl.playerview[SP]; // if (TP_NeedRefreshSkins()) // { // if ((state->effects & (EF_BLUE|EF_RED) ) != (oldstate->effects & (EF_BLUE|EF_RED))) // TP_RefreshSkin(info - cl.players); // } - if (!cl.spectator && cl.teamplay && strcmp(info->team, TP_PlayerTeam())) + if (!pv->spectator && cl.teamplay && strcmp(info->team, TP_PlayerTeam())) { qboolean eyes; @@ -2915,11 +2921,11 @@ void TP_ParsePlayerInfo(player_state_t *oldstate, player_state_t *state, player_ vars.enemy_powerups |= TP_RING; } } - if (!cl.spectator && !cl.teamfortress && info - cl.players == cl.playerview[SP].playernum) + if (!pv->spectator && !cl.teamfortress && info - cl.players == pv->playernum) { if ((state->effects & (QWEF_FLAG1|QWEF_FLAG2)) && !(oldstate->effects & (QWEF_FLAG1|QWEF_FLAG2))) { - ExecTookTrigger_ (tp_name_flag.string, it_flag, cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[cl.playerview[SP].playernum].origin); + ExecTookTrigger_ (tp_name_flag.string, it_flag, cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[pv->playernum].origin); } else if (!(state->effects & (QWEF_FLAG1|QWEF_FLAG2)) && (oldstate->effects & (QWEF_FLAG1|QWEF_FLAG2))) { @@ -2935,8 +2941,9 @@ void TP_CheckPickupSound (char *s, vec3_t org, int seat) #ifndef QUAKETC int entnum; item_t *item; + playerview_t *pv = &cl.playerview[seat]; //if we're spectating, we don't want to do any actual triggers, so pretend it was someone else. - if (cl.spectator) + if (pv->spectator) seat = -1; //FIXME: on items/itembk2.wav kill relevant item timer. @@ -2992,17 +2999,17 @@ more: if (vars.stat_framecounts[STAT_ITEMS] == cls.framecount) { if (vars.items & ~vars.olditems & IT_LIGHTNING) - TP_ItemTaken (tp_name_lg.string, it_lg, cl.playerview[SP].simorg, entnum, item, seat); + TP_ItemTaken (tp_name_lg.string, it_lg, pv->simorg, entnum, item, seat); else if (vars.items & ~vars.olditems & IT_ROCKET_LAUNCHER) - TP_ItemTaken (tp_name_rl.string, it_rl, cl.playerview[SP].simorg, entnum, item, seat); + TP_ItemTaken (tp_name_rl.string, it_rl, pv->simorg, entnum, item, seat); else if (vars.items & ~vars.olditems & IT_GRENADE_LAUNCHER) - TP_ItemTaken (tp_name_gl.string, it_gl, cl.playerview[SP].simorg, entnum, item, seat); + TP_ItemTaken (tp_name_gl.string, it_gl, pv->simorg, entnum, item, seat); else if (vars.items & ~vars.olditems & IT_SUPER_NAILGUN) - TP_ItemTaken (tp_name_sng.string, it_sng, cl.playerview[SP].simorg, entnum, item, seat); + TP_ItemTaken (tp_name_sng.string, it_sng, pv->simorg, entnum, item, seat); else if (vars.items & ~vars.olditems & IT_NAILGUN) - TP_ItemTaken (tp_name_ng.string, it_ng, cl.playerview[SP].simorg, entnum, item, seat); + TP_ItemTaken (tp_name_ng.string, it_ng, pv->simorg, entnum, item, seat); else if (vars.items & ~vars.olditems & IT_SUPER_SHOTGUN) - TP_ItemTaken (tp_name_ssg.string, it_ssg, cl.playerview[SP].simorg, entnum, item, seat); + TP_ItemTaken (tp_name_ssg.string, it_ssg, pv->simorg, entnum, item, seat); } } return; @@ -3020,11 +3027,11 @@ more: TP_ItemTaken (item->cvar->string, item->itemflag, org, entnum, item, seat); else if (seat >= 0) { - if (armor_updated && cl.playerview[SP].stats[STAT_ARMOR] == 100) + if (armor_updated && pv->stats[STAT_ARMOR] == 100) TP_ItemTaken (tp_name_ga.string, it_ga, org, entnum, NULL, seat); - else if (armor_updated && cl.playerview[SP].stats[STAT_ARMOR] == 150) + else if (armor_updated && pv->stats[STAT_ARMOR] == 150) TP_ItemTaken (tp_name_ya.string, it_ya, org, entnum, NULL, seat); - else if (armor_updated && cl.playerview[SP].stats[STAT_ARMOR] == 200) + else if (armor_updated && pv->stats[STAT_ARMOR] == 200) TP_ItemTaken (tp_name_ra.string, it_ra, org, entnum, NULL, seat); } return; @@ -3216,6 +3223,7 @@ static void TP_FindPoint (void) item_vis_t visitem; extern cvar_t v_viewheight; int oldskip = pmove.skipent; + playerview_t *pv = &cl.playerview[SP]; if (vars.pointtime == realtime) return; @@ -3223,11 +3231,11 @@ static void TP_FindPoint (void) if (!cl.validsequence) goto nothing; - pmove.skipent = cl.playerview[SP].viewentity; + pmove.skipent = pv->viewentity; - ang[0] = cl.playerview[SP].viewangles[0]; ang[1] = cl.playerview[SP].viewangles[1]; ang[2] = 0; + ang[0] = pv->viewangles[0]; ang[1] = pv->viewangles[1]; ang[2] = 0; AngleVectors (ang, visitem.forward, visitem.right, visitem.up); - VectorCopy (cl.playerview[SP].simorg, visitem.vieworg); + VectorCopy (pv->simorg, visitem.vieworg); visitem.vieworg[2] += 22 + (v_viewheight.value ? bound (-7, v_viewheight.value, 4) : 0); pointflags_dmm = pointflags; @@ -3274,7 +3282,7 @@ static void TP_FindPoint (void) info = cl.players; for (j = 0; j < cl.allocated_client_slots; j++, info++, state++) { - if (state->messagenum != cl.parsecount || j == cl.playerview[SP].playernum || info->spectator) + if (state->messagenum != cl.parsecount || j == pv->playernum || info->spectator) continue; if ( @@ -3325,7 +3333,7 @@ static void TP_FindPoint (void) if (eyes) name = tp_name_eyes.string; //duck on 2night2 - else if (cl.spectator) + else if (pv->spectator) name = bestinfo->name; else if (teammate) name = tp_name_teammate.string[0] ? tp_name_teammate.string : "teammate"; @@ -3341,7 +3349,7 @@ static void TP_FindPoint (void) if (eyes) name = tp_name_eyes.string; - else if (cl.spectator || (teammate && !tp_name_teammate.string[0])) + else if (pv->spectator || (teammate && !tp_name_teammate.string[0])) name = bestinfo->name; else name = teammate ? tp_name_teammate.string : tp_name_enemy.string; @@ -3390,6 +3398,7 @@ void TP_UpdateAutoStatus(void) char newstatusbuf[sizeof(vars.autoteamstatus)]; char *newstatus; int level; + playerview_t *pv = &cl.playerview[SP]; if (vars.autoteamstatus_time > realtime || !*tp_autostatus.string) return; @@ -3415,7 +3424,7 @@ void TP_UpdateAutoStatus(void) if (tp_autostatus.latched_string) return; - if (cl.spectator) //don't spam as spectators, that's just silly + if (pv->spectator) //don't spam as spectators, that's just silly return; if (!cl.teamplay) //don't spam in deathmatch, that's just pointless return; @@ -3427,6 +3436,7 @@ void TP_UpdateAutoStatus(void) void TP_StatChanged (int stat, int value) { #ifdef QUAKESTATS + playerview_t *pv = &cl.playerview[SP]; int i; if (stat == STAT_HEALTH) { @@ -3437,14 +3447,14 @@ void TP_StatChanged (int stat, int value) // we just respawned vars.respawntrigger_time = realtime; - if (!cl.spectator && CountTeammates()) + if (!pv->spectator && CountTeammates()) TP_ExecTrigger ("f_respawn", false); } } else if (vars.health > 0) { // We have just died - vars.droppedweapon = cl.playerview[SP].stats[STAT_ACTIVEWEAPON]; + vars.droppedweapon = pv->stats[STAT_ACTIVEWEAPON]; vars.deathtrigger_time = realtime; strcpy (vars.lastdeathloc, Macro_Location()); @@ -3453,9 +3463,9 @@ void TP_StatChanged (int stat, int value) vars.last_numenemies = vars.numenemies; vars.last_numfriendlies = vars.numfriendlies; - if (!cl.spectator && CountTeammates()) + if (!pv->spectator && CountTeammates()) { - if (cl.teamfortress && (cl.playerview[SP].stats[STAT_ITEMS] & (IT_KEY1|IT_KEY2)) + if (cl.teamfortress && (pv->stats[STAT_ITEMS] & (IT_KEY1|IT_KEY2)) && Cmd_AliasExist("f_flagdeath", RESTRICT_LOCAL)) TP_ExecTrigger ("f_flagdeath", false); else @@ -3469,14 +3479,14 @@ void TP_StatChanged (int stat, int value) i = value &~ vars.items; if (i & (IT_KEY1|IT_KEY2)) { - if (cl.teamfortress && !cl.spectator) + if (cl.teamfortress && !pv->spectator) { ExecTookTrigger_ (tp_name_flag.string, it_flag, - cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playerview[SP].playernum].origin); + cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[pv->playernum].origin); } } - if (!cl.spectator && cl.teamfortress && ~value & vars.items & (IT_KEY1|IT_KEY2)) + if (!pv->spectator && cl.teamfortress && ~value & vars.items & (IT_KEY1|IT_KEY2)) { vars.lastdrop_time = realtime; strcpy (vars.lastdroploc, Macro_Location()); @@ -3487,9 +3497,9 @@ void TP_StatChanged (int stat, int value) } else if (stat == STAT_ACTIVEWEAPON) { - if (cl.playerview[SP].stats[STAT_ACTIVEWEAPON] != vars.activeweapon) + if (pv->stats[STAT_ACTIVEWEAPON] != vars.activeweapon) TP_ExecTrigger ("f_weaponchange", false); - vars.activeweapon = cl.playerview[SP].stats[STAT_ACTIVEWEAPON]; + vars.activeweapon = pv->stats[STAT_ACTIVEWEAPON]; } #endif vars.stat_framecounts[stat] = cls.framecount; @@ -3709,6 +3719,7 @@ void TP_Init (void) qboolean TP_SuppressMessage(char *buf) { char *s; + playerview_t *pv = &cl.playerview[SP]; for (s = buf; *s && *s != 0x7f; s++) ; @@ -3717,7 +3728,7 @@ qboolean TP_SuppressMessage(char *buf) { *s++ = '\n'; *s++ = 0; - return (!cls.demoplayback && !cl.spectator && *s - 'A' == cl.playerview[SP].playernum); + return (!cls.demoplayback && !pv->spectator && *s - 'A' == pv->playernum); } return false; } @@ -3728,6 +3739,7 @@ void CL_Say (qboolean team, char *extra) { extern cvar_t cl_fakename; char text[2048], sendtext[2048], *s; + playerview_t *pv = &cl.playerview[SP]; if (Cmd_Argc() < 2) { @@ -3748,7 +3760,7 @@ void CL_Say (qboolean team, char *extra) Q_strncpyz (text, TP_ParseFunChars (s), sizeof(text)); sendtext[0] = 0; - if (team && !cl.spectator && cl_fakename.string[0] && + if (team && !pv->spectator && cl_fakename.string[0] && !strchr(s, '\x0d') /* explicit $\ in message overrides cl_fakename */) { char buf[1024]; @@ -3803,7 +3815,7 @@ void CL_Say (qboolean team, char *extra) if (team) plrflags |= 2; - CL_PrintChat(&cl.players[cl.playerview[SP].playernum], text, plrflags); + CL_PrintChat(&cl.players[pv->playernum], text, plrflags); } //strip out the extra markup @@ -3831,7 +3843,7 @@ void CL_Say (qboolean team, char *extra) *d = '\0'; //mark the message so that we ignore it when we get the echo. - strlcat (sendtext, va("\x7f!%c", 'A'+cl.playerview[SP].playernum), sizeof(sendtext)); + strlcat (sendtext, va("\x7f!%c", 'A'+pv->playernum), sizeof(sendtext)); } #ifdef Q3CLIENT diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 43e2820d..73c316f3 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // release version #define FTE_VER_MAJOR 1 -#define FTE_VER_MINOR 5 +#define FTE_VER_MINOR 6 #if defined(__APPLE__) && defined(__MACH__) #define MACOSX @@ -281,8 +281,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7) // #define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140) #define NQPROT //server and client are capable of using quake1/netquake protocols. (qw is still prefered. uses the command 'nqconnect') - #define WEBSERVER //http/ftp servers - #define WEBCLIENT //http/ftp clients. +// #define WEBSERVER //http server + #define FTPSERVER //ftp server + #define WEBCLIENT //http clients. #define RUNTIMELIGHTING //calculate lit/lux files the first time the map is loaded and doesn't have a loadable lit. // #define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm. #define CL_MASTER //query master servers and stuff for a dynamic server listing. diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 17322a08..926cbefd 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -1100,7 +1100,7 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo if (flags & ZFL_DEFLATED) { #ifdef ZIPCRYPT - //FIXME: Cvar_Get is not threadsafe. + //FIXME: Cvar_Get is not threadsafe, and nor is accessing the cvar... char *password = (flags & ZFL_WEAKENCRYPT)?Cvar_Get("fs_zip_password", "thisispublic", 0, "Filesystem")->string:NULL; #else char *password = NULL; diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 9f46c975..15ba27de 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -95,9 +95,9 @@ typedef int (VARGS gnutls_certificate_verify_function)(gnutls_session_t session) #else #include #if GNUTLS_VERSION_MAJOR >= 3 && defined(HAVE_DTLS) -#include + #include #else -#undef HAVE_DTLS + #undef HAVE_DTLS #endif #define gnutls_connection_end_t unsigned int diff --git a/engine/common/plugin.c b/engine/common/plugin.c index b0ae2fc9..137a7d52 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -1866,10 +1866,11 @@ int Plug_ConnectionlessClientPacket(char *buffer, int size) void Plug_SBar(playerview_t *pv) { #ifdef QUAKEHUD - extern qboolean sb_showscores, sb_showteamscores; + #define sb_showscores pv->sb_showscores + #define sb_showteamscores pv->sb_showteamscores #else -#define sb_showscores 0 -#define sb_showteamscores 0 + #define sb_showscores 0 + #define sb_showteamscores 0 #endif plugin_t *oc=currentplug; @@ -1877,7 +1878,7 @@ void Plug_SBar(playerview_t *pv) int cleared = false; int hudmode; - if (!Sbar_ShouldDraw()) + if (!Sbar_ShouldDraw(pv)) { SCR_TileClear (0); return; @@ -1935,9 +1936,9 @@ void Plug_SBar(playerview_t *pv) } } - if (!(ret & 2) && pv == cl.playerview) + if (!(ret & 2)) { - Sbar_DrawScoreboard(); + Sbar_DrawScoreboard(pv); } diff --git a/engine/d3d/d3d11_image.c b/engine/d3d/d3d11_image.c index c80add0d..71434d49 100644 --- a/engine/d3d/d3d11_image.c +++ b/engine/d3d/d3d11_image.c @@ -279,10 +279,15 @@ void D3D11_UploadLightmap(lightmapinfo_t *lm) mips.mip[0].width = lm->width; mips.mip[0].height = lm->height; mips.mip[0].datasize = lm->width*lm->height*4; - if (lightmap_bgra) + switch (lightmap_fmt) + { + case TF_BGRA32: mips.encoding = PTI_BGRX8; - else - mips.encoding = PTI_RGBX8; + break; + case TF_RGBA32: + mips.encoding = PTI_RGBX8; + break; + } mips.mipcount = 1; D3D11_LoadTextureMips(tex, &mips); tex->width = lm->width; diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index 7fe9dd8a..fdb64f30 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -886,7 +886,7 @@ qboolean D3D8_VID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short * IDirect3DDevice8_SetGammaRamp(pD3DDev8, D3DSGR_NO_CALIBRATION, (D3DGAMMARAMP *)ramps); return true; } -static char *(D3D8_VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt) +static char *(D3D8_VID_GetRGBInfo) (int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt) { //FIXME: no screenshots return NULL; @@ -921,6 +921,7 @@ static char *(D3D8_VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enu *fmt = TF_RGB24; // read surface rect and convert 32 bgra to 24 rgb and flip + //FIXME: shouldn't need to convert+flip any more. just return it as upside-down bgra or whatever c = desc.Width*desc.Height*3; p = (qbyte *)rect.pBits; @@ -935,6 +936,7 @@ static char *(D3D8_VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enu p += rect.Pitch; } + *bytestride = desc.Width*3; *truevidwidth = desc.Width; *truevidheight = desc.Height; } diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index 8d211cba..aa0ce7b1 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -67,6 +67,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iqm", "..\..\iqm\iqm.vcproj EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmake", "gmake.vcproj", "{0B1B2549-24DE-4FF2-844B-7A93ED5CF919}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "terrorgen", "..\..\plugins\terrorgen\terrorgen.vcproj", "{1E65A0D3-3371-4602-A69C-53BA389FFBD9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution D3DDebug|Win32 = D3DDebug|Win32 @@ -1094,6 +1096,48 @@ Global {0B1B2549-24DE-4FF2-844B-7A93ED5CF919}.VkRelease|Win32.ActiveCfg = Release|Win32 {0B1B2549-24DE-4FF2-844B-7A93ED5CF919}.VkRelease|Win32.Build.0 = Release|Win32 {0B1B2549-24DE-4FF2-844B-7A93ED5CF919}.VkRelease|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.D3DDebug|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.D3DDebug|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.D3DDebug|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.D3DRelease|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.D3DRelease|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.D3DRelease|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Debug|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Debug|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Debug|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.GLDebug|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.GLDebug|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.GLDebug|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.GLRelease|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.GLRelease|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.GLRelease|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MDebug|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MDebug|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MDebug|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MinGLDebug|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MinGLDebug|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MinGLDebug|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MinGLRelease|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MinGLRelease|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MinGLRelease|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MRelease|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MRelease|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.MRelease|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Release Dedicated Server|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Release Dedicated Server|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Release|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Release|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.Release|x64.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.VkDebug|Win32.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.VkDebug|Win32.Build.0 = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.VkDebug|x64.ActiveCfg = Debug|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.VkRelease|Win32.ActiveCfg = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.VkRelease|Win32.Build.0 = Release|Win32 + {1E65A0D3-3371-4602-A69C-53BA389FFBD9}.VkRelease|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1118,6 +1162,7 @@ Global {F756A3D2-025A-43D4-9829-4074753B774B} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} {909E9AE0-0617-469C-954E-1ED09367F90E} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} {E6CDA919-628B-45BF-A5DB-FB55179D6443} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + {1E65A0D3-3371-4602-A69C-53BA389FFBD9} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution AMDCaProjectFile = C:\Games\Quake\wip\engine\dotnet2005\CodeAnalyst\ftequake.caw diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 2373e308..cb4b28f3 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -4985,20 +4985,15 @@ static void BE_UpdateLightmaps(void) int lmidx; int glformat, gltype; int internalformat = GL_RGBA; - switch (lightmap_bytes) + switch (lightmap_fmt) { - case 4: - glformat = lightmap_bgra?GL_BGRA_EXT:GL_RGBA; - gltype = GL_UNSIGNED_INT_8_8_8_8_REV; - break; - case 3: - glformat = lightmap_bgra?GL_BGR_EXT:GL_RGB; - gltype = GL_UNSIGNED_BYTE; - break; - default: - glformat = GL_LUMINANCE; - gltype = GL_UNSIGNED_BYTE; - break; + case TF_INVALID: return; + default: Sys_Error("Bad lightmap_fmt\n"); return; + case TF_BGRA32: glformat = GL_BGRA_EXT; gltype = GL_UNSIGNED_INT_8_8_8_8_REV; break; +// case TF_RGBA32: glformat = GL_RGBA; gltype = GL_UNSIGNED_INT_8_8_8_8_REV; break; +// case TF_BGR24: glformat = GL_BGR_EXT; gltype = GL_UNSIGNED_BYTE; break; + case TF_RGB24: glformat = GL_RGB; gltype = GL_UNSIGNED_BYTE; break; + case TF_LUM8: glformat = GL_LUMINANCE;gltype = GL_UNSIGNED_BYTE; break; } if (gl_config.gles) internalformat = glformat; @@ -5025,16 +5020,12 @@ static void BE_UpdateLightmaps(void) GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexImage2D(GL_TEXTURE_2D, 0, internalformat, - lm->width, lm->height, 0, glformat, gltype, - lm->lightmaps); + qglTexImage2D(GL_TEXTURE_2D, 0, internalformat, lm->width, lm->height, 0, glformat, gltype, lm->lightmaps); } else { GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture); - qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, t, - lm->width, b-t, glformat, gltype, - lm->lightmaps+t *lm->width*lightmap_bytes); + qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, t, lm->width, b-t, glformat, gltype, lm->lightmaps+t*lm->width*lightmap_bytes); } lm->modified = false; lm->rectchange.l = lm->width; diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 9a448cbd..700a3e65 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -158,11 +158,14 @@ static qboolean QDECL Terr_InitLightmap(hmsection_t *s, qboolean initialise) if (s->lightmap < 0) { struct lmsect_s *lms; - if (!hm->unusedlmsects) + Sys_LockMutex(com_resourcemutex); + while (!hm->unusedlmsects) { int lm; int i; + Sys_UnlockMutex(com_resourcemutex); lm = Surf_NewLightmaps(1, SECTTEXSIZE*LMCHUNKS, SECTTEXSIZE*LMCHUNKS, false); + Sys_LockMutex(com_resourcemutex); for (i = 0; i < LMCHUNKS*LMCHUNKS; i++) { lms = BZ_Malloc(sizeof(*lms)); @@ -184,6 +187,7 @@ static qboolean QDECL Terr_InitLightmap(hmsection_t *s, qboolean initialise) hm->numunusedlmsects--; hm->numusedlmsects++; + Sys_UnlockMutex(com_resourcemutex); Z_Free(lms); initialise = true; @@ -2070,6 +2074,9 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean light int cx, cy; int sx, sy; + COM_WorkerFullSync(); //should probably be inside the caller or something. make sure there's no loaders still loading lightmaps when lightmaps are going to be nuked. + + validatelinks(&hm->recycle); // Con_Printf("PrePurge: %i lm chunks used, %i unused\n", hm->numusedlmsects, hm->numunusedlmsects); @@ -2177,6 +2184,7 @@ void Terr_FreeModel(model_t *mod) hm->entities = n; } Sys_DestroyMutex(hm->entitylock); + Z_Free(hm->seed); Z_Free(hm); mod->terrain = NULL; } @@ -3015,6 +3023,8 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) else culldist = 999999999999999.f; + if (culldist < hm->maxdrawdist) + culldist = hm->maxdrawdist; if (culldist > r_refdef.maxdist && r_refdef.maxdist>0) culldist = r_refdef.maxdist; @@ -4828,9 +4838,11 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g G_FLOAT(OFS_RETURN) = 0; - if (!mod || !mod->terrain) + if (!mod) + return; + if (!mod->terrain) { - if (mod && mod->loadstate == MLS_LOADING) + if (mod->loadstate == MLS_LOADING) COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); } if (mod->loadstate != MLS_LOADED) @@ -5258,6 +5270,25 @@ void Terr_ParseEntityLump(model_t *mod, heightmap_t *heightmap) heightmap->culldistance = atof(value); heightmap->culldistance *= heightmap->culldistance; } + else if (!strcmp("drawdist", key)) + heightmap->maxdrawdist = atof(value); + else if (!strcmp("seed", key)) + { + Z_Free(heightmap->seed); + heightmap->seed = Z_StrDup(value); + } + else if (!strcmp("exterior", key)) + { + heightmap->legacyterrain = false; + if (!strcmp(value, "empty") || !strcmp(value, "")) + heightmap->exteriorcontents = FTECONTENTS_EMPTY; + else if (!strcmp(value, "sky")) + heightmap->exteriorcontents = FTECONTENTS_SKY; + else if (!strcmp(value, "lava")) + heightmap->exteriorcontents = FTECONTENTS_LAVA; + else //if (!strcmp(value, "solid")) + heightmap->exteriorcontents = FTECONTENTS_SOLID; + } else if (!strcmp("skybox", key)) Q_strncpyz(heightmap->skyname, value, sizeof(heightmap->skyname)); else if (!strcmp("tiles", key)) @@ -5569,69 +5600,65 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) in = br->faces[j].lightdata; out = lm->lightmaps + (br->faces[j].lmbase[1] * lm->width + br->faces[j].lmbase[0]) * lightmap_bytes; - if (lightmap_bytes == 4) + switch(lightmap_fmt) { - if (lightmap_bgra) + default: + Sys_Error("Bad lightmap_fmt\n"); + break; + case TF_BGRA32: + for (t = 0; t < br->faces[j].lmextents[1]; t++) { - for (t = 0; t < br->faces[j].lmextents[1]; t++) + for (s = 0; s < br->faces[j].lmextents[0]; s++) { - for (s = 0; s < br->faces[j].lmextents[0]; s++) - { - *out++ = in[2]; - *out++ = in[1]; - *out++ = in[0]; - *out++ = 0xff; - in+=3; - } - out += (lm->width - br->faces[j].lmextents[0]) * 4; + *out++ = in[2]; + *out++ = in[1]; + *out++ = in[0]; + *out++ = 0xff; + in+=3; } + out += (lm->width - br->faces[j].lmextents[0]) * 4; } - else + break; + /*case TF_RGBA32: + for (t = 0; t < br->faces[j].lmextents[1]; t++) { - for (t = 0; t < br->faces[j].lmextents[1]; t++) + for (s = 0; s < br->faces[j].lmextents[0]; s++) { - for (s = 0; s < br->faces[j].lmextents[0]; s++) - { - *out++ = in[0]; - *out++ = in[1]; - *out++ = in[2]; - *out++ = 0xff; - in+=3; - } - out += (lm->width - br->faces[j].lmextents[0]) * 4; + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + *out++ = 0xff; + in+=3; } + out += (lm->width - br->faces[j].lmextents[0]) * 4; } - } - else if (lightmap_bytes == 3) - { - if (lightmap_bgra) + break;*/ + /*case TF_BGR24: + for (t = 0; t < br->faces[j].lmextents[1]; t++) { - for (t = 0; t < br->faces[j].lmextents[1]; t++) + for (s = 0; s < br->faces[j].lmextents[0]; s++) { - for (s = 0; s < br->faces[j].lmextents[0]; s++) - { - *out++ = in[2]; - *out++ = in[1]; - *out++ = in[0]; - in+=3; - } - out += (lm->width - br->faces[j].lmextents[0]) * 3; + *out++ = in[2]; + *out++ = in[1]; + *out++ = in[0]; + in+=3; } + out += (lm->width - br->faces[j].lmextents[0]) * 3; } - else + break;*/ + case TF_RGB24: + for (t = 0; t < br->faces[j].lmextents[1]; t++) { - for (t = 0; t < br->faces[j].lmextents[1]; t++) + for (s = 0; s < br->faces[j].lmextents[0]; s++) { - for (s = 0; s < br->faces[j].lmextents[0]; s++) - { - *out++ = in[0]; - *out++ = in[1]; - *out++ = in[2]; - in+=3; - } - out += (lm->width - br->faces[j].lmextents[0]) * 3; + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + in+=3; } + out += (lm->width - br->faces[j].lmextents[0]) * 3; } + break; } } } @@ -6884,7 +6911,7 @@ void Terr_WriteMapFile(vfsfile_t *file, model_t *mod) heightmap_t *hm; hm = mod->terrain; - if (hm && hm->exteriorcontents != FTECONTENTS_EMPTY) + if (hm && hm->legacyterrain) VFS_WRITE(file, "terrain\n", 8); start = entities; @@ -7355,7 +7382,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize) { - int exterior = FTECONTENTS_SOLID; + int legacyterrain; heightmap_t *hm; char token[MAX_QPATH]; @@ -7364,9 +7391,12 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize src = COM_ParseOut(buffer, token, sizeof(token)); if (!strcmp(token, "terrain")) + { + legacyterrain = true; buffer = src; + } else if (!strcmp(token, "{")) - exterior = FTECONTENTS_EMPTY; + legacyterrain = false; else { Con_Printf(CON_ERROR "%s wasn't terrain map\n", mod->name); //shouldn't happen @@ -7390,7 +7420,7 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize hm->entitylock = Sys_CreateMutex(); hm->sectionsize = sectsize; - if (exterior) + if (legacyterrain) { hm->firstsegx = -1; hm->firstsegy = -1; @@ -7404,7 +7434,9 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize hm->maxsegx = 0; hm->maxsegy = 0; } - hm->exteriorcontents = exterior; //sky outside the map + hm->legacyterrain = legacyterrain; + if (legacyterrain) + hm->exteriorcontents = FTECONTENTS_SOLID; //sky outside the map Terr_ParseEntityLump(mod, hm); @@ -7528,44 +7560,56 @@ void Mod_Terrain_Create_f(void) char *watername; char *groundheight; char *waterheight; + char *seed; vfsfile_t *file; model_t mod; memset(&mod, 0, sizeof(mod)); if (Cmd_Argc() < 2) { - Con_Printf("%s: NAME \"DESCRIPTION\" SKYNAME DEFAULTGROUNDTEX DEFAULTHEIGHT DEFAULTWATER DEFAULTWATERHEIGHT\nGenerates a fresh maps/foo.hmp file. You may wish to edit it with notepad later to customise it. You will need csaddon.dat in order to edit the actual terrain.\n", Cmd_Argv(0)); + Con_Printf("%s: NAME \"DESCRIPTION\" SKYNAME DEFAULTGROUNDTEX DEFAULTHEIGHT DEFAULTWATER DEFAULTWATERHEIGHT seed\nGenerates a fresh maps/foo.hmp file. You may wish to edit it with notepad later to customise it. You will need csaddon.dat in order to edit the actual terrain.\n", Cmd_Argv(0)); return; } mname = va("maps/%s.hmp", Cmd_Argv(1)); mapdesc = Cmd_Argv(2); if (!*mapdesc) mapdesc = Cmd_Argv(1); - skyname = Cmd_Argv(3); if (!*skyname) skyname = "sky1"; - groundname = Cmd_Argv(4); if (!*groundname) groundname = "default"; - groundheight = Cmd_Argv(5); if (!*groundheight) groundheight = "0"; - watername = Cmd_Argv(6); if (!*watername) watername = ""; - waterheight = Cmd_Argv(7); if (!*waterheight) waterheight = "1024"; + skyname = Cmd_Argv(3); + groundname = Cmd_Argv(4); + groundheight = Cmd_Argv(5); + watername = Cmd_Argv(6); + waterheight = Cmd_Argv(7); + seed = Cmd_Argv(7); Mod_SetEntitiesString(&mod, va( "{\n" "classname \"worldspawn\"\n" "message \"%s\"\n" - "_sky sky1\n" + "_sky \"%s\"\n" "_fog 0.02\n" - "_segmentsize 1024\n" + "_maxdrawdist 0 /*overrides fog distance (if greater)*/\n" + "_segmentsize 1024 /*how big each section is. this affects texturing and resolutions*/\n" "_minxsegment -2048\n" "_minysegment -2048\n" "_maxxsegment 2048\n" "_maxysegment 2048\n" - "//_defaultgroundtexture \"city4_2\"\n" - "//_defaultwatertexture \"*water2\"\n" - "//_defaultgroundheight -1024\n" - "//_defaultwaterheight 0\n" //hurrah, sea level. + "_seed \"%s\" /*for auto-gen plugins*/\n" + "_exterior solid\n" + "_defaultgroundtexture \"%s\"\n" + "_defaultgroundheight \"%s\"\n" + "_defaultwatertexture \"%s\"\n" + "_defaultwaterheight \"%s\"\n" //hurrah, sea level. // "_tiles 64 64 8 8\n" "}\n" "{\n" "classname info_player_start\n" - "origin \"0 0 1024\"\n" + "origin \"0 0 1024\" /*EDITME*/\n" "}\n" - , Cmd_Argv(2)), true); + "/*ADD EXTRA ENTITIES!*/\n" + , mapdesc + ,*skyname?skyname:"terrsky1", seed + ,*groundname?groundname:"ground1_1" + ,*groundheight?groundheight:"-1024" + ,*watername?watername:"*water2" + ,*waterheight?waterheight:"0" + ), true); mod.type = mod_heightmap; mod.terrain = hm = Z_Malloc(sizeof(*hm)); @@ -7724,7 +7768,11 @@ void Mod_Terrain_Reload_f(void) terrainfuncs_t *QDECL Terr_GetTerrainFuncs(void) { +#ifdef SERVERONLY + return NULL; //dedicated server builds have all the visual stuff stripped, which makes APIs too inconsistent. Generate then save. Or fix up the API... +#else return &terrainfuncs; +#endif } void Terr_Init(void) diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 9d767702..66e11695 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1422,7 +1422,8 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) // Mod_LoadModelWorker(mod, MLV_WARN, 0); // else if (verbose == MLV_ERROR || verbose == MLV_WARNSYNC) - COM_AddWork(WG_MAIN, Mod_LoadModelWorker, mod, NULL, verbose, 0); + Mod_LoadModelWorker(mod, NULL, verbose, 0); +// COM_AddWork(WG_MAIN, Mod_LoadModelWorker, mod, NULL, verbose, 0); else COM_AddWork(WG_LOADER, Mod_LoadModelWorker, mod, NULL, verbose, 0); } diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index 97f5171b..76e5b0cd 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -546,23 +546,14 @@ void GLBE_UploadAllLightmaps(void) qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - switch (lightmap_bytes) + switch(lightmap_fmt) //bgra32, rgba32, rgb24, lum8 { - case 4: - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - lm->width, lm->height, 0, (lightmap_bgra?GL_BGRA_EXT:GL_RGBA), GL_UNSIGNED_INT_8_8_8_8_REV, - lightmap[i]->lightmaps); - break; - case 3: - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - lm->width, lm->height, 0, (lightmap_bgra?GL_BGR_EXT:GL_RGB), GL_UNSIGNED_BYTE, - lightmap[i]->lightmaps); - break; - case 1: - qglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, - lm->width, lm->height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, - lightmap[i]->lightmaps); - break; + default: Sys_Error("Bad lightmap_fmt\n"); break; + case TF_BGRA32: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lm->width, lm->height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; +// case TF_RGBA32: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lm->width, lm->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,lightmap[i]->lightmaps); break; +// case TF_BGR24: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, lm->width, lm->height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; + case TF_RGB24: qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, lm->width, lm->height, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; + case TF_LUM8: qglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, lm->width, lm->height, 0, GL_LUMINANCE,GL_UNSIGNED_BYTE, lightmap[i]->lightmaps); break; } //for completeness. lm->lightmap_texture->width = lm->width; diff --git a/engine/gl/gl_terrain.h b/engine/gl/gl_terrain.h index 93879838..8024b0b6 100644 --- a/engine/gl/gl_terrain.h +++ b/engine/gl/gl_terrain.h @@ -287,23 +287,28 @@ typedef struct typedef struct heightmap_s { char path[MAX_QPATH]; - char skyname[MAX_QPATH]; - char groundshadername[MAX_QPATH]; - char defaultwatershader[MAX_QPATH]; //typically the name of the ocean or whatever. - unsigned int culldistance; - qboolean forcedefault; - float defaultwaterheight; - float defaultgroundheight; - char defaultgroundtexture[MAX_QPATH]; - int firstsegx, firstsegy; - int maxsegx, maxsegy; //tex/cull sections + char skyname[MAX_QPATH]; //name of the skybox + char groundshadername[MAX_QPATH]; //this is the shader we're using to draw the terrain itself. you could use other shaders here, for eg debugging or stylised weirdness. + unsigned int culldistance; //entities will be culled if they're this far away (squared distance + float maxdrawdist; //maximum view distance. extends view if larger than fog implies. + + unsigned char *seed; //used by whatever terrain generator. + qboolean forcedefault; //sections that cannot be loaded/generated will receive default values for stuff. + char defaultgroundtexture[MAX_QPATH];//texture used for defaulted sections + char defaultwatershader[MAX_QPATH]; //shader used for defaulted sections that have heights beneath defaultwaterheight. + float defaultwaterheight; //water height. if you want your islands to be surrounded by water. + float defaultgroundheight; //defaulted sections will have a z plane this high + + int firstsegx, firstsegy; //min bounds of the terrain, in sections + int maxsegx, maxsegy; //max bounds of the terrain, in sections float sectionsize; //each section is this big, in world coords hmcluster_t *cluster[MAXCLUSTERS*MAXCLUSTERS]; shader_t *skyshader; shader_t *shader; mesh_t skymesh; mesh_t *askymesh; - unsigned int exteriorcontents; + qboolean legacyterrain; //forced exterior=SOLID + unsigned int exteriorcontents; //contents type outside of the terrain sections area (.map should be empty, while terrain will usually block). unsigned int loadingsections; //number of sections currently being loaded. avoid loading extras while non-zero. size_t traceseq; size_t drawnframe; diff --git a/engine/http/ftpclient.c b/engine/http/ftpclient.c index 45df1deb..855d3069 100644 --- a/engine/http/ftpclient.c +++ b/engine/http/ftpclient.c @@ -1,6 +1,6 @@ #include "quakedef.h" -#if 0//def WEBCLIENT +#ifdef FTPCLIENT #include "iweb.h" diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index 0987bb88..8fd49836 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -8,7 +8,7 @@ #endif #endif -#ifdef WEBSERVER +#ifdef FTPSERVER #include "iweb.h" diff --git a/engine/http/iweb.h b/engine/http/iweb.h index 2176d342..952a4c6c 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -1,7 +1,9 @@ #ifndef IWEB_H__ #define IWEB_H__ -#ifdef WEBSERVER +qboolean SV_AllowDownload (const char *name); + +#if defined(WEBSERVER) || defined(FTPSERVER) #ifdef WEBSVONLY //When running standalone @@ -34,8 +36,6 @@ struct sockaddr; struct sockaddr_qstorage; int NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s); -qboolean SV_AllowDownload (const char *name); - typedef qboolean iwboolean; diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index d4875de4..b84a44af 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -1,6 +1,6 @@ #include "quakedef.h" -#ifdef WEBSERVER +#if defined(WEBSERVER) || defined(FTPSERVER) #include "iweb.h" #include "netinc.h" @@ -503,15 +503,18 @@ IWEBFILE *IWebFOpenRead(char *name) //fread(name, "rb"); #else +#if defined(WEBSERVER) || defined(FTPSERVER) +static cvar_t sv_readlevel = CVAR("sv_readlevel", "0"); //default to allow anyone +static cvar_t sv_writelevel = CVARD("sv_writelevel", "35", "Specifies the required trust level at which user accounts may write to the user-specific subdir of /uploads/USERNAME/*. If blank, then no uploads are permitted"); //allowed to write to uploads/uname +static cvar_t sv_fulllevel = CVARD("sv_fulllevel", "51", "User accounts with an access level greater than this may write anywhere, including the gamedir. Note that setting this low is increadibly risky. An empty value will be understood to never give this permission."); //allowed to write anywhere, replace any file... #ifdef WEBSERVER -cvar_t ftpserver = CVAR("sv_ftp", "0"); -cvar_t ftpserver_port = CVAR("sv_ftp_port", "21"); -cvar_t httpserver = CVAR("sv_http", "0"); -cvar_t httpserver_port = CVAR("sv_http_port", "80"); -cvar_t sv_readlevel = CVAR("sv_readlevel", "0"); //default to allow anyone -cvar_t sv_writelevel = CVAR("sv_writelevel", "35"); //allowed to write to uploads/uname -cvar_t sv_fulllevel = CVAR("sv_fulllevel", "51"); //allowed to write anywhere, replace any file... -cvar_t sv_ftp_port_range = CVARD("sv_ftp_port_range", "0", "Specifies the port range for the server to create listening sockets for 'active' ftp connections, to work around NAT/firewall issues.\nMost FTP clients should use passive connections, but there's still some holdouts like windows."); +static cvar_t httpserver = CVAR("sv_http", "0"); +static cvar_t httpserver_port = CVAR("sv_http_port", "80"); +#endif +#ifdef FTPSERVER +static cvar_t ftpserver = CVAR("sv_ftp", "0"); +static cvar_t ftpserver_port = CVAR("sv_ftp_port", "21"); +static cvar_t sv_ftp_port_range = CVARD("sv_ftp_port_range", "0", "Specifies the port range for the server to create listening sockets for 'active' ftp connections, to work around NAT/firewall issues.\nMost FTP clients should use passive connections, but there's still some holdouts like windows."); int IWebGetSafeListeningPort(void) { @@ -533,6 +536,7 @@ int IWebGetSafeListeningPort(void) return base + (sequence++ % (range+1-base)); } #endif +#endif //this file contains functions called from each side. @@ -680,9 +684,9 @@ int IWebAuthorize(const char *name, const char *password) Rank_GetPlayerInfo(id, &info); - if (info.s.trustlevel >= sv_fulllevel.value) + if (*sv_fulllevel.string && info.s.trustlevel >= sv_fulllevel.value) return IWEBACC_READ | IWEBACC_WRITE | IWEBACC_FULL; //allowed to read and write anywhere to the quake filesystem - if (info.s.trustlevel >= sv_writelevel.value) + if (*sv_writelevel.string && info.s.trustlevel >= sv_writelevel.value) return IWEBACC_READ | IWEBACC_WRITE; //allowed to read anywhere write to specific places if (info.s.trustlevel >= sv_readlevel.value) return IWEBACC_READ; //read only anywhere diff --git a/engine/http/webgen.c b/engine/http/webgen.c index ef5257cc..f10d3aa5 100644 --- a/engine/http/webgen.c +++ b/engine/http/webgen.c @@ -1,11 +1,11 @@ #include "quakedef.h" -#ifdef WEBSERVER +#if defined(WEBSERVER) || defined(FTPSERVER) #include "iweb.h" -#ifdef CLIENTONLY -vfsfile_t *IWebGenerateFile(char *name) +#if defined(CLIENTONLY) || !defined(WEBSERVER) +vfsfile_t *IWebGenerateFile(const char *name, const char *content, int contentlength) { return NULL; } diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index ae01f41b..27a5e55e 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -703,13 +703,11 @@ HMODULE scintilla; pbool resetprogssrc; //progs.src was changed, reload project info. - HWND mainwindow; HWND gamewindow; HWND mdibox; HWND watches; HWND optionsmenu; -HWND outputwindow; HWND outputbox; HWND projecttree; HWND search_name; @@ -717,6 +715,240 @@ HWND search_gotodef; HWND search_grep; HACCEL accelerators; + +//our splitter... +#define SPLITTER_SIZE 4 +static struct splits_s +{ + HWND wnd; + HWND splitter; + int minsize; + int cury; + int cursize; + float frac; + +} *splits; +static size_t numsplits; +static RECT splitterrect; + +static struct splits_s *SplitterGet(HWND id) +{ + size_t s; + for (s = 0; s < numsplits; s++) + { + if (splits[s].wnd == id) + return &splits[s]; + } + return NULL; +} +static int SplitterShrinkPrior(size_t s, int px) +{ + int found = 0; + int avail; + for (; px && s > 0; s--) + { + avail = splits[s].cursize - splits[s].minsize; + if (avail > px) + avail = px; + + splits[s].cursize -= avail; + found += avail; + px -= avail; + } + + if (px) + { + avail = splits[0].cursize - splits[0].minsize; + if (avail > px) + avail = px; + + splits[0].cursize -= avail; + found += avail; + px -= avail; + } + + return found; +} +static SplitterShrinkNext(size_t s, int px) +{ + int found = 0; + int avail; + for (; px && s < numsplits; s++) + { + avail = splits[s].cursize - splits[s].minsize; + if (avail > px) + avail = px; + + splits[s].cursize -= avail; + found += avail; + px -= avail; + } + return found; +} +static void SplitterUpdate(void); +static LRESULT CALLBACK SplitterWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + size_t s; + PAINTSTRUCT ps; + RECT rect; + int y; + int cascade; + switch(message) + { + case WM_LBUTTONDOWN: + SetCapture(hWnd); + return TRUE; + case WM_MOUSEMOVE: + if (wParam & MK_LBUTTON) + if (GetCapture() == hWnd) + goto doresize; + return true; + case WM_LBUTTONUP: + ReleaseCapture(); + doresize: + y = GET_Y_LPARAM(lParam); + GetClientRect(hWnd, &rect); + y = y - rect.top - SPLITTER_SIZE/2; + for (s = 1; s < numsplits; s++) + { + if (splits[s].splitter == hWnd) + { + cascade = 0; + if (y < 0) + splits[s].cursize += SplitterShrinkPrior(s-1, -y); + else + splits[s-1].cursize += SplitterShrinkNext(s, y); + SplitterUpdate(); + break; + } + } + return TRUE; + case WM_PAINT: + BeginPaint(hWnd,(LPPAINTSTRUCT)&ps); + EndPaint(hWnd,(LPPAINTSTRUCT)&ps); + return TRUE; + default: + return DefWindowProc(hWnd,message,wParam,lParam); + } +} +static void SplitterUpdate(void) +{ + int y = 0; + size_t s; + if (!numsplits) + return; + + //figure out the total height + for (s = numsplits; s-- > 0; ) + { + y += splits[s].cursize; + } + y = splitterrect.bottom-splitterrect.top; + + //now figure out their positions relative to that + for (s = numsplits; s-- > 1; ) + { + y -= splits[s].cursize; + splits[s].cury = y; + y -= SPLITTER_SIZE; + } + + splits[0].cursize = y; + splits[0].cury = 0; + if (splits[0].cursize < splits[0].minsize) + splits[0].cursize += SplitterShrinkNext(1, splits[0].minsize-splits[0].cursize); + + for (s = 0; s < numsplits; s++) + { + if (s) + { + if (!splits[s].splitter) + { + WNDCLASSA wclass; + wclass.style = 0; + wclass.lpfnWndProc = SplitterWndProc; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + wclass.hInstance = ghInstance; + wclass.hIcon = NULL; + wclass.hCursor = LoadCursor(0, IDC_SIZENS); + wclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); + wclass.lpszMenuName = NULL; + wclass.lpszClassName = "splitter"; + RegisterClassA(&wclass); + splits[s].splitter = CreateWindowExA(0, wclass.lpszClassName, "", WS_CHILD|WS_VISIBLE, splitterrect.left, splitterrect.top+splits[s].cury-SPLITTER_SIZE, splitterrect.right-splitterrect.left, SPLITTER_SIZE, mainwindow, NULL, ghInstance, NULL); + } + else + SetWindowPos(splits[s].splitter, HWND_TOP, splitterrect.left, splitterrect.top+splits[s].cury-SPLITTER_SIZE, splitterrect.right-splitterrect.left, SPLITTER_SIZE, SWP_NOZORDER); + } + else + { + if (splits[s].splitter) + { + DestroyWindow(splits[s].splitter); + splits[s].splitter = NULL; + } + } + SetWindowPos(splits[s].wnd, HWND_TOP, splitterrect.left, splitterrect.top+splits[s].cury, splitterrect.right-splitterrect.left, splits[s].cursize, SWP_NOZORDER); + } +} +static void SplitterFocus(HWND w, int minsize) +{ + struct splits_s *s = SplitterGet(w); + if (s) + { + if (s->cursize < minsize) + { + s->cursize += SplitterShrinkPrior(s-splits-1, (minsize-s->cursize)/2); + if (s->cursize < minsize) + s->cursize += SplitterShrinkNext(s-splits+1, minsize-s->cursize); + if (s->cursize < minsize) + s->cursize += SplitterShrinkPrior(s-splits-1, minsize-s->cursize); + SplitterUpdate(); + } + } + + SetFocus(w); +} +static void SplitterAdd(HWND w, int minsize) +{ + struct splits_s *n = malloc(sizeof(*n)*(numsplits+1)); + memcpy(n, splits, sizeof(*n)*numsplits); + free(splits); + splits = n; + n += numsplits; + + n->wnd = w; + n->splitter = NULL; + n->minsize = minsize; + n->cursize = minsize; + n->cury = 0; + + numsplits++; + + SplitterUpdate(); + ShowWindow(w, SW_SHOW); +} +static void SplitterRemove(HWND w) +{ + struct splits_s *s = SplitterGet(w); + size_t idx; + if (!s) + return; + if (s->splitter) + DestroyWindow(s->splitter); + idx = s-splits; + numsplits--; + memmove(splits+idx, splits+idx+1, sizeof(*s)*(numsplits-idx)); + + ShowWindow(w, SW_HIDE); + + SplitterUpdate(); +} + + + + FILE *logfile; void GrepAllFiles(char *string); @@ -855,21 +1087,21 @@ LRESULT CALLBACK MySubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l { *colon1 = '\0'; *colon2 = '\0'; - EditFile(line, atoi(colon1+1)-1, false); + EditFile(line, atoi(colon1+1)-1, 2); } else if (!strncmp(line, "Source file: ", 13)) - EditFile(line+13, -1, false); + EditFile(line+13, -1, 2); else if (!strncmp(line, "Including: ", 11)) - EditFile(line+11, -1, false); + EditFile(line+11, -1, 2); } else if (!strncmp(line, "including ", 10)) - EditFile(line+10, -1, false); + EditFile(line+10, -1, 2); else if (!strncmp(line, "compiling ", 10)) - EditFile(line+10, -1, false); + EditFile(line+10, -1, 2); else if (!strncmp(line, "prototyping ", 12)) - EditFile(line+12, -1, false); + EditFile(line+12, -1, 2); else if (!strncmp(line, "Couldn't open file ", 19)) - EditFile(line+19, -1, false); + EditFile(line+19, -1, 2); Edit_SetSel(hWnd, selrange.cpMin, selrange.cpMin); //deselect it. } } @@ -1385,11 +1617,7 @@ void GenericMenu(WPARAM wParam) case IDM_OUTPUT_WINDOW: - if (outputwindow && outputbox) - { - SetFocus(outputwindow); - SetFocus(outputbox); - } + SplitterFocus(outputbox, 128); break; case IDM_SHOWLINENUMBERS: { @@ -2267,6 +2495,8 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message, GetClientRect(hWnd, &rect); SetWindowPos(editor->editpane, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0); goto gdefault; + case WM_ERASEBKGND: + return TRUE; case WM_PAINT: BeginPaint(hWnd,(LPPAINTSTRUCT)&ps); @@ -2547,6 +2777,10 @@ static void EditorReload(editor_t *editor) } //line is 0-based. use -1 for no reselection +//setcontrol is the reason we're opening it. +//0: just load and go to the line. +//1: show the line as the executing one +//2: draw extra focus to it void EditFile(const char *name, int line, pbool setcontrol) { char title[1024]; @@ -2574,7 +2808,10 @@ void EditFile(const char *name, int line, pbool setcontrol) { if (line >= 0) { - Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1)-1); + if (setcontrol) + Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line+1)-1, Edit_LineIndex(neweditor->editpane, line+1)-1); + else + Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1)-1); Edit_ScrollCaret(neweditor->editpane); if (setcontrol && neweditor->scintilla) @@ -2635,15 +2872,15 @@ void EditFile(const char *name, int line, pbool setcontrol) wndclass.style = 0; - wndclass.lpfnWndProc = EditorWndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = ghInstance; + wndclass.lpfnWndProc = EditorWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = ghInstance; wndclass.hIcon = LoadIcon(ghInstance, IDI_ICON_FTEQCC); - wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); + wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); wndclass.hbrBackground = (void *)COLOR_WINDOW; - wndclass.lpszMenuName = 0; - wndclass.lpszClassName = EDIT_WINDOW_CLASS_NAME; + wndclass.lpszMenuName = 0; + wndclass.lpszClassName = EDIT_WINDOW_CLASS_NAME; RegisterClass(&wndclass); neweditor->window = NULL; @@ -2658,7 +2895,7 @@ void EditFile(const char *name, int line, pbool setcontrol) mcs.hOwner = ghInstance; mcs.x = mcs.cx = CW_USEDEFAULT; mcs.y = mcs.cy = CW_USEDEFAULT; - mcs.style = WS_OVERLAPPEDWINDOW; + mcs.style = WS_OVERLAPPEDWINDOW|WS_MAXIMIZE; mcs.lParam = 0; neweditor->window = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, @@ -2685,7 +2922,12 @@ void EditFile(const char *name, int line, pbool setcontrol) EditorReload(neweditor); if (line >= 0) - Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1)); + { + if (setcontrol) + Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line+1)-1, Edit_LineIndex(neweditor->editpane, line+1)-1); + else + Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, line), Edit_LineIndex(neweditor->editpane, line+1)-1); + } else Edit_SetSel(neweditor->editpane, Edit_LineIndex(neweditor->editpane, 0), Edit_LineIndex(neweditor->editpane, 0)); @@ -3417,8 +3659,8 @@ static LRESULT CALLBACK EngineWndProc(HWND hWnd,UINT message, } if (hWnd == gamewindow) { + SplitterRemove(watches); gamewindow = NULL; - PostMessage(mainwindow, WM_SIZE, 0, 0); } break; case WM_USER: @@ -3724,6 +3966,8 @@ void RunEngine(void) gamewindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, (LONG_PTR) (LPMDICREATESTRUCT) &mcs); } + SplitterAdd(watches, 0); + SplitterFocus(watches, 64); } else { @@ -5398,12 +5642,14 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, watches = CreateWindow(WC_LISTVIEW, (LPCTSTR) NULL, WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_EDITLABELS, 0, 0, 320, 200, hWnd, (HMENU) 0xCAD, ghInstance, NULL); - ShowWindow(watches, SW_SHOW); + + SplitterAdd(mdibox, 32); if (watches) { LVCOLUMN col; LVITEM newi; + // ListView_SetUnicodeFormat(watches, TRUE); ListView_SetExtendedListViewStyle(watches, LVS_EX_GRIDLINES); memset(&col, 0, sizeof(col)); @@ -5481,40 +5727,37 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, GetClientRect(mainwindow, &rect); if (projecttree) { - int mdiheight, watchheight; - SetWindowPos(projecttree, NULL, 0, 0, 192, rect.bottom-rect.top - 34 - 48, 0); + SetWindowPos(projecttree, NULL, 0, 0, 192, rect.bottom-rect.top - 48, SWP_NOZORDER); - SetWindowPos(search_name, NULL, 0, rect.bottom-rect.top - 33 - 48, 192, 24, 0); - SetWindowPos(search_gotodef, NULL, 0, rect.bottom-rect.top - 33 - 24, 192/2, 24, 0); - SetWindowPos(search_grep, NULL, 192/2, rect.bottom-rect.top - 33 - 24, 192/2, 24, 0); + SetWindowPos(search_name, NULL, 0, rect.bottom-rect.top - 48, 192, 24, SWP_NOZORDER); + SetWindowPos(search_gotodef, NULL, 0, rect.bottom-rect.top - 24, 192/2, 24, SWP_NOZORDER); + SetWindowPos(search_grep, NULL, 192/2, rect.bottom-rect.top - 24, 192/2, 24, SWP_NOZORDER); - if (gamewindow) - watchheight = (ListView_GetItemCount(watches) + 2) * 16; - else - watchheight = 0; - mdiheight = (rect.bottom-rect.top) - 32; - if (watchheight > mdiheight/2) - watchheight = mdiheight/2; - mdiheight -= watchheight; - SetWindowPos(watches, NULL, 192, mdiheight, rect.right-rect.left-192, watchheight, 0); - SetWindowPos(mdibox?mdibox:outputbox, NULL, 192, 0, rect.right-rect.left-192, mdiheight, 0); + splitterrect.left = 192; } else - SetWindowPos(mdibox?mdibox:outputbox, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top - 32, 0); - width = (rect.right-rect.left); - width/=NUMBUTTONS; + { + splitterrect.left = 0; + } + splitterrect.right = rect.right-rect.left; + splitterrect.bottom = rect.bottom-rect.top-32; + SplitterUpdate(); + width = (rect.right-rect.left)-splitterrect.left; for (i = 0; i < NUMBUTTONS; i++) { - SetWindowPos(buttons[i].hwnd, NULL, width*i, rect.bottom-rect.top - 32, width, 32, 0); + int l = splitterrect.left+(width*i)/(NUMBUTTONS); + int r = splitterrect.left+(width*(i+1))/(NUMBUTTONS); + SetWindowPos(buttons[i].hwnd, NULL, l, rect.bottom-rect.top - 32, r-l, 32, SWP_NOZORDER); } break; // goto gdefault; + case WM_ERASEBKGND: + return TRUE; //background is clear... or doesn't need clearing (if its fully obscured) case WM_PAINT: BeginPaint(hWnd,(LPPAINTSTRUCT)&ps); EndPaint(hWnd,(LPPAINTSTRUCT)&ps); return TRUE; - break; case WM_COMMAND: i = LOWORD(wParam); if (i == 0x4403) @@ -5722,27 +5965,6 @@ static void DoTranslateMessage(MSG *msg) } } -static LRESULT CALLBACK OutputWindowProc(HWND hWnd,UINT message, - WPARAM wParam,LPARAM lParam) -{ - RECT rect; - switch (message) - { - case WM_DESTROY: - outputwindow = NULL; - outputbox = NULL; - break; - case WM_CREATE: - outputbox = CreateAnEditControl(hWnd, NULL); - case WM_SIZE: - GetClientRect(hWnd, &rect); - SetWindowPos(outputbox, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0); - default: - return DefMDIChildProc(hWnd,message,wParam,lParam); - } - return 0; -} - void GUIPrint(HWND wnd, char *msg) { // MSG wmsg; @@ -6031,8 +6253,7 @@ int GUIprintf(const char *msg, ...) outlen = 0; /*make sure its active so we can actually scroll. stupid windows*/ - SetFocus(outputwindow); - SetFocus(outputbox); + SplitterFocus(outputbox, 0); /*colour background to default*/ TreeView_SetBkColor(projecttree, -1); @@ -6274,45 +6495,14 @@ void RunCompiler(char *args, pbool quick) void CreateOutputWindow(pbool doannoates) { - WNDCLASS wndclass; - MDICREATESTRUCT mcs; - gui_doannotates = doannoates; - if (!mdibox) //should already be created - return; - - if (!outputwindow) + if (!outputbox) { - wndclass.style = 0; - wndclass.lpfnWndProc = OutputWindowProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = ghInstance; - wndclass.hIcon = LoadIcon(ghInstance, IDI_ICON_FTEQCC); - wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); - wndclass.hbrBackground = (void *)COLOR_WINDOW; - wndclass.lpszMenuName = 0; - wndclass.lpszClassName = MAIN_WINDOW_CLASS_NAME; - RegisterClass(&wndclass); - - - - mcs.szClass = MAIN_WINDOW_CLASS_NAME; - mcs.szTitle = "Compiler output"; - mcs.hOwner = ghInstance; - mcs.x = mcs.cx = CW_USEDEFAULT; - mcs.y = mcs.cy = CW_USEDEFAULT; - mcs.style = WS_OVERLAPPEDWINDOW; - mcs.lParam = 0; - - outputwindow = (HWND) SendMessage (mdibox, WM_MDICREATE, 0, (LONG_PTR) (LPMDICREATESTRUCT) &mcs); - - ShowWindow(outputwindow, SW_SHOW); + outputbox = CreateAnEditControl(mainwindow, NULL); + SplitterAdd(outputbox, 64); } - - //bring it to the front. - SendMessage(mdibox, WM_MDIACTIVATE, (WPARAM)outputwindow, 0); + SplitterFocus(outputbox, 128); } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 26eb685f..edaed887 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -820,6 +820,7 @@ void PR_LoadGlabalStruct(qboolean muted) globalfloat (false, input_buttons); globalint (false, serverid); globalvec (false, global_gravitydir); + globalstring (false, parm_string); memset(&evalc_idealpitch, 0, sizeof(evalc_idealpitch)); memset(&evalc_pitch_speed, 0, sizeof(evalc_pitch_speed)); @@ -2664,15 +2665,25 @@ void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m) if (sv.state != ss_loading) { + int j; Con_DPrintf("Delayed model precache: %s\n", m); - MSG_WriteByte(&sv.reliable_datagram, svcfte_precache); - MSG_WriteShort(&sv.reliable_datagram, i); - MSG_WriteString(&sv.reliable_datagram, m); -#ifdef NQPROT - MSG_WriteByte(&sv.nqreliable_datagram, svcdp_precache); - MSG_WriteShort(&sv.nqreliable_datagram, i); - MSG_WriteString(&sv.nqreliable_datagram, m); -#endif + + for (j = 0; j < sv.allocated_client_slots; j++) + { + if (svs.clients[j].state < cs_connected) + continue; + if (ISDPCLIENT(&svs.clients[j]) || (svs.clients[j].fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) + { + ClientReliableWrite_Begin (&svs.clients[j], ISNQCLIENT(&svs.clients[j])?svcdp_precache:svcfte_precache, strlen(m)+4); + ClientReliableWrite_Short (&svs.clients[j], i); + ClientReliableWrite_String (&svs.clients[j], m); + } + else + { + //client doesn't support this... reset the connection so they're forced to reload everything. + //SV_StuffcmdToClient(&svs.clients[j], "cmd new\n"); + } + } } } else @@ -3677,6 +3688,25 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags) { client_t *cl; int slen; + unsigned int i; + + if (flags & STUFFCMD_BROADCAST) + { + for (i = 0, cl = svs.clients; i < sv.allocated_client_slots; i++, cl++) + { + if (cl->state != cs_spawned || cl->controller == cl) + continue; + SV_StuffcmdToClient(cl, str); + } + if (!(flags & STUFFCMD_IGNOREINDEMO)) + if (sv.mvdrecording) + { + sizebuf_t *msg = MVDWrite_Begin (dem_all, 0, 2 + strlen(str)); + MSG_WriteByte (msg, svc_stufftext); + MSG_WriteString (msg, str); + } + return; + } if (entnum < 1 || entnum > sv.allocated_client_slots) return; @@ -5529,9 +5559,7 @@ void QCBUILTIN PF_setspawnparms (pubprogfuncs_t *prinst, struct globalvars_s *pr // copy spawn parms out of the client_t client = svs.clients + (i-1); - for (i=0 ; i< NUM_SPAWN_PARMS ; i++) - if (pr_global_ptrs->spawnparamglobals[i]) - *pr_global_ptrs->spawnparamglobals[i] = client->spawn_parms[i]; + SV_SpawnParmsToQC(client); } /* @@ -5744,7 +5772,7 @@ char *PF_infokey_Internal (int entnum, const char *key) value = ""; //could be a writebyted bot... break; case SCP_QUAKEWORLD: - if (!svs.clients[entnum-1].fteprotocolextensions && !svs.clients[entnum-1].fteprotocolextensions) + if (!svs.clients[entnum-1].fteprotocolextensions && !svs.clients[entnum-1].fteprotocolextensions2) value = "quakeworld"; else value = "quakeworld+"; @@ -8550,29 +8578,44 @@ static void QCBUILTIN PF_te_teleport(pubprogfuncs_t *prinst, struct globalvars_s //void(vector org, float color, float length) te_explosion2 = #427; static void QCBUILTIN PF_te_explosion2(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + qboolean old = false; float *org = G_VECTOR(OFS_PARM0); int start = G_FLOAT(OFS_PARM1); int length = G_FLOAT(OFS_PARM2); start = bound(0, start, 255); length = bound(0, length, 255-start); - MSG_WriteByte (&sv.multicast, svc_temp_entity); - MSG_WriteByte (&sv.multicast, TEQW_EXPLOSION2); - MSG_WriteCoord (&sv.multicast, org[0]); - MSG_WriteCoord (&sv.multicast, org[1]); - MSG_WriteCoord (&sv.multicast, org[2]); - MSG_WriteByte (&sv.multicast, start); - MSG_WriteByte (&sv.multicast, length); -#ifdef NQPROT - MSG_WriteByte (&sv.nqmulticast, svc_temp_entity); - MSG_WriteByte (&sv.nqmulticast, TENQ_EXPLOSION2); - MSG_WriteCoord (&sv.nqmulticast, org[0]); - MSG_WriteCoord (&sv.nqmulticast, org[1]); - MSG_WriteCoord (&sv.nqmulticast, org[2]); - MSG_WriteByte (&sv.nqmulticast, start); - MSG_WriteByte (&sv.nqmulticast, length); -#endif - SV_MulticastProtExt(org, MULTICAST_PHS, pr_global_struct->dimension_send, 0, 0); + for(;;) + { + MSG_WriteByte (&sv.multicast, svc_temp_entity); + MSG_WriteByte (&sv.multicast, old?TE_EXPLOSION:TEQW_EXPLOSION2); + MSG_WriteCoord (&sv.multicast, org[0]); + MSG_WriteCoord (&sv.multicast, org[1]); + MSG_WriteCoord (&sv.multicast, org[2]); + if (!old) + { + MSG_WriteByte (&sv.multicast, start); + MSG_WriteByte (&sv.multicast, length); + } + #ifdef NQPROT + MSG_WriteByte (&sv.nqmulticast, svc_temp_entity); + MSG_WriteByte (&sv.nqmulticast, TENQ_EXPLOSION2); + MSG_WriteCoord (&sv.nqmulticast, org[0]); + MSG_WriteCoord (&sv.nqmulticast, org[1]); + MSG_WriteCoord (&sv.nqmulticast, org[2]); + MSG_WriteByte (&sv.nqmulticast, start); + MSG_WriteByte (&sv.nqmulticast, length); + #endif + + if (old) + { + SV_MulticastProtExt(org, MULTICAST_PHS, pr_global_struct->dimension_send, 0, PEXT_TE_BULLET); + break; + } + else + SV_MulticastProtExt(org, MULTICAST_PHS, pr_global_struct->dimension_send, PEXT_TE_BULLET, 0); + old = true; + } } //DP_TE_FLAMEJET diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index b70e335d..ac1e7aa8 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -2097,6 +2097,7 @@ qboolean PR_LoadQ1QVM(void) pr_global_ptrs->spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(qintptr_t)(&global->parm1 + i)); for (; i < NUM_SPAWN_PARMS; i++) pr_global_ptrs->spawnparamglobals[i] = NULL; + pr_global_ptrs->parm_string = NULL; #define emufield(n,t) if (field[i].type == t && !strcmp(#n, fname)) {fofs.n = (field[i].ofs - WASTED_EDICT_T_SIZE)/sizeof(float); continue;} if (VM_NonNative(q1qvm)) diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 64fc67eb..8828da80 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -100,6 +100,7 @@ typedef struct nqglobalvars_s float *input_buttons; vec3_t *global_gravitydir; float *spawnparamglobals[NUM_SPAWN_PARMS]; + string_t *parm_string; int *serverid; } globalptrs_t; diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 45999126..6a56674b 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -803,11 +803,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char * e2 = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "stats_restored", ev_float, NULL); if (e2) e2->_float = 1; - for (j=0 ; j< NUM_SPAWN_PARMS ; j++) - { - if (pr_global_ptrs->spawnparamglobals[j]) - *pr_global_ptrs->spawnparamglobals[j] = host_client->spawn_parms[j]; - } + SV_SpawnParmsToQC(host_client); pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, ent); ent->area.next = ent->area.prev = NULL; diff --git a/engine/server/server.h b/engine/server/server.h index d4e56ef6..c814308a 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -333,13 +333,18 @@ typedef struct float move_msecs; // int packetsizein; //amount of data received for this frame int packetsizeout; //amount of data that was sent in the frame - packet_entities_t entities; //package containing entity states that were sent in this frame, for deltaing + + packet_entities_t qwentities; //package containing entity states that were sent in this frame, for deltaing + struct resendinfo_s { unsigned int entnum; - unsigned int bits; //delta + unsigned int bits; //delta (fte or dpp5+) unsigned int flags; //csqc } *resend; + unsigned int numresend; + unsigned int maxresend; + unsigned short resendstats[32];//the number of each entity that was sent in this frame unsigned int numresendstats; //the bits of each entity that were sent in this frame @@ -396,7 +401,7 @@ typedef struct //merge? enum { PRESPAWN_INVALID=0, - PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked + PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked. this gives us a chance to drop any clc_move packets with formats from the previous map PRESPAWN_SERVERINFO, PRESPAWN_SOUNDLIST, //nq skips these PRESPAWN_VWEPMODELLIST, //qw ugly extension. @@ -504,7 +509,8 @@ typedef struct client_s // spawn parms are carried from level to level float spawn_parms[NUM_SPAWN_PARMS]; - char *spawninfo; + char *spawn_parmstring; //qc-specified data. + char *spawninfo; //entity-formatted data (for hexen2's ClientReEnter) float spawninfotime; float nextservertimeupdate; //next time to send STAT_TIME float lastoutgoingphysicstime;//sv.world.physicstime of the last outgoing message. @@ -1119,6 +1125,8 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg); void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext); client_t *SV_AddSplit(client_t *controller, char *info, int id); +void SV_SpawnParmsToQC(client_t *client); +void SV_SpawnParmsToClient(client_t *client); void SV_GetNewSpawnParms(client_t *cl); void SV_SaveSpawnparms (void); void SV_SaveSpawnparmsClient(client_t *client, float *transferparms); //if transferparms, calls SetTransferParms instead, and does not modify the player. diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 620f9e8e..af8461e1 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -759,7 +759,8 @@ void SV_Map_f (void) Z_Free(host_client->spawninfo); host_client->spawninfo = NULL; memset(host_client->spawn_parms, 0, sizeof(host_client->spawn_parms)); - SV_GetNewSpawnParms(host_client); + if (host_client->state > cs_zombie) + SV_GetNewSpawnParms(host_client); } if (preserveplayers && svprogfuncs && host_client->state == cs_spawned && host_client->spawninfo) @@ -2855,16 +2856,14 @@ void SV_MemInfo_f(void) sz += lp->length; fr = 0; + fr += sizeof(client_frame_t)*UPDATE_BACKUP; if (cl->pendingdeltabits) { - int maxents = cl->frameunion.frames[0].entities.max_entities; /*this is the max number of ents updated per frame. we can't track more, so...*/ - fr = sizeof(cl)*UPDATE_BACKUP+ - sizeof(*cl->pendingdeltabits)*cl->max_net_ents+ - sizeof(unsigned int)*maxents*UPDATE_BACKUP+ - sizeof(unsigned int)*maxents*UPDATE_BACKUP; + fr += sizeof(cl)*UPDATE_BACKUP+ + sizeof(*cl->pendingdeltabits)*cl->max_net_ents; } - else - fr = (sizeof(client_frame_t)+sizeof(entity_state_t)*cl->frameunion.frames[0].entities.max_entities)*UPDATE_BACKUP; + fr += sizeof(*cl->frameunion.frames[0].resend)*cl->frameunion.frames[0].maxresend*UPDATE_BACKUP; + fr += sizeof(entity_state_t)*cl->frameunion.frames[0].qwentities.max_entities*UPDATE_BACKUP; fr += sizeof(*cl->sentents.entities) * cl->sentents.max_entities; csfr = sizeof(*cl->pendingcsqcbits) * cl->max_net_ents; @@ -2873,7 +2872,8 @@ void SV_MemInfo_f(void) } } - //FIXME: report vm memory + if (sv.world.progs) + Con_Printf("ssqc: %u (used) / %u (reserved)\n", sv.world.progs->stringtablesize, sv.world.progs->stringtablemaxsize); } void SV_Download_f (void) diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 8cc1029c..1cb0533d 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -125,18 +125,18 @@ unsigned int SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, qbyte *resultbuf, unsig #endif -void SVFTE_ExpandFrames(client_t *client, int require) +void SV_ExpandNackFrames(client_t *client, int require) { client_frame_t *newframes; char *ptr; int i; - int maxents = require * 2; /*this is the max number of ents updated per frame. we can't track more, so...*/ - if (maxents > client->max_net_ents) - maxents = client->max_net_ents; + int maxlog = require * 2; /*this is the max number of ents updated per frame. we can't track more, so...*/ + if (maxlog > client->max_net_ents) + maxlog = client->max_net_ents; ptr = Z_Malloc( sizeof(client_frame_t)*UPDATE_BACKUP+ sizeof(*client->pendingdeltabits)*client->max_net_ents+ sizeof(*client->pendingcsqcbits)*client->max_net_ents+ - sizeof(newframes[i].resend)*maxents*UPDATE_BACKUP); + sizeof(newframes[i].resend)*maxlog*UPDATE_BACKUP); newframes = (void*)ptr; memcpy(newframes, client->frameunion.frames, sizeof(client_frame_t)*UPDATE_BACKUP); ptr += sizeof(client_frame_t)*UPDATE_BACKUP; @@ -148,9 +148,11 @@ void SVFTE_ExpandFrames(client_t *client, int require) ptr += sizeof(*client->pendingcsqcbits)*client->max_net_ents; for (i = 0; i < UPDATE_BACKUP; i++) { - newframes[i].entities.max_entities = maxents; + newframes[i].maxresend = maxlog; + newframes[i].qwentities.max_entities = 0; newframes[i].resend = (void*)ptr; - memcpy(newframes[i].resend, client->frameunion.frames[i].resend, sizeof(newframes[i].resend)*client->frameunion.frames[i].entities.num_entities); + newframes[i].numresend = client->frameunion.frames[i].numresend; + memcpy(newframes[i].resend, client->frameunion.frames[i].resend, sizeof(newframes[i].resend)*newframes[i].numresend); newframes[i].senttime = realtime; } Z_Free(client->frameunion.frames); @@ -348,10 +350,11 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) qboolean writtenheader = false; int viewerent; int entnum; - int lognum = client->frameunion.frames[currentsequence & UPDATE_MASK].entities.num_entities; + client_frame_t *frame = &client->frameunion.frames[currentsequence & UPDATE_MASK]; + int lognum = frame->numresend; - struct resendinfo_s *resend = client->frameunion.frames[currentsequence & UPDATE_MASK].resend; - int maxlog = client->frameunion.frames[currentsequence & UPDATE_MASK].entities.max_entities; + struct resendinfo_s *resend = frame->resend; + int maxlog = frame->maxresend; //we don't check that we got some already - because this is delta compressed! @@ -391,7 +394,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) if (lognum > maxlog) { - SVFTE_ExpandFrames(client, lognum+1); + SV_ExpandNackFrames(client, lognum+1); break; } resend[lognum].entnum = entnum; @@ -444,7 +447,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) if (lognum > maxlog) { - SVFTE_ExpandFrames(client, lognum+1); + SV_ExpandNackFrames(client, lognum+1); break; } resend[lognum].entnum = entnum; @@ -478,7 +481,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) if (lognum > maxlog) { - SVFTE_ExpandFrames(client, lognum+1); + SV_ExpandNackFrames(client, lognum+1); break; } resend[lognum].entnum = entnum; @@ -514,7 +517,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) if (lognum > maxlog) { - SVFTE_ExpandFrames(client, lognum+1); + SV_ExpandNackFrames(client, lognum+1); break; } resend[lognum].entnum = entnum; @@ -540,7 +543,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) csqcnuments = 0; - client->frameunion.frames[currentsequence & UPDATE_MASK].entities.num_entities = lognum; + frame->numresend = lognum; //prevent the qc from trying to use it at inopertune times. csqcmsgbuffer.maxsize = 0; @@ -551,6 +554,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) void SV_CSQC_DroppedPacket(client_t *client, int sequence) { int i; + client_frame_t *frame; if (!ISQWCLIENT(client) && !ISNQCLIENT(client)) return; @@ -559,39 +563,35 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence) Con_Printf("Server bug: No frames!\n"); return; } + frame = &client->frameunion.frames[sequence & UPDATE_MASK]; //skip it if we never generated that frame, to avoid pulling in stale data - if (client->frameunion.frames[sequence & UPDATE_MASK].sequence != sequence) + if (frame->sequence != sequence) { // Con_Printf("SV: Stale %i\n", sequence); return; } //lost entities need flagging for a resend - if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + if (frame->numresend) { - struct resendinfo_s *resend = client->frameunion.frames[sequence & UPDATE_MASK].resend; + struct resendinfo_s *resend = frame->resend; // Con_Printf("SV: Resend %i\n", sequence); - i = client->frameunion.frames[sequence & UPDATE_MASK].entities.num_entities; + i = frame->numresend; while (i > 0) { i--; - -// if (f[i] & UF_RESET) -// Con_Printf("Resend %i @ %i\n", i, sequence); -// if (f[i] & UF_REMOVE) -// Con_Printf("Remove %i @ %i\n", i, sequence); client->pendingdeltabits[resend[i].entnum] |= resend[i].bits; client->pendingcsqcbits[resend[i].entnum] |= resend[i].flags; } - client->frameunion.frames[sequence & UPDATE_MASK].entities.num_entities = 0; + frame->numresend = 0; //don't resend the same info twice! } //lost stats do too - if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + if (frame->numresendstats) { client_t *sp; - unsigned short *n = client->frameunion.frames[sequence & UPDATE_MASK].resendstats; - i = client->frameunion.frames[sequence & UPDATE_MASK].numresendstats; + unsigned short *n = frame->resendstats; + i = frame->numresendstats; while(i-->0) { unsigned short s = n[i]; @@ -608,7 +608,7 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence) else client->pendingstats[s>>5u] |= 1u << (s & 0x1fu); } - client->frameunion.frames[sequence & UPDATE_MASK].numresendstats = 0; + frame->numresendstats = 0; } } @@ -1532,7 +1532,7 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb /*cache frame info*/ resend = client->frameunion.frames[sequence & UPDATE_MASK].resend; outno = 0; - outmax = client->frameunion.frames[sequence & UPDATE_MASK].entities.max_entities; + outmax = client->frameunion.frames[sequence & UPDATE_MASK].maxresend; /*start writing the packet*/ MSG_WriteByte (msg, svcfte_updateentities); @@ -1564,7 +1564,7 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb } if (outno >= outmax) { //expand the frames. may need some copying... - SVFTE_ExpandFrames(client, outno+1); + SV_ExpandNackFrames(client, outno+1); break; } @@ -1615,7 +1615,7 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb else client->nextdeltaindex = j; //we overflowed or something, start going round-robin - client->frameunion.frames[sequence & UPDATE_MASK].entities.num_entities = outno; + client->frameunion.frames[sequence & UPDATE_MASK].numresend = outno; client->frameunion.frames[sequence & UPDATE_MASK].sequence = sequence; return overflow; } @@ -1642,7 +1642,7 @@ void SVQW_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t if (client->delta_sequence != -1) { fromframe = &client->frameunion.frames[client->delta_sequence & UPDATE_MASK]; - from = &fromframe->entities; + from = &fromframe->qwentities; oldmax = from->num_entities; MSG_WriteByte (msg, svc_deltapacketentities); @@ -1916,122 +1916,148 @@ void SVDP_EmitEntityDelta(unsigned int bits, entity_state_t *to, sizebuf_t *msg, MSG_WriteShort(msg, to->u.q1.traileffectnum); } -void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t *msg) +void SVDP_EmitEntitiesUpdate (client_t *client, client_frame_t *frame, packet_entities_t *to, sizebuf_t *msg) { - packet_entities_t *from; - int oldindex, newindex; - int oldnum, newnum; - int oldmax; + packet_entities_t *cur; + int newindex; + int curnum, newnum; int j; + int sequence = client->netchan.incoming_sequence; // this is the frame that we are going to delta update from + cur = &client->sentents; if (!client->netchan.incoming_sequence) - { - oldmax = 0; - from = NULL; - } - else - { - from = &client->sentents; - oldmax = from->num_entities; + { //first packet deltas from nothing. + //so make sure we start with nothing + cur->num_entities = 0; } if (to->num_entities) { j = to->entities[to->num_entities-1].number+1; - if (j > from->max_entities) + if (j > cur->max_entities) { - from->entities = BZ_Realloc(from->entities, sizeof(*from->entities) * j); - memset(&from->entities[from->max_entities], 0, sizeof(from->entities[0]) * (j - from->max_entities)); - from->max_entities = j; + cur->entities = BZ_Realloc(cur->entities, sizeof(*cur->entities) * j); + memset(&cur->entities[cur->max_entities], 0, sizeof(cur->entities[0]) * (j - cur->max_entities)); + cur->max_entities = j; } - while(j > client->sentents.num_entities) + while(j > cur->num_entities) { - from->entities[from->num_entities].number = 0; - from->num_entities++; + cur->entities[cur->num_entities].number = 0; + cur->num_entities++; } } //diff the from+to states, flagging any changed state (which is combined with any state from previous packet loss newindex = 0; - oldindex = 0; - while (newindex < to->num_entities || oldindex < oldmax) + curnum = 0; + while (newindex < to->num_entities || curnum < cur->num_entities) { - newnum = newindex >= to->num_entities ? 0x7fff : to->entities[newindex].number; - oldnum = oldindex >= oldmax ? 0x7fff : from->entities[oldindex].number; + newnum = newindex >= to->num_entities ? 0x8000 : to->entities[newindex].number; - if (newnum < oldnum) - { // this is a new entity, send it from the baseline... as far as dp understands it... - client->pendingdeltabits[newnum] |= E5_FULLUPDATE | SVDP_CalcDelta(&nullentitystate, NULL, &to->entities[oldindex], to->bonedata); - newindex++; - } - else if (newnum > oldnum) - { // the old entity isn't present in the new message - client->pendingdeltabits[oldnum] = E5_SERVERREMOVE; - oldindex++; - } - else - { // delta update from old position - client->pendingdeltabits[newnum] |= SVDP_CalcDelta(&from->entities[oldindex], NULL/*from->bonedata*/, &to->entities[oldindex], to->bonedata); - if (client->pendingdeltabits[newnum] & E5_SERVERREMOVE) - { //if it got flagged for removal, but its actually a valid entity, then assume that its an outdated remove and just flag it for a full update in case stuff got lost. - client->pendingdeltabits[newnum] &= ~E5_SERVERREMOVE; - client->pendingdeltabits[newnum] |= E5_FULLUPDATE; + if (newnum == curnum) + { + if (cur->entities[curnum].number) + { //regular update + client->pendingdeltabits[newnum] |= SVDP_CalcDelta(&cur->entities[curnum], NULL/*cur->bonedata*/, &to->entities[newindex], to->bonedata); + if (client->pendingdeltabits[newnum] & E5_SERVERREMOVE) + { //if it got flagged for removal, but its actually a valid entity, then assume that its an outdated remove and just flag it for a full update in case stuff got lost. + client->pendingdeltabits[newnum] &= ~E5_SERVERREMOVE; + client->pendingdeltabits[newnum] |= E5_FULLUPDATE; + } } - oldindex++; + else + { //this ent is new + //dpp5+ does not use baselines. it just resets from default state. + client->pendingdeltabits[newnum] = E5_FULLUPDATE | SVDP_CalcDelta(&nullentitystate, NULL, &to->entities[newindex], to->bonedata); + } + cur->entities[curnum] = to->entities[newindex]; newindex++; } + else if (cur->entities[curnum].number) + { //this entity was apparently removed since last time. + cur->entities[curnum].number = 0; + client->pendingdeltabits[curnum] = E5_SERVERREMOVE; + } + curnum++; } + to = cur; + //loop through all ents and send them as required // Con_Printf ("frame %i\n", client->netchan.incoming_sequence); - MSG_WriteByte(msg, svcdp_entities); - MSG_WriteLong(msg, client->netchan.incoming_sequence); //sequence for the client to ack (any bits sent in unacked frames will be re-queued) - if (client->protocol == SCP_DARKPLACES7) - MSG_WriteLong(msg, client->last_sequence); //movement sequence that we are acking. - - client->netchan.incoming_sequence++; - - //add in the bitmasks of dropped packets. - -/* newindex = 0; - oldindex = 0; -//Con_Printf ("---%i to %i ----\n", client->delta_sequence & UPDATE_MASK -// , client->netchan.outgoing_sequence & UPDATE_MASK); - while (newindex < to->num_entities || oldindex < oldmax) { - newnum = newindex >= to->num_entities ? 0x7fff : to->entities[newindex].number; - oldnum = oldindex >= oldmax ? 0x7fff : from->entities[oldindex].number; + unsigned int bits; + int outno, outmax = frame->maxresend; + qboolean overflow = false; + struct resendinfo_s *resend = frame->resend; - if (newnum == oldnum) - { // delta update from old position -//Con_Printf ("delta %i\n", newnum); - SVDP_EmitEntityDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, to->bonedata); - oldindex++; - newindex++; - continue; - } + MSG_WriteByte(msg, svcdp_entities); + MSG_WriteLong(msg, sequence); //sequence for the client to ack (any bits sent in unacked frames will be re-queued) + if (client->protocol == SCP_DARKPLACES7) + MSG_WriteLong(msg, client->last_sequence); //movement sequence that we are acking. - if (newnum < oldnum) - { // this is a new entity, send it from the baseline... as far as dp understands it... -//Con_Printf ("baseline %i\n", newnum); - SVDP_EmitEntityDelta (&nullentitystate, &to->entities[newindex], msg, true, to->bonedata); - newindex++; - continue; - } + client->netchan.incoming_sequence++; - if (newnum > oldnum) - { // the old entity isn't present in the new message -// Con_Printf("sRemove %i\n", oldnum); - MSG_WriteShort(msg, oldnum | 0x8000); - oldindex++; - continue; + //add in the bitmasks of dropped packets. + for(outno = 0, j = 1; j < to->num_entities; j++) + { + bits = client->pendingdeltabits[j]; + if (!bits) + continue; + if (msg->cursize + 50 > msg->maxsize) + { + overflow = true; + break; /*give up if it gets full. FIXME: bone data is HUGE.*/ + } + if (outno >= outmax) + { //expand the frames. may need some copying... + SV_ExpandNackFrames(client, outno+1); + break; + } + + if (bits & E5_SERVERREMOVE) + { //if reset is set, then reset was set eroneously. + MSG_WriteShort(msg, j | 0x8000); + resend[outno].bits = E5_SERVERREMOVE; + // Con_Printf("REMOVE %i @ %i\n", j, sequence); + } + else if (to->entities[j].number) /*only send a new copy of the ent if they actually have one already*/ + { + //if we didn't reach the end in the last packet, start at that point to avoid spam + //player slots are exempt from this, so they are in every packet (strictly speaking only the local player 'needs' this, but its nice to have it for high-priority targets too) + if (j < client->nextdeltaindex && j > svs.allocated_client_slots) + continue; + + if (bits & E5_FULLUPDATE) + { + /*flag the entity for the next packet, so we always get two resets when it appears, to reduce the effects of packetloss on seeing rockets etc*/ + bits = E5_FULLUPDATE | SVDP_CalcDelta(&nullentitystate, NULL, &to->entities[j], to->bonedata); + resend[outno].bits = E5_FULLUPDATE; + // Con_Printf("RESET %i @ %i\n", j, sequence); + } + else + resend[outno].bits = bits; + + SVDP_EmitEntityDelta (bits, &to->entities[j], msg, to->bonedata); + } + + client->pendingdeltabits[j] = 0; + + resend[outno].flags = 0; + resend[outno++].entnum = j; } + MSG_WriteShort(msg, 0x8000); //dp5+ uses 'remove world' as a terminator. + frame->numresend = outno; + frame->sequence = sequence; + + if (j == to->num_entities) //looks like we sent them all + client->nextdeltaindex = 0; //start afresh with the next packet. + else + client->nextdeltaindex = j; //we overflowed or something, start going round-robin } -*/ - MSG_WriteShort(msg, 0x8000); } #endif @@ -3965,7 +3991,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore } host_client = client; - if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || !frame->entities.entities) + if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || !frame->qwentities.entities || ISNQCLIENT(client)) { pack = &svs.entstatebuffer; if (pack->max_entities < client->max_net_ents) @@ -3976,7 +4002,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore } } else - pack = &frame->entities; + pack = &frame->qwentities; SV_Snapshot_Clear(pack); if (!pack->entities) @@ -4024,7 +4050,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore } } else if (client->protocol == SCP_DARKPLACES6 || client->protocol == SCP_DARKPLACES7) - SVDP_EmitEntitiesUpdate(client, pack, msg); + SVDP_EmitEntitiesUpdate(client, frame, pack, msg); else { for (e = 0; e < pack->num_entities; e++) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index ebb21082..758c0545 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -271,14 +271,40 @@ void SVQ1_CreateBaseline (void) } } +void SV_SpawnParmsToQC(client_t *client) +{ + int i; + // copy spawn parms out of the client_t + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + { + if (pr_global_ptrs->spawnparamglobals[i]) + *pr_global_ptrs->spawnparamglobals[i] = client->spawn_parms[i]; + } + if (pr_global_ptrs->parm_string) + *pr_global_ptrs->parm_string = client->spawn_parmstring?PR_TempString(sv.world.progs, client->spawn_parmstring):0; +} + +void SV_SpawnParmsToClient(client_t *client) +{ + int i; + for (i=0 ; ispawnparamglobals[i]) + client->spawn_parms[i] = *pr_global_ptrs->spawnparamglobals[i]; + else + client->spawn_parms[i] = 0; + } + Z_Free(client->spawn_parmstring); + if (pr_global_ptrs->parm_string) + client->spawn_parmstring = Z_StrDup(PR_GetString(sv.world.progs, *pr_global_ptrs->parm_string)); + else + client->spawn_parmstring = NULL; +} + void SV_SaveSpawnparmsClient(client_t *client, float *transferparms) { int j; - for (j=0 ; jspawnparamglobals[j]) - *pr_global_ptrs->spawnparamglobals[j] = client->spawn_parms[j]; - } + SV_SpawnParmsToQC(client); #ifdef VM_Q1 if (svs.gametype == GT_Q1QVM) @@ -314,11 +340,7 @@ void SV_SaveSpawnparmsClient(client_t *client, float *transferparms) } else { - for (j=0 ; jspawnparamglobals[j]) - client->spawn_parms[j] = *pr_global_ptrs->spawnparamglobals[j]; - } + SV_SpawnParmsToClient(client); } // call the progs to get default spawn parms for the new client @@ -394,8 +416,6 @@ void SV_SaveSpawnparms (void) void SV_GetNewSpawnParms(client_t *cl) { - int i; - if (svprogfuncs) //q2 dlls don't use parms in this manner. It's all internal to the dll. { // call the progs to get default spawn parms for the new client @@ -408,13 +428,8 @@ void SV_GetNewSpawnParms(client_t *cl) if (pr_global_ptrs->SetNewParms) PR_ExecuteProgram (svprogfuncs, pr_global_struct->SetNewParms); } - for (i=0 ; ispawnparamglobals[i]) - cl->spawn_parms[i] = *pr_global_ptrs->spawnparamglobals[i]; - else - cl->spawn_parms[i] = 0; - } + + SV_SpawnParmsToClient(cl); } } @@ -1645,14 +1660,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, { sv_player = host_client->edict; SV_ExtractFromUserinfo(host_client, true); - - // copy spawn parms out of the client_t - for (j=0 ; j< NUM_SPAWN_PARMS ; j++) - { - if (pr_global_ptrs->spawnparamglobals[j]) - *pr_global_ptrs->spawnparamglobals[j] = host_client->spawn_parms[j]; - } - + SV_SpawnParmsToQC(host_client); SV_SetUpClientEdict(host_client, sv_player); #ifndef NOLEGACY sv_player->xv->clientcolors = atoi(Info_ValueForKey(host_client->userinfo, "topcolor"))*16 + atoi(Info_ValueForKey(host_client->userinfo, "bottomcolor")); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 70007782..1d12f375 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1968,7 +1968,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) ptr += sizeof(*client->pendingcsqcbits)*client->max_net_ents; for (i = 0; i < UPDATE_BACKUP; i++) { - client->frameunion.frames[i].entities.max_entities = maxents; + client->frameunion.frames[i].maxresend = maxents; client->frameunion.frames[i].resend = (void*)ptr; ptr += sizeof(*client->frameunion.frames[i].resend)*maxents; client->frameunion.frames[i].senttime = realtime; @@ -1982,8 +1982,8 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) client->frameunion.frames = Z_Malloc((sizeof(client_frame_t))*UPDATE_BACKUP); for (i = 0; i < UPDATE_BACKUP; i++) { - client->frameunion.frames[i].entities.max_entities = 0; - client->frameunion.frames[i].entities.entities = NULL; + client->frameunion.frames[i].qwentities.max_entities = 0; + client->frameunion.frames[i].qwentities.entities = NULL; client->frameunion.frames[i].senttime = realtime; } } @@ -1992,8 +1992,8 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) client->frameunion.frames = Z_Malloc((sizeof(client_frame_t)+sizeof(entity_state_t)*maxpacketentities)*UPDATE_BACKUP); for (i = 0; i < UPDATE_BACKUP; i++) { - client->frameunion.frames[i].entities.max_entities = maxpacketentities; - client->frameunion.frames[i].entities.entities = (entity_state_t*)(client->frameunion.frames+UPDATE_BACKUP) + i*client->frameunion.frames[i].entities.max_entities; + client->frameunion.frames[i].qwentities.max_entities = maxpacketentities; + client->frameunion.frames[i].qwentities.entities = (entity_state_t*)(client->frameunion.frames+UPDATE_BACKUP) + i*client->frameunion.frames[i].qwentities.max_entities; client->frameunion.frames[i].senttime = realtime; } } diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index be97095c..b864fb1a 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1569,10 +1569,13 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) edict_t *ent; int i; float newa; + client_t *controller; ent = client->edict; if (client->controller) - client = client->controller; + controller = client->controller; + else + controller = client; if (!ent) return; @@ -1613,8 +1616,8 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) if (!client->lockangles) { //try to keep them vaugely reliable. - if (client->netchan.message.cursize < client->netchan.message.maxsize/2) - msg = &client->netchan.message; + if (controller->netchan.message.cursize < controller->netchan.message.maxsize/2) + msg = &controller->netchan.message; } if (pnum) @@ -1622,7 +1625,7 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum) MSG_WriteByte(msg, svcfte_choosesplitclient); MSG_WriteByte(msg, pnum); } - if (!client->lockangles && (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA) && client->delta_sequence != -1 && !client->viewent) + if (!client->lockangles && (controller->fteprotocolextensions2 & PEXT2_SETANGLEDELTA) && controller->delta_sequence != -1 && !client->viewent) { MSG_WriteByte (msg, svcfte_setangledelta); for (i=0 ; i < 3 ; i++) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 31b151e5..bd5147ab 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -528,8 +528,8 @@ void SVNQ_New_f (void) qboolean big; //used as a filter to exclude protocols that don't match our coord+angles mode } preferedprot[] = { -// {SCP_DARKPLACES7, true}, -// {SCP_DARKPLACES6, true}, + {SCP_DARKPLACES7, true}, + {SCP_DARKPLACES6, true}, {SCP_FITZ666, true}, //actually 999... shh... {SCP_FITZ666, false}, {SCP_BJP3, false} @@ -604,7 +604,7 @@ void SVNQ_New_f (void) protoname = "NQ"; } break; - /*case SCP_DARKPLACES6: + case SCP_DARKPLACES6: SV_LogPlayer(host_client, "new (DP6)"); protmain = PROTOCOL_VERSION_DP6; protext1 &= ~PEXT_FLOATCOORDS; //always enabled, try not to break things @@ -615,7 +615,7 @@ void SVNQ_New_f (void) protmain = PROTOCOL_VERSION_DP7; protext1 &= ~PEXT_FLOATCOORDS; //always enabled, try not to break things protoname = "DPP7"; - break;*/ + break; default: host_client->drop = true; protoname = "?""?""?"; @@ -1824,14 +1824,12 @@ void SV_SpawnSpectator (void) return; } } - } void SV_Begin_Core(client_t *split) { //this is the client-protocol-independant core, for q1/q2 gamecode client_t *oh; - int i; #ifdef HEXEN2 if (progstype == PROG_H2 && split->playerclass) split->edict->xv->playerclass = split->playerclass; //make sure it's set the same as the userinfo @@ -1878,11 +1876,7 @@ void SV_Begin_Core(client_t *split) // copy spawn parms out of the client_t - for (i=0 ; i< NUM_SPAWN_PARMS ; i++) - { - if (pr_global_ptrs->spawnparamglobals[i]) - *pr_global_ptrs->spawnparamglobals[i] = split->spawn_parms[i]; - } + SV_SpawnParmsToQC(split); // call the spawn function pr_global_struct->time = sv.world.physicstime; @@ -1912,11 +1906,7 @@ void SV_Begin_Core(client_t *split) eval2 = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "stats_restored", ev_float, NULL); if (eval2) eval2->_float = 1; - for (j=0 ; j< NUM_SPAWN_PARMS ; j++) - { - if (pr_global_ptrs->spawnparamglobals[j]) - *pr_global_ptrs->spawnparamglobals[j] = split->spawn_parms[j]; - } + SV_SpawnParmsToQC(split); pr_global_struct->time = sv.world.physicstime; pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, ent); G_FLOAT(OFS_PARM0) = sv.time - split->spawninfotime; @@ -1925,11 +1915,7 @@ void SV_Begin_Core(client_t *split) else { // copy spawn parms out of the client_t - for (i=0 ; i< NUM_SPAWN_PARMS ; i++) - { - if (pr_global_ptrs->spawnparamglobals[i]) - *pr_global_ptrs->spawnparamglobals[i] = split->spawn_parms[i]; - } + SV_SpawnParmsToQC(split); // call the spawn function #ifdef VM_Q1 @@ -4991,13 +4977,8 @@ void Cmd_Join_f (void) #endif if (pr_global_ptrs->SetNewParms) PR_ExecuteProgram (svprogfuncs, pr_global_struct->SetNewParms); - for (i=0 ; ispawnparamglobals[i]) - host_client->spawn_parms[i] = *pr_global_ptrs->spawnparamglobals[i]; - else - host_client->spawn_parms[i] = 0; - } + + SV_SpawnParmsToClient(host_client); #ifdef VM_Q1 if (svs.gametype == GT_Q1QVM) @@ -5131,14 +5112,8 @@ void Cmd_Observe_f (void) #endif if (pr_global_ptrs->SetNewParms) PR_ExecuteProgram (svprogfuncs, pr_global_struct->SetNewParms); - for (i=0 ; ispawnparamglobals[i]) - host_client->spawn_parms[i] = *pr_global_ptrs->spawnparamglobals[i]; - else - host_client->spawn_parms[i] = 0; - } + SV_SpawnParmsToClient(host_client); SV_SpawnSpectator (); // call the spawn function @@ -5372,7 +5347,6 @@ static void SVNQ_Spawn_f (void) static void SVNQ_Begin_f (void) { unsigned pmodel = 0, emodel = 0; - int i; qboolean sendangles=false; if (host_client->state == cs_spawned) @@ -5394,11 +5368,7 @@ static void SVNQ_Begin_f (void) if (SpectatorConnect) { // copy spawn parms out of the client_t - for (i=0 ; i< NUM_SPAWN_PARMS ; i++) - { - if (pr_global_ptrs->spawnparamglobals[i]) - *pr_global_ptrs->spawnparamglobals[i] = host_client->spawn_parms[i]; - } + SV_SpawnParmsToQC(host_client); // call the spawn function pr_global_struct->time = sv.world.physicstime; @@ -5412,11 +5382,7 @@ static void SVNQ_Begin_f (void) sv.spawned_client_slots++; // copy spawn parms out of the client_t - for (i=0 ; i< NUM_SPAWN_PARMS ; i++) - { - if (pr_global_ptrs->spawnparamglobals[i]) - *pr_global_ptrs->spawnparamglobals[i] = host_client->spawn_parms[i]; - } + SV_SpawnParmsToQC(host_client); sv.skipbprintclient = host_client; #ifdef VM_Q1 @@ -5951,6 +5917,7 @@ ucmd_t nqucmds[] = {"playermodel", NULL}, {"playerskin", NULL}, {"rate", SV_Rate_f}, + {"rate_burstsize", NULL}, #ifdef SVRANKING {"topten", Rank_ListTop10_f}, diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index bb2f7c04..1570bf0a 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -3977,10 +3977,15 @@ void VK_UploadLightmap(lightmapinfo_t *lm) mips.mip[0].needfree = false; mips.mip[0].width = lm->width; mips.mip[0].height = lm->height; - if (lightmap_bgra) + switch(lightmap_fmt) + { + case TF_BGRA32: mips.encoding = PTI_BGRX8; - else - mips.encoding = PTI_RGBX8; + break; + default: + Sys_Error("Unsupported encoding\n"); + break; + } mips.mipcount = 1; VK_LoadTextureMips(tex, &mips); tex->status = TEX_LOADED;