Advertisement

help with storing Players (in memory) on MORPG server

Started by December 22, 2004 05:19 PM
33 comments, last by hplus0603 20 years, 1 month ago
Your Entity base class could have a "importance mask" with known values such as "needed on map entry" "needed frequently" "need to sync when leaving" etc. You would then visit all entities on map join, only sending entity data for entities that have the "needed on map entry" bit (attribute) set. I e, whether something gets updated when you join is really an attribute of that class -- it's not special to projectiles, but probably also used by, say, thunder bolts or puffs of smoke that someone teleporting leave behind (just to grab random possible examples). I e, it's meta-data about your entities.

Also, when I join a map, I'd suggest you send me all the data I need in one big gulp. Then you start queueing updates to me from the time you sent it to me, when things move. If there's lots of stuff, it'll take a little while to catch up, but this is much easier to write than trying to do it incrementally. I think EQ did it in the big gulp way -- which is why it took a while to zone into very full zones, no doubt.
enum Bool { True, False, FileNotFound };
thats actually a really good idea. however, for now, i dont even see a need for a "get all projectiles on this map" yet. so, for now, i'll just go with my number 2 suggestion. if i ever need projectiles on a given map for some reason, ill most likely go with that flag system where i can tell an Entity when his data is needed.

also, i already send all the data at once when a player enters a map. i didnt think there was any other way [smile]. did you mean something like stream in players who aren't in the immediate visability of the player who entered the map?

anyway, thanks a lot hplus. this thread is filled with lots of great information.
FTA, my 2D futuristic action MMORPG
Advertisement
hi again,

if you dont mind, i'd like your opinion on something. since im now storing everything by the network ID instead of PlayerID, what do you think is the best way to find a player given a PlayerID? this is going to happen frequently, like everytime i receive a packet from a player (since RakNet identifies connections with a PlayerID). storing things by PlayerID is no longer an option since most Entities are not remote clients connected. the simpliest method is to just have a lookup table which maps a network ID to a Player ID. however, doing this would mean 2 lookups when i want to get a Player with his PlayerID. the other choice is a boost multi index container. do you think that having 2 lookups is a serious speed issue? (i know we talked about something similar before, but the situation has changed). id rather spend time moving on with the code then learning to use (and getting use to using) the boost multi index containers, although they do seem like a nice solution.

last, another solution could be storing 2 versions of the "Players" list. one with the key of PlayerID, the other with network ID. however, i dont really like this option for some reason. what do you think?

[Edited by - graveyard filla on December 29, 2004 4:34:14 AM]
FTA, my 2D futuristic action MMORPG
If you have 30 players, and they send network packets 10 times per second, then that's 300 look-ups per second from network ID to player ID. That's un-likely to affect speed in any appreciable way, if look-up is O(1) (linear vector with index, or hash table), or O(lg N) (map or set).

Are the network Ids known to be small integers? If so, you could have just an array of the player ID for each network ID, and index into it for look-up. Hard to be faster than that. Or is the Player ID something you allocate? If so, couldn't you just say "player ID == network ID" ? Or does player ID persist between sessions?

In any case, I doubt the look-up will be slowing you down, if you do it once for each packet coming in.
enum Bool { True, False, FileNotFound };
Quote:
Original post by hplus0603
Are the network Ids known to be small integers? If so, you could have just an array of the player ID for each network ID, and index into it for look-up.


well, they could be. however, now that i have this "unified" ID system, i don't think so. that is, every Entity will have its own unique ID. Players, Projectiles, Enemies, will never have the same ID. is this a bad idea? because, with this system, ID's are a must to be unsigned longs i would think. i might be able to get away with unsigned shorts, because i dont think there will ever be more then 65k bullets / enemies / etc flying through the air. however, to be safe i'll stick with an unsigned long. before now, i have been using a single byte to ID players because i never expect to have more then 256 players online at once. is this 3 extra bytes in (probably most) packets going to hurt me? maybe i could make a system where i never take past the value 255 from the ID pool (when assigning a player an ID), and then i could still send bytes as ID's for players?

Quote:

Or is the Player ID something you allocate? If so, couldn't you just say "player ID == network ID" ? Or does player ID persist between sessions?


the problem is that a PlayerID is 6 bytes (IP + port combo). thats the reason why i made my own network ID system, because i didnt want to send 6 bytes around in each packet to ID a player. also, with the new system, enemies and bullets dont have an IP and port, so i wouldnt be able to stuff them all into the same "ID pool" if i did that.

last, while 30 players is my goal, im really aiming to have the game scale as well as possible. however, i do think that 10 packets per second is being generous. i don't send any packets at a constant rate (yet[smile]) (in fact, so far ALL of my messages are sent reliable and ordered). as the game is now, if all the players stood completely still and no one moves or shot anybody, there would be 0 network traffic (except maybe minor things, like pinging and such). the way i handle movement is with the mouse, so i only have to send a packet each time they click to move somewhere else.

thanks again.

[Edited by - graveyard filla on December 29, 2004 3:57:46 PM]
FTA, my 2D futuristic action MMORPG
Quote:
is this 3 extra bytes in (probably most) packets going to hurt me


Now you're being lazy :-) Show us you can use a pocket calculator.
enum Bool { True, False, FileNotFound };
Advertisement
im a little confused when we talk about bandwith usage. i did some googling and im pretty sure that when referring to bandwith usage, we refer to kiloBITS per second, correct? also, when doing these tests, we only count the upstream speed of the server, correct? not download? also, im even more confused as to what a kilobit is, because it seems it can be either 1000 bits or 1024 bits.

ok, so i tested out my connection speed at this site:
http://www.dslreports.com/stest?loc=2

i ran the test twice and averaged the results, which gives me around an 18,000 byte per second upload rate, or around 145,000 bits per second.

now, lets say that the fastest fireing gun in the game has a delay of 100 MS. currently the fastest gun in the game is the SMG, which is 300 MS delay.

lets also say that i put in a delay so that a player cannot click to move unless 100 MS have passed since he has last clicked.

now, the overhead to a RakNet packet is about 46 bytes for sending RELIABLE, and also 46 bytes for sending UNRELIABLE. im not sure how much it is to send a packet RELIABLE, ORDERED though, which is how im sending all of my packets. so, im going to guess and say that its 50 bytes. the "im shooting" packet is 4 bytes position "where im standing", 4 bytes "where i shot". the server should know what type of gun i have. so we will say that this packet is 60 bytes. the movement packet is pretty much the same, 4 bytes where im standing, 4 bytes where i clicked (however this may change to 8 bytes as ive run into a problem, but thats for another day [smile]). so, we will estimate this to 60 bytes as well.

so, if a player is clicking to move as fast as he can, and holding down on the "fire" button and he is using the fastest gun, he is sending 120 x 10 = 1200 bytes per second.

since my connection can hold 18,000 bytes a second, this only leaves me with handling 15 players at once. and this doesnt even include NPC's!!!

ok, so this is a serious concern.

lets say i cap the fastest gun to be 333 MS. this gives me 3 x 60 + 10 x 60 = 768 bytes per second. this leaves me with around 23 players, still no NPC's..

this math also does not factor in the "hit / miss and damage done" packet that the server sends each time a bullet hits a target, so this number of players just gets even lower from that. it also doesnt take into account the "ack" packet which is 3 bytes, (and also doesnt account for packet loss..).

im starting to think im going to have to make the game much less "actiony" if i want to achieve my goal of 30 players. i just don't understand though.. how do they handle combat in the big MMORPGs? im guessing they send "this is the ID of who i want to hit". the server then does a calculation and sends the result to the client.

ok, lets say i did my game like that. i took out the "free aiming" projectiles and made it so bullets "heat seaked" to their target. then, i only send "this is the ID of the person im shooting at". the packet goes from being 60 bytes to around 50 bytes.

going back to the original 100 MS delay, this is 50 x 100 + 60 x 100, giving me 1100 bytes per second. this gives me 16 max players (with no NPCs). this system only gives me a single extra max player!

so, how DO these MMORPGs handle combat then? im starting to think i either really screwed up bad with my math, or i need to thouroughly re-design the combat system to my game. pity too, because i finnally just got it working [sad].

thanks again.

EDIT: maybe i am interpreting the test wrong? if anyone would be so kind as to go to the b/w test page , scroll to the bottom of that page, and click "start", and sit back and watch the results, i would be greatly appreciated. on my end, the red bar says "142 up" for upload.

[Edited by - graveyard filla on December 30, 2004 5:32:21 PM]
FTA, my 2D futuristic action MMORPG
Your tests seem reasonable.

Typically, the "kilo" used in "kilobits" is 1000, whereas in "kilobytes" and "megabytes" of RAM, it's 1024. Meanwhile, for hard disks, "gigabytes" are based on 1000 again. All kinds of fun, isn't it?

It gets worse. The bits of the rated link aren't all used for your data. There might be framing overhead, and packet overhead, and link loss overhead. This overhead varies by what technology is used. On old-school dial-up modems (1200 bps, say) there was a single start and stop bit for each byte, so each byte was actually 10 bits!

Now, it gets better, too. You should not send a "move" packet and a "fire" packet as separate packets. You should, absolutely, batch all messages you want to send in a 100 ms interval, and put them all in a single, physical network packet. RAK-net may do this for you, I don't know. This means that the IP packet overhead (20 bytes) and the UDP packet overhead (8 bytes) and whatever overhead RAK gives you (call it 20 bytes?) gets amortized on many more commands, and thus is less of a problem.

Of course, both connection directions matter. However, in reality, the outgoing bandwidth for a server is more than the incoming, because every player only sends commands for one player (themselves) but receive commands for N players (all visible). Even worse: if you host this on an at-home DSL or cable connection, the upload speed is usually much slower than the download speed; i e DSL is often 1.5 Mbit download, and 128 kbit upload. Thus, the higher bandwidth (NxN players of traffic) has to go through the slower connection (128 kbit in this example). Those co-located hosting solutions are starting to look quite good right about now... but pricey.

Assuming 700 bits total packet size for the unified updates, and 10 players online, each doing 10 packets per second, you still need 70 kilobit per player to forward all of the packets, if they're all on the same map, seeing each other with full resolution. The n-squared really gets you. But, again, it gets better:

You can, of course, play statistics. The more players you have, the more "average" your load curve will look like. Most players won't be moving quickly, or fighting, at any one instant. If you have on-demand packets (rather than a continual stream at 10 per second) then it's not uncommon to see average packet rate be something like 20%, or even 10%, of peak packet rate. I suggest you ship your game, start hosting it, and look into better networking when and if you get too many players.

You can also make it so that you scale the maximum command rate back if there are more players on the server. Tell clients what the command rate is every so often, and don't accept more than that. That way, loaded times will mean laggier play, which users will understand (although complain loudly about). I think that would be a great problem for you to have -- at that point, you can start charging $10/month for premium accounts, and start looking into a co-lo solution (they start at around $100/month).

That broadbandreports measurement page actually deducts for IP packet overhead already, by the way -- although it likely uses 1500 byte packets, to amortize this overhead. FWIW, my DSL gets 1289 kbps down and 324 up (without the overhead).

The way that we get lots of players and vehicles into our simulated world (which is action-ey), is to send user input, rather than state. I e, just mouse deltas and key masks. We run the simulation in sync on all the machines. (There correction detection and time shifting and other stuff going on, too -- see other thread). Of course, we co-locate with a top-tier data center, so we don't need to worry so much about the bandwidth (as long as we don't crowd out the 28 kbps that a typical modem gets for a user).

Also, most MMORPGs are not as action-ey, and they will degrade the view you get of players in the distance. Typical is to only send frequent updates for people near you, and in your party, and only send infrequent updates for people in the distance. This has the draw-back that you may not actually see the bullet object that hits you, if someone in the distance (behind a lot of other players) snipes at you. But that's the RPG world for you -- as we've said before, your system sounds a little more like an FPS, and thus you get FPS-style limitations. Modern FPS-es claim they need up to 64 kilobit of upstream for each player in a game -- so your cable would only do 3 players on a Battlefield 1942 map. In that light, you're already ahead!
enum Bool { True, False, FileNotFound };
hey hplus,

so the overhead for UDP is 28 bytes? for some reason i thought it was 42. anyway, ive taken some of what you said and figure i could get away with not sending projectile / movement info unless they are within a certain range. however maps are going to be kind of small anyway so im not sure how much this will help. i also have a few other tricks like setting the fastest gun to fire at 500 ms. then for something like a SMG, i would fire 3 bullets in a burst each time they pressed the fire button. i guess it wouldn't be too bad to make bullets heat-seek to save on bandwith, but from my calculations this will only gain me maybe one or two extra max players. this doesnt seem worth it at all. another thing is magic. i plan on putting a magic system as a way of combat in the game. this can definetly be "heat seaking". so for that, i just send "im casting this spell on character with ID X".

about capping the "command rate", im not sure how to do this. in my game, when a player clicks to move, he immediately starts moving to where he clicked, and the server and other clients play "catch up". the client does not wait for the server to confirm this. (the server DOES confirm this though, and if the client is in an illegal range, he will do something about it (havent coded that part yet [smile])). if someone hacked their position, it wouldnt matter since the server has the "true" position of the client. the same thing with bullets, if he hacked to fire a million bullets, it would only show up on his screen and the server would never fire the bullets on his simulation since the server checks to make sure the time since the last shot is within the time of the reload rate of the gun.

anyway, i guess i could add a confirmation to this system (e.g. the player doesnt move and his bullet doesnt fire untill he gets the "ok" packet from the server). however this would make everything delayed, and it would also add to the bandwith usage. is it nessasary to do though? maybe im misunderstanding you about the whole command rate thing.

thanks again.

[Edited by - graveyard filla on December 31, 2004 1:48:28 AM]
FTA, my 2D futuristic action MMORPG
Yes, an IP header is 20 bytes and an UDP header is 8 bytes; here's one reference.

By capping the command rate, you would delay sending a command if the player has already sent a command quite recently. If the player issues a second command that overrides the first command, before the first command has been sent, you simply only send the second command to the server.

So, player does:

0: click 3,4
starts moving towards 3,4
send packet that player is moving towards 3,4
200: click 7,8
starts moving towards 7,8
400: click 2,5
starts moving towards 2,5
500:
send packet that player is moving towards 2,5

Note that this will lead to a slight discrepancy between player client, and everybody else in the case of very quick movement changes. You could possibly avoid this by enforcing the minimum command spacing in the UI -- the player simply doesn't start walking in a new direction until the packet is actually SENT, using the above schedule. You don't need to wait for ack.

You will note that most RTS games usually delay an interval before starting on actions you give the units -- the units will first spend half a second saying "Yes Sir!". Guess why this is? :-)
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement