Clean up serverbrowser.mm
FossilOrigin-Name: 4d3e20926014cf9b4cbc48b2636feb3521c5514814d98799b63dec28aee39c42
This commit is contained in:
parent
90fc249052
commit
2fe9b5079f
4 changed files with 242 additions and 179 deletions
|
@ -63,7 +63,7 @@ snap(int sn, float f)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![stream isKindOfClass:[OFSeekableStream class]])
|
if (![stream isKindOfClass:OFSeekableStream.class])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
md2_header header;
|
md2_header header;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
{
|
{
|
||||||
MenuItem *otherItem;
|
MenuItem *otherItem;
|
||||||
|
|
||||||
if (![otherObject isKindOfClass:[MenuItem class]])
|
if (![otherObject isKindOfClass:MenuItem.class])
|
||||||
@throw [OFInvalidArgumentException exception];
|
@throw [OFInvalidArgumentException exception];
|
||||||
|
|
||||||
int x = (int)_text.longLongValue;
|
int x = (int)_text.longLongValue;
|
||||||
|
|
|
@ -28,7 +28,7 @@ alias(OFString *name, OFString *action)
|
||||||
|
|
||||||
identifiers[name] = alias;
|
identifiers[name] = alias;
|
||||||
} else {
|
} else {
|
||||||
if ([alias isKindOfClass:[Alias class]])
|
if ([alias isKindOfClass:Alias.class])
|
||||||
alias.action = action;
|
alias.action = action;
|
||||||
else
|
else
|
||||||
conoutf(
|
conoutf(
|
||||||
|
@ -79,7 +79,7 @@ getalias(OFString *name)
|
||||||
{
|
{
|
||||||
Alias *alias = identifiers[name];
|
Alias *alias = identifiers[name];
|
||||||
|
|
||||||
if ([alias isKindOfClass:[Alias class]])
|
if ([alias isKindOfClass:Alias.class])
|
||||||
return alias.action;
|
return alias.action;
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -170,10 +170,10 @@ lookup(OFString *n) // find value of ident referenced with $ in exp
|
||||||
__kindof Identifier *identifier =
|
__kindof Identifier *identifier =
|
||||||
identifiers[[n substringFromIndex:1]];
|
identifiers[[n substringFromIndex:1]];
|
||||||
|
|
||||||
if ([identifier isKindOfClass:[Variable class]]) {
|
if ([identifier isKindOfClass:Variable.class]) {
|
||||||
return [OFString
|
return [OFString
|
||||||
stringWithFormat:@"%d", *[identifier storage]];
|
stringWithFormat:@"%d", *[identifier storage]];
|
||||||
} else if ([identifier isKindOfClass:[Alias class]])
|
} else if ([identifier isKindOfClass:Alias.class])
|
||||||
return [identifier action];
|
return [identifier action];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,8 +238,7 @@ execute(OFString *string, bool isDown)
|
||||||
conoutf(@"unknown command: %@", c);
|
conoutf(@"unknown command: %@", c);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ([identifier
|
if ([identifier isKindOfClass:Command.class]) {
|
||||||
isKindOfClass:[Command class]]) {
|
|
||||||
// game defined commands use very
|
// game defined commands use very
|
||||||
// ad-hoc function signature, and just
|
// ad-hoc function signature, and just
|
||||||
// call it
|
// call it
|
||||||
|
@ -251,8 +250,7 @@ execute(OFString *string, bool isDown)
|
||||||
callWithArguments:arguments
|
callWithArguments:arguments
|
||||||
isDown:isDown];
|
isDown:isDown];
|
||||||
} else if ([identifier
|
} else if ([identifier
|
||||||
isKindOfClass:[Variable
|
isKindOfClass:Variable.class]) {
|
||||||
class]]) {
|
|
||||||
// game defined variables
|
// game defined variables
|
||||||
if (isDown) {
|
if (isDown) {
|
||||||
if (w[1].length == 0)
|
if (w[1].length == 0)
|
||||||
|
@ -265,7 +263,7 @@ execute(OFString *string, bool isDown)
|
||||||
0]];
|
0]];
|
||||||
}
|
}
|
||||||
} else if ([identifier
|
} else if ([identifier
|
||||||
isKindOfClass:[Alias class]]) {
|
isKindOfClass:Alias.class]) {
|
||||||
// alias, also used as functions and
|
// alias, also used as functions and
|
||||||
// (global) variables
|
// (global) variables
|
||||||
for (int i = 1; i < numargs; i++) {
|
for (int i = 1; i < numargs; i++) {
|
||||||
|
@ -392,7 +390,7 @@ writecfg()
|
||||||
|
|
||||||
[identifiers enumerateKeysAndObjectsUsingBlock:^(
|
[identifiers enumerateKeysAndObjectsUsingBlock:^(
|
||||||
OFString *name, __kindof Identifier *identifier, bool *stop) {
|
OFString *name, __kindof Identifier *identifier, bool *stop) {
|
||||||
if (![identifier isKindOfClass:[Variable class]] ||
|
if (![identifier isKindOfClass:Variable.class] ||
|
||||||
![identifier persisted])
|
![identifier persisted])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -406,7 +404,7 @@ writecfg()
|
||||||
|
|
||||||
[identifiers enumerateKeysAndObjectsUsingBlock:^(
|
[identifiers enumerateKeysAndObjectsUsingBlock:^(
|
||||||
OFString *name, __kindof Identifier *identifier, bool *stop) {
|
OFString *name, __kindof Identifier *identifier, bool *stop) {
|
||||||
if (![identifier isKindOfClass:[Alias class]] ||
|
if (![identifier isKindOfClass:Alias.class] ||
|
||||||
[identifier.name hasPrefix:@"nextmap_"])
|
[identifier.name hasPrefix:@"nextmap_"])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -4,174 +4,229 @@
|
||||||
#include "SDL_thread.h"
|
#include "SDL_thread.h"
|
||||||
#include "cube.h"
|
#include "cube.h"
|
||||||
|
|
||||||
struct resolverthread {
|
@interface ResolverThread: OFThread
|
||||||
SDL_Thread *thread;
|
|
||||||
char *query;
|
|
||||||
int starttime;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct resolverresult {
|
|
||||||
char *query;
|
|
||||||
ENetAddress address;
|
|
||||||
};
|
|
||||||
|
|
||||||
vector<resolverthread> resolverthreads;
|
|
||||||
vector<char *> resolverqueries;
|
|
||||||
vector<resolverresult> resolverresults;
|
|
||||||
SDL_mutex *resolvermutex;
|
|
||||||
SDL_sem *resolversem;
|
|
||||||
int resolverlimit = 1000;
|
|
||||||
|
|
||||||
int
|
|
||||||
resolverloop(void *data)
|
|
||||||
{
|
{
|
||||||
resolverthread *rt = (resolverthread *)data;
|
volatile bool _stop;
|
||||||
for (;;) {
|
}
|
||||||
|
|
||||||
|
@property (copy, nonatomic) OFString *query;
|
||||||
|
@property (nonatomic) int starttime;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ResolverResult: OFObject
|
||||||
|
@property (readonly, nonatomic) OFString *query;
|
||||||
|
@property (readonly, nonatomic) ENetAddress address;
|
||||||
|
|
||||||
|
- (instancetype)init OF_UNAVAILABLE;
|
||||||
|
- (instancetype)initWithQuery:(OFString *)query address:(ENetAddress)address;
|
||||||
|
@end
|
||||||
|
|
||||||
|
static OFMutableArray<ResolverThread *> *resolverthreads;
|
||||||
|
static OFMutableArray<OFString *> *resolverqueries;
|
||||||
|
static OFMutableArray<ResolverResult *> *resolverresults;
|
||||||
|
static SDL_sem *resolversem;
|
||||||
|
static int resolverlimit = 1000;
|
||||||
|
|
||||||
|
@implementation ResolverThread
|
||||||
|
- (id)main
|
||||||
|
{
|
||||||
|
while (!_stop) {
|
||||||
SDL_SemWait(resolversem);
|
SDL_SemWait(resolversem);
|
||||||
SDL_LockMutex(resolvermutex);
|
|
||||||
if (resolverqueries.empty()) {
|
@synchronized(ResolverThread.class) {
|
||||||
SDL_UnlockMutex(resolvermutex);
|
if (resolverqueries.count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
_query = resolverqueries.lastObject;
|
||||||
|
[resolverqueries
|
||||||
|
removeObjectAtIndex:resolverqueries.count - 1];
|
||||||
|
_starttime = lastmillis;
|
||||||
}
|
}
|
||||||
rt->query = resolverqueries.pop();
|
|
||||||
rt->starttime = lastmillis;
|
|
||||||
SDL_UnlockMutex(resolvermutex);
|
|
||||||
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
|
ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
|
||||||
enet_address_set_host(&address, rt->query);
|
enet_address_set_host(&address, _query.UTF8String);
|
||||||
SDL_LockMutex(resolvermutex);
|
|
||||||
resolverresult &rr = resolverresults.add();
|
@synchronized(ResolverThread.class) {
|
||||||
rr.query = rt->query;
|
[resolverresults addObject:[[ResolverResult alloc]
|
||||||
rr.address = address;
|
initWithQuery:_query
|
||||||
rt->query = NULL;
|
address:address]];
|
||||||
rt->starttime = 0;
|
|
||||||
SDL_UnlockMutex(resolvermutex);
|
_query = NULL;
|
||||||
|
_starttime = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stop
|
||||||
|
{
|
||||||
|
_stop = true;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ResolverResult
|
||||||
|
- (instancetype)initWithQuery:(OFString *)query address:(ENetAddress)address
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
_query = query;
|
||||||
|
_address = address;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
void
|
void
|
||||||
resolverinit(int threads, int limit)
|
resolverinit(int threads, int limit)
|
||||||
{
|
{
|
||||||
|
resolverthreads = [[OFMutableArray alloc] init];
|
||||||
|
resolverqueries = [[OFMutableArray alloc] init];
|
||||||
|
resolverresults = [[OFMutableArray alloc] init];
|
||||||
resolverlimit = limit;
|
resolverlimit = limit;
|
||||||
resolversem = SDL_CreateSemaphore(0);
|
resolversem = SDL_CreateSemaphore(0);
|
||||||
resolvermutex = SDL_CreateMutex();
|
|
||||||
|
|
||||||
while (threads > 0) {
|
while (threads > 0) {
|
||||||
resolverthread &rt = resolverthreads.add();
|
ResolverThread *rt = [[ResolverThread alloc] init];
|
||||||
rt.query = NULL;
|
rt.name = @"resolverthread";
|
||||||
rt.starttime = 0;
|
[resolverthreads addObject:rt];
|
||||||
rt.thread =
|
[rt start];
|
||||||
SDL_CreateThread(resolverloop, "resolverthread", &rt);
|
|
||||||
--threads;
|
--threads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
resolverstop(resolverthread &rt, bool restart)
|
resolverstop(size_t i, bool restart)
|
||||||
{
|
{
|
||||||
SDL_LockMutex(resolvermutex);
|
@synchronized(ResolverThread.class) {
|
||||||
// SDL_KillThread(rt.thread);
|
ResolverThread *rt = resolverthreads[i];
|
||||||
rt.query = NULL;
|
[rt stop];
|
||||||
rt.starttime = 0;
|
|
||||||
rt.thread = NULL;
|
if (restart) {
|
||||||
if (restart)
|
rt = [[ResolverThread alloc] init];
|
||||||
rt.thread =
|
rt.name = @"resolverthread";
|
||||||
SDL_CreateThread(resolverloop, "resolverthread", &rt);
|
|
||||||
SDL_UnlockMutex(resolvermutex);
|
resolverthreads[i] = rt;
|
||||||
|
|
||||||
|
[rt start];
|
||||||
|
} else
|
||||||
|
[resolverthreads removeObjectAtIndex:i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
resolverclear()
|
resolverclear()
|
||||||
{
|
{
|
||||||
SDL_LockMutex(resolvermutex);
|
@synchronized(ResolverThread.class) {
|
||||||
resolverqueries.setsize(0);
|
[resolverqueries removeAllObjects];
|
||||||
resolverresults.setsize(0);
|
[resolverresults removeAllObjects];
|
||||||
|
|
||||||
while (SDL_SemTryWait(resolversem) == 0)
|
while (SDL_SemTryWait(resolversem) == 0)
|
||||||
;
|
;
|
||||||
loopv(resolverthreads)
|
|
||||||
{
|
for (size_t i = 0; i < resolverthreads.count; i++)
|
||||||
resolverthread &rt = resolverthreads[i];
|
resolverstop(i, true);
|
||||||
resolverstop(rt, true);
|
|
||||||
}
|
}
|
||||||
SDL_UnlockMutex(resolvermutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
resolverquery(char *name)
|
resolverquery(OFString *name)
|
||||||
{
|
{
|
||||||
SDL_LockMutex(resolvermutex);
|
@synchronized(ResolverThread.class) {
|
||||||
resolverqueries.add(name);
|
[resolverqueries addObject:name];
|
||||||
SDL_SemPost(resolversem);
|
SDL_SemPost(resolversem);
|
||||||
SDL_UnlockMutex(resolvermutex);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
resolvercheck(char **name, ENetAddress *address)
|
resolvercheck(OFString **name, ENetAddress *address)
|
||||||
{
|
{
|
||||||
SDL_LockMutex(resolvermutex);
|
@synchronized(ResolverThread.class) {
|
||||||
if (!resolverresults.empty()) {
|
if (resolverresults.count > 0) {
|
||||||
resolverresult &rr = resolverresults.pop();
|
ResolverResult *rr = resolverresults.lastObject;
|
||||||
*name = rr.query;
|
*name = rr.query;
|
||||||
*address = rr.address;
|
*address = rr.address;
|
||||||
SDL_UnlockMutex(resolvermutex);
|
[resolverresults
|
||||||
|
removeObjectAtIndex:resolverresults.count - 1];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
loopv(resolverthreads)
|
|
||||||
{
|
for (size_t i = 0; i < resolverthreads.count; i++) {
|
||||||
resolverthread &rt = resolverthreads[i];
|
ResolverThread *rt = resolverthreads[i];
|
||||||
|
|
||||||
if (rt.query) {
|
if (rt.query) {
|
||||||
if (lastmillis - rt.starttime > resolverlimit) {
|
if (lastmillis - rt.starttime > resolverlimit) {
|
||||||
resolverstop(rt, true);
|
resolverstop(i, true);
|
||||||
*name = rt.query;
|
*name = rt.query;
|
||||||
SDL_UnlockMutex(resolvermutex);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_UnlockMutex(resolvermutex);
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct serverinfo {
|
@interface ServerInfo: OFObject <OFComparing>
|
||||||
string name;
|
@property (nonatomic) OFString *name;
|
||||||
string full;
|
@property (nonatomic) OFString *full;
|
||||||
string map;
|
@property (nonatomic) OFString *map;
|
||||||
string sdesc;
|
@property (nonatomic) OFString *sdesc;
|
||||||
int mode, numplayers, ping, protocol, minremain;
|
@property (nonatomic) int mode, numplayers, ping, protocol, minremain;
|
||||||
ENetAddress address;
|
@property (nonatomic) ENetAddress address;
|
||||||
};
|
@end
|
||||||
|
|
||||||
vector<serverinfo> servers;
|
@implementation ServerInfo
|
||||||
ENetSocket pingsock = ENET_SOCKET_NULL;
|
- (OFComparisonResult)compare:(id)otherObject
|
||||||
int lastinfo = 0;
|
{
|
||||||
|
if (![otherObject isKindOfClass:ServerInfo.class])
|
||||||
|
@throw [OFInvalidArgumentException exception];
|
||||||
|
|
||||||
|
if (_ping > [otherObject ping])
|
||||||
|
return OFOrderedDescending;
|
||||||
|
if (_ping < [otherObject ping])
|
||||||
|
return OFOrderedAscending;
|
||||||
|
|
||||||
|
return [_name compare:[otherObject name]];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static OFMutableArray<ServerInfo *> *servers;
|
||||||
|
static ENetSocket pingsock = ENET_SOCKET_NULL;
|
||||||
|
static int lastinfo = 0;
|
||||||
|
|
||||||
OFString *
|
OFString *
|
||||||
getservername(int n)
|
getservername(int n)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
return servers[n].name;
|
||||||
return @(servers[n].name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
addserver(OFString *servername_)
|
addserver(OFString *servername)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
const char *servername = servername_.UTF8String;
|
for (ServerInfo *si in servers)
|
||||||
loopv(servers) if (strcmp(servers[i].name, servername) ==
|
if ([si.name isEqual:servername])
|
||||||
0) return;
|
return;
|
||||||
serverinfo &si = servers.insert(0, serverinfo());
|
|
||||||
strcpy_s(si.name, servername);
|
ServerInfo *si = [[ServerInfo alloc] init];
|
||||||
si.full[0] = 0;
|
si.name = servername;
|
||||||
|
si.full = @"";
|
||||||
si.mode = 0;
|
si.mode = 0;
|
||||||
si.numplayers = 0;
|
si.numplayers = 0;
|
||||||
si.ping = 9999;
|
si.ping = 9999;
|
||||||
si.protocol = 0;
|
si.protocol = 0;
|
||||||
si.minremain = 0;
|
si.minremain = 0;
|
||||||
si.map[0] = 0;
|
si.map = @"";
|
||||||
si.sdesc[0] = 0;
|
si.sdesc = @"";
|
||||||
si.address.host = ENET_HOST_ANY;
|
ENetAddress address = { .host = ENET_HOST_ANY,
|
||||||
si.address.port = CUBE_SERVINFO_PORT;
|
.port = CUBE_SERVINFO_PORT };
|
||||||
|
si.address = address;
|
||||||
|
|
||||||
|
if (servers == nil)
|
||||||
|
servers = [[OFMutableArray alloc] init];
|
||||||
|
|
||||||
|
[servers addObject:si];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,32 +236,33 @@ pingservers()
|
||||||
ENetBuffer buf;
|
ENetBuffer buf;
|
||||||
uchar ping[MAXTRANS];
|
uchar ping[MAXTRANS];
|
||||||
uchar *p;
|
uchar *p;
|
||||||
loopv(servers)
|
|
||||||
{
|
for (ServerInfo *si in servers) {
|
||||||
serverinfo &si = servers[i];
|
|
||||||
if (si.address.host == ENET_HOST_ANY)
|
if (si.address.host == ENET_HOST_ANY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
p = ping;
|
p = ping;
|
||||||
putint(p, lastmillis);
|
putint(p, lastmillis);
|
||||||
buf.data = ping;
|
buf.data = ping;
|
||||||
buf.dataLength = p - ping;
|
buf.dataLength = p - ping;
|
||||||
enet_socket_send(pingsock, &si.address, &buf, 1);
|
ENetAddress address = si.address;
|
||||||
|
enet_socket_send(pingsock, &address, &buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastinfo = lastmillis;
|
lastinfo = lastmillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
checkresolver()
|
checkresolver()
|
||||||
{
|
{
|
||||||
char *name = NULL;
|
OFString *name = nil;
|
||||||
ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
|
ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
|
||||||
while (resolvercheck(&name, &addr)) {
|
while (resolvercheck(&name, &addr)) {
|
||||||
if (addr.host == ENET_HOST_ANY)
|
if (addr.host == ENET_HOST_ANY)
|
||||||
continue;
|
continue;
|
||||||
loopv(servers)
|
|
||||||
{
|
for (ServerInfo *si in servers) {
|
||||||
serverinfo &si = servers[i];
|
if ([name isEqual:si.name]) {
|
||||||
if (name == si.name) {
|
|
||||||
si.address = addr;
|
si.address = addr;
|
||||||
addr.host = ENET_HOST_ANY;
|
addr.host = ENET_HOST_ANY;
|
||||||
break;
|
break;
|
||||||
|
@ -225,12 +281,12 @@ checkpings()
|
||||||
char text[MAXTRANS];
|
char text[MAXTRANS];
|
||||||
buf.data = ping;
|
buf.data = ping;
|
||||||
buf.dataLength = sizeof(ping);
|
buf.dataLength = sizeof(ping);
|
||||||
|
|
||||||
while (enet_socket_wait(pingsock, &events, 0) >= 0 && events) {
|
while (enet_socket_wait(pingsock, &events, 0) >= 0 && events) {
|
||||||
if (enet_socket_receive(pingsock, &addr, &buf, 1) <= 0)
|
if (enet_socket_receive(pingsock, &addr, &buf, 1) <= 0)
|
||||||
return;
|
return;
|
||||||
loopv(servers)
|
|
||||||
{
|
for (ServerInfo *si in servers) {
|
||||||
serverinfo &si = servers[i];
|
|
||||||
if (addr.host == si.address.host) {
|
if (addr.host == si.address.host) {
|
||||||
p = ping;
|
p = ping;
|
||||||
si.ping = lastmillis - getint(p);
|
si.ping = lastmillis - getint(p);
|
||||||
|
@ -241,23 +297,19 @@ checkpings()
|
||||||
si.numplayers = getint(p);
|
si.numplayers = getint(p);
|
||||||
si.minremain = getint(p);
|
si.minremain = getint(p);
|
||||||
sgetstr();
|
sgetstr();
|
||||||
strcpy_s(si.map, text);
|
@autoreleasepool {
|
||||||
|
si.map = @(text);
|
||||||
|
}
|
||||||
sgetstr();
|
sgetstr();
|
||||||
strcpy_s(si.sdesc, text);
|
@autoreleasepool {
|
||||||
|
si.sdesc = @(text);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
sicompare(const serverinfo *a, const serverinfo *b)
|
|
||||||
{
|
|
||||||
return a->ping > b->ping
|
|
||||||
? 1
|
|
||||||
: (a->ping < b->ping ? -1 : strcmp(a->name, b->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
refreshservers()
|
refreshservers()
|
||||||
{
|
{
|
||||||
|
@ -265,37 +317,43 @@ refreshservers()
|
||||||
checkpings();
|
checkpings();
|
||||||
if (lastmillis - lastinfo >= 5000)
|
if (lastmillis - lastinfo >= 5000)
|
||||||
pingservers();
|
pingservers();
|
||||||
servers.sort((void *)sicompare);
|
[servers sort];
|
||||||
int maxmenu = 16;
|
int maxmenu = 16;
|
||||||
loopv(servers)
|
|
||||||
{
|
size_t i = 0;
|
||||||
serverinfo &si = servers[i];
|
for (ServerInfo *si in servers) {
|
||||||
if (si.address.host != ENET_HOST_ANY && si.ping != 9999) {
|
if (si.address.host != ENET_HOST_ANY && si.ping != 9999) {
|
||||||
if (si.protocol != PROTOCOL_VERSION)
|
if (si.protocol != PROTOCOL_VERSION)
|
||||||
sprintf_s(si.full)(
|
si.full = [[OFString alloc]
|
||||||
"%s [different cube protocol]", si.name);
|
initWithFormat:
|
||||||
else {
|
@"%@ [different cube protocol]",
|
||||||
|
si.name];
|
||||||
|
else
|
||||||
|
si.full = [[OFString alloc]
|
||||||
|
initWithFormat:@"%d\t%d\t%@, %@: %@ %@",
|
||||||
|
si.ping, si.numplayers,
|
||||||
|
si.map.length > 0 ? si.map : @"[unknown]",
|
||||||
|
modestr(si.mode), si.name, si.sdesc];
|
||||||
|
} else
|
||||||
|
si.full = [[OFString alloc]
|
||||||
|
initWithFormat:
|
||||||
|
(si.address.host != ENET_HOST_ANY
|
||||||
|
? @"%@ [waiting for server response]"
|
||||||
|
: @"%@ [unknown host]\t"),
|
||||||
|
si.name];
|
||||||
|
|
||||||
|
// cut off too long server descriptions
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
sprintf_s(si.full)(
|
if (si.full.length > 50)
|
||||||
"%d\t%d\t%s, %s: %s %s", si.ping,
|
si.full = [si.full substringToIndex:50];
|
||||||
si.numplayers,
|
|
||||||
si.map[0] ? si.map : "[unknown]",
|
|
||||||
modestr(si.mode).UTF8String,
|
|
||||||
si.name, si.sdesc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sprintf_s(si.full)(si.address.host != ENET_HOST_ANY
|
|
||||||
? "%s [waiting for server response]"
|
|
||||||
: "%s [unknown host]\t",
|
|
||||||
si.name);
|
|
||||||
}
|
|
||||||
si.full[50] = 0; // cut off too long server descriptions
|
|
||||||
@autoreleasepool {
|
|
||||||
menumanual(1, i, @(si.full));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menumanual(1, i, si.full);
|
||||||
|
|
||||||
if (!--maxmenu)
|
if (!--maxmenu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,8 +364,12 @@ servermenu()
|
||||||
pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, NULL);
|
pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, NULL);
|
||||||
resolverinit(1, 1000);
|
resolverinit(1, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolverclear();
|
resolverclear();
|
||||||
loopv(servers) resolverquery(servers[i].name);
|
|
||||||
|
for (ServerInfo *si in servers)
|
||||||
|
resolverquery(si.name);
|
||||||
|
|
||||||
refreshservers();
|
refreshservers();
|
||||||
menuset(1);
|
menuset(1);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +384,7 @@ updatefrommaster()
|
||||||
strstr((char *)reply, "<HTML>"))
|
strstr((char *)reply, "<HTML>"))
|
||||||
conoutf(@"master server not replying");
|
conoutf(@"master server not replying");
|
||||||
else {
|
else {
|
||||||
servers.setsize(0);
|
[servers removeAllObjects];
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
execute(@((char *)reply));
|
execute(@((char *)reply));
|
||||||
}
|
}
|
||||||
|
@ -341,6 +403,9 @@ writeservercfg()
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
fprintf(f, "// servers connected to are added here automatically\n\n");
|
fprintf(f, "// servers connected to are added here automatically\n\n");
|
||||||
loopvrev(servers) fprintf(f, "addserver %s\n", servers[i].name);
|
@autoreleasepool {
|
||||||
|
for (ServerInfo *si in servers.reversedArray)
|
||||||
|
fprintf(f, "addserver %s\n", si.name.UTF8String);
|
||||||
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue