Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tater guidebooks #130

Merged
merged 5 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading