A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using UnityEditor.Graphing; 4using UnityEditor.ShaderGraph.Drawing; 5using UnityEditor.ShaderGraph.Serialization; 6using UnityEngine; 7 8namespace UnityEditor.ShaderGraph.Internal 9{ 10 public abstract class ShaderInput : JsonObject 11 { 12 [SerializeField] 13 SerializableGuid m_Guid = new SerializableGuid(); 14 15 internal Guid guid => m_Guid.guid; 16 17 internal void OverrideGuid(string namespaceId, string name) { m_Guid.guid = GenerateNamespaceUUID(namespaceId, name); } 18 19 [SerializeField] 20 string m_Name; 21 22 public string displayName 23 { 24 get 25 { 26 if (string.IsNullOrEmpty(m_Name)) 27 return $"{concreteShaderValueType}_{objectId}"; 28 return m_Name; 29 } 30 set 31 { 32 // this is a raw set of the display name 33 // if you want to a fully graph-connected set-and-sanitize-and-update, 34 // call SetDisplayNameAndSanitizeForGraph() instead 35 m_Name = value; 36 } 37 } 38 39 internal void AddObserver(IShaderInputObserver observer) 40 { 41 m_InputObservers.Add(observer); 42 } 43 44 internal void RemoveObserver(IShaderInputObserver observer) 45 { 46 m_InputObservers.Remove(observer); 47 } 48 49 internal void ClearObservers() 50 { 51 m_InputObservers.Clear(); 52 } 53 54 internal HashSet<IShaderInputObserver> InputObservers => m_InputObservers; 55 56 HashSet<IShaderInputObserver> m_InputObservers = new(); 57 58 // sanitizes the desired name according to the current graph, and assigns it as the display name 59 // also calls the update trigger to update other bits of the graph UI that use the name 60 internal void SetDisplayNameAndSanitizeForGraph(GraphData graphData, string desiredName = null) 61 { 62 string originalDisplayName = displayName; 63 64 // if no desired name passed in, sanitize the current name 65 if (desiredName == null) 66 desiredName = originalDisplayName; 67 68 var sanitizedName = graphData.SanitizeGraphInputName(this, desiredName); 69 bool changed = (originalDisplayName != sanitizedName); 70 71 // only assign if it was changed 72 if (changed) 73 m_Name = sanitizedName; 74 75 // update the default reference name 76 UpdateDefaultReferenceName(graphData); 77 } 78 79 internal void SetReferenceNameAndSanitizeForGraph(GraphData graphData, string desiredRefName = null) 80 { 81 string originalRefName = referenceName; 82 83 // if no desired ref name, use the current name 84 if (string.IsNullOrEmpty(desiredRefName)) 85 desiredRefName = originalRefName; 86 87 // sanitize and deduplicate the desired name 88 var sanitizedRefName = graphData.SanitizeGraphInputReferenceName(this, desiredRefName); 89 90 // check if the final result is different from the current name 91 bool changed = (originalRefName != sanitizedRefName); 92 93 // if changed, then set the new name up as an override 94 if (changed) 95 overrideReferenceName = sanitizedRefName; 96 } 97 98 // resets the reference name to a "default" value (deduplicated against existing reference names) 99 // returns the new default reference name 100 internal string ResetReferenceName(GraphData graphData) 101 { 102 overrideReferenceName = null; 103 104 // because we are clearing an override, we must force a sanitization pass on the default ref name 105 // as there may now be collisions that didn't previously exist 106 UpdateDefaultReferenceName(graphData, true); 107 108 return referenceName; 109 } 110 111 internal void UpdateDefaultReferenceName(GraphData graphData, bool forceSanitize = false) 112 { 113 if (m_DefaultRefNameVersion <= 0) 114 return; // old version is updated in the getter 115 116 if (forceSanitize || 117 string.IsNullOrEmpty(m_DefaultReferenceName) || 118 (m_RefNameGeneratedByDisplayName != displayName)) 119 { 120 // Make sure all reference names are consistently auto-generated with a pre-pended underscore (if they can be renamed) 121 var targetRefName = displayName; 122 if (this.isReferenceRenamable && !targetRefName.StartsWith("_")) 123 targetRefName = "_" + targetRefName; 124 125 m_DefaultReferenceName = graphData.SanitizeGraphInputReferenceName(this, targetRefName); 126 m_RefNameGeneratedByDisplayName = displayName; 127 } 128 } 129 130 const int k_LatestDefaultRefNameVersion = 1; 131 132 // this is used to know whether this shader input is using: 133 // 0) the "old" default reference naming scheme (type + GUID) 134 // 1) the new default reference naming scheme (make it similar to the display name) 135 [SerializeField] 136 int m_DefaultRefNameVersion = k_LatestDefaultRefNameVersion; 137 138 [SerializeField] 139 string m_RefNameGeneratedByDisplayName; // used to tell what was the display name used to generate the default reference name 140 141 [SerializeField] 142 string m_DefaultReferenceName; // NOTE: this can be NULL for old graphs, or newly created properties 143 144 public string referenceName 145 { 146 get 147 { 148 if (string.IsNullOrEmpty(overrideReferenceName)) 149 { 150 if (m_DefaultRefNameVersion == 0) 151 { 152 if (string.IsNullOrEmpty(m_DefaultReferenceName)) 153 m_DefaultReferenceName = GetOldDefaultReferenceName(); 154 return m_DefaultReferenceName; 155 } 156 else // version 1 157 { 158 // default reference name is updated elsewhere in the new naming scheme 159 return m_DefaultReferenceName; 160 } 161 } 162 return overrideReferenceName; 163 } 164 } 165 166 public virtual string referenceNameForEditing => referenceName; 167 168 public override void OnBeforeDeserialize() 169 { 170 // if serialization doesn't write to m_DefaultRefNameVersion, then it is an old shader input, and should use the old default naming scheme 171 m_DefaultRefNameVersion = 0; 172 base.OnBeforeDeserialize(); 173 } 174 175 // This is required to handle Material data serialized with "_Color_GUID" reference names 176 // m_DefaultReferenceName expects to match the material data and previously used PropertyType 177 // ColorShaderProperty is the only case where PropertyType doesn't match ConcreteSlotValueType 178 public virtual string GetOldDefaultReferenceName() 179 { 180 return $"{concreteShaderValueType.ToString()}_{objectId}"; 181 } 182 183 // returns true if this shader input is CURRENTLY using the old default reference name 184 public bool IsUsingOldDefaultRefName() 185 { 186 return string.IsNullOrEmpty(overrideReferenceName) && (m_DefaultRefNameVersion == 0); 187 } 188 189 // returns true if this shader input is CURRENTLY using the new default reference name 190 public bool IsUsingNewDefaultRefName() 191 { 192 return string.IsNullOrEmpty(overrideReferenceName) && (m_DefaultRefNameVersion >= 1); 193 } 194 195 // upgrades the default reference name to use the new naming scheme 196 internal string UpgradeDefaultReferenceName(GraphData graphData) 197 { 198 m_DefaultRefNameVersion = k_LatestDefaultRefNameVersion; 199 m_DefaultReferenceName = null; 200 m_RefNameGeneratedByDisplayName = null; 201 UpdateDefaultReferenceName(graphData, true); // make sure to sanitize the new default 202 return referenceName; 203 } 204 205 [SerializeField] 206 string m_OverrideReferenceName; 207 208 internal string overrideReferenceName 209 { 210 get => m_OverrideReferenceName; 211 set => m_OverrideReferenceName = value; 212 } 213 214 [SerializeField] 215 bool m_GeneratePropertyBlock = true; 216 217 internal bool generatePropertyBlock // this is basically the "exposed" toggle 218 { 219 get => m_GeneratePropertyBlock; 220 set => m_GeneratePropertyBlock = value; 221 } 222 223 internal virtual bool isExposed => isExposable && generatePropertyBlock; 224 225 public virtual bool allowedInSubGraph 226 { 227 get { return true; } 228 } 229 230 public virtual bool allowedInMainGraph 231 { 232 get { return true; } 233 } 234 235 internal abstract ConcreteSlotValueType concreteShaderValueType { get; } 236 237 internal abstract bool isExposable { get; } 238 internal virtual bool isAlwaysExposed => false; 239 240 // this controls whether the UI allows the user to rename the display and reference names 241 internal abstract bool isRenamable { get; } 242 internal virtual bool isReferenceRenamable => isRenamable; 243 244 internal virtual bool isCustomSlotAllowed => true; 245 246 [SerializeField] 247 bool m_UseCustomSlotLabel = false; 248 249 [SerializeField] 250 string m_CustomSlotLabel; 251 252 internal bool useCustomSlotLabel 253 { 254 get => m_UseCustomSlotLabel; 255 set => m_UseCustomSlotLabel = value; 256 } 257 258 internal string customSlotLabel 259 { 260 get => m_CustomSlotLabel; 261 set => m_CustomSlotLabel = value; 262 } 263 264 [SerializeField] 265 protected int m_DismissedVersion = 0; 266 public int dismissedUpdateVersion { get => m_DismissedVersion; set => m_DismissedVersion = value; } 267 268 internal bool isConnectionTestable 269 { 270 get => m_UseCustomSlotLabel; 271 } 272 273 static internal string GetConnectionStateVariableName(string variableName) 274 { 275 return variableName + "_IsConnected"; 276 } 277 278 internal abstract ShaderInput Copy(); 279 280 internal virtual void OnBeforePasteIntoGraph(GraphData graph) { } 281 } 282}