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.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() .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); } private static RawContentReader GetReader() { var reader = Readers.FirstOrDefault(r => r.CanRead(typeof(T))); if (reader == null) throw new ContentLoadException($"{typeof(T)} has no RawContentReader"); return reader; } /// protected override void ReloadAsset(string originalAssetName, T currentAsset) { this.Read(originalAssetName, currentAsset); } private T Read(string assetName, T existing) { var reader = GetReader(); foreach (var ext in reader.GetFileExtensions()) { var file = new FileInfo(Path.Combine(this.RootDirectory, $"{assetName}.{ext}")); if (!file.Exists) continue; using (var stream = file.OpenRead()) { 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"); } /// public override void Unload() { foreach (var d in this.disposableAssets) d.Dispose(); this.disposableAssets.Clear(); base.Unload(); } /// public void Initialize() { } } }