diff --git a/docs/MILESTONE_7_ADVANCEMENTS.md b/docs/MILESTONE_7_ADVANCEMENTS.md new file mode 100644 index 0000000..0a6ee6b --- /dev/null +++ b/docs/MILESTONE_7_ADVANCEMENTS.md @@ -0,0 +1,40 @@ +# Milestone 7 advancements and discovery (#81) + +Rivencraft's advancement tab follows the visible progression in Mystcraft +Legacy's `assets/mystcraft/advancements/`: Page, unwritten Linking Book, +Writing Desk writing, Age Book, and safe Age travel. Titles such as *The Ending +Has Not Yet Been Written*, *D'ni Ink*, and *The Art of Writing* reference Myst +without requiring any assets from that game. The Legacy hidden Quinn trigger +has no established Rivencraft action and is deliberately omitted. + +`root`, `page`, and `linking_book` use vanilla server-side tick/inventory +criteria. `link_panel`, `copy_page`, `bind_age`, `open_portal`, and `enter_age` +use an impossible criterion awarded only after the server commits the +corresponding action. The Age-travel award requires a successful book or portal +link ending in a registered Rivencraft Age. Opening a book GUI, rendering a +destination preview, viewing a recipe, or merely loading an Age cannot award +it. Progress is stored by Minecraft per player and survives world restarts. + +Vanilla recipe-book unlock advancements now cover the Writing Desk, Ink Mixer, +Book Binder, and Notebook, in addition to the existing Ink Vial, Crystal +Block, and Book Receptacle unlocks. The component-sensitive Linking Book +crafting recipe remains a special recipe: its Link Panel requirement and the +Writing Desk/Ink Mixer/Book Binder processes are explained by Rivencraft's +optional JEI integration. No recipe or advancement requires JEI, Create, or +Immersive Portals to be installed. + +Manual Survival check: collect a Page and Linking Book; use the Ink Mixer to +take a Link Panel; copy a Page at the Writing Desk; bind a Descriptive Book; +enter its Age; activate a Crystal Portal. Confirm each advancement appears +only after the completed action, not from an output preview or GUI opening. +Repeat the actions with two players to confirm only the actor receives each +award. Restart an existing save and confirm completed progress remains, then +complete one previously unearned milestone. With JEI absent, the vanilla +recipe book should still reveal standard crafting recipes as their ingredients +are discovered; with JEI installed, the special writing guides should appear. + +The automated Book Binder output-award scenario stalls in the GameTest storage +runner, so it is intentionally omitted under the project test policy. For its +manual check, open a ready Binder, observe that merely previewing the finished +book does not award *A Book of Ages*, then take the book and confirm the award. +Repeat by shift-clicking the result in a fresh Binder. diff --git a/gradle.properties b/gradle.properties index f985fc6..459446b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -36,7 +36,7 @@ mod_name=Rivencraft # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0-or-later # The mod version. Rivencraft uses the x.y.z.b policy documented in README.md. -mod_version=0.6.5.2 +mod_version=0.6.6.0 immersive_portals_version=6.0.7 terrablender_version=4.1.0.8 serene_seasons_version_id=B6nTjh4b diff --git a/src/main/java/net/dnorberg/rivencraft/advancement/ProgressionAdvancements.java b/src/main/java/net/dnorberg/rivencraft/advancement/ProgressionAdvancements.java new file mode 100644 index 0000000..40138d5 --- /dev/null +++ b/src/main/java/net/dnorberg/rivencraft/advancement/ProgressionAdvancements.java @@ -0,0 +1,30 @@ +package net.dnorberg.rivencraft.advancement; + +import net.dnorberg.rivencraft.Rivencraft; +import net.dnorberg.rivencraft.book.AgeRegistrySavedData; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; + +/** Awards action-only progression after the server has committed the action. */ +public final class ProgressionAdvancements { + public static final String LINK_PANEL = "link_panel"; + public static final String COPY_PAGE = "copy_page"; + public static final String BIND_AGE = "bind_age"; + public static final String OPEN_PORTAL = "open_portal"; + public static final String ENTER_AGE = "enter_age"; + + private ProgressionAdvancements() {} + + public static void award(ServerPlayer player, String path) { + var advancement = player.getServer().getAdvancements().get( + ResourceLocation.fromNamespaceAndPath(Rivencraft.MOD_ID, "progression/" + path)); + if (advancement != null) player.getAdvancements().award(advancement, "completed"); + } + + public static void awardAgeTravel(ServerPlayer player) { + if (AgeRegistrySavedData.get(player.serverLevel()).findByDimension( + player.serverLevel().dimension().location()).isPresent()) { + award(player, ENTER_AGE); + } + } +} diff --git a/src/main/java/net/dnorberg/rivencraft/block/BookReceptacleBlock.java b/src/main/java/net/dnorberg/rivencraft/block/BookReceptacleBlock.java index 48f6af4..c99842c 100644 --- a/src/main/java/net/dnorberg/rivencraft/block/BookReceptacleBlock.java +++ b/src/main/java/net/dnorberg/rivencraft/block/BookReceptacleBlock.java @@ -1,5 +1,6 @@ package net.dnorberg.rivencraft.block; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; import com.mojang.serialization.MapCodec; import net.dnorberg.rivencraft.block.entity.BookReceptacleBlockEntity; import net.dnorberg.rivencraft.portal.CrystalPortalNetwork; @@ -117,6 +118,8 @@ public final class BookReceptacleBlock extends BaseEntityBlock { server, pos, plan, destination)); } level.playSound(null, pos, SoundEvents.ENCHANTMENT_TABLE_USE, SoundSource.BLOCKS, 1, 1); + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.OPEN_PORTAL); return ItemInteractionResult.SUCCESS; } diff --git a/src/main/java/net/dnorberg/rivencraft/gametest/Milestone7AdvancementGameTests.java b/src/main/java/net/dnorberg/rivencraft/gametest/Milestone7AdvancementGameTests.java new file mode 100644 index 0000000..2bb8861 --- /dev/null +++ b/src/main/java/net/dnorberg/rivencraft/gametest/Milestone7AdvancementGameTests.java @@ -0,0 +1,122 @@ +package net.dnorberg.rivencraft.gametest; + +import java.util.List; +import net.dnorberg.rivencraft.Rivencraft; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; +import net.dnorberg.rivencraft.block.entity.InkMixerBlockEntity; +import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity; +import net.dnorberg.rivencraft.item.PageItem; +import net.dnorberg.rivencraft.menu.InkMixerMenu; +import net.dnorberg.rivencraft.menu.WritingDeskMenu; +import net.dnorberg.rivencraft.registry.ModBlocks; +import net.dnorberg.rivencraft.registry.ModItems; +import net.dnorberg.rivencraft.writing.SymbolReference; +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.neoforged.neoforge.gametest.GameTestHolder; +import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; + +@GameTestHolder(Rivencraft.MOD_ID) +@PrefixGameTestTemplate(false) +public final class Milestone7AdvancementGameTests { + private Milestone7AdvancementGameTests() {} + + @GameTest(template = "empty") + public static void progressionAndRecipeUnlocksLoad(GameTestHelper helper) { + var registry = helper.getLevel().getServer().getAdvancements(); + for (String path : List.of("root", "page", "linking_book", "link_panel", + "copy_page", "bind_age", "enter_age", "open_portal")) { + helper.assertTrue(registry.get(id("progression/" + path)) != null, + "Progression advancement must load: " + path); + } + for (String path : List.of("book_binder", "book_receptacle", "crystal_block", + "ink_mixer", "ink_vial", "notebook", "writing_desk")) { + helper.assertTrue(registry.get(id("recipes/misc/" + path)) != null, + "Recipe-book unlock must load: " + path); + } + var player = helper.makeMockServerPlayerInLevel(); + for (String path : List.of("book_binder", "ink_mixer", "notebook", "writing_desk")) { + player.getAdvancements().award(registry.get(id("recipes/misc/" + path)), "has_material"); + helper.assertTrue(player.getRecipeBook().contains(id(path)), + "Discovering the material must unlock the " + path + " recipe"); + } + helper.succeed(); + } + + @GameTest(template = "empty") + public static void actionAwardsAreServerOwnedAndPerPlayer(GameTestHelper helper) { + var first = helper.makeMockServerPlayerInLevel(); + var second = helper.makeMockServerPlayerInLevel(); + var advancement = helper.getLevel().getServer().getAdvancements().get(id("progression/copy_page")); + helper.assertFalse(first.getAdvancements().getOrStartProgress(advancement).isDone(), + "Opening a menu or preview must not award a copied Page"); + helper.assertFalse(second.getAdvancements().getOrStartProgress(advancement).isDone(), + "Another player must not inherit the advancement"); + ProgressionAdvancements.awardAgeTravel(first); + var travel = helper.getLevel().getServer().getAdvancements().get(id("progression/enter_age")); + helper.assertFalse(first.getAdvancements().getOrStartProgress(travel).isDone(), + "Overworld travel or a preview must not count as entering an Age"); + ProgressionAdvancements.award(first, ProgressionAdvancements.COPY_PAGE); + helper.assertTrue(first.getAdvancements().getOrStartProgress(advancement).isDone(), + "The server must award the player who completed the action"); + helper.assertFalse(second.getAdvancements().getOrStartProgress(advancement).isDone(), + "Advancement progress must remain per-player in multiplayer"); + helper.succeed(); + } + + @GameTest(template = "empty") + public static void mixerPreviewDoesNotAwardButTakingPanelDoes(GameTestHelper helper) { + BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1)); + helper.getLevel().setBlock(pos, ModBlocks.INK_MIXER.get().defaultBlockState(), 3); + var mixer = (InkMixerBlockEntity) helper.getLevel().getBlockEntity(pos); + mixer.setItem(InkMixerBlockEntity.PAPER, new ItemStack(Items.PAPER)); + mixer.setItem(InkMixerBlockEntity.INK, new ItemStack(ModItems.INK_VIAL.get())); + var player = nearbyPlayer(helper, pos); + var menu = new InkMixerMenu(1, player.getInventory(), mixer); + helper.assertFalse(done(player, ProgressionAdvancements.LINK_PANEL), + "Opening the Ink Mixer must not award its milestone"); + menu.clicked(InkMixerMenu.RESULT, 0, ClickType.PICKUP, player); + helper.assertTrue(done(player, ProgressionAdvancements.LINK_PANEL), + "Taking the completed Link Panel must award its milestone"); + helper.succeed(); + } + + @GameTest(template = "empty") + public static void deskPreviewDoesNotAwardButCopyingDoes(GameTestHelper helper) { + BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1)); + helper.getLevel().setBlock(pos, ModBlocks.WRITING_DESK.get().defaultBlockState(), 3); + var desk = (WritingDeskBlockEntity) helper.getLevel().getBlockEntity(pos); + desk.setItem(0, PageItem.createSymbolPage(new SymbolReference(id("terrain/standard")))); + desk.setItem(WritingDeskBlockEntity.PAPER, new ItemStack(Items.PAPER)); + desk.setItem(WritingDeskBlockEntity.INK, new ItemStack(ModItems.INK_VIAL.get())); + var player = nearbyPlayer(helper, pos); + var menu = new WritingDeskMenu(1, player.getInventory(), desk); + helper.assertFalse(done(player, ProgressionAdvancements.COPY_PAGE), + "Opening the Writing Desk must not award a copied Page"); + menu.clicked(WritingDeskMenu.COPY_RESULT, 0, ClickType.PICKUP, player); + helper.assertTrue(done(player, ProgressionAdvancements.COPY_PAGE), + "Taking a copied Page must award its milestone"); + helper.succeed(); + } + + private static ServerPlayer nearbyPlayer(GameTestHelper helper, BlockPos pos) { + var player = helper.makeMockServerPlayerInLevel(); + player.moveTo(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + return player; + } + + private static boolean done(ServerPlayer player, String path) { + var advancement = player.getServer().getAdvancements().get(id("progression/" + path)); + return player.getAdvancements().getOrStartProgress(advancement).isDone(); + } + + private static ResourceLocation id(String path) { + return ResourceLocation.fromNamespaceAndPath(Rivencraft.MOD_ID, path); + } +} diff --git a/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java b/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java index 74a38f1..9273fef 100644 --- a/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java +++ b/src/main/java/net/dnorberg/rivencraft/item/DescriptiveBookItem.java @@ -1,5 +1,6 @@ package net.dnorberg.rivencraft.item; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; import java.util.List; import net.dnorberg.rivencraft.book.AgeReference; import net.dnorberg.rivencraft.book.AgeVisitSavedData; @@ -86,6 +87,7 @@ public final class DescriptiveBookItem extends Item { } } LinkVisualEffects.play(sourceLevel, sourcePosition, player, properties, portal); + ProgressionAdvancements.awardAgeTravel(player); player.displayClientMessage(Component.translatable( createReturnLink ? "message.rivencraft.descriptive_book.linked_first" : "message.rivencraft.descriptive_book.linked", age.name() diff --git a/src/main/java/net/dnorberg/rivencraft/item/LinkingBookItem.java b/src/main/java/net/dnorberg/rivencraft/item/LinkingBookItem.java index 0a13ca5..f408ee9 100644 --- a/src/main/java/net/dnorberg/rivencraft/item/LinkingBookItem.java +++ b/src/main/java/net/dnorberg/rivencraft/item/LinkingBookItem.java @@ -1,5 +1,6 @@ package net.dnorberg.rivencraft.item; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; import java.util.List; import net.dnorberg.rivencraft.book.LinkTarget; import net.dnorberg.rivencraft.book.AgeRegistrySavedData; @@ -64,6 +65,7 @@ public final class LinkingBookItem extends Item { : LinkingService.travel(player, target, properties); if (result == LinkingService.LinkResult.SUCCESS) { LinkVisualEffects.play(sourceLevel, sourcePosition, player, properties, portal); + ProgressionAdvancements.awardAgeTravel(player); player.displayClientMessage(Component.translatable("message.rivencraft.linking_book.linked"), true); return InteractionResultHolder.success(stack); } diff --git a/src/main/java/net/dnorberg/rivencraft/menu/BookBinderMenu.java b/src/main/java/net/dnorberg/rivencraft/menu/BookBinderMenu.java index 473f635..b5cd228 100644 --- a/src/main/java/net/dnorberg/rivencraft/menu/BookBinderMenu.java +++ b/src/main/java/net/dnorberg/rivencraft/menu/BookBinderMenu.java @@ -1,5 +1,6 @@ package net.dnorberg.rivencraft.menu; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; import java.util.Optional; import net.dnorberg.rivencraft.block.entity.BookBinderBlockEntity; import net.dnorberg.rivencraft.item.PageItem; @@ -9,6 +10,7 @@ import net.dnorberg.rivencraft.registry.ModMenus; import net.dnorberg.rivencraft.writing.PageContent; import net.dnorberg.rivencraft.writing.WritingGrammar; import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; @@ -210,7 +212,9 @@ public final class BookBinderMenu extends AbstractContainerMenu { if (!moveItemStackTo(remainder, PLAYER_START, slots.size(), true) || !remainder.isEmpty()) { return ItemStack.EMPTY; } - binder.consumeAssembly(); + if (!binder.consumeAssembly()) return ItemStack.EMPTY; + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.BIND_AGE); refreshResult(); return book; } @@ -284,7 +288,11 @@ public final class BookBinderMenu extends AbstractContainerMenu { return clientSide ? hasItem() : stillValid(player) && binder.canAssemble(); } @Override public void onTake(Player player, ItemStack stack) { - if (!clientSide && binder.consumeAssembly()) refreshResult(); + if (!clientSide && binder.consumeAssembly()) { + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.BIND_AGE); + refreshResult(); + } super.onTake(player, stack); } } diff --git a/src/main/java/net/dnorberg/rivencraft/menu/InkMixerMenu.java b/src/main/java/net/dnorberg/rivencraft/menu/InkMixerMenu.java index c99eb6f..7f92dcf 100644 --- a/src/main/java/net/dnorberg/rivencraft/menu/InkMixerMenu.java +++ b/src/main/java/net/dnorberg/rivencraft/menu/InkMixerMenu.java @@ -1,10 +1,12 @@ package net.dnorberg.rivencraft.menu; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; import net.dnorberg.rivencraft.block.entity.InkMixerBlockEntity; import net.dnorberg.rivencraft.item.PageItem; import net.dnorberg.rivencraft.registry.ModItems; import net.dnorberg.rivencraft.registry.ModMenus; import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; @@ -109,6 +111,8 @@ public final class InkMixerMenu extends AbstractContainerMenu { if (!moveItemStackTo(remainder, PLAYER_START, slots.size(), true) || !remainder.isEmpty()) return ItemStack.EMPTY; if (!mixer.consumeLinkPanelMaterials()) return ItemStack.EMPTY; + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.LINK_PANEL); refreshResult(); return output; } @@ -148,7 +152,11 @@ public final class InkMixerMenu extends AbstractContainerMenu { return clientSide ? hasItem() : stillValid(player) && mixer.canCreateLinkPanel(); } @Override public void onTake(Player player, ItemStack stack) { - if (!clientSide && mixer.consumeLinkPanelMaterials()) refreshResult(); + if (!clientSide && mixer.consumeLinkPanelMaterials()) { + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.LINK_PANEL); + refreshResult(); + } super.onTake(player, stack); } } diff --git a/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java b/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java index e717c64..1513dd4 100644 --- a/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java +++ b/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java @@ -1,5 +1,6 @@ package net.dnorberg.rivencraft.menu; +import net.dnorberg.rivencraft.advancement.ProgressionAdvancements; import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity; import net.dnorberg.rivencraft.item.PageItem; import net.dnorberg.rivencraft.registry.ModDataComponents; @@ -317,7 +318,9 @@ public final class WritingDeskMenu extends AbstractContainerMenu { if (!moveItemStackTo(movingCopy, PLAYER_START, slots.size(), true) || !movingCopy.isEmpty()) { return ItemStack.EMPTY; } - blockEntity.consumeCopyMaterials(); + if (!blockEntity.consumeCopyMaterials()) return ItemStack.EMPTY; + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.COPY_PAGE); refreshOutput(); return copy; } @@ -434,7 +437,11 @@ public final class WritingDeskMenu extends AbstractContainerMenu { return clientSide ? hasItem() : WritingDeskMenu.this.stillValid(player) && canCopy(); } @Override public void onTake(Player player, ItemStack stack) { - if (!clientSide && blockEntity.consumeCopyMaterials()) refreshOutput(); + if (!clientSide && blockEntity.consumeCopyMaterials()) { + if (player instanceof ServerPlayer serverPlayer) + ProgressionAdvancements.award(serverPlayer, ProgressionAdvancements.COPY_PAGE); + refreshOutput(); + } super.onTake(player, stack); } } diff --git a/src/main/resources/assets/rivencraft/lang/en_us.json b/src/main/resources/assets/rivencraft/lang/en_us.json index b327d53..be375c5 100644 --- a/src/main/resources/assets/rivencraft/lang/en_us.json +++ b/src/main/resources/assets/rivencraft/lang/en_us.json @@ -369,5 +369,21 @@ "symbol.rivencraft.corrupted.medium": "Corrupted Page", "symbol.rivencraft.corrupted.medium.description": "The writing shifts beyond comprehension.", "symbol.rivencraft.corrupted.small": "Corrupted Page", - "symbol.rivencraft.corrupted.small.description": "The writing shifts beyond comprehension." + "symbol.rivencraft.corrupted.small.description": "The writing shifts beyond comprehension.", + "advancement.rivencraft.root.title": "The Ending Has Not Yet Been Written", + "advancement.rivencraft.root.description": "Begin the Art of writing and linking Ages.", + "advancement.rivencraft.page.title": "A Strange Page", + "advancement.rivencraft.page.description": "Find a Page marked with the language of Ages.", + "advancement.rivencraft.linking_book.title": "A Way Back", + "advancement.rivencraft.linking_book.description": "Obtain a Linking Book and remember where you came from.", + "advancement.rivencraft.link_panel.title": "D'ni Ink", + "advancement.rivencraft.link_panel.description": "Create a Link Panel at the Ink Mixer.", + "advancement.rivencraft.copy_page.title": "The Art of Writing", + "advancement.rivencraft.copy_page.description": "Copy a Page at the Writing Desk.", + "advancement.rivencraft.bind_age.title": "A Book of Ages", + "advancement.rivencraft.bind_age.description": "Bind a completed Descriptive Book.", + "advancement.rivencraft.enter_age.title": "The Journey Begins", + "advancement.rivencraft.enter_age.description": "Safely link into an Age you have written.", + "advancement.rivencraft.open_portal.title": "A Window Between Ages", + "advancement.rivencraft.open_portal.description": "Activate a Crystal Portal with a bound book." } diff --git a/src/main/resources/data/rivencraft/advancement/progression/bind_age.json b/src/main/resources/data/rivencraft/advancement/progression/bind_age.json new file mode 100644 index 0000000..24f2a52 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/bind_age.json @@ -0,0 +1,19 @@ +{ + "parent": "rivencraft:progression/link_panel", + "display": { + "icon": { + "id": "rivencraft:descriptive_book" + }, + "title": { + "translate": "advancement.rivencraft.bind_age.title" + }, + "description": { + "translate": "advancement.rivencraft.bind_age.description" + } + }, + "criteria": { + "completed": { + "trigger": "minecraft:impossible" + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/copy_page.json b/src/main/resources/data/rivencraft/advancement/progression/copy_page.json new file mode 100644 index 0000000..e3333bf --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/copy_page.json @@ -0,0 +1,19 @@ +{ + "parent": "rivencraft:progression/page", + "display": { + "icon": { + "id": "rivencraft:writing_desk" + }, + "title": { + "translate": "advancement.rivencraft.copy_page.title" + }, + "description": { + "translate": "advancement.rivencraft.copy_page.description" + } + }, + "criteria": { + "completed": { + "trigger": "minecraft:impossible" + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/enter_age.json b/src/main/resources/data/rivencraft/advancement/progression/enter_age.json new file mode 100644 index 0000000..7dc2773 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/enter_age.json @@ -0,0 +1,20 @@ +{ + "parent": "rivencraft:progression/bind_age", + "display": { + "icon": { + "id": "rivencraft:descriptive_book" + }, + "title": { + "translate": "advancement.rivencraft.enter_age.title" + }, + "description": { + "translate": "advancement.rivencraft.enter_age.description" + }, + "frame": "goal" + }, + "criteria": { + "completed": { + "trigger": "minecraft:impossible" + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/link_panel.json b/src/main/resources/data/rivencraft/advancement/progression/link_panel.json new file mode 100644 index 0000000..169df9b --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/link_panel.json @@ -0,0 +1,19 @@ +{ + "parent": "rivencraft:progression/root", + "display": { + "icon": { + "id": "rivencraft:ink_mixer" + }, + "title": { + "translate": "advancement.rivencraft.link_panel.title" + }, + "description": { + "translate": "advancement.rivencraft.link_panel.description" + } + }, + "criteria": { + "completed": { + "trigger": "minecraft:impossible" + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/linking_book.json b/src/main/resources/data/rivencraft/advancement/progression/linking_book.json new file mode 100644 index 0000000..627de47 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/linking_book.json @@ -0,0 +1,26 @@ +{ + "parent": "rivencraft:progression/root", + "display": { + "icon": { + "id": "rivencraft:linking_book" + }, + "title": { + "translate": "advancement.rivencraft.linking_book.title" + }, + "description": { + "translate": "advancement.rivencraft.linking_book.description" + } + }, + "criteria": { + "completed": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "rivencraft:linking_book" + } + ] + } + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/open_portal.json b/src/main/resources/data/rivencraft/advancement/progression/open_portal.json new file mode 100644 index 0000000..b0fde44 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/open_portal.json @@ -0,0 +1,20 @@ +{ + "parent": "rivencraft:progression/linking_book", + "display": { + "icon": { + "id": "rivencraft:book_receptacle" + }, + "title": { + "translate": "advancement.rivencraft.open_portal.title" + }, + "description": { + "translate": "advancement.rivencraft.open_portal.description" + }, + "frame": "goal" + }, + "criteria": { + "completed": { + "trigger": "minecraft:impossible" + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/page.json b/src/main/resources/data/rivencraft/advancement/progression/page.json new file mode 100644 index 0000000..a6a5ffd --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/page.json @@ -0,0 +1,26 @@ +{ + "parent": "rivencraft:progression/root", + "display": { + "icon": { + "id": "rivencraft:page" + }, + "title": { + "translate": "advancement.rivencraft.page.title" + }, + "description": { + "translate": "advancement.rivencraft.page.description" + } + }, + "criteria": { + "completed": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "rivencraft:page" + } + ] + } + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/progression/root.json b/src/main/resources/data/rivencraft/advancement/progression/root.json new file mode 100644 index 0000000..43c3685 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/progression/root.json @@ -0,0 +1,21 @@ +{ + "display": { + "icon": { + "id": "rivencraft:descriptive_book" + }, + "title": { + "translate": "advancement.rivencraft.root.title" + }, + "description": { + "translate": "advancement.rivencraft.root.description" + }, + "background": "minecraft:textures/gui/advancements/backgrounds/stone.png", + "show_toast": false, + "announce_to_chat": false + }, + "criteria": { + "completed": { + "trigger": "minecraft:tick" + } + } +} diff --git a/src/main/resources/data/rivencraft/advancement/recipes/misc/book_binder.json b/src/main/resources/data/rivencraft/advancement/recipes/misc/book_binder.json new file mode 100644 index 0000000..b26e592 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/recipes/misc/book_binder.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_material": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:iron_ingot" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "rivencraft:book_binder" + } + } + }, + "requirements": [ + [ + "has_material", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "rivencraft:book_binder" + ] + } +} diff --git a/src/main/resources/data/rivencraft/advancement/recipes/misc/ink_mixer.json b/src/main/resources/data/rivencraft/advancement/recipes/misc/ink_mixer.json new file mode 100644 index 0000000..1ae0362 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/recipes/misc/ink_mixer.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_material": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:glass_bottle" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "rivencraft:ink_mixer" + } + } + }, + "requirements": [ + [ + "has_material", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "rivencraft:ink_mixer" + ] + } +} diff --git a/src/main/resources/data/rivencraft/advancement/recipes/misc/notebook.json b/src/main/resources/data/rivencraft/advancement/recipes/misc/notebook.json new file mode 100644 index 0000000..c1d00f8 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/recipes/misc/notebook.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_material": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:leather" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "rivencraft:notebook" + } + } + }, + "requirements": [ + [ + "has_material", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "rivencraft:notebook" + ] + } +} diff --git a/src/main/resources/data/rivencraft/advancement/recipes/misc/writing_desk.json b/src/main/resources/data/rivencraft/advancement/recipes/misc/writing_desk.json new file mode 100644 index 0000000..14e6292 --- /dev/null +++ b/src/main/resources/data/rivencraft/advancement/recipes/misc/writing_desk.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_material": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:feather" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "rivencraft:writing_desk" + } + } + }, + "requirements": [ + [ + "has_material", + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "rivencraft:writing_desk" + ] + } +}