Static Resources API
This post is inaccurate to what now exists in the API, please see the comment made before marking this PR as ready for review!
This is an API for Static Resources: user-controlled data that is accessible early, scope-independent and does not change after it is loaded.
Motivations
Due to the properties of Static Resources, they have uses in creating data-driven APIs that affect the game's state in a way that does not change, and/or in a way that must be done far before vanilla's Resource/Data Packs become available. This makes a Static Resources API essential for a future Content Pack API, as the registries said API would need to modify are static in of themselves and are frozen early on in the game's loading process, making regular resources (in the form of Data Packs) highly unsuited for such an API.
The Resource class and mutability of on-disk files
While the first two properties of Static Resources (early access and scope-independence) are already implemented in the current draft, the third property (immutability) is a far more complicated affair, as the needs of each consumer of Static Resources will likely vary heavily in terms of how many times said consumer accesses said resources. Since Resource objects are just pointers to a file and this API primarily returns Resource objects, it is possible for the contents of the file to be modified at runtime, which may cause unexpected behavior for the consumer. To be honest, I (rin) am not sure whether or not ensuring strict immutability of the data provided by Resource instances is something this API should even be concerned with doing—this will need discussion in the Quilt discord and/or in this PR's comments.
The API itself: modder & QSL-side
The API is found in the core/resource_loader package, and is primarily accessed through two StaticResourceLoaderImpl objects. Said objects are accessible outside of the API via the static interface method StaticResourceLoader#get, to which a vanilla ResourceType object is provided—while this currently (subject to change if requested—this could easily be enforced) only dictates where the API gets Resources from, it should be treated the same as in vanilla, where ResourceType.CLIENT_RESOURCES are only available on the client, and ResourceType.SERVER_DATA in all scopes.
The implementation of StaticResourceLoader (and thus the two objects provided, depending on whether server data or client resources are requested) serves as a fairly thin wrapper around another API-internal class, StaticResourceManager, which is currently little more than a re-implementation of the vanilla MultiPackResourceManager class. This was done as MultiPackResourceManager is an essential part of the very much not static vanilla resource loading process, and is targeted by mixins changing things about said process—using an object of that class (or of a child of that class) for this API would lead to it being affected by those mixins.
Currently, consumers of Static Resources are responsible for loading the files provided Resource objects point to themselves.
The API itself: the stuff exposed to end-users
Static Resources are stored within the static/resources and static/data folders: the former being for client-side resources/data and the latter for server-side resources/data. Basically, these folders have a same purpose to vanilla's resources folder and the datapacks folder in each world save, respectively. Like vanilla resource packs and data packs, the files placed in these folders must be contained in packs as well—though the distinction between resource packs and data packs is less concrete with static packs than it is with vanilla's packs.
TODO Checklist before this API is ready for review and merger
- [X] Implement the Static Resource Loader (
StaticResourceLoader/StaticResourceManagerImpl) and the manager backing it (StaticResourceManager) - [ ] Write any additional API infrastructure needed for the Static Resource Loader. Input is needed here!
- [ ] Write test mod stuff for the Static Resource Loader
- [ ] Write Javadocs
If data immutability should be ensured by the API:
- [ ] Create some form of
CachedResourceclass or something along those lines, some form of hashing of the loaded data, etc - [ ] Figure out how to even ensure said disk-loaded data immutability and implement it
After quite a bit of refactoring work, I'd say this is finally ready for review. Let's go over what's changed since the first post:
-
StaticResourceLoaderno longer exists, and is simply part of the mainResourceLoaderclass and impl. -
StaticResourceManageris now a child class ofMultiPackResourceManagerthat implements a wrapper interface—the wrapper interface is also implemented byMultiPackResourceManagerMixinto prevent cast-related exceptions. Said wrapper interface's helper method is used in said mixin to check if theMultiPackResourceManagerobject mixin methods are currently running in areStaticResourceManagerobjects, at which point they immediately return (if avoidmethod) or pass the original value (if a@ModifyVariablemixin method). Future mixins added toMultiPackResourceMangerMixinshould use this wrapper to prevent them from being ran withinStaticResourceManagers. -
No helper methods for working with JSON exist anymore—these will probably be a future PR, and work with all
Resourceobjects, not just static ones. -
Pack loading actually works now, and tests exist to prove that it works.
Thank you to everyone who gave feedback and advice in the discord and on here during the process of developing this PR, it wouldn't have been possible to write it otherwise.
Unless anyone else has suggestions for additions again, this should be ready for re-review by @LambdAurora
Could we potentially get some more movement on this soonish, now that QFAPI sync is back in order?
Should be ready for 1.20.2 now—I have absolutely no clue why there's conflicts in ResourceLoaderImpl, however. Both supposed conflicts seem to just be adding stuff? Not sure why its marking them as conflicts, but it took quite a few attempts to get this to merge at all locally, as it tended to get stuck in an infinite loop of trying to resolve the same conflicts over and over again.
Ready for 1.20.2 again if all checks pass—ResourceLoaderImpl's conflicts are git being weird just like last time
this might be hard but i would try rebasing your PR off of 1.20.2. That should hopefully fix the conflict
Have tried doing that and it gets stuck in the infinite loop usually. Might try doing it again later