mcNows
Nows Loader 0.6.2 / Minecraft 26.2

Minecraft Adapter APIs

Use stable Nows adapter helpers for registries, text, NBT, keybinds, recipe displays, events and generated data.

Minecraft Adapter APIs

mc/<version> exposes Minecraft-facing API helpers for the selected game version. In 0.6.0 the stable path is Nows-owned input values first, then adapter translation into the real Minecraft API for that version.

Mods can use the same Nows API class names across supported versions while each adapter handles common version details:

RegistryApi registries = MinecraftApi.registries(context);
TextApi text = MinecraftApi.text(context);
NbtApi nbt = MinecraftApi.nbt(context);

Item item = registries.registerItem(ItemSpec.builder("my_mod:widget")
        .maxStackSize(16)
        .build());
BlockEntry block = registries.registerBlockWithItem(
        BlockSpec.builder("my_mod:machine")
                .material(BlockMaterial.METAL)
                .strength(2.0F, 6.0F)
                .requiresCorrectTool()
                .item(ItemSpec.builder("my_mod:machine").maxStackSize(32).build())
                .build());
ItemStack stone = registries.itemStack(ItemStackSpec.of("minecraft:stone", 2));

The older native escape hatches still exist for advanced code, such as custom item/block factories and raw registry registration. Prefer the stable specs when the mod only needs common item, block, stack or material intent.

The adapter entrypoint is MinecraftApi. It resolves services from NowsContext, so use it after the loader has created the mod context, usually inside your mod entrypoint or a lifecycle listener that runs after bootstrap.

What The Adapter Owns

Area Current helper shape
registry ids, keys and tags id, resourceLocation, key, tag, itemKey, blockKey, itemTag, blockTag
basic items and blocks plain item/block registration, configurable properties, custom factories
content registration food, sword, armor, block item, block with item, menus, block entities, recipes, sounds, creative tabs
text literal, translatable and keybind components
NBT compound/list construction, common primitive reads/writes, explicit fallbacks
client UI hooks, config screens, keybinds and local player helpers
data and events data packs, generated JSON, command registration and tick callbacks

The returned objects are still Minecraft objects for the target adapter. That is deliberate: a mod can use Nows for stable setup and then continue with normal Minecraft APIs.

Content Mods

For content-heavy mods, the registry adapter also covers the common objects that usually differ between Fabric, Forge and Minecraft versions:

RecipeType<MyRecipe> type = registries.registerRecipeType("my_mod:oven_baking");
RecipeSerializer<MyRecipe> serializer = registries.registerRecipeSerializer(
        "my_mod:oven_baking",
        MyRecipeSerializer.create());

MenuType<MyMenu> menu = registries.registerMenu("my_mod:oven", MyMenu::new);
BlockEntityType<MyBlockEntity> blockEntity = registries.registerBlockEntity(
        "my_mod:oven",
        MyBlockEntity::new,
        ovenBlock);

SoundEvent sound = registries.registerVariableRangeSound("my_mod:frying");

These helpers are aimed at the boring registration layer that changes shape across loaders and Minecraft versions:

  • registerRecipeType creates the named recipe type and gives it a stable string id for recipe lookup and debugging.
  • registerRecipeSerializer registers your custom serializer object without making the mod repeat the raw registry call in every target.
  • registerMenu registers a simple two-argument AbstractContainerMenu factory, the common pattern for inventory/container menus.
  • registerBlockEntity registers a block entity type from a Nows BlockEntityFactory, so mods do not need to depend on Minecraft’s version-specific builder or supplier names.
  • registerVariableRangeSound registers a regular variable-range SoundEvent, matching the usual custom sound event pattern.

Item And Food Mods

For item-only or food-heavy mods, keep the mod data in your own constants and call the item helpers in a loop. This is the easiest path for mods that mainly differ by food values, stack sizes, creative tabs or generated assets:

Map<String, Item> foods = new LinkedHashMap<>();

for (FoodEntry entry : FoodEntries.ALL) {
    Item item = registries.registerFood(
            "my_mod:" + entry.id(),
            new FoodProperties.Builder()
                    .nutrition(entry.nutrition())
                    .saturationModifier(entry.saturation())
                    .build(),
            props -> props.stacksTo(entry.maxStackSize()));
    foods.put(entry.id(), item);
}

registries.registerCreativeTab(
        "my_mod:foods",
        text.translatable("itemGroup.my_mod.foods"),
        () -> new ItemStack(foods.get("complete_breakfast")),
        (parameters, output) -> foods.values().forEach(output::accept));

Machines And Workstations

For machine or workstation mods, keep the machine behavior in normal Minecraft subclasses and use Nows only for the stable registration boundary. A cooking block entity can still own its inventory, ticking, recipe lookup, save/load and experience logic directly. Nows only removes the repeated registry wiring:

Block ovenBlock = registries.registerCustomBlock("my_mod:oven",
        props -> new OvenBlock(props.strength(3.5F)));
BlockItem ovenItem = registries.registerBlockItem("my_mod:oven", ovenBlock);

RecipeType<OvenRecipe> ovenRecipes = registries.registerRecipeType("my_mod:oven");
RecipeSerializer<OvenRecipe> ovenSerializer = registries.registerRecipeSerializer(
        "my_mod:oven",
        OvenRecipeSerializer.create());

BlockEntityType<OvenBlockEntity> ovenEntity = registries.registerBlockEntity(
        "my_mod:oven",
        OvenBlockEntity::new,
        ovenBlock);
MenuType<OvenMenu> ovenMenu = registries.registerMenu("my_mod:oven", OvenMenu::new);

Mods with simple facing machine blocks can reuse Nows base block classes instead of copying the same state boilerplate across versions:

import space.nows.mcnows.mc.api.registry.block.HorizontalBlock;
import space.nows.mcnows.mc.api.registry.block.HorizontalLitBlock;

Block pan = registries.registerCustomBlock("my_mod:pan",
        props -> new HorizontalBlock(props.strength(1.5F)));
Block stove = registries.registerCustomBlock("my_mod:stove",
        props -> new HorizontalLitBlock(props.strength(3.5F).lightLevel(state ->
                state.getValue(HorizontalLitBlock.LIT) ? 13 : 0)));

HorizontalBlock adds the HORIZONTAL_FACING property, placement direction, rotation and mirror behavior. HorizontalLitBlock adds the same facing behavior plus Minecraft’s LIT property. They are useful for simple props, stoves, pans, ovens and other workstation blocks. If a block has custom voxel shapes, waterlogging, redstone behavior, menu opening, ticking or entity interaction, subclass one of these or use registerCustomBlock with your own Minecraft block class.

Lookup And Simple Logic

Existing registry entries can be queried with Optional-returning methods or fail-fast getters:

var widgetId = registries.resourceLocation("my_mod:widget");
ResourceKey<Item> widgetKey = registries.itemKey("my_mod:widget");
TagKey<Block> machineBlocks = registries.blockTag("my_mod:machines");
registries.item("minecraft:diamond").ifPresent(stackItem -> {});
Item diamond = registries.getItem("minecraft:diamond");
Block stone = registries.getBlock("minecraft:stone");

Use registries.id(...) or registries.resourceLocation(...) for the selected adapter’s real resource-id type. Newer adapters return Identifier; older adapters return ResourceLocation. registries.key(...), itemKey(...), blockKey(...), tag(...), itemTag(...) and blockTag(...) cover the common registry key/tag cases when the target Minecraft version exposes those classes.

Text helpers cover the common literal, translation and keybind component constructors without making mods remember when Minecraft renamed those factories:

Component title = text.component(McText.translatable("screen.my_mod.settings"));
Component help = text.component(McText.keybind("key.my_mod.open_oven"));

McText is the stable public value. Each adapter maps it to TextComponent, Component.literal, Component.translatable or the matching Minecraft text API for that version.

Keybinds

Client mods can register keybind categories and key mappings through Nows instead of wiring each Minecraft version by hand:

KeybindApi keys = MinecraftApi.keybinds(context);

keys.registerCategory("key.categories.my_mod");

keys.registerKeyboard(
        "key.my_mod.open_oven",
        "key.categories.my_mod",
        GLFW.GLFW_KEY_O,
        () -> MyScreens.openOven(context));

For actions that should run while the key is held, keep the returned mapping and use the normal client tick hook:

KeybindRegistration boost = keys.registerKeyboard(
        "key.my_mod.boost",
        "key.categories.my_mod",
        GLFW.GLFW_KEY_B);

MinecraftApi.events(context).clientTick(client -> {
    if (boost.isDown() && client.player != null) {
        client.player.setDeltaMovement(client.player.getDeltaMovement().multiply(1.2D, 1.0D, 1.2D));
    }
});

The default category is key.categories.nows. Key ids and categories should be translation keys so Minecraft’s Controls screen can show localized names.

registerKeyboard(id, category, key, onPress) installs a press callback directly. If the action depends on continuous state, keep the returned KeybindRegistration and poll isDown() in GameEvents.clientTick.

NBT helpers cover common compound/list reads and writes with explicit fallbacks. 0.6.0 also adds stable Nows NBT payloads that adapters convert to the real Minecraft tag classes:

NbtCompound data = nbt.stableCompound()
        .putString("owner", "my_mod")
        .putInt("heat", 7)
        .putBoolean("active", true);

CompoundTag nativeData = nbt.compound(data);
Tag nativeValue = nbt.tag(NbtValue.compound(data));

The native helpers remain available for direct reads/writes on Minecraft CompoundTag and ListTag. Item-stack custom data is still deliberately separate because Minecraft 1.20.5+ moved much of that surface toward data components.

Use direct Minecraft APIs for anything outside this list: world saves, block entity serialization details, data components, custom renderers, entity behavior and low-level packet encoding.

Recipe Viewer Porting

Mods that already expose recipes to JEI can move their category and layout logic to Nows without depending on JEI at compile time. The RecipeViewerApi stores neutral display metadata that can be bridged later to JEI, REI, EMI or a built-in viewer:

RecipeViewerApi recipes = MinecraftApi.recipeViewer(context);

recipes.registerCategory(
        "my_mod:oven",
        OvenRecipe.class,
        text.translatable("recipe.my_mod.oven"),
        new ItemStack(ovenBlock),
        (recipe, layout) -> layout
                .input(20, 18, recipe.ingredient())
                .catalyst(20, 52, new ItemStack(ovenBlock))
                .output(82, 18, recipe.result())
                .build());

recipes.registerCatalyst("my_mod:oven", new ItemStack(ovenBlock));
recipes.registerRecipeTransfer("my_mod:oven", ovenMenu);

The porting shape mirrors the common JEI split:

  • registerCategory replaces the JEI category registration boundary while keeping the mod’s own recipe class.
  • RecipeViewerLayout.Builder covers the usual input, inputStack, inputStacks, output, outputStacks and catalyst slots with stable x/y coordinates.
  • registerCatalyst records workstation or tool stacks that should open the category.
  • registerRecipeTransfer links a menu type to the category so a later viewer bridge can offer transfer buttons.

Keep recipe lookup, validation and screen rendering in normal Minecraft code. This API is only the shared display contract, so the same mod code can run on Nows even when JEI is absent.

For simple behavior, mods can attach small logic hooks:

registries.registerItem("my_mod:wrench", props -> props.stacksTo(1), new ItemLogic() {
    @Override
    public InteractionResult useOn(UseOnContext context) {
        return InteractionResult.SUCCESS;
    }
});

registries.registerBlock("my_mod:speed_plate", props -> props.strength(1.0F), new BlockLogic() {
    @Override
    public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
        entity.setDeltaMovement(entity.getDeltaMovement().multiply(1.4D, 1.0D, 1.4D));
    }
});

For custom behavior beyond the basic layer, use Minecraft’s API directly. registerCustomItem and registerCustomBlock accept your own Item/Block subclasses.