diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 34bdf5e1f..eafab7331 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -990,7 +990,7 @@ qboolean CL_GetMessage (void) if (cls.demoplayback != DPB_NONE) return CL_GetDemoMessage (); - if (NET_GetPacket (NS_CLIENT, 0) < 0) + if (NET_GetPacket (cls.sockets, 0) < 0) return false; return true; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 849884068..804e2fac3 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -301,11 +301,6 @@ qbyte *host_basepal; qbyte *h2playertranslations; cvar_t host_speeds = CVAR("host_speeds","0"); // set for running times -#ifdef CRAZYDEBUGGING -cvar_t developer = CVAR("developer","1"); -#else -cvar_t developer = CVAR("developer","0"); -#endif int fps_count; qboolean forcesaveprompt; @@ -455,7 +450,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr) Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string); - NET_SendPacket (NS_CLIENT, strlen(data), data, adr); + NET_SendPacket (cls.sockets, strlen(data), data, adr); cl.splitclients = 0; } @@ -724,7 +719,7 @@ void CL_SendConnectPacket (netadr_t *to, int mtu, if (info) Q_strncatz(data, va("0x%x \"%s\"\n", PROTOCOL_INFO_GUID, info), sizeof(data)); - NET_SendPacket (NS_CLIENT, strlen(data), data, to); + NET_SendPacket (cls.sockets, strlen(data), data, to); } char *CL_TryingToConnect(void) @@ -752,7 +747,7 @@ void CL_CheckForResend (void) char *host; extern int r_blockvidrestart; -#ifndef CLIENTONLY +#ifdef HAVE_SERVER if (!cls.state && (!connectinfo.trying || sv.state != ss_clustermode) && sv.state) { const char *lbp; @@ -951,7 +946,7 @@ void CL_CheckForResend (void) NET_AdrToString(data, sizeof(data), &connectinfo.adr); /*eat up the server's packets, to clear any lingering loopback packets (like disconnect commands... yes this might cause packetloss for other clients)*/ - while(NET_GetPacket (NS_SERVER, 0) >= 0) + while(NET_GetPacket (svs.sockets, 0) >= 0) { } net_message.packing = SZ_RAWBYTES; @@ -1119,7 +1114,7 @@ void CL_CheckForResend (void) if (contype & 1) { Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255); - switch(NET_SendPacket (NS_CLIENT, strlen(data), data, &connectinfo.adr)) + switch(NET_SendPacket (cls.sockets, strlen(data), data, &connectinfo.adr)) { case NETERR_CLOGGED: //temporary failure case NETERR_SENT: //yay, works! @@ -1159,7 +1154,7 @@ void CL_CheckForResend (void) MSG_WriteString(&sb, "getchallenge"); *(int*)sb.data = LongSwap(NETFLAG_CTL | sb.cursize); - switch(NET_SendPacket (NS_CLIENT, sb.cursize, sb.data, &connectinfo.adr)) + switch(NET_SendPacket (cls.sockets, sb.cursize, sb.data, &connectinfo.adr)) { case NETERR_CLOGGED: //temporary failure case NETERR_SENT: //yay, works! @@ -1540,7 +1535,7 @@ void CL_Rcon_f (void) } } - NET_SendPacket (NS_CLIENT, strlen(message)+1, message, &to); + NET_SendPacket (cls.sockets, strlen(message)+1, message, &to); } void CL_BlendFog(fogstate_t *result, fogstate_t *oldf, float time, fogstate_t *newf) @@ -2659,7 +2654,7 @@ void CL_Packet_f (void) } *out = 0; - NET_SendPacket (NS_CLIENT, out-send, send, &adr); + NET_SendPacket (cls.sockets, out-send, send, &adr); if (Cmd_FromGamecode()) { @@ -2905,7 +2900,7 @@ void CL_ConnectionlessPacket (void) Q_snprintfz(data+6, sizeof(data)-6, "%i %i", atoi(MSG_ReadString()), cls.realip_ident); len = strlen(data); - NET_SendPacket (NS_CLIENT, len, &data, &net_from); + NET_SendPacket (cls.sockets, len, &data, &net_from); return; } @@ -2954,7 +2949,7 @@ void CL_ConnectionlessPacket (void) { connectinfo.istransfer = true; connectinfo.adr = adr; - NET_SendPacket (NS_CLIENT, strlen(data), data, &adr); + NET_SendPacket (cls.sockets, strlen(data), data, &adr); } } return; @@ -3205,7 +3200,7 @@ void CL_ConnectionlessPacket (void) //server says it can do tls. char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge); - NET_SendPacket (NS_CLIENT, strlen(pkt), pkt, &net_from); + NET_SendPacket (cls.sockets, strlen(pkt), pkt, &net_from); return; } if (connectinfo.dtlsupgrade == DTLS_REQUIRE) @@ -3730,7 +3725,7 @@ void CL_ReadPackets (void) if (cls.state == ca_disconnected) { //connect to nq servers, but don't get confused with sequenced packets. - if (NET_WasSpecialPacket(NS_CLIENT)) + if (NET_WasSpecialPacket(cls.sockets)) continue; #ifdef NQPROT CLNQ_ConnectionlessPacket (); @@ -3744,7 +3739,7 @@ void CL_ReadPackets (void) if (!cls.demoplayback && !NET_CompareAdr (&net_from, &cls.netchan.remote_address)) { - if (NET_WasSpecialPacket(NS_CLIENT)) + if (NET_WasSpecialPacket(cls.sockets)) continue; Con_DPrintf ("%s:sequenced packet from wrong server\n" ,NET_AdrToString(adr, sizeof(adr), &net_from)); @@ -4188,7 +4183,7 @@ void CL_FTP_f(void) void CL_Fog_f(void) { int ftype = Q_strcasecmp(Cmd_Argv(0), "fog"); - if ((cl.fog_locked && !Cmd_FromGamecode()) || Cmd_Argc() <= 1) + if ((cl.fog_locked && !Cmd_FromGamecode() && !cls.allow_cheats) || Cmd_Argc() <= 1) { if (Cmd_ExecLevel != RESTRICT_INSECURE) Con_Printf("Current fog %f (r:%f g:%f b:%f, a:%f bias:%f)\n", cl.fog[ftype].density, cl.fog[ftype].colour[0], cl.fog[ftype].colour[1], cl.fog[ftype].colour[2], cl.fog[ftype].alpha, cl.fog[ftype].depthbias); @@ -4420,7 +4415,6 @@ void CL_Init (void) CSQC_RegisterCvarsAndThings(); #endif Cvar_Register (&host_speeds, cl_controlgroup); - Cvar_Register (&developer, cl_controlgroup); Cvar_Register (&cfg_save_name, cl_controlgroup); @@ -5307,7 +5301,9 @@ done: // if (f->flags & HRF_DOWNLOADED) man->blockupdate = true; BZ_Free(fdata); +#ifdef PACKAGEMANAGER PM_Shutdown(); +#endif FS_ChangeGame(man, true, true); } else @@ -6359,7 +6355,9 @@ Host_Init */ void Host_Init (quakeparms_t *parms) { +#ifdef PACKAGEMANAGER char engineupdated[MAX_OSPATH]; +#endif int man; com_parseutf8.ival = 1; //enable utf8 parsing even before cvars are registered. @@ -6385,6 +6383,7 @@ void Host_Init (quakeparms_t *parms) Cmd_Init (); COM_Init (); +#ifdef PACKAGEMANAGER //we have enough of the filesystem inited now that we can read the package list and figure out which engine was last installed. if (PM_FindUpdatedEngine(engineupdated, sizeof(engineupdated))) { @@ -6402,6 +6401,8 @@ void Host_Init (quakeparms_t *parms) } PM_Shutdown(); //will restart later as needed, but we need to be sure that no files are open or anything. } +#endif + V_Init (); NET_Init (); @@ -6548,7 +6549,9 @@ void Host_Shutdown(void) Validation_FlushFileList(); Cmd_Shutdown(); +#ifdef PACKAGEMANAGER PM_Shutdown(); +#endif Key_Unbindall_f(); #ifdef PLUGINS diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index cd89b79d4..a7ee1e992 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -17,7 +17,7 @@ enum masterprotocol_e MP_DPMASTER }; -#if defined(CL_MASTER) && !defined(SERVERONLY) +#if defined(CL_MASTER) && defined(HAVE_CLIENT) #define SS_PROTOCOLMASK 0xf #define SS_UNKNOWN 0 #define SS_QUAKEWORLD 1 @@ -134,7 +134,10 @@ typedef struct serverinfo_s qbyte players; qbyte maxplayers; qbyte sends; - qbyte status; //1=alive, 2=displayed + qbyte status; +#define SRVSTATUS_ALIVE 1u //server is responding to pings +#define SRVSTATUS_DISPLAYED 2u //server passed all filters +#define SRVSTATUS_GLOBAL 4u //server was reported by one of the master servers (ie: global and not local) qbyte numspectators; qbyte numhumans; @@ -247,8 +250,6 @@ serverinfo_t *Master_SortedServer(int idx); void Master_SetMaskString(qboolean or_, hostcachekey_t field, const char *param, slist_test_t testop); void Master_SetMaskInteger(qboolean or_, hostcachekey_t field, int param, slist_test_t testop); serverinfo_t *Master_FindRoute(netadr_t target); -#else -#define MasterInfo_WriteServers() #endif diff --git a/engine/client/client.h b/engine/client/client.h index 54cdd20fa..71078ece8 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -541,7 +541,6 @@ typedef struct #ifdef NQPROT int signon; #endif - int language; colourised_t *colourised; qboolean nqexpectingstatusresponse; diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index 0df68f5c4..9f5213290 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -1028,7 +1028,7 @@ void CLQ3_SendAuthPacket(netadr_t *gameserver) } MSG_WriteByte(&msg, 0); - NET_SendPacket (NS_CLIENT, msg.cursize, msg.data, &authaddr); + NET_SendPacket (cls.sockets, msg.cursize, msg.data, &authaddr); } else Con_Printf(" failed\n"); @@ -1062,7 +1062,7 @@ void CLQ3_SendConnectPacket(netadr_t *to, int challenge, int qport) return; } #endif - NET_SendPacket (NS_CLIENT, msg.cursize, msg.data, to); + NET_SendPacket (cls.sockets, msg.cursize, msg.data, to); } #endif diff --git a/engine/client/console.c b/engine/client/console.c index 346a2df82..b96eec920 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1061,7 +1061,7 @@ Handles cursor positioning, line wrapping, etc ================ */ -#ifndef CLIENTONLY +#ifdef HAVE_SERVER extern redirect_t sv_redirected; extern char sv_redirected_buf[8000]; void SV_FlushRedirect (void); @@ -1103,7 +1103,7 @@ void VARGS Con_Printf (const char *fmt, ...) return; } -#ifndef CLIENTONLY +#ifdef HAVE_SERVER // add to redirected message if (sv_redirected) { @@ -1147,7 +1147,7 @@ void VARGS Con_TPrintf (translation_t text, ...) { va_list argptr; char msg[MAXPRINTMSG]; - const char *fmt = langtext(text, cls.language); + const char *fmt = langtext(text, com_language); va_start (argptr,text); vsnprintf (msg,sizeof(msg), fmt,argptr); @@ -1161,7 +1161,7 @@ void VARGS Con_SafeTPrintf (translation_t text, ...) { va_list argptr; char msg[MAXPRINTMSG]; - const char *fmt = langtext(text, cls.language); + const char *fmt = langtext(text, com_language); va_start (argptr,text); vsnprintf (msg,sizeof(msg), fmt,argptr); diff --git a/engine/client/m_download.c b/engine/client/m_download.c index c001714a5..83c9e6ef0 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -2946,22 +2946,12 @@ qboolean PM_CanInstall(const char *packagename) { return false; } -void PM_Command_f (void) -{ - Con_Printf("Package Manager is not implemented in this build\n"); -} -void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri) -{ -} void PM_EnumeratePlugins(void (*callback)(const char *name)) { } void PM_ManifestPackage(const char *metaname, int security) { } -void PM_Shutdown(void) -{ -} int PM_IsApplying(qboolean listsonly) { return false; diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index 4e4523aa0..f03d8fb06 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -577,6 +577,7 @@ qboolean MultiBeginGame (union menuoption_s *option,struct menu_s *menu, int key if (cls.state) Cbuf_AddText("disconnect\n", RESTRICT_LOCAL); + Cbuf_AddText("sv_playerslots \"\"\n", RESTRICT_LOCAL); //just in case. Cbuf_AddText(va("maxclients \"%s\"\n", numplayeroptions[info->numplayers->selectedoption]), RESTRICT_LOCAL); if (info->rundedicated->value) Cbuf_AddText("setrenderer dedicated\n", RESTRICT_LOCAL); @@ -711,7 +712,7 @@ void M_Menu_GameOptions_f (void) info->mapnameedit = MC_AddEdit (menu, 64, 160, y, "map", "start"); y += 16; - menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 0, 32, NULL, false); + menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 0, menu->selecteditem->common.posy, NULL, false); info->lowercolour = bottomcolor.value; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 693011faf..57656b3f1 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -75,7 +75,7 @@ enum ASPECT2D_CUSTOM, }; -qboolean M_Vid_GetMode(int num, int *w, int *h) +qboolean M_Vid_GetMode(qboolean forfullscreen, int num, int *w, int *h) { int i; diff --git a/engine/client/net_master.c b/engine/client/net_master.c index c17278e63..5032433ab 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -82,6 +82,7 @@ static void SV_SetMaster_f (void); extern cvar_t sv_public; extern cvar_t sv_reportheartbeats; +extern cvar_t sv_heartbeat_interval; extern cvar_t sv_listen_qw; extern cvar_t sv_listen_nq; @@ -98,7 +99,7 @@ typedef struct { qboolean resolving; //set any time the cvar is modified netadr_t adr[MAX_MASTER_ADDRESSES]; } net_masterlist_t; -net_masterlist_t net_masterlist[] = { +static net_masterlist_t net_masterlist[] = { #ifndef QUAKETC //user-specified master lists. {MP_QUAKEWORLD, CVARC("net_qwmaster1", "", Net_Masterlist_Callback)}, @@ -244,12 +245,14 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master) char adr[MAX_ADR_SIZE]; netadr_t *na; int i; + int e; for (i = 0; i < MAX_MASTER_ADDRESSES; i++) { na = &master->adr[i]; if (na->port) { + e = -1; switch(master->protocol) { case MP_QUAKEWORLD: @@ -272,32 +275,26 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master) madeqwstring = true; } - if (sv_reportheartbeats.value) - { - if (sv_reportheartbeats.ival != 2 || !master->announced) - Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); - master->announced = true; - } - - NET_SendPacket (NS_SERVER, strlen(string), string, na); + e = NET_SendPacket (svs.sockets, strlen(string), string, na); } break; #ifdef Q2SERVER case MP_QUAKE2: - if (svs.gametype == GT_QUAKE2 && sv_listen_qw.value) //set listen to 1 to allow qw connections, 2 to allow nq connections too. + if (svs.gametype == GT_QUAKE2 && sv_listen_qw.value) //sv_listen==sv_listen_qw, yes, weird. { - if (sv_reportheartbeats.value) + char *str = "\377\377\377\377heartbeat\n%s\n%s"; + char info[8192]; + char q2users[8192]; + size_t i; + const char *infos[] = {"hostname", "*version", "deathmatch", "fraglimit", "timelimit", "gamedir", "mapname", "maxclients", "dmflags", NULL}; + InfoBuf_ToString(&svs.info, info, sizeof(info), NULL, NULL, infos, NULL, NULL); + q2users[0] = 0; + for (i = 0; i < sv.allocated_client_slots; i++) { - if (sv_reportheartbeats.ival != 2 || !master->announced) - Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); - master->announced = true; - } - - { - char *str = "\377\377\377\377heartbeat\n%s"; - char *q2statusresp = ""; - NET_SendPacket (NS_SERVER, strlen(str), va(str, q2statusresp), na); + if (svs.clients[i].state >= cs_connected) + Q_strncatz(q2users, va("%i %i \"%s\"\n", svs.clients[i].old_frags, SV_CalcPing(&svs.clients[i], false), svs.clients[i].name), sizeof(q2users)); } + e = NET_SendPacket (svs.sockets, strlen(str), va(str, info, q2users), na); } break; #endif @@ -311,22 +308,55 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master) if (sv_listen_dp.value || sv_listen_nq.value) #endif { - if (sv_reportheartbeats.value) - { - if (sv_reportheartbeats.ival != 2 || !master->announced) - Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); - master->announced = true; - } - - { - //darkplaces here refers to the master server protocol, rather than the game protocol - //(specifies that the server responds to infoRequest packets from the master) - char *str = "\377\377\377\377heartbeat DarkPlaces\x0A"; - NET_SendPacket (NS_SERVER, strlen(str), str, na); - } + //darkplaces here refers to the master server protocol, rather than the game protocol + //(specifies that the server responds to infoRequest packets from the master) + char *str = "\377\377\377\377heartbeat DarkPlaces\x0A"; + e = NET_SendPacket (svs.sockets, strlen(str), str, na); } break; default: + e = -2; + break; + } + switch(e) + { + case -1: //master not enabled for this game type + break; + case NETERR_SENT: + if (sv_reportheartbeats.value) + { + if (sv_reportheartbeats.ival != 2 || !master->announced) + { + COM_Parse(master->cv.string); + Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token); + } + master->announced = true; + } + break; + case NETERR_NOROUTE: + if (sv_reportheartbeats.value) + { + if (sv_reportheartbeats.ival != 2 || !master->announced) + { + COM_Parse(master->cv.string); + Con_TPrintf (CON_WARNING"No route for heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token); + } + master->announced = true; + } + break; + default: + case NETERR_DISCONNECTED: + case NETERR_MTU: + case NETERR_CLOGGED: + if (sv_reportheartbeats.value) + { + if (sv_reportheartbeats.ival != 2 || !master->announced) + { + COM_Parse(master->cv.string); + Con_TPrintf (CON_ERROR"Failed to send heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token); + } + master->announced = true; + } break; } } @@ -395,12 +425,12 @@ void SV_Master_Worker_Resolved(void *ctx, void *data, size_t a, size_t b) { #ifdef Q2SERVER case MP_QUAKE2: - NET_SendPacket (NS_SERVER, 8, "\xff\xff\xff\xffping", na); + NET_SendPacket (svs.sockets, 8, "\xff\xff\xff\xffping", na); break; #endif case MP_QUAKEWORLD: //qw does this for some reason, keep the behaviour even though its unreliable thus pointless - NET_SendPacket (NS_SERVER, 2, "k\0", na); + NET_SendPacket (svs.sockets, 2, "k\0", na); break; default: break; @@ -445,18 +475,18 @@ Send a message to the master every few minutes to let it know we are alive, and log information ================ */ -#define HEARTBEAT_SECONDS 300 void SV_Master_Heartbeat (void) { int i; + int interval = bound(90, sv_heartbeat_interval.ival, 600); if (sv_public.ival<=0 || SSV_IsSubServer()) return; - if (realtime-HEARTBEAT_SECONDS - svs.last_heartbeat < HEARTBEAT_SECONDS) + if (realtime-interval - svs.last_heartbeat < interval) return; // not time to send yet - svs.last_heartbeat = realtime-HEARTBEAT_SECONDS; + svs.last_heartbeat = realtime-interval; svs.heartbeat_sequence++; @@ -605,7 +635,7 @@ void SV_Master_Shutdown (void) if (sv_reportheartbeats.value) Con_TPrintf ("Sending shutdown to %s\n", NET_AdrToString (adr, sizeof(adr), na)); - NET_SendPacket (NS_SERVER, strlen(string), string, na); + NET_SendPacket (svs.sockets, strlen(string), string, na); break; //dp has no shutdown default: @@ -736,7 +766,7 @@ void Master_HideServer(serverinfo_t *server) else i++; } - server->status &= ~2u; + server->status &= ~SRVSTATUS_DISPLAYED; } void Master_InsertAt(serverinfo_t *server, int pos) @@ -754,7 +784,7 @@ void Master_InsertAt(serverinfo_t *server, int pos) visibleservers[pos] = server; numvisibleservers++; - server->status |= 2u; + server->status |= SRVSTATUS_DISPLAYED; } qboolean Master_CompareInteger(int a, int b, slist_test_t rule) @@ -907,8 +937,8 @@ qboolean Master_PassesMasks(serverinfo_t *a) qboolean val, res; // qboolean enabled; - //always filter out dead unresponsive servers. - if (!(a->status & 1)) + //always filter out dead/unresponsive servers. + if (!(a->status & SRVSTATUS_ALIVE)) return false; val = 1; @@ -1066,7 +1096,7 @@ void Master_ShowServer(serverinfo_t *server) void Master_ResortServer(serverinfo_t *server) { - if (server->status&2u) + if (server->status&SRVSTATUS_DISPLAYED) { if (!Master_PassesMasks(server)) Master_HideServer(server); @@ -1092,7 +1122,7 @@ int Master_SortServers(void) { numvisibleservers = 0; for (server = firstserver; server; server = server->next) - server->status &= ~2u; + server->status &= ~SRVSTATUS_DISPLAYED; } for (server = firstserver; server; server = server->next) @@ -2343,6 +2373,7 @@ void MasterInfo_ProcessHTTP(struct dl_download *dl) Master_ResortServer(info); } + info->status |= SRVSTATUS_GLOBAL; } } @@ -2450,6 +2481,7 @@ char *jsonnode(int level, char *node) Master_ResortServer(info); } + info->status |= SRVSTATUS_GLOBAL; } return node; @@ -2655,7 +2687,7 @@ void MasterInfo_Refresh(qboolean doreset) if (doreset) { for (info = firstserver; info; info = info->next) - info->status &= ~1; //hide until we get a new response from it. + info->status &= ~SRVSTATUS_ALIVE; //hide until we get a new response from it. } loadedone = false; @@ -2675,7 +2707,7 @@ void MasterInfo_Refresh(qboolean doreset) #ifndef QUAKETC Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_QWSERVER), MT_BCAST, MP_QUAKEWORLD, "Nearby QuakeWorld UDP servers."); // Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTP, MP_QUAKEWORLD, "gameaholic's QW master"); - Master_AddMasterHTTP("https://www.quakeservers.net/lists/servers/global.txt",MT_MASTERHTTP, MP_QUAKEWORLD, "QuakeServers.net (http)"); +// Master_AddMasterHTTP("https://www.quakeservers.net/lists/servers/global.txt",MT_MASTERHTTP, MP_QUAKEWORLD, "QuakeServers.net (http)"); #endif #ifdef NQPROT // Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master"); @@ -2904,7 +2936,7 @@ unsigned int Master_NumAlive(void) for (info = firstserver; info; info = info->next) { - if (info->status&1u) + if (info->status&SRVSTATUS_ALIVE) count++; } return count; @@ -3032,7 +3064,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor info->refreshtime = 0; } - info->status |= 1u; + info->status |= SRVSTATUS_ALIVE; nl = strchr(msg, '\n'); if (nl) @@ -3484,6 +3516,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) if ((old->special & (SS_PROTOCOLMASK)) != (type & (SS_PROTOCOLMASK))) old->special = type | (old->special & (SS_FAVORITE|SS_LOCAL)); old->sends = 1; //reset. + old->status |= SRVSTATUS_GLOBAL; Z_Free(info); } else @@ -3492,6 +3525,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) info->special = type; info->refreshtime = 0; + info->status |= SRVSTATUS_GLOBAL; Q_snprintfz(info->name, sizeof(info->name), "%s (via %s)", NET_AdrToString(adr, sizeof(adr), &info->adr), madr); diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index 04b6f9bb1..e6cc29240 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -707,14 +707,15 @@ void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_g } } -qboolean M_Vid_GetMode(int num, int *w, int *h); +qboolean M_Vid_GetMode(qboolean forfullscreen, int num, int *w, int *h); //a bit pointless really void QCBUILTIN PF_cl_getresolution (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { float mode = G_FLOAT(OFS_PARM0); -// qboolean fixedmodes = (prinst->callargc >= 2)?!G_FLOAT(OFS_PARM1):false; //if true, we should return sane-sized modes suitable for a window... or the mod could make up its own, but whatever. + qboolean forfullscreen = (prinst->callargc >= 2)?G_FLOAT(OFS_PARM1):true; //if true, we should return queried video modes... or the mod could make up its own, but whatever. float *ret = G_VECTOR(OFS_RETURN); int w, h; + float pixelheight = 0; w=h=0; if (mode == -1) @@ -723,11 +724,11 @@ void QCBUILTIN PF_cl_getresolution (pubprogfuncs_t *prinst, struct globalvars_s Sys_GetDesktopParameters(&w, &h, &bpp, &rate); } else - M_Vid_GetMode(mode, &w, &h); + M_Vid_GetMode(forfullscreen, mode, &w, &h); ret[0] = w; ret[1] = h; - ret[2] = (w&&h)?1:0; + ret[2] = pixelheight?pixelheight:((w&&h)?1:0); //pixelheight } #ifdef CL_MASTER @@ -988,7 +989,7 @@ static struct modlist_s static size_t nummods; static qboolean modsinited; -static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man) +/*static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man) { int i = nummods; modlist = BZ_Realloc(modlist, (i+1) * sizeof(*modlist)); @@ -997,7 +998,7 @@ static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man) modlist[i].description = man->formalname; nummods = i+1; return true; -} +}*/ static int QDECL Mods_AddGamedir(const char *fname, qofs_t fsize, time_t mtime, void *usr, searchpathfuncs_t *spath) { char *f; @@ -1027,7 +1028,7 @@ static int QDECL Mods_AddGamedir(const char *fname, qofs_t fsize, time_t mtime, return true; } } - f = FS_MallocFile(va("%s%s/modinfo.txt", usr, gamedir), FS_SYSTEM, NULL); + f = FS_MallocFile(va("%s%s/modinfo.txt", (const char*)usr, gamedir), FS_SYSTEM, NULL); if (f) { modlist = BZ_Realloc(modlist, (i+1) * sizeof(*modlist)); @@ -1070,7 +1071,6 @@ void QCBUILTIN PF_cl_getgamedirinfo(pubprogfuncs_t *prinst, struct globalvars_s if (modlist[diridx].description) RETURN_TSTRING(modlist[diridx].description); break; - //fallthrough case 0: //name RETURN_TSTRING(modlist[diridx].gamedir); break; @@ -1091,8 +1091,8 @@ void QCBUILTIN PF_cl_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s *pr_ char *send = Z_Malloc(4+strlen(contents)); send[0] = send[1] = send[2] = send[3] = 0xff; memcpy(send+4, contents, strlen(contents)); - //FIXME: NS_CLIENT is likely to change its port randomly... - G_FLOAT(OFS_RETURN) = NET_SendPacket(NS_CLIENT, 4+strlen(contents), send, &to); + //FIXME: this is likely to change its port randomly... + G_FLOAT(OFS_RETURN) = NET_SendPacket(cls.sockets, 4+strlen(contents), send, &to); Z_Free(send); } } diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index fa4a4e0d6..664a887ad 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -99,13 +99,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define QUAKEDEF_H__ -#ifdef SERVERONLY -#define isDedicated true -#endif -#ifdef CLIENTONLY -#define isDedicated false -#endif - #ifdef __linux__ #define PNG_SUCKS_WITH_SETJMP //cos it does. #endif @@ -154,8 +147,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern "C" { #endif -#include "translate.h" - #include "common.h" #include "bspfile.h" #include "vid.h" @@ -163,6 +154,7 @@ extern "C" { #include "zone.h" #include "mathlib.h" #include "cvar.h" +#include "translate.h" #include "net.h" #ifndef WEBSVONLY #include "protocol.h" @@ -375,8 +367,11 @@ void COM_AssertMainThread(const char *msg); extern qboolean msg_suppress_1; // suppresses resolution and cache size console output // an fullscreen DIB focus gain/loss - -#if !defined(SERVERONLY) && !defined(CLIENTONLY) +#ifndef HAVE_CLIENT +#define isDedicated true +#elif !defined(HAVE_SERVER) +#define isDedicated false +#else extern qboolean isDedicated; #endif extern qboolean wantquit; //flagged if we want to force a quit, safely breaking out of any modal stuff diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index c22981547..f9d2ff33e 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -1711,6 +1711,7 @@ char *particle_set_high = "surfaceparm nodlight\n" "glslprogram\n" "{\n" +"!!samps screen=0\n" "varying vec2 tcoord;\n" "varying vec4 scoord;\n" "varying float alph;\n" @@ -1738,7 +1739,7 @@ char *particle_set_high = // f = 1.0 - tcoord*tcoord; "if (f < 0.0) discard;\n" "f *= alph;\n" -"gl_FragColor = texture2D(s_t0, nst - tcoord*f);\n" +"gl_FragColor = texture2D(s_screen, nst - tcoord*f);\n" "}\n" "#endif\n" "}\n" diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 89fba59de..308ac3d06 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -127,7 +127,7 @@ cvar_t r_refractreflect_scale = CVARD ("r_refractreflect_scale", "0.5", "Use cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE); cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0"); cvar_t r_dynamic = CVARFD ("r_dynamic", IFMINIMAL("0","1"), - CVAR_ARCHIVE, "-1: the engine will bypass dlights completely, allowing for better batching.\n0: no standard dlights at all.\n1: coloured dlights will be used, they may show through walls. These are not realtime things.\n2: The dlights will be forced to monochrome (this does not affect coronas/flashblends/rtlights attached to the same light)."); + CVAR_ARCHIVE, "-1: the engine will use only pvs to determine which surfaces are visible. This can significantly reduce CPU time, but only if there are many surfaces with few textures visible from the camera.\n0: no standard dlights at all.\n1: coloured dlights will be used, they may show through walls. These are not realtime things.\n2: The dlights will be forced to monochrome (this does not affect coronas/flashblends/rtlights attached to the same light)."); cvar_t r_fastturb = CVARF ("r_fastturb", "0", CVAR_SHADERSYSTEM); cvar_t r_fastsky = CVARF ("r_fastsky", "0", @@ -1557,8 +1557,8 @@ TRACE(("dbg: R_ApplyRenderer: wad loaded\n")); Draw_Init(); TRACE(("dbg: R_ApplyRenderer: draw inited\n")); #ifdef MENU_NATIVECODE - if (mn_entry) - mn_entry->Init(MI_RENDERER, vid.width, vid.height, vid.rotpixelwidth, vid.rotpixelheight); + if (mn_entry) + mn_entry->Init(MI_RENDERER, vid.width, vid.height, vid.rotpixelwidth, vid.rotpixelheight); #endif R_Init(); RQ_Init(); diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index fac589d2e..d314ca391 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -104,7 +104,7 @@ cvar_t snd_khz = CVARAFD( "s_khz", DEFAULT_SND_KHZ, "snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz."); cvar_t snd_inactive = CVARAFD( "s_inactive", "1", "snd_inactive", CVAR_ARCHIVE, - "Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed." + "Play sound while application is inactive (ie: tabbed out). Needs a snd_restart if changed." ); //set if you want sound even when tabbed out. cvar_t _snd_mixahead = CVARAFD( "s_mixahead", "0.1", "_snd_mixahead", CVAR_ARCHIVE, "Specifies how many seconds to prebuffer audio. Lower values give less latency, but might result in crackling. Different hardware/drivers have different tolerances, and this setting may be ignored completely where drivers are expected to provide their own tolerances."); @@ -152,7 +152,7 @@ cvar_t snd_voip_send = CVARFD("cl_voip_send", "0", CVAR_ARCHIVE, "Sends voice- cvar_t snd_voip_test = CVARD("cl_voip_test", "0", "If 1, enables you to hear your own voice directly, bypassing the server and thus without networking latency, but is fine for checking audio levels. Note that sv_voip_echo can be set if you want to include latency and packetloss considerations, but setting that cvar requires server admin access and is thus much harder to use."); cvar_t snd_voip_vad_threshhold = CVARFD("cl_voip_vad_threshhold", "15", CVAR_ARCHIVE, "This is the threshhold for voice-activation-detection when sending voip data"); cvar_t snd_voip_vad_delay = CVARD("cl_voip_vad_delay", "0.3", "Keeps sending voice data for this many seconds after voice activation would normally stop"); -cvar_t snd_voip_capturingvol = CVARAFD("cl_voip_capturingvol", "0.5", NULL, CVAR_ARCHIVE, "Volume multiplier applied while capturing, to avoid your audio from being heard by others. Does not affect game volume when other speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used)."); +cvar_t snd_voip_capturingvol = CVARAFD("cl_voip_capturingvol", "0.5", NULL, CVAR_ARCHIVE, "Volume multiplier applied while capturing, to avoid your audio from being heard by others. Does not affect game volume when others speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used)."); cvar_t snd_voip_showmeter = CVARAFD("cl_voip_showmeter", "1", NULL, CVAR_ARCHIVE, "Shows your speech volume above the standard hud. 0=hide, 1=show when transmitting, 2=ignore voice-activation disable"); cvar_t snd_voip_play = CVARAFCD("cl_voip_play", "1", NULL, CVAR_ARCHIVE, S_Voip_Play_Callback, "Enables voip playback. Value is a volume scaler."); @@ -286,7 +286,11 @@ enum VOIP_INVALID = 16 //not currently generating audio. }; +#ifdef NOLEGACY +#define VOIP_DEFAULT_CODEC VOIP_OPUS +#else #define VOIP_DEFAULT_CODEC (cls.protocol==CP_QUAKEWORLD?VOIP_SPEEX_OLD:VOIP_OPUS) //opus is preferred, but ezquake is still common and only supports my first attempt at voice compression so favour that for quakeworld. +#endif static struct { struct diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 9fe4ca8c1..25b87ea16 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -114,15 +114,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif -#if defined(SERVERONLY) && defined(CLIENTONLY) - #undef CLIENTONLY //impossible build. assume the config had CLIENTONLY and they tried building a dedicated server -#endif -#ifndef WEBSVONLY - #ifndef CLIENTONLY - #define HAVE_SERVER +#ifdef MASTERONLY + #define SV_MASTER + #undef SUBSERVERS + #undef PLUGINS + #undef HUFFNETWORK + #undef SUPPORT_ICE + #undef WEBCLIENT + #undef LOADERTHREAD + #undef PACKAGEMANAGER + #undef PACKAGE_PK3 + #undef PACKAGE_Q1PAK + #undef PACKAGE_DOOMWAD + #undef PACKAGE_VPK + #undef PACKAGE_DZIP + #undef AVAIL_GZDEC +#else + #if defined(SERVERONLY) && defined(CLIENTONLY) + #undef CLIENTONLY //impossible build. assume the config had CLIENTONLY and they tried building a dedicated server #endif - #ifndef SERVERONLY - #define HAVE_CLIENT + #ifndef WEBSVONLY + #ifndef CLIENTONLY + #define HAVE_SERVER + #endif + #ifndef SERVERONLY + #define HAVE_CLIENT + #endif #endif #endif diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 58912f666..b33230295 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -65,7 +65,9 @@ cvar_t cfg_save_buttons = CVARFD("cfg_save_buttons", "0", CVAR_ARCHIVE|CVAR_NOTF cvar_t cl_warncmd = CVARF("cl_warncmd", "1", CVAR_NOSAVE|CVAR_NORESET); cvar_t cl_aliasoverlap = CVARF("cl_aliasoverlap", "1", CVAR_NOTFROMSERVER); +#ifdef HAVE_CLIENT cvar_t tp_disputablemacros = CVARF("tp_disputablemacros", "1", CVAR_SEMICHEAT); +#endif //============================================================================= @@ -120,9 +122,11 @@ static char *TP_MacroString (char *s, int *newaccesslevel, int *len) macro = ¯o_commands[i]; if (!Q_strcasecmp(s, macro->name)) { +#ifdef HAVE_CLIENT if (macro->disputableintentions) if (!tp_disputablemacros.ival) *newaccesslevel = 0; +#endif if (len) *len = strlen(macro->name); return macro->func(); @@ -187,7 +191,7 @@ static void Cmd_Wait_f (void) if (cmd_blockwait) return; -#ifndef CLIENTONLY +#ifdef HAVE_SERVER if (cmd_didwait && sv.state) Con_DPrintf("waits without server frames\n"); #endif @@ -531,7 +535,7 @@ void Cbuf_Execute (void) { int level; -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (cmd_text[RESTRICT_LOCAL].waitattime && cls.state == ca_active) { //keep binds blocked until after the next input frame was sent to the server (at which point it will be cleared @@ -876,7 +880,7 @@ static void Cmd_Echo_f (void) //echo text is often quoted, so expand the text again now that we're no longer in quotes. t = Cmd_ExpandString(text, extext, sizeof(extext), &level, !Cmd_IsInsecure()?true:false, true); -#ifdef SERVERONLY +#ifndef HAVE_CLIENT Con_Printf ("%s", t); #else t = TP_ParseFunChars(t); @@ -1163,7 +1167,7 @@ static void Cmd_Alias_f (void) } } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT static void Cmd_AliasEdit_f (void) { char *alias = Cmd_AliasExist(Cmd_Argv(1), RESTRICT_LOCAL); @@ -2579,7 +2583,7 @@ static void Cmd_Apropos_f (void) //FIXME: add aliases. } -#ifndef SERVERONLY // FIXME +#ifdef HAVE_CLIENT // FIXME /* =================== Cmd_ForwardToServer @@ -2731,29 +2735,29 @@ void Cmd_ExecuteString (const char *text, int level) Con_TPrintf("cmd '%s' was restricted.\n", cmd_argv[0]); else if (!cmd->function) { -#ifdef VM_CG +#if defined(VM_CG) && defined(HAVE_CLIENT) if (CG_Command()) return; #endif -#ifdef Q3SERVER +#if defined(Q3SERVER) && defined(HAVE_SERVER) if (SVQ3_Command()) return; #endif -#ifdef VM_UI +#if defined(VM_UI) && defined(HAVE_CLIENT) if (UI_Command()) return; #endif if (Cmd_AliasExist(cmd_argv[0], level)) break; //server stuffed an alias for a command that it would already have received. use that instead. -#if defined(CSQC_DAT) && !defined(SERVERONLY) +#if defined(CSQC_DAT) && defined(HAVE_CLIENT) if (CSQC_ConsoleCommand(-1, text)) return; //let the csqc handle it if it wants. #endif -#if defined(MENU_DAT) && !defined(SERVERONLY) +#if defined(MENU_DAT) && defined(HAVE_CLIENT) if (MP_ConsoleCommand(text)) return; //let the csqc handle it if it wants. #endif -#if defined(MENU_NATIVECODE) && !defined(SERVERONLY) +#if defined(MENU_NATIVECODE) && defined(HAVE_CLIENT) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) return; #endif @@ -2777,11 +2781,11 @@ void Cmd_ExecuteString (const char *text, int level) { int execlevel; -#ifndef SERVERONLY //an emergency escape mechansim, to avoid infinatly recursing aliases. +#ifdef HAVE_CLIENT //an emergency escape mechansim, to avoid infinatly recursing aliases. extern qboolean keydown[]; extern unsigned int con_splitmodifier; - if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT])) + if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT]) && !isDedicated) return; #endif @@ -2837,7 +2841,7 @@ void Cmd_ExecuteString (const char *text, int level) Q_strncpyz(dest, a->value, sizeof(dest)); Cbuf_InsertText (dest, execlevel, false); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (con_splitmodifier > 0) { //if the alias was execed via p1/p2 etc, make sure that propagates properly (at least for simple aliases like impulses) //fixme: should probably prefix each line. that may have different issues however. @@ -2910,15 +2914,15 @@ void Cmd_ExecuteString (const char *text, int level) return; } -#if defined(CSQC_DAT) && !defined(SERVERONLY) +#if defined(CSQC_DAT) && defined(HAVE_CLIENT) if (CSQC_ConsoleCommand(-1, text)) return; #endif -#if defined(MENU_DAT) && !defined(SERVERONLY) +#if defined(MENU_DAT) && defined(HAVE_CLIENT) if (MP_ConsoleCommand(text)) return; //let the csqc handle it if it wants. #endif -#if defined(MENU_NATIVECODE) && !defined(SERVERONLY) +#if defined(MENU_NATIVECODE) && defined(HAVE_CLIENT) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) return; #endif @@ -2928,7 +2932,7 @@ void Cmd_ExecuteString (const char *text, int level) return; #endif -#ifndef CLIENTONLY +#ifdef HAVE_SERVER if (sv.state) { if (PR_ConsoleCmd(text)) @@ -2936,19 +2940,19 @@ void Cmd_ExecuteString (const char *text, int level) } #endif -#ifdef VM_CG +#if defined(VM_CG) && defined(HAVE_CLIENT) if (CG_Command()) return; #endif -#ifdef Q3SERVER +#if defined(Q3SERVER) && defined(HAVE_SERVER) if (SVQ3_Command()) return; #endif -#ifdef VM_UI +#if defined(VM_UI) && defined(HAVE_CLIENT) if (UI_Command()) return; #endif -#ifdef Q2CLIENT +#if defined(Q2CLIENT) && defined(HAVE_CLIENT) if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) { //q2 servers convert unknown commands to text. Cmd_ForwardToServer(); @@ -3192,7 +3196,7 @@ static const char *If_Token_Term(const char *func, const char **end) else if (!strcmp(com_token, "vid")) //mostly for use with the menu system. { s = COM_ParseToken(s, IFPUNCT); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (qrenderer == QR_NONE) s2 = ""; else if (!strcmp(com_token, "width")) @@ -3978,7 +3982,9 @@ static void Cmd_WriteConfig_f(void) snprintf(fname, sizeof(fname), "fte.cfg"); #endif +#if defined(CL_MASTER) && defined(HAVE_CLIENT) MasterInfo_WriteServers(); +#endif f = FS_OpenWithFriends(fname, sysname, sizeof(sysname), 3, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg"); @@ -4007,7 +4013,7 @@ static void Cmd_WriteConfig_f(void) } VFS_PRINTF(f, "// %s config file\n\n", *fs_gamename.string?fs_gamename.string:FULLENGINENAME); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (cfg_save_binds.ival) Key_WriteBindings (f); if (cfg_save_buttons.ival) @@ -4022,11 +4028,11 @@ static void Cmd_WriteConfig_f(void) #else VFS_WRITE(f, "// Dedicated Server config\n\n", 28); #endif -#ifdef CLIENTONLY - VFS_WRITE(f, "// no local/server infos\n\n", 26); -#else +#ifdef HAVE_SERVER if (cfg_save_infos.ival) SV_SaveInfos(f); +#else + VFS_WRITE(f, "// no local/server infos\n\n", 26); #endif if (cfg_save_aliases.ival) Alias_WriteAliases (f); @@ -4042,7 +4048,7 @@ static void Cmd_Reset_f(void) { } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT // dumps current console contents to a text file static void Cmd_Condump_f(void) { @@ -4231,7 +4237,7 @@ void Cmd_Init (void) Cmd_AddCommand ("alias",Cmd_Alias_f); Cmd_AddCommand ("newalias",Cmd_Alias_f); Cmd_AddCommand ("wait", Cmd_Wait_f); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT Cmd_AddCommand ("cmd", Cmd_ForwardToServer_f); Cmd_AddCommand ("condump", Cmd_Condump_f); Cmd_AddCommandAD ("aliasedit", Cmd_AliasEdit_f, Key_Alias_c, NULL); @@ -4279,7 +4285,9 @@ void Cmd_Init (void) Cmd_AddMacro("qt", Macro_Quote, false); Cmd_AddMacro("dedicated", Macro_Dedicated, false); +#ifdef HAVE_CLIENT Cvar_Register(&tp_disputablemacros, "Teamplay"); +#endif Cvar_Register(&ruleset_allow_in, "Console"); Cmd_AddCommandD ("in", Cmd_In_f, "Issues the given command after a time delay. Disabled if ruleset_allow_in is 0."); @@ -4296,7 +4304,7 @@ void Cmd_Init (void) Cvar_Register (&cfg_save_binds, "client operation options"); Cvar_Register (&cfg_save_buttons, "client operation options"); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT rcon_level.ival = atof(rcon_level.enginevalue); //client is restricted to not be allowed to change restrictions. #else Cvar_Register(&rcon_level, "Access controls"); //server gains versatility. diff --git a/engine/common/common.c b/engine/common/common.c index cacf37199..8277d5542 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -25,6 +25,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include +#ifndef HAVE_CLIENT +double host_frametime; +double realtime; // without any filtering or bounding +qboolean host_initialized; // true if into command execution (compatability) +quakeparms_t host_parms; +int host_hunklevel; +#endif + + //by adding 'extern' to one definition of a function in a translation unit, then the definition in that TU is NOT considered an inline definition. meaning non-inlined references in other TUs can link to it instead of their own if needed. fte_inlinebody conchar_t *Font_Decode(conchar_t *start, unsigned int *codeflags, unsigned int *codepoint); fte_inlinebody float M_SRGBToLinear(float x, float mag); @@ -103,6 +112,12 @@ static char *safeargvs[] = static const char *largv[MAX_NUM_ARGVS + countof(safeargvs) + 1]; static char *argvdummy = " "; +#ifdef CRAZYDEBUGGING +cvar_t developer = CVAR("developer","1"); +#else +cvar_t developer = CVARD("developer","0", "Enables the spewing of additional developer/debugging messages. 2 will give even more spam, much of it unwanted."); +#endif + cvar_t registered = CVARD("registered","0","Set if quake's pak1.pak is available"); cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version for server browsers"); cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers"); @@ -111,7 +126,7 @@ cvar_t fs_gamename = CVARAFD("com_fullgamename", NULL, "fs_gamename", CVAR_NOSET cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers."); cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers. cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. -#ifndef NOLEGACY +#if !defined(NOLEGACY) && defined(HAVE_CLIENT) cvar_t com_parseezquake = CVARD("com_parseezquake", "0", "Treat chevron chars from configs as a per-character flag. You should use this only for compat with nquake's configs."); #endif cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); @@ -1131,7 +1146,7 @@ static unsigned int MSG_ReadEntity(void) return num; } //we use the high bit of the entity number to state that this is a large entity. -#ifndef CLIENTONLY +#ifdef HAVE_SERVER unsigned int MSGSV_ReadEntity(client_t *fromclient) { unsigned int num; @@ -1148,7 +1163,7 @@ unsigned int MSGSV_ReadEntity(client_t *fromclient) return num; } #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT unsigned int MSGCL_ReadEntity(void) { unsigned int num; @@ -1159,6 +1174,7 @@ unsigned int MSGCL_ReadEntity(void) return num; } #endif +#if defined(HAVE_CLIENT) || defined(HAVE_SERVER) void MSG_WriteEntity(sizebuf_t *sb, unsigned int entnum) { if (entnum > MAX_EDICTS) @@ -1172,6 +1188,7 @@ void MSG_WriteEntity(sizebuf_t *sb, unsigned int entnum) else MSG_WriteShort(sb, entnum); } +#endif void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd) { @@ -1181,8 +1198,8 @@ void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd) // send the movement message // bits = 0; -#ifdef Q2CLIENT - if (cls.protocol == CP_QUAKE2) +#if defined(Q2CLIENT) && defined(HAVE_CLIENT) + if (cls_state && cls.protocol == CP_QUAKE2) { unsigned char buttons = 0; if (cmd->angles[0] != from->angles[0]) @@ -1715,7 +1732,7 @@ vec3_t bytedirs[Q2NUMVERTEXNORMALS] = #include "../client/q2anorms.h" }; #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT void MSG_ReadDir (vec3_t dir) { int b; @@ -1774,7 +1791,7 @@ float MSG_ReadAngle (void) case 1: return MSG_ReadChar() * (360.0/256); default: - Host_Error("Bad angle size\n"); + Sys_Error("Bad angle size\n"); return 0; } } @@ -5720,7 +5737,9 @@ void COM_Init (void) COM_InitWorkerThread(); #endif +#ifdef PACKAGEMANAGER Cmd_AddCommandD("pkg", PM_Command_f, "Provides a way to install / list / disable / purge packages via the console."); +#endif Cmd_AddCommandD("version", COM_Version_f, "Reports engine revision and optional compile-time settings."); //prints the pak or whatever where this file can be found. #ifdef _DEBUG @@ -5730,6 +5749,7 @@ void COM_Init (void) #endif COM_InitFilesystem (); + Cvar_Register (&developer, "Debugging"); Cvar_Register (&sys_platform, "Gamecode"); Cvar_Register (®istered, "Copy protection"); Cvar_Register (&gameversion, "Gamecode"); @@ -5737,14 +5757,12 @@ void COM_Init (void) Cvar_Register (&gameversion_max, "Gamecode"); Cvar_Register (&com_nogamedirnativecode, "Gamecode"); Cvar_Register (&com_parseutf8, "Internationalisation"); -#ifndef NOLEGACY +#if !defined(NOLEGACY) && defined(HAVE_CLIENT) Cvar_Register (&com_parseezquake, NULL); #endif Cvar_Register (&com_highlightcolor, "Internationalisation"); com_parseutf8.ival = 1; - Cvar_Register (&r_meshpitch, "Gamecode"); - TranslateInit(); COM_BiDi_Setup(); @@ -7115,7 +7133,7 @@ void Info_Print (const char *s, const char *lineprefix) } }*/ - +#if defined(HAVE_CLIENT) || defined(HAVE_SERVER) static qbyte chktbl[1024 + 4] = { 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01, 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a, @@ -7350,6 +7368,7 @@ qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence) return crc; } +#endif #endif #ifdef _WIN32 @@ -7465,3 +7484,220 @@ void COM_TimeOfDay(date_t *date) strftime( date->str, 128, "%a %b %d, %H:%M:%S %Y", newtime); } + + + + + +/* +================ +Con_Printf + +Handles cursor positioning, line wrapping, etc +================ +*/ +#define MAXPRINTMSG 4096 +// FIXME: make a buffer size safe vsprintf? +void SV_FlushRedirect (void); +#ifndef HAVE_CLIENT + +vfsfile_t *con_pipe; +#ifdef HAVE_SERVER +vfsfile_t *Con_POpen(char *conname) +{ + if (!conname || !*conname) + { + if (con_pipe) + VFS_CLOSE(con_pipe); + con_pipe = VFSPIPE_Open(2, false); + return con_pipe; + } + return NULL; +} +#endif + +static void Con_PrintFromThread (void *ctx, void *data, size_t a, size_t b) +{ + Con_Printf("%s", (char*)data); + BZ_Free(data); +} +void VARGS Con_Printf (const char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + + if (!Sys_IsMainThread()) + { + COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0); + return; + } + +#ifdef HAVE_SERVER + // add to redirected message + if (sv_redirected) + { + if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) + SV_FlushRedirect (); + strcat (sv_redirected_buf, msg); + if (sv_redirected != -1) + return; + } +#endif + + Sys_Printf ("%s", msg); // also echo to debugging console + Con_Log(msg); // log to console + + if (con_pipe) + VFS_PUTS(con_pipe, msg); +} +void Con_TPrintf (translation_t stringnum, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + const char *fmt; + + if (!Sys_IsMainThread()) + { //shouldn't be redirected anyway... + fmt = langtext(stringnum,com_language); + va_start (argptr,stringnum); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0); + return; + } + +#ifdef HAVE_SERVER + // add to redirected message + if (sv_redirected) + { + fmt = langtext(stringnum,sv_redirectedlang); + va_start (argptr,stringnum); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + + if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) + SV_FlushRedirect (); + strcat (sv_redirected_buf, msg); + return; + } +#endif + + fmt = langtext(stringnum,com_language); + + va_start (argptr,stringnum); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + + Sys_Printf ("%s", msg); // also echo to debugging console + Con_Log(msg); // log to console + + if (con_pipe) + VFS_PUTS(con_pipe, msg); +} +/* +================ +Con_DPrintf + +A Con_Printf that only shows up if the "developer" cvar is set +================ +*/ +static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b) +{ + Con_DLPrintf(a, "%s", (char*)data); + BZ_Free(data); +} +void Con_DPrintf (const char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + extern cvar_t log_developer; + + if (!developer.value && !log_developer.value) + return; + + va_start (argptr,fmt); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + + if (!Sys_IsMainThread()) + { + COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0); + return; + } + +#ifdef HAVE_SERVER + // add to redirected message + if (sv_redirected) + { + if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) + SV_FlushRedirect (); + strcat (sv_redirected_buf, msg); + if (sv_redirected != -1) + return; + } +#endif + + if (developer.value) + Sys_Printf ("%s", msg); // also echo to debugging console + + if (log_developer.value) + Con_Log(msg); // log to console +} +void Con_DLPrintf (int level, const char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + extern cvar_t log_developer; + + if (developer.ival < level && !log_developer.value) + return; + + va_start (argptr,fmt); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + + if (!Sys_IsMainThread()) + { + COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), level, 0); + return; + } + +#ifdef HAVE_SERVER + // add to redirected message + if (sv_redirected) + { + if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) + SV_FlushRedirect (); + strcat (sv_redirected_buf, msg); + if (sv_redirected != -1) + return; + } +#endif + + if (developer.ival >= level) + Sys_Printf ("%s", msg); // also echo to debugging console + + if (log_developer.value) + Con_Log(msg); // log to console +} + +//for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local. +void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + + if (developerlevel) + Con_DLPrintf (developerlevel, "%s", msg); + else + Con_Printf("%s", msg); +} +#endif \ No newline at end of file diff --git a/engine/common/common.h b/engine/common/common.h index 4a5e2f40f..fed8a6456 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -129,16 +129,16 @@ typedef enum {false, true} qboolean; #define MAX_SERVERINFO_STRING 1024 //standard quake has 512 here. #define MAX_LOCALINFO_STRING 32768 -#ifdef SERVERONLY -#define cls_state 0 -#else +#ifdef HAVE_CLIENT #define cls_state cls.state +#else +#define cls_state 0 #endif -#ifdef CLIENTONLY -#define sv_state 0 -#else +#ifdef HAVE_SERVER #define sv_state sv.state +#else +#define sv_state 0 #endif struct netprim_s diff --git a/engine/common/cvar.c b/engine/common/cvar.c index cfe7d30a4..0643e7d0a 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -746,13 +746,15 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) latch = "variable %s is latched and will be applied for the start of the next map\n"; // else if (var->flags & CVAR_LATCHFLUSH) // latch = "variable %s is latched (type flush)\n"; +#ifdef HAVE_CLIENT else if (var->flags & CVAR_VIDEOLATCH && qrenderer != QR_NONE) latch = "variable %s will be changed after a vid_restart\n"; else if (var->flags & CVAR_RENDERERLATCH && qrenderer != QR_NONE) latch = "variable %s will be changed after a vid_reload\n"; +#endif else if (var->flags & CVAR_RULESETLATCH) latch = "variable %s is latched due to current ruleset\n"; -#ifndef SERVERONLY +#ifdef HAVE_CLIENT else if (var->flags & CVAR_CHEAT && !cls.allow_cheats && cls.state) latch = "variable %s is a cheat variable - latched\n"; else if (var->flags & CVAR_SEMICHEAT && !cls.allow_semicheats && cls.state) @@ -791,13 +793,13 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) return NULL; } -#ifndef CLIENTONLY +#ifdef HAVE_SERVER if (var->flags & CVAR_SERVERINFO) { InfoBuf_SetKey (&svs.info, var->name, value); } #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (var->flags & CVAR_SHADERSYSTEM) { if (var->string && value) @@ -849,10 +851,10 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) if (var->flags & CVAR_TELLGAMECODE) { -#ifndef CLIENTONLY +#ifdef HAVE_SERVER SVQ1_CvarChanged(var); #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT #ifdef MENU_DAT MP_CvarChanged(var); #endif @@ -1338,7 +1340,7 @@ qboolean Cvar_Command (int level) return true; } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (v->flags & CVAR_USERINFO) { int seat = CL_TargettedSplit(true); diff --git a/engine/common/fs.c b/engine/common/fs.c index 0831aa102..f925428c4 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -12,6 +12,10 @@ #include "winquake.h" #endif +#if (defined(HAVE_CLIENT) || defined(HAVE_SERVER)) && defined(WEBCLIENT) + #define MANIFESTDOWNLOADS +#endif + void FS_BeginManifestUpdates(void); static void QDECL fs_game_callback(cvar_t *var, char *oldvalue); static void COM_InitHomedir(ftemanifest_t *man); @@ -2614,7 +2618,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const BZ_Free(buffer); } +#ifdef PACKAGEMANAGER PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 0x80000000, -1); +#endif for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++) { @@ -2661,7 +2667,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const //now load ones from the manifest FS_AddManifestPackages(oldpaths, purepath, logicalpaths, search, loadstuff); +#ifdef PACKAGEMANAGER PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 0x0, 1000-1); +#endif //now load the random ones for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++) @@ -2678,7 +2686,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const } } +#ifdef PACKAGEMANAGER PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 1000, 0x7ffffffe); +#endif } static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purepath, const char *logicalpath, searchpathfuncs_t *handle, const char *prefix, unsigned int flags, unsigned int loadstuff) @@ -3057,7 +3067,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) FS_ChangeGame(man, cfg_reload_on_gamedir.ival, false); } -#if defined(NOLEGACY) || defined(SERVERONLY) +#if defined(NOLEGACY) || !defined(HAVE_CLIENT) #define ZFIXHACK #elif defined(ANDROID) //on android, these numbers seem to be generating major weirdness, so disable these. #define ZFIXHACK @@ -3267,6 +3277,7 @@ qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, in return true; } +#ifdef HAVE_CLIENT #if 0 qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags) { @@ -3511,7 +3522,7 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn { qboolean pureflush; -#ifndef CLIENTONLY +#ifdef HAVE_SERVER //if we're the server, we can't be impure. if (sv.state) return; @@ -3543,7 +3554,7 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn if (pureflush) { -#ifndef SERVERONLY +#ifdef HAVE_CLIENT Shader_NeedReload(true); #endif Mod_ClearAll(); @@ -3551,7 +3562,6 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn } } -#ifndef SERVERONLY int FS_PureOkay(void) { qboolean ret = true; @@ -3629,6 +3639,7 @@ int FS_PureOkay(void) } #endif +#ifdef Q3CLIENT char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) { //this is for q3 compatibility. @@ -3667,6 +3678,7 @@ char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) return buffer; } +#endif /* ================ @@ -4014,7 +4026,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags) if (next || i != orderkey)//some path changed. make sure the fs cache is flushed. FS_FlushFSHashReally(false); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT Shader_NeedReload(true); #endif // Mod_ClearAll(); @@ -4095,7 +4107,7 @@ static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir return false; } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { //'stolen' from microsoft's knowledge base. //required to work around microsoft being annoying. @@ -4139,7 +4151,7 @@ int MessageBoxU(HWND hWnd, char *lpText, char *lpCaption, UINT uType); qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char *poshname, const char *savedname) { -#ifndef SERVERONLY +#ifdef HAVE_CLIENT wchar_t resultpath[MAX_OSPATH]; wchar_t title[MAX_OSPATH]; BROWSEINFOW bi; @@ -4305,7 +4317,7 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base return true; } -#if !defined(NPFTE) && !defined(SERVERONLY) //this is *really* unfortunate, but doing this crashes the browser +#if !defined(NPFTE) && defined(HAVE_CLIENT) //this is *really* unfortunate, but doing this crashes the browser if (allowprompts && poshname && *gamename && !COM_CheckParm("-manifest")) { if (Sys_DoDirectoryPrompt(basepath, basepathlen, poshname, gamename)) @@ -4411,7 +4423,7 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base } } -#if !defined(NPFTE) && !defined(SERVERONLY) //this is *really* unfortunate, but doing this crashes the browser +#if !defined(NPFTE) && defined(HAVE_CLIENT) //this is *really* unfortunate, but doing this crashes the browser if (allowprompts && poshname && *gamename && !COM_CheckParm("-manifest")) { if (Sys_DoDirectoryPrompt(basepath, basepathlen, poshname, gamename)) @@ -4458,7 +4470,9 @@ void FS_Shutdown(void) if (!fs_thread_mutex) return; +#ifdef PACKAGEMANAGER PM_ManifestPackage(NULL, false); +#endif FS_FreePaths(); Sys_DestroyMutex(fs_thread_mutex); fs_thread_mutex = NULL; @@ -4659,7 +4673,7 @@ static void FS_AppendManifestGameArguments(ftemanifest_t *man) } } -#ifdef WEBCLIENT +#ifdef MANIFESTDOWNLOADS static char *FS_RelativeURL(char *base, char *file, char *buffer, int bufferlen) { //fixme: cope with windows paths @@ -4841,7 +4855,11 @@ static void FS_PackageDownloaded(struct dl_download *dl) if (fspdl_extracttype == X_UNZIP || fspdl_extracttype == X_MULTIUNZIP) //if zip... { //archive +#ifdef PACKAGE_PK3 searchpathfuncs_t *archive = FSZIP_LoadArchive(VFSOS_Open(fspdl_temppath, "rb"), NULL, dl->url, dl->url, ""); +#else + searchpathfuncs_t *archive = NULL; +#endif if (archive) { flocation_t loc; @@ -5416,17 +5434,20 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean qboolean reloadconfigs = false; qboolean builtingame = false; flocation_t loc; - qboolean allowvidrestart = true; +#ifdef HAVE_CLIENT + qboolean allowvidrestart = true; char *vidfile[] = {"gfx.wad", "gfx/conback.lmp", //misc stuff "gfx/palette.lmp", "pics/colormap.pcx"}; //palettes searchpathfuncs_t *vidpath[countof(vidfile)]; +#endif //if any of these files change location, the configs will be re-execed. //note that we reuse path handles if they're still valid, so we can just check the pointer to see if it got unloaded/replaced. char *conffile[] = {"quake.rc", "hexen.rc", "default.cfg", "server.cfg"}; searchpathfuncs_t *confpath[countof(conffile)]; +#ifdef HAVE_CLIENT for (i = 0; i < countof(vidfile); i++) { if (allowvidrestart) @@ -5437,6 +5458,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean else vidpath[i] = NULL; } +#endif if (allowreloadconfigs && fs_noreexec.ival) allowreloadconfigs = false; @@ -5600,7 +5622,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean { if (Sys_FindGameData(man->formalname, man->installation, realpath, sizeof(realpath), man->security != MANIFEST_SECURITY_INSTALLER) && FS_FixPath(realpath, sizeof(realpath)) && FS_DirHasAPackage(realpath, man)) Q_strncpyz (newbasedir, realpath, sizeof(newbasedir)); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT else { Z_Free(man->updatefile); @@ -5614,7 +5636,9 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean { if (strcmp(com_gamepath, newbasedir)) { +#ifdef PACKAGEMANAGER PM_Shutdown(); +#endif Q_strncpyz (com_gamepath, newbasedir, sizeof(com_gamepath)); } } @@ -5664,7 +5688,9 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean if (Sys_LockMutex(fs_thread_mutex)) { +#ifdef HAVE_CLIENT qboolean vidrestart = false; +#endif FS_ReloadPackFilesFlags(~0); @@ -5672,14 +5698,14 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean FS_BeginManifestUpdates(); -#ifdef WEBCLIENT +#ifdef MANIFESTDOWNLOADS if (curpackagedownload && fs_loadedcommand) allowreloadconfigs = false; #endif COM_CheckRegistered(); - +#ifdef HAVE_CLIENT if (qrenderer != QR_NONE && allowvidrestart) { for (i = 0; i < countof(vidfile); i++) @@ -5692,6 +5718,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean } } } +#endif if (allowreloadconfigs) { @@ -5714,28 +5741,30 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean Cvar_ForceSet(&fs_gamename, fs_gamename.enginevalue); Cvar_ForceSet(&pm_downloads_url, pm_downloads_url.enginevalue); Cvar_ForceSet(&com_protocolname, com_protocolname.enginevalue); +#ifdef HAVE_CLIENT vidrestart = false; +#endif if (isDedicated) { - #ifndef CLIENTONLY +#ifdef HAVE_SERVER SV_ExecInitialConfigs(man->defaultexec?man->defaultexec:""); - #endif +#endif } else { - #ifndef SERVERONLY +#ifdef HAVE_CLIENT CL_ExecInitialConfigs(man->defaultexec?man->defaultexec:""); - #endif +#endif } } +#ifdef HAVE_CLIENT else if (vidrestart) { -#ifndef SERVERONLY Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL); -#endif vidrestart = false; } +#endif if (fs_loadedcommand) { Cbuf_AddText(fs_loadedcommand, RESTRICT_INSECURE); @@ -5743,19 +5772,19 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean fs_loadedcommand = NULL; } } +#ifdef HAVE_CLIENT if (vidrestart) { -#ifndef SERVERONLY Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL); -#endif vidrestart = false; } +#endif //rebuild the cache now, should be safe to waste some cycles on it COM_FlushFSCache(false, true); } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT Validation_FlushFileList(); //prevent previous hacks from making a difference. #endif @@ -6051,13 +6080,15 @@ static void FS_ChangeGame_f(void) if (!Q_strcasecmp(gamemode_info[i].argname+1, arg)) { Con_Printf("Switching to %s\n", gamemode_info[i].argname+1); +#ifdef PACKAGEMANAGER PM_Shutdown(); +#endif FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, i), true, true); return; } } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (!Host_RunFile(arg, strlen(arg), NULL)) Con_Printf("Game unknown\n"); #endif diff --git a/engine/common/log.c b/engine/common/log.c index 697894232..19415690c 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -520,7 +520,7 @@ static void IPLog_Identify_f(void) //treading carefully here, to avoid dns name lookups weirding everything out. IPLog_Identify(&adr, &mask, "Identity of %s", NET_AdrToStringMasked(clean, sizeof(clean), &adr, &mask)); } -#ifndef CLIENTONLY +#ifdef HAVE_SERVER else if (sv.active) { //if server is active, walk players to see if there's a name match to get their address and guess an address mask client_t *cl; @@ -537,7 +537,7 @@ static void IPLog_Identify_f(void) } } #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT else if (cls.state >= ca_connected) { //else if client is active, walk players to see if there's a name match, to get their address+mask if known via nq hacks int slot; @@ -630,7 +630,7 @@ static void IPLog_Merge_f(void) } #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT //requires UI prompts struct certlog_s { link_t l; @@ -849,7 +849,7 @@ void Log_Init(void) if (COM_CheckParm("-condebug")) Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1"); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT ClearLink(&certlog); Cmd_AddCommand("dtls_untrustall", CertLog_UntrustAll_f); Cmd_AddCommand("dtls_importtrust", CertLog_Import_f); diff --git a/engine/common/net.h b/engine/common/net.h index 26bf3a99f..ba7c942d3 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -131,14 +131,14 @@ void SVNET_RegisterCvars(void); void NET_InitClient (qboolean loopbackonly); void NET_CloseClient(void); void NET_InitServer (void); -qboolean NET_WasSpecialPacket(netsrc_t netsrc); +qboolean NET_WasSpecialPacket(struct ftenet_connections_s *col); void NET_CloseServer (void); void UDP_CloseSocket (int socket); void NET_Shutdown (void); qboolean NET_GetRates(struct ftenet_connections_s *collection, float *pi, float *po, float *bi, float *bo); qboolean NET_UpdateRates(struct ftenet_connections_s *collection, qboolean inbound, size_t size); //for demos to not be weird -int NET_GetPacket (netsrc_t netsrc, int firstsock); -neterr_t NET_SendPacket (netsrc_t socket, int length, const void *data, netadr_t *to); +int NET_GetPacket (struct ftenet_connections_s *col, int firstsock); +neterr_t NET_SendPacket (struct ftenet_connections_s *col, int length, const void *data, netadr_t *to); int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx); void NET_PrintAddresses(struct ftenet_connections_s *collection); qboolean NET_AddressSmellsFunny(netadr_t *a); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 9d85cd65e..456d29164 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -91,6 +91,14 @@ cvar_t pext_infoblobs = CVARD("_pext_infoblobs", "0", "RENAME ME WHEN STABLE. En cvar_t pext_replacementdeltas = CVARD("pext_replacementdeltas", "1", "Enables the use of alternative nack-based entity deltas"); cvar_t pext_predinfo = CVARD("pext_predinfo", "1", "Enables some extra things to support prediction over NQ protocols."); +#if defined(HAVE_CLIENT) && defined(HAVE_SERVER) +#define NET_SendPacket(c,s,d,t) NET_SendPacket(((c)!=NS_CLIENT)?svs.sockets:cls.sockets,s,d,t) +#elif defined(HAVE_SERVER) +#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t) +#else +#define NET_SendPacket(c,s,d,t) NET_SendPacket(cls.sockets,s,d,t) +#endif + /*returns the entire bitmask of supported+enabled extensions*/ unsigned int Net_PextMask(int maskset, qboolean fornq) { diff --git a/engine/common/net_ice.c b/engine/common/net_ice.c index 3918eb804..de8454bc4 100644 --- a/engine/common/net_ice.c +++ b/engine/common/net_ice.c @@ -209,7 +209,7 @@ qboolean NET_RTP_Transmit(unsigned int sequence, unsigned int timestamp, const c if (buf.overflowed) return built; } - NET_SendPacket(NS_CLIENT, buf.cursize, buf.data, &con->chosenpeer); + NET_SendPacket(cls.sockets, buf.cursize, buf.data, &con->chosenpeer); break; } } @@ -525,7 +525,7 @@ void ICE_ToStunServer(struct icestate_s *con) data[2] = ((buf.cursize-20)>>8)&0xff; data[3] = ((buf.cursize-20)>>0)&0xff; - NET_SendPacket((con->proto==ICEP_QWSERVER)?NS_SERVER:NS_CLIENT, buf.cursize, data, &con->pubstunserver); + NET_SendPacket(collection, buf.cursize, data, &con->pubstunserver); } void QDECL ICE_AddRCandidateInfo(struct icestate_s *con, struct icecandinfo_s *n) @@ -1129,10 +1129,10 @@ icefuncs_t iceapi = ICE_GetLCandidateSDP }; -qboolean ICE_WasStun(netsrc_t netsrc) +qboolean ICE_WasStun(ftenet_connections_t *col) { -#if !defined(SERVERONLY) && defined(VOICECHAT) - if (netsrc == NS_CLIENT) +#if defined(HAVE_CLIENT) && defined(VOICECHAT) + if (col == cls.sockets) { if (NET_RTP_Parse()) return true; @@ -1528,7 +1528,7 @@ qboolean ICE_WasStun(netsrc_t netsrc) data[2] = ((buf.cursize-20)>>8)&0xff; data[3] = ((buf.cursize-20)>>0)&0xff; - NET_SendPacket(netsrc, buf.cursize, data, &net_from); + NET_SendPacket(col, buf.cursize, data, &net_from); } } diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 29b97fc3a..6cb58eaa5 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -463,7 +463,7 @@ static struct static int SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file, int ret) { -#ifndef SERVERONLY +#ifdef HAVE_CLIENT //when using dtls, we expect self-signed certs and persistent trust. if (file->datagram) { diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 06ecd6bde..5b9041206 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -108,10 +108,14 @@ void (*pfreeaddrinfo) (struct addrinfo*); #endif #endif -#if defined(HAVE_IPV4) && !defined(CLIENTONLY) +#if defined(HAVE_IPV4) && defined(HAVE_SERVER) #define HAVE_NATPMP #endif +#if defined(HAVE_SERVER) || defined(MASTERONLY) +#define HAVE_HTTPSV +#endif + void NET_GetLocalAddress (int socket, netadr_t *out); //int TCP_OpenListenSocket (const char *localip, int port); #ifdef HAVE_IPV6 @@ -124,17 +128,23 @@ cvar_t timeout = CVARD("timeout","65", "Connections will time out if no pack cvar_t net_hybriddualstack = CVARD("net_hybriddualstack", "1", "Uses hybrid ipv4+ipv6 sockets where possible. Not supported on xp or below."); cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1."); cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network access, including name resolution and socket creation. Does not affect loopback/internal connections."); -#if defined(TCPCONNECT) && !defined(CLIENTONLY) +#if defined(TCPCONNECT) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV)) +#ifdef HAVE_SERVER cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless."); cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command."); +#endif #if defined(HAVE_SSL) cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port."); #endif +#ifdef SV_MASTER +cvar_t net_enable_http = CVARD("net_enable_http", "1", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay."); +#else cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay."); +#endif cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients."); cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections."); #endif -#if defined(HAVE_DTLS) && !defined(CLIENTONLY) +#if defined(HAVE_DTLS) && defined(HAVE_SERVER) static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue) { //set up the default value @@ -156,7 +166,7 @@ static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue) cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections)."); #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT static void QDECL cl_delay_packets_Announce(cvar_t *var, char *oldval) { if (cls.state >= ca_connected && cl.fpd & FPD_ANOUNCE_FAKE_LAG) @@ -2079,7 +2089,7 @@ int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize) ///////////////////////////////////////////// //loopback stuff -#if !defined(CLIENTONLY) && !defined(SERVERONLY) +#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) qboolean NET_GetLoopPacket (int sock, netadr_t *from, sizebuf_t *message) { @@ -2240,7 +2250,7 @@ ftenet_connections_t *FTENET_CreateCollection(qboolean listen) col->islisten = listen; return col; } -#if !defined(SERVERONLY) && !defined(CLIENTONLY) +#if defined(HAVE_CLIENT) && defined(HAVE_SERVER) static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean isserver, const char *address, netadr_t adr); #endif #ifdef HAVE_PACKET @@ -2438,11 +2448,11 @@ static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connectio //get the public ip. pmpreqmsg.op = 0; - NET_SendPacket(NS_SERVER, 2, &pmpreqmsg, &pmp->pmpaddr); + NET_SendPacket(collection, 2, &pmpreqmsg, &pmp->pmpaddr); //open the firewall/nat. pmpreqmsg.op = 1; - NET_SendPacket(NS_SERVER, sizeof(pmpreqmsg), &pmpreqmsg, &pmp->pmpaddr); + NET_SendPacket(collection, sizeof(pmpreqmsg), &pmpreqmsg, &pmp->pmpaddr); break; } @@ -2837,7 +2847,7 @@ qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, con #ifdef HAVE_NATPMP if (adr[i].prot == NP_NATPMP&& adr[i].type == NA_IP) establish[i] = FTENET_NATPMP_EstablishConnection; else #endif -#if !defined(CLIENTONLY) && !defined(SERVERONLY) +#if defined(HAVE_CLIENT) && defined(HAVE_SERVER) if (adr[i].prot == NP_DGRAM && adr[i].type == NA_LOOPBACK) establish[i] = FTENET_Loop_EstablishConnection; else #endif #ifdef HAVE_IPV4 @@ -3231,7 +3241,7 @@ qboolean FTENET_Datagram_GetPacket(ftenet_generic_connection_t *con) else Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost. resettime = curtime; -#ifndef SERVERONLY +#ifdef HAVE_CLIENT //fixme: synthesise a reset packet for the caller to handle? "\xff\xff\xff\xffreset" ? if (cls.state != ca_disconnected && !con->islisten) { @@ -3324,6 +3334,9 @@ neterr_t FTENET_Datagram_SendPacket(ftenet_generic_connection_t *con, int length if (ecode == NET_EMSGSIZE) return NETERR_MTU; + if (ecode == EADDRNOTAVAIL) + return NETERR_NOROUTE; //this interface doesn't actually support that (eg: happens when ipv6 is disabled on a specific interface). + if (ecode == NET_EACCES) { Con_Printf("Access denied: check firewall\n"); @@ -3340,7 +3353,7 @@ neterr_t FTENET_Datagram_SendPacket(ftenet_generic_connection_t *con, int length default: prot = ""; break; } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (ecode == NET_EADDRNOTAVAIL) Con_DPrintf("NET_Send%sPacket Warning: %i\n", prot, ecode); else @@ -3652,7 +3665,7 @@ typedef struct ftenet_tcpconnect_stream_s { TCPC_WEBSOCKETU, //utf-8 encoded data. TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary') TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV TCPC_HTTPCLIENT, //we're sending a file to this victim. TCPC_WEBRTC_CLIENT, //for brokering webrtc connections, doesn't carry any actual game data itself. TCPC_WEBRTC_HOST //for brokering webrtc connections, doesn't carry any actual game data itself. @@ -3670,7 +3683,7 @@ typedef struct ftenet_tcpconnect_stream_s { int fakesequence; //TCPC_WEBSOCKETNQ -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV struct { qboolean connection_close; @@ -3810,7 +3823,7 @@ neterr_t FTENET_TCPConnect_WebSocket_Splurge(ftenet_tcpconnect_stream_t *st, qby return NETERR_SENT; } -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV enum { WCATTR_METHOD, @@ -3866,7 +3879,9 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_ char *extraheaders = ""; time_t modificationtime = 0; char *query = strchr(arg[WCATTR_URL]+1, '?'); +#ifdef HAVE_SERVER func_t func = 0; +#endif if (query) *query++ = 0; @@ -3875,6 +3890,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_ if (!*name) name = "index.html"; +#ifdef HAVE_SERVER if (sv.state && svs.gametype == GT_PROGS && svprogfuncs) func = svprogfuncs->FindFunction(svprogfuncs, "HTTP_GeneratePage", PR_ANY); @@ -3898,42 +3914,12 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_ resp = va("%s%s", *body?"HTTP/1.1 200 Ok\r\n":"HTTP/1.1 404 File Not Found\r\n", resp); } } +#endif //FIXME: provide some resource->filename mapping that allows various misc files. if (body) ; - else if (!strcmp(name, "index.html")) - { - resp = "HTTP/1.1 200 Ok\r\n" - "Content-Type: text/html\r\n"; - - body = va( - "" - "" - "" - "" - "" -#ifdef _WIN32 - "" -#else - "" -#endif - "%s - %s" - "" - "" - "" - "" - "" - "" - ,fs_manifest->formalname, hostname.string, ENGINEWEBSITE, fs_manifest->installation, (st->remoteaddr.prot==NP_TLS)?"wss://":"ws://", arg[WCATTR_HOST]); - } #ifdef _WIN32 else if (!strcmp(name, "favicon.ico")) { //we can serve up the icon from the exe. we just have to reformat it a little. @@ -4001,6 +3987,42 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_ } } #endif +#if defined(SV_MASTER) && !defined(HAVE_SERVER) + else if ((st->dlfile=SVM_GenerateIndex(name))) + ; +#endif +#ifdef HAVE_SERVER + else if (!strcmp(name, "index.html")) + { + resp = "HTTP/1.1 200 Ok\r\n" + "Content-Type: text/html\r\n"; + + body = va( + "" + "" + "" + "" + "" +#ifdef _WIN32 + "" +#else + "" +#endif + "%s - %s" + "" + "" + "" + "" + "" + "" + ,fs_manifest->formalname, hostname.string, ENGINEWEBSITE, fs_manifest->installation, (st->remoteaddr.prot==NP_TLS)?"wss://":"ws://", arg[WCATTR_HOST]); + } /*else if (!strcmp(name, "default.fmf") && (st->dlfile = FS_OpenVFS("default.fmf", "rb", FS_ROOT))) { resp = "HTTP/1.1 200 Ok\r\n" @@ -4095,6 +4117,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_ else st->dlfile = NULL; } +#endif if (st->dlfile) { char etag[64]; @@ -4700,7 +4723,7 @@ void FTENET_TCPConnect_PrintStatus(ftenet_generic_connection_t *gcon) case TCPC_WEBSOCKETNQ: Con_Printf("websocket %s\n", adr); break; -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV case TCPC_HTTPCLIENT: Con_Printf("http %s\n", adr); break; @@ -4750,7 +4773,7 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) if (st->timeouttime < timeval) { -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV if (!st->pinging && (st->clienttype==TCPC_WEBRTC_CLIENT||st->clienttype==TCPC_WEBRTC_HOST) && *st->webrtc.resource) { //ping broker clients. there usually shouldn't be any data flow to keep it active otherwise. st->timeouttime = timeval + 30; @@ -4761,7 +4784,7 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) else #endif { - Con_Printf ("tcp peer %s timed out\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); + Con_DPrintf ("tcp peer %s timed out\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); goto closesvstream; } } @@ -4784,10 +4807,11 @@ closesvstream: if (st->inlen < 6) continue; -#if defined(HAVE_SSL) && !defined(CLIENTONLY) //if its non-ascii, then try and upgrade the connection to tls +#if defined(HAVE_SSL) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV)) //if its non-ascii, then try and upgrade the connection to tls if (net_enable_tls.ival && con->generic.islisten && st->remoteaddr.prot == NP_STREAM && st->clientstream && !((st->inbuffer[0] >= 'a' && st->inbuffer[0] <= 'z') || (st->inbuffer[0] >= 'A' && st->inbuffer[0] <= 'Z'))) { //copy off our buffer so we can read it into the tls stream's buffer instead. + char tmpbuf[256]; vfsfile_t *stream = st->clientstream; int (QDECL *realread) (struct vfsfile_s *file, void *buffer, int bytestoread); realread = stream->ReadBytes; @@ -4806,6 +4830,8 @@ closesvstream: } if (!st->clientstream || net_message.cursize) goto closesvstream; //something cocked up. we didn't give the tls stream all the data. + if (developer.ival) + Con_Printf("promoted peer to tls: %s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &st->remoteaddr)); net_message.cursize = 0; continue; } @@ -4813,11 +4839,11 @@ closesvstream: if (!strncmp(st->inbuffer, "qizmo\n", 6)) { -#ifdef CLIENTONLY - if (1) -#else - if (net_enable_qizmo.ival || !con->generic.islisten) + if ( +#ifdef HAVE_SERVER + net_enable_qizmo.ival || #endif + !con->generic.islisten) { memmove(st->inbuffer, st->inbuffer+6, st->inlen - (6)); st->inlen -= 6; @@ -4830,9 +4856,9 @@ closesvstream: } else goto closesvstream; - } -#ifndef CLIENTONLY - else if (con->generic.islisten)// && !strncmp(st->inbuffer, "GET ", 4)) + }else +#ifdef HAVE_HTTPSV + if (con->generic.islisten)// && !strncmp(st->inbuffer, "GET ", 4)) { //qtv or http request header. these terminate with a blank line. int i = 0; @@ -4889,16 +4915,15 @@ closesvstream: } continue; } - } + }else #endif - else { - Con_Printf ("Unknown TCP handshake from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); + Con_DPrintf ("Unknown TCP handshake from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); goto closesvstream; } break; -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV case TCPC_HTTPCLIENT: if (st->outlen) { /*try and flush the old data*/ @@ -4924,7 +4949,7 @@ closesvstream: VFS_CLOSE(st->dlfile); st->dlfile = NULL; st->clienttype = TCPC_UNKNOWN; - Con_Printf ("Outgoing file transfer complete\n"); + Con_DPrintf ("Outgoing file transfer complete\n"); if (st->httpstate.connection_close) goto closesvstream; } @@ -4958,7 +4983,7 @@ closesvstream: case TCPC_WEBSOCKETU: case TCPC_WEBSOCKETB: case TCPC_WEBSOCKETNQ: -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV case TCPC_WEBRTC_HOST: case TCPC_WEBRTC_CLIENT: #endif @@ -5108,7 +5133,7 @@ closesvstream: Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); goto closesvstream; } -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV #ifdef SUPPORT_RTC_ICE if (st->clienttype == TCPC_WEBRTC_CLIENT && !*st->webrtc.resource) { //this is a client that's corrected directly to us via webrtc. @@ -5211,6 +5236,8 @@ closesvstream: st = Z_Malloc(sizeof(*con->tcpstreams)); /*grab the net address*/ SockadrToNetadr(&from, fromlen, &st->remoteaddr); + if (developer.ival) + Con_Printf("new TCP connection from %s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &st->remoteaddr)); st->clienttype = TCPC_UNKNOWN; st->next = con->tcpstreams; con->tcpstreams = st; @@ -5489,7 +5516,7 @@ int FTENET_TCPConnect_SetFDSets(ftenet_generic_connection_t *gcon, fd_set *readf #endif if (st->clientstream == NULL || st->socketnum == INVALID_SOCKET) continue; -#ifndef CLIENTONLY +#ifdef HAVE_HTTPSV if (st->clienttype == TCPC_HTTPCLIENT) FD_SET(st->socketnum, writefdset); // network socket #endif @@ -6839,7 +6866,7 @@ qboolean NET_GetRates(ftenet_connections_t *collection, float *pi, float *po, fl return true; } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT //for demo playback qboolean NET_UpdateRates(ftenet_connections_t *collection, qboolean inbound, size_t size) { @@ -6877,29 +6904,10 @@ qboolean NET_UpdateRates(ftenet_connections_t *collection, qboolean inbound, siz #endif /*firstsock is a cookie*/ -int NET_GetPacket (netsrc_t netsrc, int firstsock) +int NET_GetPacket (ftenet_connections_t *collection, int firstsock) { struct ftenet_delayed_packet_s *p; - ftenet_connections_t *collection; unsigned int ctime; - if (netsrc == NS_SERVER) - { -#ifdef CLIENTONLY - Sys_Error("NET_GetPacket: Bad netsrc"); - collection = NULL; -#else - collection = svs.sockets; -#endif - } - else - { -#ifdef SERVERONLY - Sys_Error("NET_GetPacket: Bad netsrc"); - collection = NULL; -#else - collection = cls.sockets; -#endif - } if (!collection) return -1; @@ -7032,45 +7040,30 @@ static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, return NETERR_NOROUTE; } -neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t *to) +neterr_t NET_SendPacket (ftenet_connections_t *collection, int length, const void *data, netadr_t *to) { - ftenet_connections_t *collection; - - if (netsrc == NS_SERVER) - { -#ifdef CLIENTONLY - Sys_Error("NET_GetPacket: Bad netsrc"); + if (!collection) return NETERR_NOROUTE; -#else - collection = svs.sockets; -#endif - } - else - { -#ifdef SERVERONLY - Sys_Error("NET_GetPacket: Bad netsrc"); - return NETERR_NOROUTE; -#else - collection = cls.sockets; - if (cl_delay_packets.ival >= 1 && !(cl.fpd & FPD_NO_FAKE_LAG)) - { - struct ftenet_delayed_packet_s *p, **l; - if (!collection) - return NETERR_NOROUTE; //erk... - p = BZ_Malloc(sizeof(*p) - sizeof(p->data) + length); - p->sendtime = Sys_Milliseconds() + cl_delay_packets.ival; - p->next = NULL; - p->cursize = length; - p->dest = *to; - memcpy(p->data, data, length); - for (l = &collection->delayed_packets; *l; l = &((*l)->next)) - ; - *l = p; - return NETERR_SENT; //fixme: mtu, noroute, etc... panic? only allow if udp dest? - } -#endif +#ifdef HAVE_CLIENT + if (collection == cls.sockets && cl_delay_packets.ival >= 1 && !(cl.fpd & FPD_NO_FAKE_LAG)) + { + struct ftenet_delayed_packet_s *p, **l; + if (!collection) + return NETERR_NOROUTE; //erk... + p = BZ_Malloc(sizeof(*p) - sizeof(p->data) + length); + p->sendtime = Sys_Milliseconds() + cl_delay_packets.ival; + p->next = NULL; + p->cursize = length; + p->dest = *to; + memcpy(p->data, data, length); + for (l = &collection->delayed_packets; *l; l = &((*l)->next)) + ; + *l = p; + return NETERR_SENT; //fixme: mtu, noroute, etc... panic? only allow if udp dest? } +#endif + #ifdef HAVE_DTLS if (to->prot == NP_DTLS) return FTENET_DTLS_SendPacket(collection, length, data, to); @@ -7592,7 +7585,6 @@ void IPX_CloseSocket (int socket) // sleeps msec or until net socket is ready //stdin can sometimes be a socket. As a result, //we give the option to select it for nice console imput with timeouts. -#ifndef CLIENTONLY qboolean NET_Sleep(float seconds, qboolean stdinissocket) { #ifdef HAVE_PACKET @@ -7613,6 +7605,34 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket) maxfd = sock; } +#ifdef SV_MASTER + { + extern ftenet_connections_t *svm_sockets; + if (svm_sockets) + for (con = 0; con < MAX_CONNECTIONS; con++) + { + if (!svm_sockets->conn[con]) + continue; + if (svm_sockets->conn[con]->SetFDSets) + { + sock = svm_sockets->conn[con]->SetFDSets(svm_sockets->conn[con], &readfdset, &writefdset); + if (sock > maxfd) + maxfd = sock; + } + else + { + sock = svm_sockets->conn[con]->thesocket; + if (sock != INVALID_SOCKET) + { + FD_SET(sock, &readfdset); // network socket + if (sock > maxfd) + maxfd = sock; + } + } + } + } +#endif +#ifdef HAVE_SERVER if (svs.sockets) for (con = 0; con < MAX_CONNECTIONS; con++) { @@ -7635,6 +7655,7 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket) } } } +#endif if (seconds > 4.0) //realy? oh well. seconds = 4.0; @@ -7654,7 +7675,6 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket) #endif return true; } -#endif //this function is used to determine the 'default' local address. //this is used for compat with gamespy which insists on sending us a packet via that interface and not something more sensible like 127.0.0.1 @@ -7725,7 +7745,7 @@ void NET_GetLocalAddress (int socket, netadr_t *out) out->type = NA_INVALID; } -#ifndef CLIENTONLY +#ifdef HAVE_SERVER void SVNET_AddPort_f(void) { char *s = Cmd_Argv(1); @@ -7745,7 +7765,7 @@ void SVNET_AddPort_f(void) if (!svs.sockets) { svs.sockets = FTENET_CreateCollection(true); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM); #endif } @@ -7754,7 +7774,7 @@ void SVNET_AddPort_f(void) } #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT void NET_ClientPort_f(void) { Con_Printf("Active Client ports:\n"); @@ -7763,31 +7783,15 @@ void NET_ClientPort_f(void) } #endif -qboolean NET_WasSpecialPacket(netsrc_t netsrc) +qboolean NET_WasSpecialPacket(ftenet_connections_t *collection) { -#if defined(HAVE_NATPMP) - ftenet_connections_t *collection = NULL; - if (netsrc == NS_SERVER) - { -#ifndef CLIENTONLY - collection = svs.sockets; -#endif - } - else - { -#ifndef SERVERONLY - collection = cls.sockets; -#endif - } - #ifdef HAVE_NATPMP if (NET_Was_NATPMP(collection)) return true; #endif -#endif #ifdef SUPPORT_ICE - if (ICE_WasStun(netsrc)) + if (ICE_WasStun(collection)) return true; #endif @@ -7833,10 +7837,25 @@ void NET_Init (void) Cvar_Register(&net_hybriddualstack, "networking"); Cvar_Register(&net_fakeloss, "networking"); -#ifndef CLIENTONLY +#if defined(TCPCONNECT) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV)) +#ifdef HAVE_SERVER + Cvar_Register(&net_enable_qizmo, "networking"); + Cvar_Register(&net_enable_qtv, "networking"); +#endif +#if defined(HAVE_SSL) + Cvar_Register(&net_enable_tls, "networking"); +#endif + Cvar_Register(&net_enable_http, "networking"); + Cvar_Register(&net_enable_websockets, "networking"); + Cvar_Register(&net_enable_webrtcbroker, "networking"); +#endif + + + +#ifdef HAVE_SERVER Cmd_AddCommand("sv_addport", SVNET_AddPort_f); #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT Cvar_Register(&cl_delay_packets, "networking"); Cmd_AddCommand("cl_addport", NET_ClientPort_f); #endif @@ -7854,9 +7873,11 @@ void NET_Init (void) SSL_Init(); #endif +#if defined(HAVE_CLIENT)||defined(HAVE_SERVER) Net_Master_Init(); +#endif } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT void NET_CloseClient(void) { //called by disconnect console command FTENET_CloseCollection(cls.sockets); @@ -7881,7 +7902,7 @@ void NET_InitClient(qboolean loopbackonly) if (!cls.sockets) cls.sockets = FTENET_CreateCollection(false); -#ifndef CLIENTONLY +#ifdef HAVE_SERVER FTENET_AddToCollection(cls.sockets, "CLLoopback", "1", NA_LOOPBACK, NP_DGRAM); #endif if (loopbackonly) @@ -7909,7 +7930,7 @@ void NET_InitClient(qboolean loopbackonly) } #endif -#ifndef CLIENTONLY +#ifdef HAVE_SERVER #ifdef HAVE_IPV4 static void QDECL SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue) { @@ -8018,18 +8039,7 @@ void SVNET_RegisterCvars(void) // Cvar_Register (&sv_port_unix, "networking"); #endif - -#if defined(TCPCONNECT) && !defined(CLIENTONLY) - Cvar_Register (&net_enable_qizmo, "networking"); - Cvar_Register (&net_enable_qtv, "networking"); -#if defined(HAVE_SSL) - Cvar_Register (&net_enable_tls, "networking"); -#endif - Cvar_Register (&net_enable_http, "networking"); - Cvar_Register (&net_enable_websockets, "networking"); - Cvar_Register (&net_enable_webrtcbroker, "networking"); -#endif -#if defined(HAVE_DTLS) && !defined(CLIENTONLY) +#if defined(HAVE_DTLS) && defined(HAVE_SERVER) Cvar_Register (&net_enable_dtls, "networking"); #endif } @@ -8052,7 +8062,7 @@ void NET_InitServer(void) if (!svs.sockets) { svs.sockets = FTENET_CreateCollection(true); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM); #endif } @@ -8092,7 +8102,7 @@ void NET_InitServer(void) { NET_CloseServer(); -#ifndef SERVERONLY +#ifdef HAVE_CLIENT svs.sockets = FTENET_CreateCollection(true); FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM); #endif @@ -8113,10 +8123,10 @@ NET_Shutdown */ void NET_Shutdown (void) { -#ifndef CLIENTONLY +#ifdef HAVE_SERVER NET_CloseServer(); #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT FTENET_CloseCollection(cls.sockets); cls.sockets = NULL; #endif diff --git a/engine/common/netinc.h b/engine/common/netinc.h index ddbb6a498..d0f663670 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -365,7 +365,7 @@ typedef struct ftenet_connections_s } ftenet_connections_t; void ICE_Tick(void); -qboolean ICE_WasStun(netsrc_t netsrc); +qboolean ICE_WasStun(ftenet_connections_t *col); void QDECL ICE_AddLCandidateConn(ftenet_connections_t *col, netadr_t *addr, int type); void QDECL ICE_AddLCandidateInfo(struct icestate_s *con, netadr_t *adr, int adrno, int type); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 163512717..9d7b1d33a 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -1463,8 +1463,12 @@ static qintptr_t VARGS Plug_Net_SendTo(void *offset, quintptr_t mask, const qint struct sockaddr_qstorage sockaddr; if (handle == -1) { - NET_SendPacket(NS_CLIENT, srclen, src, address); +#ifdef HAVE_CLIENT + NET_SendPacket(cls.sockets, srclen, src, address); return srclen; +#else + return -2; +#endif } NetadrToSockadr(address, &sockaddr); diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index a418649f3..d4e5c9313 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1404,7 +1404,7 @@ cvar_t *PF_Cvar_FindOrGet(const char *var_name) var = Cvar_Get(var_name, def, 0, "Implicit QC variables"); if (var) - Con_Printf("^3Created QC Cvar %s\n", var_name); + Con_DPrintf("^3Created QC Cvar %s\n", var_name); else Con_Printf(CON_ERROR"Unable to create QC Cvar %s\n", var_name); } diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 954e9205f..1d3bc678f 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -4,6 +4,14 @@ //field info, netchan, and the WriteBits stuff (which should probably be moved to common.c with the others) //also contains vm filesystem +#if defined(HAVE_CLIENT) && defined(HAVE_SERVER) +#define NET_SendPacket(c,s,d,t) NET_SendPacket(((c)!=NS_CLIENT)?svs.sockets:cls.sockets,s,d,t) +#elif defined(HAVE_SERVER) +#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t) +#else +#define NET_SendPacket(c,s,d,t) NET_SendPacket(cls.sockets,s,d,t) +#endif + #define MAX_VM_FILES 8 typedef struct { diff --git a/engine/common/translate.c b/engine/common/translate.c index 4fad87fc6..9d596a768 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -8,26 +8,21 @@ //untranslate is lang->english for console commands. - +int com_language; char sys_language[64] = ""; static char langpath[MAX_OSPATH] = ""; struct language_s languages[MAX_LANGUAGES]; static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue) { -#ifndef CLIENTONLY - svs.language = TL_FindLanguage(var->string); -#endif -#ifndef SERVERONLY - cls.language = TL_FindLanguage(var->string); -#endif + com_language = TL_FindLanguage(var->string); } cvar_t language = CVARAFC("lang", sys_language, "prvm_language", CVAR_USERINFO, TL_LanguageChanged); void TranslateInit(void) { - Cvar_Register(&language, "International variables"); + Cvar_Register(&language, "Internationalisation"); } void TL_Shutdown(void) @@ -145,12 +140,7 @@ void TL_InitLanguages(const char *newlangpath) *lang = 0; //but we do support territories. -#ifndef CLIENTONLY - svs.language = TL_FindLanguage(sys_language); -#endif -#ifndef SERVERONLY - cls.language = TL_FindLanguage(sys_language); -#endif + com_language = TL_FindLanguage(sys_language); //make sure a fallback exists, but not as language 0 TL_FindLanguage(""); @@ -226,7 +216,7 @@ char *T_GetString(int num) return strings_table[num]; } -#ifndef SERVERONLY +#ifdef HAVE_CLIENT //for hexen2's objectives and stuff. static char *info_strings_list; static char **info_strings_table; diff --git a/engine/common/translate.h b/engine/common/translate.h index be32df93c..24080d824 100644 --- a/engine/common/translate.h +++ b/engine/common/translate.h @@ -14,6 +14,8 @@ struct language_s struct po_s *po; }; extern struct language_s languages[MAX_LANGUAGES]; +extern int com_language; +extern cvar_t language; #define langtext(t,l) PO_GetText(languages[l].po, t) int TL_FindLanguage(const char *lang); diff --git a/engine/common/world.h b/engine/common/world.h index 7ae9b73b8..92fe8da70 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -174,7 +174,8 @@ typedef struct wedict_s wedict_t; typedef struct { qboolean present; - vec3_t laggedpos; + vec3_t origin; + vec3_t angles; } laggedentinfo_t; #ifdef USERBE @@ -206,6 +207,7 @@ struct world_s qboolean (QDECL *Event_ContentsTransition) (struct world_s *w, wedict_t *ent, int oldwatertype, int newwatertype); model_t *(QDECL *Get_CModel)(struct world_s *w, int modelindex); void (QDECL *Get_FrameState)(struct world_s *w, wedict_t *s, framestate_t *fstate); + void (QDECL *Event_Backdate)(struct world_s *w, wedict_t *s, float timestamp); //called for MOVE_LAGGED+MOVE_HITMODEL traces unsigned int keydestmask; //menu:kdm_menu, csqc:kdm_game, server:0 unsigned int max_edicts; //limiting factor... 1024 fields*4*MAX_EDICTS == a heck of a lot. @@ -241,7 +243,8 @@ struct world_s qbyte *lastcheckpvs; // for monster ai /*antilag*/ - float lagentsfrac; + float lagentsfrac; + float lagentstime; laggedentinfo_t *lagents; unsigned int maxlagents; diff --git a/engine/common/zone.c b/engine/common/zone.c index a4d779efc..f4f2ed272 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -641,14 +641,16 @@ CACHE MEMORY void Cache_Flush(void) { //this generically named function is hyjacked to flush models and sounds, as well as ragdolls etc +#ifdef HAVE_CLIENT + S_Purge(false); +#endif +#if defined(HAVE_CLIENT) || defined(HAVE_SERVER) #ifdef RAGDOLL rag_flushdolls(true); -#endif -#ifndef SERVERONLY - S_Purge(false); #endif Mod_Purge(MP_FLUSH); -#ifndef SERVERONLY +#endif +#ifdef HAVE_CLIENT Image_Purge(); #endif } diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index d6f4c4d0c..592994a9d 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -3450,13 +3450,11 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu case SP_M_MODEL: qglUniformMatrix4fvARB(ph, 1, false, shaderstate.modelmatrix); break; - case SP_M_ENTBONES: - { - if (sh_config.maxver>=120) - qglUniformMatrix3x4fv(ph, shaderstate.sourcevbo->numbones, false, shaderstate.sourcevbo->bones); - else - qglUniform4fvARB(ph, shaderstate.sourcevbo->numbones*3, shaderstate.sourcevbo->bones); - } + case SP_M_ENTBONES_PACKED: + qglUniform4fvARB(ph, shaderstate.sourcevbo->numbones*3, shaderstate.sourcevbo->bones); + break; + case SP_M_ENTBONES_MAT3X4: + qglUniformMatrix3x4fv(ph, shaderstate.sourcevbo->numbones, false, shaderstate.sourcevbo->bones); break; case SP_M_INVVIEWPROJECTION: { @@ -4561,7 +4559,7 @@ static void DrawMeshes(void) #endif break; case BEM_DEPTHDARK: - if ((shaderstate.curshader->flags & SHADER_HASLIGHTMAP) && !TEXVALID(shaderstate.curtexnums->fullbright)) + if ((shaderstate.curshader->flags & (SHADER_HASLIGHTMAP|SHADER_NODLIGHT))==SHADER_HASLIGHTMAP && !TEXVALID(shaderstate.curtexnums->fullbright)) { if (gl_config.arb_shader_objects) { diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 9e4bdec10..16744088b 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -777,6 +777,7 @@ void Mod_Init (qboolean initial) Cvar_Register(&mod_loadentfiles, NULL); Cvar_Register(&mod_loadentfiles_dir, NULL); Cvar_Register(&temp_lit2support, NULL); + Cvar_Register (&r_meshpitch, "Gamecode"); Cmd_AddCommandD("sv_saveentfile", Mod_SaveEntFile_f, "Dumps a copy of the map's entities to disk, so that it can be edited and used as a replacement for slightly customised maps."); Cmd_AddCommandD("mod_showent", Mod_ShowEnt_f, "Allows you to quickly search through a map's entities."); Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index f73eb7a49..862a9c249 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1659,6 +1659,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip prog->preshade = Z_StrDup(prescript); prog->supportedpermutations = (~nopermutation) & (PERMUTATIONS-1); + prog->shaderver = ver; if (cvarcount) { @@ -1954,7 +1955,8 @@ struct shader_field_names_s shader_unif_names[] = {"m_modelview", SP_M_MODELVIEW},//the combined modelview matrix {"m_projection", SP_M_PROJECTION},//projection matrix /**/{"m_modelviewprojection", SP_M_MODELVIEWPROJECTION},//fancy mvp matrix. probably has degraded precision. - {"m_bones", SP_M_ENTBONES}, //bone matrix array. should normally be read via sys/skeletal.h + {"m_bones_packed", SP_M_ENTBONES_PACKED}, //bone matrix array. should normally be read via sys/skeletal.h + {"m_bones_mat3x4", SP_M_ENTBONES_MAT3X4}, //bone matrix array. should normally be read via sys/skeletal.h {"m_invviewprojection", SP_M_INVVIEWPROJECTION},//inverted vp matrix {"m_invmodelviewprojection",SP_M_INVMODELVIEWPROJECTION},//inverted mvp matrix. /**///m_modelinv @@ -4966,9 +4968,9 @@ done:; } } - pass = s->passes; - for (i = 0; i < s->numpasses; i++, pass++) + for (i = 0; i < s->numpasses; i += (pass->prog?pass->numMergedPasses:1)) { + pass = s->passes+i; if (!(pass->shaderbits & (SBITS_BLEND_BITS|SBITS_MASK_BITS))) { break; diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 352c84c3d..19d8e0732 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1133,6 +1133,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) gl_config.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture"); } gl_config.arb_shadow = GL_CheckExtension("GL_ARB_shadow"); + gl_config.arb_shadow |= gl_config.glversion >= 3.0; //seems about right, for both gles and desktop... //gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2. nvidia fucks up. depend on brute-force. :s if (GL_CheckExtension("GL_ARB_seamless_cube_map")) @@ -1325,13 +1326,7 @@ static const char *glsl_hdrs[] = "attribute vec4 v_colour4;" #endif "\n#endif\n" -#ifdef SHADOWDBG_COLOURNOTDEPTH - "#define sampler2DShadow sampler2D\n" -#else - "#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must - "#define sampler2DShadow sampler2D\n" - "#endif\n" -#endif + "#ifndef SPECEXP\n" "#define SPECEXP 1.0\n" "#endif\n" @@ -1420,9 +1415,9 @@ static const char *glsl_hdrs[] = "layout(std140) unform u_bones\n" "{\n" "#ifdef PACKEDBONES\n" - "vec4 m_bones[3*MAX_GPU_BONES];\n" + "vec4 m_bones_packed[3*MAX_GPU_BONES];\n" "#else\n" - "mat3x4 m_bones[MAX_GPU_BONES]\n" + "mat3x4 m_bones_mat3x4[MAX_GPU_BONES]\n" "#endif\n" "};\n" "#endif\n" @@ -1436,9 +1431,9 @@ static const char *glsl_hdrs[] = "#endif\n" "#ifdef SKELETAL\n" //skeletal permutation tends to require glsl 120 "#ifdef PACKEDBONES\n" - "uniform vec4 m_bones[3*MAX_GPU_BONES];\n" + "uniform vec4 m_bones_packed[3*MAX_GPU_BONES];\n" "#else\n" - "uniform mat3x4 m_bones[MAX_GPU_BONES];\n" + "uniform mat3x4 m_bones_mat3x4[MAX_GPU_BONES];\n" "#endif\n" "#endif\n" "uniform mat4 m_invviewprojection;" @@ -1497,9 +1492,9 @@ static const char *glsl_hdrs[] = "attribute vec4 v_bone;" "attribute vec4 v_weight;\n" "#ifdef PACKEDBONES\n" - "uniform vec4 m_bones[3*MAX_GPU_BONES];\n" + "uniform vec4 m_bones_packed[3*MAX_GPU_BONES];\n" "#else\n" - "uniform mat3x4 m_bones[MAX_GPU_BONES];\n" + "uniform mat3x4 m_bones_mat3x4[MAX_GPU_BONES];\n" "#endif\n" "#endif\n" @@ -1507,36 +1502,36 @@ static const char *glsl_hdrs[] = "vec4 skeletaltransform()" "{" "mat4 wmat;" - "wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" - "wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" - "wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" - "wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" - "wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" - "wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" - "wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" - "wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" - "wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" - "wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" - "wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" - "wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" + "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;" + "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;" + "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;" "wmat[3] = vec4(0.0,0.0,0.0,1.0);\n" "return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);" "}\n" "vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)" "{" "mat4 wmat;" - "wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" - "wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" - "wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" - "wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" - "wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" - "wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" - "wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" - "wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" - "wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" - "wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" - "wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" - "wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" + "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;" + "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;" + "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;" "wmat[3] = vec4(0.0,0.0,0.0,1.0);" "n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;" "t = (vec4(v_svector.xyz, 0.0) * wmat).xyz;" @@ -1546,18 +1541,18 @@ static const char *glsl_hdrs[] = "vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)" "{" "mat4 wmat;" - "wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" - "wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" - "wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" - "wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" - "wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" - "wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" - "wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" - "wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" - "wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" - "wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" - "wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" - "wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" + "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;" + "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;" + "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;" "wmat[3] = vec4(0.0,0.0,0.0,1.0);" "n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;" "t = (vec4(v_svector.xyz, 0.0) * wmat).xyz;" @@ -1568,18 +1563,18 @@ static const char *glsl_hdrs[] = "vec4 skeletaltransform_n(out vec3 n)" "{" "mat4 wmat;" - "wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" - "wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" - "wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" - "wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" - "wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" - "wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" - "wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" - "wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" - "wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" - "wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" - "wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" - "wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" + "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;" + "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;" + "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;" + "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;" + "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;" + "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;" "wmat[3] = vec4(0.0,0.0,0.0,1.0);" "n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;" "return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);" @@ -1588,19 +1583,19 @@ static const char *glsl_hdrs[] = "vec4 skeletaltransform()" "{" "mat3x4 wmat;" - "wmat = m_bones[int(v_bone.x)] * v_weight.x;" - "wmat += m_bones[int(v_bone.y)] * v_weight.y;" - "wmat += m_bones[int(v_bone.z)] * v_weight.z;" - "wmat += m_bones[int(v_bone.w)] * v_weight.w;" + "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;" + "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;" + "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;" + "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;" "return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);" "}\n" "vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)" "{" "mat3x4 wmat;" - "wmat = m_bones[int(v_bone.x)] * v_weight.x;" - "wmat += m_bones[int(v_bone.y)] * v_weight.y;" - "wmat += m_bones[int(v_bone.z)] * v_weight.z;" - "wmat += m_bones[int(v_bone.w)] * v_weight.w;" + "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;" + "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;" + "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;" + "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;" "n = vec4(v_normal.xyz, 0.0) * wmat;" "t = vec4(v_svector.xyz, 0.0) * wmat;" "b = vec4(v_tvector.xyz, 0.0) * wmat;" @@ -1609,10 +1604,10 @@ static const char *glsl_hdrs[] = "vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)" "{" "mat3x4 wmat;" - "wmat = m_bones[int(v_bone.x)] * v_weight.x;" - "wmat += m_bones[int(v_bone.y)] * v_weight.y;" - "wmat += m_bones[int(v_bone.z)] * v_weight.z;" - "wmat += m_bones[int(v_bone.w)] * v_weight.w;" + "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;" + "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;" + "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;" + "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;" "n = vec4(v_normal.xyz, 0.0) * wmat;" "t = vec4(v_svector.xyz, 0.0) * wmat;" "b = vec4(v_tvector.xyz, 0.0) * wmat;" @@ -1622,10 +1617,10 @@ static const char *glsl_hdrs[] = "vec4 skeletaltransform_n(out vec3 n)" "{" "mat3x4 wmat;" - "wmat = m_bones[int(v_bone.x)] * v_weight.x;" - "wmat += m_bones[int(v_bone.y)] * v_weight.y;" - "wmat += m_bones[int(v_bone.z)] * v_weight.z;" - "wmat += m_bones[int(v_bone.w)] * v_weight.w;" + "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;" + "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;" + "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;" + "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;" "n = vec4(v_normal.xyz, 0.0) * wmat;" "return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);" "}\n" @@ -1748,9 +1743,9 @@ static const char *glsl_hdrs[] = "vec2 tc = base;\n" "tc += OffsetVector;\n" "OffsetVector *= 0.333;\n" - "tc -= OffsetVector * texture2D(normtex, tc).w;\n" - "tc -= OffsetVector * texture2D(normtex, tc).w;\n" - "tc -= OffsetVector * texture2D(normtex, tc).w;\n" + "tc -= OffsetVector * texture2D(normtex, tc).a;\n" + "tc -= OffsetVector * texture2D(normtex, tc).a;\n" + "tc -= OffsetVector * texture2D(normtex, tc).a;\n" "return tc;\n" "#else\n" "return base;\n" @@ -2071,6 +2066,8 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int GLSlang_GenerateInternal(&glsl, *precompilerconstants++); GLSlang_GenerateInternal(&glsl, "#define ENGINE_"DISTRIBUTION"\n"); + if (ver < 120) + GLSlang_GenerateInternal(&glsl, "#define PACKEDBONES\n"); switch (shadertype) { @@ -2126,7 +2123,15 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int #if 1//def NOLEGACY const char *defaultsamplernames[] = { + #ifdef SHADOWDBG_COLOURNOTDEPTH + "#define sampler2DShadow sampler2D\n" + #else + "#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must + "#define sampler2DShadow sampler2D\n" + "#endif\n" + #endif "uniform sampler2DShadow s_shadowmap;\n", + "uniform samplerCube s_projectionmap;\n", "uniform sampler2D s_diffuse;\n", "uniform sampler2D s_normalmap;\n", @@ -2201,8 +2206,6 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int "#define varying out\n" ); } - else if (ver < 120) - GLSlang_GenerateInternal(&glsl, "#define PACKEDBONES\n"); if (gl_config_nofixedfunc) { @@ -2365,19 +2368,41 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL if (developer.ival>1) { //could use echo console-link I guess (with embedded line numbers). shaders can get quite big though. - unsigned int line; - char *eol, *start; + unsigned int rawline, line, filenum = 0; + char *eol, *start, *e; + const char *filename = name; qglGetShaderSource(shader, sizeof(str), NULL, str); Con_Printf("Shader \"%s\" source:\n", name); - for(start = str, line = 1; ;line++) + for(start = str, line = 1, rawline = 1; ;) { eol = strchr(start, '\n'); if (eol) *eol=0; - Con_Printf("%3u: %s\n", line, start); +// if (filename) +// Con_Printf("%s:%u:%u: %s\n", filename, line, rawline, start); +// else + Con_Printf("%u:%u:%u: %s\n", filenum, line, rawline, start); + if (!strncmp(start, "#line ", 6)) + { + line = strtoul(start+6, &e, 0); + while(*e == ' ') + e++; + if (*e) + { + filenum = strtoul(e, &e, 0); + while(*e == ' ') + e++; + filename = NULL; + if (e[0]=='/'&&e[1]=='/') + filename = e+2; + } + } + else + line++; if (!eol) break; start = eol+1; + rawline++; } } } @@ -2589,11 +2614,7 @@ qboolean GLSlang_CreateProgramPermu(program_t *prog, struct programpermu_s *perm if (gl_config.gles) ver = 100; else - { ver = 110; - if (sh_config.maxver>=120 && (permu->permutation & PERMUTATION_SKELETAL)) - ver = 120; - } } if ((permu->permutation & PERMUTATION_SKELETAL) && gl_config.maxattribs < 10) return false; //can happen in gles2 diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 41c589de0..1f6336d34 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -1327,10 +1327,344 @@ static void GLX_CloseLibrary(void) } */ +#if 0//def _DEBUG +//this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB. +//functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called. +//this list is just to make it easier to test+debug android gles2 stuff using windows. +static char *gles2funcs[] = +{ +#define f(n) #n, + f(glActiveTexture) + f(glAttachShader) + f(glBindAttribLocation) + f(glBindBuffer) + f(glBindFramebuffer) + f(glBindRenderbuffer) + f(glBindTexture) + f(glBlendColor) + f(glBlendEquation) + f(glBlendEquationSeparate) + f(glBlendFunc) + f(glBlendFuncSeparate) + f(glBufferData) + f(glBufferSubData) + f(glCheckFramebufferStatus) + f(glClear) + f(glClearColor) + f(glClearDepthf) + f(glClearStencil) + f(glColorMask) + f(glCompileShader) + f(glCompressedTexImage2D) + f(glCompressedTexSubImage2D) + f(glCopyTexImage2D) + f(glCopyTexSubImage2D) + f(glCreateProgram) + f(glCreateShader) + f(glCullFace) + f(glDeleteBuffers) + f(glDeleteFramebuffers) + f(glDeleteProgram) + f(glDeleteRenderbuffers) + f(glDeleteShader) + f(glDeleteTextures) + f(glDepthFunc) + f(glDepthMask) + f(glDepthRangef) + f(glDetachShader) + f(glDisable) + f(glDisableVertexAttribArray) + f(glDrawArrays) + f(glDrawElements) + f(glEnable) + f(glEnableVertexAttribArray) + f(glFinish) + f(glFlush) + f(glFramebufferRenderbuffer) + f(glFramebufferTexture2D) + f(glFrontFace) + f(glGenBuffers) + f(glGenerateMipmap) + f(glGenFramebuffers) + f(glGenRenderbuffers) + f(glGenTextures) + f(glGetActiveAttrib) + f(glGetActiveUniform) + f(glGetAttachedShaders) + f(glGetAttribLocation) + f(glGetBooleanv) + f(glGetBufferParameteriv) + f(glGetError) + f(glGetFloatv) + f(glGetFramebufferAttachmentParameteriv) + f(glGetIntegerv) + f(glGetProgramiv) + f(glGetProgramInfoLog) + f(glGetRenderbufferParameteriv) + f(glGetShaderiv) + f(glGetShaderInfoLog) + f(glGetShaderPrecisionFormat) + f(glGetShaderSource) + f(glGetString) + f(glGetTexParameterfv) + f(glGetTexParameteriv) + f(glGetUniformfv) + f(glGetUniformiv) + f(glGetUniformLocation) + f(glGetVertexAttribfv) + f(glGetVertexAttribiv) + f(glGetVertexAttribPointerv) + f(glHint) + f(glIsBuffer) + f(glIsEnabled) + f(glIsFramebuffer) + f(glIsProgram) + f(glIsRenderbuffer) + f(glIsShader) + f(glIsTexture) + f(glLineWidth) + f(glLinkProgram) + f(glPixelStorei) + f(glPolygonOffset) + f(glReadPixels) + f(glReleaseShaderCompiler) + f(glRenderbufferStorage) + f(glSampleCoverage) + f(glScissor) + f(glShaderBinary) + f(glShaderSource) + f(glStencilFunc) + f(glStencilFuncSeparate) + f(glStencilMask) + f(glStencilMaskSeparate) + f(glStencilOp) + f(glStencilOpSeparate) + f(glTexImage2D) + f(glTexParameterf) + f(glTexParameterfv) + f(glTexParameteri) + f(glTexParameteriv) + f(glTexSubImage2D) + f(glUniform1f) + f(glUniform1fv) + f(glUniform1i) + f(glUniform1iv) + f(glUniform2f) + f(glUniform2fv) + f(glUniform2i) + f(glUniform2iv) + f(glUniform3f) + f(glUniform3fv) + f(glUniform3i) + f(glUniform3iv) + f(glUniform4f) + f(glUniform4fv) + f(glUniform4i) + f(glUniform4iv) + f(glUniformMatrix2fv) + f(glUniformMatrix3fv) + f(glUniformMatrix4fv) + f(glUseProgram) + f(glValidateProgram) + f(glVertexAttrib1f) + f(glVertexAttrib1fv) + f(glVertexAttrib2f) + f(glVertexAttrib2fv) + f(glVertexAttrib3f) + f(glVertexAttrib3fv) + f(glVertexAttrib4f) + f(glVertexAttrib4fv) + f(glVertexAttribPointer) + f(glViewport) + f(wglCreateContextAttribsARB) + NULL +}; + +//this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB. +//functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called. +//this list is just to make it easier to test+debug android gles2 stuff using windows. +static char *gles1funcs[] = +{ +#define f(n) #n, + + /* Available only in Common profile */ + f(glAlphaFunc) + f(glClearColor) + f(glClearDepthf) + f(glClipPlanef) + f(glColor4f) + f(glDepthRangef) + f(glFogf) + f(glFogfv) + f(glFrustumf) + f(glGetClipPlanef) + f(glGetFloatv) + f(glGetLightfv) + f(glGetMaterialfv) + f(glGetTexEnvfv) + f(glGetTexParameterfv) + f(glLightModelf) + f(glLightModelfv) + f(glLightf) + f(glLightfv) + f(glLineWidth) + f(glLoadMatrixf) + f(glMaterialf) + f(glMaterialfv) + f(glMultMatrixf) + f(glMultiTexCoord4f) + f(glNormal3f) + f(glOrthof) + f(glPointParameterf) + f(glPointParameterfv) + f(glPointSize) + f(glPolygonOffset) + f(glRotatef) + f(glScalef) + f(glTexEnvf) + f(glTexEnvfv) + f(glTexParameterf) + f(glTexParameterfv) + f(glTranslatef) + + /* Available in both Common and Common-Lite profiles */ + f(glActiveTexture) + f(glAlphaFuncx) + f(glBindBuffer) + f(glBindTexture) + f(glBlendFunc) + f(glBufferData) + f(glBufferSubData) + f(glClear) + f(glClearColorx) + f(glClearDepthx) + f(glClearStencil) + f(glClientActiveTexture) + f(glClipPlanex) + f(glColor4ub) + f(glColor4x) + f(glColorMask) + f(glColorPointer) + f(glCompressedTexImage2D) + f(glCompressedTexSubImage2D) + f(glCopyTexImage2D) + f(glCopyTexSubImage2D) + f(glCullFace) + f(glDeleteBuffers) + f(glDeleteTextures) + f(glDepthFunc) + f(glDepthMask) + f(glDepthRangex) + f(glDisable) + f(glDisableClientState) + f(glDrawArrays) + f(glDrawElements) + f(glEnable) + f(glEnableClientState) + f(glFinish) + f(glFlush) + f(glFogx) + f(glFogxv) + f(glFrontFace) + f(glFrustumx) + f(glGetBooleanv) + f(glGetBufferParameteriv) + f(glGetClipPlanex) + f(glGenBuffers) + f(glGenTextures) + f(glGetError) + f(glGetFixedv) + f(glGetIntegerv) + f(glGetLightxv) + f(glGetMaterialxv) + f(glGetPointerv) + f(glGetString) + f(glGetTexEnviv) + f(glGetTexEnvxv) + f(glGetTexParameteriv) + f(glGetTexParameterxv) + f(glHint) + f(glIsBuffer) + f(glIsEnabled) + f(glIsTexture) + f(glLightModelx) + f(glLightModelxv) + f(glLightx) + f(glLightxv) + f(glLineWidthx) + f(glLoadIdentity) + f(glLoadMatrixx) + f(glLogicOp) + f(glMaterialx) + f(glMaterialxv) + f(glMatrixMode) + f(glMultMatrixx) + f(glMultiTexCoord4x) + f(glNormal3x) + f(glNormalPointer) + f(glOrthox) + f(glPixelStorei) + f(glPointParameterx) + f(glPointParameterxv) + f(glPointSizex) + f(glPolygonOffsetx) + f(glPopMatrix) + f(glPushMatrix) + f(glReadPixels) + f(glRotatex) + f(glSampleCoverage) + f(glSampleCoveragex) + f(glScalex) + f(glScissor) + f(glShadeModel) + f(glStencilFunc) + f(glStencilMask) + f(glStencilOp) + f(glTexCoordPointer) + f(glTexEnvi) + f(glTexEnvx) + f(glTexEnviv) + f(glTexEnvxv) + f(glTexImage2D) + f(glTexParameteri) + f(glTexParameterx) + f(glTexParameteriv) + f(glTexParameterxv) + f(glTexSubImage2D) + f(glTranslatex) + f(glVertexPointer) + f(glViewport) + + /*required to switch stuff around*/ + f(wglCreateContextAttribsARB) + f(glXGetProcAddress) + f(glXQueryExtensionsString) + f(glXChooseFBConfig) + f(glXGetFBConfigAttrib) + f(glXGetVisualFromFBConfig) + f(glXCreateContextAttribsARB) + NULL +}; +#endif + static void *GLX_GetSymbol(char *name) { void *symb; +#if 0//def _DEBUG + if (1) + { + int i; + for (i = 0; gles1funcs[i]; i++) + { + if (!strcmp(name, gles1funcs[i])) + break; + } + if (!gles1funcs[i]) + return NULL; //not in the list + } +#endif + if (glx.GetProcAddress) symb = glx.GetProcAddress(name); else diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 80ecee957..db84ddcb1 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -437,7 +437,8 @@ typedef struct { SP_W_FOG, SP_W_USER, //user-specified blob of data. - SP_M_ENTBONES, + SP_M_ENTBONES_PACKED, + SP_M_ENTBONES_MAT3X4, SP_M_VIEW, SP_M_MODEL, SP_M_MODELVIEW, diff --git a/engine/partcfgs/generatebuiltin.c b/engine/partcfgs/generatebuiltin.c index 9c2d81311..7e8e2536d 100644 --- a/engine/partcfgs/generatebuiltin.c +++ b/engine/partcfgs/generatebuiltin.c @@ -1,5 +1,6 @@ //simple tool to read the particle configs and generate a header file for inclusion in the engine. #include +#include #include struct @@ -30,7 +31,7 @@ int main(void) if (!c || !h) { printf("unable to open a file\n"); - return; + return EXIT_FAILURE; } fprintf(h, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n"); @@ -46,7 +47,7 @@ int main(void) if (!s) { printf("unable to open %s\n", effects[i].filename); - return; + return EXIT_FAILURE; } *strchr(effects[i].filename, '.') = 0; @@ -114,4 +115,6 @@ int main(void) fclose(h); fclose(c); + + return EXIT_SUCCESS; } diff --git a/engine/partcfgs/high.cfg b/engine/partcfgs/high.cfg index c83516a55..b1f8ec7d4 100644 --- a/engine/partcfgs/high.cfg +++ b/engine/partcfgs/high.cfg @@ -412,6 +412,7 @@ r_part te_teleport surfaceparm nodlight glslprogram { + !!samps screen=0 varying vec2 tcoord; varying vec4 scoord; varying float alph; @@ -439,7 +440,7 @@ r_part te_teleport // f = 1.0 - tcoord*tcoord; if (f < 0.0) discard; f *= alph; - gl_FragColor = texture2D(s_t0, nst - tcoord*f); + gl_FragColor = texture2D(s_screen, nst - tcoord*f); } #endif } diff --git a/engine/qclib/hash.c b/engine/qclib/hash.c index 6923a21d6..b8f8870a5 100644 --- a/engine/qclib/hash.c +++ b/engine/qclib/hash.c @@ -348,6 +348,21 @@ void Hash_RemoveBucket(hashtable_t *table, const char *name, bucket_t *data) return; } +void Hash_RemoveDataKey(hashtable_t *table, unsigned int key, void *data) +{ + unsigned int bucknum = key%table->numbuckets; + bucket_t **link, *buck; + + for (link = &table->bucket[bucknum]; *link; link = &(*link)->next) + { + buck = *link; + if (buck->data == data && buck->key.value == key) + { + *link = buck->next; + return; + } + } +} void Hash_RemoveKey(hashtable_t *table, unsigned int key) { unsigned int bucknum = key%table->numbuckets; diff --git a/engine/qclib/hash.h b/engine/qclib/hash.h index 874d6e9bd..2e82a24c4 100644 --- a/engine/qclib/hash.h +++ b/engine/qclib/hash.h @@ -39,6 +39,7 @@ void Hash_RemoveData(hashtable_t *table, const char *name, void *data); void Hash_RemoveDataInsensitive(hashtable_t *table, const char *name, void *data); void Hash_RemoveBucket(hashtable_t *table, const char *name, bucket_t *data); void Hash_RemoveKey(hashtable_t *table, unsigned int key); +void Hash_RemoveDataKey(hashtable_t *table, unsigned int key, void *data); void *Hash_AddKey(hashtable_t *table, unsigned int key, void *data, bucket_t *buck); #endif diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index e8046c73b..f45811881 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10116,7 +10116,7 @@ static void QCBUILTIN PF_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s char *send = Z_Malloc(4+strlen(contents)); send[0] = send[1] = send[2] = send[3] = 0xff; memcpy(send+4, contents, strlen(contents)); - G_FLOAT(OFS_RETURN) = NET_SendPacket(NS_SERVER, 4+strlen(contents), send, &to); + G_FLOAT(OFS_RETURN) = NET_SendPacket(svs.sockets, 4+strlen(contents), send, &to); Z_Free(send); } } diff --git a/engine/server/server.h b/engine/server/server.h index e559f2ed9..497e56449 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -334,7 +334,7 @@ typedef struct // received from client // reply - double senttime; //time we sent this frame to the client, for ping calcs + double senttime; //time we sent this frame to the client, for ping calcs (realtime) int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale float ping_time; //how long it took for the client to ack it, may be negative float move_msecs; // @@ -365,8 +365,9 @@ typedef struct float pmwaterjumptime; usercmd_t cmd; //these are old positions of players, to give more accurate victim positions - vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag - qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present + laggedentinfo_t laggedplayer[MAX_CLIENTS]; + unsigned int numlaggedplayers; + float laggedtime; //sv.time of when this frame was sent } client_frame_t; #ifdef Q2SERVER @@ -524,6 +525,7 @@ typedef struct client_s laggedentinfo_t laggedents[MAX_CLIENTS]; unsigned int laggedents_count; float laggedents_frac; + float laggedents_time; // spawn parms are carried from level to level float spawn_parms[NUM_SPAWN_PARMS]; @@ -939,7 +941,6 @@ typedef struct struct netprim_s netprim; - int language; //the server operators language laggedpacket_t *free_lagged_packet; packet_entities_t entstatebuffer; /*just a temp buffer*/ @@ -1325,6 +1326,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client); //sv_master.c void SVM_Think(int port); +vfsfile_t *SVM_GenerateIndex(const char *fname); // @@ -1333,6 +1335,9 @@ void SVM_Think(int port); typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped. void SV_BeginRedirect (redirect_t rd, int lang); void SV_EndRedirect (void); +extern char sv_redirected_buf[8000]; +extern redirect_t sv_redirected; +extern int sv_redirectedlang; qboolean PR_GameCodePacket(char *s); diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index f4e7f5335..6084600f7 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -63,7 +63,7 @@ crosses a waterline. ============================================================================= */ -int needcleanup; +static int needcleanup; //int fatbytes; @@ -106,9 +106,9 @@ void SV_ExpandNackFrames(client_t *client, int require) // because there can be a lot of nails, there is a special // network protocol for them #define MAX_NAILS 32 -edict_t *nails[MAX_NAILS]; -int numnails; -int nailcount = 0; +static edict_t *nails[MAX_NAILS]; +static int numnails; +static int nailcount = 0; extern int sv_nailmodel, sv_supernailmodel, sv_playermodel; #ifdef SERVER_DEMO_PLAYBACK @@ -1564,6 +1564,7 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb frame->numresend = outno; frame->sequence = sequence; + frame->laggedtime = sv.time; for (i = 0; i < to->num_entities; i++) { n = &to->entities[i]; @@ -1582,9 +1583,10 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb age = sv.time - sv.world.physicstime; age = bound(0, age, 0.1); - VectorMA(n->origin, (sv.time - cl->localtime)/8.0, n->u.q1.velocity, frame->playerpositions[j]); + VectorMA(n->origin, (sv.time - cl->localtime)/8.0, n->u.q1.velocity, frame->laggedplayer[j].origin); + VectorCopy(n->angles, frame->laggedplayer[j].angles); //FIXME: add framestate_t info. - frame->playerpresent[j] = true; + frame->laggedplayer[j].present = true; } return overflow; @@ -2762,13 +2764,14 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t * clst.lastcmd = NULL; clst.velocity = NULL; clst.localtime = sv.time; - VectorCopy(clst.origin, frame->playerpositions[j]); + VectorCopy(clst.origin, frame->laggedplayer[j].origin); } else { - VectorMA(clst.origin, (sv.time - clst.localtime), clst.velocity, frame->playerpositions[j]); + VectorMA(clst.origin, (sv.time - clst.localtime), clst.velocity, frame->laggedplayer[j].origin); } - frame->playerpresent[j] = true; + VectorCopy(clst.angles, frame->laggedplayer[j].angles); + frame->laggedplayer[j].present = true; SV_WritePlayerToClient(msg, &clst); } @@ -2983,7 +2986,7 @@ typedef struct gibfilter_s { int minframe; int maxframe; } gibfilter_t; -gibfilter_t *gibfilter; +static gibfilter_t *gibfilter; void SV_GibFilterPurge(void) { gibfilter_t *gf; @@ -3881,9 +3884,7 @@ svc_playerinfo messages */ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs) { -#ifdef NQPROT - int e; -#endif + int i; packet_entities_t *pack; edict_t *clent; client_frame_t *frame; @@ -3893,7 +3894,8 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore // this is the frame we are creating frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK]; - memset(frame->playerpresent, 0, sizeof(frame->playerpresent)); + for (i = 0; i < sv.allocated_client_slots; i++) + frame->laggedplayer[i].present = 0; // find the client's PVS if (ignorepvs) @@ -3977,6 +3979,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore SVDP_EmitEntitiesUpdate(client, frame, pack, msg); else { + int e; for (e = 0; e < pack->num_entities; e++) { if (pack->entities[e].number > sv.allocated_client_slots) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 2363db6f5..7fb45dd75 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define INVIS_CHAR2 (char)138 #define INVIS_CHAR3 (char)160 -#ifdef SERVERONLY +#ifndef HAVE_CLIENT double host_frametime; double realtime; // without any filtering or bounding qboolean host_initialized; // true if into command execution (compatability) @@ -35,13 +35,6 @@ quakeparms_t host_parms; int host_hunklevel; #endif -// callbacks -void SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue); -void SV_Tcpport6_Callback(struct cvar_s *var, char *oldvalue); -void SV_Port_Callback(struct cvar_s *var, char *oldvalue); -void SV_PortIPv6_Callback(struct cvar_s *var, char *oldvalue); -void SV_PortIPX_Callback(struct cvar_s *var, char *oldvalue); - client_t *host_client; // current client // bound the size of the physics time tic @@ -63,12 +56,9 @@ cvar_t zombietime = CVARD("zombietime", "2", "Client slots will not be reuse cvar_t sv_crypt_rcon = CVARFD("sv_crypt_rcon", "", CVAR_ARCHIVE, "Controls whether the rcon password must be hashed or not. Hashed passwords also partially prevent replay attacks, but does NOT prevent malicious actors from reading the commands/results.\n0: completely insecure. ONLY allows plain-text passwords. Do not use.\n1: Mandatory hashing (recommended).\nEmpty: Allow either, whether the password is secure or not is purely the client's responsibility/fault. Only use this for comptibility with old clients."); cvar_t sv_crypt_rcon_clockskew = CVARFD("sv_timestamplen", "60", CVAR_ARCHIVE, "Limits clock skew to reduce (delayed) replay attacks"); #ifdef SERVERONLY -cvar_t developer = CVAR("developer","0"); // show extra messages - cvar_t rcon_password = CVARF("rcon_password", "", CVAR_NOUNSAFEEXPAND); // password for remote server commands cvar_t password = CVARF("password", "", CVAR_NOUNSAFEEXPAND); // password for entering the game #else -extern cvar_t developer; extern cvar_t rcon_password; extern cvar_t password; #endif @@ -108,6 +98,7 @@ cvar_t sv_listen_q3 = CVAR("sv_listen_q3", "0"); cvar_t sv_reconnectlimit = CVARD("sv_reconnectlimit", "0", "Blocks dupe connection within the specified length of time ."); extern cvar_t net_enable_dtls; cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once."); +cvar_t sv_heartbeat_interval = CVARD("sv_heartbeat_interval", "110", "Interval between heartbeats. Low values are abusive, high values may cause NAT/ghost issues."); cvar_t sv_highchars = CVAR("sv_highchars", "1"); cvar_t sv_maxrate = CVARD("sv_maxrate", "50000", "This controls the maximum number of bytes any indivual player may receive (when not downloading). The individual user's rate will also be controlled by the user's rate cvar."); cvar_t sv_maxdrate = CVARAFD("sv_maxdrate", "500000", @@ -272,7 +263,9 @@ void SV_Shutdown (void) #endif Cvar_Shutdown(); Cmd_Shutdown(); +#ifdef PACKAGEMANAGER PM_Shutdown(); +#endif InfoBuf_Clear(&svs.info, true); @@ -1290,7 +1283,7 @@ static void SVC_GetInfo (char *challenge, int fullstatus) } } - NET_SendPacket (NS_SERVER, resp-response, response, &net_from); + NET_SendPacket (svs.sockets, resp-response, response, &net_from); } #endif @@ -1378,7 +1371,7 @@ static void SVC_Log (void) else if (seq == svs.logsequence) { //current log isn't available as its not complete yet. data[0] = A2A_NACK; - NET_SendPacket (NS_SERVER, 1, data, &net_from); + NET_SendPacket (svs.sockets, 1, data, &net_from); return; } else if (seq > svs.logsequence) //future logs are not valid either. reply with the last that was. this is for compat, just in case. @@ -1392,7 +1385,7 @@ static void SVC_Log (void) if (!fraglog_public.ival) { //frag logs are not public (for DoS protection perhaps?. data[0] = A2A_NACK; - NET_SendPacket (NS_SERVER, 1, data, &net_from); + NET_SendPacket (svs.sockets, 1, data, &net_from); return; } @@ -1404,7 +1397,7 @@ static void SVC_Log (void) Q_snprintfz(data, sizeof(data), "stdlog %i %s\n%s", seq, av, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]); else Q_snprintfz(data, sizeof(data), "stdlog %i\n%s", seq, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]); - NET_SendPacket (NS_SERVER, strlen(data)+1, data, &net_from); + NET_SendPacket (svs.sockets, strlen(data)+1, data, &net_from); } /* @@ -1420,7 +1413,7 @@ void SVC_Ping (void) data = A2A_ACK; - NET_SendPacket (NS_SERVER, 1, &data, &net_from); + NET_SendPacket (svs.sockets, 1, &data, &net_from); } //from net_from @@ -1777,7 +1770,7 @@ void VARGS SV_RejectMessage(int protocol, char *format, ...) vsnprintf (string+5,sizeof(string)-1-5, format,argptr); len = strlen(string+4)+1+4; *(int*)string = BigLong(NETFLAG_CTL|len); - NET_SendPacket(NS_SERVER, len, string, &net_from); + NET_SendPacket(svs.sockets, len, string, &net_from); return; case SCP_DARKPLACES6: case SCP_DARKPLACES7: @@ -1840,7 +1833,7 @@ void SV_AcceptMessage(client_t *newcl) MSG_WriteByte(&sb, 0/*flags*/); } *(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return; } case SCP_DARKPLACES6: @@ -3484,7 +3477,7 @@ void SVC_RemoteCommand (void) Con_TPrintf ("Bad rcon from %s:\t%s\n" , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); - SV_BeginRedirect (RD_PACKET, svs.language); + SV_BeginRedirect (RD_PACKET, com_language); Con_TPrintf ("Bad rcon_password. Passwords might be logged. Be careful.\n"); } @@ -3501,7 +3494,7 @@ void SVC_RemoteCommand (void) Con_TPrintf ("Rcon from %s:\t%s\n" , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); - SV_BeginRedirect (RD_PACKET_LOG, svs.language); + SV_BeginRedirect (RD_PACKET_LOG, com_language); remaining[0] = 0; @@ -3725,7 +3718,7 @@ qboolean SV_ConnectionlessPacket (void) if (secure.value) //FIXME: possible problem for nq clients when enabled { - Netchan_OutOfBandTPrintf (NS_SERVER, &net_from, svs.language, "%c\nThis server requires client validation.\nPlease use the "FULLENGINENAME" validation program\n", A2C_PRINT); + Netchan_OutOfBandTPrintf (NS_SERVER, &net_from, com_language, "%c\nThis server requires client validation.\nPlease use the "FULLENGINENAME" validation program\n", A2C_PRINT); } else { @@ -3891,7 +3884,7 @@ qboolean SVNQ_ConnectionlessPacket(void) SZ_Clear(&sb); MSG_WriteLong(&sb, BigLong(NETFLAG_ACK | 8)); MSG_WriteLong(&sb, sequence); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); } @@ -3907,7 +3900,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteString(&sb, va("cmd challengeconnect %i %i\n", SV_NewChallenge(), MOD_PROQUAKE)); *(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return true; } @@ -3935,7 +3928,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteString(&sb, "Incorrect game\n"); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return false; //not our game. } if (MSG_ReadByte() != NQ_NETCHAN_VERSION) @@ -3945,7 +3938,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteString(&sb, "Incorrect version\n"); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return false; //not our version... } @@ -3957,7 +3950,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteString(&sb, *banreason?va("You are banned: %s\n", banreason):"You are banned\n"); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return false; //not our version... } @@ -3982,7 +3975,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteString(&sb, "NQ clients are not supported with hexen2 gamecode\n"); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return false; //not our version... } if (sv_listen_nq.ival == 2) @@ -3995,7 +3988,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteByte(&sb, MOD_PROQUAKE); MSG_WriteByte(&sb, MOD_PROQUAKE_VERSION); *(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); SZ_Clear(&sb); @@ -4006,7 +3999,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteString(&sb, va("cmd challengeconnect %i %i %i %i %i\n", SV_NewChallenge(), mod, modver, flags, passwd)); *(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); /*don't worry about repeating, the nop case above will recover it*/ } else @@ -4048,7 +4041,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteByte (&sb, maxclients.value); MSG_WriteByte (&sb, NQ_NETCHAN_VERSION); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return true; case CCREQ_PLAYER_INFO: if (sv_showconnectionlessmessages.ival) @@ -4082,7 +4075,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteString (&sb, SV_PlayerPublicAddress(cl)); /*player's address, leave blank, don't spam that info as it can result in personal attacks exploits*/ } *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return true; case CCREQ_RULE_INFO: if (sv_showconnectionlessmessages.ival) @@ -4132,7 +4125,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteString (&sb, rval); } *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); - NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); + NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); return true; } return false; @@ -4285,7 +4278,7 @@ qboolean SV_ReadPackets (float *delay) #ifdef SERVER_DEMO_PLAYBACK while (giveup-- > 0 && SV_GetPacket()>=0) #else - while (giveup-- > 0 && (cookie=NET_GetPacket (NS_SERVER, cookie)) >= 0) + while (giveup-- > 0 && (cookie=NET_GetPacket (svs.sockets, cookie)) >= 0) #endif { // check for connectionless packet (0xffffffff) first @@ -4299,9 +4292,9 @@ qboolean SV_ReadPackets (float *delay) if (ct - lt > 5*1000) { if (*banreason) - Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, svs.language, "You are banned: %s\n", banreason); + Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, com_language, "You are banned: %s\n", banreason); else - Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, svs.language, "You are banned\n"); + Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, com_language, "You are banned\n"); } continue; } @@ -4454,7 +4447,7 @@ dominping: if (SV_BannedReason (&net_from)) continue; - if (NET_WasSpecialPacket(NS_SERVER)) + if (NET_WasSpecialPacket(svs.sockets)) continue; // packet is not from a known client @@ -5125,8 +5118,6 @@ void SV_InitLocal (void) if (isDedicated) #endif { - Cvar_Register (&developer, cvargroup_servercontrol); - Cvar_Register (&password, cvargroup_servercontrol); Cvar_Register (&rcon_password, cvargroup_servercontrol); @@ -5563,7 +5554,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose) } val = InfoBuf_ValueForKey (&cl->userinfo, "lang"); - cl->language = *val?TL_FindLanguage(val):svs.language; + cl->language = *val?TL_FindLanguage(val):com_language; val = InfoBuf_ValueForKey (&cl->userinfo, "nogib"); cl->gibfilter = !!atoi(val); diff --git a/engine/server/sv_master.c b/engine/server/sv_master.c index ea569b5bf..549716143 100644 --- a/engine/server/sv_master.c +++ b/engine/server/sv_master.c @@ -11,213 +11,729 @@ #include "netinc.h" -//quake1 protocol -// -// +//quakeworld protocol +// heartbeat: "a" +// query: "c\n%i\n%i\n" +//queryresponse: "d\naaaappaaaapp" //quake2 protocol -//client sends "query\0" -//server sends "0xff0xff0xff0xffservers" follwed by lots of ips. +// heartbeat: "heartbeat\n%s\n%i %i \"%s\"\n" +// query: "query\0" +//queryresponse: "servers\naaaappaaaapp" -#define SVM_Q1HEARTBEATTIME 330 -#define SVM_Q2HEARTBEATTIME 330 +//quake3/dpmaster protocol +// heartbeat: "heartbeat DarkPlaces\n" +// query: "getservers[Ext] [%s] %u [empty] [full] [ipv6]" +//queryresponse: "getservers[Ext]Response\\aaaapp/aaaaaaaaaaaapp\\EOF" +enum gametypes_e +{ + GT_FFA=0, + GT_TOURNEY=1, + GT_TEAM=3, + GT_CTF=4, +}; typedef struct svm_server_s { netadr_t adr; - int clients; + int protover; + unsigned int clients; + unsigned int maxclients; + char hostname[48]; //just for our own listings. + char mapname[16]; //just for our own listings. + char gamedir[16]; //again... + unsigned short gametype; float expiretime; + + bucket_t bucket; + struct svm_game_s *game; struct svm_server_s *next; } svm_server_t; -typedef struct { - SOCKET socketudp; - float time; - int port; +typedef struct svm_game_s { + struct svm_game_s *next; svm_server_t *firstserver; - int numservers; + size_t numservers; + char name[1]; +} svm_game_t; + +typedef struct { + float time; + + svm_game_t *firstgame; + size_t numgames; + + hashtable_t serverhash; + size_t numservers; + + struct rates_s + { + double timestamp; + size_t heartbeats; + size_t queries; + size_t junk; + + size_t drops; + size_t adds; + } total, stamps[60]; + size_t stampring; + double nextstamp; } masterserver_t; -masterserver_t svm = {INVALID_SOCKET}; +static masterserver_t svm; +ftenet_connections_t *svm_sockets; -void SVM_RemoveOldServers(void) +static void QDECL SVM_Tcpport_Callback(struct cvar_s *var, char *oldvalue) { - svm_server_t *server, *next, *prev=NULL; - for (server = svm.firstserver; server; server = next) + FTENET_AddToCollection(svm_sockets, var->name, var->string, NA_IP, NP_STREAM); +} +static void QDECL SVM_Port_Callback(struct cvar_s *var, char *oldvalue) +{ + FTENET_AddToCollection(svm_sockets, var->name, var->string, NA_IP, NP_DGRAM); +} +static cvar_t sv_heartbeattimeout = CVARD("sv_heartbeattimeout", "600", "How many seconds a server should remain listed after its latest heartbeat. Larger values can avoid issues from packetloss, but can also make dos attacks easier."); +static cvar_t sv_masterport = CVARC("sv_masterport", "27000 28000", SVM_Port_Callback); +static cvar_t sv_masterport_tcp = CVARC("sv_masterport_tcp", "27000 28000", SVM_Tcpport_Callback); +static cvar_t sv_maxgames = CVARD("sv_maxgames", "100", "Limits the number of games that may be known. This is to reduce denial of service attacks."); +static cvar_t sv_maxservers = CVARD("sv_maxservers", "1000", "Limits the number of servers (total from all games) that may be known. This is to reduce denial of service attacks."); + +//returns a hash key for a server's address. +static unsigned int SVM_GenerateAddressKey(const netadr_t *adr) +{ + unsigned int key; + switch(adr->type) { - next = server->next; - if (server->expiretime < svm.time) + case NA_IP: + key = *(const unsigned int*)adr->address.ip; + key ^= 0xffff0000; //match ipv6's ipv4-mapped addresses. + key ^= adr->port; + break; + case NA_IPV6: + key = *(const unsigned int*)(adr->address.ip6+0); + key ^= *(const unsigned int*)(adr->address.ip6+4); + key ^= *(const unsigned int*)(adr->address.ip6+8); + key ^= *(const unsigned int*)(adr->address.ip6+12); + key ^= adr->port; + break; + default: + key = 0; + break; + } + return key; +} +static svm_server_t *SVM_GetServer(netadr_t *adr) +{ + svm_server_t *server; + unsigned int key = SVM_GenerateAddressKey(adr); + + server = Hash_GetKey(&svm.serverhash, key); + while (server && !NET_CompareAdr(&server->adr, adr)) + { + server = Hash_GetNextKey(&svm.serverhash, key, server); + } + return server; +} + +static svm_game_t *SVM_FindGame(const char *game, qboolean create) +{ + svm_game_t *g; + for (g = svm.firstgame; g; g = g->next) + { + if (!Q_strcasecmp(game, g->name)) + return g; + } + + if (create) + { + if (svm.numgames >= sv_maxgames.ival) { - BZ_Free(server); - if (prev) - prev->next = next; + Con_DPrintf("game limit exceeded\n"); + return NULL; + } + //block some chars that may cause issues/exploits. sorry. + if (strchr(game, '.') || strchr(game, '\"') || strchr(game, '/') || strchr(game, '?') || strchr(game, '&') || strchr(game, '+') || strchr(game, '\'') || strchr(game, '<') || strchr(game, '>')) + return NULL; + if (!*game || (*game >= '0' && *game <= '9')) + return NULL; //must not start with a number either. + g = ZF_Malloc(sizeof(*g) + strlen(game)); + if (g) + { + strcpy(g->name, game); + g->next = svm.firstgame; + svm.firstgame = g; + svm.numgames++; + Con_DPrintf("Creating game \"%s\"\n", g->name); + } + } + return g; +} + +static void SVM_RemoveOldServers(void) +{ + svm_game_t **gamelink, *g; + svm_server_t **serverlink, *s; + for (gamelink = &svm.firstgame; (g=*gamelink); ) + { + for (serverlink = &g->firstserver; (s=*serverlink); ) + { + if (s->expiretime < svm.time) + { + if (developer.ival) + { + char buf[256]; + Con_Printf("timeout: %s\n", NET_AdrToString(buf, sizeof(buf), &s->adr)); + } + + Hash_RemoveDataKey(&svm.serverhash, SVM_GenerateAddressKey(&s->adr), s); + + svm.total.drops++; + *serverlink = s->next; + BZ_Free(s); + g->numservers--; + svm.numservers--; + } else - svm.firstserver = next; + serverlink = &s->next; + } + + if (!g->firstserver) + { + Con_DPrintf("game \"%s\" has no active servers\n", g->name); + *gamelink = g->next; + Z_Free(g); + svm.numgames--; } else - prev = server; + gamelink = &g->next; } } -int SVM_AddIPAddresses(sizebuf_t *sb, int first) +int SVM_AddIPAddresses(sizebuf_t *sb, int first, const char *gamename, int v4, int v6, qboolean prefixes) { int number = 0; svm_server_t *server; - - for (server = svm.firstserver; server; server = server->next) + int prefix; + int len; + svm_game_t *game = SVM_FindGame(gamename, false); + if (game) { - if (number == first) - break; + for (server = game->firstserver; server; server = server->next) + { + if (number == first) + break; - first--; + first--; + } + + for (; server; server = server->next) + { + switch(server->adr.type) + { + case NA_IP: + if (!v4) + continue; + prefix = '\\'; + len = 4; + break; + case NA_IPV6: + if (!v6) + continue; + prefix = '/'; + len = 16; + break; + default: + continue; + } + + if (prefixes) + MSG_WriteByte(sb, prefixes); + + SZ_Write(sb, server->adr.address.ip, len); + MSG_WriteShort(sb, server->adr.port); + + number++; + } } - - for (; server; server = server->next) - { - if (sb->cursize + 6 >= sb->maxsize) - break; - - MSG_WriteByte(sb, server->adr.address.ip[0]); - MSG_WriteByte(sb, server->adr.address.ip[1]); - MSG_WriteByte(sb, server->adr.address.ip[2]); - MSG_WriteByte(sb, server->adr.address.ip[3]); - MSG_WriteShort(sb, server->adr.port); - - number++; - } - return number; } -void SVM_Heartbeat(netadr_t *adr, int numclients, float validuntil) +vfsfile_t *SVM_GenerateIndex(const char *fname) { + static const char *thecss = + ""; + char tmpbuf[256]; + svm_game_t *game; svm_server_t *server; - - for (server = svm.firstserver; server; server = server->next) + vfsfile_t *f = NULL; + unsigned clients = 0, maxclients=0; + if (!strcmp(fname, "index.html")) { - if (NET_CompareAdr(&server->adr, adr)) - break; + f = VFSPIPE_Open(1, false); + VFS_PRINTF(f, "%s", thecss); + VFS_PRINTF(f, "

FTE-Master

\n"); + VFS_PRINTF(f, "\n"); + for (game = svm.firstgame; game; game = game->next) + { + VFS_PRINTF(f, "\n", game->name, game->name, (unsigned)game->numservers); + clients += game->numservers; + } + VFS_PRINTF(f, "
%s
\n"); + VFS_PRINTF(f, "%u game(s), %u server(s)\n", (unsigned)svm.numgames, clients); } + else if (!strncmp(fname, "server/", 7)) + { + netadr_t adr[64]; + int count; + + f = VFSPIPE_Open(1, false); + VFS_PRINTF(f, "%s", thecss); + VFS_PRINTF(f, "

Single Server Info

\n", tmpbuf); + + VFS_PRINTF(f, "\n"); + VFS_PRINTF(f, "\n"); + count = NET_StringToAdr2(fname+7, 0, adr, countof(adr)); + while(count-->0) + { + server = SVM_GetServer(&adr[count]); + if (server) + VFS_PRINTF(f, "\n", server->game?server->game->name:"Unknown", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), server->hostname, server->gamedir, server->mapname, server->clients, server->maxclients); + else + VFS_PRINTF(f, "\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &adr[count])); + } + VFS_PRINTF(f, "
GameAddressHostnameMod dirMapnamePlayers
%s%s%s%s%s%u/%u
?%s????/?
\n"); + } + else if (!strncmp(fname, "game/", 5)) + { + COM_StripExtension(fname+5, tmpbuf, sizeof(tmpbuf)); + game = SVM_FindGame(tmpbuf, false); + + f = VFSPIPE_Open(1, false); + VFS_PRINTF(f, "%s", thecss); + VFS_PRINTF(f, "

Servers for %s

\n", tmpbuf); + + if(game) + { + VFS_PRINTF(f, "\n"); + VFS_PRINTF(f, "\n"); + for (server = game->firstserver; server; server = server->next) + { + VFS_PRINTF(f, "\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), server->hostname, server->gamedir, server->mapname, server->clients, server->maxclients); + clients += server->clients; + maxclients += server->maxclients; + } + VFS_PRINTF(f, "
AddressHostnameGamedirMapnamePlayers
%s%s%s%s%u/%u
\n"); + VFS_PRINTF(f, "%u server(s), %u/%u client(s)\n", (unsigned)game->numservers, clients, maxclients); + } + else + VFS_PRINTF(f, "No servers known for %s\n", tmpbuf); + } + else if (!strncmp(fname, "raw/", 4)) + { //just spews all + COM_StripExtension(fname+4, tmpbuf, sizeof(tmpbuf)); + game = SVM_FindGame(tmpbuf, false); + + f = VFSPIPE_Open(1, false); + for (server = (game?game->firstserver:NULL); server; server = server->next) + VFS_PRINTF(f, "%s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr)); + } + return f; +} + +static svm_server_t *SVM_Heartbeat(const char *gamename, netadr_t *adr, int numclients, float validuntil) +{ + svm_server_t *server = SVM_GetServer(adr); + svm_game_t *game = SVM_FindGame(gamename, true); + if (!game) + return NULL; + + if (server && server->game != game) + { + server->expiretime = realtime - 1; + server = NULL; + } + if (!server) //not found { + if (svm.numservers >= sv_maxservers.ival) + { + Con_DPrintf("server limit exceeded\n"); + return NULL; + } + if (developer.ival) + { + char buf[256]; + Con_Printf("heartbeat(new - %s): %s\n", game->name, NET_AdrToString(buf, sizeof(buf), adr)); + } + server = Z_Malloc(sizeof(svm_server_t)); - server->next = svm.firstserver; - svm.firstserver = server; + server->game = game; + server->next = game->firstserver; + game->firstserver = server; + game->numservers++; + svm.numservers++; server->adr = *adr; + + svm.total.adds++; + + Hash_AddKey(&svm.serverhash, SVM_GenerateAddressKey(adr), server, &server->bucket); + } + else + { + if (developer.ival) + { + char buf[256]; + Con_Printf("heartbeat(refresh): %s\n", NET_AdrToString(buf, sizeof(buf), &server->adr)); + } } server->clients = numclients; server->expiretime = validuntil; -} - - -void SVM_Init(int port) -{ - if (svm.socketudp == INVALID_SOCKET) - svm.socketudp = UDP_OpenSocket(port, false); -} - -void SVM_ShutDown (void) -{ - if (svm.socketudp != INVALID_SOCKET) - { - UDP_CloseSocket(svm.socketudp); - svm.socketudp = INVALID_SOCKET; - } + return server; } void SVM_Think(int port) { char *s; - struct sockaddr_qstorage addr; - int addrlen; - netadr_t netaddr; - if (!port) + int cookie = 0; + int giveup = 500; + + while (giveup-- > 0 && (cookie=NET_GetPacket (svm_sockets, cookie)) >= 0) { - SVM_ShutDown(); - return; + net_message.data[net_message.cursize] = '\0'; //null term all strings. + + svm.time = Sys_DoubleTime(); + + MSG_BeginReading(msg_nullnetprim); + if (MSG_ReadLong() != -1 || msg_badread) + { //go back to start... + MSG_BeginReading(msg_nullnetprim); + } + s = MSG_ReadStringLine(); + s = COM_Parse(s); + if (!strcmp(com_token, "getservers") || !strcmp(com_token, "getserversExt")) + { //q3 + sizebuf_t sb; + int ver; + char *eos; + char game[64]; + qboolean ext = !strcmp(com_token, "getserversExt"); + qboolean empty = false; + qboolean full = false; + qboolean ipv4 = !ext; + qboolean ipv6 = false; + int gametype = -1; + s = COM_ParseOut(s, game, sizeof(game)); + ver = strtol(game, &eos, 0); + if (*eos) + { + s = COM_Parse(s); + ver = strtol(com_token, NULL, 0); + } + else + Q_strncpyz(game, "Quake3", sizeof(game)); + for(;s&&*s;) + { + s = COM_Parse(s); + if (!strcmp(com_token, "empty")) + empty = true; + else if (!strcmp(com_token, "full")) + full = true; + + else if (!strcmp(com_token, "ipv4")) + ipv4 = true; + else if (!strcmp(com_token, "ipv6")) + ipv6 = true; + + else if (!strcmp(com_token, "ffa")) + gametype = GT_FFA; + else if (!strcmp(com_token, "tourney")) + gametype = GT_TOURNEY; + else if (!strcmp(com_token, "team")) + gametype = GT_TEAM; + else if (!strcmp(com_token, "ctf")) + gametype = GT_CTF; + else if (!strncmp(com_token, "gametype=", 9)) + gametype = atoi(com_token+9); + } + svm.total.queries++; + memset(&sb, 0, sizeof(sb)); + sb.maxsize = sizeof(net_message_buffer)-2; + sb.data = net_message_buffer; + MSG_WriteLong(&sb, -1); + + if (!ipv4 && !ipv6) + ipv4 = ipv6 = true; //neither specified? use both + if (ext) + { //ipv6 and ipv4 addresses + MSG_WriteString(&sb, "getserversExtResponse"); + SVM_AddIPAddresses(&sb, 0, game, ipv4, ipv6, true); + } + else + { //ipv4 only + MSG_WriteString(&sb, "getserversResponse"); + SVM_AddIPAddresses(&sb, 0, game, ipv4, ipv6, true); + } + sb.maxsize+=2; + MSG_WriteByte(&sb, '\\'); //otherwise the last may be considered invalid and ignored. +// MSG_WriteByte(&sb, 'E'); +// MSG_WriteByte(&sb, 'O'); +// MSG_WriteByte(&sb, 'T'); + NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from); + } + else if (!strcmp(com_token, "heartbeat")) + { //quake2 heartbeat. Serverinfo and players should follow. + if (*s == '\n' && s[1] == '\\') + { //there's some serverinfo there, must be q2... + svm.total.heartbeats++; + SVM_Heartbeat("Quake2", &net_from, 0, svm.time + sv_heartbeattimeout.ival); + } + else + { //dp/q3/etc are annoying, but we can query from an emphemerial socket to check NAT rules. + sizebuf_t sb; + svm.total.queries++; + memset(&sb, 0, sizeof(sb)); + sb.maxsize = sizeof(net_message_buffer); + sb.data = net_message_buffer; + MSG_WriteLong(&sb, -1); + MSG_WriteString(&sb, "getinfo CAKE\n"); + sb.cursize--; + NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from); + } + } + else if (!strcmp(com_token, "infoResponse")) + { + int clients; + const char *game, *chal; + svm_server_t *srv; + s = MSG_ReadStringLine(); + svm.total.heartbeats++; + chal = Info_ValueForKey(s, "challenge"); + if (!strcmp(chal, "CAKE")) + { + clients = atoi(Info_ValueForKey(s, "clients")); + game = Info_ValueForKey(s, "gamename"); + srv = SVM_Heartbeat(game, &net_from, clients, svm.time + sv_heartbeattimeout.ival); + if (srv) + { + if (developer.ival) + Info_Print(s, "\t"); + srv->protover = atoi(Info_ValueForKey(s, "protocol")); + srv->maxclients = atoi(Info_ValueForKey(s, "sv_maxclients")); + Q_strncpyz(srv->hostname, Info_ValueForKey(s, "hostname"), sizeof(srv->hostname)); + Q_strncpyz(srv->gamedir, Info_ValueForKey(s, "modname"), sizeof(srv->gamedir)); + Q_strncpyz(srv->mapname, Info_ValueForKey(s, "mapname"), sizeof(srv->mapname)); + } + } + } + else if (!strcmp(com_token, "query")) + { //quake2 server listing request + sizebuf_t sb; + svm.total.queries++; + memset(&sb, 0, sizeof(sb)); + sb.maxsize = sizeof(net_message_buffer); + sb.data = net_message_buffer; + MSG_WriteLong(&sb, -1); + MSG_WriteString(&sb, "servers\n"); + sb.cursize--; + SVM_AddIPAddresses(&sb, 0, "Quake2", true, false, false); + NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from); + } + else if (*com_token == S2M_HEARTBEAT) //sequence, players + { //quakeworld heartbeat + int players; + s = MSG_ReadStringLine(); + //sequence = atoi(s); + s = MSG_ReadStringLine(); + players = atoi(s); + svm.total.heartbeats++; + SVM_Heartbeat("QuakeWorld", &net_from, players, svm.time + sv_heartbeattimeout.ival); + } + else if (*com_token == C2M_MASTER_REQUEST) + { //quakeworld server listing request + sizebuf_t sb; + svm.total.queries++; + memset(&sb, 0, sizeof(sb)); + sb.maxsize = sizeof(net_message_buffer); + sb.data = net_message_buffer; + MSG_WriteLong(&sb, -1); + MSG_WriteByte(&sb, M2C_MASTER_REPLY); + MSG_WriteByte(&sb, '\n'); + SVM_AddIPAddresses(&sb, 0, "QuakeWorld", true, false, false); + NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from); + } + else if (*com_token == A2A_PING) + { //quakeworld server listing request + sizebuf_t sb; + svm.total.queries++; + memset(&sb, 0, sizeof(sb)); + sb.maxsize = sizeof(net_message_buffer); + sb.data = net_message_buffer; + MSG_WriteLong(&sb, -1); + MSG_WriteByte(&sb, A2A_ACK); + MSG_WriteByte(&sb, '\n'); + NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from); + } + else + svm.total.junk++; } - if (port != svm.port) - { - SVM_ShutDown(); //shut down (to cause a restart) - svm.port = port; - } - - SVM_Init(port); - - addrlen = sizeof(addr); - net_message.cursize = recvfrom(svm.socketudp, net_message_buffer, sizeof(net_message_buffer)-1, 0, (struct sockaddr *)&addr, &addrlen); - if (net_message.cursize <= 0) - { - addrlen = neterrno(); - - - return; - } - net_message.data[net_message.cursize] = '\0'; //null term all strings. - SockadrToNetadr(&addr, &netaddr); - svm.time = Sys_DoubleTime(); - SVM_RemoveOldServers(); - - MSG_BeginReading(msg_nullnetprim); - if (MSG_ReadLong() != -1 || msg_badread) - { //go back to start... - MSG_BeginReading(msg_nullnetprim); - } - s = MSG_ReadStringLine(); - s = COM_Parse(s); - if (!strcmp(com_token, "getservers")) - { - sizebuf_t sb; - memset(&sb, 0, sizeof(sb)); - sb.maxsize = sizeof(net_message_buffer)-2; - sb.data = net_message_buffer; - MSG_WriteLong(&sb, -1); - MSG_WriteString(&sb, "getserversResponse\\"); - sb.cursize--; - SVM_AddIPAddresses(&sb, 0); - sb.maxsize+=2; - MSG_WriteShort(&sb, 0); - sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr)); - } - else if (!strcmp(com_token, "heartbeat")) - { //quake2 heartbeat. Serverinfo and players follow. - SVM_Heartbeat(&netaddr, 0, svm.time + SVM_Q2HEARTBEATTIME); - } - else if (!strcmp(com_token, "query")) - { //quake2 server listing request - sizebuf_t sb; - memset(&sb, 0, sizeof(sb)); - sb.maxsize = sizeof(net_message_buffer); - sb.data = net_message_buffer; - MSG_WriteLong(&sb, -1); - MSG_WriteString(&sb, "servers\n"); - sb.cursize--; -// MSG_WriteLong(&sb, 0); -// MSG_WriteShort(&sb, 0); - SVM_AddIPAddresses(&sb, 0); - sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr)); - } - else if (*com_token == S2M_HEARTBEAT) //sequence, players - { //quakeworld heartbeat - SVM_Heartbeat(&netaddr, 0, svm.time + SVM_Q1HEARTBEATTIME); - } - else if (*com_token == S2C_CHALLENGE) - { //quakeworld server listing request - sizebuf_t sb; - memset(&sb, 0, sizeof(sb)); - sb.maxsize = sizeof(net_message_buffer); - sb.data = net_message_buffer; - MSG_WriteLong(&sb, -1); - MSG_WriteByte(&sb, M2C_MASTER_REPLY); - MSG_WriteByte(&sb, '\n'); - SVM_AddIPAddresses(&sb, 0); - sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr)); - } } #else void SVM_Think(int port){} #endif + + +#ifdef MASTERONLY +static void SV_Quit_f (void) +{ + Con_TPrintf ("Shutting down.\n"); + Sys_Quit (); +} +static void SVM_Status_f(void) +{ + svm_game_t *g; + svm_server_t *s; + unsigned clients; + struct rates_s *s1, *s2; + float period; + size_t r; + + NET_PrintAddresses(svm_sockets); + NET_PrintConnectionsStatus(svm_sockets); + Con_Printf("Game count: %u\n", (unsigned)svm.numgames); + for (g = svm.firstgame; g; g = g->next) + { + clients = 0; + for (s = g->firstserver; s; s = s->next) + clients += s->clients; + Con_Printf("Game %s: %u servers, %u clients\n", g->name, (unsigned)g->numservers, clients); + } + + s1 = &svm.total; + r = (svm.stampring >= countof(svm.stamps)-1)?svm.stampring-countof(svm.stamps)-1:0; + s2 = &svm.stamps[r%countof(svm.stamps)]; + + period = s1->timestamp-s2->timestamp; + period/=60; + if (!period) + period=1; + Con_Printf("Heartbeats/min: %f\n", (s1->heartbeats-s2->heartbeats)/period); + Con_Printf("Queries/min: %f\n", (s1->queries-s2->queries)/period); +} + +void SV_Init (struct quakeparms_s *parms) +{ + int manarg; + + COM_InitArgv (parms->argc, parms->argv); + + host_parms = *parms; + + Cvar_Init(); + + Memory_Init(); + + Sys_Init(); + + COM_ParsePlusSets(false); + + Cbuf_Init (); + Cmd_Init (); + + NET_Init (); + COM_Init (); + +#ifdef WEBSERVER + IWebInit(); +#endif + + Cmd_AddCommand ("quit", SV_Quit_f); + Cmd_AddCommand ("status", SVM_Status_f); + + svm_sockets = FTENET_CreateCollection(true); + Hash_InitTable(&svm.serverhash, 1024, Z_Malloc(Hash_BytesForBuckets(1024))); + + Cvar_Register(&sv_masterport, "server control variables"); + Cvar_Register(&sv_masterport_tcp, "server control variables"); + Cvar_Register(&sv_heartbeattimeout, "server control variables"); + Cvar_Register(&sv_maxgames, "server control variables"); + Cvar_Register(&sv_maxservers, "server control variables"); + + Cvar_ParseWatches(); + host_initialized = true; + + manarg = COM_CheckParm("-manifest"); + if (manarg && manarg < com_argc-1 && com_argv[manarg+1]) + { + char *man = FS_MallocFile(com_argv[manarg+1], FS_SYSTEM, NULL); + + FS_ChangeGame(FS_Manifest_Parse(NULL, man), true, true); + BZ_Free(man); + } + else + FS_ChangeGame(NULL, true, true); + + Cmd_StuffCmds(); + Cbuf_Execute (); + + Cvar_ForceCallback(&sv_masterport); + Cvar_ForceCallback(&sv_masterport_tcp); + + + Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__); + + Con_Printf ("%s\n", version_string()); + + Con_TPrintf ("======== %s Initialized ========\n", "FTEMaster"); +} +float SV_Frame (void) +{ + realtime = Sys_DoubleTime(); + while (1) + { + const char *cmd = Sys_ConsoleInput (); + if (!cmd) + break; + Log_String(LOG_CONSOLE, cmd); + Cbuf_AddText (cmd, RESTRICT_LOCAL); + Cbuf_AddText ("\n", RESTRICT_LOCAL); + } + Cbuf_Execute (); + + SVM_Think(sv_masterport.ival); + + //record lots of info over multiple frames, for smoother stats info. + svm.total.timestamp = realtime; + if (svm.nextstamp < realtime) + { + svm.stamps[svm.stampring%countof(svm.stamps)] = svm.total; + svm.stampring++; + svm.nextstamp = realtime+60; + } + + return 4; +} +#endif \ No newline at end of file diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index f2bb60767..25ceadf67 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -41,7 +41,7 @@ Con_Printf redirection ============================================================================= */ -char sv_redirected_buf[8000]; +char sv_redirected_buf[countof(sv_redirected_buf)]; redirect_t sv_redirected; int sv_redirectedlang; @@ -74,7 +74,7 @@ void SV_FlushRedirect (void) send[4] = A2C_PRINT; memcpy (send+5, sv_redirected_buf, strlen(sv_redirected_buf)+1); - NET_SendPacket (NS_SERVER, strlen(send)+1, send, &net_from); + NET_SendPacket (svs.sockets, strlen(send)+1, send, &net_from); } #ifdef SUBSERVERS else if (sv_redirected == RD_MASTER) @@ -145,208 +145,6 @@ void SV_EndRedirect (void) sv_redirected = RD_NONE; } - -/* -================ -Con_Printf - -Handles cursor positioning, line wrapping, etc -================ -*/ -#define MAXPRINTMSG 4096 -// FIXME: make a buffer size safe vsprintf? -#ifdef SERVERONLY -vfsfile_t *con_pipe; -vfsfile_t *Con_POpen(char *conname) -{ - if (!conname || !*conname) - { - if (con_pipe) - VFS_CLOSE(con_pipe); - con_pipe = VFSPIPE_Open(2, false); - return con_pipe; - } - return NULL; -} - -static void Con_PrintFromThread (void *ctx, void *data, size_t a, size_t b) -{ - Con_Printf("%s", (char*)data); - BZ_Free(data); -} -void VARGS Con_Printf (const char *fmt, ...) -{ - va_list argptr; - char msg[MAXPRINTMSG]; - - va_start (argptr,fmt); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - - if (!Sys_IsMainThread()) - { - COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0); - return; - } - - // add to redirected message - if (sv_redirected) - { - if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) - SV_FlushRedirect (); - strcat (sv_redirected_buf, msg); - if (sv_redirected != -1) - return; - } - - Sys_Printf ("%s", msg); // also echo to debugging console - Con_Log(msg); // log to console - - if (con_pipe) - VFS_PUTS(con_pipe, msg); -} -void Con_TPrintf (translation_t stringnum, ...) -{ - va_list argptr; - char msg[MAXPRINTMSG]; - const char *fmt; - - if (!Sys_IsMainThread()) - { //shouldn't be redirected anyway... - fmt = langtext(stringnum,svs.language); - va_start (argptr,stringnum); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0); - return; - } - - // add to redirected message - if (sv_redirected) - { - fmt = langtext(stringnum,sv_redirectedlang); - va_start (argptr,stringnum); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - - if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) - SV_FlushRedirect (); - strcat (sv_redirected_buf, msg); - return; - } - - fmt = langtext(stringnum,svs.language); - - va_start (argptr,stringnum); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - - Sys_Printf ("%s", msg); // also echo to debugging console - Con_Log(msg); // log to console - - if (con_pipe) - VFS_PUTS(con_pipe, msg); -} -/* -================ -Con_DPrintf - -A Con_Printf that only shows up if the "developer" cvar is set -================ -*/ -static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b) -{ - Con_DLPrintf(a, "%s", (char*)data); - BZ_Free(data); -} -void Con_DPrintf (const char *fmt, ...) -{ - va_list argptr; - char msg[MAXPRINTMSG]; - extern cvar_t log_developer; - - if (!developer.value && !log_developer.value) - return; - - va_start (argptr,fmt); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - - if (!Sys_IsMainThread()) - { - COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0); - return; - } - - // add to redirected message - if (sv_redirected) - { - if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) - SV_FlushRedirect (); - strcat (sv_redirected_buf, msg); - if (sv_redirected != -1) - return; - } - - if (developer.value) - Sys_Printf ("%s", msg); // also echo to debugging console - - if (log_developer.value) - Con_Log(msg); // log to console -} -void Con_DLPrintf (int level, const char *fmt, ...) -{ - va_list argptr; - char msg[MAXPRINTMSG]; - extern cvar_t log_developer; - - if (developer.ival < level && !log_developer.value) - return; - - va_start (argptr,fmt); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - - if (!Sys_IsMainThread()) - { - COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), level, 0); - return; - } - - // add to redirected message - if (sv_redirected) - { - if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1) - SV_FlushRedirect (); - strcat (sv_redirected_buf, msg); - if (sv_redirected != -1) - return; - } - - if (developer.ival >= level) - Sys_Printf ("%s", msg); // also echo to debugging console - - if (log_developer.value) - Con_Log(msg); // log to console -} - -//for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local. -void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...) -{ - va_list argptr; - char msg[MAXPRINTMSG]; - - va_start (argptr,fmt); - vsnprintf (msg,sizeof(msg)-1, fmt,argptr); - va_end (argptr); - - if (developerlevel) - Con_DLPrintf (developerlevel, "%s", msg); - else - Con_Printf("%s", msg); -} -#endif - /* ============================================================================= @@ -624,7 +422,7 @@ void VARGS SV_BroadcastTPrintf (int level, translation_t stringnum, ...) client_t *cl; int i; int oldlang=-1; - const char *fmt = langtext(stringnum, oldlang=svs.language); + const char *fmt = langtext(stringnum, oldlang=com_language); va_start (argptr,stringnum); vsnprintf (string,sizeof(string)-1, fmt,argptr); diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index da06d0812..e9e2871ec 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -765,7 +765,7 @@ static int Sys_CheckChRoot(void) freeaddrinfo(info); } -#ifdef SQL +#if defined(SQL) && defined(HAVE_SERVER) SQL_Available(); #endif #ifdef HAVE_GNUTLS diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 146544a00..a046a9cec 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -194,7 +194,7 @@ qboolean SV_CheckRealIP(client_t *client, qboolean force) if (client->realip_status == 1) { msg = va("\xff\xff\xff\xff%c %i", A2A_PING, client->realip_ping); - NET_SendPacket(NS_SERVER, strlen(msg), msg, &client->realip); + NET_SendPacket(svs.sockets, strlen(msg), msg, &client->realip); } else { @@ -2566,7 +2566,7 @@ void VARGS OutofBandPrintf(netadr_t *where, char *fmt, ...) vsnprintf (send+5, sizeof(send)-5, fmt, argptr); va_end (argptr); - NET_SendPacket (NS_SERVER, strlen(send)+1, send, where); + NET_SendPacket (svs.sockets, strlen(send)+1, send, where); } /* @@ -4980,9 +4980,9 @@ void Cmd_SetPos_f(void) if (!svprogfuncs) return; - if (Cmd_Argc() != 4) + if (Cmd_Argc() != 4 && Cmd_Argc() != 7) { - SV_ClientPrintf(host_client, PRINT_HIGH, "setpos %f %f %f\n", sv_player->v->origin[0], sv_player->v->origin[1], sv_player->v->origin[2]); + SV_ClientPrintf(host_client, PRINT_HIGH, "setpos %f %f %f %f %f %f\n", sv_player->v->origin[0], sv_player->v->origin[1], sv_player->v->origin[2], sv_player->v->v_angle[0], sv_player->v->v_angle[1], sv_player->v->v_angle[2]); return; } SV_LogPlayer(host_client, "setpos cheat"); @@ -4999,6 +4999,14 @@ void Cmd_SetPos_f(void) sv_player->v->origin[1] = atof(Cmd_Argv(2)); sv_player->v->origin[2] = atof(Cmd_Argv(3)); World_LinkEdict (&sv.world, (wedict_t*)sv_player, false); + + if (Cmd_Argc() > 4) + { + sv_player->v->angles[0] = atof(Cmd_Argv(4)); + sv_player->v->angles[1] = atof(Cmd_Argv(5)); + sv_player->v->angles[2] = atof(Cmd_Argv(6)); + sv_player->v->fixangle = true; + } } void SV_SetUpClientEdict (client_t *cl, edict_t *ent) @@ -7657,7 +7665,7 @@ void SV_ExecuteClientMessage (client_t *cl) vec3_t o; int checksumIndex; qbyte checksum, calculatedChecksum; - int seq_hash, i; + int seq_hash; // calc ping time if (cl->frameunion.frames) @@ -7694,14 +7702,9 @@ void SV_ExecuteClientMessage (client_t *cl) #ifdef warningmsg #pragma warningmsg("FIXME: make antilag optionally support non-player ents too") #endif - for (i = 0; i < sv.allocated_client_slots; i++) - { - cl->laggedents[i].present = frame->playerpresent[i]; - if (cl->laggedents[i].present) - VectorCopy(frame->playerpositions[i], cl->laggedents[i].laggedpos); - } cl->laggedents_count = sv.allocated_client_slots; - + memcpy(cl->laggedents, frame->laggedplayer, sizeof(*cl->laggedents)*cl->laggedents_count); + cl->laggedents_time = frame->laggedtime; cl->laggedents_frac = !*sv_antilag_frac.string?1:sv_antilag_frac.value; } else diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 27790d597..9be66bf77 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -649,12 +649,12 @@ static int SVQ3_PointContents(vec3_t pos, int entnum) mod = Q3G_GetCModel(es->s.modelindex); if (!mod) continue; - World_TransformedTrace(mod, 0, 0, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, es->r.currentAngles, 0xffffffff); + World_TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, es->r.currentAngles, 0xffffffff); } else { mod = CM_TempBoxModel(es->r.mins, es->r.maxs); - World_TransformedTrace(mod, 0, 0, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, vec3_origin, 0xffffffff); + World_TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, vec3_origin, 0xffffffff); } cont |= tr.contents; @@ -3405,7 +3405,7 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and { Con_Printf("%s\n", reason); reason = va("\377\377\377\377print\n%s", reason); - NET_SendPacket (NS_SERVER, strlen(reason), reason, &net_from); + NET_SendPacket (svs.sockets, strlen(reason), reason, &net_from); return; } @@ -3422,7 +3422,7 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and cl->gamestatesequence = -1; - NET_SendPacket (NS_SERVER, 19, "\377\377\377\377connectResponse", &net_from); + NET_SendPacket (svs.sockets, 19, "\377\377\377\377connectResponse", &net_from); cl->frameunion.q3frames = BZ_Malloc(Q3UPDATE_BACKUP*sizeof(*cl->frameunion.q3frames)); } diff --git a/engine/server/world.c b/engine/server/world.c index b524fe40d..dfd644886 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -1241,7 +1241,7 @@ Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points ================== */ -static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, qboolean capsule, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps +static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t eang, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, qboolean capsule, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps { trace_t trace; model_t *model; @@ -1285,16 +1285,16 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v if (ent->v->solid == SOLID_PORTAL) { //solid_portal cares only about origins and as such has no mins/max - World_TransformedTrace(model, 0, &framestate, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); + World_TransformedTrace(model, 0, &framestate, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, eang, hitcontentsmask); if (trace.startsolid) //portals should not block traces. this prevents infinite looping trace.startsolid = false; hitmodel = false; } else if (ent->v->solid != SOLID_BSP) { - ent->v->angles[0]*=r_meshpitch.value; //carmack made bsp models rotate wrongly. - World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); - ent->v->angles[0]*=r_meshpitch.value; + eang[0]*=r_meshpitch.value; //carmack made bsp models rotate wrongly. + World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, hitcontentsmask); + eang[0]*=r_meshpitch.value; } else { @@ -1315,7 +1315,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v } if (hitcontentsmask & forcedcontents) { - World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, ~0u); + World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, ~0u); if (trace.contents) trace.contents = forcedcontents; } @@ -1330,7 +1330,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v } } else - World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); + World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, hitcontentsmask); } // if using hitmodel, we know it hit the bounding box, so try a proper trace now. @@ -1342,7 +1342,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v if (model && model->funcs.NativeTrace && model->loadstate == MLS_LOADED) { //do the second trace, using the actual mesh. - World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); + World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, hitcontentsmask); } } @@ -1687,9 +1687,9 @@ void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip ) angles = vec3_origin; // boxes don't rotate if (touch->svflags & SVF_MONSTER) - World_TransformedTrace (model, 0, 0, clip->start, clip->end, clip->mins2, clip->maxs2, false, &trace, touch->s.origin, angles, clip->hitcontentsmask); + World_TransformedTrace (model, 0, NULL, clip->start, clip->end, clip->mins2, clip->maxs2, false, &trace, touch->s.origin, angles, clip->hitcontentsmask); else - World_TransformedTrace (model, 0, 0, clip->start, clip->end, clip->mins, clip->maxs, false, &trace, touch->s.origin, angles, clip->hitcontentsmask); + World_TransformedTrace (model, 0, NULL, clip->start, clip->end, clip->mins, clip->maxs, false, &trace, touch->s.origin, angles, clip->hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) @@ -1875,9 +1875,9 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip) } if ((int)touch->v->flags & FL_MONSTER) - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); else - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { @@ -2034,9 +2034,9 @@ static void World_ClipToLinks (world_t *w, areagridlink_t *node, moveclip_t *cli } if ((int)touch->v->flags & FL_MONSTER) - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); else - trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); + trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); if (trace.fraction < clip->trace.fraction) { @@ -2561,18 +2561,18 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e if (type & MOVE_OTHERONLY) { wedict_t *other = WEDICT_NUM_UB(w->progs, *w->g.other); - return World_ClipMoveToEntity (w, other, other->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); + return World_ClipMoveToEntity (w, other, other->v->origin, other->v->angles, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); } #ifndef NOLEGACY if ((type&MOVE_WORLDONLY) == MOVE_WORLDONLY) { //for compat with DP wedict_t *other = w->edicts; - return World_ClipMoveToEntity (w, other, other->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); + return World_ClipMoveToEntity (w, other, other->v->origin, other->v->angles, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); } #endif // clip to world - clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.capsule, clip.hitcontentsmask); + clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, w->edicts->v->angles, start, mins, maxs, end, hullnum, false, clip.capsule, clip.hitcontentsmask); clip.start = start; clip.end = end; @@ -2622,6 +2622,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e w->lagents = svs.clients[passedict->entnum-1].laggedents; w->maxlagents = svs.clients[passedict->entnum-1].laggedents_count; w->lagentsfrac = svs.clients[passedict->entnum-1].laggedents_frac; + w->lagentstime = svs.clients[passedict->entnum-1].laggedents_time; } else if (passedict->v->owner) { @@ -2631,6 +2632,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e w->lagents = svs.clients[passedict->v->owner-1].laggedents; w->maxlagents = svs.clients[passedict->v->owner-1].laggedents_count; w->lagentsfrac = svs.clients[passedict->v->owner-1].laggedents_frac; + w->lagentstime = svs.clients[passedict->entnum-1].laggedents_time; } } } @@ -2640,7 +2642,8 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e { trace_t trace; wedict_t *touch; - vec3_t lp; + vec3_t lp, la; + int j; #ifdef USEAREAGRID World_ClipToAllLinks (w, &clip); @@ -2686,7 +2689,18 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e continue; } - VectorInterpolate(touch->v->origin, w->lagentsfrac, w->lagents[i].laggedpos, lp); + VectorInterpolate(touch->v->origin, w->lagentsfrac, w->lagents[i].origin, lp); + //I hate working with angles + VectorSubtract(w->lagents[i].angles, touch->v->angles, la); + for (j = 0; j < 3; j++) + { + la[j] = (360.0/65536) * ((int)(la[j]*(65536/360.0)) & 65535); + if (la[j]<-180) + la[j] += 360; + if (la[j]>180) + la[j] -= 360; + } + VectorMA(touch->v->angles, 1, la, la); if (clip.boxmins[0] > lp[0]+touch->v->maxs[0] || clip.boxmins[1] > lp[1]+touch->v->maxs[1] @@ -2707,7 +2721,13 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e continue; // don't clip against owner } - trace = World_ClipMoveToEntity (w, touch, lp, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); + if ((clip.type & MOVE_HITMODEL) && w->Event_Backdate) + { + w->Event_Backdate(w, touch, w->lagentstime); + trace = World_ClipMoveToEntity (w, touch, lp, la, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); + } + else + trace = World_ClipMoveToEntity (w, touch, lp, la, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction) { diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index ab477d108..117e96916 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -1,4 +1,4 @@ -!!ver 100 150 +!!ver 100 300 !!permu TESS !!permu BUMP !!permu FRAMEBLEND