A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using System.Reflection; 4using System.Text; 5using UnityEditor.Rendering; 6using UnityEngine; 7using UnityEngine.Rendering; 8using UnityEditor.ShaderGraph.Internal; 9using UnityEditor.Graphing; 10using UnityEngine.UIElements; 11using UnityEditor.ShaderGraph.Drawing; 12 13namespace UnityEditor.ShaderGraph.Serialization 14{ 15 static class MultiJsonInternal 16 { 17 #region Unknown Data Handling 18 public class UnknownJsonObject : JsonObject 19 { 20 public string typeInfo; 21 public string jsonData; 22 public JsonData<JsonObject> castedObject; 23 24 public UnknownJsonObject(string typeInfo) 25 { 26 this.typeInfo = typeInfo; 27 } 28 29 public override void Deserailize(string typeInfo, string jsonData) 30 { 31 this.jsonData = jsonData; 32 } 33 34 public override string Serialize() 35 { 36 return jsonData; 37 } 38 39 public override void OnAfterDeserialize(string json) 40 { 41 if (castedObject.value != null) 42 { 43 Enqueue(castedObject, json.Trim()); 44 } 45 } 46 47 public override void OnAfterMultiDeserialize(string json) 48 { 49 if (castedObject.value == null) 50 { 51 //Never got casted so nothing ever reffed this object 52 //likely that some other unknown json object had a ref 53 //to this thing. Need to include it in the serialization 54 //step of the object still. 55 if (jsonBlobs.TryGetValue(currentRoot.objectId, out var blobs)) 56 { 57 blobs[objectId] = jsonData.Trim(); 58 } 59 else 60 { 61 var lookup = new Dictionary<string, string>(); 62 lookup[objectId] = jsonData.Trim(); 63 jsonBlobs.Add(currentRoot.objectId, lookup); 64 } 65 } 66 } 67 68 public override T CastTo<T>() 69 { 70 if (castedObject.value != null) 71 return castedObject.value.CastTo<T>(); 72 73 Type t = typeof(T); 74 if (t == typeof(AbstractMaterialNode) || t.IsSubclassOf(typeof(AbstractMaterialNode))) 75 { 76 UnknownNodeType unt = new UnknownNodeType(jsonData); 77 valueMap[objectId] = unt; 78 s_ObjectIdField.SetValue(unt, objectId); 79 castedObject = unt; 80 return unt.CastTo<T>(); 81 } 82 else if (t == typeof(Target) || t.IsSubclassOf(typeof(Target))) 83 { 84 UnknownTargetType utt = new UnknownTargetType(typeInfo, jsonData); 85 valueMap[objectId] = utt; 86 s_ObjectIdField.SetValue(utt, objectId); 87 castedObject = utt; 88 return utt.CastTo<T>(); 89 } 90 else if (t == typeof(SubTarget) || t.IsSubclassOf(typeof(SubTarget))) 91 { 92 UnknownSubTargetType ustt = new UnknownSubTargetType(typeInfo, jsonData); 93 valueMap[objectId] = ustt; 94 s_ObjectIdField.SetValue(ustt, objectId); 95 castedObject = ustt; 96 return ustt.CastTo<T>(); 97 } 98 else if (t == typeof(ShaderInput) || t.IsSubclassOf(typeof(ShaderInput))) 99 { 100 UnknownShaderPropertyType usp = new UnknownShaderPropertyType(typeInfo, jsonData); 101 valueMap[objectId] = usp; 102 s_ObjectIdField.SetValue(usp, objectId); 103 castedObject = usp; 104 return usp.CastTo<T>(); 105 } 106 else if (t == typeof(MaterialSlot) || t.IsSubclassOf(typeof(MaterialSlot))) 107 { 108 UnknownMaterialSlotType umst = new UnknownMaterialSlotType(typeInfo, jsonData); 109 valueMap[objectId] = umst; 110 s_ObjectIdField.SetValue(umst, objectId); 111 castedObject = umst; 112 return umst.CastTo<T>(); 113 } 114 else if (t == typeof(AbstractShaderGraphDataExtension) || t.IsSubclassOf(typeof(AbstractShaderGraphDataExtension))) 115 { 116 UnknownGraphDataExtension usge = new UnknownGraphDataExtension(typeInfo, jsonData); 117 valueMap[objectId] = usge; 118 s_ObjectIdField.SetValue(usge, objectId); 119 castedObject = usge; 120 return usge.CastTo<T>(); 121 } 122 else 123 { 124 Debug.LogError($"Unable to evaluate type {typeInfo} : {jsonData}"); 125 } 126 return null; 127 } 128 } 129 130 public class UnknownTargetType : Target 131 { 132 public string jsonData; 133 public UnknownTargetType() : base() 134 { 135 isHidden = true; 136 } 137 138 private List<BlockFieldDescriptor> m_activeBlocks = null; 139 140 public UnknownTargetType(string displayName, string jsonData) 141 { 142 var split = displayName.Split('.'); 143 var last = split[split.Length - 1]; 144 this.displayName = last.Replace("Target", "") + " (Unknown)"; 145 isHidden = false; 146 this.jsonData = jsonData; 147 } 148 149 public override void Deserailize(string typeInfo, string jsonData) 150 { 151 this.jsonData = jsonData; 152 base.Deserailize(typeInfo, jsonData); 153 } 154 155 public override string Serialize() 156 { 157 return jsonData.Trim(); 158 } 159 160 //When we first call GetActiveBlocks, we assume any unknown blockfielddescriptors are owned by this target 161 public override void GetActiveBlocks(ref TargetActiveBlockContext context) 162 { 163 if (m_activeBlocks == null) 164 { 165 m_activeBlocks = new List<BlockFieldDescriptor>(); 166 foreach (var cur in context.currentBlocks) 167 { 168 if (cur.isUnknown && !string.IsNullOrEmpty(cur.displayName)) 169 { 170 m_activeBlocks.Add(cur); 171 } 172 } 173 } 174 175 foreach (var block in m_activeBlocks) 176 { 177 context.AddBlock(block); 178 } 179 } 180 181 public override void GetFields(ref TargetFieldContext context) 182 { 183 } 184 185 public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<string> registerUndo) 186 { 187 context.AddHelpBox(MessageType.Warning, "Cannot find the code for this Target, a package may be missing."); 188 } 189 190 public override bool IsActive() => false; 191 192 public override void Setup(ref TargetSetupContext context) 193 { 194 } 195 196 public override bool WorksWithSRP(RenderPipelineAsset scriptableRenderPipeline) => false; 197 } 198 199 private class UnknownSubTargetType : SubTarget 200 { 201 public string jsonData; 202 public UnknownSubTargetType() : base() 203 { 204 isHidden = true; 205 } 206 207 public UnknownSubTargetType(string displayName, string jsonData) : base() 208 { 209 isHidden = false; 210 this.displayName = displayName; 211 this.jsonData = jsonData; 212 } 213 214 public override void Deserailize(string typeInfo, string jsonData) 215 { 216 this.jsonData = jsonData; 217 base.Deserailize(typeInfo, jsonData); 218 } 219 220 public override string Serialize() 221 { 222 return jsonData.Trim(); 223 } 224 225 internal override Type targetType => typeof(UnknownTargetType); 226 227 public override void GetActiveBlocks(ref TargetActiveBlockContext context) 228 { 229 } 230 231 public override void GetFields(ref TargetFieldContext context) 232 { 233 } 234 235 public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<string> registerUndo) 236 { 237 context.AddHelpBox(MessageType.Warning, "Cannot find the code for this SubTarget, a package may be missing."); 238 } 239 240 public override bool IsActive() => false; 241 242 public override void Setup(ref TargetSetupContext context) 243 { 244 } 245 } 246 247 internal class UnknownShaderPropertyType : AbstractShaderProperty 248 { 249 public string jsonData; 250 251 public UnknownShaderPropertyType(string displayName, string jsonData) : base() 252 { 253 this.displayName = displayName; 254 this.jsonData = jsonData; 255 } 256 257 public override void Deserailize(string typeInfo, string jsonData) 258 { 259 this.jsonData = jsonData; 260 base.Deserailize(typeInfo, jsonData); 261 } 262 263 public override string Serialize() 264 { 265 return jsonData.Trim(); 266 } 267 268 internal override ConcreteSlotValueType concreteShaderValueType => ConcreteSlotValueType.Vector1; 269 internal override bool isExposable => false; 270 internal override bool isRenamable => false; 271 internal override ShaderInput Copy() 272 { 273 // we CANNOT copy ourselves, as the serialized GUID in the jsonData would not match the json GUID 274 return null; 275 } 276 277 public override PropertyType propertyType => PropertyType.Float; 278 internal override void GetPropertyReferenceNames(List<string> result) { } 279 internal override void GetPropertyDisplayNames(List<string> result) { } 280 internal override string GetPropertyBlockString() { return ""; } 281 internal override void AppendPropertyBlockStrings(ShaderStringBuilder builder) 282 { 283 builder.AppendLine("/* UNKNOWN PROPERTY: " + referenceName + " */"); 284 } 285 286 internal override bool AllowHLSLDeclaration(HLSLDeclaration decl) => false; 287 internal override void ForeachHLSLProperty(Action<HLSLProperty> action) 288 { 289 action(new HLSLProperty(HLSLType._float, referenceName, HLSLDeclaration.Global, concretePrecision)); 290 } 291 292 internal override string GetPropertyAsArgumentString(string precisionString) { return ""; } 293 internal override AbstractMaterialNode ToConcreteNode() { return null; } 294 295 internal override PreviewProperty GetPreviewMaterialProperty() 296 { 297 return new PreviewProperty(propertyType) 298 { 299 name = referenceName, 300 floatValue = 0.0f 301 }; 302 } 303 304 public override string GetPropertyTypeString() { return ""; } 305 } 306 307 internal class UnknownMaterialSlotType : MaterialSlot 308 { 309 // used to deserialize some data out of an unknown MaterialSlot 310 class SerializerHelper 311 { 312 [SerializeField] 313 public string m_DisplayName = null; 314 315 [SerializeField] 316 public SlotType m_SlotType = SlotType.Input; 317 318 [SerializeField] 319 public bool m_Hidden = false; 320 321 [SerializeField] 322 public string m_ShaderOutputName = null; 323 324 [SerializeField] 325 public ShaderStageCapability m_StageCapability = ShaderStageCapability.All; 326 } 327 328 public string jsonData; 329 330 public UnknownMaterialSlotType(string displayName, string jsonData) : base() 331 { 332 // copy some minimal information to try to keep the UI as similar as possible 333 var helper = new SerializerHelper(); 334 JsonUtility.FromJsonOverwrite(jsonData, helper); 335 this.displayName = helper.m_DisplayName; 336 this.hidden = helper.m_Hidden; 337 this.stageCapability = helper.m_StageCapability; 338 this.SetInternalData(helper.m_SlotType, helper.m_ShaderOutputName); 339 340 // save the original json for saving 341 this.jsonData = jsonData; 342 } 343 344 public override void Deserailize(string typeInfo, string jsonData) 345 { 346 this.jsonData = jsonData; 347 base.Deserailize(typeInfo, jsonData); 348 } 349 350 public override string Serialize() 351 { 352 return jsonData.Trim(); 353 } 354 355 public override bool isDefaultValue => true; 356 357 public override SlotValueType valueType => SlotValueType.Vector1; 358 359 public override ConcreteSlotValueType concreteValueType => ConcreteSlotValueType.Vector1; 360 361 public override void AddDefaultProperty(PropertyCollector properties, GenerationMode generationMode) { } 362 363 public override void CopyValuesFrom(MaterialSlot foundSlot) 364 { 365 // we CANNOT copy data from another slot, as the GUID in the serialized jsonData would not match our real GUID 366 throw new NotSupportedException(); 367 } 368 } 369 370 [NeverAllowedByTarget] 371 internal class UnknownNodeType : AbstractMaterialNode 372 { 373 public string jsonData; 374 375 public UnknownNodeType() : base() 376 { 377 jsonData = null; 378 isValid = false; 379 SetOverrideActiveState(ActiveState.ExplicitInactive, false); 380 SetActive(false, false); 381 } 382 383 public UnknownNodeType(string jsonData) 384 { 385 this.jsonData = jsonData; 386 isValid = false; 387 SetOverrideActiveState(ActiveState.ExplicitInactive, false); 388 SetActive(false, false); 389 } 390 391 public override void OnAfterDeserialize(string json) 392 { 393 jsonData = json; 394 base.OnAfterDeserialize(json); 395 } 396 397 public override string Serialize() 398 { 399 EnqueSlotsForSerialization(); 400 return jsonData.Trim(); 401 } 402 403 public override void ValidateNode() 404 { 405 base.ValidateNode(); 406 owner.AddValidationError(objectId, "This node type could not be found. No function will be generated in the shader.", ShaderCompilerMessageSeverity.Warning); 407 } 408 409 // unknown node types cannot be copied, or else their GUID would not match the GUID in the serialized jsonDAta 410 public override bool canCutNode => false; 411 public override bool canCopyNode => false; 412 } 413 414 internal class UnknownGraphDataExtension : AbstractShaderGraphDataExtension 415 { 416 public string name; 417 public string jsonData; 418 internal override string displayName => name; 419 420 internal UnknownGraphDataExtension() : base() { } 421 422 internal UnknownGraphDataExtension(string displayName, string jsonData) 423 { 424 name = displayName; 425 this.jsonData = jsonData; 426 } 427 428 public override void Deserailize(string typeInfo, string jsonData) 429 { 430 this.jsonData = jsonData; 431 base.Deserailize(typeInfo, jsonData); 432 } 433 434 public override string Serialize() 435 { 436 return jsonData.Trim(); 437 } 438 439 internal override void OnPropertiesGUI(VisualElement context, Action onChange, Action<string> registerUndo, GraphData owner) 440 { 441 var helpBox = new HelpBoxRow(MessageType.Info); 442 helpBox.Add(new Label("Cannot find the code for this data extension, a package may be missing.")); 443 context.hierarchy.Add(helpBox); 444 } 445 } 446 #endregion //Unknown Data Handling 447 448 static readonly Dictionary<string, Type> k_TypeMap = CreateTypeMap(); 449 450 internal static bool isDeserializing; 451 452 internal static readonly Dictionary<string, JsonObject> valueMap = new Dictionary<string, JsonObject>(); 453 454 static List<MultiJsonEntry> s_Entries; 455 456 internal static bool isSerializing; 457 458 internal static readonly List<JsonObject> serializationQueue = new List<JsonObject>(); 459 460 internal static readonly HashSet<string> serializedSet = new HashSet<string>(); 461 462 static JsonObject currentRoot = null; 463 464 static Dictionary<string, Dictionary<string, string>> jsonBlobs = new Dictionary<string, Dictionary<string, string>>(); 465 466 static Dictionary<string, Type> CreateTypeMap() 467 { 468 var map = new Dictionary<string, Type>(); 469 foreach (var type in TypeCache.GetTypesDerivedFrom<JsonObject>()) 470 { 471 if (type.FullName != null) 472 { 473 map[type.FullName] = type; 474 } 475 } 476 477 foreach (var type in TypeCache.GetTypesWithAttribute(typeof(FormerNameAttribute))) 478 { 479 if (type.IsAbstract || !typeof(JsonObject).IsAssignableFrom(type)) 480 { 481 continue; 482 } 483 484 foreach (var attribute in type.GetCustomAttributes(typeof(FormerNameAttribute), false)) 485 { 486 var legacyAttribute = (FormerNameAttribute)attribute; 487 map[legacyAttribute.fullName] = type; 488 } 489 } 490 491 return map; 492 } 493 494 public static Type ParseType(string typeString) 495 { 496 k_TypeMap.TryGetValue(typeString, out var type); 497 return type; 498 } 499 500 public static List<MultiJsonEntry> Parse(string str) 501 { 502 var result = new List<MultiJsonEntry>(); 503 const string separatorStr = "\n\n"; 504 var startIndex = 0; 505 var raw = new FakeJsonObject(); 506 507 while (startIndex < str.Length) 508 { 509 var jsonBegin = str.IndexOf("{", startIndex, StringComparison.Ordinal); 510 if (jsonBegin == -1) 511 { 512 break; 513 } 514 515 var jsonEnd = str.IndexOf(separatorStr, jsonBegin, StringComparison.Ordinal); 516 if (jsonEnd == -1) 517 { 518 jsonEnd = str.IndexOf("\n\r\n", jsonBegin, StringComparison.Ordinal); 519 if (jsonEnd == -1) 520 { 521 jsonEnd = str.LastIndexOf("}", StringComparison.Ordinal) + 1; 522 } 523 } 524 525 var json = str.Substring(jsonBegin, jsonEnd - jsonBegin); 526 527 JsonUtility.FromJsonOverwrite(json, raw); 528 if (startIndex != 0 && string.IsNullOrWhiteSpace(raw.type)) 529 { 530 throw new InvalidOperationException($"Type is null or whitespace in JSON:\n{json}"); 531 } 532 533 result.Add(new MultiJsonEntry(raw.type, raw.id, json)); 534 raw.Reset(); 535 536 startIndex = jsonEnd + separatorStr.Length; 537 } 538 539 return result; 540 } 541 542 public static void Enqueue(JsonObject jsonObject, string json) 543 { 544 if (s_Entries == null) 545 { 546 throw new InvalidOperationException("Can only Enqueue during JsonObject.OnAfterDeserialize."); 547 } 548 549 valueMap.Add(jsonObject.objectId, jsonObject); 550 s_Entries.Add(new MultiJsonEntry(jsonObject.GetType().FullName, jsonObject.objectId, json)); 551 } 552 553 public static JsonObject CreateInstanceForDeserialization(string typeString) 554 { 555 if (!k_TypeMap.TryGetValue(typeString, out var type)) 556 { 557 return new UnknownJsonObject(typeString); 558 } 559 var output = (JsonObject)Activator.CreateInstance(type, true); 560 //This CreateInstance function is supposed to essentially create a blank copy of whatever class we end up deserializing into. 561 //when we typically create new JsonObjects in all other cases, we want that object to be assumed to be the latest version. 562 //This doesn't work if any json object was serialized before we had the idea of version, as the blank copy would have the 563 //latest version on creation and since the serialized version wouldn't have a version member, it would not get overwritten 564 //and we would automatically upgrade all previously serialized json objects incorrectly and without user action. To avoid this, 565 //we default jsonObject version to 0, and if the serialized value has a different saved version it gets changed and if the serialized 566 //version does not have a different saved value it remains 0 (earliest version) 567 output.ChangeVersion(0); 568 output.OnBeforeDeserialize(); 569 return output; 570 } 571 572 private static FieldInfo s_ObjectIdField = 573 typeof(JsonObject).GetField("m_ObjectId", BindingFlags.Instance | BindingFlags.NonPublic); 574 575 public static void Deserialize(JsonObject root, List<MultiJsonEntry> entries, bool rewriteIds) 576 { 577 if (isDeserializing) 578 { 579 throw new InvalidOperationException("Nested MultiJson deserialization is not supported."); 580 } 581 582 try 583 { 584 isDeserializing = true; 585 currentRoot = root; 586 root.ChangeVersion(0); //Same issue as described in CreateInstance 587 for (var index = 0; index < entries.Count; index++) 588 { 589 var entry = entries[index]; 590 try 591 { 592 JsonObject value = null; 593 if (index == 0) 594 { 595 value = root; 596 } 597 else 598 { 599 value = CreateInstanceForDeserialization(entry.type); 600 } 601 602 var id = entry.id; 603 604 if (id != null) 605 { 606 // Need to make sure that references looking for the old ID will find it in spite of 607 // ID rewriting. 608 valueMap[id] = value; 609 } 610 611 if (rewriteIds || entry.id == null) 612 { 613 id = value.objectId; 614 entries[index] = new MultiJsonEntry(entry.type, id, entry.json); 615 valueMap[id] = value; 616 } 617 618 s_ObjectIdField.SetValue(value, id); 619 } 620 catch (Exception e) 621 { 622 // External code could throw exceptions, but we don't want that to fail the whole thing. 623 // Potentially, the fallback type should also be used here. 624 Debug.LogException(e); 625 } 626 } 627 628 s_Entries = entries; 629 630 // Not a foreach because `entries` can be populated by calls to `Enqueue` as we go. 631 for (var i = 0; i < entries.Count; i++) 632 { 633 var entry = entries[i]; 634 try 635 { 636 var value = valueMap[entry.id]; 637 value.Deserailize(entry.type, entry.json); 638 // Set ID again as it could be overwritten from JSON. 639 s_ObjectIdField.SetValue(value, entry.id); 640 value.OnAfterDeserialize(entry.json); 641 } 642 catch (Exception e) 643 { 644 if (!String.IsNullOrEmpty(entry.id)) 645 { 646 var value = valueMap[entry.id]; 647 if (value != null) 648 { 649 Debug.LogError($"Exception thrown while deserialize object of type {entry.type}: {e.Message}"); 650 } 651 } 652 Debug.LogException(e); 653 } 654 } 655 656 s_Entries = null; 657 658 foreach (var entry in entries) 659 { 660 try 661 { 662 var value = valueMap[entry.id]; 663 value.OnAfterMultiDeserialize(entry.json); 664 } 665 catch (Exception e) 666 { 667 Debug.LogException(e); 668 } 669 } 670 } 671 finally 672 { 673 valueMap.Clear(); 674 currentRoot = null; 675 isDeserializing = false; 676 } 677 } 678 679 public static string Serialize(JsonObject mainObject) 680 { 681 if (isSerializing) 682 { 683 throw new InvalidOperationException("Nested MultiJson serialization is not supported."); 684 } 685 686 try 687 { 688 isSerializing = true; 689 690 serializedSet.Add(mainObject.objectId); 691 serializationQueue.Add(mainObject); 692 693 var idJsonList = new List<(string, string)>(); 694 695 // Not a foreach because the queue is populated by `JsonData<T>`s as we go. 696 for (var i = 0; i < serializationQueue.Count; i++) 697 { 698 var value = serializationQueue[i]; 699 var json = value.Serialize(); 700 idJsonList.Add((value.objectId, json)); 701 } 702 703 if (jsonBlobs.TryGetValue(mainObject.objectId, out var blobs)) 704 { 705 foreach (var blob in blobs) 706 { 707 if (!idJsonList.Contains((blob.Key, blob.Value))) 708 idJsonList.Add((blob.Key, blob.Value)); 709 } 710 } 711 712 713 idJsonList.Sort((x, y) => 714 // Main object needs to be placed first 715 x.Item1 == mainObject.objectId ? -1 : 716 y.Item1 == mainObject.objectId ? 1 : 717 // We sort everything else by ID to consistently maintain positions in the output 718 x.Item1.CompareTo(y.Item1)); 719 720 721 const string k_NewLineString = "\n"; 722 var sb = new StringBuilder(); 723 foreach (var (id, json) in idJsonList) 724 { 725 sb.Append(json); 726 sb.Append(k_NewLineString); 727 sb.Append(k_NewLineString); 728 } 729 730 return sb.ToString(); 731 } 732 finally 733 { 734 serializationQueue.Clear(); 735 serializedSet.Clear(); 736 isSerializing = false; 737 } 738 } 739 740 public static void PopulateValueMap(JsonObject mainObject) 741 { 742 if (isSerializing) 743 { 744 throw new InvalidOperationException("Nested MultiJson serialization is not supported."); 745 } 746 747 try 748 { 749 isSerializing = true; 750 751 serializedSet.Add(mainObject.objectId); 752 serializationQueue.Add(mainObject); 753 754 // Not a foreach because the queue is populated by `JsonRef<T>`s as we go. 755 for (var i = 0; i < serializationQueue.Count; i++) 756 { 757 var value = serializationQueue[i]; 758 value.Serialize(); 759 valueMap[value.objectId] = value; 760 } 761 } 762 finally 763 { 764 serializationQueue.Clear(); 765 serializedSet.Clear(); 766 isSerializing = false; 767 } 768 } 769 } 770}