aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de
diff options
context:
space:
mode:
authorFluboxer <36457056+Fluboxer@users.noreply.github.com>2025-01-05 05:05:09 +0300
committerGitHub <noreply@github.com>2025-01-05 10:05:09 +0800
commit6d8592cd9663e97c8bbc7f987df3506e535f88d0 (patch)
treefa5861b159b0e6c927ac889376e95b70e0c731a3 /src/main/java/de
parent180408fabb236c1ee8a26206921695d97984ad98 (diff)
downloadSkyblocker-6d8592cd9663e97c8bbc7f987df3506e535f88d0.tar.gz
Skyblocker-6d8592cd9663e97c8bbc7f987df3506e535f88d0.tar.bz2
Skyblocker-6d8592cd9663e97c8bbc7f987df3506e535f88d0.zip
Corpse Finder (#960)
* early one. Needs polishing and config * 2nd wave of changes * a little refactor to parsing. New version is yet to be tested * another little patch to solve some silly issues * Fixed bug when some of corpses weren't highlighted. Also rebased * a little refactor to parsing. New version is yet to be tested * dementia * moved few code blocks around * Remove unused constructor * Simplify and reformat getColor method * Fix typo in log messager * Change the way the argument values are obtained and fix formatting * Extract coords pattern into a PSF variable * More formatting * Oops forgot to remove + fix typo * Clear corpses on world change * Rebased for 1.21.3 * Tweak chat message slightly * Inline LOCATION variable as it was hard to read * Bunch of stuff - Changed sent position format to match what we're reading - Extracted item id strings to PSF variables and then made a bimap between them and the corpse type that uses them. - Changed debug message to be printed in chat rather than logs to be more easily seen - Simplified and/or reformatted a bunch of code - Changed log level of some messages to `debug` * Add a debug config for corpse finder and have it toggled off by default * Fix regex and change sent message format This should allow skyhanni users to be able to parse the messages sent by skyblocker users since their regex starts matching from the start of the message content (so after any prefixes, player names) The regex change was also because of this. We use .find so the regex doesn't have to match the whole message body. * Refactor some if checks * Add auto location sharing, off by default * Corrected format and ignore player's own messages * Oops one too many inversed * Change CorpseTypeArgumentType to use StringIdentifiable and format Waypoint constructors * Migrate to CorpseType enum * Update getting enum * Wrap int parsing in try catch for possibly malformed inputs * Don't allow negative y values * Add a locale to toUpperCase * Fix rebase artifacts * Add seen waypoint todo --------- Co-authored-by: Rime <81419447+Emirlol@users.noreply.github.com> Co-authored-by: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com>
Diffstat (limited to 'src/main/java/de')
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/DebugCategory.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java26
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/DebugConfig.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CorpseFinder.java318
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java8
7 files changed, 371 insertions, 3 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DebugCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DebugCategory.java
index 9ff08e2f..a09040a0 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/DebugCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/DebugCategory.java
@@ -44,6 +44,13 @@ public class DebugCategory {
newValue -> config.debug.dumpFormat = newValue)
.controller(opt -> EnumControllerBuilder.create(opt).enumClass(Debug.DumpFormat.class)) // ConfigUtils::createEnumCyclingListController causes a NPE for some reason
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.debug.corpseFinderDebug"))
+ .binding(defaults.debug.corpseFinderDebug,
+ () -> config.debug.corpseFinderDebug,
+ newValue -> config.debug.corpseFinderDebug = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
.build();
}
}
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
index d12f523a..890d86aa 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
@@ -250,12 +250,36 @@ public class MiningCategory {
.collapsed(false)
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.mining.glacite.coldOverlay"))
- .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.glacite.coldOverlay@Tooltip")))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.glacite.coldOverlay.@Tooltip")))
.binding(defaults.mining.glacite.coldOverlay,
() -> config.mining.glacite.coldOverlay,
newValue -> config.mining.glacite.coldOverlay = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.glacite.enableCorpseFinder"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.glacite.enableCorpseFinder.@Tooltip")))
+ .binding(defaults.mining.glacite.enableCorpseFinder,
+ () -> config.mining.glacite.enableCorpseFinder,
+ newValue -> config.mining.glacite.enableCorpseFinder = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.glacite.enableParsingChatCorpseFinder"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.glacite.enableParsingChatCorpseFinder.@Tooltip")))
+ .binding(defaults.mining.glacite.enableParsingChatCorpseFinder,
+ () -> config.mining.glacite.enableParsingChatCorpseFinder,
+ newValue -> config.mining.glacite.enableParsingChatCorpseFinder = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.glacite.autoShareCorpses"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.glacite.autoShareCorpses.@Tooltip")))
+ .binding(defaults.mining.glacite.autoShareCorpses,
+ () -> config.mining.glacite.autoShareCorpses,
+ newValue -> config.mining.glacite.autoShareCorpses = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
.build())
.build();
}
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DebugConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DebugConfig.java
index 80023631..df0a69c6 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/DebugConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/DebugConfig.java
@@ -15,4 +15,7 @@ public class DebugConfig {
@SerialEntry
public boolean webSocketDebug = false;
+
+ @SerialEntry
+ public boolean corpseFinderDebug = false;
}
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
index 201c5c49..f73f38a9 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
@@ -164,6 +164,15 @@ public class MiningConfig {
public static class Glacite {
@SerialEntry
public boolean coldOverlay = true;
+
+ @SerialEntry
+ public boolean enableCorpseFinder = true;
+
+ @SerialEntry
+ public boolean enableParsingChatCorpseFinder = true;
+
+ @SerialEntry
+ public boolean autoShareCorpses = false;
}
public enum DwarvenHudStyle {
diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
index 79f45a32..cf4d2060 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
@@ -11,6 +11,7 @@ import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder;
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
+import de.hysky.skyblocker.skyblock.dwarven.CorpseFinder;
import de.hysky.skyblocker.skyblock.dwarven.CrystalsChestHighlighter;
import de.hysky.skyblocker.skyblock.dwarven.WishingCompassSolver;
import de.hysky.skyblocker.skyblock.end.EnderNodes;
@@ -57,6 +58,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
if (SkyblockerConfigManager.get().slayers.blazeSlayer.firePillarCountdown != SlayersConfig.BlazeSlayer.FirePillar.OFF) FirePillarAnnouncer.checkFirePillar(entity);
EggFinder.checkIfEgg(armorStandEntity);
+ CorpseFinder.checkIfCorpse(armorStandEntity);
try { //Prevent packet handling fails if something goes wrong so that entity trackers still update, just without compact damage numbers
CompactDamage.compactDamage(armorStandEntity);
} catch (Exception e) {
@@ -94,6 +96,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
@Inject(method = "onEntityEquipmentUpdate", at = @At(value = "TAIL"))
private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) {
EggFinder.checkIfEgg(entity);
+ CorpseFinder.checkIfCorpse(entity);
}
@Inject(method = "onPlayerListHeader", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/PlayerListHud;setFooter(Lnet/minecraft/text/Text;)V"))
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CorpseFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CorpseFinder.java
new file mode 100644
index 00000000..f3dd9aab
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CorpseFinder.java
@@ -0,0 +1,318 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.serialization.Codec;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.annotations.Init;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.debug.Debug;
+import de.hysky.skyblocker.events.SkyblockEvents;
+import de.hysky.skyblocker.utils.*;
+import de.hysky.skyblocker.utils.command.argumenttypes.blockpos.ClientBlockPosArgumentType;
+import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
+import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.command.argument.EnumArgumentType;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.decoration.ArmorStandEntity;
+import net.minecraft.text.ClickEvent;
+import net.minecraft.text.HoverEvent;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+import net.minecraft.util.StringIdentifiable;
+import net.minecraft.util.Util;
+import net.minecraft.util.math.BlockPos;
+import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.text.WordUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+public class CorpseFinder {
+ private static boolean isLocationCorrect = false;
+ private static final Pattern CORPSE_FOUND_PATTERN = Pattern.compile("([A-Z]+) CORPSE LOOT!");
+ private static final Pattern COORDS_PATTERN = Pattern.compile("x: (?<x>-?\\d+), y: (?<y>\\d+), z: (?<z>-?\\d+)");
+ private static final String PREFIX = "[Skyblocker Corpse Finder] ";
+ private static final Logger LOGGER = LoggerFactory.getLogger(CorpseFinder.class);
+ private static final Map<CorpseType, List<Corpse>> corpsesByType = new EnumMap<>(CorpseType.class);
+ private static final String LAPIS_HELMET = "LAPIS_ARMOR_HELMET";
+ private static final String UMBER_HELMET = "ARMOR_OF_YOG_HELMET";
+ private static final String TUNGSTEN_HELMET = "MINERAL_HELMET";
+ private static final String VANGUARD_HELMET = "VANGUARD_HELMET";
+
+ @Init
+ public static void init() {
+ ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> {
+ isLocationCorrect = false;
+ corpsesByType.clear();
+ });
+ SkyblockEvents.LOCATION_CHANGE.register(CorpseFinder::handleLocationChange);
+ ClientReceiveMessageEvents.GAME.register(CorpseFinder::onChatMessage);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(CorpseFinder::renderWaypoints);
+ ClientTickEvents.END_CLIENT_TICK.register(client -> {
+ if (!SkyblockerConfigManager.get().mining.glacite.enableCorpseFinder || client.player == null) return;
+ if (!isLocationCorrect) return;
+ for (List<Corpse> corpses : corpsesByType.values()) {
+ for (Corpse corpse : corpses) {
+ if (!corpse.seen && client.player.canSee(corpse.entity)) {
+ setSeen(corpse);
+ }
+ }
+ }
+ });
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE)
+ .then(literal("corpseHelper")
+ .then(literal("shareLocation")
+ .then(argument("blockPos", ClientBlockPosArgumentType.blockPos())
+ .then(argument("corpseType", CorpseType.CorpseTypeArgumentType.corpseType())
+ .executes(context -> {
+ shareLocation(ClientBlockPosArgumentType.getBlockPos(context, "blockPos"), CorpseType.CorpseTypeArgumentType.getCorpseType(context, "corpseType"));
+ return Command.SINGLE_SUCCESS;
+ })
+ )
+ )
+ )
+ )
+ ));
+ }
+
+ private static boolean seenDebugWarning = false;
+
+ private static void handleLocationChange(Location location) {
+ isLocationCorrect = location == Location.GLACITE_MINESHAFT;
+ }
+
+ public static void checkIfCorpse(Entity entity) {
+ if (entity instanceof ArmorStandEntity armorStand) checkIfCorpse(armorStand);
+ }
+
+ public static void checkIfCorpse(ArmorStandEntity armorStand) {
+ if (!isLocationCorrect || !SkyblockerConfigManager.get().mining.glacite.enableCorpseFinder) return;
+ if (armorStand.hasCustomName() || armorStand.isInvisible() || armorStand.shouldShowBasePlate()) return;
+ handleArmorStand(armorStand);
+ }
+
+ private static void handleArmorStand(ArmorStandEntity armorStand) {
+ String helmetItemId = ItemUtils.getItemId(armorStand.getEquippedStack(EquipmentSlot.HEAD));
+ CorpseType corpseType = CorpseType.fromHelmetItemId(helmetItemId);
+ if (corpseType == CorpseType.UNKNOWN) return;
+
+ LOGGER.debug(PREFIX + "Triggered code for handleArmorStand and matched with ITEM_IDS");
+ List<Corpse> corpses = corpsesByType.computeIfAbsent(corpseType, k -> new ArrayList<>());
+ if (corpses.stream().noneMatch(c -> c.entity.getBlockPos().equals(armorStand.getBlockPos()))) {
+ Waypoint corpseWaypoint;
+ float[] color = getColors(corpseType.color);
+ corpseWaypoint = new Waypoint(armorStand.getBlockPos().up(), Waypoint.Type.OUTLINED_WAYPOINT, color);
+ if (Debug.debugEnabled() && SkyblockerConfigManager.get().debug.corpseFinderDebug && !seenDebugWarning && (seenDebugWarning = true)) {
+ MinecraftClient.getInstance().player.sendMessage(
+ Constants.PREFIX.get().append(
+ Text.literal("Corpse finder debug mode is active! Please use it only for the sake of debugging corpse detection!")
+ .formatted(Formatting.GOLD, Formatting.BOLD)
+ ), false);
+ }
+ Corpse newCorpse = new Corpse(armorStand, corpseWaypoint, corpseType);
+ corpses.add(newCorpse);
+ }
+ }
+
+ private static void renderWaypoints(WorldRenderContext context) {
+ if (!SkyblockerConfigManager.get().mining.glacite.enableCorpseFinder || !isLocationCorrect) return;
+ for (List<Corpse> corpses : corpsesByType.values()) {
+ for (Corpse corpse : corpses) {
+ if (corpse.waypoint.shouldRender() && (corpse.seen || (Debug.debugEnabled() && SkyblockerConfigManager.get().debug.corpseFinderDebug))) {
+ corpse.waypoint.render(context);
+ }
+ }
+ }
+ }
+
+ private static void onChatMessage(Text text, boolean overlay) {
+ if (overlay || !isLocationCorrect || !SkyblockerConfigManager.get().mining.glacite.enableCorpseFinder || MinecraftClient.getInstance().player == null) return;
+ String string = text.getString();
+ if (string.contains(MinecraftClient.getInstance().getSession().getUsername())) return; // Ignore your own messages
+ if (SkyblockerConfigManager.get().mining.glacite.enableParsingChatCorpseFinder) parseCords(text); // parsing cords from chat
+
+ Matcher matcherCorpse = CORPSE_FOUND_PATTERN.matcher(string);
+ if (!matcherCorpse.find()) return;
+
+ LOGGER.debug(PREFIX + "Triggered code for onChatMessage");
+ LOGGER.debug(PREFIX + "State of corpsesByType: {}", corpsesByType);
+ String corpseTypeString = matcherCorpse.group(1).toUpperCase(Locale.ENGLISH);
+ CorpseType corpseType = EnumUtils.getEnum(CorpseType.class, corpseTypeString, CorpseType.UNKNOWN);
+
+ List<Corpse> corpses = corpsesByType.get(corpseType);
+ if (corpses == null) {
+ LOGGER.warn(PREFIX + "Couldn't get corpses! corpse type string: {}, parsed corpse type: {}", corpseTypeString, corpseType);
+ return;
+ }
+ corpses.stream() // Since squared distance comparison will yield the same result as normal distance comparison, we can use squared distance to avoid square root calculation
+ .min(Comparator.comparingDouble(corpse -> corpse.entity.squaredDistanceTo(MinecraftClient.getInstance().player)))
+ .ifPresentOrElse(
+ corpse -> {
+ LOGGER.info(PREFIX + "Found corpse, marking as found! {}: {}", corpse.entity.getType(), corpse.entity.getBlockPos().toShortString());
+ corpse.waypoint.setFound();
+ },
+ () -> LOGGER.warn(PREFIX + "Couldn't find the closest corpse despite triggering onChatMessage!")
+ );
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ private static void setSeen(Corpse corpse) {
+ corpse.seen = true;
+ if (SkyblockerConfigManager.get().mining.glacite.autoShareCorpses) {
+ shareLocation(corpse.entity.getBlockPos().up(), corpse.corpseType);
+ return; // There's no need to send the message twice, so we return here.
+ }
+ if (Util.getMeasuringTimeMs() - corpse.messageLastSent < 300) return;
+
+ corpse.messageLastSent = Util.getMeasuringTimeMs();
+
+ MinecraftClient.getInstance().player.sendMessage(
+ Constants.PREFIX.get()
+ .append("Found a ")
+ .append(Text.literal(WordUtils.capitalizeFully(corpse.corpseType.asString()) + " Corpse")
+ .withColor(corpse.corpseType.color.getColorValue()))
+ .append(" at " + corpse.entity.getBlockPos().up().toShortString() + "!")
+ .styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker corpseHelper shareLocation " + PosUtils.toSpaceSeparatedString(corpse.waypoint.pos) + " " + corpse.corpseType))
+ .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal("Click to share the location in chat!").formatted(Formatting.GREEN)))), false);
+ }
+
+ private static void shareLocation(BlockPos pos, CorpseType corpseType) {
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown("/pc " + toSkyhanniFormat(pos) + " | (" + WordUtils.capitalizeFully(corpseType.asString()) + " Corpse)", true);
+ }
+
+ @SuppressWarnings("DataFlowIssue")
+ private static float[] getColors(Formatting color) {
+ return ColorUtils.getFloatComponents(color.getColorValue());
+ }
+
+ // Since read in their format, might as well send in their format too.
+ // Some other mods seem to send in this same format, so it'll help any other mods that might be listening for this format.
+ private static String toSkyhanniFormat(BlockPos pos) {
+ return String.format("x: %d, y: %d, z: %d", pos.getX() + 1, pos.getY(), pos.getZ() + 1);
+ }
+
+ private static void parseCords(Text text) {
+ String message = text.getString();
+ Matcher matcher = COORDS_PATTERN.matcher(message);
+ if (!matcher.find()) return;
+
+ int x, y, z;
+ try {
+ x = Integer.parseInt(matcher.group("x"));
+ y = Integer.parseInt(matcher.group("y"));
+ z = Integer.parseInt(matcher.group("z"));
+ } catch (NumberFormatException e) {
+ LOGGER.warn(PREFIX + "Failed to parse message: `{}`, reason: {}", message, e.getMessage());
+ return;
+ }
+
+ LOGGER.debug(PREFIX + "Parsed message! X:{}, Y:{}, Z:{}", x, y, z);
+ boolean foundCorpse = false;
+ BlockPos parsedPos = new BlockPos(x - 1, y, z - 1); // skyhanni cords format difference is -1, 0, -1
+
+ for (List<Corpse> corpses : corpsesByType.values()) {
+ for (Corpse corpse : corpses) {
+ if (corpse.waypoint.pos.equals(parsedPos)) {
+ corpse.seen = true;
+ foundCorpse = true;
+ LOGGER.info(PREFIX + "Setting corpse {} as seen!", corpse.entity);
+ MinecraftClient.getInstance().player.sendMessage(
+ Constants.PREFIX.get()
+ .append("Parsed message from chat, adding corpse at ")
+ .append(corpse.entity.getBlockPos().toShortString()), false);
+ break;
+ }
+ }
+ }
+ if (!foundCorpse) {
+ LOGGER.warn(PREFIX + "Did NOT find any match for corpses! corpsesByType.values(): {}", corpsesByType.values());
+ LOGGER.info(PREFIX + "Proceeding to iterate over all corpses!");
+ for (List<Corpse> corpses : corpsesByType.values()) {
+ for (Corpse corpse : corpses) {
+ LOGGER.info(PREFIX + "Corpse: {}, BlockPos: {}", corpse.entity, corpse.entity.getBlockPos());
+ }
+ }
+ }
+ }
+
+ enum CorpseType implements StringIdentifiable {
+ LAPIS(LAPIS_HELMET, Formatting.BLUE), // dark blue looks bad and these two never exist in same shaft
+ UMBER(UMBER_HELMET, Formatting.RED),
+ TUNGSTEN(TUNGSTEN_HELMET, Formatting.GRAY),
+ VANGUARD(VANGUARD_HELMET, Formatting.BLUE),
+ UNKNOWN("UNKNOWN", Formatting.YELLOW);
+ private static final Codec<CorpseType> CODEC = StringIdentifiable.createCodec(CorpseType::values);
+ private final String helmetItemId;
+ private final Formatting color;
+
+ CorpseType(String helmetItemId, Formatting color) {
+ this.helmetItemId = helmetItemId;
+ this.color = color;
+ }
+
+ static CorpseType fromHelmetItemId(String helmetItemId) {
+ for (CorpseType value : values()) {
+ if (value.helmetItemId.equals(helmetItemId)) {
+ return value;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ @Override
+ public String asString() {
+ return name().toLowerCase();
+ }
+
+ static class CorpseTypeArgumentType extends EnumArgumentType<CorpseType> {
+ protected CorpseTypeArgumentType() {
+ super(CODEC, CorpseType::values);
+ }
+
+ static CorpseTypeArgumentType corpseType() {
+ return new CorpseTypeArgumentType();
+ }
+
+ static <S> CorpseType getCorpseType(CommandContext<S> context, String name) {
+ return context.getArgument(name, CorpseType.class);
+ }
+ }
+ }
+
+ static class Corpse {
+ private final ArmorStandEntity entity;
+ /**
+ * Waypoint position is always 1 above entity position
+ */
+ private final Waypoint waypoint;
+ /**
+ * Type of the corpse, fully uppercased.
+ */
+ private final CorpseType corpseType;
+ // TODO: migrate to seen waypoint #1108
+ private boolean seen;
+ private long messageLastSent = 0;
+
+ Corpse(ArmorStandEntity entity, Waypoint waypoint, CorpseType corpseType) {
+ this.entity = entity;
+ this.waypoint = waypoint;
+ this.seen = false;
+ this.corpseType = corpseType;
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java
index 499e605d..cd07ac58 100644
--- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java
+++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java
@@ -44,14 +44,18 @@ public class Waypoint implements Renderable {
this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, DEFAULT_LINE_WIDTH);
}
- public Waypoint(BlockPos pos, Type type, float[] colorComponents, float alpha) {
- this(pos, () -> type, colorComponents, alpha, DEFAULT_LINE_WIDTH);
+ public Waypoint(BlockPos pos, Type type, float[] colorComponents, float alpha) { // @formatter:off
+ this(pos, () -> type, colorComponents, alpha, DEFAULT_LINE_WIDTH); // @formatter:on
}
public Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha, float lineWidth) {
this(pos, typeSupplier, colorComponents, alpha, lineWidth, true);
}
+ public Waypoint(BlockPos pos, Type type, float[] colorComponents, boolean throughWalls) { // @formatter:off
+ this(pos, () -> type, colorComponents, throughWalls); // @formatter:on
+ }
+
public Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, boolean throughWalls) {
this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, DEFAULT_LINE_WIDTH, throughWalls);
}