Editor/ShaderGraphPlus/ShaderGraphPlus.V7Upgrade.cs

An editor-side JSON upgrader for ShaderGraphPlus version 7, it migrates serialized shader graph parameter and node JSON to a new schema. It processes parameter arrays (adding Options for ShaderFeatureEnumParameter or wrapping Blackboard parameter types for subgraphs) and node arrays (converting SubgraphOutput nodes into new parameter objects and adding ParameterIdentifier fields).

File AccessReflection
using ShaderGraphPlus.Nodes;
using System.Text.Json.Nodes;
using JsonUtilities;


namespace ShaderGraphPlus;

public partial class ShaderGraphPlus
{
	[SGPJsonUpgrader( typeof( ShaderGraphPlus ), 7 )]
	internal static void Upgrader_v7( JsonObject obj )
	{
		if ( obj[JsonKeys.ParameterArray] is not JsonArray oldParameterArray )
			throw new Exception( $"Cannot find jsonArray \'{JsonKeys.ParameterArray}\'" );

		if ( obj[JsonKeys.NodeArray] is not JsonArray oldNodeArray )
			throw new Exception( $"Cannot find jsonArray \'{JsonKeys.NodeArray}\'" );

		//
		// Upgrade Parameters
		//
		var newParameterArray = new JsonArray();

		if ( !CheckIfSubgraph( obj ) )
		{
			foreach ( var jsonNode in oldParameterArray )
			{
				if ( jsonNode[JsonKeys.Class] is not JsonValue classValue )
					continue;

				var parameterElement = JsonSerializer.Deserialize<JsonElement>( jsonNode.AsObject().ToJsonString() );
				var typeName = classValue.GetValue<string>();

				if ( typeName == "ShaderFeatureEnumParameter" )
				{
					var updatedParameterObject = jsonNode.DeepClone().AsObject();

					if ( updatedParameterObject.ContainsKey( "Options" ) )
					{
						var options = updatedParameterObject["Options"].Deserialize<List<string>>( SerializerOptions() );
						var newOptions = new List<ShaderFeatureEnumOption>();

						foreach ( var option in options )
						{
							newOptions.Add( new ShaderFeatureEnumOption() { Name = option } );
						}

						updatedParameterObject.Remove( "Options" );
						updatedParameterObject["Options"] = JsonSerializer.SerializeToNode( newOptions, SerializerOptions() );
					}
					else
					{
						updatedParameterObject["Options"] = JsonSerializer.SerializeToNode( new List<ShaderFeatureEnumOption>(), SerializerOptions() );
					}

					newParameterArray.Add( updatedParameterObject );
				}
				else
				{
					newParameterArray.Add( jsonNode.DeepClone() );
				}
			}
		}
		else
		{
			foreach ( var jsonNode in oldParameterArray )
			{
				if ( jsonNode[JsonKeys.Class] is not JsonValue classValue )
					continue;

				var typeName = classValue.GetValue<string>();
				var typeDesc = EditorTypeLibrary.GetType<BlackboardParameter>( typeName );
				var type = new ClassBlackboardParameterType( typeDesc );

				newParameterArray.Add( jsonNode.DeepClone() );
			}
		}

		//
		// Upgrade Nodes
		//

		var newNodeArray = new JsonArray();

		foreach ( var jsonNode in oldNodeArray )
		{
			if ( jsonNode[JsonKeys.Class] is not JsonValue classValue )
				continue;

			var typeName = classValue.GetValue<string>();
			var typeDesc = EditorTypeLibrary.GetType<BaseNodePlus>( typeName );
			var type = new ClassNodeType( typeDesc );

			if ( typeName == "SubgraphOutput" )
			{
				var updatedNodeObject = jsonNode.DeepClone().AsObject();

				if ( JsonUtils.GetPropertyValue<Guid>( updatedNodeObject, "OutputIdentifier", SerializerOptions(), Guid.NewGuid(), out Guid parameterIdentifier ) )
				{
					updatedNodeObject["ParameterIdentifier"] = JsonSerializer.SerializeToNode( parameterIdentifier, SerializerOptions() );
				}

				JsonUtils.GetPropertyValue<string>( updatedNodeObject, "OutputName", SerializerOptions(), "OutputA", out var outputName );
				JsonUtils.GetPropertyValue<string>( updatedNodeObject, "OutputDescription", SerializerOptions(), "", out var outputDescription );
				JsonUtils.GetPropertyValue<SubgraphPortType>( updatedNodeObject, "OutputType", SerializerOptions(), SubgraphPortType.Vector3, out var outputType );
				JsonUtils.GetPropertyValue<SubgraphOutputPreviewType>( updatedNodeObject, "Preview", SerializerOptions(), SubgraphOutputPreviewType.None, out var previewType );
				JsonUtils.GetPropertyValue<int>( updatedNodeObject, "PortOrder", SerializerOptions(), 0, out var portOrder );

				string parameterTypeName = outputType switch
				{
					SubgraphPortType.Bool => "BoolSubgraphOutputParameter",
					SubgraphPortType.Int => "IntSubgraphOutputParameter",
					SubgraphPortType.Float => "FloatSubgraphOutputParameter",
					SubgraphPortType.Vector2 => "Float2SubgraphOutputParameter",
					SubgraphPortType.Vector3 => "Float3SubgraphOutputParameter",
					SubgraphPortType.Vector4 => "Float4SubgraphOutputParameter",
					SubgraphPortType.Color => "ColorSubgraphOutputParameter",
					SubgraphPortType.Float2x2 => "Float2x2SubgraphOutputParameter",
					SubgraphPortType.Float3x3 => "Float3x3SubgraphOutputParameter",
					SubgraphPortType.Float4x4 => "Float4x4SubgraphOutputParameter",
					SubgraphPortType.Gradient => "GradientSubgraphOutputParameter",
					SubgraphPortType.SamplerState => "SamplerStateSubgraphOutputParameter",
					SubgraphPortType.Texture2DObject => "Texture2DSubgraphOutputParameter",
					SubgraphPortType.TextureCubeObject => "TextureCubeSubgraphOutputParameter",
					_ => throw new NotImplementedException( $"Unknown OutputType \'{outputType}\'" ),
				};

				var parameterObject = new JsonObject
				{
					{ JsonKeys.Class, JsonSerializer.SerializeToNode( parameterTypeName, SerializerOptions() ) },
					{ "Identifier", JsonSerializer.SerializeToNode( parameterIdentifier, SerializerOptions() ) },
					{ "Name", JsonSerializer.SerializeToNode( outputName, SerializerOptions() ) },
					{ "OutputDescription", JsonSerializer.SerializeToNode( outputDescription, SerializerOptions() ) },
					{ "PortOrder", JsonSerializer.SerializeToNode( portOrder, SerializerOptions() ) },
					{ "Preview", JsonSerializer.SerializeToNode( previewType, SerializerOptions() ) },
				};

				newParameterArray.Add( parameterObject );

				newNodeArray.Add( updatedNodeObject );
			}
			else
			{
				newNodeArray.Add( jsonNode.DeepClone() );
			}
		}

		obj.Remove( JsonKeys.ParameterArray );
		obj.Add( JsonKeys.ParameterArray, newParameterArray );

		obj.Remove( JsonKeys.NodeArray );
		obj.Add( JsonKeys.NodeArray, newNodeArray );
	}
}