Re: A small problem...and an upcoming update :D
Posted: Tue Dec 02, 2008 11:15 pm
Of course I remember it. I discovered it(for the most part, Andy did some awesome discovering, too).
(Long wall of text ahead. beware)
EJ's packet system worked in the following way. Every Actor that was in the game had a certain ID on the server. This includes every player, merchant, enemy, etc etc, all sharing the same pool of ID's. EJ would first send a packet to the client with all the information about your character(that is, as soon as you log on), which would hold everything about your character. Your ID, your rotation, your model, your weapon, your shield/helmet, etc etc etc. This packet would only be sent once, and the client would remember the ID of your player and always draw your player according to the model, etc, received from the packet.
The update packets would never again send what your character looks like again unless there is a change to it. The update packet would always send your X/Y position on the map, your buffs, your hp/mp(bar), the time of day, your animation, any spell effects on you, etc.. This was all done in 25 bytes(not including overhead) and was a tad bit wasteful, as most of these things did not have to be sent in every single packet, but that's ok. The good part of EJ's packet system came next. In those 25 bytes, it would also state the number of actors on the screen(not including you), and would then begin sending data about actors after the 25th byte. If it was the first time you've ever seen this specific actor(or, to avoid having to remember all that on the server, if this specific actor just walked on to your screen) the server would tell the client that actors ID number, and all the information needed about him, including model, animation, spell effect, x/y position, helmet/shield/weapon, eggs, etc. and the client would remember all of this under the specific ID number of the actor. In any update packet from this point on, the server would only need to tell the client that that specific actor is on screen(via ID number), and any information that has changed about that actor. This meant that each actor on the screen, when they would idle, move, attack, etc etc, would only take up 4 extra bytes in the update packet, provided that this isn't the first time that the client see's them.
So basically if ID 1, 2, and 3 are all on your screen(you are ID 0, lets say), the server would tell you in every update packet that ID's 1, 2, and 3 are on your screen. If ID 2 moved around, the packet would also tell you that ID 2 is on your screen and what their new X/Y position is. The client knew how many bytes in the packet were for each actor along with what each byte did because of a flag that was sent in after the ID. Based on this flag, information such as that ID's new X/Y position, that ID's animation, that ID's could be sent in minimal space and the client would know exactly what to do with it. I can explain it in further detail(showing exactly what the packet itself looked like) if you want.
EDIT: I forgot to say also that when ID 1, 2, and 3 each came onto your screen, the server also told you(the client) what they looked like, etc.. Only once, though.
Anyway I think i know how you can smooth movement out very well. From what you just said above, I gather that you don't necessarily update the client's characters X/Y position every packet, but instead only when they move, and you allow the client and the server to do movement calculations simultaneously, and perhaps sync it every few packets(or seconds). EJ does not have any movement calculations on the client side. He does not say to the client "move to this x/y at this speed" and allow the client to do that on it's own. He instead updates the x/y position of the clients character every maybe 100ms and has the client just smooth it out. So lets say for example the clients character is to move from 0,0 to 5,0, and the movement would take 1 second. Assuming EJ sends update packets every 200ms, it would look like this
C-----X-----X-----X-----X-----X
C is where the character is, X is the points where the server will tell the client where the character is every update packet. The client is in charge of smoothly moving the character from point C to the first X after the update is received(if it's every 200ms, the time it takes to get from C to X is pretty much negligable, as it sends about 10 packets for one movement.) and the server is in charge of calculating where the next point is and when he reaches that point. The server sends the next X to the client, and the client moves the character to that next point(this happens too fast to be even noticed, I mean, if theres 10 packets every second, which is what my XPS was set to, the intervals inbetween those X's were too small and xenimus made the movements smooth so that it was unnoticable). The exact same concept was used for when any other Actor was moving on the screen, and resulted in very very nice and smooth movement.
I have no clue how much any of that made sense, but lemme know what you think or if you wanna know anything more.
(Long wall of text ahead. beware)
EJ's packet system worked in the following way. Every Actor that was in the game had a certain ID on the server. This includes every player, merchant, enemy, etc etc, all sharing the same pool of ID's. EJ would first send a packet to the client with all the information about your character(that is, as soon as you log on), which would hold everything about your character. Your ID, your rotation, your model, your weapon, your shield/helmet, etc etc etc. This packet would only be sent once, and the client would remember the ID of your player and always draw your player according to the model, etc, received from the packet.
The update packets would never again send what your character looks like again unless there is a change to it. The update packet would always send your X/Y position on the map, your buffs, your hp/mp(bar), the time of day, your animation, any spell effects on you, etc.. This was all done in 25 bytes(not including overhead) and was a tad bit wasteful, as most of these things did not have to be sent in every single packet, but that's ok. The good part of EJ's packet system came next. In those 25 bytes, it would also state the number of actors on the screen(not including you), and would then begin sending data about actors after the 25th byte. If it was the first time you've ever seen this specific actor(or, to avoid having to remember all that on the server, if this specific actor just walked on to your screen) the server would tell the client that actors ID number, and all the information needed about him, including model, animation, spell effect, x/y position, helmet/shield/weapon, eggs, etc. and the client would remember all of this under the specific ID number of the actor. In any update packet from this point on, the server would only need to tell the client that that specific actor is on screen(via ID number), and any information that has changed about that actor. This meant that each actor on the screen, when they would idle, move, attack, etc etc, would only take up 4 extra bytes in the update packet, provided that this isn't the first time that the client see's them.
So basically if ID 1, 2, and 3 are all on your screen(you are ID 0, lets say), the server would tell you in every update packet that ID's 1, 2, and 3 are on your screen. If ID 2 moved around, the packet would also tell you that ID 2 is on your screen and what their new X/Y position is. The client knew how many bytes in the packet were for each actor along with what each byte did because of a flag that was sent in after the ID. Based on this flag, information such as that ID's new X/Y position, that ID's animation, that ID's could be sent in minimal space and the client would know exactly what to do with it. I can explain it in further detail(showing exactly what the packet itself looked like) if you want.
EDIT: I forgot to say also that when ID 1, 2, and 3 each came onto your screen, the server also told you(the client) what they looked like, etc.. Only once, though.
Anyway I think i know how you can smooth movement out very well. From what you just said above, I gather that you don't necessarily update the client's characters X/Y position every packet, but instead only when they move, and you allow the client and the server to do movement calculations simultaneously, and perhaps sync it every few packets(or seconds). EJ does not have any movement calculations on the client side. He does not say to the client "move to this x/y at this speed" and allow the client to do that on it's own. He instead updates the x/y position of the clients character every maybe 100ms and has the client just smooth it out. So lets say for example the clients character is to move from 0,0 to 5,0, and the movement would take 1 second. Assuming EJ sends update packets every 200ms, it would look like this
C-----X-----X-----X-----X-----X
C is where the character is, X is the points where the server will tell the client where the character is every update packet. The client is in charge of smoothly moving the character from point C to the first X after the update is received(if it's every 200ms, the time it takes to get from C to X is pretty much negligable, as it sends about 10 packets for one movement.) and the server is in charge of calculating where the next point is and when he reaches that point. The server sends the next X to the client, and the client moves the character to that next point(this happens too fast to be even noticed, I mean, if theres 10 packets every second, which is what my XPS was set to, the intervals inbetween those X's were too small and xenimus made the movements smooth so that it was unnoticable). The exact same concept was used for when any other Actor was moving on the screen, and resulted in very very nice and smooth movement.
I have no clue how much any of that made sense, but lemme know what you think or if you wanna know anything more.