366 lines
9.4 KiB
C#
366 lines
9.4 KiB
C#
|
|
#if TOOLS
|
||
|
|
|
||
|
|
using Godot;
|
||
|
|
|
||
|
|
namespace Rokojori.Tools
|
||
|
|
{
|
||
|
|
using Rokojori;
|
||
|
|
|
||
|
|
// Two-way mapping between Godot Variant and the addon's own JSON types.
|
||
|
|
// Sub-resources are referenced by resource_path; an embedded sub-resource with
|
||
|
|
// no saved path round-trips as a tagged placeholder rather than its real data -
|
||
|
|
// not needed by the first 4 routes, revisit if a fragment ever needs it.
|
||
|
|
public static class VariantJson
|
||
|
|
{
|
||
|
|
public static JSONData ToJson( Variant v )
|
||
|
|
{
|
||
|
|
switch ( v.VariantType )
|
||
|
|
{
|
||
|
|
case Variant.Type.Nil:
|
||
|
|
return new JSONValue();
|
||
|
|
|
||
|
|
case Variant.Type.Bool:
|
||
|
|
return new JSONValue( v.AsBool() );
|
||
|
|
|
||
|
|
case Variant.Type.Int:
|
||
|
|
return new JSONValue( (double) v.AsInt64() );
|
||
|
|
|
||
|
|
case Variant.Type.Float:
|
||
|
|
return new JSONValue( v.AsDouble() );
|
||
|
|
|
||
|
|
case Variant.Type.String:
|
||
|
|
case Variant.Type.StringName:
|
||
|
|
return new JSONValue( v.AsString() );
|
||
|
|
|
||
|
|
case Variant.Type.NodePath:
|
||
|
|
return new JSONValue( v.AsNodePath().ToString() );
|
||
|
|
|
||
|
|
case Variant.Type.Vector2:
|
||
|
|
return Vector2ToJson( v.AsVector2() );
|
||
|
|
|
||
|
|
case Variant.Type.Vector2I:
|
||
|
|
var v2i = v.AsVector2I();
|
||
|
|
return Vector2ToJson( new Vector2( v2i.X, v2i.Y ) );
|
||
|
|
|
||
|
|
case Variant.Type.Vector3:
|
||
|
|
return Vector3ToJson( v.AsVector3() );
|
||
|
|
|
||
|
|
case Variant.Type.Vector3I:
|
||
|
|
var v3i = v.AsVector3I();
|
||
|
|
return Vector3ToJson( new Vector3( v3i.X, v3i.Y, v3i.Z ) );
|
||
|
|
|
||
|
|
case Variant.Type.Vector4:
|
||
|
|
return Vector4ToJson( v.AsVector4() );
|
||
|
|
|
||
|
|
case Variant.Type.Color:
|
||
|
|
return ColorToJson( v.AsColor() );
|
||
|
|
|
||
|
|
case Variant.Type.Array:
|
||
|
|
return ArrayToJson( v.AsGodotArray() );
|
||
|
|
|
||
|
|
case Variant.Type.Dictionary:
|
||
|
|
return DictionaryToJson( v.AsGodotDictionary() );
|
||
|
|
|
||
|
|
case Variant.Type.Object:
|
||
|
|
return ObjectToJson( v.AsGodotObject() );
|
||
|
|
|
||
|
|
default:
|
||
|
|
// Not modeled explicitly (Rid, Callable, Signal, Transform*, Basis, Plane, Quaternion, Projection, Aabb, Rect2...).
|
||
|
|
// Falls back to a readable string so round-tripping these doesn't crash - just loses write support.
|
||
|
|
return new JSONValue( v.ToString() );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Variant FromJson( JSONData data, Variant.Type targetType )
|
||
|
|
{
|
||
|
|
if ( data == null || data.isNull )
|
||
|
|
{
|
||
|
|
return new Variant();
|
||
|
|
}
|
||
|
|
|
||
|
|
switch ( targetType )
|
||
|
|
{
|
||
|
|
case Variant.Type.Nil:
|
||
|
|
// Untyped [Export] Variant field - no declared type to convert against, shape-sniff instead.
|
||
|
|
return FromJsonInferred( data );
|
||
|
|
|
||
|
|
case Variant.Type.Bool:
|
||
|
|
return data.booleanValue;
|
||
|
|
|
||
|
|
case Variant.Type.Int:
|
||
|
|
return data.longValue;
|
||
|
|
|
||
|
|
case Variant.Type.Float:
|
||
|
|
return data.numberValue;
|
||
|
|
|
||
|
|
case Variant.Type.String:
|
||
|
|
return data.stringValue;
|
||
|
|
|
||
|
|
case Variant.Type.StringName:
|
||
|
|
return new StringName( data.stringValue );
|
||
|
|
|
||
|
|
case Variant.Type.NodePath:
|
||
|
|
return new NodePath( data.stringValue );
|
||
|
|
|
||
|
|
case Variant.Type.Vector2:
|
||
|
|
return JsonToVector2( data.AsObject() );
|
||
|
|
|
||
|
|
case Variant.Type.Vector2I:
|
||
|
|
var v2 = JsonToVector2( data.AsObject() );
|
||
|
|
return new Vector2I( (int) v2.X, (int) v2.Y );
|
||
|
|
|
||
|
|
case Variant.Type.Vector3:
|
||
|
|
return JsonToVector3( data.AsObject() );
|
||
|
|
|
||
|
|
case Variant.Type.Vector3I:
|
||
|
|
var v3 = JsonToVector3( data.AsObject() );
|
||
|
|
return new Vector3I( (int) v3.X, (int) v3.Y, (int) v3.Z );
|
||
|
|
|
||
|
|
case Variant.Type.Vector4:
|
||
|
|
return JsonToVector4( data.AsObject() );
|
||
|
|
|
||
|
|
case Variant.Type.Color:
|
||
|
|
return JsonToColor( data.AsObject() );
|
||
|
|
|
||
|
|
case Variant.Type.Array:
|
||
|
|
return JsonToArray( data.AsArray() );
|
||
|
|
|
||
|
|
case Variant.Type.Dictionary:
|
||
|
|
return JsonToDictionary( data.AsObject() );
|
||
|
|
|
||
|
|
case Variant.Type.Object:
|
||
|
|
return JsonToResource( data.AsObject() );
|
||
|
|
|
||
|
|
default:
|
||
|
|
RJLog.Error( "MCP VariantJson: write not supported for Variant type", targetType );
|
||
|
|
return new Variant();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Used for Array/Dictionary element values, which have no declared Variant type of their own -
|
||
|
|
// shape-sniffs the JSON (keys x/y/z/w, r/g/b/a, __resourcePath) rather than a real type lookup.
|
||
|
|
public static Variant FromJsonInferred( JSONData data )
|
||
|
|
{
|
||
|
|
if ( data == null || data.isNull )
|
||
|
|
{
|
||
|
|
return new Variant();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( data.isBoolean )
|
||
|
|
{
|
||
|
|
return data.booleanValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( data.isNumber )
|
||
|
|
{
|
||
|
|
return data.numberValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( data.isString )
|
||
|
|
{
|
||
|
|
return data.stringValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( data.isArray )
|
||
|
|
{
|
||
|
|
return JsonToArray( data.AsArray() );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( data.isObject )
|
||
|
|
{
|
||
|
|
var obj = data.AsObject();
|
||
|
|
|
||
|
|
if ( obj.Contains( "__resourcePath" ) )
|
||
|
|
{
|
||
|
|
return JsonToResource( obj );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( obj.Contains( "x" ) && obj.Contains( "y" ) && obj.Contains( "z" ) && obj.Contains( "w" ) )
|
||
|
|
{
|
||
|
|
return JsonToVector4( obj );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( obj.Contains( "r" ) && obj.Contains( "g" ) && obj.Contains( "b" ) )
|
||
|
|
{
|
||
|
|
return JsonToColor( obj );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( obj.Contains( "x" ) && obj.Contains( "y" ) && obj.Contains( "z" ) )
|
||
|
|
{
|
||
|
|
return JsonToVector3( obj );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( obj.Contains( "x" ) && obj.Contains( "y" ) )
|
||
|
|
{
|
||
|
|
return JsonToVector2( obj );
|
||
|
|
}
|
||
|
|
|
||
|
|
return JsonToDictionary( obj );
|
||
|
|
}
|
||
|
|
|
||
|
|
return new Variant();
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONObject Vector2ToJson( Vector2 v )
|
||
|
|
{
|
||
|
|
var o = new JSONObject();
|
||
|
|
o.Set( "x", (double) v.X );
|
||
|
|
o.Set( "y", (double) v.Y );
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONObject Vector3ToJson( Vector3 v )
|
||
|
|
{
|
||
|
|
var o = new JSONObject();
|
||
|
|
o.Set( "x", (double) v.X );
|
||
|
|
o.Set( "y", (double) v.Y );
|
||
|
|
o.Set( "z", (double) v.Z );
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONObject Vector4ToJson( Vector4 v )
|
||
|
|
{
|
||
|
|
var o = new JSONObject();
|
||
|
|
o.Set( "x", (double) v.X );
|
||
|
|
o.Set( "y", (double) v.Y );
|
||
|
|
o.Set( "z", (double) v.Z );
|
||
|
|
o.Set( "w", (double) v.W );
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONObject ColorToJson( Color c )
|
||
|
|
{
|
||
|
|
var o = new JSONObject();
|
||
|
|
o.Set( "r", (double) c.R );
|
||
|
|
o.Set( "g", (double) c.G );
|
||
|
|
o.Set( "b", (double) c.B );
|
||
|
|
o.Set( "a", (double) c.A );
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Vector2 JsonToVector2( JSONObject o )
|
||
|
|
{
|
||
|
|
if ( o == null ) return Vector2.Zero;
|
||
|
|
return new Vector2( (float) o.GetNumberOr( "x", 0 ), (float) o.GetNumberOr( "y", 0 ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Vector3 JsonToVector3( JSONObject o )
|
||
|
|
{
|
||
|
|
if ( o == null ) return Vector3.Zero;
|
||
|
|
return new Vector3( (float) o.GetNumberOr( "x", 0 ), (float) o.GetNumberOr( "y", 0 ), (float) o.GetNumberOr( "z", 0 ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Vector4 JsonToVector4( JSONObject o )
|
||
|
|
{
|
||
|
|
if ( o == null ) return Vector4.Zero;
|
||
|
|
return new Vector4( (float) o.GetNumberOr( "x", 0 ), (float) o.GetNumberOr( "y", 0 ), (float) o.GetNumberOr( "z", 0 ), (float) o.GetNumberOr( "w", 0 ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Color JsonToColor( JSONObject o )
|
||
|
|
{
|
||
|
|
if ( o == null ) return Colors.White;
|
||
|
|
return new Color(
|
||
|
|
(float) o.GetNumberOr( "r", 1 ), (float) o.GetNumberOr( "g", 1 ),
|
||
|
|
(float) o.GetNumberOr( "b", 1 ), (float) o.GetNumberOr( "a", 1 )
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONArray ArrayToJson( Godot.Collections.Array array )
|
||
|
|
{
|
||
|
|
var result = new JSONArray();
|
||
|
|
|
||
|
|
foreach ( var item in array )
|
||
|
|
{
|
||
|
|
result.Push( ToJson( item ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Godot.Collections.Array JsonToArray( JSONArray array )
|
||
|
|
{
|
||
|
|
var result = new Godot.Collections.Array();
|
||
|
|
|
||
|
|
if ( array == null )
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ( var item in array.values )
|
||
|
|
{
|
||
|
|
result.Add( FromJsonInferred( item ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONObject DictionaryToJson( Godot.Collections.Dictionary dict )
|
||
|
|
{
|
||
|
|
var result = new JSONObject();
|
||
|
|
|
||
|
|
foreach ( var key in dict.Keys )
|
||
|
|
{
|
||
|
|
result.Set( key.AsString(), ToJson( dict[ key ] ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Godot.Collections.Dictionary JsonToDictionary( JSONObject o )
|
||
|
|
{
|
||
|
|
var result = new Godot.Collections.Dictionary();
|
||
|
|
|
||
|
|
if ( o == null )
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
for ( var i = 0; i < o.keys.Count; i++ )
|
||
|
|
{
|
||
|
|
result[ o.keys[ i ] ] = FromJsonInferred( o.values[ i ] );
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static JSONData ObjectToJson( GodotObject obj )
|
||
|
|
{
|
||
|
|
if ( obj == null )
|
||
|
|
{
|
||
|
|
return new JSONValue();
|
||
|
|
}
|
||
|
|
|
||
|
|
var wrapper = new JSONObject();
|
||
|
|
|
||
|
|
if ( obj is Resource resource )
|
||
|
|
{
|
||
|
|
if ( ! string.IsNullOrEmpty( resource.ResourcePath ) )
|
||
|
|
{
|
||
|
|
wrapper.Set( "__resourcePath", resource.ResourcePath );
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
wrapper.Set( "__embeddedResourceType", resource.GetClass() );
|
||
|
|
}
|
||
|
|
|
||
|
|
return wrapper;
|
||
|
|
}
|
||
|
|
|
||
|
|
return new JSONValue( obj.ToString() );
|
||
|
|
}
|
||
|
|
|
||
|
|
public static Resource JsonToResource( JSONObject o )
|
||
|
|
{
|
||
|
|
if ( o == null || ! o.Contains( "__resourcePath" ) )
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
var path = o.GetString( "__resourcePath" );
|
||
|
|
return ResourceLoader.Load( path );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|