[Tutorial] Save, load and set player position - using y_ini
#1

Introduction
  • I've seen numerous people having trouble with saving, loading and setting player position. This tutorial will teach you how you can save the player position in an ini file, load it and set it when he spawns ( return to the last position you were when you disconnected ).
What do you need
  • y_ini - The fastest and most efficient way to write/read from a file by ******
Download
  • Download YSI Server Includes.
  • Copy/Cut the "YSI" folder into your "..pawno\include" directory.
Starting

Let's include y_ini at the top of our script.

pawn Код:
#include <YSI\y_ini>
The #include directive inserts the contents of the specified file at the current position within the current file. More directives can be found here. In our case it will load all the codes from "..pawno\include\YSI\y_ini.inc" into the script and that's what we need so we can load y_ini features.

Let's declare some variables somewhere at the top of our script:

pawn Код:
new
    Float: PosX[ MAX_PLAYERS ],
    Float: PosY[ MAX_PLAYERS ],
    Float: PosZ[ MAX_PLAYERS ],
    Float: Angle[ MAX_PLAYERS ],
    Interior[ MAX_PLAYERS ],
    VirtualWorld[ MAX_PLAYERS ]
;
The "new" keyword declares a new variable. We used the predefined tag name called "Float" which will enable the floating point support for our variables. We declared 6 arrays. An array is a variable in which you can store multiple pieces of data at once and access them dynamically. Each variable holds a number of cells ( MAX_PLAYERS ). The first one will hold the X coordinates of the player position, the second one will hold the Y coordinates of the player position, the third one will hold the Z coordinates of the player position, the fourth one will hold the Angle coordinates of the player, the fifth one will hold the interior ID of the player and the last one will hold the virtual world ID of the player. Let's create a simple stock function that will return the directory where the player file ( which will contain the position coordinates ) will be saved.

pawn Код:
stock user_ini_file(playerid)
{
    new
        string[ 128 ],
        user_name[ MAX_PLAYER_NAME ]
    ;

    GetPlayerName( playerid, user_name, MAX_PLAYER_NAME );
    format( string, sizeof ( string ), "%s.ini", user_name );
    /* scriptfiles directory */
    return
        string;
}
A stock function is a function that the PAWN parser must plug into the program when it is used and that it may simply "remove" from the program (without warning) when it is not used. To declare a stock function, prefix the function name with the keyword stock. Public functions and native functions cannot be declared 'stock'.

We declare an array called string 128 cells big and another one called user_name MAX_PLAYER_NAME cells big (which means 24(maximum player name lenght in SA:MP )). We get the playerid name using GetPlayerName function and store the player name in the variable called user_name, we format the path and store it in the variable string, at the end we return the string. Since the path is mentioned as "%s.ini", the user file will be saved in your "..scriptfiles" directory.

Let's create a simple public function to load the user data from the file:

pawn Код:
forward @load_user_position( playerid, name[], value[] );

@load_user_position( playerid, name[], value[] )
{
    INI_Float( "PositionX", PosX[ playerid ] );
    INI_Float( "PositionY", PosY[ playerid ] );
    INI_Float( "PositionZ", PosZ[ playerid ] );
    INI_Float( "Angle", Angle[ playerid ] );
    INI_Int( "Interior", Interior[ playerid ] );
    INI_Int( "VirtualWorld", VirtualWorld[ playerid ] );
    return ( 1 );
}
Public functions can be prefixed by either public or @, the @ character, when used, becomes part of the function name. INI_Float saves the passed value as a float if the name matches, INI_Int - the data is passed to the loading callback as a string, this will convert it to an integer. We will save the player position, interior and virtual world when he disconnects so let's scroll down to OnPlayerDisconnect callback.

pawn Код:
public OnPlayerDisconnect( playerid, reason )
{
    GetPlayerPos( playerid, PosX[ playerid ], PosY[ playerid ], PosZ[ playerid ] );
    GetPlayerFacingAngle( playerid, Angle[ playerid ] );
   
    new INI:File = INI_Open( user_ini_file( playerid ) );
    INI_SetTag( File, "position" );
    INI_WriteFloat( File, "PositionX", PosX[ playerid ] );
    INI_WriteFloat( File, "PositionY", PosY[ playerid ] );
    INI_WriteFloat( File, "PositionZ", PosZ[ playerid ] );
    INI_WriteFloat( File, "Angle", Angle[ playerid ] );
    INI_WriteInt( File, "Interior", GetPlayerInterior( playerid ) );
    INI_WriteInt( File, "VirtualWorld", GetPlayerVirtualWorld( playerid ) );
    INI_Close( File );
    return ( 1 );
}
OnPlayerDisconnect callback is called when a player disconnects from the server, playerid is the id of the player who left and reason id of the reason why they left.

We use GetPlayerPos function to get the current player position and save it in the variables "PosX, PosY and PosZ". We use GetPlayerFacingAngle function to get the angle of the direction the player is facing and store it in the variable "Angle". We open/create the user file using INI_Open and our stock as the parameter. We write to the user "PositionX" section the value stored in the variable PosX, we write to the user "PositionY" section the value stored in the variable PosY, to the "PositionZ" section the value stored in the variable "PosZ" and to the "Angle" section the value stored in the Angle variable, to the "Interior" section the value returned by the GetPlayerInterior function, to the "VirtualWorld" section the value returned by GetPlayerVirtualWorld function. After the values has been written we close the user file using INI_Close, we return a true value. We need to load the user position from the file when he connects so let's scroll to OnPlayerConnect callback.

pawn Код:
public OnPlayerConnect( playerid )
{
    PosX[ playerid ] = 0;
    PosY[ playerid ] = 0;
    PosZ[ playerid ] = 0;
    Angle[ playerid ] = 0;
    Interior[ playerid ] = 0;
    VirtualWorld[ playerid ] = 0;
   
    INI_ParseFile( user_ini_file( playerid ), "load_user_%s", .bExtra = true, .extra = playerid );
    return ( 1 );
}
OnPlayerConnect callback is called when a player connects to the server, playerid is the ID of the player that connected. We reset the player variables first, e use INI_ParseFile to parse his ini file (load his data), when he spawns we need to set his position, interior and virtual world so let's scroll down to OnPlayerSpawn callback.

pawn Код:
public OnPlayerSpawn( playerid )
{
    if ( PosX[ playerid ] != 0 && PosY[ playerid ] != 0 && PosZ[ playerid ] != 0 && Angle[ playerid ] != 0 )
    {
        SetPlayerPos( playerid, PosX[ playerid ], PosY[ playerid ], PosZ[ playerid ] );
        SetPlayerFacingAngle( playerid, Angle[ playerid ] );
        SetPlayerInterior( playerid, Interior[ playerid ] );
        SetPlayerVirtualWorld( playerid, VirtualWorld[ playerid ] );
        SendClientMessage( playerid, -1, "welcome to your last position" );
    }
    return ( 1 );
}
OnPlayerSpawn callback is called when a player spawns, playerid is the ID of the player that spawned.

When a player first connects to the server, his PosX, PosY, PosZ and Angle variables will be 0. The operator "!=" means "left is NOT equal to right". We check if our variables are NOT equal to 0, if so we set the player position using SetPlayerPos function, we set his angle using SetPlayerFacingAngle function, we set his interior using SetPlayerInterior function, we set his virtual world using SetPlayerVirtualWorld function and we send him a simple message using SendClientMessage function.

That's all, your script should look something like this:

pawn Код:
#include <a_samp>
#include <YSI\y_ini>

new
    Float: PosX[ MAX_PLAYERS ],
    Float: PosY[ MAX_PLAYERS ],
    Float: PosZ[ MAX_PLAYERS ],
    Float: Angle[ MAX_PLAYERS ],
    Interior[ MAX_PLAYERS ],
    VirtualWorld[ MAX_PLAYERS ]
;

stock user_ini_file(playerid)
{
    new
        string[ 128 ],
        user_name[ MAX_PLAYER_NAME ]
    ;

    GetPlayerName( playerid, user_name, MAX_PLAYER_NAME );
    format( string, sizeof ( string ), "%s.ini", user_name );
    /* scriptfiles directory */
    return
        string;
}

forward @load_user_position( playerid, name[], value[] );

@load_user_position( playerid, name[], value[] )
{
    INI_Float( "PositionX", PosX[ playerid ] );
    INI_Float( "PositionY", PosY[ playerid ] );
    INI_Float( "PositionZ", PosZ[ playerid ] );
    INI_Float( "Angle", Angle[ playerid ] );
    INI_Int( "Interior", Interior[ playerid ] );
    INI_Int( "VirtualWorld", VirtualWorld[ playerid ] );
    return ( 1 );
}

public OnPlayerDisconnect( playerid, reason )
{
    GetPlayerPos( playerid, PosX[ playerid ], PosY[ playerid ], PosZ[ playerid ] );
    GetPlayerFacingAngle( playerid, Angle[ playerid ] );
   
    new INI:File = INI_Open( user_ini_file( playerid ) );
    INI_SetTag( File, "position" );
    INI_WriteFloat( File, "PositionX", PosX[ playerid ] );
    INI_WriteFloat( File, "PositionY", PosY[ playerid ] );
    INI_WriteFloat( File, "PositionZ", PosZ[ playerid ] );
    INI_WriteFloat( File, "Angle", Angle[ playerid ] );
    INI_WriteInt( File, "Interior", GetPlayerInterior( playerid ) );
    INI_WriteInt( File, "VirtualWorld", GetPlayerVirtualWorld( playerid ) );
    INI_Close( File );
    return ( 1 );
}

public OnPlayerConnect( playerid )
{
    PosX[ playerid ] = 0;
    PosY[ playerid ] = 0;
    PosZ[ playerid ] = 0;
    Angle[ playerid ] = 0;
    Interior[ playerid ] = 0;
    VirtualWorld[ playerid ] = 0;
   
    INI_ParseFile( user_ini_file( playerid ), "load_user_%s", .bExtra = true, .extra = playerid );
    return ( 1 );
}


public OnPlayerSpawn( playerid )
{
    if ( PosX[ playerid ] != 0 && PosY[ playerid ] != 0 && PosZ[ playerid ] != 0 )
    {
        SetPlayerPos( playerid, PosX[ playerid ], PosY[ playerid ], PosZ[ playerid ] );
        SetPlayerFacingAngle( playerid, Angle[ playerid ] );
        SetPlayerInterior( playerid, Interior[ playerid ] );
        SetPlayerVirtualWorld( playerid, VirtualWorld[ playerid ] );
        SendClientMessage( playerid, -1, "welcome to your last position" );
    }
    return ( 1 );
}
The user ini file will look something like this:

Код:
[position]
PositionX = 171.252197
PositionY = -72.037948
PositionZ = 2.210306
Angle = 150.401428
Interior = 3
VirtualWorld = 0
Special thanks to
Reply
#2

All i can really say is when you do a tutorial about saving a players position its important that you include virtual world, and interior support. If a player logs out in an interior using this code, then relogs later, they will begin to fall from the sky and eventually die.....
Reply
#3

pawn Код:
public OnPlayerSpawn( playerid )
{
    if ( PosX[ playerid ] != 0 && PosY[ playerid ] != 0 && PosZ[ playerid ] != 0 )
    {
        SetPlayerPos( playerid, PosX[ playerid ], PosY[ playerid ], PosZ[ playerid ] );
        SetPlayerFacingAngle( playerid, Angle[ playerid ] );
        SendClientMessage( playerid, -1, "welcome to your last position" );
    }
    return ( 1 );
}
This would cause loading the position every spawn(even after death).
+ You don't clear the variables:
Player 0 loads his data, and disconnects. A newbie connects with ID 0, and gets spawned to the position.
Reply
#4

Very Nice Could Of Used This When I Was Making My Server A While Back
Reply
#5

Quote:
Originally Posted by SantarioLeone
Посмотреть сообщение
All i can really say is when you do a tutorial about saving a players position its important that you include virtual world, and interior support. If a player logs out in an interior using this code, then relogs later, they will begin to fall from the sky and eventually die.....
Forgot that, updated.

Quote:
Originally Posted by wups
Посмотреть сообщение
You don't clear the variables:
Player 0 loads his data, and disconnects. A newbie connects with ID 0, and gets spawned to the position.
Updated.
Reply
#6

Good tutorial though. +Repped
Reply
#7

Do not work for me and i have no idea WHY? I did everything how it says, no errors, when i disconnect i check the ini and the cords are there but when i reconnect again it just spawns me in the default spawn.

Reply
#8

Quote:
Originally Posted by dmng825
Посмотреть сообщение
Do not work for me and i have no idea WHY? I did everything how it says, no errors, when i disconnect i check the ini and the cords are there but when i reconnect again it just spawns me in the default spawn.

Same problem
Reply
#9

Bump. Anyone please help? Posts above.
Reply
#10

BUMP Save location but it dont read it.
Reply
#11

Could anyone help i made every thing and it compiles well then when iam disconnect i returned to my defult spawn
Reply
#12

I get these
pawn Code:
C:\Users\Michael C\Desktop\GTA San Andreas\gamemodes\NewRP.pwn(81) : error 017: undefined symbol "PosX"
C:\Users\Michael C\Desktop\GTA San Andreas\gamemodes\NewRP.pwn(81) : warning 215: expression has no effect
C:\Users\Michael C\Desktop\GTA San Andreas\gamemodes\NewRP.pwn(81) : error 001: expected token: ";", but found "]"
C:\Users\Michael C\Desktop\GTA San Andreas\gamemodes\NewRP.pwn(81) : error 029: invalid expression, assumed zero
C:\Users\Michael C\Desktop\GTA San Andreas\gamemodes\NewRP.pwn(81) : fatal error 107: too many error messages on one line

Compilation aborted.Pawn compiler 3.2.3664          Copyright (c) 1997-2006, ITB CompuPhase


4 Errors.
After i made that forward
Reply
#13

Code:
D:\samp servas\Naujas aplankas\gamemodes\****.pwn(214) : error 017: undefined symbol "INI_ParseFile"
D:\samp servas\Naujas aplankas\gamemodes\****.pwn(214) : warning 215: expression has no effect
D:\samp servas\Naujas aplankas\gamemodes\****.pwn(214) : error 029: invalid expression, assumed zero
D:\samp servas\Naujas aplankas\gamemodes\****.pwn(214) : error 017: undefined symbol "extra"
D:\samp servas\Naujas aplankas\gamemodes\****.pwn(214) : fatal error 107: too many error messages on one line

Compilation aborted.Pawn compiler 3.2.3664	 	 	Copyright © 1997-2006, ITB CompuPhase


4 Errors.
what i supposed to do?
Reply
#14

pawn Code:
warning 219: local variable "Angle" shadows a variable at a preceding level
Reply
#15

Same for me, I just spawn in the default spawn area. :/
Reply
#16

Code:
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(156) : warning 225: unreachable code
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(186) : warning 225: unreachable code
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(189) : error 021: symbol already defined: "File"
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(413) : warning 217: loose indentation
Pawn compiler 3.2.3664	 	 	Copyright © 1997-2006, ITB CompuPhase


1 Error.
Could use some help cant figure out what to do...
Reply
#17

Quote:
Originally Posted by jstowe96
View Post
Code:
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(156) : warning 225: unreachable code
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(186) : warning 225: unreachable code
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(189) : error 021: symbol already defined: "File"
C:\Users\Michael\Desktop\GTA San Andreas\zServers\SAMP Server Godfather Edit\gamemodes\hprprevamp.pwn(413) : warning 217: loose indentation
Pawn compiler 3.2.3664	 	 	Copyright © 1997-2006, ITB CompuPhase


1 Error.
Could use some help cant figure out what to do...
Post your code.
Reply
#18

I actually got it fixed, nevermind and thank you for attempting to help. Repped.
Reply
#19

I just keep ending up in the default spawn position not my players last position

Please Help Me!!!!

Reply
#20

I followed the tutorial,I had no errors but I keep spawning at the default location..can you help me please?
Reply


Forum Jump:


Users browsing this thread: 4 Guest(s)