using System.Diagnostics.CodeAnalysis; using System.Linq; using DaggerFramework.Utils; namespace DaggerFramework.Resources { public class ResourceManager { public string ResourceRoot { get; set; } = "Resources/"; public bool TryLoad(string resourceId, string path) where T : Resource { T? resource = null; var fullPath = Path.Combine(ResourceRoot, path); // TODO: don't check if file doesn't exist in the file system, make it more generic but for now it's fine if (!File.Exists(fullPath)) { _logger.Error($"File at \"{path}\" doesn't exist!"); return false; } _logger.Info($"Loading {path} as {typeof(T)} with id \"{resourceId}\"..."); if (!TryGetLoader(out IResourceLoader? loader)) { return false; } var extension = Path.GetExtension(fullPath); var hasExtension = loader.SupportedExtensions.Any(ext => extension[1..] == ext); if (!hasExtension) { _logger.Error($"Extension {extension} is not supported!"); } if (loader.Load(fullPath) is not T loadedResource) { return false; } resource = loadedResource; _loadedResources.Add(resourceId, resource); _logger.Info($"\"{resourceId}\" was loaded successfully."); return true; } public bool TrySave(string path, in T resource) where T : Resource { if (!TryGetSaver(out IResourceSaver? saver)) { return false; } if (!saver.TrySave(path, in resource)) { return false; } return true; } public bool TryGetResource(string resourceId, [NotNullWhen(true)] out T? resource) where T : Resource { resource = null; if (!IsResourceLoaded(resourceId)) { _logger.Error($"Resource \"{resourceId}\" has not yet been loaded!"); return false; } var expectedResource = _loadedResources[resourceId]; if (expectedResource is not T loadedResource) { _logger.Error($"Given resource is of wrong type: provided {typeof(T)}, expected {expectedResource.GetType()}!"); return false; } resource = loadedResource; return true; } public bool IsResourceLoaded(string resourceId) => _loadedResources.ContainsKey(resourceId); public void AddResourceLoaderAssociation(IResourceLoader loader) where T : Resource { _logger.Info($"Added resource loader association for {typeof(T)}."); _resourceLoaderAssociations.Add(typeof(T), loader); } public void AddResourceSaverAssociation(IResourceSaver saver) where T : Resource { _logger.Info($"Added resource saver association for {typeof(T)}."); _resourceSaverAssociations.Add(typeof(T), saver); } private bool TryGetLoader([NotNullWhen(true)] out IResourceLoader? loader) where T : Resource { loader = null; if (!_resourceLoaderAssociations.ContainsKey(typeof(T))) { _logger.Error($"No loader association found for {typeof(T)}."); return false; } loader = _resourceLoaderAssociations[typeof(T)] as IResourceLoader; if (loader is not null) { _logger.Info($"Using {loader.GetType()} for loading..."); } else { _logger.Error($"No loader association found for {typeof(T)}."); return false; } return true; } private bool TryGetSaver([NotNullWhen(true)] out IResourceSaver? saver) where T : Resource { saver = null; if (!_resourceSaverAssociations.ContainsKey(typeof(T))) { _logger.Error($"No saver association found for {typeof(T)}."); return false; } saver = _resourceSaverAssociations[typeof(T)] as IResourceSaver; if (saver is not null) { _logger.Info($"Using {saver.GetType()} for saving..."); } else { _logger.Error($"No saver association found for {typeof(T)}."); return false; } return true; } private Logger _logger = new(nameof(ResourceManager)); private readonly Dictionary _resourceLoaderAssociations = new() { {typeof(Sound), new SoundLoader()}, {typeof(Texture2d), new Texture2dLoader()}, {typeof(Font), new FontLoader()} }; private readonly Dictionary _resourceSaverAssociations = new() { }; private Dictionary _loadedResources = new(); } }