SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Scripting Help > Tutorials

Reply
 
Thread Tools Display Modes
Old 27/11/2011, 01:18 PM   #1
SmiT
Huge Clucker
 
Join Date: Oct 2011
Posts: 352
Reputation: 63
Default Save, load and set player position - using y_ini

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 Y_Less
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.

Code:
#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:

Code:
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.

Code:
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:

Code:
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.

Code:
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.

Code:
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.

Code:
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:

Code:
#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:

Code:
[position]
PositionX = 171.252197
PositionY = -72.037948
PositionZ = 2.210306
Angle = 150.401428
Interior = 3
VirtualWorld = 0
Special thanks to

Last edited by SmiT; 28/11/2011 at 01:51 PM.
SmiT is offline   Reply With Quote
Old 27/11/2011, 07:10 PM   #2
SantarioLeone
Big Clucker
 
Join Date: Jul 2008
Posts: 166
Reputation: 23
Default Re: Save, load and set player position - using y_ini

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.....
__________________

Easiest way to help your server stay alive with free hosting.Click Here
Working on a RP project from scratch, anyone interested in working together PM me, i have a beta host to test things.
SantarioLeone is offline   Reply With Quote
Old 27/11/2011, 08:13 PM   #3
wups
High-roller
 
wups's Avatar
 
Join Date: Apr 2010
Location: Lithuania
Posts: 1,257
Reputation: 137
Default Re: Save, load and set player position - using y_ini

Code:
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.
wups is offline   Reply With Quote
Old 27/11/2011, 09:05 PM   #4
RepzThat
Little Clucker
 
Join Date: Nov 2011
Posts: 42
Reputation: 11
Default Re: Save, load and set player position - using y_ini

Very Nice Could Of Used This When I Was Making My Server A While Back
__________________
Open Positions:
Mapper (Pm if interested)
RepzThat is offline   Reply With Quote
Old 28/11/2011, 01:52 PM   #5
SmiT
Huge Clucker
 
Join Date: Oct 2011
Posts: 352
Reputation: 63
Default Re: Save, load and set player position - using y_ini

Quote:
Originally Posted by SantarioLeone View Post
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 View Post
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.
SmiT is offline   Reply With Quote
Old 29/11/2011, 06:20 PM   #6
SantarioLeone
Big Clucker
 
Join Date: Jul 2008
Posts: 166
Reputation: 23
Default Re: Save, load and set player position - using y_ini

Good tutorial though. +Repped
__________________

Easiest way to help your server stay alive with free hosting.Click Here
Working on a RP project from scratch, anyone interested in working together PM me, i have a beta host to test things.
SantarioLeone is offline   Reply With Quote
Old 31/12/2011, 05:08 PM   #7
dmng825
Little Clucker
 
Join Date: Dec 2011
Posts: 2
Reputation: 0
Default Re: Save, load and set player position - using y_ini

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.

dmng825 is offline   Reply With Quote
Old 31/12/2011, 09:41 PM   #8
Zom3ie
Little Clucker
 
Zom3ie's Avatar
 
Join Date: Nov 2011
Location: USA
Posts: 15
Reputation: 0
Default Re: Save, load and set player position - using y_ini

Quote:
Originally Posted by dmng825 View Post
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
Zom3ie is offline   Reply With Quote
Old 02/01/2012, 01:16 PM   #9
dmng825
Little Clucker
 
Join Date: Dec 2011
Posts: 2
Reputation: 0
Default Re: Save, load and set player position - using y_ini

Bump. Anyone please help? Posts above.
dmng825 is offline   Reply With Quote
Old 17/02/2012, 04:22 PM   #10
maxmax1
Little Clucker
 
Join Date: Sep 2009
Posts: 23
Reputation: 0
Default Re: Save, load and set player position - using y_ini

BUMP Save location but it dont read it.

Last edited by maxmax1; 17/02/2012 at 06:39 PM.
maxmax1 is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[Include] Player Inventory System 0.2b (Menu + Save / Load) -zriptarusk Filterscripts 37 24/01/2014 08:08 PM
I need help! pls! /s and /r or /l script or fs save position and load position ProdrifterX Scripting Help 2 14/10/2011 05:02 PM
Save & Load position anumaz Help Archive 4 16/07/2011 04:26 AM
save player position ! dorperez Help Archive 2 19/01/2011 04:27 PM
[FilterScript] [FS] Position Saver (dynamic position save system) Nero_3D Filterscripts 13 20/08/2010 07:02 PM


All times are GMT. The time now is 11:58 AM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.