using System; using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace MLEM.Data.Content { /// /// Represents a version of that doesn't load content binary xnb files, but rather as their regular formats. /// public class RawContentManager : ContentManager, IGameComponent { private static readonly RawContentReader[] Readers = AppDomain.CurrentDomain.GetAssemblies() .Where(a => !a.IsDynamic) .SelectMany(a => a.GetExportedTypes()) .Where(t => t.IsSubclassOf(typeof(RawContentReader)) && !t.IsAbstract) .Select(t => t.GetConstructor(Type.EmptyTypes).Invoke(null)) .Cast().ToArray(); private readonly List disposableAssets = new List(); /// /// The graphics device that this content manager uses /// public readonly GraphicsDevice GraphicsDevice; /// /// Creates a new content manager with an optionally specified root directory. /// /// The service provider of your game /// The root directory. Defaults to "Content" public RawContentManager(IServiceProvider serviceProvider, string rootDirectory = "Content") : base(serviceProvider, rootDirectory) { if (serviceProvider.GetService(typeof(IGraphicsDeviceService)) is IGraphicsDeviceService s) this.GraphicsDevice = s.GraphicsDevice; } /// /// Loads a raw asset with the given name, based on the . /// If the asset was previously loaded using this method, the cached asset is merely returned. /// /// The path and name of the asset to load, without extension. /// The type of asset to load /// The asset, either loaded from the cache, or from disk. public override T Load(string assetName) { if (this.LoadedAssets.TryGetValue(assetName, out var ret) && ret is T t) return t; return this.Read(assetName, default); } /// protected override void ReloadAsset(string originalAssetName, T currentAsset) { this.Read(originalAssetName, currentAsset); } private T Read(string assetName, T existing) { var triedFiles = new List(); foreach (var reader in Readers.Where(r => r.CanRead(typeof(T)))) { foreach (var ext in reader.GetFileExtensions()) { var file = Path.Combine(this.RootDirectory, $"{assetName}.{ext}"); triedFiles.Add(file); if (!File.Exists(file)) continue; using (var stream = File.OpenRead(file)) { var read = reader.Read(this, assetName, stream, typeof(T), existing); if (!(read is T t)) throw new ContentLoadException($"{reader} returned non-{typeof(T)} for asset {assetName}"); this.LoadedAssets[assetName] = t; if (t is IDisposable d && !this.disposableAssets.Contains(d)) this.disposableAssets.Add(d); return t; } } } throw new ContentLoadException($"Asset {assetName} not found. Tried files {string.Join(", ", triedFiles)}"); } /// public override void Unload() { foreach (var d in this.disposableAssets) d.Dispose(); this.disposableAssets.Clear(); base.Unload(); } /// public void Initialize() { } } }