4 using System.Collections.Generic;
6 using System.Reflection;
7 using System.Threading.Tasks;
8 using SiliconStudio.Core.Diagnostics;
9 using SiliconStudio.Core.IO;
10 using SiliconStudio.Core.Serialization.Contents;
11 using SiliconStudio.Core.Serialization.Converters;
12 using SiliconStudio.Core.Storage;
14 namespace SiliconStudio.Core.Serialization.Assets
16 public sealed
partial class AssetManager : IAssetManager
20 public static Func<DatabaseFileProvider> GetFileProvider {
get; set; }
25 private readonly Dictionary<ObjectId, AssetReference> loadedAssetsByUrl =
new Dictionary<ObjectId, AssetReference>();
27 private readonly Dictionary<object, AssetReference> loadedAssetsUrl =
new Dictionary<object, AssetReference>();
31 Serializer =
new AssetSerializer { LowLevelSerializerSelector = SerializerSelector.Default };
34 public void Save(
string url,
object asset)
36 if (url == null)
throw new ArgumentNullException(
"url");
37 if (asset == null)
throw new ArgumentNullException(
"asset");
39 lock (loadedAssetsByUrl)
41 using (var profile = Profiler.Begin(AssetProfilingKeys.AssetSave))
43 SerializeObject(url, asset,
true);
50 return FileProvider.OpenStream(url, VirtualFileMode.Open, VirtualFileAccess.Read, streamFlags:streamFlags);
56 settings = AssetManagerLoaderSettings.Default;
58 if (url == null)
throw new ArgumentNullException(
"url");
60 lock (loadedAssetsByUrl)
62 using (var profile = Profiler.Begin(AssetProfilingKeys.AssetLoad, url))
64 AssetReference assetReference;
65 return (T)DeserializeObject(null, out assetReference, url, typeof(T), settings);
72 return Task.Factory.StartNew(() => Load<T>(url, settings));
77 if (obj == null)
throw new ArgumentNullException(
"obj");
78 lock (loadedAssetsByUrl)
80 AssetReference assetReference;
81 if (!loadedAssetsUrl.TryGetValue(obj, out assetReference))
87 url = assetReference.Url;
94 lock (loadedAssetsByUrl)
96 AssetReference assetReference;
97 if (!loadedAssetsUrl.TryGetValue(obj, out assetReference))
98 throw new InvalidOperationException(
"Asset not loaded through this AssetManager.");
101 DecrementReference(assetReference,
true);
107 context.Set(ContentSerializerContext.ContentSerializerContextProperty, contentSerializerContext);
110 foreach (var property
in Serializer.SerializerContextTags)
112 context.Tags.SetObject(property.Key, property.Value);
116 internal object DeserializeObject(AssetReference parentAssetReference, out AssetReference assetReference,
string url, Type objType, AssetManagerLoaderSettings settings,
ConverterContext converterContext = null)
120 if (!FileProvider.AssetIndexMap.TryGetValue(url, out objectId))
121 throw new InvalidOperationException(
string.Format(
"Asset [{0}] not found.", url));
124 if (loadedAssetsByUrl.TryGetValue(objectId, out assetReference))
126 while (assetReference != null && !objType.GetTypeInfo().IsAssignableFrom(assetReference.Object.GetType().GetTypeInfo()))
128 assetReference = assetReference.Next;
131 if (assetReference != null)
134 bool isRoot = parentAssetReference == null;
135 if (isRoot || parentAssetReference.References.Add(assetReference))
137 IncrementReference(assetReference, isRoot);
140 return assetReference.Object;
144 if (!FileProvider.FileExists(url))
145 throw new InvalidOperationException(
string.Format(
"Asset [{0}] not found.", url));
151 using (var stream = FileProvider.OpenStream(url, VirtualFileMode.Open, VirtualFileAccess.Read))
158 Type headerObjType = null;
161 var streamReader =
new BinarySerializationReader(stream);
162 var chunkHeader = ChunkHeader.Read(streamReader);
163 if (chunkHeader != null)
165 headerObjType = Type.GetType(chunkHeader.Type);
169 var serializer = Serializer.GetSerializer(headerObjType, objType);
170 if (serializer == null)
171 throw new InvalidOperationException(
string.Format(
"Content serializer for {0}/{1} could not be found.", headerObjType, objType));
175 if (chunkHeader != null && chunkHeader.OffsetToReferences != -1)
178 streamReader.NativeStream.Seek(chunkHeader.OffsetToReferences, SeekOrigin.Begin);
179 contentSerializerContext.SerializeReferences(streamReader);
180 streamReader.NativeStream.Seek(chunkHeader.OffsetToObject, SeekOrigin.Begin);
184 assetReference =
new AssetReference(objectId, url, parentAssetReference == null);
185 contentSerializerContext.AssetReference = assetReference;
187 result = serializer.Construct(contentSerializerContext);
189 PrepareSerializerContext(contentSerializerContext, streamReader.Context);
190 contentSerializerContext.ConverterContext = converterContext;
192 result = contentSerializerContext.SerializeContent(streamReader, serializer, result);
194 SetAssetObject(assetReference, result);
197 if (parentAssetReference != null)
199 parentAssetReference.References.Add(assetReference);
203 if (settings.LoadContentReferences)
209 bool shouldBeLoaded =
true;
211 AssetReference childReference;
213 if (settings.ContentFilter != null)
214 settings.ContentFilter(contentReference, ref shouldBeLoaded);
218 contentReference.ObjectValue = DeserializeObject(assetReference, out childReference, contentReference.Location, contentReference.Type, settings);
226 internal object DeserializeObjectRecursive(AssetReference parentAssetReference, out AssetReference assetReference,
231 if (!FileProvider.AssetIndexMap.TryGetValue(url, out objectId))
232 throw new InvalidOperationException(
string.Format(
"Asset [{0}] not found.", url));
235 var serializer = Serializer.GetSerializer(headerObjType, objType);
236 if (serializer == null)
237 throw new InvalidOperationException(
string.Format(
"Content serializer for {0}/{1} could not be found.", headerObjType, objType));
240 contentSerializerContext.chunkReferences.AddRange(otherContext.chunkReferences);
243 assetReference =
new AssetReference(objectId, url, parentAssetReference == null);
244 contentSerializerContext.AssetReference = assetReference;
246 var result = serializer.Construct(contentSerializerContext);
248 var streamReader =
new BinarySerializationReader(stream);
250 PrepareSerializerContext(contentSerializerContext, streamReader.Context);
251 contentSerializerContext.ConverterContext = converterContext;
253 result = contentSerializerContext.SerializeContent(streamReader, serializer, result);
255 SetAssetObject(assetReference, result);
258 if (parentAssetReference != null)
260 parentAssetReference.References.Add(assetReference);
266 private void SerializeObject(
string url,
object obj,
bool publicReference)
274 if (loadedAssetsUrl.ContainsKey(obj))
277 var serializer = Serializer.GetSerializer(null, obj.GetType());
278 if (serializer == null)
279 throw new InvalidOperationException(
string.Format(
"Content serializer for {0} could not be found.", obj.GetType()));
283 using (var stream = FileProvider.OpenStream(url, VirtualFileMode.Create, VirtualFileAccess.Write))
285 var streamWriter =
new BinarySerializationWriter(stream);
286 PrepareSerializerContext(contentSerializerContext, streamWriter.Context);
288 ChunkHeader header = null;
292 var serializationType = serializer.SerializationType;
293 if (serializationType != null)
295 header =
new ChunkHeader();
296 header.Type = serializer.SerializationType.AssemblyQualifiedName;
297 header.Write(streamWriter);
298 header.OffsetToObject = (int)streamWriter.NativeStream.Position;
301 contentSerializerContext.SerializeContent(streamWriter, serializer, obj);
306 header.OffsetToReferences = (int)streamWriter.NativeStream.Position;
307 contentSerializerContext.SerializeReferences(streamWriter);
310 stream.Seek(0, SeekOrigin.Begin);
313 header.Write(
new BinarySerializationWriter(stream));
319 if (!FileProvider.AssetIndexMap.TryGetValue(url, out objectId))
320 throw new InvalidOperationException(
string.Format(
"Asset [{0}] not found.", url));
322 var assetReference =
new AssetReference(objectId, url, publicReference);
323 contentSerializerContext.AssetReference = assetReference;
324 SetAssetObject(assetReference, obj);
328 foreach (var contentReference
in contentSerializerContext.ContentReferences)
330 if (contentReference.ObjectValue != null)
331 SerializeObject(contentReference.Location, contentReference.ObjectValue,
false);
338 internal void SetAssetObject(AssetReference assetReference,
object obj)
340 if (obj == null)
throw new ArgumentNullException(
"obj");
342 if (assetReference.Object != null)
344 if (assetReference.Object != obj)
345 throw new InvalidOperationException(
"SetAssetObject has already been called with a different object");
350 var objectId = assetReference.ObjectId;
351 assetReference.Object = obj;
353 lock (loadedAssetsByUrl)
355 AssetReference previousAssetReference;
357 if (loadedAssetsByUrl.TryGetValue(objectId, out previousAssetReference))
359 assetReference.Next = previousAssetReference.Next;
360 assetReference.Prev = previousAssetReference;
362 if (previousAssetReference.Next != null)
363 previousAssetReference.Next.Prev = assetReference;
364 previousAssetReference.Next = assetReference;
368 loadedAssetsByUrl[objectId] = assetReference;
371 loadedAssetsUrl[obj] = assetReference;
375 UrlServices.SetUrl(obj, assetReference.Url);
void Unload(object obj)
Unloads the specified object.
Specifies settings for AssetManager.Load{T} operations.
List< ContentReference > ContentReferences
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
void Save(string url, object asset)
bool TryGetAssetUrl(object obj, out string url)
A hash to uniquely identify data.
ArchiveMode
Enumerates the different mode of serialization (either serialization or deserialization).
Stream OpenAsStream(string url, StreamFlags streamFlags)
Opens the specified URL as a stream used for custom raw asset loading.
StreamFlags
Describes the different type of streams.