Jump to content
Sign in to follow this  
SicSemperTyrannis

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

Recommended Posts

Version: 1.0

Download: http://www.mediafire.com/?yzm429w3v5yvv5m

README:

iniDB - A simple server-side database extension using INI files (and more)

----------------------------------------------------------------------------------------------

Author:

SicSemperTyrannis

Support:

http://raiderbattalion.enjin.com/

How to use:

To use "iniDB" in your mission, install the extension in your ARMA2 or ARMA3 directory by copying the entire "@inidb" folder included in the download to your root directory.

Don't forget to copy over over or create the /db/ folder.

It should look like: /Arma 3/@inidb/iniDB.dll

It should look like: /Arma 3/@inidb/db/

It should look like: /Arma 3/@inidb/Addons/iniDB.pbo

Then in your mission init.sqf, somewhere before you want to use the functions do this:

call compile preProcessFile "\iniDB\init.sqf";

It should be noted that when you install the @inidb folder you can delete the /examples/ directory from there if you please, they serve no purpose in that folder.

You have permission to use, upload or otherwise distribute this as please, but don't hold me responsible for anything.

----------------------------------------------------------------------------------------------

CHANGELOG

13-March-2013

- Module

- Initial Release

- init.sqf

- Initial Release

DOCUMENTATION:

iniDB by SicSemperTyrannis

Support: http://raiderbattalion.enjin.com/

Function: iniDB_version

Usage: diag_log call iniDB_version;

Output: 1.0

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_CRC32

Usage: diag_log "SicSemperTyrannis" call iniDB_CRC32;

Output: "204E6A8B"

Notes: This is a standard implementation and will match PHP and various other languages.

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_MD5

Usage: diag_log "SicSemperTyrannis" call iniDB_MD5;

Output: "ee89b42582c546fe47d17b14f6331bff"

Notes: This is a standard implementation and will match PHP and various other languages.

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_Base64Encode

Usage: diag_log "SicSemperTyrannis" call iniDB_Base64Encode;

Output: "U2ljU2VtcGVyVHlyYW5uaXM="

Notes: This is a standard implementation and will match PHP and various other languages.

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_Base64Decode

Usage: diag_log "U2ljU2VtcGVyVHlyYW5uaXM=" call iniDB_Base64Decode;

Output: "SicSemperTyrannis"

Notes: This is a standard implementation and will match PHP and various other languages.

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_exists

Usage: diag_log "myDatabaseFile" call iniDB_exists;

Output: true if the database exists as a file, false otherwise

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_delete

Usage: diag_log "myDatabaseFile" call iniDB_delete;

Output: true if the file was deleted successfully, false otherwise

Notes: If you are concerned about security, you can recompile the PBO/DLL without this function.

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_read

Usage: diag_log ["myDatabaseFile", "SicSemperTyrannis", "position"] call iniDB_read;

Output: "[1000.0, 1000.0, 1000.0]" (STRING)

Usage: diag_log ["myDatabaseFile", "SicSemperTyrannis", "position", "ARRAY"] call iniDB_read;

Output: [1000.0, 1000.0, 1000.0] (ARRAY)

Usage: diag_log ["myDatabaseFile", "SicSemperTyrannis", "health", "NUMBER"] call iniDB_read;

Usage: diag_log ["myDatabaseFile", "SicSemperTyrannis", "health", "SCALAR"] call iniDB_read;

Output: 100.0 (SCALAR/NUMBER)

Notes: If you do not pass a third parameter, the return value is always a string. If you pass a third parameter it must be "ARRAY", "NUMBER" or "SCALAR". SCALAR and NUMBER are the same thing, NUMBER is just an alias.

NUMBER/SCALAR will return a SCALAR type (number)

ARRAY will return an array type.

Anything else will return a string type.

----------------------------------------------------------------------------------------------------------------------------------------------

Function: iniDB_write

Usage: ["myDatabaseFile", "SicSemperTyrannis", "position", position player] call iniDB_write;

Usage: ["myDatabaseFile", "SicSemperTyrannis", "health", 100.0] call iniDB_write;

Usage: ["myDatabaseFile", "SicSemperTyrannis", "name", profileName player] call iniDB_write;

Output: true if the write succeeds, false otherwise.

Notes: The fourth parameter is assumed to be a string, array or number (scalar). If it is not, it will save as a string by default. This function automatically derives the type by the variable passed.

Please avoid saving strings or data with the character ' in it, it is an expected bug, but untested.

----------------------------------------------------------------------------------------------------------------------------------------------

Final Note: There are undocumented functions available by looking at the PBO source, but it serves little purpose trying to utilize them.

Please hash any sensitive information passed to your server with the MD5 or CRC functions.

Please give me credits if you use it in your mission! Not a big deal, you don't really have to, it'd just be a cool thing to do.

If you want a custom extension made, feel free to give me a shout! This one is simple and stupid, but I can do some amazing things, too.

You can save and load data persistently for your mission. Save money for players, inventories, etc. This is meant for servers but I guess it could be used for clients, too.

The PBO (SQF) and C++ source is included, no viruses and such here. Have fun.

Edited by SicSemperTyrannis
Made the title a little bit more clear
  • Like 3

Share this post


Link to post
Share on other sites

This has been a dream of mine for years in arma and I got to help get this man addicted to arma.

Share this post


Link to post
Share on other sites

To expand on the functionality a little bit:

http://forums.bistudio.com/showthread.php?148577-GET-SET-Loadout-(saves-and-loads-pretty-much-everything)

Combining with this script I can save data (position, loadout) in "savePlayerData.sqf":

_unit = _this;
_puid = getPlayerUID _unit;

if(!isServer) exitWith {};

if(_puid == "_SP_PLAYER_" || _puid == "") exitWith {};

// Allow users with multiple profiles to make new profiles and have new lives
// We want to use CRC hashes for the name because some people have spaces, weird characters or some other stuff so it's just better this way.
_profileName = _unit getVariable["profileName", ""];

if(_profileName == "") exitWith {};

_unitFileName = format["%1_%2", _puid, (_profileName call iniDB_CRC32)];

// We will save to the same file, but use different sections for each side
// We don't want cop uniforms/pos/etc saving over to insurgent or civilian sides
// This will mean persistent data will carry over _per occupation_, pretty neat right?
_sectionTitle = format["%1", side _unit];

// Actually save global data
[_unitFileName, _sectionTitle, "pos", position _unit] call iniDB_write;
[_unitFileName, _sectionTitle, "loadout", ([_unit] call getLoadout)] call iniDB_write;

And also load data from "loadPlayerData.sqf":

_unit = _this;
_puid = getPlayerUID _unit;

if(!isServer) exitWith {};

if(_puid == "_SP_PLAYER_" || _puid == "") exitWith {};

_profileName = _unit getVariable["profileName", ""];

if(_profileName == "") exitWith {};

_unitFileName = format["%1_%2", _puid, (_profileName call iniDB_CRC32)];
_sectionTitle = format["%1", side _unit];

_unit setPos ([_unitFileName, _sectionTitle, "pos", "ARRAY"] call iniDB_read);

[_unit, ([_unitFileName, _sectionTitle, "loadout", "ARRAY"] call iniDB_read)] spawn setLoadout;

This means if I save the player's data in a loop, leave the server and come back, my old position and loadout will be restored. Sort of like DayZ.

Note: I also put this in the client init

player setVariable["profileName", profileName, true]; //3rd var "true" reports it to the server

Well, that's it for my explaining!

EDIT:

It hasn't been tested, but I see no reason why this wouldn't work on ARMA 2 as well.

Edited by SicSemperTyrannis
  • Like 1

Share this post


Link to post
Share on other sites

It's a good idea, for a great many purposes an actual database is overkill.

Share this post


Link to post
Share on other sites

Great work! I've been looking for something like this for a while. I have encountered an issue, however.

I made a blank Stats.sqf in the db folder, but my save script doesn't seem to edit it:

["Stats", getPlayerUID player, "position", position player] call iniDB_write;
["Stats", getPlayerUID player, "hunger", Hunger] call iniDB_write;
["Stats", getPlayerUID player, "weapons", weapons player] call iniDB_write;
["Stats", getPlayerUID player, "magazines", magazines player] call iniDB_write;
["Stats", getPlayerUID player, "inventory", INV_InventarArray] call iniDB_write;

Does it matter if I use "getPlayerUID player" or "format["%1", getPlayerUID player]"?

Tested for Arma2 OA in editor (not dedicated)

Edited by eagledude4

Share this post


Link to post
Share on other sites

@eagledude4: No scripts actually go in the db folder. You shouldn't have to manually create any files at all in the db folder. It's reserved for storing ini files.

create a "Stats.ini" if you want "iniDB_exists" to return true.

EDIT: I have made a series of bad edits to this post, I'll get back to you.

---------- Post added at 08:25 ---------- Previous post was at 08:19 ----------

Okay, a couple of problems with your code.

Try doing

diag_log format["%1", (["Stats", getPlayerUID player, "position", position player] call iniDB_write)];

To log results, I suspect that diag_log is taking the array that's supposed to be passed to iniDB_write as a parameter to it's own function, rather than "_this" param to iniDB_write.

Also, you have a spelling error with "ARRAU". This will cause issues. You also don't read into any variables or log the result, you're just invoking "iniDB_read", which serves no real purpose.

Your first example looks alright though. (writing)

Edited by SicSemperTyrannis

Share this post


Link to post
Share on other sites

Thanks for the reply. I later realised that the DB format wasn't sqf :P I found out that the functions dont work in the editor, so that's why I was experiencing issues. The dial_log I used was successful in returning the array.

Edited by eagledude4

Share this post


Link to post
Share on other sites

It is always supposed to overwrite the old value, if you write to the same value. If you're getting different results I'll have to see your write code.

Share this post


Link to post
Share on other sites

Write code:

_Profile = format["%1", getPlayerUID player];

[_Profile, "playerData", "position", position player] call iniDB_write;
[_Profile, "playerData", "hunger", Hunger] call iniDB_write;
[_Profile, "playerData", "weapons", weapons player] call iniDB_write;
[_Profile, "playerData", "magazines", magazines player] call iniDB_write;
[_Profile, "playerData", "inventory", INV_InventarArray] call iniDB_write;

Edited by eagledude4

Share this post


Link to post
Share on other sites

It should always overwrite the old value, even if the value is the same it will overwrite it. Your code looks good, can you paste the ini file?

Share this post


Link to post
Share on other sites

Greetings I seem to have a issue with getting stuffs saved on the server and i'm not sure how to cause the server to save it, as on Local Server(hosted MP) It seems that only my GUID can save but no one's else.. How would i solve this issue?

I'm using

saveloadout.sqf

diag_log format["%1", (["Stats", getPlayerUID player, "position", position player] call iniDB_write)];
diag_log format["%1", (["Stats", getPlayerUID player, "loadout", player call getLoadout call iniDB_write)];
diag_log format["%1", (["Stats", getPlayerUID player, "backpack", backpack player] call iniDB_write)];
diag_log format["%1", (["Stats", getPlayerUID player, "vest", vest player] call iniDB_write)];
diag_log format["%1", (["Stats", getPlayerUID player, "uniform", uniform player] call iniDB_write)];
hint "Success";

But not enterily sure where to call it from, I'm trying to run from

player addaction ["Save Loadout", "saveloadout.sqf"];

in the init file, I'm kinda new to database features and it would be a great to get it working on our warfare server, Thanks.

  • Like 1

Share this post


Link to post
Share on other sites

Your code is probably executing on the client, not the server.

"player" is a local variable for the client, you should be executing it on the server.

Look at it like this: They don't have @inidb installed, if they did it might work but they're not required to do this.

What you want to do is make the saveLoadout.sqf function send data to the server scripts via some function designed to send that data.

For example,

player setVariable["triggerSave", true, true]; // the third "true" makes sure this is broadcast to the server

then on the server side

serverSaveData.sqf ->

if(!isServer) exitWith {};

{
if((_x getVariable["triggerSave", false])) then {
	// Save data to ini file here
};
} forEach allUnits;

You'd probably want to call this in a loop. To load the data you'd follow a similar concept.

Share this post


Link to post
Share on other sites

Could i possible Get in contact with you over steam or such for assistance? Its still not extreamly clear for me, Will send you a PM with my steam

Share this post


Link to post
Share on other sites

I am not really in the position to provide that sort of... intense support. I am actually pretty busy.

Once you understand the concept of client/server networking (there's wiki articles about it, too) it's not that hard to understand.

Share this post


Link to post
Share on other sites

Alrighty, im just unsure wich one of your last quotes goes where and how to call it to do something, But thanks for replying :)

---------- Post added at 20:10 ---------- Previous post was at 19:49 ----------

Alrighty, im just unsure wich one of your last quotes goes where and how to call it to do something, But thanks for replying :)

So i'll be having 1 sqf wich is clientsavedata.sqf wich simply does

player setVariable["triggerSave", true, true];

wich then shoud call upon the serversave.sqf that is

if(!isServer) exitWith {};
   {
if((_x getVariable["triggerSave", false])) then {
diag_log format["%1", (["Stats", getPlayerUID _x, "position", position _x] call iniDB_write)];
};
} forEach allUnits;

and init does

execVM "serversavedata.sqf";
execVM "clientsavedata.sqf";

and it would be called by something settings the value of varible to 0? Hmm.. start making sense unless im completly wrong

Edited by DukeRevenger

Share this post


Link to post
Share on other sites

EDIT: forgot init.sqf line :(

Edited by Kolmain

Share this post


Link to post
Share on other sites

God.. i cant figure out how to get this running non-local, What does the init file need to make clients auto save and then that it just loads the array on spawn

Share this post


Link to post
Share on other sites

this is very nice

Share this post


Link to post
Share on other sites

That seems about right, DukeRevenger. You also shouldn't forget to set triggerSave to false on the server after you've written the data, or if it's in a loop it'll just save continuously.

---------- Post added at 22:39 ---------- Previous post was at 22:37 ----------

God.. i cant figure out how to get this running non-local, What does the init file need to make clients auto save and then that it just loads the array on spawn

It isn't designed to make "clients auto save", if you want to save data to the client there is functions like http://community.bistudio.com/wiki/saveVar which I believe allow you to save to the local computer.

iniDB should be used for things that require saving on the server-side specifically.

EDIT: However, I will probably make an example mission soon for a simple gear save since so many people have asked for one.

Share this post


Link to post
Share on other sites

What i ment is more that "loop" each 10th second to save on server with auto save, I'm not fully into coding so my way of speaking may sound invalid :p

Share this post


Link to post
Share on other sites

If you want to automatically save and load, you don't need any code running on the client, probably.

serverSaveData.sqf:

while{true} do {
{
	if(isPlayer _x) then {
		// Save their data here
	};
} forEach allUnits;
};

Then in the player init (the character initialization) and respawn event handler, set their loadout.

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
Sign in to follow this  

×