@@ -45,15 +45,38 @@ public class FbxPrefab : MonoBehaviour
45
45
#if UNITY_EDITOR
46
46
public class FbxRepresentation
47
47
{
48
- public Dictionary < string , FbxRepresentation > c ;
48
+ /// <summary>
49
+ /// Children of this node.
50
+ /// The key is the name, which is assumed to be unique.
51
+ /// The value is, recursively, the representation of that subtree.
52
+ /// </summary>
53
+ Dictionary < string , FbxRepresentation > children ;
54
+
55
+ /// <summary>
56
+ /// Children of this node.
57
+ /// The key is the name of the type of the Component. We accept that there may be several.
58
+ /// The value is the json for the component, to be decoded with EditorJsonUtility.
59
+ /// </summary>
60
+ Dictionary < string , List < string > > components ;
49
61
50
62
public static FbxRepresentation FromTransform ( Transform xfo ) {
51
- var c = new Dictionary < string , FbxRepresentation > ( ) ;
63
+ var children = new Dictionary < string , FbxRepresentation > ( ) ;
52
64
foreach ( Transform child in xfo ) {
53
- c . Add ( child . name , FromTransform ( child ) ) ;
65
+ children . Add ( child . name , FromTransform ( child ) ) ;
66
+ }
67
+ var components = new Dictionary < string , List < string > > ( ) ;
68
+ foreach ( var component in xfo . GetComponents < Component > ( ) ) {
69
+ var typeName = component . GetType ( ) . ToString ( ) ;
70
+ List < string > comps ;
71
+ if ( ! components . TryGetValue ( typeName , out comps ) ) {
72
+ comps = new List < string > ( ) ;
73
+ components [ typeName ] = comps ;
74
+ }
75
+ comps . Add ( UnityEditor . EditorJsonUtility . ToJson ( component ) ) ;
54
76
}
55
77
var fbxrep = new FbxRepresentation ( ) ;
56
- fbxrep . c = c ;
78
+ fbxrep . children = children ;
79
+ fbxrep . components = components ;
57
80
return fbxrep ;
58
81
}
59
82
@@ -78,50 +101,115 @@ static bool Consume(char expected, string json, ref int index, bool required = t
78
101
}
79
102
}
80
103
104
+ // %-escape a string to make sure that " and \ are set up to be easy to parse
105
+ static string EscapeString ( string str ) {
106
+ var builder = new System . Text . StringBuilder ( ) ;
107
+ foreach ( var c in str ) {
108
+ switch ( c ) {
109
+ case '%' : builder . Append ( "%25" ) ; break ;
110
+ case '\\ ' : builder . Append ( "%5c" ) ; break ;
111
+ case '"' : builder . Append ( "%22" ) ; break ;
112
+ default : builder . Append ( c ) ; break ;
113
+ }
114
+ }
115
+ return builder . ToString ( ) ;
116
+ }
117
+
118
+ static string UnEscapeString ( string str , int index , int len ) {
119
+ var builder = new System . Text . StringBuilder ( ) ;
120
+ for ( int i = index ; i < index + len ; ++ i ) {
121
+ if ( str [ i ] != '%' ) {
122
+ builder . Append ( str [ i ] ) ;
123
+ } else {
124
+ string number = str . Substring ( i + 1 , 2 ) ;
125
+ int ord = System . Convert . ToInt32 ( number , 16 ) ;
126
+ builder . Append ( ( char ) ord ) ;
127
+ }
128
+ }
129
+ return builder . ToString ( ) ;
130
+ }
131
+
81
132
static FbxRepresentation FromJsonHelper ( string json , ref int index ) {
82
133
Consume ( '{' , json , ref index ) ;
83
134
var fbxrep = new FbxRepresentation ( ) ;
84
135
if ( Consume ( '}' , json , ref index , required : false ) ) {
85
136
// this is a leaf; we're done.
86
137
} else {
87
- // this is a parent of one or more objects; store them.
88
- fbxrep . c = new Dictionary < string , FbxRepresentation > ( ) ;
138
+ // this is a node with important data
139
+ fbxrep . children = new Dictionary < string , FbxRepresentation > ( ) ;
140
+ fbxrep . components = new Dictionary < string , List < string > > ( ) ;
141
+
89
142
do {
90
143
Consume ( '"' , json , ref index ) ;
91
144
int nameStart = index ;
92
145
while ( json [ index ] != '"' ) { index ++ ; }
93
146
string name = json . Substring ( nameStart , index - nameStart ) ;
94
147
index ++ ;
95
148
Consume ( ':' , json , ref index ) ;
96
- var subrep = FromJsonHelper ( json , ref index ) ;
97
- fbxrep . c . Add ( name , subrep ) ;
149
+ // if name starts with - it's a child; otherwise it's a
150
+ // component (which can't start with a - because it's
151
+ // the name of a C# type)
152
+ if ( name [ 0 ] == '-' ) {
153
+ var subrep = FromJsonHelper ( json , ref index ) ;
154
+ fbxrep . children . Add ( name . Substring ( 1 ) , subrep ) ;
155
+ } else {
156
+ // Read the string. It won't have any quote marks
157
+ // in it, because we escape them using %-encoding
158
+ // like in a URL.
159
+ Consume ( '"' , json , ref index ) ;
160
+ int componentStart = index ;
161
+ while ( json [ index ] != '"' ) { index ++ ; }
162
+ index ++ ;
163
+
164
+ // We %-escaped the string so there would be no
165
+ // quotes (nor backslashes that might confuse other
166
+ // json parsers), now undo that.
167
+ List < string > comps ;
168
+ if ( ! fbxrep . components . TryGetValue ( name , out comps ) ) {
169
+ comps = new List < string > ( ) ;
170
+ fbxrep . components [ name ] = comps ;
171
+ }
172
+ comps . Add ( UnEscapeString ( json , componentStart , index - componentStart ) ) ;
173
+ }
98
174
} while ( Consume ( ',' , json , ref index , required : false ) ) ;
99
175
Consume ( '}' , json , ref index ) ;
100
176
}
101
177
return fbxrep ;
102
178
}
103
179
104
180
public static FbxRepresentation FromJson ( string json ) {
105
- if ( json . Length == 0 ) { return null ; }
181
+ if ( json . Length == 0 ) { return new FbxRepresentation ( ) ; }
106
182
int index = 0 ;
107
183
return FromJsonHelper ( json , ref index ) ;
108
184
}
109
185
110
186
void ToJsonHelper ( System . Text . StringBuilder builder ) {
111
187
builder . Append ( "{" ) ;
112
- if ( c != null ) {
113
- bool first = true ;
114
- foreach ( var kvp in c . OrderBy ( kvp => kvp . Key ) ) {
188
+ bool first = true ;
189
+ if ( children != null ) {
190
+ foreach ( var kvp in children . OrderBy ( kvp => kvp . Key ) ) {
115
191
if ( ! first ) { builder . Append ( ',' ) ; }
116
192
else { first = false ; }
117
193
118
- builder . Append ( '"' ) ;
119
- builder . Append ( kvp . Key ) ; // the name
120
- builder . Append ( '"' ) ;
121
- builder . Append ( ':' ) ;
194
+ // print names with a '-' in front
195
+ builder . AppendFormat ( "\" -{0}\" :" , kvp . Key ) ;
122
196
kvp . Value . ToJsonHelper ( builder ) ;
123
197
}
124
198
}
199
+ if ( components != null ) {
200
+ foreach ( var kvp in components . OrderBy ( kvp => kvp . Key ) ) {
201
+ var name = kvp . Key ;
202
+ foreach ( var componentValue in kvp . Value ) {
203
+ if ( ! first ) { builder . Append ( ',' ) ; }
204
+ else { first = false ; }
205
+
206
+ // print component name and value, but escape the value
207
+ // string to make sure we can parse it later
208
+ builder . AppendFormat ( "\" {0}\" : \" {1}\" " , name ,
209
+ EscapeString ( componentValue ) ) ;
210
+ }
211
+ }
212
+ }
125
213
builder . Append ( "}" ) ;
126
214
}
127
215
@@ -132,22 +220,22 @@ public string ToJson() {
132
220
}
133
221
134
222
public static bool IsLeaf ( FbxRepresentation rep ) {
135
- return rep == null || rep . c == null ;
223
+ return rep == null || rep . children == null ;
136
224
}
137
225
138
226
public static HashSet < string > CopyKeySet ( FbxRepresentation rep ) {
139
227
if ( IsLeaf ( rep ) ) {
140
228
return new HashSet < string > ( ) ;
141
229
} else {
142
- return new HashSet < string > ( rep . c . Keys ) ;
230
+ return new HashSet < string > ( rep . children . Keys ) ;
143
231
}
144
232
}
145
233
146
234
public static FbxRepresentation Find ( FbxRepresentation rep , string key ) {
147
235
if ( IsLeaf ( rep ) ) { return null ; }
148
236
149
237
FbxRepresentation child ;
150
- if ( rep . c . TryGetValue ( key , out child ) ) {
238
+ if ( rep . children . TryGetValue ( key , out child ) ) {
151
239
return child ;
152
240
}
153
241
return null ;
@@ -164,7 +252,6 @@ public static FbxRepresentation Find(FbxRepresentation rep, string key) {
164
252
/// </summary>
165
253
public class UpdateList
166
254
{
167
-
168
255
// We build up a flat list of names for the nodes of the old fbx,
169
256
// the new fbx, and the prefab. We also figure out the parents.
170
257
class Data {
@@ -502,6 +589,15 @@ public FbxRepresentation GetFbxHistory()
502
589
return FbxRepresentation . FromJson ( m_fbxHistory ) ;
503
590
}
504
591
592
+ /// <summary>
593
+ /// Returns the string representation of the fbx file as it was last time we sync'd.
594
+ /// Really just for debugging.
595
+ /// </summary>
596
+ public string GetFbxHistoryString ( )
597
+ {
598
+ return m_fbxHistory ;
599
+ }
600
+
505
601
/// <summary>
506
602
/// Sync the prefab to match the FBX file.
507
603
/// </summary>
0 commit comments