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 to bool

    • 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
}