Modio
A binary file IO script designed specifically for modular SA:MP gamemodes.
Install / Use
/learn @Southclaws/ModioREADME
modio.inc
"modio" (modular IO) is a file reader/writer library for SA:MP that takes advantage of fblockread and fblockwrite.
How many numbers are on a clock?

A plaintext format such as INI or JSON would answer: 15 A binary file format such as modio would answer 12
Hopefully that analogy hooked your interest in this library!
This library is designed for modular gamemodes. Gamemodes that have a lot of different parts that must save to a single file. I wrote it with y_hooks/ALS in mind. For example: calling the modio write function to save player data in 10 OnPlayerDisconnect hooks will all save to the file using a single write operation, pretty cool huh?
Installation
Simply install to your project:
sampctl package install Southclaws/modio
Include in your code and begin using the library:
#include <modio>
Usage
Code in module #1:
static
mod1_Data[MAX_PLAYERS][10]; // 10 cells are stored with each player
hook OnPlayerConnect(playerid) {
new
name[MAX_PLAYER_NAME],
filename[35];
GetPlayerName(playerid, name, MAX_PLAYER_NAME);
format(filename, 35, "users/%s.dat", name);
modio_read(filename, _T<M,O,D,1>, 10, mod1_Data[playerid]);
return 1;
}
hook OnPlayerDisconnect(playerid, reason) {
new
name[MAX_PLAYER_NAME],
filename[35];
GetPlayerName(playerid, name, MAX_PLAYER_NAME);
format(filename, 35, "users/%s.dat", name);
modio_push(filename, _T<M,O,D,1>, 10, mod1_Data[playerid]);
return 1;
}
Code in module #2:
static
mod2_Data[MAX_PLAYERS][64]; // 64 cells are stored with each player
hook OnPlayerConnect(playerid) {
new
name[MAX_PLAYER_NAME],
filename[35];
GetPlayerName(playerid, name, MAX_PLAYER_NAME);
format(filename, 35, "users/%s.dat", name);
modio_read(filename, _T<M,O,D,2>, 64, mod1_Data[playerid]);
return 1;
}
hook OnPlayerDisconnect(playerid, reason) {
new
name[MAX_PLAYER_NAME],
filename[35];
GetPlayerName(playerid, name, MAX_PLAYER_NAME);
format(filename, 35, "users/%s.dat", name);
modio_push(filename, _T<M,O,D,2>, 64, mod1_Data[playerid]);
return 1;
}
Here we can see two different scripts hooking OnPlayerConnect and OnPlayerDisconnect each pushing some data related to the player that is unique and specific to that script. The file is only opened and written to once because modio is clever, it knows when the last push is called.
The process is exactly the same for reading, one simple function call in each hook.
How it works
Each piece of data is tagged with a 4 character (32 bit) cell so sections of data from different scripts can be named - that's what the _T<M,O,D,1> and _T<M,O,D,2> things were. The weird syntax packs the characters into a single cell.
The data is stored in a partially non-order-dependent structure since the hook order is usually indeterminate anyway so the tags are used to search for data.
This is what modio's binary structure looks like:
cell size in bytes
HEADER
filever 4
numbyte 4
numtags 4
taglist numtags * 8
[
tagname 4
physpos 4
]
BODY
tagbody numtags * (n tagsize)
[
tagname 4
tagsize 4
tagdata tagsize * 4
]
I'll go through each section and explain it:
Header
-
filever (1 cell) A single number which identifies which version of modio is required to read the file.
-
numbyte (1 cell) The size of the header and body in cells (4 bytes per cell).
-
numtags (1 cell) The number of tags/data sections in the file.
-
taglist (numtags x 2 cells) A list of tags in the file; each item in this list has two elements:
- tagname (1 cell) The 4 character tag name
- physpos (1 cell) The physical position of the actual data block (offset from first body cell. First tag always has a physpos of 0)
Body
-
data block
- tagname (1 cell) The 4 character tag name
- tagsize (1 cell) The amount of cells stored in the block (not including these first two cells)
- tagdata (tagsize cells) The actual data
Known Issues
modio_pushinOnGameModeExiton gamemode restarts/exits- Since the write function uses a very short timer to perform a single write after all of the
modio_pushcalls are done, calling it onOnGameModeExitmeans the timer is never called since the script stops completely after this callback. The current fix for this is to just write the entire file each timemodio_pushis called.
- Since the write function uses a very short timer to perform a single write after all of the
modio_pushinOnPlayerDisconnecton gamemode restarts/exits- Saving data on
OnPlayerDisconnectis also problematic when restarting or exiting the gamemode. The fix for this is manual unfortunately: the user must write a loop inOnGameModeExitthat callsmodio_finalise_writefor each user file being written to.
- Saving data on
Testing
To test, simply run the package:
sampctl package run
And connect to localhost:7777 to test.
