public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer szr)
        {
            JObject jObject    = JObject.Load(reader);
            var     name       = (string)jObject["name"];
            var     typeName   = (string)jObject["$type"];
            var     realType   = Type.GetType(typeName);
            var     settings   = JsonBlueprints.CreateSettings(realType);
            var     serializer = JsonSerializer.Create(settings);
            BlueprintScriptableObject result = null;

            if (jObject["$append"] != null)
            {
                serializer.ObjectCreationHandling = ObjectCreationHandling.Reuse;
                var copy = (string)jObject["$append"];
                jObject.Remove("$append");
                var parts = copy.Split(':');
                result = ResourcesLibrary.TryGetBlueprint(parts[1]);
                name   = result.name;
                Main.DebugLog($"Appending to {result.name}");
            }
            if (jObject["$replace"] != null)
            {
                var copy = (string)jObject["$replace"];
                jObject.Remove("$replace");
                var parts = copy.Split(':');
                result = ResourcesLibrary.TryGetBlueprint(parts[1]);
                name   = result.name;
                Main.DebugLog($"replacing to {result.name}");
            }
            if (jObject["$copy"] != null)
            {
                var copy = (string)jObject["$copy"];
                jObject.Remove("$copy");
                var parts    = copy.Split(':');
                var resource = ResourcesLibrary.TryGetBlueprint(parts[1]);
                result = (BlueprintScriptableObject)BlueprintUtil.ShallowClone(resource);
                Main.DebugLog($"Copying {resource.name}");
            }
            if (name == null)
            {
                throw new System.Exception("Missing name");
            }
            if (JsonBlueprints.Blueprints.ContainsKey(name))
            {
                //throw new System.Exception("Cannot create blueprint twice");
            }
            if (result == null)
            {
                result = ScriptableObject.CreateInstance(realType) as BlueprintScriptableObject;
            }
            JsonBlueprints.Blueprints[name] = result;
            BlueprintUtil.AddBlueprint(result, name);
            serializer.Populate(jObject.CreateReader(), result);
            return(result);
        }
        public object ReadResource(JsonReader reader, Type objectType, object existingValue, JsonSerializer szr)
        {
            JObject jObject = JObject.Load(reader);
            var     name    = (string)jObject["name"];

            Main.DebugLog($"Deserializing {name} of {objectType.Name} with {GetType().Name}");
            var typeName            = (string)jObject["$type"];
            var realType            = Type.GetType(typeName);
            ScriptableObject result = null;

            if (jObject["$append"] != null)
            {
                var settings = JsonBlueprints.CreateSettings(null);
                szr = JsonSerializer.Create(settings);
                szr.ObjectCreationHandling = ObjectCreationHandling.Reuse;
                var copy = (string)jObject["$append"];
                jObject.Remove("$append");
                var parts = copy.Split(':');
                result = ResourcesLibrary.TryGetResource <ScriptableObject>(parts[1]);
                name   = result.name;
                Main.DebugLog($"Appending to {result.name}");
            }
            if (jObject["$replace"] != null)
            {
                var copy = (string)jObject["$replace"];
                jObject.Remove("$replace");
                var parts = copy.Split(':');
                result = ResourcesLibrary.TryGetBlueprint(parts[1]);
                name   = result.name;
            }
            if (jObject["$copy"] != null)
            {
                var copy = (string)jObject["$copy"];
                jObject.Remove("$copy");
                var parts    = copy.Split(':');
                var resource = ResourcesLibrary.TryGetResource <ScriptableObject>(parts[1]);
                result = (ScriptableObject)BlueprintUtil.ShallowClone(resource);
                Main.DebugLog($"Copying {resource.name}");
            }
            if (result == null)
            {
                result = ScriptableObject.CreateInstance(realType);
            }
            szr.Populate(jObject.CreateReader(), result);
            return(result);
        }