diff --git a/README.md b/README.md index 1fdb351..4752248 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,20 @@ -

SNAP: Struct N' Array Parser 3.0.0

+

SNAP: Struct N' Array Parsing 3.2.0

-

Replacement for ds_map/ds_list-based encoding/decoding

+

Easy struct/array saving and loading

Download the .yymps here

  -Functions included are: +Functions included can: -1. `foreach(struct/array, method, [dsType])` -2. `snap_deep_copy(struct/array)` -3. `snap_to_json(struct/array, [pretty], [alphabetizeStructs])` -4. `snap_from_json(string)` -5. `snap_to_binary(struct/array)` -6. `snap_from_binary(buffer, [offset], [size], [destroyBuffer])` -7. `snap_from_xml(string)` -8. `snap_to_xml(struct/array, [alphabetizeStructs])` +1. Iterate over all elements of a struct/array and execute a function: `foreach()` +2. Make a deep copy of a struct/array: `snap_deep_copy(struct/array)` +3. Encode/decode JSON +4. Encode/decode binary +5. Encode/decode [messagepack](https://msgpack.org/index.html) +6. Encode/decode XML +7. Decode INI ----- @@ -44,7 +43,7 @@ Returns a copy of the given `struct/array`, including a copy of any nested struc ### snap_to_json(struct/array, [pretty], [alphabetizeStructs]) ### -Turns struct and array nested data into a JSON string. The root data type can be either a struct or an array. Setting `[pretty]` to `true` will format the JSON string in a more pleasing human-readable way, whereas setting `[alphabetizeStructs]` to `true` will output the struct variables in ascending alphabetical order. Using pretty and/or alphabetized output does incur a performance penalty. +Turns struct and array nested data into a JSON string. The root datatype can be either a struct or an array. Setting `[pretty]` to `true` will format the JSON string in a more pleasing human-readable way, whereas setting `[alphabetizeStructs]` to `true` will output the struct variables in ascending alphabetical order. Using pretty and/or alphabetized output does incur a performance penalty.   @@ -56,13 +55,25 @@ Decodes a JSON string into nested struct/array data. This function will happily ### snap_to_binary(struct/array) ### -Returns a buffer that holds binary encoded struct and array nested data. The root data type can be either a struct or an array. This is substantially faster than `snap_to_json()`. +Returns a buffer that holds binary encoded struct and array nested data. The root datatype can be either a struct or an array. This is substantially faster than `snap_to_json()`.   -### snap_from_binary(buffer, [offset], [size], [destroyBuffer]) ### +### snap_from_binary(buffer, [offset], [destroyBuffer]) ### -Unpacks binary encoded struct/array data. An `[offset]` and total `[size]` for the data within the buffer can be specified which is helpful for working with composite buffers. Set `[size]` to `-1` to use the entire size of the buffer. If `[destroyBuffer]` is set to `true` then the input buffer will be destroyed once the function has finished executing. This function is a lot faster than `snap_from_json_string()`. +Unpacks binary encoded struct/array data. An `[offset]` for the data within the buffer can be specified which is helpful for working with composite buffers. If `[destroyBuffer]` is set to `true` then the input buffer will be destroyed once the function has finished executing. This function is a lot faster than `snap_from_json_string()`. + +  + +### snap_to_messagepack(struct/array) ### + +Returns a buffer that holds a binary representation of struct and array nested data according to the [messagepack](https://msgpack.org/index.html) specification. The root datatype can any datatype. This function is slower then the proprietary `snap_to_binary()`, but the [messagepack](https://msgpack.org/index.html) format is widely used and tends to output slightly smaller buffers. + +  + +### snap_from_messagepack(buffer, [offset], [destroyBuffer]) ### + +Unpacks [messagepack](https://msgpack.org/index.html) binary data into a struct/array data. An `[offset]` for the data within the buffer can be specified which is helpful for working with composite buffers. If `[destroyBuffer]` is set to `true` then the input buffer will be destroyed once the function has finished executing. `snap_from_messagepack()` is a little slower than `snap_from_binary()`.   @@ -115,3 +126,18 @@ This is a bit wordy, so here's an example. The following XML and struct/array li ### snap_to_xml(struct/array, [alphabetizeStructs]) ### Turns struct and array nested data into a XML string. The data must be structured as above in GML example for `snap_from_xml()`. Setting `[alphabetizeStructs]` to `true` will output child element in ascending alphabetical order. Using an alphabetized output incurs a performance penalty. + +  + +### snap_from_ini_string(string, [tryReal]) ### + +Parses a string representation of an .ini file into nested structs: sections are stored as nested structs inside the root struct. Setting `[tryReal]` to `true` (the default value) will instruct the function to attempt to turn any values into real numbers if possible. + +_**N.B.** This script is only intended to read the .ini files and strings that GM generates using the native `ini_close()` function. This is not a full implementation of an .ini specification (not that an official one really exists)._ + +  + +### snap_from_ini_file(filename, [tryReal]) ### + +Convenience function that loads an .ini file from disk and passes it into `snap_from_ini_string()`. + diff --git a/objects/oTestBinary/Create_0.gml b/objects/oTestBinary/Create_0.gml index 7830e3e..2739900 100644 --- a/objects/oTestBinary/Create_0.gml +++ b/objects/oTestBinary/Create_0.gml @@ -25,4 +25,6 @@ struct = { url : "https://www.jujuadams.com/" }; -show_debug_message(snap_to_json(snap_from_binary(snap_to_binary(struct)), true, true)); \ No newline at end of file +buffer = snap_to_binary(struct); +show_debug_message(buffer_base64_encode(buffer, 0, -1)); +show_debug_message(snap_to_json(snap_from_binary(buffer), true, true)); \ No newline at end of file diff --git a/objects/oTestBinary/oTestMessagepack.yy b/objects/oTestBinary/oTestMessagepack.yy new file mode 100644 index 0000000..54ae13d --- /dev/null +++ b/objects/oTestBinary/oTestMessagepack.yy @@ -0,0 +1,33 @@ +{ + "spriteId": null, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 1, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"parent":{"name":"oTestMessagepack","path":"objects/oTestMessagepack/oTestMessagepack.yy",},"resourceVersion":"1.0","name":null,"tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "snap", + "path": "snap.yyp", + }, + "resourceVersion": "1.0", + "name": "oTestMessagepack", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/objects/oTestINI/Create_0.gml b/objects/oTestINI/Create_0.gml new file mode 100644 index 0000000..606c9a5 --- /dev/null +++ b/objects/oTestINI/Create_0.gml @@ -0,0 +1,22 @@ +var _text = @'[Section 1] +; comment +Option 1 = value 1 ; option "Option 1" has value "value 1" +oPtion 1 = \ value 2\ \ \ ; option "oPtion 1" has value " value 2 ", "oPtion 1" and "Option 1" are different + +[Numbers] +num = "-1285" +num_bin = 0b01101001 +num_hex = 0x12ae +num_oct = 01754 + +float1 = -124.45667356 +float2 = +4.1234565E+45 +float3 = 412.34565e45 +float4 = -1.1245864E-6 + +[Other] +bool1 = 1 +bool2 = on +bool3=f'; + +show_debug_message(snap_to_json(snap_from_ini_string(_text, false), true, true)); \ No newline at end of file diff --git a/objects/oTestINI/oTestINI.yy b/objects/oTestINI/oTestINI.yy new file mode 100644 index 0000000..71ef6ac --- /dev/null +++ b/objects/oTestINI/oTestINI.yy @@ -0,0 +1,33 @@ +{ + "spriteId": null, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 1, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"parent":{"name":"oTestINI","path":"objects/oTestINI/oTestINI.yy",},"resourceVersion":"1.0","name":null,"tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "snap", + "path": "snap.yyp", + }, + "resourceVersion": "1.0", + "name": "oTestINI", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/objects/oTestMessagepack/Create_0.gml b/objects/oTestMessagepack/Create_0.gml new file mode 100644 index 0000000..ec8643f --- /dev/null +++ b/objects/oTestMessagepack/Create_0.gml @@ -0,0 +1,30 @@ +struct = { + a : true, + b : false, + c : undefined, + d : 1/9, + e : 15/100, + array : [ + 5, + 6, + 7, + { + struct : "struct!", + nested : { + nested : "nested!", + array : [ + "more", + "MORE", + "M O R E" + ] + } + } + ], + test : "text!", + test2 : "\"Hello world!\"", + url : "https://www.jujuadams.com/" +}; + +buffer = snap_to_messagepack(struct); +show_debug_message(buffer_base64_encode(buffer, 0, -1)); +show_debug_message(snap_to_json(snap_from_messagepack(buffer), true, true)); \ No newline at end of file diff --git a/objects/oTestMessagepack/oTestMessagepack.yy b/objects/oTestMessagepack/oTestMessagepack.yy new file mode 100644 index 0000000..54ae13d --- /dev/null +++ b/objects/oTestMessagepack/oTestMessagepack.yy @@ -0,0 +1,33 @@ +{ + "spriteId": null, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 1, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"parent":{"name":"oTestMessagepack","path":"objects/oTestMessagepack/oTestMessagepack.yy",},"resourceVersion":"1.0","name":null,"tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "snap", + "path": "snap.yyp", + }, + "resourceVersion": "1.0", + "name": "oTestMessagepack", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/rooms/rMain/rMain.yy b/rooms/rMain/rMain.yy index aad308d..5d73c45 100644 --- a/rooms/rMain/rMain.yy +++ b/rooms/rMain/rMain.yy @@ -14,7 +14,7 @@ ], "layers": [ {"instances":[ - {"properties":[],"isDnd":false,"objectId":{"name":"oTestBinary","path":"objects/oTestBinary/oTestBinary.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":64.0,"y":32.0,"resourceVersion":"1.0","name":"inst_721877E5","tags":[],"resourceType":"GMRInstance",}, + {"properties":[],"isDnd":false,"objectId":{"name":"oTestBinary","path":"objects/oTestBinary/oTestBinary.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":32.0,"y":32.0,"resourceVersion":"1.0","name":"inst_6380F5B5","tags":[],"resourceType":"GMRInstance",}, ],"visible":true,"depth":0,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Instances","tags":[],"resourceType":"GMRInstanceLayer",}, {"spriteId":null,"colour":4278190080,"x":0,"y":0,"htiled":false,"vtiled":false,"hspeed":0.0,"vspeed":0.0,"stretch":false,"animationFPS":15.0,"animationSpeedType":0,"userdefinedAnimFPS":false,"visible":true,"depth":100,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Background","tags":[],"resourceType":"GMRBackgroundLayer",}, ], @@ -22,7 +22,7 @@ "creationCodeFile": "", "inheritCode": false, "instanceCreationOrder": [ - {"name":"inst_721877E5","path":"rooms/rMain/rMain.yy",}, + {"name":"inst_6380F5B5","path":"rooms/rMain/rMain.yy",}, ], "inheritCreationOrder": false, "sequenceId": null, diff --git a/scripts/snap_deep_copy/snap_deep_copy.gml b/scripts/snap_deep_copy/snap_deep_copy.gml index b4f3650..f892c5e 100644 --- a/scripts/snap_deep_copy/snap_deep_copy.gml +++ b/scripts/snap_deep_copy/snap_deep_copy.gml @@ -2,7 +2,7 @@ /// /// @param struct/array The struct/array to be copied /// -/// @jujuadams 2020-06-16 +/// @jujuadams 2020-06-24 function snap_deep_copy(_value) { @@ -28,11 +28,11 @@ function __snap_deep_copy(_value) constructor if (is_struct(_value)) { - _value = copy_struct(_source); + _value = copy_struct(_value); } else if (is_array(_value)) { - _value = copy_array(_source); + _value = copy_array(_value); } variable_struct_set(_copy, _name, _value); @@ -57,11 +57,11 @@ function __snap_deep_copy(_value) constructor if (is_struct(_value)) { - _value = copy_struct(_source); + _value = copy_struct(_value); } else if (is_array(_value)) { - _value = copy_array(_source); + _value = copy_array(_value); } _copy[@ _i] = _value; diff --git a/scripts/snap_from_binary/snap_from_binary.gml b/scripts/snap_from_binary/snap_from_binary.gml index 389e240..9d8c9d4 100644 --- a/scripts/snap_from_binary/snap_from_binary.gml +++ b/scripts/snap_from_binary/snap_from_binary.gml @@ -1,11 +1,10 @@ -/// @return Nested struct/array data decoded from the buffer +/// @return Nested struct/array data encoded from the buffer, using a proprietary format /// -/// @param buffer Binary data to be decoded, created by sna_to_binary() +/// @param buffer Binary data to be decoded, created by snap_to_binary() /// @param [offset] Start position for binary decoding in the buffer. Defaults to 0, the start of the buffer -/// @param [size] Number of bytes of data to be decoded. Set to -1 to use the entire size of the buffer. Defaults to -1 /// @param [destroyBuffer] Set to to destroy the input buffer. Defaults to /// -/// @jujuadams 2020-05-02 +/// @jujuadams 2020-06-20 /* 0x00 - terminator @@ -24,14 +23,11 @@ function snap_from_binary() { var _buffer = argument[0]; var _offset = ((argument_count > 1) && (argument[1] != undefined))? argument[1] : 0; - var _size = ((argument_count > 2) && (argument[2] != undefined))? argument[2] : -1; - var _destroy_buffer = ((argument_count > 3) && (argument[3] != undefined))? argument[3] : false; - - if (_size < 0) _size = buffer_get_size(_buffer) - _offset; + var _destroy_buffer = ((argument_count > 2) && (argument[2] != undefined))? argument[2] : false; var _old_tell = buffer_tell(_buffer); buffer_seek(_buffer, buffer_seek_start, _offset); - var _result = (new __snap_from_binary_parser(_buffer, _size)).root; + var _result = (new __snap_from_binary_parser(_buffer)).root; buffer_seek(_buffer, buffer_seek_start, _old_tell); if (_destroy_buffer) buffer_delete(_buffer); @@ -39,18 +35,16 @@ function snap_from_binary() return _result; } -function __snap_from_binary_parser(_buffer, _buffer_size) constructor +function __snap_from_binary_parser(_buffer) constructor { buffer = _buffer; - buffer_size = _buffer_size; - root = undefined; root_is_struct = false; root_array_size = 0; in_key = false; key = undefined; - while(buffer_tell(buffer) < buffer_size) + while(true) { if (in_key) { @@ -102,7 +96,7 @@ function __snap_from_binary_parser(_buffer, _buffer_size) constructor case 0x01: //Struct case 0x02: //Array buffer_seek(buffer, buffer_seek_relative, -1); - value = (new __snap_from_binary_parser(_buffer, _buffer_size)).root; + value = (new __snap_from_binary_parser(_buffer)).root; break; case 0x03: //String diff --git a/scripts/snap_from_ini_file/snap_from_ini_file.gml b/scripts/snap_from_ini_file/snap_from_ini_file.gml new file mode 100644 index 0000000..2ba4885 --- /dev/null +++ b/scripts/snap_from_ini_file/snap_from_ini_file.gml @@ -0,0 +1,28 @@ +/// @return Struct/array that represents the data in the INI file +/// +/// N.B. That this script is only intended to read the .ini files that GM generates +/// using the native ini_close() function. This is not a full implementation +/// of the INI specification +/// +/// @param filename The INI file to parse +/// @param [tryReal] Try to convert strings to real values if possible. Defaults to +/// +/// @jujuadams 2020-06-16 + +function snap_from_ini_file() +{ + var _filename = argument[0]; + var _try_real = (argument_count > 1)? argument[1] : undefined; + + if (!file_exists(_filename)) + { + show_error("snap_from_ini_file():\nFile \"" + string(_filename) + "\" could not be found\n ", false); + return {}; + } + + var _buffer = buffer_load(_filename); + var _string = buffer_read(_buffer, buffer_string); + buffer_delete(_buffer); + + return snap_from_ini_string(_string, _try_real); +} \ No newline at end of file diff --git a/scripts/snap_from_ini_file/snap_from_ini_file.yy b/scripts/snap_from_ini_file/snap_from_ini_file.yy new file mode 100644 index 0000000..d9263d8 --- /dev/null +++ b/scripts/snap_from_ini_file/snap_from_ini_file.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "Struct N' Array Parser", + "path": "folders/Struct N' Array Parser.yy", + }, + "resourceVersion": "1.0", + "name": "snap_from_ini_file", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/scripts/snap_from_ini_string/snap_from_ini_string.gml b/scripts/snap_from_ini_string/snap_from_ini_string.gml new file mode 100644 index 0000000..f6d7930 --- /dev/null +++ b/scripts/snap_from_ini_string/snap_from_ini_string.gml @@ -0,0 +1,179 @@ +/// @return Struct/array that represents the data in the INI file +/// +/// N.B. That this script is only intended to read the .ini files that GM generates +/// using the native ini_close() function. This is not a full implementation +/// of the INI specification +/// +/// @param string The INI string to parse +/// @param [tryReal] Try to convert strings to real values if possible. Defaults to +/// +/// @jujuadams 2020-06-16 + +function snap_from_ini_string() +{ + var _string = argument[0]; + var _try_real = ((argument_count > 1) && (argument[1] != undefined))? argument[1] : true; + + if (_try_real) + { + show_error("snap_from_ini_string():\nUnfortunately, the [tryReal] feature is currently broken due to beta bugs.\nHopefully they get fixed soon!\n \nIn the meantime, please set [tryReal] to \n ", false); + _try_real = false; + } + + var _size = string_byte_length(_string) + 1; + var _buffer = buffer_create(_size, buffer_grow, 1); + buffer_write(_buffer, buffer_string, _string); + buffer_seek(_buffer, buffer_seek_start, 0); + + var _skip_whitespace = true; + var _in_comment = false; + + var _in_key = false; + var _key_start = -1; + var _key = ""; + + var _in_value = false; + var _in_string = false; + var _seen_backslash = false; + var _value_start = 0; + var _last_non_whitespace = -1; + + var _in_section = false; + var _section = undefined; + var _section_start = 0; + var _section_struct = undefined; + + var _root = {}; + + repeat(_size) + { + var _value = buffer_read(_buffer, buffer_u8); + + if (_in_comment) //Ignore everything apart from a newline if we've seen a comment + { + if ((_value == 10) || (_value == 13)) //Newline + { + _in_comment = false; + _skip_whitespace = true; + } + } + else if ((_value == ord(";")) && !_in_value) //We handle comments at the end of a key:value pair in the <_in_value> section + { + _in_comment = true; + } + else + { + if (_skip_whitespace && (_value > 32)) _skip_whitespace = false; + + if (!_skip_whitespace) + { + if (_in_value) + { + if ((_value == 0) //Null + || (_value == 10) //Newline + || (_value == 13) //Newline + || (_value == ord(";")) //Comment semicolon + || (_in_string && (_value == ord("\"")) && (buffer_peek(_buffer, buffer_tell(_buffer)-2, buffer_u8) != ord("\\")))) //Unescaped double quote + { + if (_value == ord(";")) _in_comment = true; + + var _old_tell = buffer_tell(_buffer); + if (_in_string) _value_start++; + buffer_poke(_buffer, _last_non_whitespace + 1, buffer_u8, 0x0); + buffer_seek(_buffer, buffer_seek_start, _value_start); + + _value = buffer_read(_buffer, buffer_string); + buffer_seek(_buffer, buffer_seek_start, _old_tell); + + if (_seen_backslash) + { + _value = string_replace_all(_value, "\\\\", chr(1)); //Turn all \\ into a system character + _value = string_replace_all(_value, "\\", ""); //Turn all single \ into nothing + _value = string_replace_all(_value, chr(1), "\\"); //Restore \\ from the system character + } + + if (!_in_string && _try_real) + { + //TODO - Broken in runtime 23.1.1.123 + try { _value = real(_value); } catch(_) {} + } + + variable_struct_set(_section_struct, _key, _value); + + _in_value = false; + _in_key = true; + _key_start = -1; + _skip_whitespace = true; + _in_string = false; + } + else + { + if (_value_start < 0) + { + _value_start = buffer_tell(_buffer) - 1; + if (_value == ord("\"")) _in_string = true; + } + + if (_value > 32) _last_non_whitespace = buffer_tell(_buffer) - 1; + if ((_value == 32) && (buffer_peek(_buffer, buffer_tell(_buffer) - 2, buffer_u8) == ord("\\"))) _last_non_whitespace = buffer_tell(_buffer) - 1; + if (_value == ord("\\")) _seen_backslash = true; + } + } + else if (_value == ord("[")) //Open a section + { + _in_value = false; + _in_key = false; + _in_section = true; + _section_start = buffer_tell(_buffer); + } + else if (_in_section) + { + if (_value == ord("]")) + { + buffer_poke(_buffer, buffer_tell(_buffer)-1, buffer_u8, 0x0); + buffer_seek(_buffer, buffer_seek_start, _section_start); + _section = buffer_read(_buffer, buffer_string); + + var _section_struct = variable_struct_get(_root, _section); + if (_section_struct == undefined) + { + _section_struct = {}; + variable_struct_set(_root, _section, _section_struct); + } + + _in_section = false; + _in_key = true; + _key_start = -1; + _skip_whitespace = true; + } + } + else if (_in_key) + { + if (_key_start < 0) _key_start = buffer_tell(_buffer)-1; + + if (_value == ord("=")) + { + var _old_tell = buffer_tell(_buffer); + buffer_poke(_buffer, _last_non_whitespace + 1, buffer_u8, 0x0); + buffer_seek(_buffer, buffer_seek_start, _key_start); + _key = buffer_read(_buffer, buffer_string); + buffer_seek(_buffer, buffer_seek_start, _old_tell); + + _in_key = false; + _skip_whitespace = true; + _in_value = true; + _value_start = -1; + } + else + { + if (_value > 32) _last_non_whitespace = buffer_tell(_buffer) - 1; + } + } + } + } + } + + buffer_delete(_buffer); + + return _root +} \ No newline at end of file diff --git a/scripts/snap_from_ini_string/snap_from_ini_string.yy b/scripts/snap_from_ini_string/snap_from_ini_string.yy new file mode 100644 index 0000000..3fb348f --- /dev/null +++ b/scripts/snap_from_ini_string/snap_from_ini_string.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "Struct N' Array Parser", + "path": "folders/Struct N' Array Parser.yy", + }, + "resourceVersion": "1.0", + "name": "snap_from_ini_string", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/scripts/snap_from_messagepack/snap_from_messagepack.gml b/scripts/snap_from_messagepack/snap_from_messagepack.gml new file mode 100644 index 0000000..0a83e88 --- /dev/null +++ b/scripts/snap_from_messagepack/snap_from_messagepack.gml @@ -0,0 +1,234 @@ +/// @return Nested struct/array data decoded from the buffer, using the messagepack standard +/// +/// More information on messagepack can be found here: https://msgpack.org/index.html +/// +/// @param buffer Binary data to be decoded, created by snap_to_binary() +/// @param [offset] Start position for binary decoding in the buffer. Defaults to 0, the start of the buffer +/// @param [destroyBuffer] Set to to destroy the input buffer. Defaults to +/// +/// @jujuadams 2020-06-20 + +function snap_from_messagepack() +{ + var _buffer = argument[0]; + var _offset = ((argument_count > 1) && (argument[1] != undefined))? argument[1] : 0; + var _destroy_buffer = ((argument_count > 3) && (argument[3] != undefined))? argument[3] : false; + + var _old_tell = buffer_tell(_buffer); + buffer_seek(_buffer, buffer_seek_start, _offset); + var _result = (new __snap_from_messagepack_parser(_buffer)).root; + buffer_seek(_buffer, buffer_seek_start, _old_tell); + + if (_destroy_buffer) buffer_delete(_buffer); + + return _result; +} + +function __snap_from_messagepack_parser(_buffer) constructor +{ + buffer = _buffer; + + static read_struct = function(_size) + { + var _struct = {}; + repeat(_size) + { + var _key = read_value(); + var _value = read_value(); + variable_struct_set(_struct, _key, _value); + } + return _struct; + } + + static read_array = function(_size) + { + var _array = array_create(_size, undefined); + var _i = 0; + repeat(_size) + { + _array[@ _i] = read_value(); + ++_i; + } + return _array; + } + + static read_string = function(_size) + { + var _null_position = buffer_tell(buffer) + _size; + if (_null_position >= buffer_get_size(buffer)) + { + //If the string runs into the end of the buffer, just read out the string + return buffer_read(buffer, buffer_text); + } + + //Read the byte just after the end of the string and replace it with 0x00 + var _peek = buffer_peek(buffer, _null_position, buffer_u8); + buffer_poke(buffer, _null_position, buffer_u8, 0x00); + + //Get GM to read from the start of the string to the null byte + var _string = buffer_read(buffer, buffer_string); + + //Take a step back and replace the original byte with what we found before + buffer_seek(buffer, buffer_seek_relative, -1); + buffer_poke(buffer, _null_position, buffer_u8, _peek); + + return _string; + } + + static read_bin = function(_size) + { + var _array = array_create(_size); + + var _i = 0; + repeat(_size) + { + _array[@ _i] = buffer_read(buffer, buffer_u8); + ++_i; + } + + return { + messagepack_datatype__ : "bin", + data : _array + }; + } + + static read_ext = function(_size) + { + var _type = buffer_read(buffer, buffer_s8); + var _array = array_create(_size); + + var _i = 0; + repeat(_size) + { + _array[@ _i] = buffer_read(buffer, buffer_u8); + ++_i; + } + + return { + messagepack_datatype__ : "ext", + type : _type, + data : _array + }; + } + + static buffer_read_little = function(_datatype) + { + switch(buffer_sizeof(_datatype)) + { + case 1: + return buffer_read(buffer, _datatype); + break; + + case 2: + buffer_poke(flip_buffer, 1, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 0, buffer_u8, buffer_read(buffer, buffer_u8)); + break; + + case 4: + buffer_poke(flip_buffer, 3, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 2, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 1, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 0, buffer_u8, buffer_read(buffer, buffer_u8)); + break; + + case 8: + buffer_poke(flip_buffer, 7, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 6, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 5, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 4, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 3, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 2, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 1, buffer_u8, buffer_read(buffer, buffer_u8)); + buffer_poke(flip_buffer, 0, buffer_u8, buffer_read(buffer, buffer_u8)); + break; + } + + return buffer_peek(flip_buffer, 0, _datatype); + } + + static read_value = function() + { + var _byte = buffer_read(buffer, buffer_u8); + if (_byte <= 0x7f) //positive fixint 0x00 -> 0x7f + { + //First 7 bits are the integer + return int64(_byte & 0x7f); + } + else if (_byte <= 0x8f) //fixmap 0x80 -> 0x8f + { + //Size is determined by the first 4 bits + return read_struct(_byte & 0x0f); + } + else if (_byte <= 0x9f) //fixarray 0x90 -> 0x9f + { + //Size is determined by the first 4 bits + return read_array(_byte & 0x0f); + } + else if (_byte <= 0xbf) //fixstr 0xa0 -> 0xbf + { + //Size is determined by the first 5 bits + return read_string(_byte & 0x1f); + } + else if ((_byte >= 0xe0) && (_byte <= 0xff)) //negative fixint 0xe0 -> 0xff + { + //First 5 bites are the integer + return -(_byte & 0x1f); + } + else switch(_byte) + { + case 0xc0: /*191*/ return undefined; break; //nil + case 0xc1: /*192*/ show_debug_message("snap_from_binary(): WARNING! Datatype 0xc1 found, but this value should never be used"); break; //Baby shoes for sale, never worn + case 0xc2: /*193*/ return bool(false); break; //false + case 0xc3: /*194*/ return bool(true ); break; //true + + case 0xc4: /*195*/ return read_bin(buffer_read(buffer, buffer_u8 )); break; //bin 8 + case 0xc5: /*196*/ return read_bin(buffer_read_little( buffer_u16)); break; //bin 16 + case 0xc6: /*197*/ return read_bin(buffer_read_little( buffer_u32)); break; //bin 32 + + case 0xc7: /*198*/ return read_ext(buffer_read(buffer, buffer_u8 )); break; //ext 8 + case 0xc8: /*199*/ return read_ext(buffer_read_little( buffer_u16)); break; //ext 16 + case 0xc9: /*201*/ return read_ext(buffer_read_little( buffer_u32)); break; //ext 32 + + case 0xca: /*202*/ return buffer_read_little(buffer_f32); break; //float 32 + case 0xcb: /*203*/ return buffer_read_little(buffer_f64); break; //float 64 + + case 0xcc: /*204*/ return buffer_read(buffer, buffer_u8 ); break; // uint 8 + case 0xcd: /*205*/ return buffer_read_little( buffer_u16); break; // uint 16 + case 0xce: /*206*/ return buffer_read_little( buffer_u32); break; // uint 32 + case 0xcf: /*207*/ return buffer_read_little( buffer_u64); break; // uint 64 + + case 0xd0: /*208*/ return buffer_read(buffer, buffer_s8 ); break; // int 8 + case 0xd1: /*209*/ return buffer_read_little( buffer_s16); break; // int 16 + case 0xd2: /*210*/ return buffer_read_little( buffer_s32); break; // int 32 + case 0xd3: /*211*/ return buffer_read_little( buffer_u64); break; // int 64 !!! No signed 64-bit integer read in GameMaker + + case 0xd4: /*212*/ return read_ext( 1); break; //fixext 1 + case 0xd5: /*213*/ return read_ext( 2); break; //fixext 2 + case 0xd6: /*214*/ return read_ext( 4); break; //fixext 4 + case 0xd7: /*215*/ return read_ext( 8); break; //fixext 8 + case 0xd8: /*216*/ return read_ext(16); break; //fixext 16 + + case 0xd9: /*217*/ return read_string(buffer_read(buffer, buffer_u8 )); break; //str 8 + case 0xda: /*218*/ return read_string(buffer_read_little( buffer_u16)); break; //str 16 + case 0xdb: /*219*/ return read_string(buffer_read_little( buffer_u32)); break; //str 32 + + case 0xdc: /*220*/ return read_array( buffer_read_little(buffer_u16)); break; //array 16 + case 0xdd: /*221*/ return read_array( buffer_read_little(buffer_u32)); break; //array 32 + + case 0xde: /*222*/ return read_struct(buffer_read_little(buffer_u16)); break; //map 16 + case 0xdf: /*223*/ return read_struct(buffer_read_little(buffer_u32)); break; //map 32 + + default: + show_debug_message("snap_from_binary(): WARNING! Unsupported datatype " + string(_byte) + " found"); + break; + } + + return undefined; + } + + //messagepack is big-endian because the creator hates normalcy + //This means we need to use a separate buffer for flipping values around + flip_buffer = buffer_create(8, buffer_fixed, 1); + root = read_value(); + buffer_delete(flip_buffer); +} \ No newline at end of file diff --git a/scripts/snap_from_messagepack/snap_from_messagepack.yy b/scripts/snap_from_messagepack/snap_from_messagepack.yy new file mode 100644 index 0000000..64fcf39 --- /dev/null +++ b/scripts/snap_from_messagepack/snap_from_messagepack.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "Struct N' Array Parser", + "path": "folders/Struct N' Array Parser.yy", + }, + "resourceVersion": "1.0", + "name": "snap_from_messagepack", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/scripts/snap_to_binary/snap_to_binary.gml b/scripts/snap_to_binary/snap_to_binary.gml index ff09143..fb725f9 100644 --- a/scripts/snap_to_binary/snap_to_binary.gml +++ b/scripts/snap_to_binary/snap_to_binary.gml @@ -1,4 +1,4 @@ -/// @return Buffer that contains binary encoded struct/array nested data +/// @return Buffer that contains binary encoded struct/array nested data, using a proprietary format /// /// @param struct/array The data to be encoded. Can contain structs, arrays, strings, and numbers. N.B. Will not encode ds_list, ds_map etc. /// diff --git a/scripts/snap_to_messagepack/snap_to_messagepack.gml b/scripts/snap_to_messagepack/snap_to_messagepack.gml new file mode 100644 index 0000000..7d9936c --- /dev/null +++ b/scripts/snap_to_messagepack/snap_to_messagepack.gml @@ -0,0 +1,377 @@ +/// @return Buffer that represents the struct/array nested data, using the messagepack standard +/// +/// More information on messagepack can be found here: https://msgpack.org/index.html +/// +/// @param struct/array The data to be encoded. Can contain structs, arrays, strings, and numbers. N.B. Will not encode ds_list, ds_map etc. +/// +/// @jujuadams 2020-06-20 + +function snap_to_messagepack(_ds) +{ + return (new __snap_to_messagepack_parser(_ds)).buffer; +} + +function __snap_to_messagepack_parser(_ds) constructor +{ + static write_struct = function(_struct) + { + var _names = variable_struct_get_names(_struct); + var _count = array_length(_names); + + if (_count <= 0x0f) + { + //Size is determined by the first 4 bits + buffer_write(buffer, buffer_u8, 0x80 | _count); + } + else if (_count <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xde); + buffer_write_little(buffer_u16, _count); + } + else if (_count <= 0xffffffff) + { + buffer_write(buffer, buffer_u8, 0xdf); + buffer_write_little(buffer_u32, _count); + } + else + { + show_error("snap_to_binary():\nTrying to write a struct longer than 4294967295 elements\n(How did you make a struct this big?!)\n ", true); + } + + var _i = 0; + repeat(_count) + { + var _name = _names[_i]; + write_value(_name); + write_value(variable_struct_get(_struct, _name)); + + ++_i; + } + } + + static write_array = function(_array) + { + var _count = array_length(_array); + + if (_count <= 0x0f) + { + //Size is determined by the first 4 bits + buffer_write(buffer, buffer_u8, 0x90 | _count); + } + else if (_count <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xdc); + buffer_write_little(buffer_u16, _count); + } + else if (_count <= 0xffffffff) + { + buffer_write(buffer, buffer_u8, 0xdd); + buffer_write_little(buffer_u32, _count); + } + else + { + show_error("snap_to_binary():\nTrying to write an array longer than 4294967295 elements\n(How did you make an array this big?!)\n ", true); + } + + var _i = 0; + repeat(_count) + { + write_value(_array[_i]); + ++_i; + } + } + + static write_string = function(_string) + { + var _size = string_byte_length(_string); + + if (_size <= 0x1f) + { + //Size is determined by the first 5 bits + buffer_write(buffer, buffer_u8, 0xa0 | _size); + } + else if (_size <= 0xff) + { + buffer_write(buffer, buffer_u8, 0xd9); + buffer_write(buffer, buffer_u8, _size); + } + else if (_size <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xda); + buffer_write_little(buffer_u16, _size); + } + else if (_size <= 0xffffffffff) + { + buffer_write(buffer, buffer_u8, 0xdb); + buffer_write_little(buffer_u32, _size); + } + else + { + show_error("snap_to_binary():\nTrying to write a string longer than 4294967295 bytes\n(How did you make a string this big?!)\n ", true); + } + + buffer_write(buffer, buffer_text, _string); + } + + static write_number = function(_value) + { + if (is_int32(_value) || is_int64(_value) || (floor(_value) == _value)) + { + //Integer + if (_value > 0) + { + //Positive, use an unsigned integer + if (_value <= 0x7f) + { + //First 7 bits are the integer + buffer_write(buffer, buffer_u8, _value); + } + else if (_value <= 0xff) + { + buffer_write(buffer, buffer_u8, 0xcc); + buffer_write(buffer, buffer_u8, _value); + } + else if (_value <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xcd); + buffer_write_little(buffer_u8, _value); + } + else if (_value <= 0xffffffff) + { + buffer_write(buffer, buffer_u8, 0xce); + buffer_write_little(buffer_u8, _value); + } + else + { + buffer_write(buffer, buffer_u8, 0xcf); + buffer_write_little(buffer_u8, _value); + } + } + else if (_value == 0) + { + //Zero exactly + buffer_write(buffer, buffer_u8, 0x00); + } + else + { + //Negative, use a signed integer + _value = -_value; + + if (_value <= 0x1f) + { + //First 5 bits are the integer + buffer_write(buffer, buffer_u8, 0xe0 | _value); + } + else if (_value <= 0xff) + { + buffer_write(buffer, buffer_u8, 0xd0); + buffer_write(buffer, buffer_u8, _value); + } + else if (_value <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xd1); + buffer_write_little(buffer_u8, _value); + } + else if (_value <= 0xffffffff) + { + buffer_write(buffer, buffer_u8, 0xd2); + buffer_write_little(buffer_u8, _value); + } + else + { + //!!! No signed 64-bit integer read in GameMaker so this might be redundant + buffer_write(buffer, buffer_u8, 0xd3); + buffer_write_little(buffer_u8, _value); + } + } + } + else + { + //Floating Point + buffer_write(buffer, buffer_u8, 0xcb); + buffer_write_little(buffer_f64, _value); + } + } + + static write_bin = function(_struct) + { + var _array = _struct.data; + var _count = array_length(_array); + + if (_count <= 0xff) + { + buffer_write(buffer, buffer_u8, 0xc4); + buffer_write(buffer, buffer_u8, _count); + } + else if (_count <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xc5); + buffer_write_little(buffer_u16, _count); + } + else if (_count <= 0xffffffff) + { + buffer_write(buffer, buffer_u8, 0xc6); + buffer_write_little(buffer_u32, _count); + } + else + { + show_error("snap_to_binary():\nTrying to write a binary array longer than 4294967295 elements\n(How did you make an array this big?!)\n ", true); + } + + var _i = 0; + repeat(_count) + { + buffer_write(buffer, buffer_u8, _array[_i]); + ++_i; + } + } + + static write_ext = function(_struct) + { + var _array = _struct.data; + var _count = array_length(_array); + + if (_count == 1) + { + buffer_write(buffer, buffer_u8, 0xd4); + } + else if (_count == 2) + { + buffer_write(buffer, buffer_u8, 0xd5); + } + else if (_count == 4) + { + buffer_write(buffer, buffer_u8, 0xd6); + } + else if (_count == 8) + { + buffer_write(buffer, buffer_u8, 0xd7); + } + else if (_count == 16) + { + buffer_write(buffer, buffer_u8, 0xd8); + } + else if (_count <= 0xff) + { + buffer_write(buffer, buffer_u8, 0xc7); + buffer_write(buffer, buffer_u8, _count); + } + else if (_count <= 0xffff) + { + buffer_write(buffer, buffer_u8, 0xc8); + buffer_write_little(buffer_u16, _count); + } + else if (_count <= 0xffffffff) + { + buffer_write(buffer, buffer_u8, 0xc9); + buffer_write_little(buffer_u32, _count); + } + else + { + show_error("snap_to_binary():\nTrying to write an extended binary array longer than 4294967295 elements\n(How did you make an array this big?!)\n ", true); + } + + buffer_write(buffer, buffer_s8, _struct.type); + + var _i = 0; + repeat(_count) + { + buffer_write(buffer, buffer_u8, _array[_i]); + ++_i; + } + } + + static buffer_write_little = function(_datatype, _value) + { + switch(buffer_sizeof(_datatype)) + { + case 1: + buffer_write(buffer, _datatype, _value); + break; + + case 2: + buffer_poke(flip_buffer, 0, _datatype, _value); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 1, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 0, buffer_u8)); + break; + + case 4: + buffer_poke(flip_buffer, 0, _datatype, _value); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 3, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 2, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 1, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 0, buffer_u8)); + break; + + case 8: + buffer_poke(flip_buffer, 0, _datatype, _value); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 7, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 6, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 5, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 4, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 3, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 2, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 1, buffer_u8)); + buffer_write(buffer, buffer_u8, buffer_peek(flip_buffer, 0, buffer_u8)); + break; + } + } + + static write_value = function(_value) + { + if (is_struct(_value)) + { + var _messagepack_datatype = variable_struct_get(_value, "messagepack_datatype__"); + if (_messagepack_datatype == "bin") + { + write_bin(_value); + } + else if (_messagepack_datatype == "ext") + { + write_bin(_value); + } + else + { + //Normal struct + write_struct(_value); + } + } + else if (is_array(_value)) + { + write_array(_value); + } + else if (is_string(_value)) + { + write_string(_value); + } + else if (is_bool(_value)) + { + buffer_write(buffer, buffer_u8, _value? 0xc3 : 0xc2); + } + else if (is_numeric(_value)) + { + write_number(_value); + } + else if (is_undefined(_value)) + { + buffer_write(buffer, buffer_u8, 0xc0); + } + else + { + show_error("snap_to_binary():\nUnsupported datatype \"" + typeof(_value) + "\"\n ", false); + buffer_write(buffer, buffer_u8, 0xc0); + } + } + + + + //messagepack is big-endian because the creator hates normalcy + //This means we need to use a separate buffer for flipping values around + flip_buffer = buffer_create(8, buffer_fixed, 1); + + buffer = buffer_create(1024, buffer_grow, 1); + write_value(_ds); + buffer_resize(buffer, max(1, buffer_tell(buffer))); + + buffer_delete(flip_buffer); +} \ No newline at end of file diff --git a/scripts/snap_to_messagepack/snap_to_messagepack.yy b/scripts/snap_to_messagepack/snap_to_messagepack.yy new file mode 100644 index 0000000..39094eb --- /dev/null +++ b/scripts/snap_to_messagepack/snap_to_messagepack.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "Struct N' Array Parser", + "path": "folders/Struct N' Array Parser.yy", + }, + "resourceVersion": "1.0", + "name": "snap_to_messagepack", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/snap.yyp b/snap.yyp index 14ae6ee..e1695a6 100644 --- a/snap.yyp +++ b/snap.yyp @@ -1,16 +1,22 @@ { "resources": [ - {"id":{"name":"snap_from_xml","path":"scripts/snap_from_xml/snap_from_xml.yy",},"order":7,}, - {"id":{"name":"snap_to_xml","path":"scripts/snap_to_xml/snap_to_xml.yy",},"order":6,}, + {"id":{"name":"snap_from_xml","path":"scripts/snap_from_xml/snap_from_xml.yy",},"order":9,}, + {"id":{"name":"snap_to_xml","path":"scripts/snap_to_xml/snap_to_xml.yy",},"order":8,}, {"id":{"name":"snap_deep_copy","path":"scripts/snap_deep_copy/snap_deep_copy.yy",},"order":1,}, + {"id":{"name":"oTestINI","path":"objects/oTestINI/oTestINI.yy",},"order":6,}, {"id":{"name":"snap_from_json","path":"scripts/snap_from_json/snap_from_json.yy",},"order":3,}, {"id":{"name":"foreach","path":"scripts/foreach/foreach.yy",},"order":0,}, {"id":{"name":"snap_to_json","path":"scripts/snap_to_json/snap_to_json.yy",},"order":2,}, + {"id":{"name":"snap_from_binary","path":"scripts/snap_from_binary/snap_from_binary.yy",},"order":5,}, {"id":{"name":"oTestJSON","path":"objects/oTestJSON/oTestJSON.yy",},"order":2,}, {"id":{"name":"snap_to_binary","path":"scripts/snap_to_binary/snap_to_binary.yy",},"order":4,}, - {"id":{"name":"snap_from_binary","path":"scripts/snap_from_binary/snap_from_binary.yy",},"order":5,}, - {"id":{"name":"oTestBinary","path":"objects/oTestBinary/oTestBinary.yy",},"order":3,}, + {"id":{"name":"snap_to_messagepack","path":"scripts/snap_to_messagepack/snap_to_messagepack.yy",},"order":6,}, + {"id":{"name":"snap_from_ini_string","path":"scripts/snap_from_ini_string/snap_from_ini_string.yy",},"order":10,}, + {"id":{"name":"snap_from_messagepack","path":"scripts/snap_from_messagepack/snap_from_messagepack.yy",},"order":7,}, + {"id":{"name":"oTestMessagepack","path":"objects/oTestMessagepack/oTestMessagepack.yy",},"order":3,}, + {"id":{"name":"snap_from_ini_file","path":"scripts/snap_from_ini_file/snap_from_ini_file.yy",},"order":11,}, {"id":{"name":"oTestXML","path":"objects/oTestXML/oTestXML.yy",},"order":5,}, + {"id":{"name":"oTestBinary","path":"objects/oTestBinary/oTestBinary.yy",},"order":7,}, {"id":{"name":"rMain","path":"rooms/rMain/rMain.yy",},"order":1,}, ], "Options": [ @@ -51,7 +57,7 @@ {"CopyToMask":153720560310812910,"filePath":"datafiles","resourceVersion":"1.0","name":"README.md","resourceType":"GMIncludedFile",}, ], "MetaData": { - "IDEVersion": "23.1.1.141", + "IDEVersion": "23.1.1.157", }, "resourceVersion": "1.3", "name": "snap",