Skip to content

Runtime Resource Packs

MehVahdJukaar edited this page Jul 25, 2026 · 1 revision

Runtime Resource Packs

Generate textures, models, blockstates, recipes, tags and lang files while the game loads, and serve them from a virtual resource pack.

This is the flagship feature and the reason the library exists. If your mod registers blocks that depend on what other mods are installed, one per wood type, one per color, you can't ship files for all of them. So you build the assets at runtime out of the textures that are actually there.

Your generator reads the already loaded packs, so it sees the player's own resource pack too, and writes into a sink. The result sits below every other pack, so anyone can still override a generated file with a real one.

Getting Started

Extend DynamicClientResourceProvider (assets) or DynamicServerResourceProvider (data), and register it on init:

RegHelper.registerDynamicResourceProvider(new MyModAssets());
public class MyModAssets extends DynamicClientResourceProvider {

    public MyModAssets() {
        super(MyMod.res("example_pack"), PackGenerationStrategy.CACHED);
    }

    @Override
    protected Collection<String> gatherSupportedNamespaces() {
        return List.of("minecraft");   // must be known before anything is generated
    }

    @Override
    public void regenerateDynamicAssets(Consumer<ResourceGenTask> executor) {
        // split the work in a few tasks, they run in parallel
        executor.accept((manager, sink) -> {
            JsonObject json = new JsonObject();
            json.addProperty("parent", "block/stone");
            sink.addItemModel(MyMod.res("sturdy_stone_bricks"), json);

            // only generate if no pack already provides it. The supplier isn't called otherwise
            sink.addTextureIfNotPresent(manager, MyMod.res("block/sturdy_stone_bricks"),
                    () -> makeTexture(manager));

            // take a vanilla file and string replace your way to a new one
            StaticResource stone = StaticResource.getOrThrow(manager,
                    ResourceLocation.parse("models/block/stone_bricks.json"));
            sink.addSimilarJsonResource(manager, stone, "stone_bricks", "sturdy_stone_bricks");
        });
    }

    @Override
    public void addDynamicTranslations(AfterLanguageLoadEvent event) {
        event.addEntry("mymod.test.translation", "Hello World!");
    }
}

The ResourceSink has an addX for everything: textures, models, blockstates, lang, tags, recipes, loot tables, or raw json and bytes. The IfNotPresent / UnlessPresent variants skip the work when a real pack already has that file, use them for anything a pack author might want to hand-author.

Example: DynamicResourcesExample

Generation strategies

The second constructor argument decides when the work is redone:

Strategy
CACHED Generate once, cache to disk, reuse. The normal choice
CACHED_ZIPPED Same, cached as a zip
REGEN_ON_EVERY_RELOAD Rebuild on every F3+T, in memory
runOnce() Once per launch, in memory
NO_OP Never. For a pack you fill some other way

Caches invalidate when the mod list changes, and when a config marked affectsDynamicPacks() changes.

Notes

extra_debug in the common config dumps everything that was generated to .minecraft/debug/.

merge_dynamic_resource_packs (client, on by default) merges every mod's dynamic pack into one. Turn it off to see them separately in the pack list.

See Texture Manipulation for building the images you feed into the sink, and Block Set API for what usually drives all of this.

Clone this wiki locally