[Include] [INC] SII 2.0.6 - Fast cache based INI Reader/Writer
#1

Slick's INI Include 2.0.6


I have decided to release an include of mine for reading/writing INI files. I wrote it some time ago after want of a faster solution than DINI. Rather than change to DJSON I still wanted to use INI files because they are simple and clean, and so this script was born.

Slick's INI Include works using a complete cache system that does all its manipulation in memory. When a file is opened, its transferred to memory where data can be read/written, deleted, etc and then wrote all back to the file when finished. Rather than opening/parsing/closing a file each time you want to access a entry. This means it is very fast.


Features
  • Speed - Thanks to the cache system, mass amounts of data can be read/written all in one go.
  • Security - Many tests have been performed to ensure the script is crash-proof in all situations.
  • Customization - Easily change the amount of supported string sizes, lines and more.
  • Compatibility - Backwards compatible with DINI files, follows the INI standard http://en.wikipedia.org/wiki/INI_file
  • Comments - Manually edit your files and place helpful comments (Semicolons ; indicate the start of a comment)
  • Easy - Even your mother could use this!

Benchmark
I performed some benchmarks using SII, DINI and the raw file functions. There were two tests performed over a number of times with the average results shown here. The first test involved creating a file, writing a key with a value and then removing the file. The second test did the same thing but with a mass number of entries being written which is where other solutions like DINI really begin to show their dull colours.

As you can see, SII is almost as fast as using the raw file functions on their own, around a 5 millisecond difference to be exact.


Tutorial
Basic player accounts with SII and DCMD
pawn Code:
#include <a_samp>
#include <SII> // Include SII.inc

#define dcmd(%1,%2,%3) if (!strcmp((%3)[1], #%1, true, (%2)) && ((((%3)[(%2) + 1] == '\0') && (dcmd_%1(playerid, ""))) || (((%3)[(%2) + 1] == ' ') && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1

new player_name[MAX_PLAYERS][MAX_PLAYER_NAME];
new bool: player_loggedin[MAX_PLAYERS];

main()
{

}

public OnGameModeInit()
{
    AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
    return 1;
}

public OnPlayerConnect(playerid)
{
    GetPlayerName(playerid, player_name[playerid], MAX_PLAYER_NAME);
    return 1;
}

public OnPlayerDisconnect(playerid)
{
    player_loggedin[playerid] = false;
    return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    dcmd(register, 8, cmdtext);
    dcmd(login, 5, cmdtext);
    return 0;
}

dcmd_register(playerid, params[])
{
    if (player_loggedin[playerid]) // Player is already registered and logged in
    {
        SendClientMessage(playerid, 0x0040FFAA, "You are already registered and logged in.");
        return 1;
    }
    else if (!params[0]) // No password was specified
    {
        SendClientMessage(playerid, 0x0040FFAA, "Usage: /register [password]");
        return 1;
    }
    else if (INI_Open("Users.ini")) // Try open "Users.ini"
    {
        new password[128];
        if (INI_ReadString(password, player_name[playerid], MAX_PLAYER_NAME)) // Is player already registered?
        {
            SendClientMessage(playerid, 0x0040FFAA, "You are already registred, please /login.");
        }
        else // Register player
        {
            INI_WriteString(player_name[playerid], params);
            SendClientMessage(playerid, 0x0040FFAA, "Registration successful.");
        }
        INI_Save(); // Save all the data we have written to "Users.ini"
        INI_Close(); // Remember to close open files when finished
        return 1;
    }
    SendClientMessage(playerid, 0x0040FFAA, "Registration failed."); // There was an error opening "Users.ini"
    return 1;
}

dcmd_login(playerid, params[])
{
    if (player_loggedin[playerid]) // Player is already logged in
    {
        SendClientMessage(playerid, 0x0040FFAA, "You are already logged in.");
        return 1;
    }
    else if (!params[0]) // No password was specified
    {
        SendClientMessage(playerid, 0x0040FFAA, "Usage: /login [password]");
        return 1;
    }
    else if (INI_Open("Users.ini")) // Try open "Users.ini"
    {
        new password[128];
        if (INI_ReadString(password, player_name[playerid], MAX_PLAYER_NAME)) // Read players data (if it exists)
        {
            if (!strcmp(password, params, false)) // Login player
            {
                player_loggedin[playerid] = true;
                SendClientMessage(playerid, 0x0040FFAA, "Login successful.");
            }
            else // Incorrect password
            {
                SendClientMessage(playerid, 0x0040FFAA, "Incorrect Password.");
            }
        }
        else // No data was found for the player
        {
            SendClientMessage(playerid, 0x0040FFAA, "Please /register first.");
        }
        INI_Close(); // Remember to close open files when finished, no need to save this time
        return 1;
    }
    SendClientMessage(playerid, 0x0040FFAA, "Login failed."); // There was an error opening "Users.ini"
    return 1;
}

// Other functions include INI_Exists("filename"), INI_WriteInt("key", value), INI_WriteFloat("key", Float: value),
// value = INI_ReadInt("key"), Float: value = INI_ReadFloat("key"), INI_RemoveEntry("key") and INI_Remove("filename").

Download (updated link)


Please post feedback and any bugs if you find them..
Enjoy
Reply
#2

Wow looks nice dude gonna Test it soon.Are u sure about the Backward Compatbilty =?
Reply
#3

Yep compatibly with DINI and most other INI files is supported
Reply
#4

Sorry I should have explained it better.

When INI_Open is called, the file is parsed to memory. Now lets say you use INI_WriteString to add some data (a line), it will write to memory, not the file. Only when you call INI_Save will everything be written back to the original file. Then lastly, you would call INI_Close which frees up memory ready for opening again (doesn't touch the file). So the only time the physical file is accessed is during INI_Open and INI_Save.

Hope that helped

EDIT: I redone the first post with a tutorial demonstrating a basic accounts system
Reply
#5

Quote:
Originally Posted by [DRuG
Slick ]
Sorry I should have explained it better.

When INI_Open is called, the file is parsed to memory. Now lets say you use INI_WriteString to add some data (a line), it will write to memory, not the file. Only when you call INI_Save will everything be written back to the original file. Then lastly, you would call INI_Close which frees up memory ready for opening again (doesn't touch the file). So the only time the physical file is accessed is during INI_Open and INI_Save.

Hope that helped

EDIT: I redone the first post with a tutorial demonstrating a basic accounts system
I guess you can also open every file on startup and write during the game to the memory, also reading from it. And when the game ends, it writes everything.

With game I mean calling OnGameModeInit and OnGameModeExit.
Reply
#6

Problem with mine atm.

Pawn:
Code:
	ownCar1owner = INI_ReadString("ownCar1owner");
		x = INI_ReadFloat("ownCar1x");
		y = INI_ReadFloat("ownCar1y");
		z = INI_ReadFloat("ownCar1z");
		f = INI_ReadFloat("ownCar1f");
		ownCar1 = AddStaticVehicle(560, x, y, z, f, 6, 0);

		ownCar2owner = INI_ReadString("ownCar2owner");
		x = INI_ReadFloat("ownCar2x");
		y = INI_ReadFloat("ownCar2y");
		z = INI_ReadFloat("ownCar2z");
		f = INI_ReadFloat("ownCar2f");
		ownCar2 = AddStaticVehicle(561, x, y, z, f, 6, 0);
Ini:
Code:
ownCar1owner=None
ownCar1x=1098
ownCar1y=-1774
ownCar1z=13.4
ownCar1f=268

ownCar2owner=None
ownCar2x=1098
ownCar2y=-1768
ownCar2z=13.4
ownCar2f=268
That is spawning the vehicle, but the first one faces the wrong direction and the second one is in completely the wrong place. Any ideas? (I've checked these co-ordinates and they're right).
Reply
#7

Code:
ownCar1owner=None
ownCar1x=1098
ownCar1y=-1774
ownCar1z=13.4
ownCar1f=268

ownCar2owner=None
ownCar2x=1098
ownCar2y=-1768
ownCar2z=13.4
ownCar2f=268
As far as I know, floats must not be alone, like, they must have a .0 on the end of it - otherwise are read as 0 - same for converting any other string to a float. So you should try changing that to this:
Code:
ownCar1owner=None
ownCar1x=1098.0
ownCar1y=-1774.0
ownCar1z=13.4
ownCar1f=268.0

ownCar2owner=None
ownCar2x=1098.0
ownCar2y=-1768.0
ownCar2z=13.4
ownCar2f=268.0

Also.. this part is wrong...
Code:
ownCar1owner = INI_ReadString("ownCar1owner");
Code:
ownCar2owner = INI_ReadString("ownCar2owner");
> stock INI_ReadString(dest[], const key[], maxlength = sizeof(dest))
You're using it wrong. Rather, It'd be:
Code:
INI_ReadString(ownCar1owner, "ownCar1owner");
Code:
INI_ReadString(ownCar2owner, "ownCar2owner");
Specify the size of the destination string if needed.


Oh yeah, if you're using it to store vehicles in that fashion, I'd suggest you increase the amount of lines, and store the XYZR like this, split using your own code by commas:
Code:
ownCar1pos=1098.0,-1774.0,13.4268.0,268.0
That results in a smaller file, and possibly even faster read/write speeds.


I've used SII for my entire gamemode - as far as I know, everything works perfectly.
Reply
#8

That still doesn't seem to work :S

EDIT: Those new string commands bring up an Argument mismatch error.
EDIT2: They cars spawn fine as long as I don't have the string stuff in there?

Works:
Code:
		new float:x, float:y, float:z, float:f;
		
		//INI_ReadString(ownCar1owner, "ownCar1owner");
		x = INI_ReadFloat("ownCar1x");
		y = INI_ReadFloat("ownCar1y");
		z = INI_ReadFloat("ownCar1z");
		f = INI_ReadFloat("ownCar1f");
		ownCar1 = AddStaticVehicle(560, x, y, z, f, 6, 0);
		
		//INI_ReadString(ownCar2owner, "ownCar2owner");
		x = INI_ReadFloat("ownCar2x");
		y = INI_ReadFloat("ownCar2y");
		z = INI_ReadFloat("ownCar2z");
		f = INI_ReadFloat("ownCar2f");
		ownCar2 = AddStaticVehicle(561, x, y, z, f, 6, 0);
Reply
#9

> EDIT: Those new string commands bring up an Argument mismatch error.
I was assuming the variables 'ownCar1owner' and 'ownCar2owner' were strings, since a string is what you're reading. Right now, you have declared them as a normal integer - therefore an argument type mismatch.
Reply
#10

Got it all working, thanks
Reply
#11

Quote:
Originally Posted by Wadabak
I guess you can also open every file on startup and write during the game to the memory, also reading from it. And when the game ends, it writes everything.

With game I mean calling OnGameModeInit and OnGameModeExit.
Not quite, you can only have one file open at a time, which is why you don't need file ID's. That's why I recommend you lay out your code similar to:
pawn Код:
if (INI_Open("filename"))
{
    // Functions here
    INI_Close();
}
To ensure any reading/writing functions don't get called if the file could not be opened. While this won't cause any direct problems, in a rare situation you might find you start manipulating data from another file that has been opened.

Glad to see you got it working Mazza101
Reply
#12

i like it, but can you add a "sections" support? If you do this it will be the best INI include ever i seen
Reply
#13

Works fine and is really easy to use.I'm going to use it for my Admin script .
I added some extra functions because I thought they might be usefull,at least if you change from DINI to SII .

>> pastebin<<
Reply
#14

Whoa awesome to see people using it after all this time I did actually start writing an updated version some time ago, seeing you guys are interested is the boost I needed to finish it, stay tuned!
Reply
#15

Quote:
Originally Posted by [DRuG
Slick ]
Whoa awesome to see people using it after all this time I did actually start writing an updated version some time ago, seeing you guys are interested is the boost I needed to finish it, stay tuned!
great, i hope we'll see something special )
Reply
#16

How does this compare in terms of speed with DJSon, I know that they write the information in different ways, but as it's not me that reads the INI's and rather the computer, I don't really care >.> As long as the computer's happy, I am too.
Reply
#17

any updates?
Reply
#18

Really nice Include
Reply
#19

Vry nice Script, use it everytime

But now i got following error:
Quote:

error 035: argument type mismatch (argument 1)

in
Код:
public untemp(string:playername)
{
	if(INI_Open("temp.ini"))
	{
	  INI_RemoveEntry(playername); //<<<<<<<<<<<<<<<<<<<<<<<<
	  INI_Save();
	  INI_Close();
	}
	return 1;
}
(Marked the error-line)

Hope on fast fix,
Trooper
Reply
#20

I'd sugges you use this code


Код:
public untemp(playername[])
{
	if(INI_Open("temp.ini"))
	{
	  INI_RemoveEntry(playername); //<<<<<<<<<<<<<<<<<<<<<<<<
	  INI_Save();
	  INI_Close();
	}
	return 1;
}
PS:It seems he didn't plan to release new update this year : o
Reply


Forum Jump:


Users browsing this thread: 4 Guest(s)