Tracking users in a virtual world

Started by
11 comments, last by hplus0603 14 years, 1 month ago
I have a virtual world (MMO environment) in which I require users to login with a username and password into the world. Currently, when a user connects and login I store their socket/connection info in a dictionary; the socket being the key and the account object being the value. However, I later find the need to when for example: "A sends a message to B" "Server reckgnonzies this; and B is identified as Bob in the packet" "Server now needs to know what socket Bob's is" How can I figure this out without using a very slow for loop?
Advertisement
Quote:login with a username and password


This means that there is some store, a database perchance, which has a list of all user/password pairs.

Assign each of these a unique number (ID). If using a database, primary or any auto increment key will do.

Quote:I store their socket/connection info in a dictionary

Instead, store their ID. Then have the following structures:
- Player, which holds socket, ID and anything else
- ID->Player dictionary
Quote:Original post by Antheus
Quote:login with a username and password


This means that there is some store, a database perchance, which has a list of all user/password pairs.

Assign each of these a unique number (ID). If using a database, primary or any auto increment key will do.

Quote:I store their socket/connection info in a dictionary

Instead, store their ID. Then have the following structures:
- Player, which holds socket, ID and anything else
- ID->Player dictionary


Wouldn't the username already function as a unique identifier?
You probably want a sort of connection/player object that stores both the socket and the username.
When a socket receives data it can easily grab the username in the same object.

Also if someone for example, send a tell to "username", you can have a dictionary with every connection/player object using the username as key.
Then lookup the username in the dictionary to fetch the right connection/player object which contains the socket.
If the problem is "how do I go from socket (int) to user information" then a std::hash_map is probably the right answer in C++, and a similar container (Dictionary<>, dict(), etc) in other languages. This works for TCP.

For UDP, you will have to map remote IP address/port (as seen in recvfrom()) instead, but it's the same idea.

Trusting a user ID sent by the user on the wire is not a good idea, because the user may lie (hack their client).
enum Bool { True, False, FileNotFound };
Quote:Original post by hplus0603
If the problem is "how do I go from socket (int) to user information" then a std::hash_map is probably the right answer in C++, and a similar container (Dictionary<>, dict(), etc) in other languages.

Trusting a user ID sent by the user on the wire is not a good idea, because the user may lie (hack their client).

You don't have to trust the user to get the ID from him, you just need to verify it. I'd use a simple std::vector and the user sent ID for indexing, then for validation I'd compare the stored IP address/port with the sender's.
Quote:You don't have to trust the user to get the ID from him, you just need to verify it.


Right, but what have you won? Using a vector instead of a hash_map? And, at that point, you have to write more complex code, because you have to also test that the ID is not out of range for the vector. Plus you have to manage the vector integer name space. Neither of which is hard, but all of which has more possibilities for bugs than just std::hash_map::insert()/erase(). (Or, if your stdlib is older, std::map)

enum Bool { True, False, FileNotFound };
The issue indeed is connection to user info. I'm pairing the end point (UDP) to the dictionary (C#) or hash table in many other languages. The issue here is, if my packet information refers to another user. How would I reference this user easily? Such as sending a 'private' message?
Quote:Original post by hplus0603
Quote:You don't have to trust the user to get the ID from him, you just need to verify it.


Right, but what have you won? Using a vector instead of a hash_map?

I just like the lightweight, simple and fast solutoins. Why hash_map if you get away with a simple vector?

Quote:
And, at that point, you have to write more complex code, because you have to also test that the ID is not out of range for the vector. Plus you have to manage the vector integer name space.

you just deriver from std::vector and overload the operator[] where you index by size(), not that many bugs you could cause. sure, those are some more lines of code compared to using hash_map, but the complexity of the overall code is less.
it's like a hashmap without the need of hash and collision-resolving (just the bounds checking).

Quote: Neither of which is hard, but all of which has more possibilities for bugs than just std::hash_map::insert()/erase(). (Or, if your stdlib is older, std::map)

sure, you could use those, you could always use those, but I guess nobody does if he gets away with less complex solutions (although the complexity is hidden under the interface of the stl).
I guess I don't see the complexity of the map based approach?

Vector:

0) receive user packet with IP
1) read id from the user packet
2) check whether ID is in range for vector, if not -> bad id
3) read user information from vector
4) compare IP address in user information with IP from user packet, if different -> bad id

Hash map:

0) receive user packet with IP
1) retrieve user information from hash map using IP, if not there -> bad id

Of course, this is such a small bit of data that it doesn't really matter, and won't show up in a profiling tool ever. Use whatever you're most comfortable with :-)
enum Bool { True, False, FileNotFound };
I'm using a hash map.. it seems fast & efficient.. and in profiling I've found no faster method. My question above still remains.

This topic is closed to new replies.

Advertisement