A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5using UnityEditor.Graphing;
6using UnityEngine;
7
8namespace UnityEditor.ShaderGraph
9{
10 sealed partial class GraphData : ISerializationCallbackReceiver
11 {
12 public static class GraphValidation
13 {
14 static Dictionary<Type, FieldInfo> s_ActiveSubTarget = new();
15 static readonly PropertyInfo s_JsonData = typeof(Serialization.JsonData<SubTarget>).GetProperty("value");
16
17 static SubTarget GetActiveSubTarget(Target target)
18 {
19 // All targets have an active subtarget but it's not accessible from ShaderGraph
20 // so we use reflection to access it
21
22 var type = target.GetType();
23 if (!s_ActiveSubTarget.TryGetValue(type, out var activeSubTarget))
24 {
25 activeSubTarget = type.GetField("m_ActiveSubTarget", BindingFlags.Instance | BindingFlags.NonPublic);
26 s_ActiveSubTarget.Add(type, activeSubTarget);
27 }
28 if (activeSubTarget != null)
29 {
30 var jsonData = activeSubTarget.GetValue(target);
31 if (jsonData != null)
32 {
33 return s_JsonData.GetValue(jsonData) as SubTarget;
34 }
35 }
36 return null;
37 }
38
39 public static void ValidateNode(AbstractMaterialNode node)
40 {
41 Type t = node.GetType();
42 node.ValidateNode();
43 if (!(node is BlockNode))
44 {
45 bool disallowedByAnyTargets = false;
46 bool disallowedByAllTargets = true;
47 bool disallowedByAnySubTarget = false;
48 IEnumerable<Target> targets = node.owner.activeTargets;
49 if (node.owner.isSubGraph)
50 {
51 targets = node.owner.allPotentialTargets;
52 }
53 foreach (var target in targets)
54 {
55 //if at least one target doesn't allow a node, it is considered invalid
56 if (!target.IsNodeAllowedByTarget(t))
57 {
58 disallowedByAnyTargets = true;
59 node.isValid = false;
60 node.owner.AddValidationError(node.objectId, $"{node.name} Node is not allowed by {target.displayName} implementation", Rendering.ShaderCompilerMessageSeverity.Warning);
61 node.owner.m_UnsupportedTargets.Add(target);
62 }
63 //at least one target does allow node, not going to be explicitly set inactive
64 else
65 {
66 disallowedByAllTargets = false;
67 }
68
69 var subtarget = GetActiveSubTarget(target);
70 if (subtarget != null && !subtarget.IsNodeAllowedBySubTarget(t))
71 {
72 disallowedByAnySubTarget = true;
73 node.isValid = false;
74 node.owner.AddValidationError(node.objectId, $"{node.name} Node is not allowed by {subtarget.displayName} implementation", Rendering.ShaderCompilerMessageSeverity.Error);
75 }
76 }
77 if (!disallowedByAnyTargets && !disallowedByAnySubTarget)
78 {
79 node.isValid = true;
80 }
81
82 //Set ActiveState based on if all targets disallow this node
83 if (disallowedByAllTargets)
84 {
85 node.SetOverrideActiveState(AbstractMaterialNode.ActiveState.ExplicitInactive);
86 node.owner.AddValidationError(node.objectId, $"{node.name} Node is not allowed by any active targets, and will not be used in generation", Rendering.ShaderCompilerMessageSeverity.Warning);
87 }
88 else
89 {
90 node.SetOverrideActiveState(AbstractMaterialNode.ActiveState.Implicit);
91 }
92 }
93 }
94
95 public static void ValidateGraph(GraphData graph)
96 {
97 graph.m_UnsupportedTargets.Clear();
98 GraphDataUtils.ApplyActionLeafFirst(graph, ValidateNode);
99 }
100 }
101 }
102}