diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 840b6279b..a1146bf1b 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -567,7 +567,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json 0f4e5a2fc58580df5b156fdac438ddeb6b57e386 assets/create/lang/en_ud.json -85d790bedbdc65bb6e6377edcc63e7b00455e879 assets/create/lang/en_us.json +2502e2934b3e39763f5619e1522b0b6f98bc26d7 assets/create/lang/en_us.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json @@ -2316,6 +2316,8 @@ ba80332510acab3f60f30d8b802ee2d450fd51b9 data/create/advancements/recipes/create 1dea56b4759da676f0edf0878ec834a4129d110b data/create/advancements/recipes/create.base/copper_ladder_from_plates_copper_stonecutting.json 3397bed32684183c2896348e3010f47137e3216d data/create/advancements/recipes/create.base/copycat_panel_from_zinc_ingot_stonecutting.json 3c22b58635d4b1c1e4c4033e43b7b4a74b1af186 data/create/advancements/recipes/create.base/copycat_step_from_zinc_ingot_stonecutting.json +3194b8da04cfb26f070b0a14f210f0117f252993 data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json +a1746099602e91fd23fba112016d41c71f9de62e data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json 376bda381f3dedb52b03eb1504b103d8ddd1b672 data/create/advancements/recipes/create.base/crafting/appliances/copper_backtank.json 9833d16405f8c51646590e98588fb410f96d9523 data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_boots.json 680c982dd1d3c45bed4d390fc0da5042750c157a data/create/advancements/recipes/create.base/crafting/appliances/copper_diving_helmet.json @@ -4004,6 +4006,8 @@ bea832822e0e5f0048eb94649641ea541e11f943 data/create/recipes/copper_shingles_fro 10fdc13f5b2b745e13e6e4e949a07ceaf4544a26 data/create/recipes/copper_tiles_from_plates_copper_stonecutting.json 89aed29928cdfa7cdde43d4a51fc4387497ddde0 data/create/recipes/copycat_panel_from_zinc_ingot_stonecutting.json c06a4519139a33250c01297b532ba6ac7d76284c data/create/recipes/copycat_step_from_zinc_ingot_stonecutting.json +005f8ad32598ea98314031e66b06e95e1f8ddd13 data/create/recipes/crafting/appliances/clipboard.json +db648fd89bc2030f3e1e9baa0d2b5b69238dec4c data/create/recipes/crafting/appliances/clipboard_clear.json eb18d5972484418fa5a768633e68688ad20d2bd7 data/create/recipes/crafting/appliances/copper_backtank.json 5771562086710eb5a3a05d464989d2f23d6c5e86 data/create/recipes/crafting/appliances/copper_diving_boots.json ec38ddb44e4bf8eaaba6f9d27e8469234fc98528 data/create/recipes/crafting/appliances/copper_diving_helmet.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 05c6ce5ab..c2f53b0e1 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1212,7 +1212,7 @@ "create.gui.schematicannon.option.skipMissing": "Skip missing Blocks", "create.gui.schematicannon.option.skipBlockEntities": "Protect Block Entities", "create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon", - "create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.listPrinter": "Place a Clipboard or Book here to print a Checklist for your Schematic", "create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.", "create.gui.schematicannon.option.skipBlockEntities.description": "The cannon will avoid replacing data holding blocks such as Chests.", diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json new file mode 100644 index 000000000..98fd32361 --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/clipboard" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:andesite_alloy" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/clipboard" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json new file mode 100644 index 000000000..39d0e338d --- /dev/null +++ b/src/generated/resources/data/create/advancements/recipes/create.base/crafting/appliances/clipboard_clear.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "create:crafting/appliances/clipboard_clear" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "create:clipboard" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "create:crafting/appliances/clipboard_clear" + } + } + }, + "requirements": [ + [ + "has_item", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/clipboard.json b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard.json new file mode 100644 index 000000000..c32ad1552 --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "A", + "P", + "G" + ], + "key": { + "G": { + "tag": "minecraft:planks" + }, + "P": { + "item": "minecraft:paper" + }, + "A": { + "item": "create:andesite_alloy" + } + }, + "result": { + "item": "create:clipboard" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/create/recipes/crafting/appliances/clipboard_clear.json b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard_clear.json new file mode 100644 index 000000000..de19409bd --- /dev/null +++ b/src/generated/resources/data/create/recipes/crafting/appliances/clipboard_clear.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "create:clipboard" + } + ], + "result": { + "item": "create:clipboard" + } +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardEntry.java b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardEntry.java index 570546412..dcdbb066e 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardEntry.java +++ b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardEntry.java @@ -13,12 +13,19 @@ import net.minecraft.world.item.ItemStack; public class ClipboardEntry { - boolean checked; - MutableComponent text; + public boolean checked; + public MutableComponent text; + public ItemStack icon; public ClipboardEntry(boolean checked, MutableComponent text) { this.checked = checked; this.text = text; + this.icon = ItemStack.EMPTY; + } + + public ClipboardEntry displayItem(ItemStack icon) { + this.icon = icon; + return this; } public static List> readAll(ItemStack clipboardItem) { @@ -29,6 +36,17 @@ public class ClipboardEntry { .readCompoundList(pageTag.getList("Entries", Tag.TAG_COMPOUND), ClipboardEntry::readNBT)); } + public static List getLastViewedEntries(ItemStack heldItem) { + List> pages = ClipboardEntry.readAll(heldItem); + if (pages.isEmpty()) + return new ArrayList<>(); + int page = heldItem.getTag() == null ? 0 + : Math.min(heldItem.getTag() + .getInt("PreviouslyOpenedPage"), pages.size() - 1); + List entries = pages.get(page); + return entries; + } + public static void saveAll(List> entries, ItemStack clipboardItem) { CompoundTag tag = clipboardItem.getOrCreateTag(); tag.put("Pages", NBTHelper.writeCompoundList(entries, list -> { @@ -42,11 +60,18 @@ public class ClipboardEntry { CompoundTag nbt = new CompoundTag(); nbt.putBoolean("Checked", checked); nbt.putString("Text", Component.Serializer.toJson(text)); + if (icon.isEmpty()) + return nbt; + nbt.put("Icon", icon.serializeNBT()); return nbt; } public static ClipboardEntry readNBT(CompoundTag tag) { - return new ClipboardEntry(tag.getBoolean("Checked"), Component.Serializer.fromJson(tag.getString("Text"))); + ClipboardEntry clipboardEntry = + new ClipboardEntry(tag.getBoolean("Checked"), Component.Serializer.fromJson(tag.getString("Text"))); + if (tag.contains("Icon")) + clipboardEntry.displayItem(ItemStack.of(tag.getCompound("Icon"))); + return clipboardEntry; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java index f9cf68581..80dd935d7 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java +++ b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreen.java @@ -64,6 +64,7 @@ public class ClipboardScreen extends AbstractSimiScreen { int hoveredEntry; boolean hoveredCheck; + boolean readonly; DisplayCache displayCache = DisplayCache.EMPTY; TextFieldHelper editContext; @@ -91,6 +92,10 @@ public class ClipboardScreen extends AbstractSimiScreen { editContext = new TextFieldHelper(this::getCurrentEntryText, this::setCurrentEntryText, this::getClipboard, this::setClipboard, this::validateTextForEntry); editingIndex = startEmpty ? 0 : -1; + readonly = item.getTag() != null && item.getTag() + .getBoolean("Readonly"); + if (readonly) + editingIndex = -1; } @Override @@ -122,7 +127,7 @@ public class ClipboardScreen extends AbstractSimiScreen { addRenderableWidget(forward); addRenderableWidget(backward); - forward.visible = currentPage < 50; + forward.visible = currentPage < 50 && (!readonly || currentPage + 1 < pages.size()); backward.visible = currentPage > 0; } @@ -153,8 +158,9 @@ public class ClipboardScreen extends AbstractSimiScreen { for (int i = 0; i < currentEntries.size(); i++) { ClipboardEntry clipboardEntry = currentEntries.get(i); String text = clipboardEntry.text.getString(); - totalHeight += Math.max(12, font.split(Components.literal(text), 150) - .size() * 9 + 3); + totalHeight += + Math.max(12, font.split(Components.literal(text), clipboardEntry.icon.isEmpty() ? 150 : 130) + .size() * 9 + 3); if (totalHeight > my) { hoveredEntry = i; @@ -211,17 +217,24 @@ public class ClipboardScreen extends AbstractSimiScreen { if (currentPage == previously) return; editingIndex = -1; - if (pages.size() <= currentPage) + if (pages.size() <= currentPage) { + if (readonly) { + currentPage = previously; + return; + } pages.add(new ArrayList<>()); + } currentEntries = pages.get(currentPage); if (currentEntries.isEmpty()) { currentEntries.add(new ClipboardEntry(false, Components.empty())); - editingIndex = 0; - editContext.setCursorToEnd(); - clearDisplayCacheAfterChange(); + if (!readonly) { + editingIndex = 0; + editContext.setCursorToEnd(); + clearDisplayCacheAfterChange(); + } } - forward.visible = currentPage < 50; + forward.visible = currentPage < 50 && (!readonly || currentPage + 1 < pages.size()); backward.visible = currentPage > 0; if (next) @@ -245,20 +258,24 @@ public class ClipboardScreen extends AbstractSimiScreen { for (int i = 0; i < currentEntries.size(); i++) { ClipboardEntry clipboardEntry = currentEntries.get(i); boolean checked = clipboardEntry.checked; + int iconOffset = clipboardEntry.icon.isEmpty() ? 0 : 16; font.draw(ms, "\u25A1", x + 45, y + 51, checked ? 0x668D7F6B : 0xff8D7F6B); if (checked) font.draw(ms, "\u2714", x + 45, y + 50, 0x31B25D); - List split = font.split(clipboardEntry.text, 150); + List split = font.split(clipboardEntry.text, 150 - iconOffset); if (split.isEmpty()) { y += 12; continue; } + if (!clipboardEntry.icon.isEmpty()) + itemRenderer.renderGuiItem(clipboardEntry.icon, x + 54, y + 50); + for (FormattedCharSequence sequence : split) { if (i != editingIndex) - font.draw(ms, sequence, x + 58, y + 50, checked ? 0x31B25D : 0x311A00); + font.draw(ms, sequence, x + 58 + iconOffset, y + 50, checked ? 0x31B25D : 0x311A00); y += 9; } y += 3; @@ -525,7 +542,7 @@ public class ClipboardScreen extends AbstractSimiScreen { return true; } - if (hoveredEntry != editingIndex) { + if (hoveredEntry != editingIndex && !readonly) { editingIndex = hoveredEntry; if (hoveredEntry >= currentEntries.size()) { currentEntries.add(new ClipboardEntry(false, Components.empty())); diff --git a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreenHelper.java b/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreenHelper.java deleted file mode 100644 index 0e53a7075..000000000 --- a/src/main/java/com/simibubi/create/content/curiosities/clipboard/ClipboardScreenHelper.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.simibubi.create.content.curiosities.clipboard; - -import net.minecraft.SharedConstants; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.inventory.BookEditScreen; - -public class ClipboardScreenHelper { - - - -} diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java index 5cb745bd1..de3810d1c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeBlock.java @@ -2,13 +2,16 @@ package com.simibubi.create.content.logistics.block.redstone; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; +import java.util.List; import java.util.Random; import java.util.function.BiConsumer; import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.curiosities.clipboard.ClipboardEntry; import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; @@ -19,6 +22,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -76,20 +80,31 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock return InteractionResult.SUCCESS; } - boolean display = heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName(); + boolean display = + heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName() || AllItems.CLIPBOARD.isIn(heldItem); DyeColor dye = DyeColor.getColor(heldItem); if (!display && dye == null) return InteractionResult.PASS; - if (world.isClientSide) - return InteractionResult.SUCCESS; CompoundTag tag = heldItem.getTagElement("display"); String tagElement = tag != null && tag.contains("Name", Tag.TAG_STRING) ? tag.getString("Name") : null; + if (AllItems.CLIPBOARD.isIn(heldItem)) { + List entries = ClipboardEntry.getLastViewedEntries(heldItem); + for (int i = 0; i < entries.size();) { + tagElement = Component.Serializer.toJson(entries.get(i).text); + break; + } + } + + if (world.isClientSide) + return InteractionResult.SUCCESS; + + String tagUsed = tagElement; walkNixies(world, pos, (currentPos, rowPosition) -> { if (display) - withBlockEntityDo(world, currentPos, be -> be.displayCustomText(tagElement, rowPosition)); + withBlockEntityDo(world, currentPos, be -> be.displayCustomText(tagUsed, rowPosition)); if (dye != null) world.setBlockAndUpdate(currentPos, withColor(state, dye)); }); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java index aa3cbefb8..d64ada626 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/display/FlapDisplayBlock.java @@ -8,12 +8,15 @@ import java.util.function.Predicate; import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; import com.simibubi.create.content.contraptions.base.KineticBlockEntity; import com.simibubi.create.content.contraptions.relays.elementary.ICogWheel; import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.curiosities.clipboard.ClipboardEntry; import com.simibubi.create.foundation.block.IBE; +import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; import com.simibubi.create.foundation.utility.placement.PlacementHelpers; @@ -27,6 +30,7 @@ import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; @@ -158,7 +162,8 @@ public class FlapDisplayBlock extends HorizontalKineticBlock return InteractionResult.SUCCESS; } - boolean display = heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName(); + boolean display = + heldItem.getItem() == Items.NAME_TAG && heldItem.hasCustomHoverName() || AllItems.CLIPBOARD.isIn(heldItem); DyeColor dye = DyeColor.getColor(heldItem); if (!display && dye == null) @@ -171,8 +176,20 @@ public class FlapDisplayBlock extends HorizontalKineticBlock CompoundTag tag = heldItem.getTagElement("display"); String tagElement = tag != null && tag.contains("Name", Tag.TAG_STRING) ? tag.getString("Name") : null; - if (display) + if (display) { + if (AllItems.CLIPBOARD.isIn(heldItem)) { + List entries = ClipboardEntry.getLastViewedEntries(heldItem); + int line = lineIndex; + for (int i = 0; i < entries.size(); i++) { + for (String string : entries.get(i).text.getString() + .split("\n")) + flapBE.applyTextManually(line++, Component.Serializer.toJson(Components.literal(string))); + } + return InteractionResult.SUCCESS; + } + flapBE.applyTextManually(lineIndex, tagElement); + } if (dye != null) { world.playSound(null, pos, SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F); flapBE.setColour(lineIndex, dye); @@ -315,7 +332,8 @@ public class FlapDisplayBlock extends HorizontalKineticBlock BlockPos relative = pPos.relative(d); BlockState adjacent = pLevel.getBlockState(relative); if (canConnect(pState, adjacent)) - KineticBlockEntity.switchToBlockState(pLevel, relative, updateColumn(pLevel, relative, adjacent, false)); + KineticBlockEntity.switchToBlockState(pLevel, relative, + updateColumn(pLevel, relative, adjacent, false)); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java b/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java index d79dc1586..0b76235a6 100644 --- a/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java +++ b/src/main/java/com/simibubi/create/content/schematics/MaterialChecklist.java @@ -6,6 +6,10 @@ import java.util.List; import java.util.Locale; import com.google.common.collect.Sets; +import com.simibubi.create.AllItems; +import com.simibubi.create.content.curiosities.clipboard.ClipboardEntry; +import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides; +import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides.ClipboardType; import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.Lang; @@ -27,6 +31,7 @@ import net.minecraft.world.item.Items; public class MaterialChecklist { public static final int MAX_ENTRIES_PER_PAGE = 5; + public static final int MAX_ENTRIES_PER_CLIPBOARD_PAGE = 7; public Object2IntMap gathered = new Object2IntArrayMap<>(); public Object2IntMap required = new Object2IntArrayMap<>(); @@ -70,7 +75,7 @@ public class MaterialChecklist { gathered.put(item, stack.getCount()); } - public ItemStack createItem() { + public ItemStack createWrittenBook() { ItemStack book = new ItemStack(Items.WRITTEN_BOOK); CompoundTag tag = book.getOrCreateTag(); @@ -88,9 +93,11 @@ public class MaterialChecklist { List keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet())); Collections.sort(keys, (item1, item2) -> { Locale locale = Locale.ENGLISH; - String name1 = item1.getDescription().getString() + String name1 = item1.getDescription() + .getString() .toLowerCase(locale); - String name2 = item2.getDescription().getString() + String name2 = item2.getDescription() + .getString() .toLowerCase(locale); return name1.compareTo(name2); }); @@ -109,30 +116,33 @@ public class MaterialChecklist { if (itemsWritten == MAX_ENTRIES_PER_PAGE) { itemsWritten = 0; - textComponent.append(Components.literal("\n >>>").withStyle(ChatFormatting.BLUE)); + textComponent.append(Components.literal("\n >>>") + .withStyle(ChatFormatting.BLUE)); pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); textComponent = Components.empty(); } itemsWritten++; - textComponent.append(entry(new ItemStack(item), amount, true)); + textComponent.append(entry(new ItemStack(item), amount, true, true)); } for (Item item : completed) { if (itemsWritten == MAX_ENTRIES_PER_PAGE) { itemsWritten = 0; - textComponent.append(Components.literal("\n >>>").withStyle(ChatFormatting.DARK_GREEN)); + textComponent.append(Components.literal("\n >>>") + .withStyle(ChatFormatting.DARK_GREEN)); pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); textComponent = Components.empty(); } itemsWritten++; - textComponent.append(entry(new ItemStack(item), getRequiredAmount(item), false)); + textComponent.append(entry(new ItemStack(item), getRequiredAmount(item), false, true)); } pages.add(StringTag.valueOf(Component.Serializer.toJson(textComponent))); tag.put("pages", pages); + tag.putBoolean("readonly", true); tag.putString("author", "Schematicannon"); tag.putString("title", ChatFormatting.BLUE + "Material Checklist"); textComponent = Lang.translateDirect("materialChecklist") @@ -145,6 +155,80 @@ public class MaterialChecklist { return book; } + public ItemStack createWrittenClipboard() { + ItemStack clipboard = AllItems.CLIPBOARD.asStack(); + CompoundTag tag = clipboard.getOrCreateTag(); + int itemsWritten = 0; + + List> pages = new ArrayList<>(); + List currentPage = new ArrayList<>(); + + if (blocksNotLoaded) { + currentPage.add(new ClipboardEntry(false, Lang.translateDirect("materialChecklist.blocksNotLoaded") + .withStyle(ChatFormatting.RED))); + } + + List keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet())); + Collections.sort(keys, (item1, item2) -> { + Locale locale = Locale.ENGLISH; + String name1 = item1.getDescription() + .getString() + .toLowerCase(locale); + String name2 = item2.getDescription() + .getString() + .toLowerCase(locale); + return name1.compareTo(name2); + }); + + List completed = new ArrayList<>(); + for (Item item : keys) { + int amount = getRequiredAmount(item); + if (gathered.containsKey(item)) + amount -= gathered.getInt(item); + + if (amount <= 0) { + completed.add(item); + continue; + } + + if (itemsWritten == MAX_ENTRIES_PER_CLIPBOARD_PAGE) { + itemsWritten = 0; + currentPage.add(new ClipboardEntry(false, Components.literal(">>>") + .withStyle(ChatFormatting.DARK_GRAY))); + pages.add(currentPage); + currentPage = new ArrayList<>(); + } + + itemsWritten++; + currentPage.add(new ClipboardEntry(false, entry(new ItemStack(item), amount, true, false)) + .displayItem(new ItemStack(item))); + } + + for (Item item : completed) { + if (itemsWritten == MAX_ENTRIES_PER_PAGE) { + itemsWritten = 0; + currentPage.add(new ClipboardEntry(true, Components.literal(">>>") + .withStyle(ChatFormatting.DARK_GREEN))); + pages.add(currentPage); + currentPage = new ArrayList<>(); + } + + itemsWritten++; + currentPage.add(new ClipboardEntry(true, entry(new ItemStack(item), getRequiredAmount(item), false, false)) + .displayItem(new ItemStack(item))); + } + + pages.add(currentPage); + ClipboardEntry.saveAll(pages, clipboard); + ClipboardOverrides.switchTo(ClipboardType.WRITTEN, clipboard); + clipboard.getOrCreateTagElement("display") + .putString("Name", Component.Serializer.toJson(Lang.translateDirect("materialChecklist") + .setStyle(Style.EMPTY.withItalic(Boolean.FALSE)))); + tag.putBoolean("Readonly", true); + clipboard.setTag(tag); + return clipboard; + } + public int getRequiredAmount(Item item) { int amount = required.getOrDefault(item, 0); if (damageRequired.containsKey(item)) @@ -152,7 +236,7 @@ public class MaterialChecklist { return amount; } - private Component entry(ItemStack item, int amount, boolean unfinished) { + private MutableComponent entry(ItemStack item, int amount, boolean unfinished, boolean forBook) { int stacks = amount / 64; int remainder = amount % 64; MutableComponent tc = Components.empty(); @@ -160,11 +244,14 @@ public class MaterialChecklist { .setStyle(Style.EMPTY .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(item))))); - if (!unfinished) + if (!unfinished && forBook) tc.append(" \u2714"); - tc.withStyle(unfinished ? ChatFormatting.BLUE : ChatFormatting.DARK_GREEN); - return tc.append(Components.literal("\n" + " x" + amount).withStyle(ChatFormatting.BLACK)) - .append(Components.literal(" | " + stacks + "\u25A4 +" + remainder + "\n").withStyle(ChatFormatting.GRAY)); + if (!unfinished || forBook) + tc.withStyle(unfinished ? ChatFormatting.BLUE : ChatFormatting.DARK_GREEN); + return tc.append(Components.literal("\n" + " x" + amount) + .withStyle(ChatFormatting.BLACK)) + .append(Components.literal(" | " + stacks + "\u25A4 +" + remainder + (forBook ? "\n" : "")) + .withStyle(ChatFormatting.GRAY)); } } diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlockEntity.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlockEntity.java index d4cb56776..33e94bf4f 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonBlockEntity.java @@ -700,8 +700,9 @@ public class SchematicannonBlockEntity extends SmartBlockEntity implements MenuP updateChecklist(); dontUpdateChecklist = true; - inventory.extractItem(BookInput, 1, false); - ItemStack stack = checklist.createItem(); + ItemStack extractItem = inventory.extractItem(BookInput, 1, false); + ItemStack stack = AllItems.CLIPBOARD.isIn(extractItem) ? checklist.createWrittenClipboard() + : checklist.createWrittenBook(); stack.setCount(inventory.getStackInSlot(BookOutput) .getCount() + 1); inventory.setStackInSlot(BookOutput, stack); diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java index febefdb34..8db0581cf 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonInventory.java @@ -28,7 +28,8 @@ public class SchematicannonInventory extends ItemStackHandler { case 1: // Blueprint output return false; case 2: // Book input - return stack.sameItem(new ItemStack(Items.BOOK)) || stack.sameItem(new ItemStack(Items.WRITTEN_BOOK)); + return AllItems.CLIPBOARD.isIn(stack) || stack.sameItem(new ItemStack(Items.BOOK)) + || stack.sameItem(new ItemStack(Items.WRITTEN_BOOK)); case 3: // Material List output return false; case 4: // Gunpowder diff --git a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java index 00d226019..6f056de67 100644 --- a/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java +++ b/src/main/java/com/simibubi/create/foundation/data/recipe/StandardRecipeGen.java @@ -1011,6 +1011,18 @@ public class StandardRecipeGen extends CreateRecipeProvider { .viaShapeless(b -> b.requires(I.wheatFlour()) .requires(Items.WATER_BUCKET)), + CLIPBOARD = create(AllItems.CLIPBOARD).unlockedBy(I::andesite) + .viaShaped(b -> b.define('G', I.planks()) + .define('P', Items.PAPER) + .define('A', I.andesite()) + .pattern("A") + .pattern("P") + .pattern("G")), + + CLIPBOARD_CLEAR = create(AllItems.CLIPBOARD).withSuffix("_clear") + .unlockedBy(AllItems.CLIPBOARD::get) + .viaShapeless(b -> b.requires(AllItems.CLIPBOARD.get())), + DIVING_HELMET = create(AllItems.COPPER_DIVING_HELMET).unlockedBy(I::copper) .viaShaped(b -> b.define('G', Tags.Items.GLASS) .define('P', I.copper()) diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index e3fba6afb..472453f5f 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -357,7 +357,7 @@ "create.gui.schematicannon.option.skipBlockEntities": "Protect Block Entities", "create.gui.schematicannon.slot.gunpowder": "Add gunpowder to fuel the cannon", - "create.gui.schematicannon.slot.listPrinter": "Place books here to print a Checklist for your Schematic", + "create.gui.schematicannon.slot.listPrinter": "Place a Clipboard or Book here to print a Checklist for your Schematic", "create.gui.schematicannon.slot.schematic": "Add your Schematic here. Make sure it is deployed at a specific location.", "create.gui.schematicannon.option.skipMissing.description": "If the cannon cannot find a required Block for placement, it will continue at the next Location.",