Author Topic: FOnline-JSON  (Read 4114 times)

Offline JovankaB

  • Rotator
  • JovankaB
FOnline-JSON
« on: August 10, 2014, 01:43:20 pm »
No, FOnline-JSON is not a new server. Sorry.

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


Important notes


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:

Code: [Select]
#include "json_h.fos"
To load a JSON file use JSONLoad function:

Code: [Select]
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.

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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:

JSON Value type      Compatible data types
Undefined-
Null-
Booleanbool
Numberint, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float, double
Stringstring, string@
Object-
Arrayarray<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>

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:

Code: [Select]
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:

Code: [Select]
_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:

Code: [Select]
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:

Code: [Select]
poems[2].save("hacked_poem.json");
If you did everything correctly, the "hacked_poem.json" should look like this:
Code: [Select]
{
  "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.

« Last Edit: August 11, 2014, 07:02:37 am by JovankaB »

Re: FOnline-JSON
« Reply #1 on: August 09, 2017, 07:10:55 pm »
I just want to say that the way our data files look is extremely ugly. XML is laughable and outdated, but I would prefer having them in  XML for sure to simplify parsing through. Json though is a completely different level. I hope the core devs will start switching to Json format as the primary one. Although I would totally prefer SQL to keep track of unique ids and unused entities with things like cascading.

Great stuff, thank you for creating this!


Offline JovankaB

  • Rotator
  • JovankaB
Re: FOnline-JSON
« Reply #2 on: August 14, 2017, 06:44:07 am »
Quote
Great stuff, thank you for creating this!

You are welcome and thank you for your kind words :)
I did it for fun and the warm feeling of sharing it with others is also very nice ;)
« Last Edit: August 15, 2017, 03:15:41 pm by JovankaB »

Re: FOnline-JSON
« Reply #3 on: August 28, 2017, 07:58:08 pm »
Its a great script however the interface part doesn't seem to be functioning properly on rev404.

The method of using the json as a standalone singleton did not work.
@ server module json

I tried to include the json files directly in the modules and that did not work.

It gave me asspain about the interface differing from the class definition of the JSON class, problem was highly likely my end.

I had to rend and tear to get it working for my requirements but otherwise it was some good work.

« Last Edit: August 28, 2017, 08:02:28 pm by devis »

Offline JovankaB

  • Rotator
  • JovankaB
Re: FOnline-JSON
« Reply #4 on: September 06, 2017, 11:57:59 pm »
What can I say, not maintained code :)
Sorry to hear it gave you asspain :)

I looked in Github, apparently there are some compatibility defines for rev 404
https://github.com/rotators/fonline-json/issues/12

Re: FOnline-JSON
« Reply #5 on: July 16, 2022, 01:37:01 pm »
What can I say, not maintained code :)
(...)

Hi, I am trying to use this solution.
I took this: https://github.com/rotators/fonline-json
and tried it: https://github.com/rotators/fonline-json/wiki/Installation,
on the Fonline Reloaded Season 1 server (I think), I received the message:

FOnline server, version 0506-EC.
[01: 188] *** Starting initialization ****
[01: 192] Script system initialization ...
[01: 203] Reload scripts ...
[03: 494] Script :: LoadScript - Unable to preprocess file <json.fos>, error <json_export.fos (18) Error: Unknown directive.
>.
[03: 494] Load module fail, name <json>.
[05: 080] Reload scripts fail.
[06: 162] Reload scripts fail.
[06: 162] Initialization fail!

I am green and at the beginning of my way through the wasteland.
Anyone have an idea how to get it to work? Or maybe someone has a ready solution?

Tom_Abuser