|
@@ -2,64 +2,91 @@ Namespace mojo3d.jsonifier
|
|
|
|
|
|
Class Jsonifier
|
|
Class Jsonifier
|
|
|
|
|
|
|
|
+Private
|
|
|
|
+
|
|
|
|
+ Class Instance
|
|
|
|
+ Field id:Int
|
|
|
|
+ Field obj:Variant
|
|
|
|
+ Field ctor:Invocation
|
|
|
|
+ Field initialState:JsonObject
|
|
|
|
+
|
|
|
|
+ Operator To:String()
|
|
|
|
+ Return "Instance(type="+obj.Type+" dynamic type="+obj.DynamicType+")"
|
|
|
|
+ End
|
|
|
|
+ End
|
|
|
|
+
|
|
|
|
+ Field _loading:Int
|
|
|
|
+ Field _instLoading:Int
|
|
|
|
+ Field _instsByObj:=New Map<Object,Instance>
|
|
|
|
+ Field _insts:=New Stack<Instance>
|
|
|
|
+
|
|
|
|
+Public
|
|
|
|
+
|
|
|
|
+ Method BeginLoading()
|
|
|
|
+
|
|
|
|
+ _loading+=1
|
|
|
|
+
|
|
|
|
+ If _loading>1 Return
|
|
|
|
+
|
|
|
|
+ _instLoading=_insts.Length
|
|
|
|
+ End
|
|
|
|
+
|
|
|
|
+ Method EndLoading()
|
|
|
|
+
|
|
|
|
+ _loading-=1
|
|
|
|
+
|
|
|
|
+ If _loading Return
|
|
|
|
+
|
|
|
|
+ For Local i:=_instLoading Until _insts.Length
|
|
|
|
+ Local inst:=_insts[i]
|
|
|
|
+ Local tobj:=Cast<Object>( inst.obj )
|
|
|
|
+ inst.initialState=JsonifyState( tobj )
|
|
|
|
+ next
|
|
|
|
+ End
|
|
|
|
+
|
|
Method AddInstance( obj:Variant,ctor:Invocation )
|
|
Method AddInstance( obj:Variant,ctor:Invocation )
|
|
|
|
|
|
Local tobj:=Cast<Object>( obj )
|
|
Local tobj:=Cast<Object>( obj )
|
|
|
|
|
|
- Assert( Not _instsByObj.Contains( tobj ) )
|
|
|
|
-
|
|
|
|
- Local inst:=New Instance
|
|
|
|
|
|
+ Local inst:=_instsByObj[tobj]
|
|
|
|
+ If inst
|
|
|
|
+ If inst.ctor Print "Warning: overwriting instance ctor for "+inst
|
|
|
|
+ inst.ctor=ctor
|
|
|
|
+ Return
|
|
|
|
+ Endif
|
|
|
|
+
|
|
|
|
+ inst=New Instance
|
|
|
|
+ inst.id=_insts.Length
|
|
inst.obj=obj
|
|
inst.obj=obj
|
|
- inst.id="@"+String(_insts.Length)
|
|
|
|
- inst.ctor=ctor
|
|
|
|
- inst.initialState=JsonifyState( tobj )
|
|
|
|
|
|
|
|
- _instsByObj[tobj]=inst
|
|
|
|
- _instsById[inst.id]=inst
|
|
|
|
-
|
|
|
|
_insts.Add( inst )
|
|
_insts.Add( inst )
|
|
- End
|
|
|
|
-
|
|
|
|
- 'ctor via ctor
|
|
|
|
- Method AddInstance( obj:Variant,args:Variant[] )
|
|
|
|
-
|
|
|
|
- AddInstance( obj,New Invocation( obj.DynamicType,"New",Null,args ) )
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
- 'ctor via method call
|
|
|
|
- Method AddInstance( obj:Variant,decl:String,inst:Variant,args:Variant[] )
|
|
|
|
|
|
+ _instsByObj[tobj]=inst
|
|
|
|
|
|
- AddInstance( obj,New Invocation( decl,inst,args ) )
|
|
|
|
- End
|
|
|
|
|
|
+ If _loading Return
|
|
|
|
|
|
- 'ctor via function call
|
|
|
|
- Method AddInstance( obj:Variant,decl:String,args:Variant[] )
|
|
|
|
-
|
|
|
|
- AddInstance( obj,New Invocation( decl,Null,args ) )
|
|
|
|
|
|
+ inst.ctor=ctor
|
|
|
|
+ inst.initialState=JsonifyState( tobj )
|
|
End
|
|
End
|
|
-
|
|
|
|
|
|
+
|
|
Method JsonifyInstances:JsonObject()
|
|
Method JsonifyInstances:JsonObject()
|
|
|
|
|
|
Local jobj:=New JsonObject
|
|
Local jobj:=New JsonObject
|
|
|
|
|
|
jobj["assetsDir"]=New JsonString( AssetsDir() )
|
|
jobj["assetsDir"]=New JsonString( AssetsDir() )
|
|
|
|
|
|
- Local jinsts:=New JsonArray( _insts.Length )
|
|
|
|
|
|
+ Local jinsts:=New Stack<JsonValue>
|
|
|
|
|
|
For Local i:=0 Until _insts.Length
|
|
For Local i:=0 Until _insts.Length
|
|
|
|
|
|
- Local jobj:=New JsonObject
|
|
|
|
|
|
+' Print "Jsonifying "+i
|
|
|
|
|
|
Local inst:=_insts[i]
|
|
Local inst:=_insts[i]
|
|
Local tobj:=Cast<Object>( inst.obj )
|
|
Local tobj:=Cast<Object>( inst.obj )
|
|
|
|
+
|
|
|
|
+ 'compute delta state
|
|
|
|
+ Local state:=JsonifyState( tobj )
|
|
|
|
|
|
- jobj["id"]=New JsonString( inst.id )
|
|
|
|
-
|
|
|
|
- jobj["type"]=New JsonString( tobj.DynamicType.Name )
|
|
|
|
-
|
|
|
|
- jobj["ctor"]=Jsonify( inst.ctor )
|
|
|
|
-
|
|
|
|
- Local state:=JsonifyState( tobj ),dstate:=New JsonObject
|
|
|
|
|
|
+ Local dstate:=New JsonObject
|
|
|
|
|
|
For Local it:=Eachin state.All()
|
|
For Local it:=Eachin state.All()
|
|
|
|
|
|
@@ -69,12 +96,19 @@ Class Jsonifier
|
|
If CompareJson( x,y )<>0 dstate[it.Key]=x
|
|
If CompareJson( x,y )<>0 dstate[it.Key]=x
|
|
Next
|
|
Next
|
|
|
|
|
|
- jobj["state"]=dstate
|
|
|
|
|
|
+ If Not inst.ctor And dstate.Empty Continue
|
|
|
|
+
|
|
|
|
+ Local jobj:=New JsonObject
|
|
|
|
+ jobj["type"]=New JsonString( tobj.DynamicType.Name ) 'not actually used, cool for debug
|
|
|
|
+
|
|
|
|
+ jobj["id"]=New JsonNumber( inst.id )
|
|
|
|
+ If inst.ctor jobj["ctor"]=Jsonify( inst.ctor )
|
|
|
|
+ If Not dstate.Empty jobj["state"]=dstate
|
|
|
|
|
|
- jinsts[i]=jobj
|
|
|
|
|
|
+ jinsts.Add( jobj )
|
|
Next
|
|
Next
|
|
|
|
|
|
- jobj["instances"]=jinsts
|
|
|
|
|
|
+ jobj["instances"]=New JsonArray( jinsts )
|
|
|
|
|
|
Return jobj
|
|
Return jobj
|
|
End
|
|
End
|
|
@@ -86,44 +120,73 @@ Class Jsonifier
|
|
If jobj.Contains( "assetsDir" ) SetAssetsDir( jobj.GetString( "assetsDir" ) )
|
|
If jobj.Contains( "assetsDir" ) SetAssetsDir( jobj.GetString( "assetsDir" ) )
|
|
|
|
|
|
Local jinsts:=jobj.GetArray( "instances" )
|
|
Local jinsts:=jobj.GetArray( "instances" )
|
|
|
|
+
|
|
|
|
+ Local jobjsById:=New IntMap<JsonObject>
|
|
|
|
|
|
For Local i:=0 Until jinsts.Length
|
|
For Local i:=0 Until jinsts.Length
|
|
|
|
|
|
Local jobj:=jinsts.GetObject( i )
|
|
Local jobj:=jinsts.GetObject( i )
|
|
|
|
+ Assert( jobj.Contains( "id" ) )
|
|
|
|
|
|
- Local obj:Variant
|
|
|
|
-
|
|
|
|
- If i<_insts.Length
|
|
|
|
-
|
|
|
|
- obj=_insts[i].obj
|
|
|
|
- Else
|
|
|
|
- Local ctor:=Cast<Invocation>( Dejsonify( jobj["ctor"],Typeof<Invocation> ) )
|
|
|
|
|
|
+ Local id:=jobj.GetNumber( "id" )
|
|
|
|
+ Assert( Not jobjsById.Contains( id ) )
|
|
|
|
|
|
- obj=ctor.Execute()
|
|
|
|
- Endif
|
|
|
|
-
|
|
|
|
- _dejsonified.Add( obj )
|
|
|
|
|
|
+ jobjsById[id]=jobj
|
|
|
|
+ Next
|
|
|
|
+
|
|
|
|
+ 'copy of insts alreday created (ie: initial Scene)
|
|
|
|
+ Local tinsts:=_insts.ToArray(),id:=0
|
|
|
|
+
|
|
|
|
+ For Local i:=0 Until jinsts.Length
|
|
|
|
|
|
- Local tobj:=Cast<Object>( obj )
|
|
|
|
|
|
+ Local jobj:=jinsts.GetObject( i )
|
|
|
|
+ If Not jobj.Contains( "ctor" ) Continue
|
|
|
|
|
|
- 'set value type state only on this pass.
|
|
|
|
- If jobj.Contains( "state" ) DejsonifyState( tobj,jobj.GetObject( "state" ),tobj.DynamicType,False )
|
|
|
|
- Next
|
|
|
|
|
|
+ Local ctor:=Cast<Invocation>( Dejsonify( jobj["ctor"],Typeof<Invocation> ) )
|
|
|
|
+ ctor.Execute()
|
|
|
|
+
|
|
|
|
+ For Local j:=id Until _insts.Length
|
|
|
|
+
|
|
|
|
+ If Not jobjsById.Contains( j ) Continue
|
|
|
|
|
|
- 'set reference type state - do this on a second pass 'coz of forward refs. Probably wont always work?
|
|
|
|
- For Local i:=0 Until _dejsonified.Length
|
|
|
|
|
|
+ Local jobj:=jobjsById[j]
|
|
|
|
+ Local tobj:=Cast<Object>( _insts[j].obj )
|
|
|
|
+ If jobj.Contains( "state" ) DejsonifyState( tobj,jobj.GetObject( "state" ),tobj.DynamicType,False )
|
|
|
|
+ Next
|
|
|
|
|
|
- Local jobj:=jinsts.GetObject( i )
|
|
|
|
|
|
+ id=_insts.Length
|
|
|
|
|
|
- Local obj:=_dejsonified[i]
|
|
|
|
|
|
+ Next
|
|
|
|
+
|
|
|
|
+ 'set reference type state - do this on a second pass 'coz of forward refs. Probably wont always work?
|
|
|
|
+ For Local i:=0 Until _insts.Length
|
|
|
|
|
|
- Local tobj:=Cast<Object>( obj )
|
|
|
|
|
|
+ If Not jobjsById.Contains( i ) Continue
|
|
|
|
|
|
|
|
+ Local jobj:=jobjsById[i]
|
|
|
|
+ Local tobj:=Cast<Object>( _insts[i].obj )
|
|
If jobj.Contains( "state" ) DejsonifyState( tobj,jobj.GetObject( "state" ),tobj.DynamicType,True )
|
|
If jobj.Contains( "state" ) DejsonifyState( tobj,jobj.GetObject( "state" ),tobj.DynamicType,True )
|
|
Next
|
|
Next
|
|
|
|
|
|
SetAssetsDir( assetsDir )
|
|
SetAssetsDir( assetsDir )
|
|
End
|
|
End
|
|
|
|
+ 'ctor via ctor
|
|
|
|
+ Method AddInstance( obj:Variant,args:Variant[] )
|
|
|
|
+
|
|
|
|
+ AddInstance( obj,New Invocation( obj.DynamicType,"New",Null,args ) )
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ 'ctor via method call
|
|
|
|
+ Method AddInstance( obj:Variant,decl:String,inst:Variant,args:Variant[] )
|
|
|
|
+
|
|
|
|
+ AddInstance( obj,New Invocation( decl,inst,args ) )
|
|
|
|
+ End
|
|
|
|
+
|
|
|
|
+ 'ctor via function call
|
|
|
|
+ Method AddInstance( obj:Variant,decl:String,args:Variant[] )
|
|
|
|
+
|
|
|
|
+ AddInstance( obj,New Invocation( decl,Null,args ) )
|
|
|
|
+ End
|
|
|
|
|
|
Method Jsonify:JsonValue( value:Variant )
|
|
Method Jsonify:JsonValue( value:Variant )
|
|
|
|
|
|
@@ -131,7 +194,7 @@ Class Jsonifier
|
|
|
|
|
|
Local type:=value.Type
|
|
Local type:=value.Type
|
|
Assert( type )
|
|
Assert( type )
|
|
-
|
|
|
|
|
|
+
|
|
'handle primitive types
|
|
'handle primitive types
|
|
Select type
|
|
Select type
|
|
Case Typeof<Bool>
|
|
Case Typeof<Bool>
|
|
@@ -152,7 +215,7 @@ Class Jsonifier
|
|
Local obj:=Cast<Object>( value )
|
|
Local obj:=Cast<Object>( value )
|
|
If Not obj Return JsonValue.NullValue
|
|
If Not obj Return JsonValue.NullValue
|
|
Local inst:=_instsByObj[obj]
|
|
Local inst:=_instsByObj[obj]
|
|
- If inst Return New JsonString( inst.id )
|
|
|
|
|
|
+ If inst Return New JsonString( "@"+inst.id )
|
|
Case "Enum"
|
|
Case "Enum"
|
|
Return New JsonNumber( value.EnumValue )
|
|
Return New JsonNumber( value.EnumValue )
|
|
End
|
|
End
|
|
@@ -164,6 +227,11 @@ Class Jsonifier
|
|
Next
|
|
Next
|
|
|
|
|
|
Select type.Kind
|
|
Select type.Kind
|
|
|
|
+ Case "Unknown"
|
|
|
|
+ Local obj:=Cast<Object>( value )
|
|
|
|
+ If Not obj Return JsonValue.NullValue
|
|
|
|
+ Local inst:=_instsByObj[obj]
|
|
|
|
+ If inst Return New JsonString( "@"+inst.id )
|
|
Case "Class"
|
|
Case "Class"
|
|
Return JsonValue.NullValue
|
|
Return JsonValue.NullValue
|
|
Case "Array"
|
|
Case "Array"
|
|
@@ -207,9 +275,8 @@ Class Jsonifier
|
|
Return type.NullValue
|
|
Return type.NullValue
|
|
Elseif jvalue.IsString
|
|
Elseif jvalue.IsString
|
|
Local id:=Int( jvalue.ToString().Slice( 1 ) )
|
|
Local id:=Int( jvalue.ToString().Slice( 1 ) )
|
|
- Assert( id>=0 And id<_dejsonified.Length,"Dejsonify error" )
|
|
|
|
- Local inst:=_dejsonified[id]
|
|
|
|
- Return inst
|
|
|
|
|
|
+ Assert( id>=0 And id<_insts.Length,"Dejsonify error" )
|
|
|
|
+ Return _insts[id].obj
|
|
Endif
|
|
Endif
|
|
Case "Enum"
|
|
Case "Enum"
|
|
Return type.MakeEnum( jvalue.ToNumber() )
|
|
Return type.MakeEnum( jvalue.ToNumber() )
|
|
@@ -222,6 +289,12 @@ Class Jsonifier
|
|
Next
|
|
Next
|
|
|
|
|
|
Select type.Kind
|
|
Select type.Kind
|
|
|
|
+ Case "Unknown"
|
|
|
|
+ If jvalue.IsString
|
|
|
|
+ Local id:=Int( jvalue.ToString().Slice( 1 ) )
|
|
|
|
+ Assert( id>=0 And id<_insts.Length,"Dejsonify error" )
|
|
|
|
+ Return _insts[id].obj
|
|
|
|
+ Endif
|
|
Case "Class"
|
|
Case "Class"
|
|
Return type.NullValue
|
|
Return type.NullValue
|
|
Case "Array"
|
|
Case "Array"
|
|
@@ -242,20 +315,6 @@ Class Jsonifier
|
|
|
|
|
|
Private
|
|
Private
|
|
|
|
|
|
- Class Instance
|
|
|
|
- Field obj:Variant
|
|
|
|
- Field id:String
|
|
|
|
- Field ctor:Invocation
|
|
|
|
- Field initialState:JsonObject
|
|
|
|
- End
|
|
|
|
-
|
|
|
|
- Field _insts:=New Stack<Instance>
|
|
|
|
-
|
|
|
|
- Field _instsByObj:=New Map<Object,Instance>
|
|
|
|
- Field _instsById:=New StringMap<Instance>
|
|
|
|
-
|
|
|
|
- Field _dejsonified:=New Stack<Variant>
|
|
|
|
-
|
|
|
|
Method JsonifyState:JsonObject( obj:Object )
|
|
Method JsonifyState:JsonObject( obj:Object )
|
|
|
|
|
|
Local jobj:=New JsonObject
|
|
Local jobj:=New JsonObject
|
|
@@ -300,7 +359,7 @@ Class Jsonifier
|
|
|
|
|
|
Local type:=d.Type
|
|
Local type:=d.Type
|
|
|
|
|
|
- Local isinst:=type.Kind="Class"
|
|
|
|
|
|
+ Local isinst:=type.Kind="Class" Or type.Kind="Unknown"
|
|
|
|
|
|
If Not isinst And type.Kind="Array" And type.ElementType.Kind="Class" isinst=True
|
|
If Not isinst And type.Kind="Array" And type.ElementType.Kind="Class" isinst=True
|
|
|
|
|