diff options
| author | Peyton Brown <81496880+PeytonBrown@users.noreply.github.com> | 2025-06-10 04:50:11 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-10 04:50:11 -0400 |
| commit | b84dd664e4656ee0c8fd82fc1caa10cbbccf6c21 (patch) | |
| tree | a25be13b28c091188721ecb1800269721b95e5b1 /src/main/java | |
| parent | fa012efe78f477c9cb766858e220e26251f390c8 (diff) | |
| download | Skyblocker-b84dd664e4656ee0c8fd82fc1caa10cbbccf6c21.tar.gz Skyblocker-b84dd664e4656ee0c8fd82fc1caa10cbbccf6c21.tar.bz2 Skyblocker-b84dd664e4656ee0c8fd82fc1caa10cbbccf6c21.zip | |
Add waypoints to forest nodes (#1325)
* Initial Implementation
* Remove waypoint if block is right clicked
* Changed to HIGHLIGHT waypoint type
* Remove from list if not seen for 5 seconds
* resolve pr comments
Diffstat (limited to 'src/main/java')
4 files changed, 194 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/ForagingCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/ForagingCategory.java index d5c844b7..81e64ea4 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/ForagingCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/ForagingCategory.java @@ -1,7 +1,10 @@ package de.hysky.skyblocker.config.categories; +import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; import dev.isxander.yacl3.api.ConfigCategory; +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.OptionGroup; import net.minecraft.text.Text; public class ForagingCategory { @@ -9,9 +12,21 @@ public class ForagingCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("skyblocker.config.foraging")) - //Modern Foraging island + //Galatea + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.foraging.galatea")) + .collapsed(false) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("skyblocker.config.foraging.galatea.enableForestNodeHelper")) + .binding(defaults.foraging.galatea.enableForestNodeHelper, + () -> config.foraging.galatea.enableForestNodeHelper, + newValue -> config.foraging.galatea.enableForestNodeHelper = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) + //Hunting - YACL doesn't like empty option groups /*.group(OptionGroup.createBuilder() .name(Text.translatable("skyblocker.config.foraging.hunting")) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/ForagingConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/ForagingConfig.java index 1a7c3598..aa4dcc6d 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/ForagingConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/ForagingConfig.java @@ -5,8 +5,16 @@ import dev.isxander.yacl3.config.v2.api.SerialEntry; public class ForagingConfig { @SerialEntry + public Galatea galatea = new Galatea(); + + @SerialEntry public Hunting hunting = new Hunting(); + public static class Galatea { + @SerialEntry + public boolean enableForestNodeHelper = true; + } + public static class Hunting { } diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index 6372bd4d..22e921ff 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -24,6 +24,7 @@ import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.fishing.FishingHelper; import de.hysky.skyblocker.skyblock.fishing.FishingHookDisplayHelper; import de.hysky.skyblocker.skyblock.fishing.SeaCreatureTracker; +import de.hysky.skyblocker.skyblock.galatea.ForestNodes; import de.hysky.skyblocker.skyblock.slayers.SlayerManager; import de.hysky.skyblocker.skyblock.slayers.boss.demonlord.FirePillarAnnouncer; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListManager; @@ -186,6 +187,7 @@ public abstract class ClientPlayNetworkHandlerMixin extends ClientCommonNetworkH DojoManager.onParticle(packet); CrystalsChestHighlighter.onParticle(packet); EnderNodes.onParticle(packet); + ForestNodes.onParticle(packet); WishingCompassSolver.onParticle(packet); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/galatea/ForestNodes.java b/src/main/java/de/hysky/skyblocker/skyblock/galatea/ForestNodes.java new file mode 100644 index 00000000..01819f47 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/galatea/ForestNodes.java @@ -0,0 +1,168 @@ +package de.hysky.skyblocker.skyblock.galatea; + +import de.hysky.skyblocker.annotations.Init; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.ColorUtils; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import de.hysky.skyblocker.utils.waypoint.Waypoint; +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.fabricmc.fabric.api.event.player.AttackBlockCallback; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.decoration.DisplayEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.particle.ParticleType; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.ActionResult; +import net.minecraft.util.DyeColor; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class ForestNodes { + private static final Logger LOGGER = LoggerFactory.getLogger(ForestNodes.class); + private static final MinecraftClient client = MinecraftClient.getInstance(); + private static final Map<BlockPos, ForestNode> forestNodes = new HashMap<>(); + + @Init + public static void init() { + Scheduler.INSTANCE.scheduleCyclic(ForestNodes::update, 20); + WorldRenderEvents.AFTER_TRANSLUCENT.register(ForestNodes::render); + AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> { + if (!shouldProcess()) { + return ActionResult.PASS; + } + forestNodes.remove(pos); + return ActionResult.PASS; + }); + UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> { + if (!shouldProcess()) { + return ActionResult.PASS; + } + BlockPos pos = hitResult.getBlockPos(); + forestNodes.remove(pos); + return ActionResult.PASS; + }); + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset()); + } + + public static void onParticle(ParticleS2CPacket packet) { + if (!shouldProcess()) { + return; + } + + ParticleType<?> particleType = packet.getParameters().getType(); + if (!ParticleTypes.HAPPY_VILLAGER.getType().equals(particleType)) { + return; + } + + double x = packet.getX(); + double y = packet.getY() - 1; + double z = packet.getZ(); + BlockPos pos = BlockPos.ofFloored(x, y, z); + + // Check for three ItemDisplayEntity with minecraft:string in the same block + if (client.world != null) { + int stringItemCount = countStringItemDisplays(pos); + if (stringItemCount == 3) { + forestNodes.computeIfAbsent(pos, ForestNode::new); + } + } + } + + private static int countStringItemDisplays(BlockPos pos) { + ClientWorld world = client.world; + if (world == null) { + return 0; + } + + // Get all ItemDisplayEntity within the same block + List<DisplayEntity.ItemDisplayEntity> entities = world.getEntitiesByClass( + DisplayEntity.ItemDisplayEntity.class, + Box.of(pos.toCenterPos(), 1.0, 1.0, 1.0), + entity -> true + ); + + // Count those with minecraft:string + return (int) entities.stream() + .filter(entity -> { + ItemStack stack = entity.getItemStack(); + return !stack.isEmpty() && stack.getItem().equals(Items.STRING); + }) + .count(); + } + + private static void update() { + if (!shouldProcess()) { + return; + } + Iterator<Map.Entry<BlockPos, ForestNode>> iterator = forestNodes.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry<BlockPos, ForestNode> entry = iterator.next(); + ForestNode forestNode = entry.getValue(); + forestNode.updateWaypoint(); + if (!forestNode.shouldRender()) { + iterator.remove(); + } + } + } + + private static void render(WorldRenderContext context) { + if (!shouldProcess()) { + return; + } + for (ForestNode forestNode : forestNodes.values()) { + if (forestNode.shouldRender()) { + forestNode.render(context); + } + } + } + + private static boolean shouldProcess() { + return SkyblockerConfigManager.get().foraging.galatea.enableForestNodeHelper && Utils.isInGalatea(); + } + + private static void reset() { + forestNodes.clear(); + } + + public static class ForestNode extends Waypoint { + private long lastConfirmed; + + private ForestNode(BlockPos pos) { + super(pos, + () -> Type.HIGHLIGHT, + ColorUtils.getFloatComponents(DyeColor.ORANGE), + DEFAULT_HIGHLIGHT_ALPHA, + DEFAULT_LINE_WIDTH, + false + ); + this.lastConfirmed = System.currentTimeMillis(); + } + + private void updateWaypoint() { + long currentTimeMillis = System.currentTimeMillis(); + if (lastConfirmed + 2000 > currentTimeMillis || client.world == null) { + return; + } + int stringItemCount = countStringItemDisplays(pos); + if (stringItemCount == 3) { + lastConfirmed = System.currentTimeMillis(); + } + } + + @Override + public boolean shouldRender() { + return super.shouldRender() && lastConfirmed + 5000 > System.currentTimeMillis(); + } + } +} |
