]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
finished a lot of little todo items, mostly regarding server list and networking...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 19 Sep 2003 01:52:41 +0000 (01:52 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Fri, 19 Sep 2003 01:52:41 +0000 (01:52 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3469 d7cf8633-e32d-0410-b094-e92efae38249

cl_demo.c
cl_main.c
host.c
menu.c
netconn.c
netconn.h
r_sky.c
todo

index e97648d68c5333053da42a62f18c2c3ebe61b426..e6aca73da60b921bf58d8161135e30e9dc8a5a67 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -308,6 +308,9 @@ void CL_PlayDemo_f (void)
        // disconnect from server
        CL_Disconnect ();
 
+       // update networking ports (this is mainly just needed at startup)
+       NetConn_ClientFrame();
+
        // open the demo file
        strcpy (name, Cmd_Argv(1));
        FS_DefaultExtension (name, ".dem");
index fe5f8afd642dd37de7f002e0362ec628e4538012..b235339ce35b49bd7927b1cd8e558595cfb5253b 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -222,13 +222,13 @@ void CL_EstablishConnection(const char *host)
 
        // clear menu's connect error message
        m_return_reason[0] = 0;
-
-       // stop demo loop in case this fails
        cls.demonum = -1;
-       CL_Disconnect();
 
        if (LHNETADDRESS_FromString(&cls.connect_address, host, 26000) && (cls.connect_mysocket = NetConn_ChooseClientSocketForAddress(&cls.connect_address)))
        {
+               // stop demo loop in case this fails
+               CL_Disconnect();
+
                cls.connect_trying = true;
                cls.connect_remainingtries = 3;
                cls.connect_nextsendtime = 0;
@@ -244,6 +244,11 @@ void CL_EstablishConnection(const char *host)
                        NetConn_ServerFrame();
                }
        }
+       else
+       {
+               Con_Printf("Unable to find a suitable network socket to connect to server.\n");
+               strcpy(m_return_reason, "No network");
+       }
 }
 
 /*
diff --git a/host.c b/host.c
index dadc7ed3eb5000a86b24ba0134178b2038635108..0f083e98830aaab474d8d12c607bc4612255c92f 100644 (file)
--- a/host.c
+++ b/host.c
@@ -541,7 +541,7 @@ Returns false if the time is too short to run a frame
 extern cvar_t cl_avidemo;
 qboolean Host_FilterTime (double time)
 {
-       double timecap;
+       double timecap, timeleft;
        realtime += time;
 
        if (slowmo.value < 0.0f)
@@ -554,21 +554,24 @@ qboolean Host_FilterTime (double time)
                Cvar_SetValue("cl_avidemo", 0.0f);
 
        // check if framerate is too high
-       if (cl_avidemo.value >= 0.1f)
+       if (!cls.timedemo)
        {
-               timecap = 1.0 / (double)cl_avidemo.value;
-               if ((realtime - oldrealtime) < timecap)
-                       return false;
-       }
-       else if (!cls.timedemo)
-       {
-               // default to sys_ticrate (server framerate - presumably low) unless we're the active window and either connected to a server or playing a video
+               // default to sys_ticrate (server framerate - presumably low) unless we
+               // have a good reason to run faster
                timecap = sys_ticrate.value;
-               if (vid_activewindow && (cls.state == ca_connected || cl_videoplaying))
+               if (cl_avidemo.value >= 0.1f)
+                       timecap = 1.0 / (double)cl_avidemo.value;
+               else if (vid_activewindow && !scr_con_current)
                        timecap = 1.0 / host_maxfps.value;
 
-               if ((realtime - oldrealtime) < timecap)
+               timeleft = oldrealtime + timecap - realtime;
+               if (timeleft > 0)
+               {
+                       // don't totally hog the CPU
+                       if (timeleft >= 0.02)
+                               Sys_Sleep();
                        return false;
+               }
        }
 
        // LordHavoc: copy into host_realframetime as well
@@ -685,11 +688,7 @@ void _Host_Frame (float time)
 
        // decide the simulation time
        if (!Host_FilterTime(time))
-       {
-               // if time was rejected, don't totally hog the CPU
-               Sys_Sleep();
                return;
-       }
 
        cl.islocalgame = NetConn_IsLocalGame();
 
@@ -880,7 +879,10 @@ void Host_Init (void)
        Con_DPrintf ("========Initialized=========\n");
 
        if (cls.state != ca_dedicated)
+       {
                VID_Open();
+               SCR_BeginLoadingPlaque();
+       }
 }
 
 
diff --git a/menu.c b/menu.c
index a785f554b43a73f52b0e41424dc012b43be83b95..df2b53bc0ab92332f3c6d8f8662329afa8f7cae2 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -3363,26 +3363,38 @@ void M_ServerList_Draw (void)
 {
        int n, y, visible, start, end;
        cachepic_t *p;
+       const char *s;
 
        // use as much vertical space as available
        M_Background(640, vid.conheight);
        // scroll the list as the cursor moves
-       visible = (vid.conheight - 16 - 32) / 8;
+       s = va("%i/%i masters %i/%i servers", masterreplycount, masterquerycount, serverreplycount, serverquerycount);
+       M_PrintRed((640 - strlen(s) * 8) / 2, 32, s);
+       if (*m_return_reason)
+               M_Print(16, vid.conheight - 8, m_return_reason);
+       y = 48;
+       visible = (vid.conheight - 16 - y) / 8;
        start = bound(0, slist_cursor - (visible >> 1), hostCacheCount - visible);
        end = min(start + visible, hostCacheCount);
 
        p = Draw_CachePic("gfx/p_multi.lmp");
        M_DrawPic((640 - p->width) / 2, 4, "gfx/p_multi.lmp");
-       y = 32;
-       for (n = start;n < end;n++)
+       if (end > start)
        {
-               M_Print(0, y, hostcache[n].line1);y += 8;
-               M_Print(0, y, hostcache[n].line2);y += 8;
+               for (n = start;n < end;n++)
+               {
+                       DrawQ_Fill(menu_x, menu_y + y, 640, 16, n == slist_cursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+                       M_Print(0, y, hostcache[n].line1);y += 8;
+                       M_Print(0, y, hostcache[n].line2);y += 8;
+               }
+       }
+       else if (realtime - masterquerytime < 3)
+       {
+               if (masterquerycount)
+                       M_Print(0, y, "No servers found");
+               else
+                       M_Print(0, y, "No master servers found (network problem?)");
        }
-       M_DrawCharacter(0, 32 + (slist_cursor - start) * 16, 12+((int)(realtime*4)&1));
-
-       if (*m_return_reason)
-               M_Print(16, vid.conheight - 8, m_return_reason);
 }
 
 
index 9d2abab9dbdda00e9004026287cd43f23950de50..d72dffed91e56f39b1d2521f7009acde343c7b31 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -68,6 +68,12 @@ static int unreliableMessagesReceived = 0;
 static int reliableMessagesSent = 0;
 static int reliableMessagesReceived = 0;
 
+double masterquerytime = -1000;
+int masterquerycount = 0;
+int masterreplycount = 0;
+int serverquerycount = 0;
+int serverreplycount = 0;
+
 int hostCacheCount = 0;
 hostcache_t hostcache[HOSTCACHESIZE];
 
@@ -468,17 +474,17 @@ static int clientport2 = -1;
 static int hostport = -1;
 static void NetConn_UpdateServerStuff(void)
 {
-       if (clientport2 != cl_netport.integer)
-       {
-               clientport2 = cl_netport.integer;
-               if (cls.state == ca_connected)
-                       Con_Printf("Changing \"cl_port\" will not take effect until you reconnect.\n");
-       }
        if (cls.state != ca_dedicated)
        {
-               if (cls.state == ca_disconnected && clientport != cl_netport.integer)
+               if (clientport2 != cl_netport.integer)
                {
-                       clientport = cl_netport.integer;
+                       clientport2 = cl_netport.integer;
+                       if (cls.state == ca_connected)
+                               Con_Printf("Changing \"cl_port\" will not take effect until you reconnect.\n");
+               }
+               if (cls.state == ca_disconnected && clientport != clientport2)
+               {
+                       clientport = clientport2;
                        NetConn_CloseClientPorts();
                }
                if (cl_numsockets == 0)
@@ -689,21 +695,6 @@ int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length,
                        string += 13;
                        // hostcache only uses text addresses
                        LHNETADDRESS_ToString(peeraddress, cname, sizeof(cname), true);
-                       // search the cache for this server
-                       for (n = 0; n < hostCacheCount; n++)
-                               if (!strcmp(cname, hostcache[n].cname))
-                                       break;
-                       // add it or update it
-                       if (n == hostCacheCount)
-                       {
-                               // if cache is full replace highest ping server (the list is
-                               // kept sorted so this is always the last, and if this server
-                               // is good it will be sorted into an early part of the list)
-                               if (hostCacheCount >= HOSTCACHESIZE)
-                                       n = hostCacheCount - 1;
-                               else
-                                       hostCacheCount++;
-                       }
                        if ((s = SearchInfostring(string, "gamename"     )) != NULL) strncpy(game, s, sizeof(game) - 1);else game[0] = 0;
                        if ((s = SearchInfostring(string, "modname"      )) != NULL) strncpy(mod , s, sizeof(mod ) - 1);else mod[0] = 0;
                        if ((s = SearchInfostring(string, "mapname"      )) != NULL) strncpy(map , s, sizeof(map ) - 1);else map[0] = 0;
@@ -711,59 +702,67 @@ int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length,
                        if ((s = SearchInfostring(string, "protocol"     )) != NULL) c = atoi(s);else c = -1;
                        if ((s = SearchInfostring(string, "clients"      )) != NULL) users = atoi(s);else users = 0;
                        if ((s = SearchInfostring(string, "sv_maxclients")) != NULL) maxusers = atoi(s);else maxusers = 0;
-                       pingtime = 9999;
-                       for (i = 0;i < HOSTCACHESIZE;i++)
-                               if (!LHNETADDRESS_Compare(peeraddress, &pingcache[i].peeraddress))
-                                       pingtime = (int)(realtime - pingcache[i].senttime);
-                       pingtime = bound(0, pingtime, 9999);
-                       memset(&hostcache[n], 0, sizeof(hostcache[n]));
-                       // store the data the engine cares about (address and ping)
-                       strcpy(hostcache[n].cname, cname);
-                       hostcache[n].ping = pingtime;
-                       // build description strings for the things users care about
-                       snprintf(hostcache[n].line1, sizeof(hostcache[n].line1), "%5d%c%3u/%3u %-65.65s", (int)pingtime, c != NET_PROTOCOL_VERSION ? '*' : ' ', users, maxusers, name);
-                       snprintf(hostcache[n].line2, sizeof(hostcache[n].line2), "%-21.21s %-19.19s %-17.17s %-20.20s", cname, game, mod, map);
-                       // if ping is especially high, display it as such
-                       if (pingtime >= 300)
-                       {
-                               // orange numbers (lower block)
-                               for (i = 0;i < 5;i++)
-                                       if (hostcache[n].line1[i] != ' ')
-                                               hostcache[n].line1[i] += 128;
-                       }
-                       else if (pingtime >= 200)
-                       {
-                               // yellow numbers (in upper block)
-                               for (i = 0;i < 5;i++)
-                                       if (hostcache[n].line1[i] != ' ')
-                                               hostcache[n].line1[i] -= 30;
-                       }
-                       // if not in the slist menu we should print the server to console
-                       if (m_state != m_slist)
-                               Con_Printf("%s\n%s\n", hostcache[n].line1, hostcache[n].line2);
-                       // and finally, re-sort the list
-                       for (i = 0;i < hostCacheCount;i++)
+                       // search the cache for this server and update it
+                       for (n = 0; n < hostCacheCount; n++)
                        {
-                               for (j = i + 1;j < hostCacheCount;j++)
+                               if (!strcmp(cname, hostcache[n].cname))
                                {
-                                       //if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
-                                       if (hostcache[i].ping > hostcache[j].ping)
+                                       if (hostcache[n].ping == 100000)
+                                               serverreplycount++;
+                                       pingtime = (int)((realtime - hostcache[n].querytime) * 1000.0);
+                                       pingtime = bound(0, pingtime, 9999);
+                                       // update the ping
+                                       hostcache[n].ping = pingtime;
+                                       // build description strings for the things users care about
+                                       snprintf(hostcache[n].line1, sizeof(hostcache[n].line1), "%5d%c%3u/%3u %-65.65s", (int)pingtime, c != NET_PROTOCOL_VERSION ? '*' : ' ', users, maxusers, name);
+                                       snprintf(hostcache[n].line2, sizeof(hostcache[n].line2), "%-21.21s %-19.19s %-17.17s %-20.20s", cname, game, mod, map);
+                                       // if ping is especially high, display it as such
+                                       if (pingtime >= 300)
+                                       {
+                                               // orange numbers (lower block)
+                                               for (i = 0;i < 5;i++)
+                                                       if (hostcache[n].line1[i] != ' ')
+                                                               hostcache[n].line1[i] += 128;
+                                       }
+                                       else if (pingtime >= 200)
                                        {
-                                               memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
-                                               memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
-                                               memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
+                                               // yellow numbers (in upper block)
+                                               for (i = 0;i < 5;i++)
+                                                       if (hostcache[n].line1[i] != ' ')
+                                                               hostcache[n].line1[i] -= 30;
                                        }
+                                       // if not in the slist menu we should print the server to console
+                                       if (m_state != m_slist)
+                                               Con_Printf("%s\n%s\n", hostcache[n].line1, hostcache[n].line2);
+                                       // and finally, re-sort the list
+                                       for (i = 0;i < hostCacheCount;i++)
+                                       {
+                                               for (j = i + 1;j < hostCacheCount;j++)
+                                               {
+                                                       //if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
+                                                       if (hostcache[i].ping > hostcache[j].ping)
+                                                       {
+                                                               memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
+                                                               memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
+                                                               memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
+                                                       }
+                                               }
+                                       }
+                                       break;
                                }
                        }
                        return true;
                }
                if (!strncmp(string, "getserversResponse\\", 19) && hostCacheCount < HOSTCACHESIZE)
                {
-                       int i, best;
-                       double besttime;
+                       int i, n, j;
+                       hostcache_t temp;
                        // Extract the IP addresses
                        data += 18;
                        length -= 18;
+                       masterreplycount++;
+                       if (m_state != m_slist)
+                               Con_Printf("received server list...\n");
                        while (length >= 7 && data[0] == '\\' && (data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || data[4] != 0xFF) && data[5] * 256 + data[6] != 0)
                        {
                                sprintf(ipstring, "%u.%u.%u.%u:%u", data[1], data[2], data[3], data[4], (data[5] << 8) | data[6]);
@@ -771,28 +770,54 @@ int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, qbyte *data, int length,
                                        Con_Printf("Requesting info from server %s\n", ipstring);
                                LHNETADDRESS_FromString(&svaddress, ipstring, 0);
                                NetConn_WriteString(mysocket, "\377\377\377\377getinfo", &svaddress);
-                               // replace oldest or matching entry in ping cache
-                               // we scan this later when getting a reply to see how long it took
-                               besttime = realtime;
-                               best = 0;
-                               for (i = 0;i < HOSTCACHESIZE;i++)
+
+
+                               // add to slist (hostCache)
+                               // search the cache for this server
+                               for (n = 0; n < hostCacheCount; n++)
+                                       if (!strcmp(ipstring, hostcache[n].cname))
+                                               break;
+                               // add it or update it
+                               if (n == hostCacheCount)
                                {
-                                       if (!LHNETADDRESS_Compare(&svaddress, &pingcache[i].peeraddress))
+                                       // if cache is full replace highest ping server (the list is
+                                       // kept sorted so this is always the last, and if this server
+                                       // is good it will be sorted into an early part of the list)
+                                       if (hostCacheCount >= HOSTCACHESIZE)
+                                               n = hostCacheCount - 1;
+                                       else
                                        {
-                                               best = i;
-                                               break;
+                                               serverquerycount++;
+                                               hostCacheCount++;
                                        }
-                                       if (besttime > pingcache[i].senttime)
+                               }
+                               memset(&hostcache[n], 0, sizeof(hostcache[n]));
+                               // store the data the engine cares about (address and ping)
+                               strcpy(hostcache[n].cname, ipstring);
+                               hostcache[n].ping = 100000;
+                               hostcache[n].querytime = realtime;
+                               // build description strings for the things users care about
+                               snprintf(hostcache[n].line1, sizeof(hostcache[n].line1), "?");
+                               snprintf(hostcache[n].line2, sizeof(hostcache[n].line2), "%s", ipstring);
+                               // if not in the slist menu we should print the server to console
+                               if (m_state != m_slist)
+                                       Con_Printf("querying %s\n", ipstring);
+                               // and finally, re-sort the list
+                               for (i = 0;i < hostCacheCount;i++)
+                               {
+                                       for (j = i + 1;j < hostCacheCount;j++)
                                        {
-                                               besttime = pingcache[i].senttime;
-                                               best = i;
-                                               // if ping cache isn't full yet we can skip out early
-                                               if (!besttime)
-                                                       break;
+                                               //if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
+                                               if (hostcache[i].ping > hostcache[j].ping)
+                                               {
+                                                       memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
+                                                       memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
+                                                       memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
+                                               }
                                        }
                                }
-                               pingcache[best].peeraddress = svaddress;
-                               pingcache[best].senttime = realtime;
+
+
                                // move on to next address in packet
                                data += 7;
                                length -= 7;
@@ -918,13 +943,26 @@ void NetConn_ClientFrame(void)
                if (cls.connect_remainingtries == 0)
                {
                        cls.connect_trying = false;
-                       Con_Printf("Connect failed\n");
+                       if (m_state == m_slist)
+                               strcpy(m_return_reason, "Connect: Failed");
+                       else
+                               Con_Printf("Connect failed\n");
                        return;
                }
                if (cls.connect_nextsendtime)
-                       Con_Printf("Still trying...\n");
+               {
+                       if (m_state == m_slist)
+                               strcpy(m_return_reason, "Connect: Still trying");
+                       else
+                               Con_Printf("Still trying...\n");
+               }
                else
-                       Con_Printf("Trying...\n");
+               {
+                       if (m_state == m_slist)
+                               strcpy(m_return_reason, "Connect: Trying");
+                       else
+                               Con_Printf("Trying...\n");
+               }
                cls.connect_nextsendtime = realtime + 1;
                cls.connect_remainingtries--;
                // try challenge first (newer server)
@@ -1371,7 +1409,8 @@ void NetConn_ServerFrame(void)
                        NetConn_ServerParsePacket(sv_sockets[i], readbuffer, length, &peeraddress);
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
        {
-               if (host_client->netconnection && realtime > host_client->netconnection->timeout)
+               // never timeout loopback connections
+               if (host_client->netconnection && realtime > host_client->netconnection->timeout && LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(host_client->netconnection->mysocket)) != LHNETADDRESSTYPE_LOOP)
                {
                        Con_Printf("Client \"%s\" connection timed out\n", host_client->name);
                        sv_player = host_client->edict;
@@ -1418,10 +1457,20 @@ void NetConn_QueryMasters(void)
 
                        // search internet
                        for (masternum = 0;sv_masters[masternum].name;masternum++)
+                       {
                                if (sv_masters[masternum].string && LHNETADDRESS_FromString(&masteraddress, sv_masters[masternum].string, MASTER_PORT) && LHNETADDRESS_GetAddressType(&masteraddress) == LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i])))
+                               {
+                                       masterquerycount++;
                                        NetConn_WriteString(cl_sockets[i], request, &masteraddress);
+                               }
+                       }
                }
        }
+       if (!masterquerycount)
+       {
+               Con_Printf("Unable to query master servers, no suitable network sockets active.\n");
+               strcpy(m_return_reason, "No network");
+       }
 }
 
 void NetConn_Heartbeat(int priority)
@@ -1494,7 +1543,10 @@ int NetConn_SendToAll(sizebuf_t *data, double blocktime)
 
 static void Net_Heartbeat_f(void)
 {
-       NetConn_Heartbeat(2);
+       if (sv.active)
+               NetConn_Heartbeat(2);
+       else
+               Con_Printf("No server running, can not heartbeat to master server.\n");
 }
 
 void PrintStats(netconn_t *conn)
@@ -1521,6 +1573,11 @@ void Net_Stats_f(void)
 
 void Net_Slist_f(void)
 {
+       masterquerytime = realtime;
+       masterquerycount = 0;
+       masterreplycount = 0;
+       serverquerycount = 0;
+       serverreplycount = 0;
        hostCacheCount = 0;
        memset(&pingcache, 0, sizeof(pingcache));
        if (m_state != m_slist)
index c1d1e6708a2afb1b90558d482b62f93bedf0d00d..cc991276ea9c4c612f387266cf8c0cffdb64321c 100755 (executable)
--- a/netconn.h
+++ b/netconn.h
@@ -159,7 +159,9 @@ extern int playercolor;
 typedef struct
 {
        // ping time for sorting servers
-       double ping;
+       int ping;
+       // used to calculate ping when update comes in
+       double querytime;
        // address for connecting
        char cname[128];
        // description (seen by user)
@@ -191,6 +193,12 @@ extern unsigned short ntohs (unsigned short netshort);
 //
 //============================================================================
 
+extern double masterquerytime;
+extern int masterquerycount;
+extern int masterreplycount;
+extern int serverquerycount;
+extern int serverreplycount;
+
 extern sizebuf_t net_message;
 
 extern cvar_t cl_fakelocalping_min;
diff --git a/r_sky.c b/r_sky.c
index 2995a85dd6e17dc1f5300cb482637996bb8ba148..41f9876351dd6497d711f8cf478f924ff9abb8f3 100644 (file)
--- a/r_sky.c
+++ b/r_sky.c
@@ -221,7 +221,7 @@ static void R_SkyBox(void)
        {
                m.tex[0] = R_GetTexture(skyboxside[i]);
                R_Mesh_State_Texture(&m);
-               R_Mesh_Draw(4, 2, skyboxelements + i * 6);
+               R_Mesh_Draw(6*4, 2, skyboxelements + i * 6);
        }
 }
 
diff --git a/todo b/todo
index 0b50644f8eb34ee43609b4ff0f8acccf3d91e792..0eeeef5b527a6475664dd123104a1524abc2d5fa 100644 (file)
--- a/todo
+++ b/todo
@@ -1,23 +1,22 @@
 - todo: difficulty ratings are: 0 = trivial, 1 = easy, 2 = easy-moderate, 3 = moderate, 4 = moderate-hard, 5 = hard, 6 = hard++, 7 = nightmare, d = done, -n = done but have not notified the people who asked for it, f = failed
+-n darkplaces: add stats to slist menu displaying how many masters/servers have been queried and replied (tell yummyluv)
 -n darkplaces: check out qe1 textures and make sure they load in all the e1 maps, report of crashing in most but not all maps (Linny Amore)
+-n darkplaces: display "No servers found" instead of a cursor when there are none (yummyluv)
 -n darkplaces: fix a crash when changing level while using qe1 textures (Todd)
--n darkplaces: make LHNET_Read print out the names of read errors (yummyluv)
+-n darkplaces: fix skybox geometry (SeienAbunae)
+-n darkplaces: net_slist and the server browser should show servers when they are queried, not just when they reply; which would replace the matching entry (yummyluv)
+-n darkplaces: net_slist should print out "No network." if networking is not initialized (yummyluv)
+-n darkplaces: remove dead master server from default masters list (yummyluv)
 -n darkplaces: revert noclip movement to match nq for compatibility with mods that trap movement as input (MauveBib)
+-n darkplaces: segfault reading memory in windows when starting a new server from menu (yummyluv)
+-n darkplaces: server is starting before the "port" cvar is set by commandline and scripts? (yummyluv)
+-n darkplaces: typing ip in join game menu should show 'trying' and 'no response' after a while, or 'no network' if networking is not initialized (yummyluv)
 -n dpmod: make grapple off-hand (joe hill)
-0 darkplaces: add Draw2D function to model struct to make it easy to draw models without an entity (Tomaz)
-0 darkplaces: fix "game speed" menu option, it's too far left (Tomaz)
-4 darkplaces: add crude DML model loading with animation list (ask Riot for dml library) (Mitchell)
-5 darkplaces: add crude SKM model loading with animation list (Vermeulen)
-2 darkplaces: should support corona-model shaders somehow (equation: pow(normalizationcubemap(transform(eye, vertexmatrix)) dot3 '0 0 1', 8)), which are normally used around unusually shaped lights instead of flat coronas (Mitchell)
-0 lhfire: make a lhfire.txt and move the scripting info to it, add some more general explanation and tips
-0 darkplaces: add sv_gameplayfix_grenadebouncedownslopes cvar (default 1)
-0 darkplaces: add sv_gameplayfix_swiminbmodels cvar (default 1)
-0 darkplaces: add sv_gameplayfix_stepwhilejumping cvar (default 1), note that sv_jumpstep must also be on to enable this
-0 darkplaces: add sv_gameplayfix_noairborncorpse cvar (default 1)
 0 darkplaces: ability to disable fopen builtin access to read /, read data/, write data/, or disable fopen builtin entirely
 0 darkplaces: add DP_GFX_QUAKE3MODELTAGS, DP_GFX_SKINFILES, and any other new extensions to the wiki
 0 darkplaces: add DP_LITSUPPORT extension and document it
 0 darkplaces: add DP_SV_ROTATINGBMODEL extension to explain that MOVETYPE_PUSH/SOLID_BSP support rotation in darkplaces and a demonstration of how to use it without qc modifications (Uffe, Supajoe)
+0 darkplaces: add Draw2D function to model struct to make it easy to draw models without an entity (Tomaz)
 0 darkplaces: add a .collision_cancollide QC function call to decide if an entity should collide with another, or pass through it (Uffe)
 0 darkplaces: add a clipmask thingy to allow QC to mask off collisions as it wishes (Uffe)
 0 darkplaces: add a scr_screenshot_jpeg_quality cvar (Electro)
 0 darkplaces: add lightning beam settings to menu (romi)
 0 darkplaces: add slowmo to options menu (Cristian Beltramo)
 0 darkplaces: add support for multiple -game's (note: this needs an enhanced COM_CheckParm to find the multiple matches) (Static_Fiend)
+0 darkplaces: add sv_gameplayfix_grenadebouncedownslopes cvar (default 1)
+0 darkplaces: add sv_gameplayfix_noairborncorpse cvar (default 1)
+0 darkplaces: add sv_gameplayfix_stepwhilejumping cvar (default 1), note that sv_jumpstep must also be on to enable this
+0 darkplaces: add sv_gameplayfix_swiminbmodels cvar (default 1)
 0 darkplaces: add svc_setanglefloat and DP_SVC_SETANGLEFLOAT extension (FrikaC, SeienAbunae)
 0 darkplaces: add te_flamejet builtin and add extension (Supajoe)
-0 darkplaces: add view height to chase_active again (yummyluv)
 0 darkplaces: alias layers should have a shadow volume pass so that nodraw textures don't cast a shadow (Electro)
 0 darkplaces: bug in mod_q3bsp_optimizedtraceline code, bots shooting through walls? (Vermeulen)
 0 darkplaces: bullets don't hit walls at steep angles in id1
 0 darkplaces: can't move when stuck in a monster (SeienAbunae)
 0 darkplaces: change particle() macro in cl_particles.c to have a do{}while(0) to eat the ;
 0 darkplaces: cl_particles_maximum cvar (default 32768) which would change number of particles allowed at once (TheBeast)
-0 darkplaces: cl_port 26001 causes server browser to read successfully (yummyluv)
 0 darkplaces: clean up the DrawQ_ blendfunc handling, instead of taking DRAWFLAG_ADDITIVE they should take blendfunc values (Black)
 0 darkplaces: client colors being reset to "15 15" each level in prydon gate (FrikaC)
 0 darkplaces: crashes if you type too long a command line in the console (SeienAbunae)
 0 darkplaces: darkplaces-glx -path transfusion crashes, fix the crash even though it's not going to work anyway (Todd)
 0 darkplaces: dedicated server hosting prydon with multiple players exhibited severe networking bugs in tests, including failure to find acked network frames, and a segfault (Supajoe, Uffe, FrikaC, Harb)
-0 darkplaces: dedicated server should error out if it has no sockets (yummyluv)
-0 darkplaces: dedicated server should not bother allocating a loopback socket (yummyluv)
 0 darkplaces: default to 32bit color
 0 darkplaces: delay "connect" and "playdemo" and "timedemo" until after video init to cause quicker video startup (KrimZon)
 0 darkplaces: document how polygon collision works in the code (KrimZon)
 0 darkplaces: figure out random crashes on map changes (Uffe, QorpsE)
 0 darkplaces: figure out what's wrong with gloss rendering vertex calculations, which may be GF2 related (QorpsE)
 0 darkplaces: figure out why monsters keep making fall pain sound after they've landed in dpmod (Cruaich)
+0 darkplaces: fix "game speed" menu option, it's too far left (Tomaz)
 0 darkplaces: fix 'wall hugging' stuttering, also stuttering movement when walking over steps or monsters (romi)
 0 darkplaces: fix con_notify (should control number of lines)
 0 darkplaces: fix intermission failing to move view to intermission camera (romi, Zombie_13)
 0 darkplaces: fix key based turning being affected by slowmo - it should not be
-0 darkplaces: fix skybox geometry (SeienAbunae)
 0 darkplaces: fix the fact singleplayer is using maxplayers 8
 0 darkplaces: fix view blends slightly lingering as time goes on, they should go away completely (Cruaich)
 0 darkplaces: get rid of stencil options and make 32bit color automatically use stencil
 0 darkplaces: hack PF_nextent to skip inaccessible client slots depending on maxplayers - but always report ones that are active at the time (FrikaC)
-0 darkplaces: heartbeat should print an error message if used with no server running (yummyluv)
 0 darkplaces: identify weird lightmap texturing bug on TNT cards - goes away in r_textureunits 1 (NotoriousRay, Uffe)
 0 darkplaces: increase resolution of particlefont to 512x512 (Chillo)
 0 darkplaces: integrate zinx's psycho.c gamma hack as an easteregg
-0 darkplaces: investigate why server is not automatically sending heartbeats (yummyluv)
 0 darkplaces: make Com_HexDumpToConsole not use color
 0 darkplaces: make DP_EF_FULLBRIGHT extension (FrikaC)
 0 darkplaces: make S_Update take a matrix4x4_t *
 0 darkplaces: make sure that sound engine does not remove sounds when volume drops to 0 due to going out of range (SeienAbunae)
 0 darkplaces: make the WriteEntitiesToClient code call TraceBox directly instead of SV_Move because checking all the entities is far too slow in helm18 (banshee21)
 0 darkplaces: model interpolation off crashes?  (SeienAbunae)
-0 darkplaces: net_slist and the server browser should show servers when they are queried, not just when they reply; which would replace the matching entry (yummyluv)
-0 darkplaces: net_slist should print out "No network." if networking is not initialized (yummyluv)
 0 darkplaces: noclipping out the ceiling of q3dm17 crashes (Static_Fiend)
 0 darkplaces: pointcontents crash when building harvester in gvb2? (yummyluv)
 0 darkplaces: r_shadow should load .ent when importing light entities
 0 darkplaces: r_shadow_portallight 1 (default) mode is broken currently, does not light all surfaces, maybe even fails to go through some portals? (Vermeulen)
 0 darkplaces: r_skyscroll1 and r_skyscroll2 cvars (SeienAbunae)
-0 darkplaces: remove dead master server from default masters list (yummyluv)
 0 darkplaces: rename r_picmip and r_max_size and such to glquake names
 0 darkplaces: reset zoom on connect (Rick)
 0 darkplaces: scrags frequently fly through ceilings - this needs to be fixed
-0 darkplaces: segfault reading memory in windows when starting a new server from menu (yummyluv)
-0 darkplaces: server is starting before the "port" cvar is set by commandline and scripts? (yummyluv)
 0 darkplaces: shadows are not working with model tag attachments (Electro)
 0 darkplaces: test TecnoX and find the frikbot crash in SV_Physics (KrimZon)
 0 darkplaces: test zlib support with entirely pk3'd id1 data (should crash because of zlib not being setup early enough - fix this) (Mabus)
 0 darkplaces: the new sound engine should have a cvar for random variations of pitch on sounds like in doom (RenegadeC)
 0 darkplaces: try not adding gravity when onground to see if it gets rid of ramp sliding (Midgar)
 0 darkplaces: tweak the blood decals in the particlefont to make them look more like the q2e_blood.avi video (Vermeulen)
-0 darkplaces: typing ip in join game menu should show 'trying' and 'no response' after a while, or 'no network' if networking is not initialized (yummyluv)
 0 dpmod: add a "monsterwander" cvar and default it off, this would enable the spawnwanderpath code (Zombie13)
 0 dpmod: add combo kill detection; rapid burst of kills (SeienAbunae)
 0 dpmod: add flame thrower enforcers back (scar3crow)
 0 dpzoo: thief-like area to sneak past a guard who can easily kill you (shambler?) to demonstrate lightlevel checking
 0 dpzoo: transparent glass bmodels (DP_ENT_ALPHA)
 0 hmap: add space to seconds reports in all utilities so it doesn't say secondssss (FrikaC)
+0 lhfire: make a lhfire.txt and move the scripting info to it, add some more general explanation and tips
 0 litsupport: fix the one COM_HunkFile call that uses two parameters (glquake took one) and fix the few "//lit support begin" messages at the end of code blocks (metlslime)
 0 revelation: change the wabbit kill message to " was hunting wabbit but shot " " instead"
 0 sv_user.qc: figure out why looking up/down slows movement and fix it (Vermeulen)
 1 darkplaces: client crashes on +button8? (Static_Fiend)
 1 darkplaces: crashes on radeon in rare situations that seem to occur in dpmod dm 7 mode? (Option42)
 1 darkplaces: decide on an extension name for .ent loading and report it, also document in dpextensions (tell FrikaC, Gleeb, and add to wiki)
-1 darkplaces: display "No servers found" instead of a cursor when there are none (yummyluv)
 1 darkplaces: don't accept connect packets after first one (tell Willis)
-1 darkplaces: figure out what's causing skybox to go textureless occasionally (yummyluv)
 1 darkplaces: finish porting Quake2 keyboard stuff (such as clipboard) (Rick, FrikaC)
 1 darkplaces: fix lots of bugs and then retitle the website to get more publicity: DarkPlaces: Re-live Quake again...
 1 darkplaces: fix stuck buttons during a level change (mercury82, tkimmet@ezworks.net)  (further note: this is from the console becoming active temporarily and catching the key release when the player lets go during the loading stage, make it possible to release a button that was pressed before the console was activated, or make it execute -commands for all pressed binds when level starts)
 2 darkplaces: add cvar callbacks and make net cvars have callbacks
 2 darkplaces: add fuhquake naming of map textures (textures/start/quake.tga style)
 2 darkplaces: add removemapmusic (optional map name or ogg name to clear) and mapmusic commands (<maps/mapname.bsp> <music/whatever.ogg> perhaps) to manipulate list of per-map music overrides (Joseph Caporale, tell Static_Fiend)
-2 darkplaces: add stats to slist menu displaying how many masters/servers have been queried and replied (tell yummyluv)
 2 darkplaces: figure out how to prevent "alias a a" - infinite loop when executed, this should be detected when executing it (Vicious)
 2 darkplaces: figure out why -sndspeed 22050, 44100 and 16000 are choppy in windows? (cheapalert)
 2 darkplaces: frikbot scores don't update - discovered this is because of the fact they have no client (Todd)
 2 darkplaces: player ip logging by nickname (sublim3)
 2 darkplaces: prevent player name changes faster than twice a second (sublim3)
 2 darkplaces: proquake precise aiming support (sublim3 doesn't care, but tell him anyway)
+2 darkplaces: should support corona-model shaders somehow (equation: pow(normalizationcubemap(transform(eye, vertexmatrix)) dot3 '0 0 1', 8)), which are normally used around unusually shaped lights instead of flat coronas (Mitchell)
 2 darkplaces: upgrade protocol to have shorts for stats (scar3crow)
 2 darkplaces: write a readme (Antti)
 2 darkplaces: zym shadows
 4 darkplaces: add SKM model support with multianimation support using multiple .frame fields on the entities (Vermeulen)
 4 darkplaces: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh)
 4 darkplaces: add builtins to clientside qc for gl calls
+4 darkplaces: add crude DML model loading with animation list (ask Riot for dml library) (Mitchell)
 4 darkplaces: add traceboxwithcontents function (same as tracebox but adds the startcontents parameter) (LTH, SeienAbunae, http://forums.inside3d.com/showflat.pl?Board=Engine&Number=909 )
 4 darkplaces: add wav music playback (tell Joseph Caporale, tell Static_Fiend)
 4 darkplaces: figure out what is breaking in prydon gate town curig (Uffe)
 5 darkplaces: add a "edictedit" command to open up a dialog to edit an edict (allow multiple dialogs to be open at once)
 5 darkplaces: add a new TE_TELEPORTSHELL effect which would take an entity and create a fading plasma shell of its model at the moment of teleportation (tell fuh and Mercury about this)
 5 darkplaces: add back colormod extension (FrikaC, Uffe)
+5 darkplaces: add crude SKM model loading with animation list (Vermeulen)
 5 darkplaces: add dpshader support
 5 darkplaces: add short and long documentation string to each cvar/command (QorpsE)
 5 darkplaces: do a minimap that works by simply using nearclip to sheer off anything above the eye, and draws anything below normally, or via a cvar as height coloring (Supajoe)
@@ -311,10 +303,13 @@ d darkplaces: add cl_decals to effects options menu
 d darkplaces: add file access functions and string handling (diGGer)
 d darkplaces: add multiple skin support to md2/md3 (Vermeuln)
 d darkplaces: add scr_conbrightness cvar (0-1) to control brightness of conback (0 = black and does not load conback, resets back to 0 if conback fails to load)
+d darkplaces: add view height to chase_active again (yummyluv)
 d darkplaces: add wgl support for mouse buttons 4 and 5 (Intellimouse Explorer) from Q2 (source supplied in email from joseph caporale@sbcglobal.net)
 d darkplaces: check if nodrawtoclient works and if not, fix it (Uffe)
 d darkplaces: colors of player in demos seems to alter player config (this is clearly a more severe problem than just demos) (tkimmet@ezworks.net)
 d darkplaces: debug server crash
+d darkplaces: dedicated server should error out if it has no sockets (yummyluv)
+d darkplaces: dedicated server should not bother allocating a loopback socket (yummyluv)
 d darkplaces: default deathmatch 1 in multiplayer games like Nexuiz incase someone starts a game from console (Vermeulen)
 d darkplaces: figure out what is broken about the shadow volumes or stencil comparisons
 d darkplaces: figure out what is wrong with loading _glow/_luma textures on md3 models (not bsp textures) (kd23 Nexuiz)
@@ -345,7 +340,9 @@ d darkplaces: fix wrapping textures on sprites/models (Elric)
 d darkplaces: get rid of frags per hour rating in deathmatch scoreboard and mini scoreboard
 d darkplaces: gl_flashblend 1 should disable dlighting of models (Tomaz)
 d darkplaces: have a look at CFQ and figure out why its b0rked (it assumed nq noclip movement)
+d darkplaces: heartbeat should print an error message if used with no server running (yummyluv)
 d darkplaces: loadgame broken (Linny Amore)
+d darkplaces: make LHNET_Read print out the names of read errors (yummyluv)
 d darkplaces: make client load .ent files
 d darkplaces: make missing skins show as white on models (Electro)
 d darkplaces: make model lerping optional