1+ using Newtonsoft . Json ;
2+ using Newtonsoft . Json . Linq ;
3+ using System ;
4+ using UnityEngine ;
5+ #if UNITY_EDITOR
6+ using UnityEditor ; // Required for AssetDatabase and EditorUtility
7+ #endif
8+
9+ namespace UnityMcpBridge . Runtime . Serialization
10+ {
11+ public class Vector3Converter : JsonConverter < Vector3 >
12+ {
13+ public override void WriteJson ( JsonWriter writer , Vector3 value , JsonSerializer serializer )
14+ {
15+ writer . WriteStartObject ( ) ;
16+ writer . WritePropertyName ( "x" ) ;
17+ writer . WriteValue ( value . x ) ;
18+ writer . WritePropertyName ( "y" ) ;
19+ writer . WriteValue ( value . y ) ;
20+ writer . WritePropertyName ( "z" ) ;
21+ writer . WriteValue ( value . z ) ;
22+ writer . WriteEndObject ( ) ;
23+ }
24+
25+ public override Vector3 ReadJson ( JsonReader reader , Type objectType , Vector3 existingValue , bool hasExistingValue , JsonSerializer serializer )
26+ {
27+ JObject jo = JObject . Load ( reader ) ;
28+ return new Vector3 (
29+ ( float ) jo [ "x" ] ,
30+ ( float ) jo [ "y" ] ,
31+ ( float ) jo [ "z" ]
32+ ) ;
33+ }
34+ }
35+
36+ public class Vector2Converter : JsonConverter < Vector2 >
37+ {
38+ public override void WriteJson ( JsonWriter writer , Vector2 value , JsonSerializer serializer )
39+ {
40+ writer . WriteStartObject ( ) ;
41+ writer . WritePropertyName ( "x" ) ;
42+ writer . WriteValue ( value . x ) ;
43+ writer . WritePropertyName ( "y" ) ;
44+ writer . WriteValue ( value . y ) ;
45+ writer . WriteEndObject ( ) ;
46+ }
47+
48+ public override Vector2 ReadJson ( JsonReader reader , Type objectType , Vector2 existingValue , bool hasExistingValue , JsonSerializer serializer )
49+ {
50+ JObject jo = JObject . Load ( reader ) ;
51+ return new Vector2 (
52+ ( float ) jo [ "x" ] ,
53+ ( float ) jo [ "y" ]
54+ ) ;
55+ }
56+ }
57+
58+ public class QuaternionConverter : JsonConverter < Quaternion >
59+ {
60+ public override void WriteJson ( JsonWriter writer , Quaternion value , JsonSerializer serializer )
61+ {
62+ writer . WriteStartObject ( ) ;
63+ writer . WritePropertyName ( "x" ) ;
64+ writer . WriteValue ( value . x ) ;
65+ writer . WritePropertyName ( "y" ) ;
66+ writer . WriteValue ( value . y ) ;
67+ writer . WritePropertyName ( "z" ) ;
68+ writer . WriteValue ( value . z ) ;
69+ writer . WritePropertyName ( "w" ) ;
70+ writer . WriteValue ( value . w ) ;
71+ writer . WriteEndObject ( ) ;
72+ }
73+
74+ public override Quaternion ReadJson ( JsonReader reader , Type objectType , Quaternion existingValue , bool hasExistingValue , JsonSerializer serializer )
75+ {
76+ JObject jo = JObject . Load ( reader ) ;
77+ return new Quaternion (
78+ ( float ) jo [ "x" ] ,
79+ ( float ) jo [ "y" ] ,
80+ ( float ) jo [ "z" ] ,
81+ ( float ) jo [ "w" ]
82+ ) ;
83+ }
84+ }
85+
86+ public class ColorConverter : JsonConverter < Color >
87+ {
88+ public override void WriteJson ( JsonWriter writer , Color value , JsonSerializer serializer )
89+ {
90+ writer . WriteStartObject ( ) ;
91+ writer . WritePropertyName ( "r" ) ;
92+ writer . WriteValue ( value . r ) ;
93+ writer . WritePropertyName ( "g" ) ;
94+ writer . WriteValue ( value . g ) ;
95+ writer . WritePropertyName ( "b" ) ;
96+ writer . WriteValue ( value . b ) ;
97+ writer . WritePropertyName ( "a" ) ;
98+ writer . WriteValue ( value . a ) ;
99+ writer . WriteEndObject ( ) ;
100+ }
101+
102+ public override Color ReadJson ( JsonReader reader , Type objectType , Color existingValue , bool hasExistingValue , JsonSerializer serializer )
103+ {
104+ JObject jo = JObject . Load ( reader ) ;
105+ return new Color (
106+ ( float ) jo [ "r" ] ,
107+ ( float ) jo [ "g" ] ,
108+ ( float ) jo [ "b" ] ,
109+ ( float ) jo [ "a" ]
110+ ) ;
111+ }
112+ }
113+
114+ public class RectConverter : JsonConverter < Rect >
115+ {
116+ public override void WriteJson ( JsonWriter writer , Rect value , JsonSerializer serializer )
117+ {
118+ writer . WriteStartObject ( ) ;
119+ writer . WritePropertyName ( "x" ) ;
120+ writer . WriteValue ( value . x ) ;
121+ writer . WritePropertyName ( "y" ) ;
122+ writer . WriteValue ( value . y ) ;
123+ writer . WritePropertyName ( "width" ) ;
124+ writer . WriteValue ( value . width ) ;
125+ writer . WritePropertyName ( "height" ) ;
126+ writer . WriteValue ( value . height ) ;
127+ writer . WriteEndObject ( ) ;
128+ }
129+
130+ public override Rect ReadJson ( JsonReader reader , Type objectType , Rect existingValue , bool hasExistingValue , JsonSerializer serializer )
131+ {
132+ JObject jo = JObject . Load ( reader ) ;
133+ return new Rect (
134+ ( float ) jo [ "x" ] ,
135+ ( float ) jo [ "y" ] ,
136+ ( float ) jo [ "width" ] ,
137+ ( float ) jo [ "height" ]
138+ ) ;
139+ }
140+ }
141+
142+ public class BoundsConverter : JsonConverter < Bounds >
143+ {
144+ public override void WriteJson ( JsonWriter writer , Bounds value , JsonSerializer serializer )
145+ {
146+ writer . WriteStartObject ( ) ;
147+ writer . WritePropertyName ( "center" ) ;
148+ serializer . Serialize ( writer , value . center ) ; // Use serializer to handle nested Vector3
149+ writer . WritePropertyName ( "size" ) ;
150+ serializer . Serialize ( writer , value . size ) ; // Use serializer to handle nested Vector3
151+ writer . WriteEndObject ( ) ;
152+ }
153+
154+ public override Bounds ReadJson ( JsonReader reader , Type objectType , Bounds existingValue , bool hasExistingValue , JsonSerializer serializer )
155+ {
156+ JObject jo = JObject . Load ( reader ) ;
157+ Vector3 center = jo [ "center" ] . ToObject < Vector3 > ( serializer ) ; // Use serializer to handle nested Vector3
158+ Vector3 size = jo [ "size" ] . ToObject < Vector3 > ( serializer ) ; // Use serializer to handle nested Vector3
159+ return new Bounds ( center , size ) ;
160+ }
161+ }
162+
163+ // Converter for UnityEngine.Object references (GameObjects, Components, Materials, Textures, etc.)
164+ public class UnityEngineObjectConverter : JsonConverter < UnityEngine . Object >
165+ {
166+ public override bool CanRead => true ; // We need to implement ReadJson
167+ public override bool CanWrite => true ;
168+
169+ public override void WriteJson ( JsonWriter writer , UnityEngine . Object value , JsonSerializer serializer )
170+ {
171+ if ( value == null )
172+ {
173+ writer . WriteNull ( ) ;
174+ return ;
175+ }
176+
177+ #if UNITY_EDITOR // AssetDatabase and EditorUtility are Editor-only
178+ if ( UnityEditor . AssetDatabase . Contains ( value ) )
179+ {
180+ // It's an asset (Material, Texture, Prefab, etc.)
181+ string path = UnityEditor . AssetDatabase . GetAssetPath ( value ) ;
182+ if ( ! string . IsNullOrEmpty ( path ) )
183+ {
184+ writer . WriteValue ( path ) ;
185+ }
186+ else
187+ {
188+ // Asset exists but path couldn't be found? Write minimal info.
189+ writer . WriteStartObject ( ) ;
190+ writer . WritePropertyName ( "name" ) ;
191+ writer . WriteValue ( value . name ) ;
192+ writer . WritePropertyName ( "instanceID" ) ;
193+ writer . WriteValue ( value . GetInstanceID ( ) ) ;
194+ writer . WritePropertyName ( "isAssetWithoutPath" ) ;
195+ writer . WriteValue ( true ) ;
196+ writer . WriteEndObject ( ) ;
197+ }
198+ }
199+ else
200+ {
201+ // It's a scene object (GameObject, Component, etc.)
202+ writer . WriteStartObject ( ) ;
203+ writer . WritePropertyName ( "name" ) ;
204+ writer . WriteValue ( value . name ) ;
205+ writer . WritePropertyName ( "instanceID" ) ;
206+ writer . WriteValue ( value . GetInstanceID ( ) ) ;
207+ writer . WriteEndObject ( ) ;
208+ }
209+ #else
210+ // Runtime fallback: Write basic info without AssetDatabase
211+ writer . WriteStartObject ( ) ;
212+ writer . WritePropertyName ( "name" ) ;
213+ writer . WriteValue ( value . name ) ;
214+ writer . WritePropertyName ( "instanceID" ) ;
215+ writer . WriteValue ( value . GetInstanceID ( ) ) ;
216+ writer . WritePropertyName ( "warning" ) ;
217+ writer . WriteValue ( "UnityEngineObjectConverter running in non-Editor mode, asset path unavailable." ) ;
218+ writer . WriteEndObject ( ) ;
219+ #endif
220+ }
221+
222+ public override UnityEngine . Object ReadJson ( JsonReader reader , Type objectType , UnityEngine . Object existingValue , bool hasExistingValue , JsonSerializer serializer )
223+ {
224+ if ( reader . TokenType == JsonToken . Null )
225+ {
226+ return null ;
227+ }
228+
229+ #if UNITY_EDITOR
230+ if ( reader . TokenType == JsonToken . String )
231+ {
232+ // Assume it's an asset path
233+ string path = reader . Value . ToString ( ) ;
234+ return UnityEditor . AssetDatabase . LoadAssetAtPath ( path , objectType ) ;
235+ }
236+
237+ if ( reader . TokenType == JsonToken . StartObject )
238+ {
239+ JObject jo = JObject . Load ( reader ) ;
240+ if ( jo . TryGetValue ( "instanceID" , out JToken idToken ) && idToken . Type == JTokenType . Integer )
241+ {
242+ int instanceId = idToken . ToObject < int > ( ) ;
243+ UnityEngine . Object obj = UnityEditor . EditorUtility . InstanceIDToObject ( instanceId ) ;
244+ if ( obj != null && objectType . IsAssignableFrom ( obj . GetType ( ) ) )
245+ {
246+ return obj ;
247+ }
248+ }
249+ // Could potentially try finding by name as a fallback if ID lookup fails/isn't present
250+ // but that's less reliable.
251+ }
252+ #else
253+ // Runtime deserialization is tricky without AssetDatabase/EditorUtility
254+ // Maybe log a warning and return null or existingValue?
255+ Debug . LogWarning ( "UnityEngineObjectConverter cannot deserialize complex objects in non-Editor mode." ) ;
256+ // Skip the token to avoid breaking the reader
257+ if ( reader . TokenType == JsonToken . StartObject ) JObject . Load ( reader ) ;
258+ else if ( reader . TokenType == JsonToken . String ) reader . ReadAsString ( ) ;
259+ // Return null or existing value, depending on desired behavior
260+ return existingValue ;
261+ #endif
262+
263+ throw new JsonSerializationException ( $ "Unexpected token type '{ reader . TokenType } ' when deserializing UnityEngine.Object") ;
264+ }
265+ }
266+ }
0 commit comments