Public Access
This commit is contained in:
1 parent
8246640f49
commit
114a6ee21e
19 files changed
+251
-111
No files matched your search
@@ -195,26 +195,19 @@ public final class BookBinderBlockEntity extends BlockEntity implements Containe
|
||||
if (pages.isEmpty()) return ItemStack.EMPTY;
|
||||
int end = nextPageIndex();
|
||||
if (index < 0 || index > end) return ItemStack.EMPTY;
|
||||
boolean link = false;
|
||||
ItemStack linkPanel = ItemStack.EMPTY;
|
||||
List<ItemStack> writing = new ArrayList<>();
|
||||
for (ItemStack page : pages) {
|
||||
if (page.isEmpty()) continue;
|
||||
if (!page.is(ModItems.PAGE.get()) || page.getCount() != 1) return ItemStack.EMPTY;
|
||||
if (PageItem.content(page).kind() == PageContent.Kind.LINK_PANEL) {
|
||||
if (link || !items.get(LINK_PANEL).isEmpty()) return ItemStack.EMPTY;
|
||||
link = true;
|
||||
if (!linkPanel.isEmpty() || !items.get(LINK_PANEL).isEmpty()) return ItemStack.EMPTY;
|
||||
linkPanel = page;
|
||||
} else if (validPage(page)) writing.add(page);
|
||||
else return ItemStack.EMPTY;
|
||||
}
|
||||
if (end + writing.size() > PAGE_COUNT || writing.isEmpty() && !link) return ItemStack.EMPTY;
|
||||
if (link) {
|
||||
for (ItemStack page : pages) {
|
||||
if (!page.isEmpty() && PageItem.content(page).kind() == PageContent.Kind.LINK_PANEL) {
|
||||
items.set(LINK_PANEL, page.copy());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (end + writing.size() > PAGE_COUNT || writing.isEmpty() && linkPanel.isEmpty()) return ItemStack.EMPTY;
|
||||
if (!linkPanel.isEmpty()) items.set(LINK_PANEL, linkPanel.copy());
|
||||
for (int current = end - 1; current >= index; current--)
|
||||
items.set(FIRST_PAGE + current + writing.size(), items.get(FIRST_PAGE + current));
|
||||
for (ItemStack page : writing) items.set(FIRST_PAGE + index++, page.copy());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.dnorberg.rivencraft.block.entity;
|
||||
|
||||
import net.dnorberg.rivencraft.item.InkVialItem;
|
||||
import net.dnorberg.rivencraft.writing.InkVialExchange;
|
||||
import net.dnorberg.rivencraft.registry.ModBlockEntities;
|
||||
import net.dnorberg.rivencraft.registry.ModItems;
|
||||
import net.dnorberg.rivencraft.writing.WritingInkService;
|
||||
@@ -64,35 +65,21 @@ public final class InkMixerBlockEntity extends BlockEntity implements Container
|
||||
worldPosition.getZ() + 0.5) <= 64.0;
|
||||
}
|
||||
|
||||
private boolean hasBottleSpace() {
|
||||
ItemStack bottles = items.get(BOTTLES);
|
||||
return bottles.isEmpty() || bottles.is(Items.GLASS_BOTTLE)
|
||||
&& bottles.getCount() < bottles.getMaxStackSize();
|
||||
}
|
||||
|
||||
/** No server tick: refill only when ink, bottle space, or consumption changes. */
|
||||
private void refillEmptyBasin() {
|
||||
if (level == null || level.isClientSide || inkRemaining != 0 || !hasBottleSpace()) return;
|
||||
ItemStack vial = items.get(INK);
|
||||
if (!vial.is(ModItems.INK_VIAL.get())) return;
|
||||
int amount = Math.clamp(InkVialItem.remaining(vial), 0, InkVialItem.CAPACITY);
|
||||
if (amount == 0) return;
|
||||
inkRemaining = amount;
|
||||
vial.shrink(1);
|
||||
if (vial.isEmpty()) items.set(INK, ItemStack.EMPTY);
|
||||
ItemStack bottles = items.get(BOTTLES);
|
||||
if (bottles.isEmpty()) items.set(BOTTLES, new ItemStack(Items.GLASS_BOTTLE));
|
||||
else bottles.grow(1);
|
||||
setChanged();
|
||||
if (level != null && !level.isClientSide && inkRemaining == 0) {
|
||||
int addedInk = InkVialExchange.exchange(items, INK, BOTTLES);
|
||||
if (addedInk > 0) {
|
||||
inkRemaining = addedInk;
|
||||
setChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canCreateLinkPanel() {
|
||||
if (!items.get(PAPER).is(Items.PAPER)) return false;
|
||||
int cost = WritingInkService.linkPanelCost();
|
||||
if (inkRemaining >= cost) return true;
|
||||
ItemStack vial = items.get(INK);
|
||||
return vial.is(ModItems.INK_VIAL.get()) && hasBottleSpace()
|
||||
&& inkRemaining + InkVialItem.remaining(vial) >= cost;
|
||||
return InkVialExchange.canPay(items, INK, BOTTLES, inkRemaining, cost);
|
||||
}
|
||||
|
||||
/** Commit inputs only when a virtual output is actually taken. */
|
||||
@@ -100,13 +87,7 @@ public final class InkMixerBlockEntity extends BlockEntity implements Container
|
||||
if (!canCreateLinkPanel()) return false;
|
||||
int cost = WritingInkService.linkPanelCost();
|
||||
if (inkRemaining < cost) {
|
||||
ItemStack vial = items.get(INK);
|
||||
inkRemaining += Math.clamp(InkVialItem.remaining(vial), 0, InkVialItem.CAPACITY);
|
||||
vial.shrink(1);
|
||||
if (vial.isEmpty()) items.set(INK, ItemStack.EMPTY);
|
||||
ItemStack bottles = items.get(BOTTLES);
|
||||
if (bottles.isEmpty()) items.set(BOTTLES, new ItemStack(Items.GLASS_BOTTLE));
|
||||
else bottles.grow(1);
|
||||
inkRemaining += InkVialExchange.exchange(items, INK, BOTTLES);
|
||||
}
|
||||
inkRemaining -= cost;
|
||||
items.get(PAPER).shrink(1);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.dnorberg.rivencraft.block.entity;
|
||||
|
||||
import net.dnorberg.rivencraft.item.InkVialItem;
|
||||
import net.dnorberg.rivencraft.writing.InkVialExchange;
|
||||
import net.dnorberg.rivencraft.writing.WritingInkService;
|
||||
import net.dnorberg.rivencraft.registry.ModBlockEntities;
|
||||
import net.dnorberg.rivencraft.registry.ModItems;
|
||||
@@ -92,26 +93,15 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain
|
||||
};
|
||||
}
|
||||
|
||||
private boolean hasBottleSpace() {
|
||||
ItemStack returned = items.get(RETURN);
|
||||
return returned.isEmpty() || returned.is(Items.GLASS_BOTTLE)
|
||||
&& returned.getCount() < returned.getMaxStackSize();
|
||||
}
|
||||
|
||||
/** Consume one vial only when the empty meter can return its glass bottle. */
|
||||
private void refillEmptyInkBar() {
|
||||
if (level == null || level.isClientSide || inkRemaining != 0 || !hasBottleSpace()) return;
|
||||
ItemStack vial = items.get(INK);
|
||||
if (!vial.is(ModItems.INK_VIAL.get())) return;
|
||||
int ink = Math.clamp(InkVialItem.remaining(vial), 0, InkVialItem.CAPACITY);
|
||||
if (ink == 0) return;
|
||||
inkRemaining = ink;
|
||||
vial.shrink(1);
|
||||
if (vial.isEmpty()) items.set(INK, ItemStack.EMPTY);
|
||||
ItemStack returned = items.get(RETURN);
|
||||
if (returned.isEmpty()) items.set(RETURN, new ItemStack(Items.GLASS_BOTTLE));
|
||||
else returned.grow(1);
|
||||
setChanged();
|
||||
if (level != null && !level.isClientSide && inkRemaining == 0) {
|
||||
int addedInk = InkVialExchange.exchange(items, INK, RETURN);
|
||||
if (addedInk > 0) {
|
||||
inkRemaining = addedInk;
|
||||
setChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The output is virtual; inputs are committed only after a result can be given to a player. */
|
||||
@@ -119,23 +109,14 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain
|
||||
ItemStack paper = items.get(PAPER);
|
||||
if (!canPlaceItem(PAPER, paper) || paper.isEmpty()) return false;
|
||||
int cost = WritingInkService.symbolCopyCost();
|
||||
if (inkRemaining >= cost) return true;
|
||||
ItemStack vial = items.get(INK);
|
||||
return vial.is(ModItems.INK_VIAL.get()) && inkRemaining + InkVialItem.remaining(vial) >= cost
|
||||
&& hasBottleSpace();
|
||||
return InkVialExchange.canPay(items, INK, RETURN, inkRemaining, cost);
|
||||
}
|
||||
|
||||
public boolean consumeCopyMaterials() {
|
||||
if (!canConsumeCopyMaterials()) return false;
|
||||
int cost = WritingInkService.symbolCopyCost();
|
||||
if (inkRemaining < cost) {
|
||||
ItemStack vial = items.get(INK);
|
||||
inkRemaining += Math.clamp(InkVialItem.remaining(vial), 0, InkVialItem.CAPACITY);
|
||||
vial.shrink(1);
|
||||
if (vial.isEmpty()) items.set(INK, ItemStack.EMPTY);
|
||||
ItemStack returned = items.get(RETURN);
|
||||
if (returned.isEmpty()) items.set(RETURN, new ItemStack(Items.GLASS_BOTTLE));
|
||||
else returned.grow(1);
|
||||
inkRemaining += InkVialExchange.exchange(items, INK, RETURN);
|
||||
}
|
||||
inkRemaining -= cost;
|
||||
removeItem(PAPER, 1);
|
||||
@@ -148,7 +129,6 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain
|
||||
refillEmptyInkBar();
|
||||
}
|
||||
@Override public void clearContent() {
|
||||
items.clear();
|
||||
items = NonNullList.withSize(SIZE, ItemStack.EMPTY);
|
||||
inkRemaining = 0;
|
||||
displayPage = ItemStack.EMPTY;
|
||||
|
||||
@@ -28,7 +28,7 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@GameTestHolder("rivencraft_archive_binder")
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class BookBinderGameTests {
|
||||
private BookBinderGameTests() {}
|
||||
@@ -74,7 +74,6 @@ public final class BookBinderGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void missingSymbolPageSurvivesReloadButCannotBeAssembled(GameTestHelper helper) {
|
||||
BookBinderBlockEntity binder = place(helper);
|
||||
binder.setTitle("Recoverable Writing");
|
||||
@@ -93,7 +92,6 @@ public final class BookBinderGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void assemblyIsAtomicAndRetainsPageOrder(GameTestHelper helper) {
|
||||
BookBinderBlockEntity binder = place(helper);
|
||||
binder.setTitle("A New Age");
|
||||
@@ -256,7 +254,6 @@ public final class BookBinderGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void forgedBinderActionsAndReplayedOutputCannotDuplicateBook(GameTestHelper helper) {
|
||||
BookBinderBlockEntity binder = place(helper);
|
||||
binder.setTitle("Single Assembly");
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package net.dnorberg.rivencraft.gametest;
|
||||
|
||||
import net.dnorberg.rivencraft.Rivencraft;
|
||||
import net.minecraft.gametest.framework.GameTest;
|
||||
import net.minecraft.gametest.framework.GameTestHelper;
|
||||
import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
/** Small default smoke suite; the detailed milestone regressions are opt-in. */
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class CoreGameTests {
|
||||
private CoreGameTests() {}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void previewBackendSelection(GameTestHelper helper) {
|
||||
LinkingGameTests.previewBackendSelectionCoversOptionalDependencyMatrix(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void linkTargetPersistence(GameTestHelper helper) {
|
||||
LinkingGameTests.linkTargetSurvivesItemSerialization(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void deterministicAgeDefinition(GameTestHelper helper) {
|
||||
LinkingGameTests.ageDefinitionIsCreatedOnceWithDeterministicData(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void blockedLinkDestination(GameTestHelper helper) {
|
||||
LinkingGameTests.travelRejectsBlockedDestination(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void legacyWritingAndPageFreeBooks(GameTestHelper helper) {
|
||||
WritingDataGameTests.oldBareListWritingAndPageFreeBooksRemainReadable(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void pagePersistenceAndUnknownSymbols(GameTestHelper helper) {
|
||||
WritingDataGameTests.pageItemPreservesContentAndRejectsForgedUnknownSymbols(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void notebookPersistence(GameTestHelper helper) {
|
||||
WritingDataGameTests.notebookContentsPreserveOrderGapsNamesAndUnknownPages(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void deskCopyTransaction(GameTestHelper helper) {
|
||||
WritingDeskGameTests.takingCopySpendsPaperAndOneInkThenReturnsGlassBottle(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void deskRejectsForgedAndStaleActions(GameTestHelper helper) {
|
||||
WritingDeskGameTests.forgedDeskSelectionsAndStaleMenuCannotCopy(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void twoBlockDeskDropsOnce(GameTestHelper helper) {
|
||||
WritingDeskGameTests.twoBlockDeskSharesOneInventoryAndBreaksTogether(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void oldDeskMigration(GameTestHelper helper) {
|
||||
WritingDeskGameTests.oldDeskInventoryMigratesAndAll88TabsPersist(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void binderKeepsMissingSymbolsRecoverable(GameTestHelper helper) {
|
||||
BookBinderGameTests.missingSymbolPageSurvivesReloadButCannotBeAssembled(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void binderAssemblyTransaction(GameTestHelper helper) {
|
||||
BookBinderGameTests.assemblyIsAtomicAndRetainsPageOrder(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void binderRejectsForgedAndReplayedActions(GameTestHelper helper) {
|
||||
BookBinderGameTests.forgedBinderActionsAndReplayedOutputCannotDuplicateBook(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void mixerOutputTransaction(GameTestHelper helper) {
|
||||
InkMixerGameTests.linkPanelRequiresTakingOutputAndPersistsInk(helper);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void linkingBookRecipe(GameTestHelper helper) {
|
||||
LinkingBookRecipeGameTests.legacyRecipeRequiresExactlyLeatherAndLinkPanel(helper);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.dnorberg.rivencraft.gametest;
|
||||
|
||||
import net.dnorberg.rivencraft.Rivencraft;
|
||||
import net.dnorberg.rivencraft.block.entity.InkMixerBlockEntity;
|
||||
import net.dnorberg.rivencraft.menu.InkMixerMenu;
|
||||
import net.dnorberg.rivencraft.registry.ModBlocks;
|
||||
@@ -18,7 +17,7 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@GameTestHolder("rivencraft_archive_mixer")
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class InkMixerGameTests {
|
||||
private InkMixerGameTests() {}
|
||||
@@ -29,7 +28,6 @@ public final class InkMixerGameTests {
|
||||
return (InkMixerBlockEntity) helper.getLevel().getBlockEntity(pos);
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void linkPanelRequiresTakingOutputAndPersistsInk(GameTestHelper helper) {
|
||||
InkMixerBlockEntity mixer = place(helper);
|
||||
mixer.setItem(InkMixerBlockEntity.PAPER, new ItemStack(Items.PAPER, 2));
|
||||
|
||||
@@ -19,12 +19,11 @@ import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@GameTestHolder("rivencraft_archive_recipe")
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class LinkingBookRecipeGameTests {
|
||||
private LinkingBookRecipeGameTests() {}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void legacyRecipeRequiresExactlyLeatherAndLinkPanel(GameTestHelper helper) {
|
||||
LinkingBookRecipe recipe = new LinkingBookRecipe(CraftingBookCategory.MISC);
|
||||
ItemStack panel = PageItem.createLinkPanelPage();
|
||||
|
||||
@@ -34,7 +34,7 @@ import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
/** Server-side regression coverage for persistent linking-book data and travel safety. */
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@GameTestHolder("rivencraft_archive_linking")
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class LinkingGameTests {
|
||||
private static final BlockPos ORIGIN = new BlockPos(0, 1, 0);
|
||||
@@ -42,7 +42,6 @@ public final class LinkingGameTests {
|
||||
private LinkingGameTests() {
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void previewBackendSelectionCoversOptionalDependencyMatrix(GameTestHelper helper) {
|
||||
assertPreviewBackend(helper, RivencraftClientConfig.PreviewMode.AUTO, true, true,
|
||||
PreviewBackendSelector.Backend.IMMERSIVE_PORTALS);
|
||||
@@ -127,7 +126,6 @@ public final class LinkingGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void linkTargetSurvivesItemSerialization(GameTestHelper helper) {
|
||||
LinkTarget expected = new LinkTarget(
|
||||
GlobalPos.of(helper.getLevel().dimension(), helper.absolutePos(ORIGIN)),
|
||||
@@ -181,7 +179,6 @@ public final class LinkingGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void ageDefinitionIsCreatedOnceWithDeterministicData(GameTestHelper helper) {
|
||||
UUID ageId = UUID.randomUUID();
|
||||
String requestedName = "Test Age " + ageId;
|
||||
@@ -666,7 +663,6 @@ public final class LinkingGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void travelRejectsBlockedDestination(GameTestHelper helper) {
|
||||
BlockPos absoluteOrigin = helper.absolutePos(ORIGIN);
|
||||
for (BlockPos position : BlockPos.betweenClosed(
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.mojang.serialization.JsonOps;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.dnorberg.rivencraft.Rivencraft;
|
||||
import net.dnorberg.rivencraft.book.AgeReference;
|
||||
import net.dnorberg.rivencraft.writing.OrderedWriting;
|
||||
import net.dnorberg.rivencraft.writing.PageContent;
|
||||
@@ -31,7 +30,7 @@ import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
/** Acceptance coverage for Milestone 4's persistent writing contracts. */
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@GameTestHolder("rivencraft_archive_writing")
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class WritingDataGameTests {
|
||||
private WritingDataGameTests() {
|
||||
@@ -62,7 +61,6 @@ public final class WritingDataGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void oldBareListWritingAndPageFreeBooksRemainReadable(GameTestHelper helper) {
|
||||
OrderedWriting writing = new OrderedWriting(List.of(
|
||||
WritingEntry.linkPanel(), WritingEntry.symbol(reference("example:removed_symbol"))));
|
||||
@@ -126,7 +124,6 @@ public final class WritingDataGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void pageItemPreservesContentAndRejectsForgedUnknownSymbols(GameTestHelper helper) {
|
||||
SymbolReference known = reference("rivencraft:terrain/standard");
|
||||
SymbolReference unknown = reference("example:forged_symbol");
|
||||
@@ -156,7 +153,6 @@ public final class WritingDataGameTests {
|
||||
}
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void notebookContentsPreserveOrderGapsNamesAndUnknownPages(GameTestHelper helper) {
|
||||
ItemStack first = PageItem.createSymbolPage(reference("rivencraft:terrain/standard"));
|
||||
first.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.dnorberg.rivencraft.gametest;
|
||||
|
||||
import java.util.List;
|
||||
import net.dnorberg.rivencraft.Rivencraft;
|
||||
import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity;
|
||||
import net.dnorberg.rivencraft.block.WritingDeskBlock;
|
||||
import net.dnorberg.rivencraft.menu.WritingDeskMenu;
|
||||
@@ -26,7 +25,7 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.neoforged.neoforge.gametest.GameTestHolder;
|
||||
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
|
||||
|
||||
@GameTestHolder(Rivencraft.MOD_ID)
|
||||
@GameTestHolder("rivencraft_archive_desk")
|
||||
@PrefixGameTestTemplate(false)
|
||||
public final class WritingDeskGameTests {
|
||||
private WritingDeskGameTests() {}
|
||||
@@ -94,7 +93,6 @@ public final class WritingDeskGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void takingCopySpendsPaperAndOneInkThenReturnsGlassBottle(GameTestHelper helper) {
|
||||
BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1));
|
||||
helper.getLevel().setBlock(pos, ModBlocks.WRITING_DESK.get().defaultBlockState(), 3);
|
||||
@@ -256,7 +254,6 @@ public final class WritingDeskGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void forgedDeskSelectionsAndStaleMenuCannotCopy(GameTestHelper helper) {
|
||||
BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1));
|
||||
helper.getLevel().setBlock(pos, ModBlocks.WRITING_DESK.get().defaultBlockState(), 3);
|
||||
@@ -339,7 +336,6 @@ public final class WritingDeskGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void twoBlockDeskSharesOneInventoryAndBreaksTogether(GameTestHelper helper) {
|
||||
BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1));
|
||||
var block = ModBlocks.WRITING_DESK.get();
|
||||
@@ -462,7 +458,6 @@ public final class WritingDeskGameTests {
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void oldDeskInventoryMigratesAndAll88TabsPersist(GameTestHelper helper) {
|
||||
BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1));
|
||||
var registries = helper.getLevel().registryAccess();
|
||||
|
||||
@@ -166,15 +166,12 @@ public final class WritingDeskMenu extends AbstractContainerMenu {
|
||||
selectedPage = page;
|
||||
selectedSymbol = null;
|
||||
} else if (id >= CATALOG_BUTTON_BASE && id < CATALOG_BUTTON_BASE + catalog.size()) {
|
||||
if (!catalog.equals(WritingDeskCatalog.available(blockEntity))) {
|
||||
refreshCatalog();
|
||||
List<SymbolDisplayMetadata> available = WritingDeskCatalog.available(blockEntity);
|
||||
if (!catalog.equals(available)) {
|
||||
refreshCatalog(available);
|
||||
return false;
|
||||
}
|
||||
ResourceLocation requested = catalog.get(id - CATALOG_BUTTON_BASE).id();
|
||||
if (!WritingDeskCatalog.available(blockEntity).stream().anyMatch(entry -> entry.id().equals(requested))) {
|
||||
return false;
|
||||
}
|
||||
selectedSymbol = requested;
|
||||
selectedSymbol = available.get(id - CATALOG_BUTTON_BASE).id();
|
||||
} else return false;
|
||||
refreshOutput();
|
||||
return true;
|
||||
@@ -390,7 +387,11 @@ public final class WritingDeskMenu extends AbstractContainerMenu {
|
||||
|
||||
private void refreshCatalog() {
|
||||
if (clientSide || blockEntity == null) return;
|
||||
List<SymbolDisplayMetadata> current = WritingDeskCatalog.available(blockEntity);
|
||||
refreshCatalog(WritingDeskCatalog.available(blockEntity));
|
||||
}
|
||||
|
||||
private void refreshCatalog(List<SymbolDisplayMetadata> current) {
|
||||
if (clientSide || blockEntity == null) return;
|
||||
if (!current.equals(catalog)) {
|
||||
catalog = current;
|
||||
if (serverViewer != null && serverViewer.containerMenu == this) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package net.dnorberg.rivencraft.writing;
|
||||
|
||||
import net.dnorberg.rivencraft.item.InkVialItem;
|
||||
import net.dnorberg.rivencraft.registry.ModItems;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
/** Shared, server-side vial-to-meter exchange for the Desk and Ink Mixer. */
|
||||
public final class InkVialExchange {
|
||||
private InkVialExchange() {}
|
||||
|
||||
public static boolean canPay(NonNullList<ItemStack> items, int inkSlot, int bottleSlot,
|
||||
int storedInk, int cost) {
|
||||
return storedInk >= cost || canExchange(items, inkSlot, bottleSlot)
|
||||
&& storedInk + vialInk(items.get(inkSlot)) >= cost;
|
||||
}
|
||||
|
||||
/** Returns added ink; zero means no inputs were changed. */
|
||||
public static int exchange(NonNullList<ItemStack> items, int inkSlot, int bottleSlot) {
|
||||
if (!canExchange(items, inkSlot, bottleSlot)) return 0;
|
||||
ItemStack vial = items.get(inkSlot);
|
||||
int addedInk = vialInk(vial);
|
||||
vial.shrink(1);
|
||||
if (vial.isEmpty()) items.set(inkSlot, ItemStack.EMPTY);
|
||||
ItemStack bottles = items.get(bottleSlot);
|
||||
if (bottles.isEmpty()) items.set(bottleSlot, new ItemStack(Items.GLASS_BOTTLE));
|
||||
else bottles.grow(1);
|
||||
return addedInk;
|
||||
}
|
||||
|
||||
private static boolean canExchange(NonNullList<ItemStack> items, int inkSlot, int bottleSlot) {
|
||||
ItemStack vial = items.get(inkSlot);
|
||||
ItemStack bottles = items.get(bottleSlot);
|
||||
return vial.is(ModItems.INK_VIAL.get()) && vialInk(vial) > 0
|
||||
&& (bottles.isEmpty() || bottles.is(Items.GLASS_BOTTLE)
|
||||
&& bottles.getCount() < bottles.getMaxStackSize());
|
||||
}
|
||||
|
||||
private static int vialInk(ItemStack vial) {
|
||||
return Math.clamp(InkVialItem.remaining(vial), 0, InkVialItem.CAPACITY);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package net.dnorberg.rivencraft.writing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity;
|
||||
import net.dnorberg.rivencraft.item.PageItem;
|
||||
import net.dnorberg.rivencraft.registry.ModDataComponents;
|
||||
@@ -20,7 +20,7 @@ public final class WritingDeskCatalog {
|
||||
private WritingDeskCatalog() {}
|
||||
|
||||
public static List<SymbolDisplayMetadata> available(WritingDeskBlockEntity desk) {
|
||||
Map<ResourceLocation, SymbolDisplayMetadata> unique = new TreeMap<>();
|
||||
Map<ResourceLocation, SymbolDisplayMetadata> unique = new HashMap<>();
|
||||
for (int slot = 0; slot < WritingDeskBlockEntity.COLLECTIONS; slot++) {
|
||||
ItemStack collection = desk.getItem(slot);
|
||||
if (collection.is(ModItems.PAGE.get())) add(unique, collection);
|
||||
|
||||
Reference in new issue
Block a user