@@ -215,7 +215,7 @@ private static object CreateAsset(JObject @params)
215215
216216 if ( propertiesForApply . HasValues )
217217 {
218- ApplyMaterialProperties ( mat , propertiesForApply ) ;
218+ MaterialOps . ApplyProperties ( mat , propertiesForApply , ManageGameObject . InputSerializer ) ;
219219 }
220220 }
221221 AssetDatabase . CreateAsset ( mat , fullPath ) ;
@@ -443,7 +443,7 @@ prop.Value is JObject componentProperties
443443 {
444444 // Apply properties directly to the material. If this modifies, it sets modified=true.
445445 // Use |= in case the asset was already marked modified by previous logic (though unlikely here)
446- modified |= ApplyMaterialProperties ( material , properties ) ;
446+ modified |= MaterialOps . ApplyProperties ( material , properties , ManageGameObject . InputSerializer ) ;
447447 }
448448 // Example: Modifying a ScriptableObject
449449 else if ( asset is ScriptableObject so )
@@ -897,299 +897,7 @@ private static void EnsureDirectoryExists(string directoryPath)
897897 }
898898 }
899899
900- /// <summary>
901- /// Applies properties from JObject to a Material.
902- /// </summary>
903- private static bool ApplyMaterialProperties ( Material mat , JObject properties )
904- {
905- if ( mat == null || properties == null )
906- return false ;
907- bool modified = false ;
908-
909- // Example: Set shader
910- if ( properties [ "shader" ] ? . Type == JTokenType . String )
911- {
912- string shaderRequest = properties [ "shader" ] . ToString ( ) ;
913- Shader newShader = RenderPipelineUtility . ResolveShader ( shaderRequest ) ;
914- if ( newShader != null && mat . shader != newShader )
915- {
916- mat . shader = newShader ;
917- modified = true ;
918- }
919- }
920- // Example: Set color property
921- if ( properties [ "color" ] is JObject colorProps )
922- {
923- string propName = colorProps [ "name" ] ? . ToString ( ) ?? GetMainColorPropertyName ( mat ) ; // Auto-detect if not specified
924- if ( colorProps [ "value" ] is JArray colArr && colArr . Count >= 3 )
925- {
926- try
927- {
928- Color newColor = new Color (
929- colArr [ 0 ] . ToObject < float > ( ) ,
930- colArr [ 1 ] . ToObject < float > ( ) ,
931- colArr [ 2 ] . ToObject < float > ( ) ,
932- colArr . Count > 3 ? colArr [ 3 ] . ToObject < float > ( ) : 1.0f
933- ) ;
934- if ( mat . HasProperty ( propName ) )
935- {
936- if ( mat . GetColor ( propName ) != newColor )
937- {
938- mat . SetColor ( propName , newColor ) ;
939- modified = true ;
940- }
941- }
942- else
943- {
944- Debug . LogWarning (
945- $ "Material '{ mat . name } ' with shader '{ mat . shader . name } ' does not have color property '{ propName } '. " +
946- $ "Color not applied. Common color properties: _BaseColor (URP), _Color (Standard)"
947- ) ;
948- }
949- }
950- catch ( Exception ex )
951- {
952- Debug . LogWarning (
953- $ "Error parsing color property '{ propName } ': { ex . Message } "
954- ) ;
955- }
956- }
957- }
958- else if ( properties [ "color" ] is JArray colorArr ) //Use color now with examples set in manage_asset.py
959- {
960- // Auto-detect the main color property for the shader
961- string propName = GetMainColorPropertyName ( mat ) ;
962- try
963- {
964- if ( colorArr . Count >= 3 )
965- {
966- Color newColor = new Color (
967- colorArr [ 0 ] . ToObject < float > ( ) ,
968- colorArr [ 1 ] . ToObject < float > ( ) ,
969- colorArr [ 2 ] . ToObject < float > ( ) ,
970- colorArr . Count > 3 ? colorArr [ 3 ] . ToObject < float > ( ) : 1.0f
971- ) ;
972- if ( mat . HasProperty ( propName ) )
973- {
974- if ( mat . GetColor ( propName ) != newColor )
975- {
976- mat . SetColor ( propName , newColor ) ;
977- modified = true ;
978- }
979- }
980- else
981- {
982- Debug . LogWarning (
983- $ "Material '{ mat . name } ' with shader '{ mat . shader . name } ' does not have color property '{ propName } '. " +
984- $ "Color not applied. Common color properties: _BaseColor (URP), _Color (Standard)"
985- ) ;
986- }
987- }
988- }
989- catch ( Exception ex )
990- {
991- Debug . LogWarning (
992- $ "Error parsing color property '{ propName } ': { ex . Message } "
993- ) ;
994- }
995- }
996- // Example: Set float property
997- if ( properties [ "float" ] is JObject floatProps )
998- {
999- string propName = floatProps [ "name" ] ? . ToString ( ) ;
1000- if (
1001- ! string . IsNullOrEmpty ( propName ) &&
1002- ( floatProps [ "value" ] ? . Type == JTokenType . Float || floatProps [ "value" ] ? . Type == JTokenType . Integer )
1003- )
1004- {
1005- try
1006- {
1007- float newVal = floatProps [ "value" ] . ToObject < float > ( ) ;
1008- if ( mat . HasProperty ( propName ) && mat . GetFloat ( propName ) != newVal )
1009- {
1010- mat . SetFloat ( propName , newVal ) ;
1011- modified = true ;
1012- }
1013- }
1014- catch ( Exception ex )
1015- {
1016- Debug . LogWarning (
1017- $ "Error parsing float property '{ propName } ': { ex . Message } "
1018- ) ;
1019- }
1020- }
1021- }
1022- // Example: Set texture property (case-insensitive key and subkeys)
1023- {
1024- JObject texProps = null ;
1025- var direct = properties . Property ( "texture" ) ;
1026- if ( direct != null && direct . Value is JObject t0 ) texProps = t0 ;
1027- if ( texProps == null )
1028- {
1029- var ci = properties . Properties ( ) . FirstOrDefault (
1030- p => string . Equals ( p . Name , "texture" , StringComparison . OrdinalIgnoreCase ) ) ;
1031- if ( ci != null && ci . Value is JObject t1 ) texProps = t1 ;
1032- }
1033- if ( texProps != null )
1034- {
1035- string rawName = ( texProps [ "name" ] ?? texProps [ "Name" ] ) ? . ToString ( ) ;
1036- string texPath = ( texProps [ "path" ] ?? texProps [ "Path" ] ) ? . ToString ( ) ;
1037- if ( ! string . IsNullOrEmpty ( texPath ) )
1038- {
1039- var newTex = AssetDatabase . LoadAssetAtPath < Texture > (
1040- AssetPathUtility . SanitizeAssetPath ( texPath ) ) ;
1041- if ( newTex == null )
1042- {
1043- Debug . LogWarning ( $ "Texture not found at path: { texPath } ") ;
1044- }
1045- else
1046- {
1047- // Reuse alias resolver so friendly names like 'albedo' work here too
1048- string candidateName = string . IsNullOrEmpty ( rawName ) ? "_BaseMap" : rawName ;
1049- string targetProp = ResolvePropertyName ( candidateName ) ;
1050- if ( ! string . IsNullOrEmpty ( targetProp ) && mat . HasProperty ( targetProp ) )
1051- {
1052- if ( mat . GetTexture ( targetProp ) != newTex )
1053- {
1054- mat . SetTexture ( targetProp , newTex ) ;
1055- modified = true ;
1056- }
1057- }
1058- }
1059- }
1060- }
1061- }
1062-
1063- // --- Flexible direct property assignment ---
1064- // Allow payloads like: { "_Color": [r,g,b,a] }, { "_Glossiness": 0.5 }, { "_MainTex": "Assets/.." }
1065- // while retaining backward compatibility with the structured keys above.
1066- // This iterates all top-level keys except the reserved structured ones and applies them
1067- // if they match known shader properties.
1068- var reservedKeys = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) { "shader" , "color" , "float" , "texture" } ;
1069-
1070- // Helper resolves common URP/Standard aliasing (e.g., _Color <-> _BaseColor, _MainTex <-> _BaseMap, _Glossiness <-> _Smoothness)
1071- string ResolvePropertyName ( string name )
1072- {
1073- if ( string . IsNullOrEmpty ( name ) ) return name ;
1074- string [ ] candidates ;
1075- var lower = name . ToLowerInvariant ( ) ;
1076- switch ( lower )
1077- {
1078- case "_color" : candidates = new [ ] { "_Color" , "_BaseColor" } ; break ;
1079- case "_basecolor" : candidates = new [ ] { "_BaseColor" , "_Color" } ; break ;
1080- case "_maintex" : candidates = new [ ] { "_MainTex" , "_BaseMap" } ; break ;
1081- case "_basemap" : candidates = new [ ] { "_BaseMap" , "_MainTex" } ; break ;
1082- case "_glossiness" : candidates = new [ ] { "_Glossiness" , "_Smoothness" } ; break ;
1083- case "_smoothness" : candidates = new [ ] { "_Smoothness" , "_Glossiness" } ; break ;
1084- // Friendly names → shader property names
1085- case "metallic" : candidates = new [ ] { "_Metallic" } ; break ;
1086- case "smoothness" : candidates = new [ ] { "_Smoothness" , "_Glossiness" } ; break ;
1087- case "albedo" : candidates = new [ ] { "_BaseMap" , "_MainTex" } ; break ;
1088- default : candidates = new [ ] { name } ; break ; // keep original as-is
1089- }
1090- foreach ( var candidate in candidates )
1091- {
1092- if ( mat . HasProperty ( candidate ) ) return candidate ;
1093- }
1094- return name ; // fall back to original
1095- }
1096-
1097- foreach ( var prop in properties . Properties ( ) )
1098- {
1099- if ( reservedKeys . Contains ( prop . Name ) ) continue ;
1100- string shaderProp = ResolvePropertyName ( prop . Name ) ;
1101- JToken v = prop . Value ;
1102-
1103- // Color: numeric array [r,g,b,(a)]
1104- if ( v is JArray arr && arr . Count >= 3 && arr . All ( t => t . Type == JTokenType . Float || t . Type == JTokenType . Integer ) )
1105- {
1106- if ( mat . HasProperty ( shaderProp ) )
1107- {
1108- try
1109- {
1110- var c = new Color (
1111- arr [ 0 ] . ToObject < float > ( ) ,
1112- arr [ 1 ] . ToObject < float > ( ) ,
1113- arr [ 2 ] . ToObject < float > ( ) ,
1114- arr . Count > 3 ? arr [ 3 ] . ToObject < float > ( ) : 1f
1115- ) ;
1116- if ( mat . GetColor ( shaderProp ) != c )
1117- {
1118- mat . SetColor ( shaderProp , c ) ;
1119- modified = true ;
1120- }
1121- }
1122- catch ( Exception ex )
1123- {
1124- Debug . LogWarning ( $ "Error setting color '{ shaderProp } ': { ex . Message } ") ;
1125- }
1126- }
1127- continue ;
1128- }
1129-
1130- // Float: single number
1131- if ( v . Type == JTokenType . Float || v . Type == JTokenType . Integer )
1132- {
1133- if ( mat . HasProperty ( shaderProp ) )
1134- {
1135- try
1136- {
1137- float f = v . ToObject < float > ( ) ;
1138- if ( ! Mathf . Approximately ( mat . GetFloat ( shaderProp ) , f ) )
1139- {
1140- mat . SetFloat ( shaderProp , f ) ;
1141- modified = true ;
1142- }
1143- }
1144- catch ( Exception ex )
1145- {
1146- Debug . LogWarning ( $ "Error setting float '{ shaderProp } ': { ex . Message } ") ;
1147- }
1148- }
1149- continue ;
1150- }
1151900
1152- // Texture: string path
1153- if ( v . Type == JTokenType . String )
1154- {
1155- string texPath = v . ToString ( ) ;
1156- if ( ! string . IsNullOrEmpty ( texPath ) && mat . HasProperty ( shaderProp ) )
1157- {
1158- var tex = AssetDatabase . LoadAssetAtPath < Texture > ( AssetPathUtility . SanitizeAssetPath ( texPath ) ) ;
1159- if ( tex != null && mat . GetTexture ( shaderProp ) != tex )
1160- {
1161- mat . SetTexture ( shaderProp , tex ) ;
1162- modified = true ;
1163- }
1164- }
1165- continue ;
1166- }
1167- }
1168-
1169- // TODO: Add handlers for other property types (Vectors, Ints, Keywords, RenderQueue, etc.)
1170- return modified ;
1171- }
1172-
1173- /// <summary>
1174- /// Auto-detects the main color property name for a material's shader.
1175- /// Tries common color property names in order: _BaseColor (URP), _Color (Standard), etc.
1176- /// </summary>
1177- private static string GetMainColorPropertyName ( Material mat )
1178- {
1179- if ( mat == null || mat . shader == null )
1180- return "_Color" ;
1181-
1182- // Try common color property names in order of likelihood
1183- string [ ] commonColorProps = { "_BaseColor" , "_Color" , "_MainColor" , "_Tint" , "_TintColor" } ;
1184- foreach ( var prop in commonColorProps )
1185- {
1186- if ( mat . HasProperty ( prop ) )
1187- return prop ;
1188- }
1189-
1190- // Fallback to _Color if none found
1191- return "_Color" ;
1192- }
1193901
1194902 /// <summary>
1195903 /// Applies properties from JObject to a PhysicsMaterial.
0 commit comments