From db768bb4f789267f05b40ab68c1e3a8477f1c6b4 Mon Sep 17 00:00:00 2001 From: Dustin Norberg Date: Mon, 21 Sep 2026 06:38:44 -0400 Subject: [PATCH] Complete bootstrap milestone --- README.md | 7 ++-- docs/PORTING.md | 10 +++++- .../net/dnorberg/rivencraft/Rivencraft.java | 29 +++-------------- .../rivencraft/item/DescriptiveBookItem.java | 32 +++++++++++++++++++ .../rivencraft/registry/ModCreativeTabs.java | 28 ++++++++++++++++ .../rivencraft/registry/ModItems.java | 25 +++++++++++++++ .../assets/rivencraft/lang/en_us.json | 1 + 7 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java create mode 100644 src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java create mode 100644 src/main/java/net/dnorberg/rivencraft/registry/ModItems.java diff --git a/README.md b/README.md index 81c13e3..4a1de14 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,10 @@ Rivencraft is a clean, incremental port of the ideas and gameplay of [Mystcraft Legacy](https://github.com/Mystcraft/Mystcraft-Legacy) to Minecraft 1.21.1 on NeoForge. -The project is at the bootstrap stage. It currently provides a valid NeoForge -mod, a creative tab, and a placeholder Descriptive Book item. Age generation, -linking, symbols, instability, and writing mechanics have not been ported yet. +The bootstrap milestone is complete. The project currently provides a valid +NeoForge mod, a creative tab, and an unwritten Descriptive Book item. Age +generation, linking, symbols, instability, and writing mechanics have not been +ported yet. ## Requirements diff --git a/docs/PORTING.md b/docs/PORTING.md index 2e6714d..c55521d 100644 --- a/docs/PORTING.md +++ b/docs/PORTING.md @@ -8,7 +8,7 @@ split into independently testable milestones. ## Milestones 1. **Bootstrap** — NeoForge 1.21.1 build, mod metadata, item registration, and - CI. (In progress.) + CI. **Complete.** 2. **Books and linking** — descriptive/linking book data components, lectern-like interaction, safe teleportation, and return links. 3. **Ages** — dimension definitions backed by data packs, deterministic seeds, @@ -36,3 +36,11 @@ The first functional target is: create a Descriptive Book, bind it to one server-managed Age definition, travel to that Age, and use a Linking Book to return. This exercises persistence, networking, dimensions, and safety before the symbol grammar is introduced. + +## Milestone 1 acceptance record + +- The project builds on a Java 21 JDK with `./gradlew build`. +- Mod identity and dependencies are declared in generated NeoForge metadata. +- Registrations are isolated by registry type and use deferred registration. +- The Descriptive Book loads with a model, name, tooltip, and creative tab. +- CI builds every pushed commit and pull request. diff --git a/src/main/java/net/dnorberg/rivencraft/Rivencraft.java b/src/main/java/net/dnorberg/rivencraft/Rivencraft.java index 6490add..d2ac486 100644 --- a/src/main/java/net/dnorberg/rivencraft/Rivencraft.java +++ b/src/main/java/net/dnorberg/rivencraft/Rivencraft.java @@ -1,15 +1,10 @@ package net.dnorberg.rivencraft; import com.mojang.logging.LogUtils; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.Item; +import net.dnorberg.rivencraft.registry.ModCreativeTabs; +import net.dnorberg.rivencraft.registry.ModItems; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredItem; -import net.neoforged.neoforge.registries.DeferredRegister; import org.slf4j.Logger; @Mod(Rivencraft.MOD_ID) @@ -17,25 +12,9 @@ public final class Rivencraft { public static final String MOD_ID = "rivencraft"; public static final Logger LOGGER = LogUtils.getLogger(); - private static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MOD_ID); - private static final DeferredRegister CREATIVE_TABS = - DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MOD_ID); - - public static final DeferredItem DESCRIPTIVE_BOOK = ITEMS.registerSimpleItem( - "descriptive_book", - new Item.Properties().stacksTo(1) - ); - - public static final DeferredHolder RIVENCRAFT_TAB = - CREATIVE_TABS.register("rivencraft", () -> CreativeModeTab.builder() - .title(Component.translatable("itemGroup.rivencraft")) - .icon(() -> DESCRIPTIVE_BOOK.get().getDefaultInstance()) - .displayItems((parameters, output) -> output.accept(DESCRIPTIVE_BOOK.get())) - .build()); - public Rivencraft(IEventBus modEventBus) { - ITEMS.register(modEventBus); - CREATIVE_TABS.register(modEventBus); + ModItems.register(modEventBus); + ModCreativeTabs.register(modEventBus); LOGGER.info("Initializing Rivencraft"); } } diff --git a/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java b/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java new file mode 100644 index 0000000..d0bf781 --- /dev/null +++ b/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java @@ -0,0 +1,32 @@ +package net.dnorberg.rivencraft.item; + +import java.util.List; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; + +/** + * A book that will eventually describe and link to a generated Age. + * + *

The bootstrap implementation deliberately has no interaction behavior. + * Binding and travel belong to the books-and-linking milestone, where their + * server-authoritative data model can be introduced together.

+ */ +public final class DescriptiveBookItem extends Item { + public DescriptiveBookItem(Properties properties) { + super(properties); + } + + @Override + public void appendHoverText( + ItemStack stack, + TooltipContext context, + List tooltipComponents, + TooltipFlag tooltipFlag + ) { + tooltipComponents.add(Component.translatable("item.rivencraft.descriptive_book.unwritten") + .withStyle(ChatFormatting.GRAY)); + } +} diff --git a/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java b/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java new file mode 100644 index 0000000..354d8b8 --- /dev/null +++ b/src/main/java/net/dnorberg/rivencraft/registry/ModCreativeTabs.java @@ -0,0 +1,28 @@ +package net.dnorberg.rivencraft.registry; + +import net.dnorberg.rivencraft.Rivencraft; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.CreativeModeTab; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +public final class ModCreativeTabs { + private static final DeferredRegister CREATIVE_TABS = + DeferredRegister.create(Registries.CREATIVE_MODE_TAB, Rivencraft.MOD_ID); + + public static final DeferredHolder RIVENCRAFT = + CREATIVE_TABS.register("rivencraft", () -> CreativeModeTab.builder() + .title(Component.translatable("itemGroup.rivencraft")) + .icon(() -> ModItems.DESCRIPTIVE_BOOK.get().getDefaultInstance()) + .displayItems((parameters, output) -> output.accept(ModItems.DESCRIPTIVE_BOOK.get())) + .build()); + + private ModCreativeTabs() { + } + + public static void register(IEventBus modEventBus) { + CREATIVE_TABS.register(modEventBus); + } +} diff --git a/src/main/java/net/dnorberg/rivencraft/registry/ModItems.java b/src/main/java/net/dnorberg/rivencraft/registry/ModItems.java new file mode 100644 index 0000000..38b85ee --- /dev/null +++ b/src/main/java/net/dnorberg/rivencraft/registry/ModItems.java @@ -0,0 +1,25 @@ +package net.dnorberg.rivencraft.registry; + +import net.dnorberg.rivencraft.Rivencraft; +import net.dnorberg.rivencraft.item.DescriptiveBookItem; +import net.minecraft.world.item.Item; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredItem; +import net.neoforged.neoforge.registries.DeferredRegister; + +public final class ModItems { + private static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(Rivencraft.MOD_ID); + + public static final DeferredItem DESCRIPTIVE_BOOK = ITEMS.registerItem( + "descriptive_book", + DescriptiveBookItem::new, + new Item.Properties().stacksTo(1) + ); + + private ModItems() { + } + + public static void register(IEventBus modEventBus) { + ITEMS.register(modEventBus); + } +} diff --git a/src/main/resources/assets/rivencraft/lang/en_us.json b/src/main/resources/assets/rivencraft/lang/en_us.json index 9dfb840..ba9bb8d 100644 --- a/src/main/resources/assets/rivencraft/lang/en_us.json +++ b/src/main/resources/assets/rivencraft/lang/en_us.json @@ -1,4 +1,5 @@ { "item.rivencraft.descriptive_book": "Descriptive Book", + "item.rivencraft.descriptive_book.unwritten": "Unwritten", "itemGroup.rivencraft": "Rivencraft" }