Skip to content

Commit

Permalink
Add tater guidebooks (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
haykam821 committed Jun 20, 2024
1 parent bfbbe9e commit 137edfe
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/main/java/xyz/nucleoid/extras/lobby/NEItems.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import xyz.nucleoid.extras.lobby.item.RuleBookItem;
import xyz.nucleoid.extras.lobby.item.tater.CreativeTaterBoxItem;
import xyz.nucleoid.extras.lobby.item.tater.TaterBoxItem;
import xyz.nucleoid.extras.lobby.item.tater.TaterGuidebookItem;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -96,6 +97,7 @@ public class NEItems {
entries.add(NEItems.GAME_PORTAL_OPENER);
entries.add(NEItems.TATER_BOX);
entries.add(NEItems.CREATIVE_TATER_BOX);
entries.add(NEItems.TATER_GUIDEBOOK);
TATERS.forEach(entries::add);
})
.build();
Expand Down Expand Up @@ -446,6 +448,7 @@ public class NEItems {
public static final Item TATER_BOX = new TaterBoxItem(new Item.Settings().maxDamage(0));
public static final Item CREATIVE_TATER_BOX = new CreativeTaterBoxItem(new Item.Settings().maxDamage(0));

public static final Item TATER_GUIDEBOOK = new TaterGuidebookItem(new Item.Settings().maxCount(1));
public static final Item QUICK_ARMOR_STAND = new QuickArmorStandItem(new Item.Settings());
public static final Item GAME_PORTAL_OPENER = new GamePortalOpenerItem(new Item.Settings().maxCount(1));
public static final Item LAUNCH_FEATHER = new LaunchFeatherItem(new Item.Settings().maxCount(1));
Expand Down Expand Up @@ -811,6 +814,7 @@ public static void register() {
register("tater_box", TATER_BOX);
register("creative_tater_box", CREATIVE_TATER_BOX);

register("tater_guidebook", TATER_GUIDEBOOK);
register("quick_armor_stand", QUICK_ARMOR_STAND);
register("game_portal_opener", GAME_PORTAL_OPENER);
register("launch_feather", LAUNCH_FEATHER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import xyz.nucleoid.server.translations.api.Localization;

import java.util.*;
import java.util.stream.Stream;

public class TaterBoxItem extends Item implements PolymerItem, Equipment {
private static final Text NOT_OWNER_MESSAGE = Text.translatable("text.nucleoid_extras.tater_box.not_owner").formatted(Formatting.RED);
Expand Down Expand Up @@ -91,18 +92,7 @@ private void openTaterBox(World world, ServerPlayerEntity user, ItemStack stack,

taters.add(createGuiElement(stack, user, hand, Items.BARRIER, NONE_TEXT, null, true));

TinyPotatoBlock.TATERS.stream()
.sorted(Comparator.comparing(tater -> {
if (!(tater instanceof CorruptaterBlock)) {
var name = tater.getName();

if (name != null) {
return Localization.text(name, user).getString();
}
}

return Registries.BLOCK.getId(tater).getPath();
}, String.CASE_INSENSITIVE_ORDER))
getSortedTaterStream(user)
.map(tater -> {
boolean found = state.collectedTaters.contains(tater);

Expand Down Expand Up @@ -224,4 +214,19 @@ public static void setSelectedTater(ItemStack stack, @Nullable Identifier select
tag.putString(SELECTED_TATER_KEY, selectedTaterId.toString());
}
}

public static Stream<TinyPotatoBlock> getSortedTaterStream(ServerPlayerEntity player) {
return TinyPotatoBlock.TATERS.stream()
.sorted(Comparator.comparing(tater -> {
if (!(tater instanceof CorruptaterBlock)) {
var name = tater.getName();

if (name != null) {
return Localization.text(name, player).getString();
}
}

return Registries.BLOCK.getId(tater).getPath();
}, String.CASE_INSENSITIVE_ORDER));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package xyz.nucleoid.extras.lobby.item.tater;

import java.util.Set;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;

import eu.pb4.polymer.core.api.item.PolymerItem;
import eu.pb4.sgui.api.elements.BookElementBuilder;
import eu.pb4.sgui.api.gui.BookGui;
import net.minecraft.SharedConstants;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.nbt.NbtList;
import net.minecraft.registry.Registries;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.HoverEvent;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.text.Texts;
import net.minecraft.util.Formatting;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import xyz.nucleoid.extras.lobby.block.tater.TinyPotatoBlock;
import xyz.nucleoid.extras.mixin.lobby.ThreadedAnvilChunkStorageAccessor;

public class TaterGuidebookItem extends Item implements PolymerItem {
private static final Text MISSING_SYMBOL = Text.literal("❌").formatted(Formatting.RED);
private static final Text FOUND_SYMBOL = Text.literal("✔").formatted(Formatting.GREEN);
private static final Text TOO_MANY_SYMBOL = Text.literal("✔").setStyle(Style.EMPTY.withColor(0x055005));

private static final int RECORD_COOLDOWN = 2 * SharedConstants.TICKS_PER_SECOND;

private static final String TATER_POSITIONS_KEY = "tater_positions";

public TaterGuidebookItem(Settings settings) {
super(settings);
}

@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
var stack = user.getStackInHand(hand);

if (!world.isClient() && user.isCreativeLevelTwoOp()) {
var player = (ServerPlayerEntity) user;
var taterPositionMap = getTaterPositions(stack);

if (user.isSneaking()) {
recordToGuidebook(player, taterPositionMap, stack);
} else {
showGuidebook(player, taterPositionMap, stack);
}

return TypedActionResult.success(stack, world.isClient());
}

return TypedActionResult.pass(stack);
}

@Override
public Item getPolymerItem(ItemStack stack, ServerPlayerEntity player) {
return Items.WRITTEN_BOOK;
}

private static void recordToGuidebook(ServerPlayerEntity player, SetMultimap<Item, BlockPos> taterPositions, ItemStack stack) {
int initialCount = taterPositions.size();

var chunkManager = player.getServerWorld().getChunkManager();

var chunkStorage = chunkManager.threadedAnvilChunkStorage;
var accessor = (ThreadedAnvilChunkStorageAccessor) (Object) chunkStorage;

for (var holder : accessor.callEntryIterator()) {
var chunk = holder.getWorldChunk();

if (chunk != null) {
recordChunk(chunk, taterPositions);
}
}

setTaterPositions(stack, taterPositions);

player.getItemCooldownManager().set(stack.getItem(), RECORD_COOLDOWN);

int difference = taterPositions.size() - initialCount;
player.sendMessage(Text.translatable("text.nucleoid_extras.tater_guidebook.recorded", difference), true);
}

private static void recordChunk(Chunk chunk, SetMultimap<Item, BlockPos> taterPositions) {
chunk.forEachBlockMatchingPredicate(state -> {
return state.getBlock() instanceof TinyPotatoBlock;
}, (pos, state) -> {
taterPositions.put(state.getBlock().asItem(), pos.toImmutable());
});
}

private static void showGuidebook(ServerPlayerEntity player, SetMultimap<Item, BlockPos> taterPositionMap, ItemStack stack) {
var builder = new BookElementBuilder();
var taters = TaterBoxItem.getSortedTaterStream(player).iterator();

boolean firstPage = true;

while (taters.hasNext()) {
var page = Text.empty();

if (firstPage) {
page.append(stack.getName().copy().formatted(Formatting.BOLD));
page.append(ScreenTexts.LINE_BREAK);

page.append(Text.translatable("text.nucleoid_extras.tater_guidebook.header", taterPositionMap.size()));
page.append(ScreenTexts.LINE_BREAK);
page.append(ScreenTexts.LINE_BREAK);

firstPage = false;
}

for (int index = 0; index < (16 * 4); index++) {
if (!taters.hasNext()) break;

var tater = taters.next().asItem();
var positions = taterPositionMap.get(tater);

var symbol = getSymbol(positions);

var hoverEvent = getHoverEvent(tater, positions);
var clickEvent = getClickEvent(tater, positions);

var text = symbol.copy().styled(style -> {
return style
.withHoverEvent(hoverEvent)
.withClickEvent(clickEvent);
});

page.append(text);
}

builder.addPage(page);
}

var ui = new BookGui(player, builder);
ui.open();
}

private static Text getSymbol(Set<BlockPos> positions) {
return switch (positions.size()) {
case 0 -> MISSING_SYMBOL;
case 1 -> FOUND_SYMBOL;
default -> TOO_MANY_SYMBOL;
};
}

private static HoverEvent getHoverEvent(Item tater, Set<BlockPos> positions) {
var hoverText = tater.getName().copy();

for (var pos : positions) {
hoverText.append(ScreenTexts.LINE_BREAK);

Text coordinates = Text.translatable("chat.coordinates", pos.getX(), pos.getY(), pos.getZ());
hoverText.append(Texts.bracketed(coordinates).formatted(Formatting.GREEN));
}

return new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText);
}

private static ClickEvent getClickEvent(Item tater, Set<BlockPos> positions) {
if (positions.isEmpty()) return null;

var pos = positions.iterator().next();
var command = "/tp @s " + pos.getX() + " " + pos.getY() + " " + pos.getZ();
return new ClickEvent(ClickEvent.Action.RUN_COMMAND, command);
}

private static SetMultimap<Item, BlockPos> getTaterPositions(ItemStack stack) {
var map = HashMultimap.<Item, BlockPos>create();
var nbt = stack.getSubNbt(TATER_POSITIONS_KEY);

if (nbt != null) {
for (var key : nbt.getKeys()) {
var id = Identifier.tryParse(key);
if (id == null) continue;

var item = Registries.ITEM.get(id);
if (item == null) continue;

var list = nbt.getList(key, NbtElement.COMPOUND_TYPE);

for (int index = 0; index < list.size(); index++) {
var pos = list.getCompound(index);
map.put(item, NbtHelper.toBlockPos(pos));
}
}
}

return map;
}

private static void setTaterPositions(ItemStack stack, SetMultimap<Item, BlockPos> taterPositions) {
var nbt = stack.getOrCreateSubNbt(TATER_POSITIONS_KEY);

taterPositions.asMap().forEach((item, positions) -> {
var list = new NbtList();

for (var pos : positions) {
list.add(NbtHelper.fromBlockPos(pos));
}

nbt.put(Registries.ITEM.getId(item).toString(), list);
});
}
}
4 changes: 4 additions & 0 deletions src/main/resources/data/nucleoid_extras/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@
"item.nucleoid_extras.launch_feather": "Launch Feather",
"item.nucleoid_extras.tater_box": "Tater Box",
"item.nucleoid_extras.creative_tater_box": "Creative Tater Box",
"item.nucleoid_extras.tater_guidebook": "Tater Guidebook",
"item.nucleoid_extras.quick_armor_stand": "Quick Armor Stand (Lobby only!)",
"item.nucleoid_extras.rule_book": "Rule Book",
"item.nucleoid_extras.rule_book.author": "Server admins",
Expand All @@ -381,6 +382,9 @@
"text.nucleoid_extras.creative_tater_box.collect_all": "Collect All",
"text.nucleoid_extras.creative_tater_box.reset": "Reset",

"text.nucleoid_extras.tater_guidebook.recorded": "Recorded %d new tater positions in the Tater Guidebook!",
"text.nucleoid_extras.tater_guidebook.header": "%d tater positions",

"text.nucleoid_extras.contributor_statue.title": "Select Contributor",

"text.nucleoid_extras.lobby_items": "Do not use this block outside of lobby!",
Expand Down

0 comments on commit 137edfe

Please sign in to comment.