24 Mar, 2009, Scandum wrote in the 181st comment:
Votes: 0
I went ahead and made some modifications to the protocol:

1. I removed "Educational" from the genre list since it's not a genre, it's still listed in the gameplay list.

2. I added "None" as an option to GENRE, SUBGENRE, GAMEPLAY, and GAMESYSTEM. Mainly for social and educational muds.

3. In the case a World variable's value can't be calculated "-1" should be returned.

4. Now mentions specifically that if no Intermud protocol is supported an empty string should be returned.

I think that settles the most important issues that have been brought forth.
24 Mar, 2009, Scandum wrote in the 182nd comment:
Votes: 0
Wrote some example Merc code for unique player counting:
int unique_host( DESCRIPTOR_DATA *d )
{
DESCRIPTOR_DATA *dtemp;

for (dtemp = mud->f_desc ; dtemp ; dtemp = dtemp->next)
{
if (d == dtemp)
{
return 1;
}

if (!strcmp(d->host, dtemp->host))
{
return 0;
}
}
return 0;
}

/*
Give the number of players counting multiple characters from the same
IP as one.
*/

int unique_players(void)
{
DESCRIPTOR_DATA *dtemp;
int cnt = 0;

for (dtemp = mud->f_desc ; dtemp ; dtemp = dtemp->next)
{
if (dtemp->character)
{
cnt += unique_host(dtemp);
}
}
return cnt;
}


Not sure if the above could be improved or optimized.

The fastest way is probably to sort new sockets with strcmp by IP. Then you could run through the socket list once, jumping over blocks of identical IPs counting them as one player.
24 Mar, 2009, Scandum wrote in the 183rd comment:
Votes: 0
Some more example code, this time of a sorted socket list:

// Utility macro

#define INSERT_LEFT(link, rght, first, next, prev) \
{ \
(link)->prev = (rght)->prev; \
(rght)->prev = (link); \
(link)->next = (rght); \
\
if ((link)->prev) \
{ \
(link)->prev->next = (link); \
} \
else \
{ \
(first) = (link); \
} \
}

// Inside the new_descriptor function in comm.c:

for (dtmp = mud->f_desc ; dtmp ; dtmp = dtmp->next)
{
if (strcmp(dtmp->host, dnew->host) < 0)
{
INSERT_LEFT(dnew, dtmp, mud->f_desc, next, prev);
break;
}
}

if (dtmp == NULL)
{
LINK(dnew, mud->f_desc, mud->l_desc, next, prev);
}

// Actual player counting

int unique_players(void)
{
DESCRIPTOR_DATA *desc;
int cnt;

for (desc = mud->f_desc ; desc ; desc = desc->next)
{
if (desc->next && !strcmp(desc->host, desc->next->host))
{
continue;
}
cnt++;
}
return cnt;
}
24 Mar, 2009, David Haley wrote in the 184th comment:
Votes: 0
Scandum, has anybody other than yourself spoken in favor of using IP addresses? At this point I'm just curious.
24 Mar, 2009, elanthis wrote in the 185th comment:
Votes: 0
Might want to refine that code a bit before using it on any MUD with a large playerbase.

Seriously, calculate unique IPs at connect/disconnect time at the very least. Keep a list (or tree, perferably) of IPs updated when a connection is made or closed. That's useful in a number of other ways, too, such as allowing the MUD admin to set per-IP limits, get a list of all players using the same IP at any time, etc. Plus it wouldn't be an O(N^2) algorithm.
24 Mar, 2009, David Haley wrote in the 186th comment:
Votes: 0
Indeed, this could be made a lot better. In fact, without being any more clever than just using a simple data structure like a set to uniquefy the list would bring it down to O(n log n) instead of O(n^2) without doing the smarter things that Elanthis talked about.
24 Mar, 2009, elanthis wrote in the 187th comment:
Votes: 0
Implementing a simple set in C is really no easier than implementing one that can track the connections, too. Might as well go for the gold.
24 Mar, 2009, Scandum wrote in the 188th comment:
Votes: 0
The second snippet is O(N) which will suffice for most muds. It'll need to be fixed to check logged in status though.
24 Mar, 2009, elanthis wrote in the 189th comment:
Votes: 0
Doh, so it is. I totally missed that whole post somehow. Sorry.
24 Mar, 2009, David Haley wrote in the 190th comment:
Votes: 0
elanthis said:
Implementing a simple set in C is really no easier than implementing one that can track the connections, too

Indeed. It's easy to forget that when you spend most of your time in C++ or dynamic languages… sigh!
24 Mar, 2009, Scandum wrote in the 191st comment:
Votes: 0
Alright, O(N) version with merc22 compatible connection status checking.

// Utility macro

#define INSERT_LEFT(link, rght, first, next, prev) \
{ \
(link)->prev = (rght)->prev; \
(rght)->prev = (link); \
(link)->next = (rght); \
\
if ((link)->prev) \
{ \
(link)->prev->next = (link); \
} \
else \
{ \
(first) = (link); \
} \
}

// Inside the new_descriptor function in comm.c:

for (dtmp = mud->f_desc ; dtmp ; dtmp = dtmp->next)
{
if (strcmp(dtmp->host, dnew->host) < 0)
{
INSERT_LEFT(dnew, dtmp, mud->f_desc, next, prev);
break;
}
}

if (dtmp == NULL)
{
LINK(dnew, mud->f_desc, mud->l_desc, next, prev);
}

// The actual player counting

int unique_players(void)
{
DESCRIPTOR_DATA *desc;
int cnt = 0;

for (desc = mud->f_desc ; desc ; desc = desc->next)
{
if (desc->connected < CON_PLAYING)
{
continue;
}
cnt++;

while (desc->next && !strcmp(desc->host, desc->next->host))
{
desc = desc->next;
}
}
return cnt;
}
24 Mar, 2009, David Haley wrote in the 192nd comment:
Votes: 0
Isn't the IP address also stored in integral form? No need to do a full string comparison for the sorting and unique counting.
24 Mar, 2009, Scandum wrote in the 193rd comment:
Votes: 0
Only stored as a string in merc22 as far as I can tell.

strcmp() bails out at the first non matching character, so it's pretty fast.
24 Mar, 2009, elanthis wrote in the 194th comment:
Votes: 0
IPv4 addresses can be stored as a simple 32-bit integer, but if you plan on supporting IPv6, you essentially end up needing to just use memcmp anyhow. (There isn't a standard "sort-compare addresses" function that I know of, anyway – would be ecstatic if somebody proved me wrong.)

On a purely theoretical security-admin note… is this list also used for WHO listings and the like? If so, using an IP-sorted list could be used as a potential attack vector for guessing other users' IP addresses. (This is the kind of crap I used to get paid to think about. I hated that job… but at least my systems did have a flawless security record even after 7 years of testing. Why a municipal government agency was so interested in paying for security professionals and constant testing is beyond me… I must've been a cog in the wheel of government cover-up conspiracy! … or more likely the elected officials were just idiots willing to shell out taxpayer money due to paranoia over things they didn't even really understand. But conspiracy is so much more fun!)
24 Mar, 2009, David Haley wrote in the 195th comment:
Votes: 0
Well, it wasn't clear to me that we'd actually all agreed that we wanted to even think about IP addresses in the first place… And yes, the concern that IP addresses could be used to find alts was brought up, even if you reported players vs. unique players, without sorting a who list.
24 Mar, 2009, Scandum wrote in the 196th comment:
Votes: 0
WHO listings are sorted by level on merc, and it should be doable to sort equal level characters by login time if alt spotting is a big concern.

David Haley said:
Well, it wasn't clear to me that we'd actually all agreed that we wanted to even think about IP addresses in the first place…

It's hard to tell because I don't think many people will jump in to defend my position while I'm actively defending it. Keep in mind that Crat got zero criticism on his text based concept until I dropped my objections.

From what I've seen with the voting on TMS, Muds can and will go to extremes. Many muds will likely encourage players to idle multiple characters (or blatantly multi-log 50 characters) just to get that 50 or 100+ player count.
24 Mar, 2009, David Haley wrote in the 197th comment:
Votes: 0
Well, not to beat a dead horse, but I'm seeing a lot of people defending certain positions, and you're more or less the only person defending the opposite position. Maybe there is a silent majority out there that completely agrees with you, but, well, we can't design a protocol around what people don't say.

Anyhow, the system can be gamed no matter what you do. The MUD could report a random number of players between 100 and 200. The MUD could ask a bunch of people to run bots from their machines to get unique IP addresses. For instance, when I was at school, I had access to tens upon tens if not hundreds of cluster machines I could have run telnet bots off of.

This problem is basically social, not technical. Nothing you do will ever prevent MUDs from simply reporting the wrong number.
24 Mar, 2009, KaVir wrote in the 198th comment:
Votes: 0
Scandum said:
From what I've seen with the voting on TMS, Muds can and will go to extremes. Many muds will likely encourage players to idle multiple characters (or blatantly multi-log 50 characters) just to get that 50 or 100+ player count.


I wouldn't say "many", but "some". And how many of those muds do you think will accurately report the number of unique connections they've got?
24 Mar, 2009, Cratylus wrote in the 199th comment:
Votes: 0
Hmm…it occurs to me….
24 Mar, 2009, Cratylus wrote in the 200th comment:
Votes: 0
180.0/292