Mod [script] fonline-json

What's your opinion about this script?


  • Всего проголосовало
    8
Автор темы #1
Дата рег
22 Окт 2012
Сообщения
6
Симпатии
23
Sorry for English, I don't know Russian.

I don't expect that many people will find this script interesting, but maybe someone will find it useful. If not, at least writing it was fun.

FOnline-JSON is a module allowing you to load, save and work with JSON files in FOnline scripts. JSON is a lightweight data-interchange format, which can be used for example for configuration files or for any other data in human-readable form.

Why use it? JSON is a very popular format and unlike the .ini files or some custom data formats, its syntax is standardized. It has implementations in all popular programming languages, which means creating tools for the data stored in JSON is easier and less bug-prone. It's more simple and more compact than XML.

FOnline-JSON module will do all the hard work of parsing JSON data for you, and makes working with it a breeze (IMHO anyway). It will take care of errors in a convenient way, by returning Undefined JSON value instead of null pointers.

Installation
  1. Download the latest release from here: FOnline-JSON_v0.1.zip
  2. The release contains 2 files: json.fos and json_h.fos. Unzip the files into your scripts folder.
  3. In scripts.cfg file add json module to the server, client or mapper target (or all of them).
  4. If you use FOnline revision 399 or earlier open json_h.fos file and uncomment the line:
    Код:
    // #define _JSON_REV_PRE400

Important notes
  1. FOnline supports Unicode since revision 400. Earlier revisions won't show Unicode characters properly. Files must be encoded with UTF-8 (supporting other encodings would be too painful with pre-400).
  2. Other open issues can be checked here: https://github.com/rotators/fonline-json/issues
  3. The module isn't finished yet, but it's usable in 99% cases. The repository of the module is here: https://github.com/rotators/fonline-json

For the smartasses

If you feel like you are better in reading source codes than tutorials, head straight to the repository.


For the rest of us (tutorial)

Download the JSON file that will be used in the tutorial from here.

Note: In the tutorial, whenever I use italicized text, it means JSON values, not elements of AngelScript. So for example if you see Null, it means a JSON Null value, not a null pointer, etc.

Loading a JSON file

First of all, include FOnline-JSON header in the module that will be using JSON:

Код:
#include "json_h.fos"
To load a JSON file use JSONLoad function:

Код:
JSON@ poems = JSONLoad("poems.json");
What happens behind the scenes: file "poems.json" is parsed into a structure of JSON values and a handle to the root value is returned. In this case root value is an Array of Objects. JSON values are AngelScript objects sharing JSON interface, with one special case - the Undefined, which is a special value that means "no value".

Traversing a JSON structure

You can traverse the structure of JSON values using index operator. Use integer with the index operator to get an element of an Array and a string to get a property of an Object.

Код:
JSON@ poemYear = poems[0]["year"];
If you try to get something that doesn't exist, instead of script error the Undefined value is returned. Using index operator on Undefined also returns Undefined. It means you can safely traverse deeply nested JSON structures without validating every element of it - in the worst case you will end up with a handle to Undefined and a few wasted function calls.

You can use JSON::isUndefined() method to check if the value is Undefined:

Код:
if (poemYear.isUndefined())
{
	Log("No year? Oh noes."); return;
}
Similarly, you can check the type of a value using JSON::isArray() , JSON::isString() etc.

Retrieving primitve data from a JSON value

To retrieve primitive data from a JSON value object, use >> operator with a handle of the JSON value on the left side and a variable used as destination of the retrieval on the right side:

Код:
int year = 0;
poemYear >> year;
This will retrieve a value of poemYear into the year int. The value will be retrieved only if the type of the JSON value is compatible with the type of the variable used as destination of the retrieval. So in the example above, the value will be retrieved only if poemYear is a JSON Number. Otherwise nothing will happen.

This allows you to not check if the JSON value has a correct type, if you initialize variables used for retrieval with some sane default values. Here is the compatibility table:

[xtable=skin1|632x173]
{tbody}
{tr}
{td}JSON Value{/td}
{td}Compatible data types{/td}
{/tr}
{tr}
{td}Undefined{/td}
{td}-{/td}
{/tr}
{tr}
{td}Null{/td}
{td}-{/td}
{/tr}
{tr}
{td}Boolean{/td}
{td}bool{/td}
{/tr}
{tr}
{td}Number{/td}
{td}int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float, double{/td}
{/tr}
{tr}
{td}String{/td}
{td}string, string@{/td}
{/tr}
{tr}
{td}Object{/td}
{td}-{/td}
{/tr}
{tr}
{td}Array{/td}
{td}array<bool>, array<string>, array<string@>, array<int>, array<int8>, array<int16>, array<int32>, array<int64>, array<uint>, array<uint8>, array<uint16>, array<uint32>, array<uint64>, array<float>, array<double>{/td}
{/tr}
{/tbody}
[/xtable]
Retrieving arrays works by appending values of the compatible elements of the JSON Array to the end of the array used for retrieval. Incompatible values will be skipped (JSON Arrays can contain values of mixed types).

Storing a primitve data in a JSON value

Storing primitive data in a JSON value works similarly to retrieval, just goes in opposite way and uses << operator:

Код:
poems[2]["title"] << "The title of the third poem got hacked!";
The same compatibility rules apply, except storing data in JSON arrays using arrays isn't implemented yet (for now you have to iterate the array and insert elements in it "manually").

Iterating Arrays and Objects

You can easily iterate Arrays and Objects using _JSON_ForEach(value, callback) macro:

Код:
_JSON_ForEach(poems, @LogPoemTitle);
 
void LogPoemTitle(JSON@ poem, uint index)
{
	string title = "No title";
	poem["title"] >> title;
	Log("Poem " + index + ": \"" + title + "\"");
}
The function LogPoemTitle will be called for every element of the poems Array.

Iterating Objects works similarly, except the second parameter of the callback function is const string& key.
In both cases there is a third optional argument JSON@ all - a handle to the "parent" value.

If you don't care about compatibility with FOnline revision < 400, instead of the macro you can use a bit nicer form:

Код:
poems.forEach(@LogPoemTitle);
Saving a JSON file

You can save any JSON value using JSON::save() method. It doesn't have to be the root value of loaded file, so you can easily save only a part of the original file:

Код:
poems[2].save("hacked_poem.json");
If you did everything correctly, the "hacked_poem.json" should look like this:
Код:
{
  "title": "The title of the third poem got hacked!",
  "year": 1784,
  "song": false,
  "text": [
	"Roses are red,",
	"Violets are blue,",
	"Sugar is sweet,",
	"And so are you."
  ]
}
This concludes the tutorial. There is a few more features, but undocumented for now.
 
Последнее редактирование:
Дата рег
21 Окт 2012
Сообщения
173
Симпатии
79
It would be nice if we could load json also by GET-request (through dll of course)
 
Автор темы #3
Дата рег
22 Окт 2012
Сообщения
6
Симпатии
23
I didn't write about it, but you can load JSON from a string using JSONParse function:
JSON@ JSONParse(const string& text)

Example (using heredoc strings):
Код:
JSON@ teams = JSONParse("""
[
	{
		"name": "Red Team",
		"color": [255, 0, 0]
	},
	{
		"name": "Green Team",
		"color": [0, 255, 0]
	},
	{
		"name": "Blue Team",
		"color": [0, 0, 255]
	}
]
""");
So it's only a matter of making a GET request. But I don't feel like it's a job for the module.
 
Последнее редактирование: