Jump to content
code34

iniDBI2 - Save and Load data to the server or your local computer without databases!

Recommended Posts

Question, im currently having a strange issue that I was not having before. when the player loads into the mission i have it execute a script called clientStart.sqf which calls a function to get all the needed information about the player and send it to the server using publicVariableServer

clientStart.sqf. when the player first joins the server it runs whats inside the else statement.

_isRespawn = _this select 0;

player enableFatigue false;

if (_isRespawn) then
{
	if ((side player) == WEST) then
	{
		execVM "cop\sayings.sqf";
		player allowDamage false;
	};
}
else
{
	execVM "database\client\eventHandlers.sqf";
	
	if ((side player) == INDEPENDENT) then
	{
		execVM "tools\setTools.sqf";
		execVM "shop\shopInit.sqf";
	}
	else
	{
		execVM "cop\sayings.sqf";
		player allowDamage false;
	};
	
	_checkClientFnc =
	{
		hint "IN CHECK CLIENT FNC";
		_id = getPlayerUID player;
		_name = name player;
		_cId = clientOwner;
		pid = [_id, _name, pGear, _cId];
		publicVariableServer "pid";
	};
	call _checkClientFnc;
};

the pid publicVariableEventHandler is ran from the server as soon as the mission starts in the file clientCheck.sqf

"pid" addPublicVariableEventHandler
{
	"IN PID EVENT HANDLER" remoteExec ["hint"];
	private ["_data"];
	_data = _this select 1;
	_id = _data select 0;
	_name = _data select 1;
	_gear = _data select 2;
	_cId = _data select 3;
	
	_inidbi = ["new", _id] call OO_INIDBI;
	_dataExist = "exists" call _inidbi;
	
	if (_dataExist) then
	{
		"IN IF STATEMENT OF PID EVENT HANDLER" remoteExec ["hint"];
		null = [_id, _cId] execVM "database\getData.sqf";
	}
	else
	{
		"IN ELSE STATEMENT OF PID EVENT HANDLER" remoteExec ["hint"];
		null = [_id, _name, _gear] execVM "database\createDatabase.sqf";
	};
};

and thats where im running into issues. i have a variable _dataExist to check if the file is already existing for the players UID, if no file exists it is suppose to run createDatabase.sqf, and if it does exist it is suppose to run getData.sqf. however no matter what, for some reason it always runs getData.sqf because _dataExist always returns true for some reason even when i clear out the db folder entirely.

 

 

also when it does run getData.sqf it somehow manages to create a database as well and store the information somehow using "read" and i am just at a complete loss here as to whats going wrong. this is my first time really using inidbi2 btw, so far its been great but somehow something goofed. this is being tested on a dedicated server(off my machine) and the mod is running on the server, the mod is not running on the test client.

 

heres getData and createDatabase

_id = _this select 0;
_cId = _this select 1;

_inidbi = ["new", _id] call OO_INIDBI;
_cash = ["read", ["PlayerInfo", "Cash", []]] call _inidbi;
_gear = ["read", ["PlayerInfo", "Gear", []]] call _inidbi;
_maxWeight = ["read", ["PlayerTools", "LockPick", []]] call _inidbi;
_lockPick = ["read", ["PlayerTools", "LockPick", []]] call _inidbi;

loadData = [_cash, _gear, _lockPick, _maxWeight];

_cId publicVariableClient "loadData";
//"IN CREATE DATABASE FILE" remoteExec ["hint"];

_id = _this select 0;
_name = _this select 1;
_gear = _this select 2;

_inidbi = ["new", _id] call OO_INIDBI;

["write", ["PlayerInfo", "Name", _name]] call _inidbi;
["write", ["PlayerInfo", "Gear", _gear]] call _inidbi;
["write", ["PlayerInfo", "Cash", 0]] call _inidbi;
["write", ["PlayerInfo", "MaxWeight", 100]] call _inidbi;
["write", ["PlayerTools", "LockPick", false]] call _inidbi;

and heres the mission. the files that are in question are server\clientCheck, server\createDatabase, server\getData

https://www.dropbox.com/s/wul8c0wmaabrnid/robTheHood.Malden.rar?dl=0

Share this post


Link to post
Share on other sites

hi,

 

Quote

however no matter what, for some reason it always runs getData.sqf because _dataExist always returns true for some reason even when i clear out the db folder entirely.

 

You should try first to do a simple test on server side with no other code, and publicvariable code.

 

Just check the "exists" function return in a log file :)

 

Share this post


Link to post
Share on other sites
27 minutes ago, code34 said:

hi,

 

 

You should try first to do a simple test on server side with no other code, and publicvariable code.

 

Just check the "exists" function return in a log file :)

 

thats what i initially did and had gotten everything working as it should, it still saves the data i need properly later on in the mission and when there is data for the player already created inside the db folder it loads the data it needs properly, its just that

_inidbi = ["new", _id] call OO_INIDBI;

_dataExist = "exists" call _inidbi;

always returns true no matter what situation i try. i didnt use a log file i globally executed a hint right after  _dataExist = "exists" call _inidbi; so i could see what it was returning. it returned true when it was suppose to be false and returned true when it was suppose to return true lol. when i made another little test mission previously to get familiar with inidbi2 i had a similar setup and it would return true/false without any issue, it just has my brain in a twist

Share this post


Link to post
Share on other sites

strange ...but sometimes ARMA has incoherent returns, in this case, you should restart ARMA or machine.

I still had this case 2 days ago with the publicvariable precisely (without inidbi) and  the arma restart solved the problem.

Share this post


Link to post
Share on other sites
6 minutes ago, code34 said:

strange ...but sometimes ARMA has incoherent returns, in this case, you should restart ARMA or machine.

I still had this case 2 days ago with the publicvariable precisely (without inidbi) and  the arma restart solved the problem.

thats is weird. ive tried restarting arma and same with my pc as this has been a 20+ hour project so far over the past week with no luck. ill try copying it over and using it in another mission and see if that changes the result if it bugged the mission somehow or not.

Share this post


Link to post
Share on other sites

the first reason that i can see it s there is async read / write. While you delete the file, another is already created when you test if it exists.

 

It could happen with handlers and publicvariable because handler dont work in the same maner in local and distant

Share this post


Link to post
Share on other sites

@gokitty1199 Hi. you said ""exists" call _inidbi;" always returns true but of course it does when you call the " ["new", _id] call OO_INIDBI;" before it.

 

the "exists" command simply checks if the ini file exists

 

Edit: although I could be wrong about this because I don't think "new" yet creates the file so "exists" should return false if there's no ini file.

 

 

Edited by gc8

Share this post


Link to post
Share on other sites
13 hours ago, code34 said:

the first reason that i can see it s there is async read / write. While you delete the file, another is already created when you test if it exists.

 

It could happen with handlers and publicvariable because handler dont work in the same maner in local and distant

ill look into that and see if it creates a file before it calls the check which would make sense if thats the case. thank you!

 

11 hours ago, gc8 said:

@gokitty1199 Hi. you said ""exists" call _inidbi;" always returns true but of course it does when you call the " ["new", _id] call OO_INIDBI;" before it.

 

the "exists" command simply checks if the ini file exists

 

Edit: although I could be wrong about this because I don't think "new" yet creates the file so "exists" should return false if there's no ini file.

 

 

from what ive experience just calling "new" doesnt create the file, it creates once you write to it so its like this. someone correct me if im wrong please

_inidbi = ["new", "myNewFile"] call OO_INIDBI;
_exist = "exist" call _inidbi;
if (_exist) then
{
	hint "file exists";
}
else
{
	hint "no file exists";//should hint this
};

["write", ["testS", "testK", "randomStr"]] call _inidbi;

_exist = "exist" call _inidbi;
if (_exist) then
{
	hint "file exists";//should hint this
}
else
{
	hint "no file exists";
};

 

Share this post


Link to post
Share on other sites

Hi, I am having an issue with a leaderboard script. Basically I have it so it logs your kills, deaths, play time, name, etc. When you join the server if creates the DB and lists the information, and while I play it also saves my stats. However, when I leave and join the server again, it resets my stats. Is there any of you who could help me with this issue? I'll past the code in here and hopefully someone can assist me. If you have any more questions please feel free to message me on discord or steam. 

Spoiler

In my InitServer.sqf

 

while {true} do {

databaseplayers = ["new", "databaseplayers"] call OO_INIDBI;

{

_section = getPlayerUID _x;

_playerKills = _x getVariable ["GMKills", 0];

_playerTime = _x getVariable ["GMPlaytime", 0];

_playerDeaths = _x getVariable ["GMDeaths", 0];

_donatorLevel = _x getVariable ["GMDonator", 0];

_playerName = name _x;

["write",[_section, "kills", _playerKills]] call databaseplayers;

        ["write",[_section, "deaths", _playerDeaths]] call databaseplayers;

        ["write",[_section, "name", _playerName]] call databaseplayers;

["write",[_section, "playtime", _playerTime]] call databaseplayers;

["write",[_section, "donatorLevel", _donatorLevel]] call databaseplayers;

leaderBoardArray = [];

newDatabaseLBArray = "getSections" call databaseplayers;

{

_nameOfUser = ["read", [_x, "name"]] call _indibi;

_userKillCount = ["read", [_x, "kills"]] call _indibi;

_userDonatorLevel = ["read", [_x, "donatorLevel"]] call _indibi;

_userDonator = format ["%1", _userDonatorLevel];

leaderBoardArray pushBackUnique [_nameOfUser, _userKillCount, _userDonator];

leaderBoardArray sort true;

publicVariable "leaderBoardArray";

} forEach newDatabaseLBArray;

} forEach playableUnits;

sleep 30;

};

 

Spoiler

my loadstats.sqf

 

_sender = _this select 0;

_senderid = getPlayerUID _sender;

 

databaseplayers = ["new", "databaseplayers"] call OO_INIDBI;

 

_kills = ["read", [_senderid, "kills", 0]] call databaseplayers;

_deaths = ["read", [_senderid, "deaths", 0]] call databaseplayers;

_playtime = ["read", [_senderid, "playtime", 0]] call databaseplayers;

_donatorLevel = ["read", [_senderid, "donatorlevel", 0]] call databaseplayers;

 

_sender setVariable ["GMKills", _kills,true];

_sender setVariable ["GMDeaths", _deaths,true];

_sender setVariable ["GMPlaytime", _playtime,true];

_sender setVariable ["GMDonator", _donatorLevel,true];

 

Steam: http://steamcommunity.com/id/ColeSlaughter/

Discord: Cole Slaughter#9727

 

Thanks!

Share this post


Link to post
Share on other sites
13 hours ago, code34 said:

the first reason that i can see it s there is async read / write. While you delete the file, another is already created when you test if it exists.

 

It could happen with handlers and publicvariable because handler dont work in the same maner in local and distant

yep that was why. it was already creating the file from somewhere somehow for the client before that function was called, thanks man.

Share this post


Link to post
Share on other sites

hi

 

@gokitty1199ok good news :)

 

for more information about the command

_inidbi = ["new", "myNewFile"] call OO_INIDBI;

OO_INIDBI is a CLASS. When you call the "new" function, it will instanciate this class through the constructor public function and return an object that you store into _inidbi variable.
https://github.com/code34/inidbi2/blob/master/%40inidbi2/Addons/inidbi2/oo_inidbi.sqf

 

@Cole Slaughter  you have to use an unique file id by player to save / restore your data

 

  • Like 1

Share this post


Link to post
Share on other sites
8 minutes ago, code34 said:

hi

 

@gokitty1199ok good news :)

 

for more information about the command


_inidbi = ["new", "myNewFile"] call OO_INIDBI;

OO_INIDBI is a CLASS. When you call the "new" function, it will instanciate this class through the constructor public function and return an object that you store into _inidbi variable.
https://github.com/code34/inidbi2/blob/master/%40inidbi2/Addons/inidbi2/oo_inidbi.sqf

 

@Cole Slaughter  you have to use an unique file id by player to save / restore your data

 

How could I set that up? I just need the stats to persist and update as you play?

Share this post


Link to post
Share on other sites
databaseplayers = ["new", "databaseplayers"] call OO_INIDBI;

instead of using databaseplayers, try with a unique id by player like name or other things you want.

Share this post


Link to post
Share on other sites
8 minutes ago, code34 said:

databaseplayers = ["new", "databaseplayers"] call OO_INIDBI;

instead of using databaseplayers, try with a unique id by player like name or other things you want.

But is there a way to just add in a save/read function for my current list? Because the way I have the leaderboard UI setup Its grabbing the list from the databaseplayers DB

Share this post


Link to post
Share on other sites
55 minutes ago, Cole Slaughter said:

How could I set that up? I just need the stats to persist and update as you play?

you could try using the method i have setup and posted above. on the server create 2 publicVariableEventHandlers, one to check and one to save(make sure to execVM the .sqf file that these are in when the mission loads before any client will connect for added safety.

on the client(for example lets use initPlayerLocal) get some information from the player such as their UID, name, and clientID as we will be passing them to the servers check handler with publicVariableServer

_id = getPlayerUID player;//players UID
_name = name player;//name of player duh
_cId = clientOwner;//client id
playerCheckInfo = [_id, _name, _cId];//array to pass that info to the eventhandler
publicVariableServer "playerCheckInfo";//call event handler with the array being passed

this will run the publicVariableEventHandlers on the server that is called "playerCheckInfo". inside of that eventHandler setup something like this that will use the "new" command and then the "exist" command to check if the player already has a file with their UID. do so like this

"playerCheckInfo" addPublicVariableEventHandler//the eventhandler that should of already been ran when the mission starts
{
	private ["_data"];
	_data = _this select 1;//define _data using private and set it equal to _this select 1 which is the information that was passed to this event handler. 							  //if you did _this select 0 then it just selects the name of the eventHandler
	_id = _data select 0;//sets _id to the players UID/first part of information passed
	_name = _data select 1;//sets _name to the players name/second part of information passed
	_cId = _data select 2;//sets _cId to the players clientID/third part of information passed
	
	_inidbi = ["new", _id] call OO_INIDBI;//create a new class object with the name _inidbi
	_dataExist = "exists" call _inidbi;//check if a file exists with the file name of the players UID
	
	if (_dataExist) then//if it exists then run a .sqf file that will be used to get the information and store it onto the player
	{
		null = [_id, _cId] execVM "loadData.sqf";//pass in the players id for the check, and their clientID so we can run publicVariableClient on their 												 //client
	}
	else//if it doesnt exist then run a .sqf file to create the file with the wanted information
	{
		null = [_id, _name] execVM "createNewDatabase.sqf";//pass in stuff you want such as the id(needed) and players name
	};
};

inside of createNewDatabase do this

//players name and UID were passed into this file so
_id = _this select 0;//store players UID
_name = _this select 1;//store players name

_inidbi = ["new", _id] call OO_INIDBI;//create a new class

//this is what creates the actual file for us to see
["write", ["PlayerInfo", "Name", _name]] call _inidbi;//create a section for the players info with their name and other details that you want to store
["write", ["PlayerStats", "Kills", 0]] call _inidbi;//section for their stats such as kills and set it to 0(since first time joining)
//do the same for the rest of what you want

ok now that its setup so it creates a database if its the players first time joining, we can work on loadData.sqf so when he reconnects it just loads the data from the file like this

//players UID and clientID were passed into this file so
_id = _this select 0;
_cId = _this select 1;

_inidbi = ["new", _id] call OO_INIDBI;//create a new class
_kills = ["read", ["PlayerStats", "Kills", []]] call _inidbi;//reads from PlayerStats section and the Kills portion and stores in _kills


loadData = [_kills];//when you have more stuff just put it in here but create array loadData

_cId publicVariableClient "loadData";//pass loadData to the player whos clientID matches the one that is stored in _cId

so this will execute the eventhandler called loadData that is on the client so we will just need to store the info passed into whatever variable we want(using just a global variable for this example)

//literally does the same thing as the servers event handler so not gonna bother commenting through
"loadData" addPublicVariableEventHandler
{
	private ["_data"];
	_data = _this select 1;
	_kills = _data select 0;

	kills = _kills;//since _kills was passed into this eventHandler, set your kills variable to equal it. so kills should now be equal to what was in the file
};

as for how to save the data, it depends on how you want it done. im assuming your variables are being updated constantly on the client so you could make an eventhandler that runs when the player dies or reconnects and have it call a file that does the same thing as the first part of the post but instead of calling playerCheckInfo call it playerSave pass in the stuff such as kills/shots fired or whatever and inside the new playerSave event handler just have it write to the file in the exact same way as playerCheckInfo did.

Share this post


Link to post
Share on other sites
2 minutes ago, gokitty1199 said:

you could try using the method i have setup and posted above. on the server create 2 publicVariableEventHandlers, one to check and one to save(make sure to execVM the .sqf file that these are in when the mission loads before any client will connect for added safety.

on the client(for example lets use initPlayerLocal) get some information from the player such as their UID, name, and clientID as we will be passing them to the servers check handler with publicVariableServer


_id = getPlayerUID player;//players UID
_name = name player;//name of player duh
_cId = clientOwner;//client id
playerCheckInfo = [_id, _name, _cId];//array to pass that info to the eventhandler
publicVariableServer "playerCheckInfo";//call event handler with the array being passed

this will run the publicVariableEventHandlers on the server that is called "playerCheckInfo". inside of that eventHandler setup something like this that will use the "new" command and then the "exist" command to check if the player already has a file with their UID. do so like this


"playerCheckInfo" addPublicVariableEventHandler//the eventhandler that should of already been ran when the mission starts
{
	private ["_data"];
	_data = _this select 1;//define _data using private and set it equal to _this select 1 which is the information that was passed to this event handler. 							  //if you did _this select 0 then it just selects the name of the eventHandler
	_id = _data select 0;//sets _id to the players UID/first part of information passed
	_name = _data select 1;//sets _name to the players name/second part of information passed
	_cId = _data select 2;//sets _cId to the players clientID/third part of information passed
	
	_inidbi = ["new", _id] call OO_INIDBI;//create a new class object with the name _inidbi
	_dataExist = "exists" call _inidbi;//check if a file exists with the file name of the players UID
	
	if (_dataExist) then//if it exists then run a .sqf file that will be used to get the information and store it onto the player
	{
		null = [_id, _cId] execVM "loadData.sqf";//pass in the players id for the check, and their clientID so we can run publicVariableClient on their 												 //client
	}
	else//if it doesnt exist then run a .sqf file to create the file with the wanted information
	{
		null = [_id, _name] execVM "createNewDatabase.sqf";//pass in stuff you want such as the id(needed) and players name
	};
};

inside of createNewDatabase do this


//players name and UID were passed into this file so
_id = _this select 0;//store players UID
_name = _this select 1;//store players name

_inidbi = ["new", _id] call OO_INIDBI;//create a new class

//this is what creates the actual file for us to see
["write", ["PlayerInfo", "Name", _name]] call _inidbi;//create a section for the players info with their name and other details that you want to store
["write", ["PlayerStats", "Kills", 0]] call _inidbi;//section for their stats such as kills and set it to 0(since first time joining)
//do the same for the rest of what you want

ok now that its setup so it creates a database if its the players first time joining, we can work on loadData.sqf so when he reconnects it just loads the data from the file like this


//players UID and clientID were passed into this file so
_id = _this select 0;
_cId = _this select 1;

_inidbi = ["new", _id] call OO_INIDBI;//create a new class
_kills = ["read", ["PlayerStats", "Kills", []]] call _inidbi;//reads from PlayerStats section and the Kills portion and stores in _kills


loadData = [_kills];//when you have more stuff just put it in here but create array loadData

_cId publicVariableClient "loadData";//pass loadData to the player whos clientID matches the one that is stored in _cId

so this will execute the eventhandler called loadData that is on the client so we will just need to store the info passed into whatever variable we want(using just a global variable for this example)


//literally does the same thing as the servers event handler so not gonna bother commenting through
"loadData" addPublicVariableEventHandler
{
	private ["_data"];
	_data = _this select 1;
	_kills = _data select 0;

	kills = _kills;//since _kills was passed into this eventHandler, set your kills variable to equal it. so kills should now be equal to what was in the file
};

 

I will try this, thank you!

Share this post


Link to post
Share on other sites
1 minute ago, Cole Slaughter said:

I will try this, thank you!

just a random note i updated it a tad after you replied about how to regularly save it

Share this post


Link to post
Share on other sites

im not sure if anyone will find this of much use here but i made a few tutorials starting from how to install inidbi2 and how to check/create a database file and then how to retrieve from the file and write to the file(saving). its not the greatest but it may be enough to get someone going since there is not much in relation to how to use it.

 

 

 

 

  • Like 1
  • Thanks 2

Share this post


Link to post
Share on other sites

hI

2 hours ago, gokitty1199 said:

im not sure if anyone will find this of much use here but i made a few tutorials starting from how to install inidbi2 and how to check/create a database file and then how to retrieve from the file and write to the file(saving). its not the greatest but it may be enough to get someone going since there is not much in relation to how to use it.

 

 

 

 

 

Nice work gotikitty1199, i'm pretty sure, it will help a lot of peoples :)

 

  • Like 4

Share this post


Link to post
Share on other sites
8 minutes ago, code34 said:

hI

 

Nice work gotikitty1199, i'm pretty sure, it will help a lot of peoples :)

 

well you made, this is a great alternative for a simple persistent setup so thank you

  • Like 1

Share this post


Link to post
Share on other sites
On 13/12/2017 at 6:38 AM, bullkanox said:

Hi, im create this script.

InitPlayerLocal.sqf ------------ Auto init / Intro Black Screen / Check Database / Wait Time For Charges / Create Profile (if no exists) / Load Profile (if exists) / Autosave Profile for 5 Minutes (Optional)

Save_Profile.sqf----------------- Check Database / Save Profile / Save: Location+Direction+Oxygen+Health+Inventory

Load_Profile.sqf----------------- Check Database / Load Profile / Load: Location+Direction+Oxygen+Health+Inventory

 

Im job for more options and updates, example Save/Load: Vehicles, Ranking, etc...  

 

InitPlayerLocal.sqf


//////////////////////////////////////////////////////////////////
// Function file for:	Arma 3
// Created by:			Savage
// Clan: 				CalaverasCMP
// Web : 				www.CalaverasCMP.com
//////////////////////////////////////////////////////////////////

// Auto init /////////////////////////////////////////////////////

sleep 0.001; // Wait time.
titleCut ["", "BLACK FADED", 999]; // Start black screen intro

_player = _this select 0;
// _player = player; // You
_player_id = getPlayerUID player; // Number of Steam ID
_player_name = profileName; // Name of player

_db = ["new", _player_id] call OO_INIDBI; // Call database
_check_db = "exists" call _db; // Check if database exists, if exists return TRUE, if not the result is FALSE
// systemChat format ["DataBase exists: ---%1---", _check_db]; //Debug

sleep .001; // Wait time

if (_check_db) then { // If _check_db is TRUE load this

	_load_profile = execVM "Load_Profile.sqf"; // Execute SQF
	sleep .001;	// Wait Time
	titleText ["Loading Your Profile...\n\nPlease Wait!","PLAIN", 5]; // Show text on center screen
	titleFadeOut 2;
	sleep 10; // Wait time
	
	} else { // If _check_db is FALSE load this
	
	_save_profile = execVM "Save_Profile.sqf"; // Execute SQF
	sleep .001; // Wait time
	titleText ["Creating your profile...\n\nPlease wait!","PLAIN", 5]; // Show text on center screen
	titleFadeOut 2;
	sleep 10; // Wait time
};

sleep .001; // Wait time

"dynamicBlur" ppEffectEnable true;   
"dynamicBlur" ppEffectAdjust [6];   
"dynamicBlur" ppEffectCommit 0;     
"dynamicBlur" ppEffectAdjust [0.0];  
"dynamicBlur" ppEffectCommit 5;  
	
titleCut ["", "BLACK IN", 5]; // Close black screen

sleep 2; // Wait time

// Auto Save Profile /////////////////////////////////////////////
[]spawn {
	while {true} do {
	sleep 300; // wait time (300 Seconds = 5 Minutes).
	_auto_save_profile = execVM "Save_Profile.sqf"; // Execute SQF
	systemChat "Profile Save"; // Show message on system chat
	};
};
//////////////////////////////////////////////////////////////////

 

Save_Profile.sqf


//////////////////////////////////////////////////////////////////
// Function file for:	Arma 3
// Created by:			Savage
// Clan: 				CalaverasCMP
// Web : 				www.CalaverasCMP.com
//////////////////////////////////////////////////////////////////

// Save Profile //////////////////////////////////////////////////

// _player = _this select 1;
_player = player; // You
_player_id = getPlayerUID player; // Number of Steam ID
_player_name = profileName; // Name of player

_db = ["new", _player_id] call OO_INIDBI; // Call database
_check_db = "exists" call _db; // Check if database exists, if exists return TRUE, if not the result is FALSE
// systemChat format ["DataBase exists: ---%1---", _check_db]; //Debug

sleep .002; // Wait time

//============	Save Stats
//PLAYER
_write_db = ["write", [_player_name, "location", position _player]] call _db;
_write_db = ["write", [_player_name, "direction", getDir _player]] call _db;
_write_db = ["write", [_player_name, "oxygen", getOxygenRemaining _player]] call _db;
_write_db = ["write", [_player_name, "health", damage _player]] call _db;

//INVENTORY
_write_db = ["write", [_player_name, "getUnitLoadout", getUnitLoadout _player]] call _db;

sleep .002;// Wait Time

systemChat "Save Profile Complete"; // Show System Chat

 

Load_Profile.sqf


//////////////////////////////////////////////////////////////////
// Function file for:	Arma 3
// Created by:			Savage
// Clan: 				CalaverasCMP
// Web : 				www.CalaverasCMP.com
//////////////////////////////////////////////////////////////////

// Load Profile //////////////////////////////////////////////////

// _player = _this select 1;
_player = player; // You
_player_id = getPlayerUID player; // Number of Steam ID
_player_name = profileName; // Name of player

_db = ["new", _player_id] call OO_INIDBI; // Call database
_check_db = "exists" call _db; // Check if database exists, if exists return TRUE, if not the result is FALSE
// systemChat format ["DataBase exists: ---%1---", _check_db]; //Debug

sleep .002; // Wait time

//============	Load Stats
// PLAYER
_read_db = ["read", [_player_name, "location"]] call _db;
_player setPos _read_db;
sleep .001;

_read_db = ["read", [_player_name, "direction"]] call _db;
_player setDir _read_db;
sleep .001;

_read_db = ["read", [_player_name, "health"]] call _db;
_player setDamage _read_db;
sleep .001;

_read_db = ["read", [_player_name, "oxygen"]] call _db;
_player setOxygenRemaining _read_db;
sleep .001;

// INVENTORY
_read_db = ["read", [_player_name, "getUnitLoadout"]] call _db;
_player setUnitLoadout _read_db;
sleep .001;

systemChat "Load Profile Complete";

Thanks for this mod......[Code34]...........!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Thanks for this Bullkanox, i'm pretty new to all of this and this is helping me in the right direction, however.

 

When i try to use it, it wont load any of the locations, or loadout. It saves it all in the database however. Im just not sure on how else i can approach this. 

 

In my db i have 

 

[[STD]Hash_Cookie]
location="[1303.9,3049.09,0.00126255]"
[[STD]Hash_Cookie]
direction="220.256"
[[STD]Hash_Cookie]
oxygen="1"
[[STD]Hash_Cookie]
health="0"
[[STD]Hash_Cookie]
getUnitLoadout="[,[],""],[],["PstlTool_Spotlight","","","",[],[],""],["U_MilitiaUniTShirt_G",[]],["V_LegStrapBag_black_F",[]],["B_AssaultPack_blk",[["5Rnd_792x57_Kar98",9,5]]],"H_Hat_Boonie_Cowboy","",[],["ItemMap","","","","tf_microdagr",""]]"
[[STD]Hash_Cookie]
location="[1269.97,3032.45,0.00135469]"
[[STD]Hash_Cookie]
direction="154.287"
[[STD]Hash_Cookie]
oxygen="1"
[[STD]Hash_Cookie]
health="0"
[[STD]Hash_Cookie]
getUnitLoadout="[["Bolt792x57_CZ550","","","",["5Rnd_792x57_Kar98",5],[],""],[],["PstlTool_Spotlight","","","",[],[],""],["U_MilitiaUniTShirt_G",[]],["V_LegStrapBag_black_F",[]],["B_AssaultPack_blk",[["5Rnd_792x57_Kar98",9,5]]],"H_Hat_Boonie_Cowboy","",[],["ItemMap","","","","tf_microdagr",""]]"
 

I havent added anything to your script except changing the auto save to make it sooner so i can test it out, any help from anyone? 

 

Error that keeps coming up is on line 24 of load_profile, unexpected bool.

 

I hope its not too newbie to ask for help :) 

Share this post


Link to post
Share on other sites
21 hours ago, HashCookie said:

 

 

Error that keeps coming up is on line 24 of load_profile, unexpected bool.

 

I hope its not too newbie to ask for help :) 

you need a third parameter 

How yours was without the third parameter
_read_db = ["read", [_player_name, "location"]] call _db;

With the third parameter
_read_db = ["read", [_player_name, "location", []]] call _db;

 

load_profile

//////////////////////////////////////////////////////////////////
// Function file for:	Arma 3
// Created by:			Savage
// Clan: 				CalaverasCMP
// Web : 				www.CalaverasCMP.com
//////////////////////////////////////////////////////////////////

// Load Profile //////////////////////////////////////////////////

// _player = _this select 1;
_player = player; // You
_player_id = getPlayerUID player; // Number of Steam ID
_player_name = profileName; // Name of player

_db = ["new", _player_id] call OO_INIDBI; // Call database
_check_db = "exists" call _db; // Check if database exists, if exists return TRUE, if not the result is FALSE
// systemChat format ["DataBase exists: ---%1---", _check_db]; //Debug

sleep .002; // Wait time

//============	Load Stats
// PLAYER
_read_db = ["read", [_player_name, "location", []]] call _db;
_player setPos _read_db;
sleep .001;

_read_db = ["read", [_player_name, "direction", []]] call _db;
_player setDir _read_db;
sleep .001;

_read_db = ["read", [_player_name, "health", []]] call _db;
_player setDamage _read_db;
sleep .001;

_read_db = ["read", [_player_name, "oxygen", []]] call _db;
_player setOxygenRemaining _read_db;
sleep .001;

// INVENTORY
_read_db = ["read", [_player_name, "getUnitLoadout", []]] call _db;
_player setUnitLoadout _read_db;
sleep .001;

systemChat "Load Profile Complete";

 

Share this post


Link to post
Share on other sites
On 24/06/2018 at 11:46 AM, gokitty1199 said:

you need a third parameter 


How yours was without the third parameter
_read_db = ["read", [_player_name, "location"]] call _db;

With the third parameter
_read_db = ["read", [_player_name, "location", []]] call _db;

 

load_profile


//////////////////////////////////////////////////////////////////
// Function file for:	Arma 3
// Created by:			Savage
// Clan: 				CalaverasCMP
// Web : 				www.CalaverasCMP.com
//////////////////////////////////////////////////////////////////

// Load Profile //////////////////////////////////////////////////

// _player = _this select 1;
_player = player; // You
_player_id = getPlayerUID player; // Number of Steam ID
_player_name = profileName; // Name of player

_db = ["new", _player_id] call OO_INIDBI; // Call database
_check_db = "exists" call _db; // Check if database exists, if exists return TRUE, if not the result is FALSE
// systemChat format ["DataBase exists: ---%1---", _check_db]; //Debug

sleep .002; // Wait time

//============	Load Stats
// PLAYER
_read_db = ["read", [_player_name, "location", []]] call _db;
_player setPos _read_db;
sleep .001;

_read_db = ["read", [_player_name, "direction", []]] call _db;
_player setDir _read_db;
sleep .001;

_read_db = ["read", [_player_name, "health", []]] call _db;
_player setDamage _read_db;
sleep .001;

_read_db = ["read", [_player_name, "oxygen", []]] call _db;
_player setOxygenRemaining _read_db;
sleep .001;

// INVENTORY
_read_db = ["read", [_player_name, "getUnitLoadout", []]] call _db;
_player setUnitLoadout _read_db;
sleep .001;

systemChat "Load Profile Complete";

 

Ahh! Even an amateur like me should have seen that. About to give it a go, thanks for the reply! 

 

Ohkk getting an error in expression now. I feel like its so close, just missing something... But even still i have to figure out why the database isnt fully overwriting, just adding to the data... 

 

21:16:50 Error in expression <ame, "location", []]] call _db;
_player setPos _read_db;
sleep .001;

_read_db =>
21:16:50   Error position: <setPos _read_db;
sleep .001;

_read_db =>
21:16:50   Error 0 elements provided, 3 expected
21:16:50 File C:\Users\ashst\Documents\Arma 3 - Other Profiles\[STD]Hash_Cookie\missions\[test].Tanoa\Load_Profile.sqf, line 24
21:16:50 Error in expression <me, "direction", []]] call _db;
_player setDir _read_db;
sleep .001;

_read_db =>
21:16:50   Error position: <setDir _read_db;
sleep .001;

_read_db =>
21:16:50   Error setdir: Type Array, expected Number
21:16:50 File C:\Users\ashst\Documents\Arma 3 - Other Profiles\[STD]Hash_Cookie\missions\[test].Tanoa\Load_Profile.sqf, line 28

Edited by HashCookie
Update

Share this post


Link to post
Share on other sites

Hey guys, So after crushing it down for a week i have finally come down to a working database. I cannot take all the credit because i scrapped and researched from many scripts. 

 

Credits to:

Bullkanox, Gokitty1199, Mr.Jizz and of course Code34

 

However i must add, Gokitty1199, excellent videos detailing on the database, however i did find that dumping everything you put into init.sqf into initplayerlocal.sqf made it so then everyones data gets saved and read instead of the first person who joins the server only. Small change but other than that it works well. I cannot wait to get onto some of the other content you have made for scripting. As i said before im amateur at this so i expected to be blindfolded pinning the tail on the donkey and it helped me out immensely. 

 

I am posting the barebones of this so someone else like me doesnt have to dig around for a week trying to get something to work. 

 

initplayerlocal.sqf

Quote

sleep 0.001; // Wait time.
titleCut ["", "BLACK FADED", 999]; // Start black screen intro
sleep 5;


_clientID = clientOwner;
_UID = getPlayerUID player;
_name = name player;
checkForDatabase = [_clientID, _UID, _name];
publicVariableServer "checkForDatabase";

player addAction ["save data" ,
{
     _UID = getPlayerUID player;
     _gear = getunitloadout player;
     _pos = getPosATL player;
     saveData = [_UID, _gear, _pos];
     publicVariableServer "saveData";
}];

"loadData" addPublicVariableEventHandler
{
     _gear = (_this select 1);     
    player setunitLoadout _gear;     
            
};

"loadpos" addPublicVariableEventHandler
{
     _pos = (_this select 1);     
    player setPosATL _pos;     
            
};

"dynamicBlur" ppEffectEnable true;   
"dynamicBlur" ppEffectAdjust [6];   
"dynamicBlur" ppEffectCommit 0;     
"dynamicBlur" ppEffectAdjust [0.0];  
"dynamicBlur" ppEffectCommit 5;  
    
titleCut ["", "BLACK IN", 5]; // Close black screen

sleep 5; // Wait time

[]spawn {
    while {true} do {
    sleep 15; // wait time (300 Seconds = 5 Minutes).
    _auto_save_profile = execVM "autosave.sqf"; // Execute SQF
    systemChat "Profile Save"; // Show message on system chat
    };
};
 

 

initserver.sqf

Quote

"checkForDatabase" addPublicVariableEventHandler
{
     private ["_data"];
     _data = (_this select 1);
     _clientID = (_data select 0);
     _UID = (_data select 1);
     _playerName = (_data select 2);
     
     _inidbi = ["new", _UID] call OO_INIDBI;
     _fileExist = "exists" call _inidbi;
     
     if (_fileExist) then
     {
     null = [_UID, _clientID] execVM "getdata.sqf";
     }
     else
     {
     null = [_clientID, _UID, _playerName] execvm "createDatabase.sqf";
     };
};

"saveData" addPublicVariableEventHandler
{
      private ["_data"];
     _data = (_this select 1);
     _UID = (_data select 0);
     _gear = (_data select 1);
     _pos = (_data select 2);
     
     _inidbi = ["new", _UID] call OO_INIDBI;
     
     ["write", ["Player Gear", "Gear", _gear]] call _inidbi;
     
     ["write", ["Player Pos", "Pos", _pos]] call _inidbi;
};

 

createDatabase.sqf

Quote

_clientID = (_this select 0);
_UID = (_this select 1);
_playerName = (_this select 2);

_inidbi = ["new", _UID] call OO_INIDBI;

["write", ["Player Info", "Name", _playername]] call _inidbi;

 

getData.sqf

Quote

_UID = (_this select 0);
_clientID = (_this select 1);

_inidbi = ["new", _UID] call OO_INIDBI;

_gear = ["read", ["Player Gear", "Gear", []]] call _inidbi;

_pos = ["read", ["Player Pos", "Pos", []]] call _inidbi;

loadData = _gear;
loadpos = _pos;
_clientID publicVariableClient "loadData"; 

_clientID publicVariableClient "loadpos"; 

 

Autosave.sqf

Quote

_UID = getPlayerUID player;
     _gear = getunitloadout player;
     _pos = getPosATL player;
     saveData = [_UID, _gear, _pos];
     publicVariableServer "saveData";

 

I might also add Ammobox persistancy aswell, fixed marcys3's script, it deleted all content when another player joins in. Just be sure that when you place down the ammobox, its contents are deleted. 

 

ammobox init

Quote

null = [this] execVM "load_box.sqf";null = [this] execVM "save_box.sqf"

 

load_box.sqf

Quote

_object = _this select 0;


_inidbi = ["new", "crates"] call OO_INIDBI;

_items = ["read", ["box", "locker"]] call _inidbi;


if(!(_items isEqualTo [])) then
        {
            {
                _subArr = _items select _forEachIndex;
                _weps = _subArr select 0;
                _wepsCount = _subArr select 1;
                _mags = _subArr select 2;
                _magsCount = _subArr select 3;
                _itemss = _subArr select 4;
                _itemsCount = _subArr select 5;
                _backpacks = _subArr select 6;
                _backpacksCount = _subArr select 7;
                {
                    _object addWeaponCargoGlobal[_x,_wepsCount select _forEachIndex];
                } forEach _weps;
                {
                    _object addMagazineCargoGlobal[_x,_magsCount select _forEachIndex];
                } forEach _mags;
                {
                    _object addItemCargoGlobal[_x,_itemsCount select _forEachIndex];
                } forEach _itemss;
                {
                    _object addBackpackCargoGlobal[_x,_backpacksCount select _forEachIndex];
                } forEach _backpacks;
            } forEach _items;    
};
 

 

Save_box.sqf

Quote

_object = _this select 0;


Sleep 1;
while {true} do {
Sleep 5;

_saveArray = [];
_guns = getWeaponCargo _object;
_mags = getMagazineCargo _object;
_items = getItemCargo _object;
_backpacks = getBackpackCargo _object;
_subArray = _guns + _mags + _items + _backpacks;
_saveArray set [count _saveArray,_subArray];

_inidbi = ["new", "crates"] call OO_INIDBI;


_bool=["write", ["box", "locker", _saveArray]] call _inidbi;


};

 

This had my mind in a jumble for a while so i really hope this helps out other people looking to do persistence with friends on their operations like me.

  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites

Hello folks, 

 

Firstly, I want to thank code34 for this mod. It has opened up so many possibilities for me, and I am so keen to get it working on my server. Also, thank you to gokitty1199, your videos made the impossible possible for me, and I could not have achieved what I have so far without your tutorials. I have learned a lot, so thank you!

 

Next, I want to apologise if the solution to what I am asking is completely obvious. I am by all accounts a very novice scripter, so perhaps the answer to my problem is right in front of my eyes and I just am too blind to see it.

 

I am trying to build a pilot's diary, simply to record the time spent in the heli. Now, using gokitty1199's tuts, and some googling, I have got something that works. Well, most of the time. The problem I am having is with the initial load of the DB info into the script. 

 

On first load into the server (and in case it matters, I am testing in the editor, using the MP option), the script does not work. My debug hints that trigger when you get in and out of the heli show that the data is not being passed into the script as it should on first accessing the server (i.e. when the DB is created initially). However, when I respawn and try again, it works completely fine. So, not a critical problem, but it's really doing my head in not understanding why X)

 

Could someone please explain where I am going wrong here? How do I get the flight data loaded correctly on first load of the server? I hope I have explained this properly..

 

My files:

 

init.sqf

Spoiler


_clientID = clientOwner;
_UID = getPlayerUID player;
_name = name player;

checkForDatabase = [_clientID, _UID, _name];
publicVariableServer "checkForDatabase";

"loadMasterData" addPublicVariableEventHandler
{
        private ["_data"];
        _data = (_this select 1);
        _name = (_data select 0);
        _mins = (_data select 1);

};

execVM "heli.sqf";

 

 

initServer.sqf

Spoiler


"checkForDatabase" addPublicVariableEventHandler
{
        private ["_data"];
        _data = (_this select 1);
        _clientID = (_data select 0);
        _UID = (_data select 1);
        _playerName = (_data select 2);
        _mins = (_data select 3);

        _inidbi = ["new", _UID] call OO_INIDBI;
        _fileExist = "exists" call _inidbi;
        
        if (_fileExist) then
        {
            hint format ["WELCOME BACK %1 - YOUR PROFILE HAS BEEN LOADED SUCCESSFULLY", _playerName]; 
            null = [_UID, _clientID] execVM "getData.sqf";
        }
        else
        {
            hint format ["WELCOME TO THE SERVER %1 - YOUR PROFILE HAS BEEN CREATED", _playerName]; 
            null = [_clientID, _UID, _playerName, _mins] execVM "createDatabase.sqf";
        };
};    

"saveFlightMins" addPublicVariableEventHandler 
{
        private ["_data"];
        _data = (_this select 1);
        _UID = (_data select 0);
        _minsFlown = (_data select 1);

        _inidbi = ["new", _UID] call OO_INIDBI;
        
        ["write", ["Pilot Data", "Minutes Flown", _minsFlown]] call _inidbi;    

};
 

 

createDatabase.sqf

Spoiler

 

_clientID = (_this select 0);
_UID = (_this select 1);
_playerName = (_this select 2);
 

_inidbi = ["new", _UID] call OO_INIDBI;

["write", ["Player Info", "Name", _playerName]] call _inidbi;
["write", ["Pilot Data", "Minutes Flown", 0]] call _inidbi; // 

 

 

getData.sqf

Spoiler

 

_UID = (_this select 0);
_clientID = (_this select 1);

_inidbi = ["new", _UID] call OO_INIDBI;

_name = ["read", ["Player Info", "Name", []]] call _inidbi;
_mins = ["read", ["Pilot Data", "Minutes Flown", []]] call _inidbi;

loadMasterData = [_name, _mins];
_clientID publicVariableClient "loadMasterData";

 

 

heli.sqf

Spoiler


pilotRank = 1; // not relevant, will be used to control who will have the diary feature

 

"loadMasterData" addPublicVariableEventHandler
{
        private ["_data"];
        _data = (_this select 1);
        _name = (_data select 0); 
        _mins = (_data select 1);
        loadedPilotMinutes = _mins;
        loadedName = _name;
};

 

player addEventHandler ["getInMan", {
    if (pilotRank == 1) then {
    flightStart = time;
    hint format ["Welcome back %1, your current flight time (in minutes) is: %2", loadedName, loadedPilotMinutes];    
    };
}];


player addEventHandler ["getOutMan", {
    if (pilotRank == 1 && alive player) then {
    flightEnd = time;
    totalPilotSeconds = round (flightEnd - flightStart);
    totalPilotMinutes = round (totalPilotSeconds / 60);

    _UID = getPlayerUID player;
    _mins = totalPilotMinutes + loadedPilotMinutes;
    saveFlightMins = [_UID, _mins];
    publicVariableServer "saveFlightMins";

    hint format ["Last Flight (mins) --- %1 Total Flight Time (mins) --- %2", totalPilotMinutes, _mins];
        
    };
}];

 

 

 

I have tried to resolve this on my own, and for the life of me I cannot get this to work on the first time the DB loads. 

 

@gokitty1199 @code34 Any advice gratefully appreciated!

 

PS. I have another blocker with load values, but I wanted to tackle my problems one at a time ;)

 

 

 

 

Edited by reggaeman007jah
added @ invites and tidied my spoilers a bit

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×