diff options
Diffstat (limited to 'src')
9 files changed, 236 insertions, 38 deletions
diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterBlock.java b/src/main/java/moe/nea/funnyteleporters/TeleporterBlock.java index a12037e..45d88e8 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterBlock.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterBlock.java @@ -6,6 +6,7 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.block.RespawnAnchorBlock; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityTicker; import net.minecraft.block.entity.BlockEntityType; @@ -22,7 +23,7 @@ public class TeleporterBlock extends Block implements PolymerBlock, BlockEntityP @Override public BlockState getPolymerBlockState(BlockState blockState) { - return Blocks.SEA_LANTERN.getDefaultState(); + return Blocks.RESPAWN_ANCHOR.getDefaultState().with(RespawnAnchorBlock.CHARGES, RespawnAnchorBlock.MAX_CHARGES); } public TeleporterBlockEntity getBE(World world, BlockPos pos) { diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterBlockEntity.java b/src/main/java/moe/nea/funnyteleporters/TeleporterBlockEntity.java index e225830..2cc452c 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterBlockEntity.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterBlockEntity.java @@ -1,22 +1,20 @@ package moe.nea.funnyteleporters; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.DataResult; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.entity.Entity; import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtOps; import net.minecraft.registry.RegistryWrapper; -import net.minecraft.server.world.ServerWorld; import net.minecraft.util.TypeFilter; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Set; @@ -37,7 +35,8 @@ public class TeleporterBlockEntity extends BlockEntity { var up = blockPos.up(); var newEntities = new HashSet<>(world.getEntitiesByType(TypeFilter.instanceOf(Entity.class), Box.enclosing(up, up), entity -> true)); for (Entity entity : newEntities) { - if (incomingEntities.remove(entity)) { + var ref = new Ref(entity); + if (incomingEntities.remove(ref)) { trackedEntities.remove(entity); continue; } @@ -46,6 +45,11 @@ public class TeleporterBlockEntity extends BlockEntity { } } trackedEntities = newEntities; + while (true) { + var ref = (Ref) refQueue.poll(); + if (ref == null) break; + incomingEntities.remove(ref); + } } @Override @@ -67,12 +71,39 @@ public class TeleporterBlockEntity extends BlockEntity { } } + class Ref extends WeakReference<Entity> { + public Ref(Entity referent) { + super(referent, refQueue); + hash = System.identityHashCode(referent); + } + + int hash; + + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Ref ref) { + return ref.hash == this.hash && ref.get() == this.get(); + } + return false; + } + } + + private final ReferenceQueue<Entity> refQueue = new ReferenceQueue<>(); Set<Entity> trackedEntities = new HashSet<>(); - Set<Entity> incomingEntities = new HashSet<>(); + Set<Ref> incomingEntities = new HashSet<>(); @Nullable TeleporterDestination destination; void performTeleport(Entity subject) { if (destination == null) return; destination.teleport(subject); } + + public void addIncoming(Entity subject) { + incomingEntities.add(new Ref(subject)); + } } diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterDestination.java b/src/main/java/moe/nea/funnyteleporters/TeleporterDestination.java index b867fc4..44e6d46 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterDestination.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterDestination.java @@ -8,14 +8,17 @@ import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.jetbrains.annotations.NotNull; import java.util.Comparator; +import java.util.List; +import java.util.Optional; import java.util.Set; public record TeleporterDestination( @@ -31,6 +34,11 @@ public record TeleporterDestination( return COMPARATOR.compare(this, o); } + public List<Text> formatName(String prefix) { // TODO: use this more often + return List.of(Text.literal("%s x: %d, y: %d, z: %d".formatted(prefix, blockPos().getX(), blockPos().getY(), blockPos().getZ())), + Text.literal("In Dimension: %s".formatted(target().getValue()))); + } + public void teleport(Entity subject) { var sourceWorld = subject.getWorld(); var destinationWorld = getDestinationWorld((ServerWorld) sourceWorld); @@ -39,15 +47,17 @@ public record TeleporterDestination( if (!(destinationBE instanceof TeleporterBlockEntity be)) { return; } - be.incomingEntities.add(subject); + be.addIncoming(subject); var destPos = blockPos().up().toBottomCenterPos(); subject.teleport(destinationWorld, destPos.x, destPos.y, destPos.z, Set.of(), subject.getYaw(), subject.getPitch()); } - public record Labeled(RegistryEntry<Item> item, TeleporterDestination destination) { + public record Labeled(RegistryEntry<Item> item, TeleporterDestination destination, Optional<String> name) { public static Codec<Labeled> CODEC = RecordCodecBuilder.create(instance -> instance.group( Registries.ITEM.getEntryCodec().fieldOf("item").forGetter(Labeled::item), - TeleporterDestination.CODEC.fieldOf("destination").forGetter(Labeled::destination)).apply(instance, Labeled::new)); + TeleporterDestination.CODEC.fieldOf("destination").forGetter(Labeled::destination), + Codec.STRING.optionalFieldOf("name").forGetter(Labeled::name) + ).apply(instance, Labeled::new)); } public ServerWorld getDestinationWorld(ServerWorld world) { diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusBlockEntity.java b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusBlockEntity.java index ba6808a..dbc8150 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusBlockEntity.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusBlockEntity.java @@ -6,6 +6,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.item.Item; +import net.minecraft.item.ItemConvertible; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtOps; @@ -14,6 +15,7 @@ import net.minecraft.registry.RegistryWrapper; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.util.math.BlockPos; +import java.util.Optional; import java.util.TreeMap; public class TeleporterNexusBlockEntity extends BlockEntity { @@ -23,21 +25,41 @@ public class TeleporterNexusBlockEntity extends BlockEntity { super(type, pos, state); } - public TreeMap<TeleporterDestination, RegistryEntry<Item>> destinations = new TreeMap<>(); - private static final Codec<TreeMap<TeleporterDestination, RegistryEntry<Item>>> DESTINATION_CODEC = + public Optional<String> getName(TeleporterDestination dest) { + var label = destinations.get(dest); + return label != null ? (label.label) : Optional.empty(); + } + + public ItemConvertible getIcon(TeleporterDestination dest) { + var label = destinations.get(dest); + return (label != null ? label.item : getDefaultItem()).value(); + } + + public record Label( + RegistryEntry<Item> item, + Optional<String> label + ) { + } + + public TreeMap<TeleporterDestination, Label> destinations = new TreeMap<>(); + private static final Codec<TreeMap<TeleporterDestination, Label>> DESTINATION_CODEC = TeleporterDestination.Labeled.CODEC .listOf() .xmap( pairs -> { - var hash = new TreeMap<TeleporterDestination, RegistryEntry<Item>>(); + var hash = new TreeMap<TeleporterDestination, Label>(); for (TeleporterDestination.Labeled pair : pairs) { - hash.put(pair.destination(), pair.item()); + hash.put(pair.destination(), new Label(pair.item(), pair.name())); } return hash; }, - map -> map.entrySet().stream().map(it -> new TeleporterDestination.Labeled(it.getValue(), it.getKey())).toList() + map -> map.entrySet().stream().map(it -> new TeleporterDestination.Labeled(it.getValue().item(), it.getKey(), it.getValue().label())).toList() ); + static RegistryEntry<Item> getDefaultItem() { + return Registries.ITEM.getEntry(Items.ENDER_PEARL); + } + @Override protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { super.readNbt(nbt, registryLookup); @@ -52,7 +74,7 @@ public class TeleporterNexusBlockEntity extends BlockEntity { } public void addDestination(TeleporterDestination destination) { - destinations.putIfAbsent(destination, Registries.ITEM.getEntry(Items.ENDER_PEARL)); + destinations.putIfAbsent(destination, new Label(getDefaultItem(), Optional.empty())); markDirty(); } @@ -62,7 +84,13 @@ public class TeleporterNexusBlockEntity extends BlockEntity { } public void setIcon(TeleporterDestination dest, Item item) { - destinations.put(dest, Registries.ITEM.getEntry(item)); + var entry = Registries.ITEM.getEntry(item); + destinations.compute(dest, (key, old) -> old == null ? new Label(entry, Optional.empty()) : new Label(entry, old.label())); + markDirty(); + } + + public void setName(TeleporterDestination dest, Optional<String> string) { + destinations.compute(dest, (key, old) -> old == null ? new Label(getDefaultItem(), string) : new Label(old.item(), string)); markDirty(); } } diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusEditorScreen.java b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusEditorScreen.java index 582ffe5..7fe55a6 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusEditorScreen.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusEditorScreen.java @@ -11,37 +11,75 @@ import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; public class TeleporterNexusEditorScreen extends SimpleGui { - private final TeleporterNexusBlockEntity blockEntity; - private final TeleporterDestination dest; + final TeleporterNexusBlockEntity blockEntity; + final TeleporterDestination dest; public TeleporterNexusEditorScreen(TeleporterNexusBlockEntity blockEntity, TeleporterDestination dest, ServerPlayerEntity player) { super(ScreenHandlerType.GENERIC_9X3, player, false); this.blockEntity = blockEntity; this.dest = dest; - setTitle(Text.literal("Set Icon for Teleporter")); setSlots(); } void setSlots() { + setTitle(Text.literal("Set Icon for " + blockEntity.getName(dest).orElse("teleporter"))); for (int i = 0; i < width * height; i++) { setSlot(i, Utils.createBlankBlack()); } - setSlot(width * height / 2, - GuiElementBuilder.from(new ItemStack(blockEntity.destinations.getOrDefault(dest, Registries.ITEM.getEntry(Items.ENDER_PEARL)).value())) + setSlot(4 + 9, + GuiElementBuilder.from(new ItemStack(blockEntity.getIcon(dest))) .setName(Text.literal("Click item in your inventory to set icon."))); + setSlot(2 + 9, + GuiElementBuilder.from(new ItemStack(Items.OAK_SIGN)) + .setName(Text.literal("Click here to change name")) + .addLoreLine(Text.literal("Click here to set a name for the teleport destination") + .setStyle(Utils.colouredLoreStyle(Formatting.AQUA))) + .setCallback(this::handleNameChange)); + setSlot(9 + 6, + GuiElementBuilder.from(new ItemStack(Items.BARRIER)) + .setName(Text.literal("Delete").withColor(0xFFFF0000)) + .addLoreLine(Text.literal("Shift-Click here to remove this location") + .setStyle(Utils.colouredLoreStyle(Formatting.RED))) + .addLoreLine(Text.literal("from the teleport nexus") + .setStyle(Utils.colouredLoreStyle(Formatting.RED))) + .setCallback(this::handleDelete)); + } + + void handleNameChange() { + new TeleporterNexusNameEditorScreen(this).open(); + } + + void handleDelete(ClickType clickType) { + if (clickType == ClickType.MOUSE_LEFT_SHIFT) { + blockEntity.removeDestination(dest); + back(); + } else { + player.sendMessage(Text.literal("You need to shift click to delete locations.")); + } + } + + @Override + public void onClose() { + back(); + } + + void back() { + new TeleporterNexusScreen(blockEntity, player).open(); } @Override public boolean onAnyClick(int index, ClickType type, SlotActionType action) { - System.out.println("Index: " + index); var slot = getSlotRedirectOrPlayer(index); if (slot == null) return true; var stack = slot.getStack(); if (!stack.isEmpty()) { blockEntity.setIcon(dest, stack.getItem()); - new TeleporterNexusScreen(blockEntity, player).open(); + setSlots(); + if (screenHandler != null) + screenHandler.syncState(); } return false; } diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusNameEditorScreen.java b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusNameEditorScreen.java new file mode 100644 index 0000000..f4d33ea --- /dev/null +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusNameEditorScreen.java @@ -0,0 +1,29 @@ +package moe.nea.funnyteleporters; + +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import eu.pb4.sgui.api.gui.AnvilInputGui; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.text.Text; + +import java.util.Optional; + +public class TeleporterNexusNameEditorScreen extends AnvilInputGui { + private final TeleporterNexusEditorScreen previous; + + public TeleporterNexusNameEditorScreen(TeleporterNexusEditorScreen previous) { + super(previous.getPlayer(), false); + this.previous = previous; + setTitle(Text.literal("Edit Name")); + setSlot(2, GuiElementBuilder.from(new ItemStack(Items.OAK_SIGN)) + .setName(Text.literal("Click here to save")) + .setCallback(this::save)); + setDefaultInputValue(previous.blockEntity.getName(previous.dest).orElse("")); + } + + void save() { + previous.blockEntity.setName(previous.dest, Optional.of(getInput())); + previous.setSlots(); + previous.open(); + } +} diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusScreen.java b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusScreen.java index 302d630..4a9088e 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterNexusScreen.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterNexusScreen.java @@ -6,6 +6,7 @@ import eu.pb4.sgui.api.elements.GuiElementBuilderInterface; import eu.pb4.sgui.api.gui.SimpleGui; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.server.network.ServerPlayerEntity; @@ -25,12 +26,20 @@ public class TeleporterNexusScreen extends SimpleGui { setTitle(Text.literal("Teleport Nexus")); } + int scroll = 0; + void setSlots() { for (int i = 0; i < 9; i++) { setSlot(i, Utils.createBlankBlack()); setSlot(i + (height - 1) * width, Utils.createBlankBlack()); } + if (scroll > 0) { + setSlot(0, GuiElementBuilder.from(new ItemStack(Items.ARROW)) + .setName(Text.literal("Previous page")) + .setCallback(() -> scroll(-1))); + } var it = blockEntity.destinations.entrySet().iterator(); + Utils.skipIt(it, scroll * width * (height - 2)); for (int i = 1; i < height - 1 && it.hasNext(); i++) { for (int j = 0; j < width && it.hasNext(); j++) { int index = i * width + j; @@ -38,12 +47,31 @@ public class TeleporterNexusScreen extends SimpleGui { setSlot(index, getHandlerForEntry(entry)); } } + if (it.hasNext()) { + setSlot(1, GuiElementBuilder.from(new ItemStack(Items.ARROW)) + .setName(Text.literal("Next page")) + .setCallback(() -> scroll(1))); + } + } + + void scroll(int offset) { + scroll = Math.max(0, scroll + offset); + setSlots(); + } + + void handleClick(ClickType clickType, TeleporterDestination destination) { + if (clickType == ClickType.MOUSE_RIGHT) { + new TeleporterNexusEditorScreen(blockEntity, destination, player).open(); + return; + } + destination.teleport(player); + close(); } - private GuiElementBuilderInterface<?> getHandlerForEntry(Map.Entry<TeleporterDestination, RegistryEntry<Item>> entry) { + private GuiElementBuilderInterface<?> getHandlerForEntry(Map.Entry<TeleporterDestination, TeleporterNexusBlockEntity.Label> entry) { var dest = entry.getKey(); - return GuiElementBuilder.from(new ItemStack(entry.getValue())) - .setName(Text.literal("Teleport to")) + return GuiElementBuilder.from(new ItemStack(entry.getValue().item())) + .setName(Text.literal("Teleport to" + entry.getValue().label().map(it -> " " + it).orElse(""))) .hideDefaultTooltip() .addLoreLine(Text.literal(String.format("x: %d, y: %d, z: %d", dest.blockPos().getX(), dest.blockPos().getY(), dest.blockPos().getZ())) .setStyle(Style.EMPTY.withItalic(false).withColor(Formatting.AQUA))) @@ -52,13 +80,6 @@ public class TeleporterNexusScreen extends SimpleGui { .addLoreLine(Text.empty()) .addLoreLine(Text.literal("Left-Click to teleport.").setStyle(Style.EMPTY.withItalic(false).withColor(Formatting.GRAY))) .addLoreLine(Text.literal("Right-Click to edit item.").setStyle(Style.EMPTY.withItalic(false).withColor(Formatting.GRAY))) - .setCallback((clickType) -> { - if (clickType == ClickType.MOUSE_RIGHT) { - new TeleporterNexusEditorScreen(blockEntity, dest, player).open(); - return; - } - dest.teleport(player); - close(); - }); + .setCallback(clickType -> handleClick(clickType, dest)); } } diff --git a/src/main/java/moe/nea/funnyteleporters/TeleporterWand.java b/src/main/java/moe/nea/funnyteleporters/TeleporterWand.java index fa379b4..6510123 100644 --- a/src/main/java/moe/nea/funnyteleporters/TeleporterWand.java +++ b/src/main/java/moe/nea/funnyteleporters/TeleporterWand.java @@ -1,15 +1,25 @@ package moe.nea.funnyteleporters; import eu.pb4.polymer.core.api.item.PolymerItem; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.item.Items; +import net.minecraft.item.tooltip.TooltipType; +import net.minecraft.registry.RegistryWrapper; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; +import java.util.List; + public class TeleporterWand extends Item implements PolymerItem { public TeleporterWand(Settings settings) { super(settings); @@ -21,6 +31,27 @@ public class TeleporterWand extends Item implements PolymerItem { } @Override + public ItemStack getPolymerItemStack(ItemStack original, TooltipType tooltipType, RegistryWrapper.WrapperLookup lookup, @Nullable ServerPlayerEntity player) { + var stack = PolymerItem.super.getPolymerItemStack(original, tooltipType, lookup, player); + var dest = original.get(FunnyRegistry.TELEPORTER_DESTINATION); + if (dest != null) { + stack.set(DataComponentTypes.LORE, new LoreComponent(dest.formatName("Linked to"))); + } + return stack; + } + + @Override + public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) { + var stack = user.getStackInHand(hand); + if (user.isSneaking()) { + if (stack.remove(FunnyRegistry.TELEPORTER_DESTINATION) != null) { + user.sendMessage(Text.literal("Cleared saved destination.")); + } + } + return TypedActionResult.success(stack, world.isClient()); + } + + @Override public ActionResult useOnBlock(ItemUsageContext context) { var destination = context.getStack().get(FunnyRegistry.TELEPORTER_DESTINATION); var block = context.getWorld().getBlockState(context.getBlockPos()).getBlock(); @@ -34,9 +65,8 @@ public class TeleporterWand extends Item implements PolymerItem { if (context.getPlayer() != null && context.getPlayer().isSneaking()) { context.getStack().set(FunnyRegistry.TELEPORTER_DESTINATION, new TeleporterDestination(context.getWorld().getRegistryKey(), context.getBlockPos())); context.getPlayer().sendMessage(Text.literal("Saved teleport destination to wand.")); - } else { + } else if (destination != null){ var be = FunnyRegistry.TELEPORTER.getBE(context.getWorld(), context.getBlockPos()); - // TODO: check for empty destination be.destination = destination; be.markDirty(); if (context.getPlayer() != null) { diff --git a/src/main/java/moe/nea/funnyteleporters/Utils.java b/src/main/java/moe/nea/funnyteleporters/Utils.java index 9fae3d1..b0a1649 100644 --- a/src/main/java/moe/nea/funnyteleporters/Utils.java +++ b/src/main/java/moe/nea/funnyteleporters/Utils.java @@ -3,7 +3,9 @@ package moe.nea.funnyteleporters; import net.minecraft.component.DataComponentTypes; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.text.Style; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.Unit; import java.util.Iterator; @@ -21,4 +23,12 @@ public class Utils { it.next(); } } + + public static Style emptyLoreStyle() { + return Style.EMPTY.withItalic(false); + } + + public static Style colouredLoreStyle(Formatting formatting) { + return emptyLoreStyle().withColor(formatting); + } } |