diff --git a/src/main/java/com/lovetropics/extras/client/screen/map/PoiButton.java b/src/main/java/com/lovetropics/extras/client/screen/map/PoiButton.java index b6529f12..0c1212f2 100644 --- a/src/main/java/com/lovetropics/extras/client/screen/map/PoiButton.java +++ b/src/main/java/com/lovetropics/extras/client/screen/map/PoiButton.java @@ -15,6 +15,7 @@ class PoiButton extends AbstractButton { private static final int ICON_SIZE = 16; + private static final int HALF_ICON_SIZE = ICON_SIZE / 2; private static final int BORDER_SIZE = 3; private static final int SIZE = ICON_SIZE + BORDER_SIZE * 2; private static final int TOOLTIP_HEIGHT = 18; @@ -22,6 +23,7 @@ class PoiButton extends AbstractButton { private static final int HOVER_ANIMATION_LENGTH = 8; private static final ResourceLocation TOOLTIP_LOCATION = new ResourceLocation("textures/gui/advancements/widgets.png"); + private static final ResourceLocation SPECIAL_MARKER = new ResourceLocation("textures/item/bell.png"); private final Poi poi; private final Font font; @@ -91,6 +93,10 @@ protected void renderWidget(final GuiGraphics graphics, final int mouseX, final final ResourceLocation icon = poi.resourceLocation(); graphics.blit(icon, getX() + BORDER_SIZE, getY() + BORDER_SIZE, zOffset, 0.0f, 0.0f, ICON_SIZE, ICON_SIZE, ICON_SIZE, ICON_SIZE); + + if (poi.isMarkSpecial()) { + graphics.blit(SPECIAL_MARKER, getX() + BORDER_SIZE + HALF_ICON_SIZE, getY() + BORDER_SIZE + HALF_ICON_SIZE, zOffset, 0.0f, 0.0f, HALF_ICON_SIZE, HALF_ICON_SIZE, HALF_ICON_SIZE, HALF_ICON_SIZE); + } } @Override diff --git a/src/main/java/com/lovetropics/extras/command/PoiCommand.java b/src/main/java/com/lovetropics/extras/command/PoiCommand.java index c301ab4e..798d004c 100644 --- a/src/main/java/com/lovetropics/extras/command/PoiCommand.java +++ b/src/main/java/com/lovetropics/extras/command/PoiCommand.java @@ -154,8 +154,9 @@ private static int addWithDefaults(CommandContext ctx) { final ResourceLocation icon = getId(ctx, "icon"); final GlobalPos globalPos = GlobalPos.of(ctx.getSource().getLevel().dimension(), ctx.getSource().getPlayer().getOnPos().above()); final boolean enabled = false; + final boolean markSpecial = false; - final Poi newPoi = new Poi(name, description, icon, globalPos, enabled); + final Poi newPoi = new Poi(name, description, icon, globalPos, enabled, markSpecial); MapPoiManager.get(ctx.getSource().getServer()).add(newPoi); ctx.getSource().sendSuccess(() -> Component.literal("Added new disabled POI " + newPoi.name() + " at your current position"), false); return Command.SINGLE_SUCCESS; @@ -236,8 +237,9 @@ private static Poi createPoiFromCtx(CommandContext ctx) { final WorldCoordinates worldCoordinates = ctx.getArgument("blockpos", WorldCoordinates.class); final GlobalPos globalPos = GlobalPos.of(ctx.getSource().getLevel().dimension(), worldCoordinates.getBlockPos(ctx.getSource())); final boolean enabled = getBool(ctx, "enabled"); + final boolean markSpecial = false; - return new Poi(name, description, icon, globalPos, enabled); + return new Poi(name, description, icon, globalPos, enabled, markSpecial); } private static Stream suggestGlobalPos(CommandContext ctx) { diff --git a/src/main/java/com/lovetropics/extras/data/poi/MapPoiManager.java b/src/main/java/com/lovetropics/extras/data/poi/MapPoiManager.java index 1f29afd1..68f485a5 100644 --- a/src/main/java/com/lovetropics/extras/data/poi/MapPoiManager.java +++ b/src/main/java/com/lovetropics/extras/data/poi/MapPoiManager.java @@ -3,24 +3,28 @@ import com.lovetropics.extras.LTExtras; import com.lovetropics.extras.network.ClientboundPoiPacket; import com.lovetropics.extras.network.LTExtrasNetwork; +import com.lovetropics.extras.schedule.StreamSchedule; +import com.lovetropics.lib.permission.PermissionsApi; +import com.lovetropics.lib.permission.role.RoleOverrideType; +import com.lovetropics.lib.permission.role.RoleReader; import com.mojang.serialization.Codec; import net.minecraft.Util; +import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.saveddata.SavedData; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.network.PacketDistributor; import javax.annotation.Nullable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -33,8 +37,10 @@ public class MapPoiManager extends SavedData { public static final BoundingBox MAP_BB = new BoundingBox(2013, 0, 1883, 2910, 0, 2799); private static final Codec> CODEC = Codec.unboundedMap(Codec.STRING, Poi.CODEC); private static final String STORAGE_ID = LTExtras.MODID + "_map_poi"; + private static final RoleOverrideType HOST_ROLE = (RoleOverrideType) RoleOverrideType.byId("host"); private final Map pois; + public MapPoiManager(final Map pois) { this.pois = pois; } @@ -77,6 +83,58 @@ public Set getEnabledPois() { .collect(Collectors.toSet()); } + //TODO where would a better place to hook this into be? seems expensive here + @SubscribeEvent + public static void onServerTick(TickEvent.ServerTickEvent event) { + if (event.getServer().getTickCount() % 20 != 0) { + return; + } + + //TODO: if there is no host, skip all this. can we know if there is a host without looking at all players? + + Optional firstHost = event.getServer().getPlayerList().getPlayers() + .stream() + .filter(p -> PermissionsApi.lookup().byPlayer(p).overrides().test(HOST_ROLE)) + .findFirst(); + + if (firstHost.isEmpty()) { + //TODO just for testing, remove before merging + firstHost = Optional.ofNullable(event.getServer().getPlayerList().getPlayerByName("Dev2")); + if (firstHost.isEmpty()) { + return; + } + } + + final ServerPlayer host = firstHost.get(); + final BlockPos hostPosition = host.blockPosition(); + + final MapPoiManager manager = MapPoiManager.get(event.getServer()); + final Optional min = manager.getEnabledPois() + .stream() + .min(Comparator.comparingDouble(p -> p.globalPos().pos().distSqr(hostPosition))); + + if (min.isEmpty()) { + return; + } + + final Poi nearestPoi = min.get(); + manager.markSpecial(nearestPoi.name()); + } + + public void markSpecial(String name) { + pois.values() + .stream().filter(Poi::isMarkSpecial) + .map(p -> p.setMarkSpecial(false)) + .forEach(p -> LTExtrasNetwork.CHANNEL.send(PacketDistributor.ALL.noArg(), new ClientboundPoiPacket(p, false))); + + final Poi poi = pois.get(name); + if (poi != null) { + poi.setMarkSpecial(true); + LTExtrasNetwork.CHANNEL.send(PacketDistributor.ALL.noArg(), new ClientboundPoiPacket(poi, false)); + } + setDirty(); + } + public Set getDisabledPois() { return pois.values().stream() .filter(Predicate.not(Poi::enabled)) diff --git a/src/main/java/com/lovetropics/extras/data/poi/Poi.java b/src/main/java/com/lovetropics/extras/data/poi/Poi.java index fa2e821d..bd3ebea9 100644 --- a/src/main/java/com/lovetropics/extras/data/poi/Poi.java +++ b/src/main/java/com/lovetropics/extras/data/poi/Poi.java @@ -15,7 +15,8 @@ public final class Poi { ExtraCodecs.COMPONENT.fieldOf("description").forGetter(Poi::description), ResourceLocation.CODEC.fieldOf("resourceLocation").forGetter(Poi::resourceLocation), GlobalPos.CODEC.fieldOf("blockPos").forGetter(Poi::globalPos), - Codec.BOOL.fieldOf("enabled").forGetter(Poi::enabled) + Codec.BOOL.fieldOf("enabled").forGetter(Poi::enabled), + Codec.BOOL.fieldOf("markSpecial").forGetter(Poi::isMarkSpecial) ).apply(i, Poi::new)); private final String name; @@ -23,18 +24,21 @@ public final class Poi { private final ResourceLocation resourceLocation; private final GlobalPos globalPos; private boolean enabled; + private boolean markSpecial; public Poi( String name, Component description, ResourceLocation resourceLocation, GlobalPos globalPos, - boolean enabled) { + boolean enabled, + boolean markSpecial) { this.name = name; this.description = description; this.resourceLocation = resourceLocation; this.globalPos = globalPos; this.enabled = enabled; + this.markSpecial = markSpecial; } //Use only the name for equals&hashCode. Maybe tiny bit risky but dupe handling is free @@ -71,6 +75,15 @@ public boolean enabled() { return enabled; } + public boolean isMarkSpecial() { + return markSpecial; + } + + public Poi setMarkSpecial(boolean markSpecial) { + this.markSpecial = markSpecial; + return this; + } + @Override public String toString() { return "Poi[" + diff --git a/src/main/java/com/lovetropics/extras/network/ClientboundPoiPacket.java b/src/main/java/com/lovetropics/extras/network/ClientboundPoiPacket.java index 55017a93..f158faec 100644 --- a/src/main/java/com/lovetropics/extras/network/ClientboundPoiPacket.java +++ b/src/main/java/com/lovetropics/extras/network/ClientboundPoiPacket.java @@ -3,7 +3,6 @@ import com.lovetropics.extras.client.ClientMapPoiManager; import com.lovetropics.extras.data.poi.Poi; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; @@ -14,6 +13,7 @@ public ClientboundPoiPacket(final FriendlyByteBuf input) { input.readComponent(), input.readResourceLocation(), input.readGlobalPos(), + input.readBoolean(), input.readBoolean()), input.readBoolean()); } @@ -24,6 +24,7 @@ public void write(final FriendlyByteBuf output) { output.writeResourceLocation(poi.resourceLocation()); output.writeGlobalPos(poi.globalPos()); output.writeBoolean(poi.enabled()); + output.writeBoolean(poi.isMarkSpecial()); output.writeBoolean(delete); }