Skip to content
This repository has been archived by the owner on Jan 21, 2023. It is now read-only.

MonoBehaviour export as Json #477

Closed
mikuhl-dev opened this issue Jan 29, 2020 · 2 comments
Closed

MonoBehaviour export as Json #477

mikuhl-dev opened this issue Jan 29, 2020 · 2 comments

Comments

@mikuhl-dev
Copy link

It would be so cool to be able to export MonoBehaviours as Json, making it easier to sort through data.

@TheLounger
Copy link

TheLounger commented May 13, 2020

I did some work on adding JSON support to AssetStudio for TextAsset. Still isn't finished and requires some more testing. I created basic parent/child-based logic for creating hierarchies, but it's still in an early stage, creates very verbose output and may not even be the best way to do it.

The structure

public class ScriptNode
{
    public string name;
    public string type;
    public object value;
    public List<ScriptNode> children;

    public ScriptNode this[string childName] => children?.Single((ScriptNode c) => c.name == childName);
    public ScriptNode this[int childIndex] => children?.ElementAt(childIndex);

    public ScriptNode()
    public ScriptNode(string type, string name, object value = null)
    public ScriptNode(object typeInstance, string name, bool useInstanceValue = true, object value = null)

    public ScriptNode AddChildNode(object typeInstance, string name, bool useInstanceValue = true, object value = null)
    public ScriptNode AddChildNode(string type, string name, object value = null)
    public ScriptNode AddChildNode(ScriptNode node)

    public string ToJson(Formatting formatting = Formatting.Indented, JsonSerializerSettings settings = null)
    public override string ToString()
}

Example MonoBehaviour

public class DisplayObject : MonoBehaviour
{
    public GameObject gameObj;
    public int childIndex;
    public bool hasMasks;
}

MonoBehaviour asset JSON output

{
  "name": "m_MonoBehaviour",
  "type": "AssetStudio.MonoBehaviour",
  "children": [
    {
      "name": "m_GameObject",
      "type": "AssetStudio.PPtr`1[AssetStudio.GameObject]",
      "children": [
        {
          "name": "m_FileID",
          "type": "System.Int32",
          "value": 0
        },
        {
          "name": "m_PathID",
          "type": "System.Int64",
          "value": 4641
        },
        {
          "name": "m_Enabled",
          "type": "System.Byte",
          "value": 1
        }
      ]
    },
    {
      "name": "m_Script",
      "type": "AssetStudio.PPtr`1[AssetStudio.MonoScript]",
      "children": [
        {
          "name": "m_FileID",
          "type": "System.Int32",
          "value": 0
        },
        {
          "name": "m_PathID",
          "type": "System.Int64",
          "value": 3311
        },
        {
          "name": "m_Name",
          "type": "System.String",
          "value": ""
        }
      ]
    },
    {
      "name": "gameObj",
      "type": "AssetStudio.PPtr`1[UnityEngine.GameObject]",
      "children": [
        {
          "name": "m_FileID",
          "type": "System.Int32",
          "value": 0
        },
        {
          "name": "m_PathID",
          "type": "System.Int64",
          "value": 4641
        }
      ]
    },
    {
      "name": "childIndex",
      "type": "System.Int32",
      "value": 0
    },
    {
      "name": "hasMasks",
      "type": "System.Boolean",
      "value": false
    }
  ]
}

Examples of how the hierarchy is built
(inside AssetStudio's script dumper loop)

if (typeSig.FullName == "System.String")
{
    parentNode.AddChildNode(typeDef.FullName, name, reader.ReadAlignedString());
    return;
}

...

if (depth != -1 && IsAssignFromUnityObject(typeDef))
{
    var pptr = new PPtr<Object>(reader);
    var node = parentNode.AddChildNode($"AssetStudio.PPtr`1[{typeDef.FullName}]", name);
    node.AddChildNode(pptr.m_FileID, nameof(pptr.m_FileID));
    node.AddChildNode(pptr.m_PathID, nameof(pptr.m_PathID));
    return;
}

It's still using types that AssetStudio is seeing at runtime, instead of Unity runtime types it probably should be showing. I'm not sure if children ought to be removed and only use value. It is important however that it is as versatile as possible and simple to parse by other apps.

Using the JSON text would be as simple as deserializing it/casting it into the ScriptNode class.

using (StreamReader sr = new StreamReader("MonoBehaviour.json"))
using (JsonReader reader = new JsonTextReader(sr))
{
    ScriptNode root = new JsonSerializer().Deserialize<ScriptNode>(reader);

    Console.WriteLine(root["hasMasks"].value);

    ScriptNode pathId = root["gameObj"]["m_PathID"];
    Console.WriteLine($"{pathId.type} {pathId.name}: {pathId.value}");
}
False
System.Int64 m_PathID: 4641

Comments, suggestions? 😄

AssetStudio_JSON_Export.mkv.exe.bmp.gif

@Perfare
Copy link
Owner

Perfare commented Aug 14, 2020

@MichaelPriebe @TheLounger I refactored the parsing part of MonoBehaviour, I think it is now almost perfect and can output json.

hexstr pushed a commit to hexstr/AssetStudio that referenced this issue Oct 19, 2021
Former-commit-id: 835b6ccaffe70f47f4816c4b1dca8ec88f35e6d1
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants