Example #1
0
        /// <summary>
        /// Reloads a content. If possible, same recursively referenced objects are reused.
        /// </summary>
        /// <param name="obj">The object to reload.</param>
        /// <param name="newUrl">The url of the new object to load. This allows to replace an asset by another one, or to handle renamed content.</param>
        /// <param name="settings">The loader settings.</param>
        /// <returns>True if it could be reloaded, false otherwise.</returns>
        /// <exception cref="System.InvalidOperationException">Content not loaded through this ContentManager.</exception>
        public bool Reload(object obj, string newUrl = null, ContentManagerLoaderSettings settings = null)
        {
            if (settings == null)
            {
                settings = ContentManagerLoaderSettings.Default;
            }

            lock (LoadedAssetUrls)
            {
                Reference reference;
                if (!LoadedAssetReferences.TryGetValue(obj, out reference))
                {
                    return(false); // The object is not loaded
                }
                var url = newUrl ?? reference.Url;

                using (var profile = Profiler.Begin(ContentProfilingKeys.ContentReload, url))
                {
                    DeserializeObject(reference.Url, url, obj.GetType(), obj, settings);
                }

                if (url != reference.Url)
                {
                    LoadedAssetUrls.Remove(reference.Url);
                }
                return(true);
            }
        }
Example #2
0
        /// <summary>
        /// Loads content from the specified URL.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="url">The URL.</param>
        /// <param name="settings">The settings.</param>
        /// <returns>The loaded content.</returns>
        /// <remarks>If the asset is already loaded, it just increases the reference count of the asset and return the same instance.</remarks>
        /// <exception cref="System.ArgumentNullException">url</exception>
        public object Load(Type type, string url, ContentManagerLoaderSettings settings = null)
        {
            if (settings == null)
            {
                settings = ContentManagerLoaderSettings.Default;
            }

            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }

            lock (LoadedAssetUrls)
            {
                using (var profile = Profiler.Begin(ContentProfilingKeys.ContentLoad, url))
                {
                    return(DeserializeObject(url, url, type, null, settings));
                }
            }
        }
Example #3
0
        private object DeserializeObject(Queue <DeserializeOperation> serializeOperations, Reference parentReference, string url, Type objType, object obj, ContentManagerLoaderSettings settings)
        {
            // Try to find already loaded object
            Reference reference = FindDeserializedObject(url, objType);

            if (reference != null && reference.Deserialized)
            {
                // Add reference
                bool isRoot = parentReference == null;
                if (isRoot || parentReference.References.Add(reference))
                {
                    IncrementReference(reference, isRoot);
                }

                // Check if need to fully stream resource
                if (!settings.AllowContentStreaming)
                {
                    var streamingManager = services.GetService <IStreamingManager>();
                    streamingManager?.FullyLoadResource(reference.Object);
                }

                return(reference.Object);
            }

            if (!FileProvider.FileExists(url))
            {
                HandleAssetNotFound(url);
                return(null);
            }

            ContentSerializerContext contentSerializerContext;
            object result;

            // Open asset binary stream
            try
            {
                using (var stream = FileProvider.OpenStream(url, VirtualFileMode.Open, VirtualFileAccess.Read))
                {
                    // File does not exist
                    // TODO/Benlitz: Add a log entry for that, it's not expected to happen
                    if (stream == null)
                    {
                        return(null);
                    }

                    Type headerObjType = null;

                    // Read header
                    var streamReader = new BinarySerializationReader(stream);
                    var chunkHeader  = ChunkHeader.Read(streamReader);
                    if (chunkHeader != null)
                    {
                        headerObjType = AssemblyRegistry.GetType(chunkHeader.Type);
                    }

                    // Find serializer
                    var serializer = Serializer.GetSerializer(headerObjType, objType);
                    if (serializer == null)
                    {
                        throw new InvalidOperationException($"Content serializer for {headerObjType}/{objType} could not be found.");
                    }
                    contentSerializerContext = new ContentSerializerContext(url, ArchiveMode.Deserialize, this)
                    {
                        LoadContentReferences = settings.LoadContentReferences,
                        AllowContentStreaming = settings.AllowContentStreaming,
                    };

                    // Read chunk references
                    if (chunkHeader != null && chunkHeader.OffsetToReferences != -1)
                    {
                        // Seek to where references are stored and deserialize them
                        streamReader.NativeStream.Seek(chunkHeader.OffsetToReferences, SeekOrigin.Begin);
                        contentSerializerContext.SerializeReferences(streamReader);
                        streamReader.NativeStream.Seek(chunkHeader.OffsetToObject, SeekOrigin.Begin);
                    }

                    if (reference == null)
                    {
                        // Create Reference
                        reference = new Reference(url, parentReference == null);
                        result    = obj ?? serializer.Construct(contentSerializerContext);
                        SetAssetObject(reference, result);
                    }
                    else
                    {
                        result = reference.Object;
                    }

                    reference.Deserialized = true;

                    PrepareSerializerContext(contentSerializerContext, streamReader.Context);

                    contentSerializerContext.SerializeContent(streamReader, serializer, result);

                    // Add reference
                    parentReference?.References.Add(reference);
                }
            }
            catch (Exception exception)
            {
                throw new ContentManagerException($"Unexpected exception while loading asset [{url}]. Reason: {exception.Message}. Check inner-exception for details.", exception);
            }

            if (settings.LoadContentReferences)
            {
                // Process content references
                // TODO: Should we work at ChunkReference level?
                foreach (var contentReference in contentSerializerContext.ContentReferences)
                {
                    bool shouldBeLoaded = true;

                    //Reference childReference;

                    settings.ContentFilter?.Invoke(contentReference, ref shouldBeLoaded);

                    if (shouldBeLoaded)
                    {
                        serializeOperations.Enqueue(new DeserializeOperation(reference, contentReference.Location, contentReference.Type, contentReference.ObjectValue));
                    }
                }
            }

            return(result);
        }
Example #4
0
        private object DeserializeObject(string initialUrl, string newUrl, Type type, object obj, ContentManagerLoaderSettings settings)
        {
            var serializeOperations = new Queue <DeserializeOperation>();

            serializeOperations.Enqueue(new DeserializeOperation(null, newUrl, type, obj));

            Reference reference = null;

            if (obj != null)
            {
                reference = FindDeserializedObject(initialUrl, type);
                if (reference.Object != obj)
                {
                    throw new InvalidOperationException("Object doesn't match, can't reload");
                }
            }

            // Let's put aside old references, so that we unload them only afterwise (avoid a referenced object to be unloaded for no reason)
            HashSet <Reference> references = null;

            if (reference != null)
            {
                // Let's collect dependent reference, and reset current list
                references           = reference.References;
                reference.References = new HashSet <Reference>();

                // Mark object as not deserialized yet
                reference.Deserialized = false;
            }

            bool   isFirstOperation = true;
            object result           = null;

            while (serializeOperations.Count > 0)
            {
                var serializeOperation = serializeOperations.Dequeue();
                var deserializedObject = DeserializeObject(serializeOperations, serializeOperation.ParentReference, serializeOperation.Url, serializeOperation.ObjectType, serializeOperation.Object, settings);
                if (isFirstOperation)
                {
                    result           = deserializedObject;
                    isFirstOperation = false;
                }
            }

            if (reference != null)
            {
                foreach (var dependentReference in references)
                {
                    DecrementReference(dependentReference, false);
                }
            }

            return(result);
        }
Example #5
0
 /// <summary>
 /// Loads an asset from the specified URL asynchronously.
 /// </summary>
 /// <param name="type">The type.</param>
 /// <param name="url">The URL.</param>
 /// <param name="settings">The settings.</param>
 /// <remarks>If the asset is already loaded, it just increases the reference count of the asset and return the same instance.</remarks>
 /// <returns>The loaded content.</returns>
 public Task <object> LoadAsync(Type type, string url, ContentManagerLoaderSettings settings = null)
 {
     return(ScheduleAsync(() => Load(type, url, settings)));
 }
Example #6
0
 /// <summary>
 /// Loads an asset from the specified URL asynchronously.
 /// </summary>
 /// <typeparam name="T">The content type.</typeparam>
 /// <param name="url">The URL to load from.</param>
 /// <param name="settings">The settings. If null, fallback to <see cref="ContentManagerLoaderSettings.Default" />.</param>
 /// <remarks>If the asset is already loaded, it just increases the reference count of the asset and return the same instance.</remarks>
 /// <returns>The loaded content.</returns>
 public Task <T> LoadAsync <T>(string url, ContentManagerLoaderSettings settings = null) where T : class
 {
     return(ScheduleAsync(() => Load <T>(url, settings)));
 }
Example #7
0
 /// <summary>
 /// Reloads a content asynchronously. If possible, same recursively referenced objects are reused.
 /// </summary>
 /// <param name="obj">The object to reload.</param>
 /// <param name="newUrl">The url of the new object to load. This allows to replace an asset by another one, or to handle renamed content.</param>
 /// <param name="settings">The loader settings.</param>
 /// <returns>A task that completes when the content has been reloaded. The result of the task is True if it could be reloaded, false otherwise.</returns>
 /// <exception cref="System.InvalidOperationException">Content not loaded through this ContentManager.</exception>
 public Task <bool> ReloadAsync(object obj, string newUrl = null, ContentManagerLoaderSettings settings = null)
 {
     return(ScheduleAsync(() => Reload(obj, newUrl, settings)));
 }
Example #8
0
 /// <summary>
 /// Loads content from the specified URL.
 /// </summary>
 /// <typeparam name="T">The content type.</typeparam>
 /// <param name="url">The URL to load from.</param>
 /// <param name="settings">The settings. If null, fallback to <see cref="ContentManagerLoaderSettings.Default" />.</param>
 /// <remarks>If the asset is already loaded, it just increases the reference count of the asset and return the same instance.</remarks>
 /// <returns>The loaded content.</returns>
 public T Load <T>(string url, ContentManagerLoaderSettings settings = null) where T : class
 {
     return((T)Load(typeof(T), url, settings));
 }