[Tutorial] Understanding the SA-MP sync
#1

Tambiйn estб disponible en espaсol.
Muchas gracias a MrDeath.

hey,
I've noticed a lot of bugs and problems people have with scripting is caused by lack of knowledge in this area. After reading this, I hope I'm going to have cleared a few things up.

Topics:
  • The script runs on a single thread
  • Player updates
  • Player-affecting server functions
  • Key sync
  • Packet loss (advanced)
  • Packet misorder (advanced)
The script runs on a single thread
This might sound complicated for some people, allow me to explain: All the actions the server does are always after waiting for the latest action to finish.
For example, if you have code that takes 3 seconds to run in OnPlayerConnect (such as the old GeoIP plugin), then the server will wait for that code to finish before doing anything else.

Things that might take a lot of time:
  • Dealing with large strings
  • Looping through players, doing several things
  • Reading and writing a lot to files
The server will have to wait for all these to finish; therefore, try and keep your code as fast as possible.

Benefits
The benefits of having the server run on a single thread (in my opinion) is you have full control over the flow of information to the server; you will always process every action in the server as it comes in. If the server would be multi-threaded, then player information could get updated while your code is running. I don't think that would be any better, honestly.

Player updates
When any of these things changes for the client, the client will send information to the server and the server will call OnPlayerUpdate:
  • Health/armour
  • Vehicle health, body damage, color, mods
  • Death
  • Velocity
  • Position/rotation
  • Animation
  • Pressed keys
  • Weapon/ammo
  • Camera position (only when aiming/shooting; if not, it's sent about twice a second)
You can, with scripting, detect almost exactly what has changes in OnPlayerUpdate.

What happens when a player moves the camera, starts moving, and presses the action key after that?
1. If the player was aiming/shooting, the camera angle and facing angle will be sent in the same update and OnPlayerUpdate will be called. If the player wasn't aiming/shooting, OnPlayerUpdate might or might not be called at this moment (probably not).
2. OnPlayerUpdate is called for the new key state; OnPlayerKeyStateChange is not called because the key is left/right or up/down. The player's animation will also be updated before OnPlayerUpdate is called, if it was changed instantly.

Note: I'm not 100% sure if the animation will be in the same update as the keys, I can't test that at the moment.

The ID returned from GetPlayerAnimationIndex changes as fast as a new animation is initialized for the client. For example, when you start running the animation will be changed the moment you press a key to move (even though you might not notice it instantly).

What happens when I return 0 in OnPlayerUpdate?
OnPlayerUpdate is called before the server sends the new information to the other players. If you return 0 in any OnPlayerUpdate call (filterscripts or gamemode), the update will not be sent to other clients.

Example of good usage
This will stop the player from shooting or moving/warping back when froze. No more "ghost shooting" or whatever you might call it!
pawn Code:
new
    bool:g_IsPlayerFroze[ MAX_PLAYERS ] // Store a variable for each player defining wether they have been froze or not.
;

public OnPlayerSpawn( playerid )
{
    g_IsPlayerFroze[ playerid ] = false; // The player always gets unfroze upon spawning
}

public OnPlayerUpdate( playerid )
{
    static // I use static variables here because they won't have to get initialized each time the function is executed.
        s_Keys,
        s_UpDown,
        s_LeftRight
    ;
   
    GetPlayerKeys( playerid, s_Keys, s_UpDown, s_LeftRight ); // Get the keys currently being pressed
   
    if ( g_IsPlayerFroze[ playerid ] && ( s_Keys || s_UpDown || s_LeftRight ) ) // If any keys are pressed, don't sync the update
        return 0;
   
    return 1;
}

// Use the following 2 functions to freeze/unfreeze players

stock FreezePlayer( playerid )
{
    g_IsPlayerFroze[ playerid ] = true; // The server now treats the player as a froze player
   
    TogglePlayerControllable( playerid, false );
}

stock UnfreezePlayer( playerid )
{
    g_IsPlayerFroze[ playerid ] = false; // Opposite of the comment above!
   
    TogglePlayerControllable( playerid, true );
}
Example of bad usage
Below, return 1 is not in the function so every single player update won't be synced.
pawn Code:
public OnPlayerUpdate( playerid )
{
    if ( GetPlayerWeapon( playerid ) == WEAPON_MINIGUN )
        Ban( playerid );
}
Better code:
pawn Code:
public OnPlayerUpdate( playerid )
{
    if ( GetPlayerWeapon( playerid ) == WEAPON_MINIGUN )
        Ban( playerid );
   
    return 1;
}
Player-affecting server functions
Functions such as SetPlayerHealth, GivePlayerMoney, PutPlayerInVehicle, etc. all send a message from the server only to the player it is affecting (SetPlayerVirtualWorld is an exception here).

What does that mean?
Well.. If the player has 73 health and you use SetPlayerHealth to set it to 100, this is what happens:
  1. SetPlayerHealth( playerid, 100.0 ) -> The server sends a message to the affected client telling it to update the health to 100.
  2. The client is currently paused so the message is put in a pool and will be handled once the player is unpaused and all the messages in the pool before it was handled.
  3. A timer in the gamemode uses GetPlayerHealth on the player and it shows 73.
  4. The client now unpaused, and all the messages in the pool are now handled.
  5. The health is changed for the client.
  6. An update it sent to the server.
  7. OnPlayerUpdate is called.
  8. The new health is sent to all other players on the server, and they now see the player having health 100!
Key sync
SA-MP is synced by copying the keys you press and applying them for all other clients. If you press aim and fire, you will press aim and fire for other clients aswell; that means, even if you're shooting on your screen you might be standing in front of a desynced vehicle or be knifed/dead from a car explosion on other player's screens. This is referred to as desync.

Fixing a desynced player
To fix a desynced player, the only proper way is to stream the player in/out or respawn the player. Streaming the player in/out would take about a second; therefore, respawning the player is the most essential solution.
I'll get back on this with fully working re-sync code!

Keys sent to the server
Some might believe, if you press and release a button real quick the server won't see it. Wrong! For example, if you press and release fire the server will receive 2 updates: you pressing fire, and you releasing fire.

Packet loss
Sometimes, when a player update is sent to the server, it might get lost out in the big world. This might cause bugs or problems in the script; be prepared for packet loss!

How can I avoid packet-loss related script bugs?
Never trust the client, both on good and evil. You never know if the client is a script kiddie trying to mess with your server, someone with a bad wifi/connection, or someone with a random packet loss.
Packet loss usually causes confusion with player information, for example:
  • Player 1 has 50 armour.
  • The server has a brand new, top-notch anti-armour cheat based on player updates!
  • The anti-armour cheat will detect if the armour changed, and the player didn't lose $240 while in an ammu-nation.
  1. Player 1 goes into an ammo. The server now knows that, because of code in OnPlayerInteriorChange.
  2. Player 1 buys an armour and sends an update to the server with the new armour and pays $240.
  3. Player 1 sends a packet to the server with that information; the packet is lost!
  4. Player 1 starts moving around, updates are sent for this but the server has no idea about the $240 or the armour.
  5. Player 1 gets shot, the new armour is sent in a player update to the server. The server still has no idea about the $240!
  6. The server anti-cheat sees this, and bans the player for armour cheating.
Preventing this faulty ban:
  • Notifying admins and adding what happened to a hidden "suspected cheating count" (that would ban after for example 3 suspicious events).
  • Giving the player $1 and wait for the new money update; possibly remove the armour and give it back only if new money is received within the next 1-3 player updates.
Packet misorder
Packet misorder is when messages sent doesn't get received in the order they were sent.
A scenario:
  • Player 1 has 85 armour.
  • The server has a brand new, top-notch anti-armour cheat based on player updates!
  • The anti-armour cheat will detect if the armour changed, and the player didn't lose $240 while in an ammu-nation.
  1. Player 1 is fighting for his life!
  2. Player 1 gets hit twice, first on 10 hp then 20 hp; two packets with new armour are sent to the server.
  3. The packets are misplaced; the server first receives a message telling the player has 55 armour (85-10-20).
  4. The first package gets to the server after the second, with armour 75.
  5. The server thinks the player's armour has increased and bans the player for armour cheating.
Preventing this faulty ban:
  • Notifying admins and adding what happened to a hidden "suspected cheating count" (that would ban after for example 3 suspicious events).
  • Not take any actions until 2-3 more player updates; still only generate a warning.
  • Take actions only if the new armour is larger than or equal to 100.




I hope you learned something from this tutorial. If I provided faulty/diffuse information, let me know! I might add more information to this topic.
Reply
#2

Good for new people. +1
Reply
#3

Quote:
Originally Posted by Retardedwolf
View Post
Good for new people. +1
It should be useful for more advanced people, aswell. I've seen many good scripters release code not ready for packet loss/misorder, pausing, or heavy lag!
Reply
#4

haha, i liked the examples xD
you can really know how a server is like
Reply
#5

Quote:
Originally Posted by g_aSlice
View Post
It should be useful for more advanced people, aswell. I've seen many good scripters release code not ready for packet loss/misorder, pausing, or heavy lag!
Hm, I don't consider myself as a 'good' scripter but I do already understand most parts mentioned in this tutorial but I'm not saying this is a bad tutorial. It teaches people about SA-MP sync totally.
Reply
#6

Quote:
Originally Posted by Retardedwolf
View Post
Hm, I don't consider myself as a 'good' scripter but I do already understand most parts mentioned in this tutorial but I'm not saying this is a bad tutorial. It teaches people about SA-MP sync totally.
Write down any words/sentences you don't understand and I'll break them down/explain further.
Reply
#7

Quote:
Originally Posted by g_aSlice
View Post
Write down any words/sentences you don't understand and I'll break them down/explain further.
If my post didn't tell you, Yes, sorry for making you feel that you made a mistake or something too complicated. I don't mean it that way. I'm just saying before reading this tutorial I have already understand-ed most of the stuff mentioned in this tutorial.

(If you're asking me for suggestions, I recommend you to add some spaces and maybe something to make the tutorial look better, an example is Y_Less' release topics as it is placed out well and have good and better colours to make it look better. [NOTE: I'm not saying being simple sucks].) altho I already think most of the stuff is already good and explained well.
Reply
#8

Thanks for explaining more about packets that are send between the client and the server, this really helps me a lot as I experience this frequently. I know a few things about it already, but this really helped in understanding it better ^^
Reply
#9

thanks i learnt something new today about packet loss
Reply
#10

Thanks for the solve of TogglePlayerControllable

Nice tut also
Reply
#11

Hey, thanks for posting this. It's definitely going to help explain things in the future.
Reply
#12

Thanks for tutorial, I learned some things .
Reply
#13

Great tutorial overall.

Quote:

Notifying admins and adding what happened to a hidden "suspected cheating count" (that would ban after for example 3 suspicious events).

Great to see that you're promoting the usage of this, most scripters tend to disregard the fact that there could be packet loss.
Reply
#14

Quote:
Originally Posted by Calgon
View Post
Great tutorial overall.



Great to see that you're promoting the usage of this, most scripters tend to disregard the fact that there could be packet loss.
Yes, it's the best like that, you send saying suspicious cheater, you spec him and done, no wrong bans.
Reply
#15

This shows that servers advertising quad cores and such is useless right?
Reply
#16

Nice info helped me understand more about how the server works, theres not much info around about this type of thing (not that i can find anyway) so +1 to u sir!
Reply
#17

SuperB info, finaly I understand how to fix dumb moving while player freezed.

also I like this example
"Server has no idea about $240 and armour"


Also good to know some things what other time was self-understandable, now I know why that or that happens

10/10
Reply
#18

I've found it useful, really nice, thanks!
Reply
#19

Very good information! Congratulations!

Just one off-topic question, why to you declare variables like g_ and s_ and such? Global and Static?

Where did you learn this coding technique? Here in my country programming teachers never teach about coding techniques regarding naming things and etc..
Reply
#20

Quote:
Originally Posted by ViRuXe
View Post
Very good information! Congratulations!

Just one off-topic question, why to you declare variables like g_ and s_ and such? Global and Static?

Where did you learn this coding technique? Here in my country programming teachers never teach about coding techniques regarding naming things and etc..
This is kinda what I tend to stick with most of the time when writing PAWN stuff: http://en.wikipedia.org/wiki/Hungari...ation#Examples
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)