Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved Dynamic Json editing on Il2Cpp

Discussion in 'Scripting' started by DragonCoder, Dec 3, 2023.

  1. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,635
    Hello Community,

    have the usecase of modifying a rather messy and complex 3rd party json file.
    If you are curious: The scene format of OBS. E.g.
    Code (Json):
    1. {
    2.    "DesktopAudioDevice1":{
    3.       "prev_ver":503316480,
    4.       "name":"Desktop Audio",
    5.       "uuid":"ce1bdce0-f5a6-4bd3-85da-1daafa645e7d",
    6.       "id":"wasapi_output_capture",
    7.       "versioned_id":"wasapi_output_capture",
    8.       "settings":{
    9.          "device_id":"default"
    10.       },
    11.       "mixers":255,
    12.       "sync":0,
    13.       "flags":0,
    14.       "volume":1.0,
    15.       "balance":0.5,
    16.       "enabled":true,
    17.       "muted":false,
    18.       "push-to-mute":false,
    19.       "push-to-mute-delay":0,
    20.       "push-to-talk":false,
    21.       "push-to-talk-delay":0,
    22.       "hotkeys":{
    23.          "libobs.mute":[
    24.          
    25.          ],
    26.          "libobs.unmute":[
    27.          
    28.          ],
    29.          "libobs.push-to-mute":[
    30.          
    31.          ],
    32.          "libobs.push-to-talk":[
    33.          
    34.          ]
    35.       },
    36.       "deinterlace_mode":0,
    37.       "deinterlace_field_order":0,
    38.       "monitoring_type":0,
    39.       "private_settings":{
    40.        
    41.       }
    42.    },
    43.    "AuxAudioDevice1":{
    44.       "prev_ver":503316480,
    45.       "name":"Mic/Aux",
    46.       "uuid":"b5a75ab5-41e0-459e-bc65-93da01b59377",
    47.       "id":"wasapi_input_capture",
    48.       "versioned_id":"wasapi_input_capture",
    49.       "settings":{
    50.          "device_id":"default"
    51.       },
    52.       "mixers":255,
    53.       "sync":0,
    54.       "flags":0,
    55.       "volume":1.0,
    56.       "balance":0.5,
    57.       "enabled":true,
    58.       "muted":true,
    59.       "push-to-mute":false,
    60.       "push-to-mute-delay":0,
    61.       "push-to-talk":false,
    62.       "push-to-talk-delay":0,
    63.       "hotkeys":{
    64.          "libobs.mute":[
    65.          
    66.          ],
    67.          "libobs.unmute":[
    68.          
    69.          ],
    70.          "libobs.push-to-mute":[
    71.          
    72.          ],
    73.          "libobs.push-to-talk":[
    74.          
    75.          ]
    76.       },
    77.       "deinterlace_mode":0,
    78.       "deinterlace_field_order":0,
    79.       "monitoring_type":0,
    80.       "private_settings":{
    81.        
    82.       }
    83.    },
    84.    "current_scene":"RecordScene",
    85.    "current_program_scene":"RecordScene",
    86.    "scene_order":[
    87.       {
    88.          "name":"RecordScene"
    89.       }
    90.    ],
    91.    "name":"Untitled",
    92.    "sources":[
    93.       {
    94.          "prev_ver":503316480,
    95.          "name":"RecordScene",
    96.          "uuid":"b67dc900-4bd0-4081-acda-839293a8bb30",
    97.          "id":"scene",
    98.          "versioned_id":"scene",
    99.          "settings":{
    100.             "id_counter":3,
    101.             "custom_size":false,
    102.             "items":[
    103.                {
    104.                   "name":"GameCapture",
    105.                   "source_uuid":"a4b574be-66e3-4562-aaef-947542c8ae16",
    106.                   "visible":true,
    107.                   "locked":true,
    108.                   "rot":0.0,
    109.                   "pos":{
    110.                      "x":0.0,
    111.                      "y":0.0
    112.                   },
    113.                   "scale":{
    114.                      "x":1.0,
    115.                      "y":1.0
    116.                   },
    117.                   "align":5,
    118.                   "bounds_type":2,
    119.                   "bounds_align":0,
    120.                   "bounds":{
    121.                      "x":1920.0,
    122.                      "y":1080.0
    123.                   },
    124.                   "crop_left":0,
    125.                   "crop_top":0,
    126.                   "crop_right":0,
    127.                   "crop_bottom":0,
    128.                   "id":1,
    129.                   "group_item_backup":false,
    130.                   "scale_filter":"disable",
    131.                   "blend_method":"default",
    132.                   "blend_type":"normal",
    133.                   "show_transition":{
    134.                      "duration":0
    135.                   },
    136.                   "hide_transition":{
    137.                      "duration":0
    138.                   },
    139.                   "private_settings":{
    140.                    
    141.                   }
    142.                }
    143.             ]
    144.          },
    145.          "mixers":0,
    146.          "sync":0,
    147.          "flags":0,
    148.          "volume":1.0,
    149.          "balance":0.5,
    150.          "enabled":true,
    151.          "muted":false,
    152.          "push-to-mute":false,
    153.          "push-to-mute-delay":0,
    154.          "push-to-talk":false,
    155.          "push-to-talk-delay":0,
    156.          "hotkeys":{
    157.             "OBSBasic.SelectScene":[
    158.              
    159.             ],
    160.             "libobs.show_scene_item.1":[
    161.              
    162.             ],
    163.             "libobs.hide_scene_item.1":[
    164.              
    165.             ]
    166.          },
    167.          "deinterlace_mode":0,
    168.          "deinterlace_field_order":0,
    169.          "monitoring_type":0,
    170.          "private_settings":{
    171.          
    172.          }
    173.       },
    174.       {
    175.          "prev_ver":503316480,
    176.          "name":"GameCapture",
    177.          "uuid":"a4b574be-66e3-4562-aaef-947542c8ae16",
    178.          "id":"game_capture",
    179.          "versioned_id":"game_capture",
    180.          "settings":{
    181.             "window":"Player.log - Notepad:Notepad:Notepad.exe",
    182.             "capture_mode":"window",
    183.             "capture_cursor":false,
    184.             "anti_cheat_hook":false,
    185.             "hook_rate":3
    186.          },
    187.          "mixers":0,
    188.          "sync":0,
    189.          "flags":0,
    190.          "volume":1.0,
    191.          "balance":0.5,
    192.          "enabled":true,
    193.          "muted":false,
    194.          "push-to-mute":false,
    195.          "push-to-mute-delay":0,
    196.          "push-to-talk":false,
    197.          "push-to-talk-delay":0,
    198.          "hotkeys":{
    199.             "hotkey_start":[
    200.              
    201.             ],
    202.             "hotkey_stop":[
    203.              
    204.             ]
    205.          },
    206.          "deinterlace_mode":0,
    207.          "deinterlace_field_order":0,
    208.          "monitoring_type":0,
    209.          "private_settings":{
    210.          
    211.          }
    212.       }
    213.    ],
    214.    "groups":[
    215.    
    216.    ],
    217.    "quick_transitions":[
    218.       {
    219.          "name":"Cut",
    220.          "duration":300,
    221.          "hotkeys":[
    222.          
    223.          ],
    224.          "id":1,
    225.          "fade_to_black":false
    226.       },
    227.       {
    228.          "name":"Fade",
    229.          "duration":300,
    230.          "hotkeys":[
    231.          
    232.          ],
    233.          "id":2,
    234.          "fade_to_black":false
    235.       },
    236.       {
    237.          "name":"Fade",
    238.          "duration":300,
    239.          "hotkeys":[
    240.          
    241.          ],
    242.          "id":3,
    243.          "fade_to_black":true
    244.       }
    245.    ],
    246.    "transitions":[
    247.    
    248.    ],
    249.    "saved_projectors":[
    250.    
    251.    ],
    252.    "current_transition":"Fade",
    253.    "transition_duration":300,
    254.    "preview_locked":false,
    255.    "scaling_enabled":false,
    256.    "scaling_level":0,
    257.    "scaling_off_x":0.0,
    258.    "scaling_off_y":0.0,
    259.    "modules":{
    260.       "scripts-tool":[
    261.        
    262.       ],
    263.       "output-timer":{
    264.          "streamTimerHours":0,
    265.          "streamTimerMinutes":0,
    266.          "streamTimerSeconds":30,
    267.          "recordTimerHours":0,
    268.          "recordTimerMinutes":0,
    269.          "recordTimerSeconds":30,
    270.          "autoStartStreamTimer":false,
    271.          "autoStartRecordTimer":false,
    272.          "pauseRecordTimer":true
    273.       },
    274.       "auto-scene-switcher":{
    275.          "interval":300,
    276.          "non_matching_scene":"",
    277.          "switch_if_not_matching":false,
    278.          "active":false,
    279.          "switches":[
    280.          
    281.          ]
    282.       },
    283.       "captions":{
    284.          "source":"",
    285.          "enabled":false,
    286.          "lang_id":1033,
    287.          "provider":"mssapi"
    288.       }
    289.    }
    290. }

    Only need to change a few fields so I'd like to avoid to recreate this complex structure as C# classes.
    In Python this would be a breeze and almost as easy it's on a Mono environment thanks to Newtonsoft's capability of using the "dynamic" keyword for a magical runtime class.
    Unfortunately dynamic isn't usable on Il2cpp builds however

    Is there a solution for Il2CPP?

    Huge thanks in advance!

    EDIT: Oh, this is a thing: https://json2csharp.com/
    Hmm, results in 280 lines of code for this json and there's no guarantee it won't break with special configurations in OBS..
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,287
    I wonder if you could do it all deserializing it to
    Dictionary<string,object>
    ...

    You'd have to write code to dig in as far as you want, modify and put it back.

    There's no guarantee OBS itself won't change in the future. After all, I see...

    Another approach is to go low-tech and do it all as a string search / replace, perhaps with regexes to make things easier. Dirty, but might do it! :)
     
    Bunny83 likes this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,843
    You could use my SimpleJSON which is just a single file. It decodes to simple wrapper classes which directly represent the actual json structure (objects, arrays, number, bool, string, null).

    It's as simple as

    Code (CSharp):
    1. JSONNode n = JSON.Parse(yourJsonText);
    2. string devId = n["DesktopAudioDevice1"]["settings"]["device_id"];
    The JSONNode base class has many implicit conversion operators which makes it quite easy to convert / access the actual data. But it also has several casting properties like AsInt, AsFloat, etc. Note that the repository also has some examples of "extension" files. Since all classes are declared partial, it's very easy to implement your own conversion of a custom class that you need often. Extension files just can be dropped in your project next to the SimpleJSON.cs. There is one of some of the Unity structs (like Vector2/3/4, Matrix4x4, Color, etc).
     
    _geo__ and Kurt-Dekker like this.
  4. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,635
    Yeah I did that first but wasn't so happy with that solution.

    @Bunny83 Very nice library you wrote! Cool that such a thing exists. It solved the usecase perfectly.
    Unity should include that in the engine :D
    Have you considered putting it on the store?