Public Access
This commit is contained in:
1 parent
1ff62e9aaa
commit
c39ebd78ba
23 files changed
+543
-7
No files matched your search
@@ -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.
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user