diff options
| author | xolatile | 2025-08-06 22:54:55 +0200 |
|---|---|---|
| committer | xolatile | 2025-08-06 22:54:55 +0200 |
| commit | 0a1172b75f571685c264a8b9d8ee224bbf11381f (patch) | |
| tree | d041fdc68a60f0ebb48a3852bbcce6d9432f83d5 /src/engine/serverbrowser.cpp | |
| parent | affde05dc07a94643f1fd2751b2b441f57f73d7d (diff) | |
| download | xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.xz xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.zst | |
Please do not hate me, it makes sense...
Diffstat (limited to 'src/engine/serverbrowser.cpp')
| -rw-r--r-- | src/engine/serverbrowser.cpp | 310 |
1 files changed, 88 insertions, 222 deletions
diff --git a/src/engine/serverbrowser.cpp b/src/engine/serverbrowser.cpp index 85109bf..a839c35 100644 --- a/src/engine/serverbrowser.cpp +++ b/src/engine/serverbrowser.cpp @@ -4,15 +4,13 @@ #define PROTOCOL_VERSION 260 // bump when protocol changes, dpulicate -struct resolverthread -{ +struct resolverthread { SDL_Thread *thread; const char *query; int starttime; }; -struct resolverresult -{ +struct resolverresult { const char *query; ENetAddress address; }; @@ -26,28 +24,23 @@ SDL_cond *querycond, *resultcond; #define RESOLVERTHREADS 2 #define RESOLVERLIMIT 3000 -int resolverloop(void * data) -{ +int resolverloop(void * data) { resolverthread *rt = (resolverthread *)data; SDL_LockMutex(resolvermutex); SDL_Thread *thread = rt->thread; SDL_UnlockMutex(resolvermutex); if(!thread || SDL_GetThreadID(thread) != SDL_ThreadID()) return 0; - while(thread == rt->thread) - { + while(thread == rt->thread) { SDL_LockMutex(resolvermutex); while(resolverqueries.empty()) SDL_CondWait(querycond, resolvermutex); rt->query = resolverqueries.pop(); rt->starttime = totalmillis; SDL_UnlockMutex(resolvermutex); - ENetAddress address = { ENET_HOST_ANY, ENET_PORT_ANY }; enet_address_set_host(&address, rt->query); - SDL_LockMutex(resolvermutex); - if(rt->query && thread == rt->thread) - { + if(rt->query && thread == rt->thread) { resolverresult &rr = resolverresults.add(); rr.query = rt->query; rr.address = address; @@ -60,15 +53,12 @@ int resolverloop(void * data) return 0; } -void resolverinit() -{ +void resolverinit() { resolvermutex = SDL_CreateMutex(); querycond = SDL_CreateCond(); resultcond = SDL_CreateCond(); - SDL_LockMutex(resolvermutex); - loopi(RESOLVERTHREADS) - { + loopi(RESOLVERTHREADS) { resolverthread &rt = resolverthreads.add(); rt.query = NULL; rt.starttime = 0; @@ -77,11 +67,9 @@ void resolverinit() SDL_UnlockMutex(resolvermutex); } -void resolverstop(resolverthread &rt) -{ +void resolverstop(resolverthread &rt) { SDL_LockMutex(resolvermutex); - if(rt.query) - { + if(rt.query) { #if SDL_VERSION_ATLEAST(2, 0, 2) SDL_DetachThread(rt.thread); #endif @@ -92,47 +80,38 @@ void resolverstop(resolverthread &rt) SDL_UnlockMutex(resolvermutex); } -void resolverclear() -{ +void resolverclear() { if(resolverthreads.empty()) return; - SDL_LockMutex(resolvermutex); resolverqueries.shrink(0); resolverresults.shrink(0); - loopv(resolverthreads) - { + loopv(resolverthreads) { resolverthread &rt = resolverthreads[i]; resolverstop(rt); } SDL_UnlockMutex(resolvermutex); } -void resolverquery(const char *name) -{ +void resolverquery(const char *name) { if(resolverthreads.empty()) resolverinit(); - SDL_LockMutex(resolvermutex); resolverqueries.add(name); SDL_CondSignal(querycond); SDL_UnlockMutex(resolvermutex); } -bool resolvercheck(const char **name, ENetAddress *address) -{ +bool resolvercheck(const char **name, ENetAddress *address) { bool resolved = false; SDL_LockMutex(resolvermutex); - if(!resolverresults.empty()) - { + if(!resolverresults.empty()) { resolverresult &rr = resolverresults.pop(); *name = rr.query; address->host = rr.address.host; resolved = true; } - else loopv(resolverthreads) - { + else loopv(resolverthreads) { resolverthread &rt = resolverthreads[i]; - if(rt.query && totalmillis - rt.starttime > RESOLVERLIMIT) - { + if(rt.query && totalmillis - rt.starttime > RESOLVERLIMIT) { resolverstop(rt); *name = rt.query; resolved = true; @@ -142,39 +121,31 @@ bool resolvercheck(const char **name, ENetAddress *address) return resolved; } -bool resolverwait(const char *name, ENetAddress *address) -{ +bool resolverwait(const char *name, ENetAddress *address) { if(resolverthreads.empty()) resolverinit(); - defformatstring(text, "resolving %s... (esc to abort)", name); renderprogress(0, text); - SDL_LockMutex(resolvermutex); resolverqueries.add(name); SDL_CondSignal(querycond); int starttime = SDL_GetTicks(), timeout = 0; bool resolved = false; - for(;;) - { + for(;;) { SDL_CondWaitTimeout(resultcond, resolvermutex, 250); - loopv(resolverresults) if(resolverresults[i].query == name) - { + loopv(resolverresults) if(resolverresults[i].query == name) { address->host = resolverresults[i].address.host; resolverresults.remove(i); resolved = true; break; } if(resolved) break; - timeout = SDL_GetTicks() - starttime; renderprogress(min(float(timeout)/RESOLVERLIMIT, 1.0f), text); if(interceptkey(SDLK_ESCAPE)) timeout = RESOLVERLIMIT + 1; if(timeout > RESOLVERLIMIT) break; } - if(!resolved && timeout > RESOLVERLIMIT) - { - loopv(resolverthreads) - { + if(!resolved && timeout > RESOLVERLIMIT) { + loopv(resolverthreads) { resolverthread &rt = resolverthreads[i]; if(rt.query == name) { resolverstop(rt); break; } } @@ -185,24 +156,19 @@ bool resolverwait(const char *name, ENetAddress *address) #define CONNLIMIT 20000 -int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &address) -{ +int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &address) { defformatstring(text, "connecting to %s... (esc to abort)", hostname); renderprogress(0, text); - ENetSocketSet readset, writeset; - if(!enet_socket_connect(sock, &address)) for(int starttime = SDL_GetTicks(), timeout = 0; timeout <= CONNLIMIT;) - { + if(!enet_socket_connect(sock, &address)) for(int starttime = SDL_GetTicks(), timeout = 0; timeout <= CONNLIMIT;) { ENET_SOCKETSET_EMPTY(readset); ENET_SOCKETSET_EMPTY(writeset); ENET_SOCKETSET_ADD(readset, sock); ENET_SOCKETSET_ADD(writeset, sock); int result = enet_socketset_select(sock, &readset, &writeset, 250); if(result < 0) break; - else if(result > 0) - { - if(ENET_SOCKETSET_CHECK(readset, sock) || ENET_SOCKETSET_CHECK(writeset, sock)) - { + else if(result > 0) { + if(ENET_SOCKETSET_CHECK(readset, sock) || ENET_SOCKETSET_CHECK(writeset, sock)) { int error = 0; if(enet_socket_get_option(sock, ENET_SOCKOPT_ERROR, &error) < 0 || error) break; return 0; @@ -212,45 +178,30 @@ int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress renderprogress(min(float(timeout)/CONNLIMIT, 1.0f), text); if(interceptkey(SDLK_ESCAPE)) break; } - return -1; } -struct pingattempts -{ +struct pingattempts { enum { MAXATTEMPTS = 2 }; - int offset, attempts[MAXATTEMPTS]; - pingattempts() : offset(0) { clearattempts(); } - void clearattempts() { memset(attempts, 0, sizeof(attempts)); } - void setoffset() { offset = 1 + rnd(0xFFFFFF); } - - int encodeping(int millis) - { + int encodeping(int millis) { millis += offset; return millis ? millis : 1; } - - int decodeping(int val) - { + int decodeping(int val) { return val - offset; } - - int addattempt(int millis) - { + int addattempt(int millis) { int val = encodeping(millis); loopk(MAXATTEMPTS-1) attempts[k+1] = attempts[k]; attempts[0] = val; return val; } - - bool checkattempt(int val, bool del = true) - { - if(val) loopk(MAXATTEMPTS) if(attempts[k] == val) - { + bool checkattempt(int val, bool del = true) { + if(val) loopk(MAXATTEMPTS) if(attempts[k] == val) { if(del) attempts[k] = 0; return true; } @@ -261,15 +212,11 @@ struct pingattempts enum { UNRESOLVED = 0, RESOLVING, RESOLVED }; -struct serverinfo : pingattempts -{ - enum - { +struct serverinfo : pingattempts { + enum { WAITING = INT_MAX, - MAXPINGS = 3 }; - string name, map, sdesc; int port, numplayers, resolved, ping, lastping, nextping; int pings[MAXPINGS]; @@ -277,65 +224,47 @@ struct serverinfo : pingattempts ENetAddress address; bool keep; const char *password; - serverinfo() - : port(-1), numplayers(0), resolved(UNRESOLVED), keep(false), password(NULL) - { + : port(-1), numplayers(0), resolved(UNRESOLVED), keep(false), password(NULL) { name[0] = map[0] = sdesc[0] = '\0'; clearpings(); setoffset(); } - - ~serverinfo() - { + ~serverinfo() { DELETEA(password); } - - void clearpings() - { + void clearpings() { ping = WAITING; loopk(MAXPINGS) pings[k] = WAITING; nextping = 0; lastping = -1; clearattempts(); } - - void cleanup() - { + void cleanup() { clearpings(); attr.setsize(0); numplayers = 0; } - - void reset() - { + void reset() { lastping = -1; } - - void checkdecay(int decay) - { + void checkdecay(int decay) { if(lastping >= 0 && totalmillis - lastping >= decay) cleanup(); if(lastping < 0) lastping = totalmillis; } - - void calcping() - { + void calcping() { int numpings = 0, totalpings = 0; loopk(MAXPINGS) if(pings[k] != WAITING) { totalpings += pings[k]; numpings++; } ping = numpings ? totalpings/numpings : WAITING; } - - void addping(int rtt, int millis) - { + void addping(int rtt, int millis) { if(millis >= lastping) lastping = -1; pings[nextping] = rtt; nextping = (nextping+1)%MAXPINGS; calcping(); } - - static bool compare(serverinfo *a, serverinfo *b) - { + static bool compare(serverinfo *a, serverinfo *b) { bool ac = (a->attr.length() != 0) && (a->attr[0]==PROTOCOL_VERSION); bool bc = (b->attr.length() != 0) && (b->attr[0]==PROTOCOL_VERSION); if(ac > bc) return true; @@ -358,36 +287,27 @@ vector<serverinfo *> servers; ENetSocket pingsock = ENET_SOCKET_NULL; int lastinfo = 0; -static serverinfo *newserver(const char *name, int port, uint ip = ENET_HOST_ANY) -{ +static serverinfo *newserver(const char *name, int port, uint ip = ENET_HOST_ANY) { serverinfo *si = new serverinfo; si->address.host = ip; si->address.port = server::serverinfoport(port); if(ip!=ENET_HOST_ANY) si->resolved = RESOLVED; - si->port = port; if(name) copystring(si->name, name); - else if(ip==ENET_HOST_ANY || enet_address_get_host_ip(&si->address, si->name, sizeof(si->name)) < 0) - { + else if(ip==ENET_HOST_ANY || enet_address_get_host_ip(&si->address, si->name, sizeof(si->name)) < 0) { delete si; return NULL; - } - servers.add(si); - return si; } -void addserver(const char *name, int port, const char *password, bool keep) -{ +void addserver(const char *name, int port, const char *password, bool keep) { if(port <= 0) port = server::serverport(); - loopv(servers) - { + loopv(servers) { serverinfo *s = servers[i]; if(strcmp(s->name, name) || s->port != port) continue; - if(password && (!s->password || strcmp(s->password, password))) - { + if(password && (!s->password || strcmp(s->password, password))) { DELETEA(s->password); s->password = newstring(password); } @@ -407,47 +327,37 @@ VARP(maxservpings, 0, 10, 1000); pingattempts lanpings; -template<size_t N> static inline void buildping(ENetBuffer &buf, uchar (&ping)[N], pingattempts &a) -{ +template<size_t N> static inline void buildping(ENetBuffer &buf, uchar (&ping)[N], pingattempts &a) { ucharbuf p(ping, N); putint(p, a.addattempt(totalmillis)); buf.data = ping; buf.dataLength = p.length(); } -void pingservers() -{ - if(pingsock == ENET_SOCKET_NULL) - { +void pingservers() { + if(pingsock == ENET_SOCKET_NULL) { pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); - if(pingsock == ENET_SOCKET_NULL) - { + if(pingsock == ENET_SOCKET_NULL) { lastinfo = totalmillis; return; } enet_socket_set_option(pingsock, ENET_SOCKOPT_NONBLOCK, 1); enet_socket_set_option(pingsock, ENET_SOCKOPT_BROADCAST, 1); - lanpings.setoffset(); } - ENetBuffer buf; uchar ping[MAXTRANS]; - static int lastping = 0; if(lastping >= servers.length()) lastping = 0; - loopi(maxservpings ? min(servers.length(), maxservpings) : servers.length()) - { + loopi(maxservpings ? min(servers.length(), maxservpings) : servers.length()) { serverinfo &si = *servers[lastping]; if(++lastping >= servers.length()) lastping = 0; if(si.address.host == ENET_HOST_ANY) continue; buildping(buf, ping, si); enet_socket_send(pingsock, &si.address, &buf, 1); - si.checkdecay(servpingdecay); } - if(searchlan) - { + if(searchlan) { ENetAddress address; address.host = ENET_HOST_BROADCAST; address.port = server::laninfoport(); @@ -457,31 +367,24 @@ void pingservers() lastinfo = totalmillis; } -void checkresolver() -{ +void checkresolver() { int resolving = 0; - loopv(servers) - { + loopv(servers) { serverinfo &si = *servers[i]; if(si.resolved == RESOLVED) continue; - if(si.address.host == ENET_HOST_ANY) - { + if(si.address.host == ENET_HOST_ANY) { if(si.resolved == UNRESOLVED) { si.resolved = RESOLVING; resolverquery(si.name); } resolving++; } } if(!resolving) return; - const char *name = NULL; - for(;;) - { + for(;;) { ENetAddress addr = { ENET_HOST_ANY, ENET_PORT_ANY }; if(!resolvercheck(&name, &addr)) break; - loopv(servers) - { + loopv(servers) { serverinfo &si = *servers[i]; - if(name == si.name) - { + if(name == si.name) { si.resolved = RESOLVED; si.address.host = addr.host; break; @@ -492,8 +395,7 @@ void checkresolver() static int lastreset = 0; -void checkpings() -{ +void checkpings() { if(pingsock==ENET_SOCKET_NULL) return; enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE; ENetBuffer buf; @@ -502,22 +404,19 @@ void checkpings() char text[MAXTRANS]; buf.data = ping; buf.dataLength = sizeof(ping); - while(enet_socket_wait(pingsock, &events, 0) >= 0 && events) - { + while(enet_socket_wait(pingsock, &events, 0) >= 0 && events) { int len = enet_socket_receive(pingsock, &addr, &buf, 1); if(len <= 0) return; ucharbuf p(ping, len); int millis = getint(p); serverinfo *si = NULL; loopv(servers) if(addr.host == servers[i]->address.host && addr.port == servers[i]->address.port) { si = servers[i]; break; } - if(si) - { + if(si) { if(!si->checkattempt(millis)) continue; millis = si->decodeping(millis); } else if(!searchlan || !lanpings.checkattempt(millis, false)) continue; - else - { + else { si = newserver(NULL, server::serverport(addr.port), addr.host); millis = lanpings.decodeping(millis); } @@ -534,8 +433,7 @@ void checkpings() } } -void sortservers() -{ +void sortservers() { servers.sort(serverinfo::compare); } COMMAND(sortservers, ""); @@ -543,17 +441,14 @@ COMMAND(sortservers, ""); VARP(autosortservers, 0, 1, 1); VARP(autoupdateservers, 0, 1, 1); -void refreshservers() -{ +void refreshservers() { static int lastrefresh = 0; if(lastrefresh==totalmillis) return; - if(totalmillis - lastrefresh > 1000) - { + if(totalmillis - lastrefresh > 1000) { loopv(servers) servers[i]->reset(); lastreset = totalmillis; } lastrefresh = totalmillis; - checkresolver(); checkpings(); if(totalmillis - lastinfo >= servpingrate/(maxservpings ? max(1, (servers.length() + maxservpings - 1) / maxservpings) : 1)) pingservers(); @@ -562,26 +457,21 @@ void refreshservers() serverinfo *selectedserver = NULL; -const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax) -{ +const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax) { refreshservers(); - if(servers.empty()) - { + if(servers.empty()) { if(header) execute(header); return NULL; } serverinfo *sc = NULL; - for(int start = 0; start < servers.length();) - { + for(int start = 0; start < servers.length();) { if(start > 0) cgui->tab(); if(header) execute(header); int end = servers.length(); cgui->pushlist(); - loopi(10) - { + loopi(10) { if(!game::serverinfostartcolumn(cgui, i)) break; - for(int j = start; j < end; j++) - { + for(int j = start; j < end; j++) { if(!i && j+1 - start >= pagemin && (j+1 - start >= pagemax || cgui->shouldtab())) { end = j; break; } serverinfo &si = *servers[j]; const char *sdesc = si.sdesc; @@ -600,8 +490,7 @@ const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax) return "connectselected"; } -void connectselected() -{ +void connectselected() { if(!selectedserver) return; connectserv(selectedserver->name, selectedserver->port, selectedserver->password); selectedserver = NULL; @@ -609,8 +498,7 @@ void connectselected() COMMAND(connectselected, ""); -void clearservers(bool full = false) -{ +void clearservers(bool full = false) { resolverclear(); if(full) servers.deletecontents(); else loopvrev(servers) if(!servers[i]->keep) delete servers.remove(i); @@ -619,24 +507,19 @@ void clearservers(bool full = false) #define RETRIEVELIMIT 20000 -void retrieveservers(vector<char> &data) -{ +void retrieveservers(vector<char> &data) { ENetSocket sock = connectmaster(true); if(sock == ENET_SOCKET_NULL) return; - extern char *mastername; defformatstring(text, "retrieving servers from %s... (esc to abort)", mastername); renderprogress(0, text); - int starttime = SDL_GetTicks(), timeout = 0; const char *req = "list\n"; int reqlen = strlen(req); ENetBuffer buf; - while(reqlen > 0) - { + while(reqlen > 0) { enet_uint32 events = ENET_SOCKET_WAIT_SEND; - if(enet_socket_wait(sock, &events, 250) >= 0 && events) - { + if(enet_socket_wait(sock, &events, 250) >= 0 && events) { buf.data = (void *)req; buf.dataLength = reqlen; int sent = enet_socket_send(sock, NULL, &buf, 1); @@ -650,12 +533,9 @@ void retrieveservers(vector<char> &data) if(interceptkey(SDLK_ESCAPE)) timeout = RETRIEVELIMIT + 1; if(timeout > RETRIEVELIMIT) break; } - - if(reqlen <= 0) for(;;) - { + if(reqlen <= 0) for(;;) { enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE; - if(enet_socket_wait(sock, &events, 250) >= 0 && events) - { + if(enet_socket_wait(sock, &events, 250) >= 0 && events) { if(data.length() >= data.capacity()) data.reserve(4096); buf.data = data.getbuf() + data.length(); buf.dataLength = data.capacity() - data.length(); @@ -668,39 +548,31 @@ void retrieveservers(vector<char> &data) if(interceptkey(SDLK_ESCAPE)) timeout = RETRIEVELIMIT + 1; if(timeout > RETRIEVELIMIT) break; } - if(data.length()) data.add('\0'); enet_socket_destroy(sock); } bool updatedservers = false; -void updatefrommaster() -{ +void updatefrommaster() { vector<char> data; retrieveservers(data); if(data.empty()) conoutf(CON_ERROR, "master server not replying"); - else - { + else { clearservers(); char *line = data.getbuf(); - while(char *end = (char *)memchr(line, '\n', data.length() - (line - data.getbuf()))) - { + while(char *end = (char *)memchr(line, '\n', data.length() - (line - data.getbuf()))) { *end = '\0'; - const char *args = line; while(args < end && !iscubespace(*args)) args++; int cmdlen = args - line; while(args < end && iscubespace(*args)) args++; - - if(matchstring(line, cmdlen, "addserver")) - { + if(matchstring(line, cmdlen, "addserver")) { string ip; int port; if(sscanf(args, "%100s %d", ip, &port) == 2) addserver(ip, port); } else if(matchstring(line, cmdlen, "echo")) conoutf("\f1%s", args); - line = end + 1; } } @@ -708,8 +580,7 @@ void updatefrommaster() updatedservers = true; } -void initservers() -{ +void initservers() { selectedserver = NULL; if(autoupdateservers && !updatedservers) updatefrommaster(); } @@ -720,17 +591,14 @@ ICOMMAND(clearservers, "i", (int *full), clearservers(*full!=0)); COMMAND(updatefrommaster, ""); COMMAND(initservers, ""); -void writeservercfg() -{ +void writeservercfg() { if(!game::savedservers()) return; stream *f = openutf8file(path(game::savedservers(), true), "w"); if(!f) return; int kept = 0; - loopv(servers) - { + loopv(servers) { serverinfo *s = servers[i]; - if(s->keep) - { + if(s->keep) { if(!kept) f->printf("// servers that should never be cleared from the server list\n\n"); if(s->password) f->printf("keepserver %s %d %s\n", escapeid(s->name), s->port, escapestring(s->password)); else f->printf("keepserver %s %d\n", escapeid(s->name), s->port); @@ -739,11 +607,9 @@ void writeservercfg() } if(kept) f->printf("\n"); f->printf("// servers connected to are added here automatically\n\n"); - loopv(servers) - { + loopv(servers) { serverinfo *s = servers[i]; - if(!s->keep) - { + if(!s->keep) { if(s->password) f->printf("addserver %s %d %s\n", escapeid(s->name), s->port, escapestring(s->password)); else f->printf("addserver %s %d\n", escapeid(s->name), s->port); } |
