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 Teleport Maze Solver + small things #1115

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
newValue -> config.dungeons.puzzleSolvers.solveTrivia = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.dungeons.puzzle.solveTeleportMaze"))
.binding(defaults.dungeons.puzzleSolvers.solveTeleportMaze,
() -> config.dungeons.puzzleSolvers.solveTeleportMaze,
newValue -> config.dungeons.puzzleSolvers.solveTeleportMaze = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.build())

// The Professor (F3/M3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ public static class PuzzleSolvers {

@SerialEntry
public boolean solveTrivia = true;

@SerialEntry
public boolean solveTeleportMaze = true;
}

public static class TheProfessor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.SlayersConfig;
import de.hysky.skyblocker.skyblock.CompactDamage;
import de.hysky.skyblocker.skyblock.FishingHelper;
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.puzzle.TeleportMaze;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.dwarven.CrystalsChestHighlighter;
import de.hysky.skyblocker.skyblock.dwarven.WishingCompassSolver;
Expand All @@ -20,16 +23,21 @@
import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientCommonNetworkHandler;
import net.minecraft.client.network.ClientConnectionState;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityStatuses;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.s2c.play.*;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -40,14 +48,18 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ClientPlayNetworkHandler.class)
public abstract class ClientPlayNetworkHandlerMixin {
public abstract class ClientPlayNetworkHandlerMixin extends ClientCommonNetworkHandler {
@Shadow
private ClientWorld world;

@Shadow
@Final
private static Logger LOGGER;

protected ClientPlayNetworkHandlerMixin(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) {
super(client, connection, connectionState);
}

@Inject(method = "onEntityTrackerUpdate", at = @At("TAIL"))
private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) {
if (!(entity instanceof ArmorStandEntity armorStandEntity)) return;
Expand All @@ -71,6 +83,16 @@ public abstract class ClientPlayNetworkHandlerMixin {
}
}

@Inject(method = "onPlayerPositionLook", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", shift = At.Shift.AFTER))
private void skyblocker$beforeTeleport(PlayerPositionLookS2CPacket packet, CallbackInfo ci, @Share("playerBeforeTeleportBlockPos") LocalRef<BlockPos> beforeTeleport) {
beforeTeleport.set(client.player.getBlockPos().toImmutable());
}

@Inject(method = "onPlayerPositionLook", at = @At(value = "RETURN"))
private void skyblocker$onTeleport(PlayerPositionLookS2CPacket packet, CallbackInfo ci, @Share("playerBeforeTeleportBlockPos") LocalRef<BlockPos> beforeTeleport) {
TeleportMaze.INSTANCE.onTeleport(client, beforeTeleport.get(), client.player.getBlockPos().toImmutable());
}

@ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V", ordinal = 0))
private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity) {
DungeonManager.onItemPickup(itemEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ protected HandledScreenMixin(Text title) {
@Inject(method = "renderBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/gui/DrawContext;FII)V"))
private void skyblocker$drawUnselectedQuickNavButtons(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
if (quickNavButtons != null) for (QuickNavButton quickNavButton : quickNavButtons) {
if (!quickNavButton.toggled()) {
// Render the button behind the main inventory background if it's not toggled or if it's still fading in
if (!quickNavButton.toggled() || quickNavButton.getAlpha() < 255) {
quickNavButton.setRenderInFront(false);
quickNavButton.render(context, mouseX, mouseY, delta);
}
}
Expand All @@ -178,6 +180,7 @@ protected HandledScreenMixin(Text title) {
private void skyblocker$drawSelectedQuickNavButtons(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
if (quickNavButtons != null) for (QuickNavButton quickNavButton : quickNavButtons) {
if (quickNavButton.toggled()) {
quickNavButton.setRenderInFront(true);
quickNavButton.render(context, mouseX, mouseY, delta);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,28 @@
import java.util.stream.Collectors;

import de.hysky.skyblocker.skyblock.entity.MobGlow;
import de.hysky.skyblocker.skyblock.tabhud.util.Ico;
import net.minecraft.item.ItemStack;

public enum DungeonClass {
UNKNOWN("Unknown", MobGlow.NO_GLOW),
HEALER("Healer", 0x820dd1),
MAGE("Mage", 0x36c6e3),
BERSERK("Berserk", 0xfa5b16),
ARCHER("Archer", 0xed240e),
TANK("Tank", 0x138717);
UNKNOWN("Unknown", MobGlow.NO_GLOW, Ico.BARRIER),
HEALER("Healer", 0x820dd1, Ico.POTION),
MAGE("Mage", 0x36c6e3, Ico.B_ROD),
BERSERK("Berserk", 0xfa5b16, Ico.DIASWORD),
ARCHER("Archer", 0xed240e, Ico.BOW),
TANK("Tank", 0x138717, Ico.CHESTPLATE);

private static final Map<String, DungeonClass> CLASSES = Arrays.stream(values())
.collect(Collectors.toUnmodifiableMap(DungeonClass::displayName, Function.identity()));

private final String name;
private final int color;
private final ItemStack icon;

DungeonClass(String name, int colour) {
DungeonClass(String name, int color, ItemStack icon) {
this.name = name;
this.color = colour;
this.color = color;
this.icon = icon;
}

public String displayName() {
Expand All @@ -37,6 +41,10 @@ public int color() {
return this.color;
}

public ItemStack icon() {
return icon;
}

public static DungeonClass from(String name) {
return CLASSES.getOrDefault(name, UNKNOWN);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package de.hysky.skyblocker.skyblock.dungeon.puzzle;

import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.utils.ColorUtils;
import de.hysky.skyblocker.utils.render.RenderHelper;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.DyeColor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class TeleportMaze extends DungeonPuzzle {
private static final Set<BlockPos> ROOM_CENTERS = Set.of(
new BlockPos(7, 68, 9),
new BlockPos(23, 68, 9),
new BlockPos(7, 68, 17),
new BlockPos(23, 68, 17),
new BlockPos(7, 68, 25),
new BlockPos(15, 68, 25),
new BlockPos(23, 68, 25)
);
private static final Set<BlockPos> TELEPORT_PADS = Set.of(
new BlockPos(15, 69, 12), // Start
new BlockPos(4, 69, 6),
new BlockPos(10, 69, 6),
new BlockPos(20, 69, 6),
new BlockPos(26, 69, 6),
new BlockPos(4, 69, 12),
new BlockPos(10, 69, 12),
new BlockPos(20, 69, 12),
new BlockPos(26, 69, 12),
new BlockPos(4, 69, 14),
new BlockPos(10, 69, 14),
new BlockPos(20, 69, 14),
new BlockPos(26, 69, 14),
new BlockPos(4, 69, 20),
new BlockPos(10, 69, 20),
new BlockPos(20, 69, 20),
new BlockPos(26, 69, 20),
new BlockPos(4, 69, 22),
new BlockPos(10, 69, 22),
new BlockPos(12, 69, 22),
new BlockPos(18, 69, 22),
new BlockPos(20, 69, 22),
new BlockPos(26, 69, 22),
new BlockPos(4, 69, 28),
new BlockPos(10, 69, 28),
new BlockPos(12, 69, 28),
new BlockPos(18, 69, 28),
new BlockPos(20, 69, 28),
new BlockPos(26, 69, 28),
new BlockPos(15, 69, 14) // End
);
public static final TeleportMaze INSTANCE = new TeleportMaze();
/**
* The actual coordinate of pads that have been detected and the room type they teleport to.
*/
private final Map<BlockPos, RoomType> pads = new HashMap<>();
/**
* The actual coordinate of the final pad.
*/
@Nullable
private BlockPos finalPad;

private TeleportMaze() {
super("teleport-maze", "teleport-pad-room");
}

public void onTeleport(MinecraftClient client, BlockPos from, BlockPos to) {
if (!shouldSolve() || !DungeonManager.isCurrentRoomMatched() || client.player == null || client.world == null) return;

BlockPos prevPlayer = DungeonManager.getCurrentRoom().actualToRelative(from.withY(69));
BlockPos player = DungeonManager.getCurrentRoom().actualToRelative(to.withY(69));
if (prevPlayer.equals(player) || !TELEPORT_PADS.contains(prevPlayer)) return;

// Process the teleport from the previous pad to the current pad
processTeleport(client.world, prevPlayer, player);
// Find the pad closest to the player, which is the current pad they teleported to
BlockPos nearestPad = TELEPORT_PADS.stream().min(Comparator.comparingDouble(pad -> pad.getSquaredDistance(player))).orElse(null);
// Also process the teleport from the current pad to the previous pad
processTeleport(client.world, nearestPad, prevPlayer);
}

private void processTeleport(World world, BlockPos from, BlockPos to) {
getRoomType(world, to).ifPresent(type -> pads.put(DungeonManager.getCurrentRoom().relativeToActual(from), type));
}

private Optional<RoomType> getRoomType(World world, BlockPos pos) {
// Special processing for the entrance
if (pos.getX() == 15 && pos.getZ() == 12) return Optional.of(RoomType.ENTRANCE);
// Check if the position is in a room and return the room type by checking the ore block
return ROOM_CENTERS.stream().filter(center -> center.getX() - 3 <= pos.getX() && pos.getX() <= center.getX() + 3 &&
center.getZ() - 3 <= pos.getZ() && pos.getZ() <= center.getZ() + 3).findAny()
.map(DungeonManager.getCurrentRoom()::relativeToActual).map(world::getBlockState).map(BlockState::getBlock).flatMap(RoomType::fromBlock);
}

@Override
public void tick(MinecraftClient client) {
if (!SkyblockerConfigManager.get().dungeons.puzzleSolvers.solveTeleportMaze || !shouldSolve() || finalPad != null) return;
// Mark the last unused pad that's not the start or the end as the final pad
List<BlockPos> finalPads = TELEPORT_PADS.stream().filter(pad -> pad.getX() != 15) // Filter out the start and end pads
.map(DungeonManager.getCurrentRoom()::relativeToActual).filter(pad -> !pads.containsKey(pad)).toList(); // Filter out used pads
if (finalPads.size() == 1) finalPad = finalPads.getFirst(); // If there's only one left, mark it as the final pad
}

@Override
public void render(WorldRenderContext context) {
if (!SkyblockerConfigManager.get().dungeons.puzzleSolvers.solveTeleportMaze || !shouldSolve()) return;
for (Map.Entry<BlockPos, RoomType> entry : pads.entrySet()) {
RenderHelper.renderFilled(context, entry.getKey(), entry.getValue().colorComponents, 0.5f, true);
}
if (finalPad != null) {
RenderHelper.renderFilled(context, finalPad, ColorUtils.getFloatComponents(DyeColor.LIME), 1f, true);
RenderHelper.renderLineFromCursor(context, Vec3d.ofCenter(finalPad), ColorUtils.getFloatComponents(DyeColor.LIME), 1f, 2f);
}
}

@Override
public void reset() {
super.reset();
pads.clear();
finalPad = null;
}

private enum RoomType {
ENTRANCE(Blocks.BARRIER, DyeColor.GRAY),
COAL(Blocks.COAL_ORE, DyeColor.BLACK),
IRON(Blocks.IRON_ORE, DyeColor.LIGHT_GRAY),
REDSTONE(Blocks.REDSTONE_ORE, DyeColor.RED),
LAPIS(Blocks.LAPIS_ORE, DyeColor.BLUE),
GOLD(Blocks.GOLD_ORE, DyeColor.YELLOW),
DIAMOND(Blocks.DIAMOND_ORE, DyeColor.CYAN),
EMERALD(Blocks.EMERALD_ORE, DyeColor.LIME);

private final Block block;
private final float[] colorComponents;

RoomType(Block block, DyeColor dyeColor) {
this.block = block;
this.colorComponents = ColorUtils.getFloatComponents(dyeColor);
}

private static Optional<RoomType> fromBlock(Block block) {
return Arrays.stream(values()).filter(type -> type.block == block).findFirst();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private static void sendResultMessage(String player, SecretData secretData, bool
PlayerEntity playerEntity = MinecraftClient.getInstance().player;
if (playerEntity != null) {
if (success) {
playerEntity.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secretsTracker.feedback", Text.literal(player).withColor(0xf57542), "§7" + secretData.secrets(), getCacheText(secretData.cached(), secretData.cacheAge()))), false);
playerEntity.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secretsTracker.feedback", Text.literal(player).append(" (" + DungeonPlayerManager.getClassFromPlayer(playerEntity).displayName() + ")").withColor(0xf57542), "§7" + secretData.secrets(), getCacheText(secretData.cached(), secretData.cacheAge()))), false);
} else {
playerEntity.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secretsTracker.failFeedback")), false);
}
Expand Down
Loading
Loading