serialization
Definitions
profile - NWN has three different (de)serialization profiles:
blueprint - UTC, UTT, etc, etc. BIC is included here, though not a blueprint itself.
instance - Instances of blueprints stored in an area’s GIT file.
savegame - All game and object state. This is outside of the scope of this library.. for now.
type - C++ types corresponding to GFF serialization types.
uint8_t
- Also convertible tobool
int8_t
uint16_t
int16_t
uint32_t
int32_t
uint64_t
int64_t
float
double
std::string
Resref
LocString
ByteArray
Scoped Enumerations are convertible when their underlying type matches the GFF type.
The library may support the lifting of numeric types, i.e. reading a
int16_t
into int16_t
or int32_t
or int64_t
.
struct is a collection of key-value pairs, where the key is a 16 character string and the value is one of the above types (almost).
list is a list solely of structs, this follows the GFF pattern.
gffjson refers to the nwn-lib/neverwinter.nim json format that mimics GFF. The extent to which this is supported by the library is an open issue.
json refers specifically to rollnw json serialization. This very closely mimics the structure of a given object, such that if you load the JSON into another language, or a dynamic language that can construct arbitrary objects from JSON, the usage is identical or analogous to the C++ objects.
Examples
Example - How to build your own GFF
nw::GffBuilder gff{"GFF"};
// Add a field. Note that the type of the field is determined by the value
// passed.
gff.top.add_field("DATA", 9);
// Add a list. Note that in the GFF format lists contain only structs
auto& xs = gff.top.add_list("LIST");
// So when you push_back, you're creating a struct with a specific struct ID
auto& st = xs.push_back(0xBEEF);
// Now you can add fields to the struct
st.add_field("A", 1)
.add_field("B", 12);
// Add a struct. It's pretty rare that a gff field is a struct but if necessary
// you can add a struct with its struct ID, then add fields like above.
gff.top.add_struct("STRUCT", 42)
.add_field("A", 1)
.add_field("B", 12);
gff.build(); // This must be called after all fields have been added.
gff.write_to("mygff.gff");
Sample rollnw JSON serialization format
{
"$type": "UTC",
"$version": 1,
"appearance": {
"body_parts": {
"belt": 0,
"bicep_left": 1,
"bicep_right": 1,
"foot_left": 1,
"foot_right": 1,
"forearm_left": 1,
"forearm_right": 1,
"hand_left": 1,
"hand_right": 1,
"head": 119,
"neck": 1,
"pelvis": 1,
"shin_left": 1,
"shin_right": 1,
"shoulder_left": 0,
"shoulder_right": 0,
"thigh_left": 1,
"thigh_right": 1,
"torso": 1
},
"hair": 167,
"id": 6,
"phenotype": 0,
"portrait_id": 65,
"skin": 3,
"tail": 0,
"tattoo1": 1,
"tattoo2": 1,
"wings": 0
},
"bodybag": 0,
"chunk_death": 0,
"combat_info": {
"ac_natural": 0,
"special_abilities": [
{
"flags": 1,
"level": 15,
"spell": 120
}
]
},
"common": {
"comment": "",
"locals": {
"DIPType": {
"integer": 3
},
"DeflectionAC": {
"integer": 6
},
"DodgeAC": {
"integer": 6
},
"OtherImmunes": {
"integer": 1001945111
},
"Soak": {
"string": "15+5"
},
"VFXDur1": {
"integer": 11
},
"rlgs_ss_1": {
"string": "lt_agent_1"
}
},
"object_type": 5,
"palette_id": 0,
"resref": "pl_agent_001",
"tag": "pl_agent_001"
},
"conversation": "",
"cr": 38.0,
"cr_adjust": -36,
"decay_time": 5000,
"deity": "",
"description": {
"strings": [],
"strref": 4294967295
},
"disarmable": 0,
"equipment": {
"arms": "handwish",
"chest": "dk_agent_thread2",
"creature_left": "pl_slam_1d2"
},
"faction_id": 1,
"gender": 0,
"good_evil": 100,
"hp": 894,
"hp_current": 894,
"hp_max": 1014,
"immortal": 0,
"interruptable": 0,
"inventory": [],
"lawful_chaotic": 50,
"levels": [
{
"class": 4,
"level": 10,
"spellbook": {
"known": [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
],
"memorized": [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
}
},
{
"class": 5,
"level": 30,
"spellbook": {
"known": [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
],
"memorized": [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
}
}
],
"lootable": 0,
"name_first": {
"strings": [
{
"lang": 0,
"string": "Agent"
}
],
"strref": 4294967295
},
"name_last": {
"strings": [],
"strref": 4294967295
},
"pc": 0,
"perception_range": 11,
"plot": false,
"race": 6,
"scripts": {
"on_attacked": "mon_ai_5attacked",
"on_blocked": "mon_ai_13blocked",
"on_conversation": "mon_ai_4conv",
"on_damaged": "mon_ai_6dmged",
"on_death": "mon_ai_7death",
"on_disturbed": "mon_ai_8disturb",
"on_endround": "mon_ai_3ocre",
"on_heartbeat": "mon_ai_1hb",
"on_perceived": "mon_ai_2percep",
"on_rested": "mon_ai_10rest",
"on_spawn": "mon_ai_9spawn",
"on_spell_cast_at": "mon_ai_11spcast",
"on_user_defined": "mon_ai_12ud"
},
"soundset": 171,
"starting_package": 4,
"stats": {
"abilities": [
40,
13,
16,
10,
16,
9
],
"feats": [
2,
3,
4,
6,
8,
10,
21,
26,
32,
41,
45,
46,
49,
206,
207,
208,
209,
211,
212,
214,
215,
216,
258,
260,
289,
290,
291,
292,
297,
391,
392,
408,
755,
756,
757,
971,
1089
],
"save_bonus": {
"fort": 9,
"reflex": 15,
"will": 13
},
"skills": [
0,
1,
0,
40,
11,
30,
30,
1,
30,
0,
20,
0,
30,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
2,
0
]
},
"subrace": "",
"walkrate": 4
}