using System.Diagnostics.CodeAnalysis; using Robust.Client.ResourceManagement; using Robust.Shared.Utility; namespace Content.Client.Stylesheets; public abstract partial class BaseStylesheet { /// /// The file roots of the stylesheet, dictates where assets get read from for the given type of resource. /// Roots will be checked in order for assets, avoid having a significant number of them. /// /// /// Must be a constant, changes to this after construction will not be reflected. /// public abstract Dictionary Roots { get; } /// /// Attempts to locate a resource within the stylesheet's roots. /// /// The relative path of the target resource. /// The discovered/cached resource, if any. /// Type of the resource to read. /// Whether is null. public bool TryGetResource(ResPath target, [NotNullWhen(true)] out T? resource) where T : BaseResource, new() { DebugTools.Assert(target.IsRelative, "Target path must be relative. Use ResCache directly if you need an absolute file location."); foreach (var root in Roots[typeof(T)]) { if (ResCache.TryGetResource(root / target, out resource)) return true; } resource = null; return false; } /// /// Retrieves a resource, or throws. /// /// The relative path of the target resource. /// Type of the resource to read. /// The retrieved resource /// Thrown if the resource does not exist within the stylesheet's roots. public T GetResource(ResPath target) where T : BaseResource, new() { if (TryGetResource(target, out T? res)) return res; throw new MissingStyleResourceException(this, target.ToString()); } /// /// Retrieves a resource, or falls back to the specified root. The resource should be present at the fallback /// root, or else it throws /// /// /// This should be used to allow common sheetlets to be generic over multiple stylesheets without forcing other /// styles to have the resource present, if your sheetlet is stylesheet-specific you should not use this. /// /// The relative path of the target resource. /// The root that this resource will always exist at /// Type of the resource to read. /// The retrieved resource /// Thrown if the resource does not exist in the fallback root. public T GetResourceOr(ResPath target, ResPath fallbackRoot) where T : BaseResource, new() { DebugTools.Assert(fallbackRoot.IsRooted, "Fallback root must be absolute. Roots can be retrieved from the stylesheets."); if (!ResCache.TryGetResource(fallbackRoot / target, out T? fallback)) throw new ExpectedResourceException(this, target.ToString()); return TryGetResource(target, out T? res) ? res : fallback; } } /// /// Exception thrown when the never-fail helpers in fail to locate a resource. /// /// The stylesheet /// public sealed class MissingStyleResourceException(BaseStylesheet sheet, string target) : Exception { public override string Message => $"Failed to find any resource at \"{target}\" for {sheet}. The roots are: {sheet.Roots}"; public override string? Source => sheet.ToString(); } /// /// Exception thrown when the never-fail helpers in expect a resource at a location /// but do not find it. /// /// The stylesheet /// public sealed class ExpectedResourceException(BaseStylesheet sheet, string target) : Exception { public override string Message => $"Failed to find any resource at \"{target}\" for {sheet}, when such a resource was expected."; public override string? Source => sheet.ToString(); }