diff options
Diffstat (limited to 'src')
10 files changed, 576 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 3fca09ce..c11e4c86 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -13,6 +13,8 @@ import de.hysky.skyblocker.skyblock.dungeon.puzzle.TicTacToe; import de.hysky.skyblocker.skyblock.dungeon.puzzle.waterboard.Waterboard; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker; +import de.hysky.skyblocker.skyblock.dwarven.CrystalsHud; +import de.hysky.skyblocker.skyblock.dwarven.CrystalsLocationsManager; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud; import de.hysky.skyblocker.skyblock.end.BeaconHighlighter; import de.hysky.skyblocker.skyblock.item.*; @@ -99,6 +101,8 @@ public class SkyblockerMod implements ClientModInitializer { QuickNav.init(); ItemCooldowns.init(); DwarvenHud.init(); + CrystalsHud.init(); + CrystalsLocationsManager.init(); ChatMessageListener.init(); Shortcuts.init(); DiscordRPCManager.init(); @@ -142,6 +146,8 @@ public class SkyblockerMod implements ClientModInitializer { Scheduler.INSTANCE.scheduleCyclic(LividColor::update, 10); Scheduler.INSTANCE.scheduleCyclic(BackpackPreview::tick, 50); Scheduler.INSTANCE.scheduleCyclic(DwarvenHud::update, 40); + Scheduler.INSTANCE.scheduleCyclic(CrystalsHud::update, 40); + Scheduler.INSTANCE.scheduleCyclic(CrystalsLocationsManager::update, 40); Scheduler.INSTANCE.scheduleCyclic(PlayerListMgr::updateList, 20); } diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index a7569adb..886f81fb 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -873,6 +873,12 @@ public class SkyblockerConfig { @SerialEntry public DwarvenHud dwarvenHud = new DwarvenHud(); + + @SerialEntry + public CrystalsHud crystalsHud = new CrystalsHud(); + + @SerialEntry + public CrystalsWaypoints crystalsWaypoints = new CrystalsWaypoints(); } public static class DwarvenHud { @@ -891,6 +897,30 @@ public class SkyblockerConfig { @SerialEntry public int y = 10; } + public static class CrystalsHud { + @SerialEntry + public boolean enabled = true; + + + @SerialEntry + public boolean enableBackground = true; + + @SerialEntry + public int x = 10; + + @SerialEntry + public int y = 50; + } + public static class CrystalsWaypoints { + @SerialEntry + public boolean enabled = true; + + @SerialEntry + public boolean findInChat = true; + + @SerialEntry + public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; + } public enum DwarvenHudStyle { SIMPLE, FANCY, CLASSIC; diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java index 80d6485b..4a7e6854 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java @@ -2,6 +2,7 @@ package de.hysky.skyblocker.config.categories; import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.skyblock.dwarven.CrystalsHudConfigScreen; import dev.isxander.yacl3.api.ButtonOption; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; @@ -53,7 +54,7 @@ public class DwarvenMinesCategory { .build()) .option(Option.<SkyblockerConfig.DwarvenHudStyle>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style")) - .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[0]"), + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[0]"), Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[1]"), Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[2]"))) .binding(defaults.locations.dwarvenMines.dwarvenHud.style, @@ -74,6 +75,50 @@ public class DwarvenMinesCategory { .controller(ConfigUtils::createBooleanController) .build()) .build()) + //crystal HUD + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsHud")) //todo i do not know if i need to duplicate text + .collapsed(false) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled")) + .binding(defaults.locations.dwarvenMines.crystalsHud.enabled, + () -> config.locations.dwarvenMines.crystalsHud.enabled, + newValue -> config.locations.dwarvenMines.crystalsHud.enabled = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(ButtonOption.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.screen")) + .text(Text.translatable("text.skyblocker.open")) + .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new CrystalsHudConfigScreen(screen))) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground")) + .binding(defaults.locations.dwarvenMines.crystalsHud.enableBackground, + () -> config.locations.dwarvenMines.crystalsHud.enableBackground, + newValue -> config.locations.dwarvenMines.crystalsHud.enableBackground = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) + //crystals waypoints + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsWaypoints")) //todo i do not know if i need to duplicate text + .collapsed(false) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled")) + .binding(defaults.locations.dwarvenMines.crystalsWaypoints.enabled, + () -> config.locations.dwarvenMines.crystalsWaypoints.enabled, + newValue -> config.locations.dwarvenMines.crystalsWaypoints.enabled = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsWaypoints.findInChat")) + .binding(defaults.locations.dwarvenMines.crystalsWaypoints.findInChat, + () -> config.locations.dwarvenMines.crystalsWaypoints.findInChat, + newValue -> config.locations.dwarvenMines.crystalsWaypoints.findInChat = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + + .build()) .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java new file mode 100644 index 00000000..7ec9cefa --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java @@ -0,0 +1,101 @@ +package de.hysky.skyblocker.skyblock.dwarven; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.ints.IntIntPair; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.texture.atlas.Sprite; +import net.minecraft.util.Identifier; +import org.apache.commons.math3.analysis.UnivariateMatrixFunction; + +import java.awt.*; +import java.util.Arrays; + +public class CrystalsHud { + public static final MinecraftClient client = MinecraftClient.getInstance(); + + protected static final Identifier MAP_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/crystals_map.png"); //todo is this the right place to store file + + private static final Identifier MAP_ICON = new Identifier("textures/map/map_icons.png"); + + public static boolean visable = false; + + + + + public static void init() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker") + .then(ClientCommandManager.literal("hud") + .then(ClientCommandManager.literal("crystals") + .executes(Scheduler.queueOpenScreenCommand(CrystalsHudConfigScreen::new)))))); + + HudRenderCallback.EVENT.register((context, tickDelta) -> { + if (!SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enabled + || client.options.playerListKey.isPressed() + || client.player == null + || !visable) { + return; + } + render(context, SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.x, + SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.y); + }); + } + + public static IntIntPair getDimForConfig() { + return IntIntPair.of(62, 62); + } + + public static void render( DrawContext context, int hudX, int hudY) { + + if (SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enableBackground) { + context.fill(hudX, hudY, hudX + 62, hudY + 62, 0x64000000); + } + + + //draw map texture + context. + drawTexture(MAP_TEXTURE,hudX,hudY,0,0,62,62,62,62); + //draw player on map + if (client.player == null || client.getNetworkHandler() == null) { + return; + } + //get player location + double playerX = client.player.getX(); + double playerZ = client.player.getZ(); + double facing = client.player.getYaw(); + //map location to map + int renderX = (int)((playerX-202)/621 * 62); + int renderY = (int)((playerZ -202)/621 * 62); + int renderAngle = (int)(facing %360); + if (renderAngle < 0){//make sure the angle is always correct between 0 and 360 + renderAngle = 360 + renderAngle; + } + //clamp location to map + renderX = Math.max(0, Math.min(62, renderX)); + renderY = Math.max(0, Math.min(62, renderY)); + //draw marker on map + context. + drawTexture(MAP_ICON,hudX+renderX,hudY+renderY,2,0,5,7,128,128); + + //todo add direction and scale (could be wrong drawing methods) and offset to center on player + + } + + public static void update() { + if (client.player == null || client.getNetworkHandler() == null || !SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enabled) { + visable = false; + return; + } + //get if the player is in the crystals + visable = Utils.isInCrystals(); + + + } + +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java new file mode 100644 index 00000000..18be8bed --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java @@ -0,0 +1,64 @@ +package de.hysky.skyblocker.skyblock.dwarven; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.tabhud.widget.hud.HudCommsWidget; +import de.hysky.skyblocker.utils.render.RenderHelper; +import it.unimi.dsi.fastutil.ints.IntIntPair; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +import java.awt.*; + +public class CrystalsHudConfigScreen extends Screen { + + private int hudX = SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.x; + private int hudY = SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.y; + private final Screen parent; + + protected CrystalsHudConfigScreen() { + this(null); + } + + public CrystalsHudConfigScreen(Screen parent) { + super(Text.of("Crystals HUD Config")); + this.parent = parent; + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + renderBackground(context, mouseX, mouseY, delta); + CrystalsHud.render( context, hudX, hudY); + context.drawCenteredTextWithShadow(textRenderer, "Right Click To Reset Position", width / 2, height / 2, Color.GRAY.getRGB()); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + IntIntPair dims = CrystalsHud.getDimForConfig(); + if (RenderHelper.pointIsInArea(mouseX, mouseY, hudX, hudY, hudX + 200, hudY + 40) && button == 0) { + hudX = (int) Math.max(Math.min(mouseX - (double) dims.leftInt() / 2, this.width - dims.leftInt()), 0); + hudY = (int) Math.max(Math.min(mouseY - (double) dims.rightInt() / 2, this.height - dims.rightInt()), 0); + } + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (button == 1) { + IntIntPair dims = CrystalsHud.getDimForConfig(); + hudX = this.width / 2 - dims.leftInt(); + hudY = this.height / 2 - dims.rightInt(); + } + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void close() { + SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.x = hudX; + SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.y = hudY; + SkyblockerConfigManager.save(); + + client.setScreen(parent); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java new file mode 100644 index 00000000..d9f31f1d --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java @@ -0,0 +1,171 @@ +package de.hysky.skyblocker.skyblock.dwarven; + +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +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.CommandRegistryAccess; +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.DefaultPosArgument; +import net.minecraft.command.argument.PosArgument; +import net.minecraft.network.message.MessageType; +import net.minecraft.network.message.SignedMessage; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; + +import java.time.Instant; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class CrystalsLocationsManager { + public static final MinecraftClient client = MinecraftClient.getInstance(); + public static Map<String,CrystalsWaypoint> ActiveWaypoints= new HashMap<>() {}; + + public static final Map<String, CrystalsWaypoint.Category> WAYPOINTLOCATIONS = Map.of( + "Jungle Temple", CrystalsWaypoint.Category.JUNGLETEMPLE, + "Mines Of Divan", CrystalsWaypoint.Category.MINESOFDIVAN, + "Goblin Queen's Den", CrystalsWaypoint.Category.GOBLINQUEENSDEN, + "Lost Precursor City", CrystalsWaypoint.Category.LOSTPRECURSORCITY, + "Khazad-dûm", CrystalsWaypoint.Category.KHAZADUM, + "Fairy Grotto", CrystalsWaypoint.Category.FAIRYGROTTO, + "Dragon's Lair", CrystalsWaypoint.Category.DRAGONSLAIR + ); + private static final Pattern TEXT_CWORDS_PATTERN = Pattern.compile("([0-9][0-9][0-9]) ([0-9][0-9][0-9]?) ([0-9][0-9][0-9])"); + + + public static void init() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker") + .then(ClientCommandManager.literal("hud") + .then(ClientCommandManager.literal("crystals") + .executes(Scheduler.queueOpenScreenCommand(CrystalsHudConfigScreen::new)))))); + + WorldRenderEvents.AFTER_TRANSLUCENT.register(CrystalsLocationsManager::render); + ClientReceiveMessageEvents.CHAT.register(CrystalsLocationsManager::extractLocationFromMessage); + ClientCommandRegistrationCallback.EVENT.register(CrystalsLocationsManager::registerWaypointLocationCommands); + } + private static void extractLocationFromMessage(Text message, SignedMessage signedMessage, GameProfile sender, MessageType.Parameters params, Instant receptionTimestamp){ + if (!SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints.findInChat ) { //todo || !Utils.isInCrystals() + return; + } + //get the message text + String value = signedMessage.getContent().getString(); + Matcher matcher = TEXT_CWORDS_PATTERN.matcher(value); + //if there are cwords in the message try to get them and what they are talking about + if (matcher.find()){ + String location = matcher.group(); + Integer[] cowordinates = Arrays.stream(location.split(" ",3)).map(Integer::parseInt).toArray(Integer[]::new); + BlockPos blockPos = new BlockPos(cowordinates[0],cowordinates[1],cowordinates[2]); + //todo make sure this is in bounds of crystals + //see if there is a name of a location to add to this + for (String waypointLocation : WAYPOINTLOCATIONS.keySet()){ + if (value.toLowerCase().contains(waypointLocation.toLowerCase())){ //todo be more lenient + //all data found to create waypoint + addCustomWaypoint(Text.of(waypointLocation),blockPos); + return; + } + } + //if the location is not found ask the user for the location (could have been in a previous chat message) + if (client.player == null || client.getNetworkHandler() == null ) { + return; + } + client.player.sendMessage(getLocationInputText(location), false); + } + + + } + private static void registerWaypointLocationCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(literal(SkyblockerMod.NAMESPACE) + .then(literal("crystalWaypoints") + .then(argument("pos", BlockPosArgumentType.blockPos()) + .then(argument("place", StringArgumentType.greedyString()) + .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"),context.getArgument("pos", PosArgument.class))) + ) + ) + ) + ); + } + private static Text getSetLocationMessage(String location,BlockPos blockPos) { + MutableText text = Text.empty(); + text.append(Text.literal("Added waypoint for "+location+" at :"+blockPos.getX()+" "+blockPos.getY()+" "+blockPos.getZ()+".")); //todo add colours + + return text; + } + private static Text getLocationInputText(String location) { + MutableText text = Text.empty(); + for (String waypointLocation : WAYPOINTLOCATIONS.keySet()){ + //todo add colour codes + text.append(Text.literal("["+waypointLocation+"]").styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker crystalWaypoints "+location+" "+waypointLocation)))); + } + + return text; + } + public static int addWaypointFromCommand(FabricClientCommandSource source, String place, PosArgument location) { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos blockPos = location.toAbsoluteBlockPos(new ServerCommandSource(null, source.getPosition(), source.getRotation(), null, 0, null, null, null, null)); + if (WAYPOINTLOCATIONS.containsKey(place)){ + addCustomWaypoint(Text.of(place), blockPos); + //todo send to map + //tell the client it has done this + if (client.player == null || client.getNetworkHandler() == null ) { + return Command.SINGLE_SUCCESS; + } + client.player.sendMessage(getSetLocationMessage(place, blockPos), false); + } + return Command.SINGLE_SUCCESS; + } + + + private static void addCustomWaypoint( Text waypointName, BlockPos pos) { + CrystalsWaypoint.Category category = WAYPOINTLOCATIONS.get(waypointName.getString()); + CrystalsWaypoint waypoint = new CrystalsWaypoint(category, waypointName, pos); + ActiveWaypoints.put(waypointName.getString(),waypoint); + } + public static void render(WorldRenderContext context) { + if (SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints.enabled ) { + for (CrystalsWaypoint crystalsWaypoint : ActiveWaypoints.values()) { + if (crystalsWaypoint.shouldRender()) { + crystalsWaypoint.render(context); + } + } + } + } + + public static void update() { + if (client.player == null || client.getNetworkHandler() == null || !SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints.enabled) { + ActiveWaypoints= new HashMap<>(); + return; + } + //get if the player is in the crystals + String location = Utils.getIslandArea().replace("⏣ ",""); + //if new location and needs waypoint add waypoint + if (!location.equals("Unknown") && WAYPOINTLOCATIONS.containsKey(location) && !ActiveWaypoints.containsKey(location)){ + //add waypoint at player location + BlockPos playerLocation = client.player.getBlockPos(); + addCustomWaypoint(Text.of(location),playerLocation); + //todo send to map gui + } + + + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java new file mode 100644 index 00000000..9c6db04f --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java @@ -0,0 +1,149 @@ +package de.hysky.skyblocker.skyblock.dwarven; + +import com.google.gson.JsonObject; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.Waypoint; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.client.MinecraftClient; +import net.minecraft.command.argument.EnumArgumentType; +import net.minecraft.entity.Entity; +import net.minecraft.text.Text; +import net.minecraft.text.TextCodecs; +import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.function.ToDoubleFunction; + +public class CrystalsWaypoint extends Waypoint { + private static final Logger LOGGER = LoggerFactory.getLogger(CrystalsWaypoint.class); + public static final Codec<CrystalsWaypoint> CODEC = RecordCodecBuilder.create(instance -> instance.group( + Category.CODEC.fieldOf("category").forGetter(crystalsWaypoint -> crystalsWaypoint.category), + TextCodecs.CODEC.fieldOf("name").forGetter(crystalsWaypoint -> crystalsWaypoint.name), + BlockPos.CODEC.fieldOf("pos").forGetter(crystalsWaypoint -> crystalsWaypoint.pos) + ).apply(instance, CrystalsWaypoint::new)); + public static final Codec<List<CrystalsWaypoint>> LIST_CODEC = CODEC.listOf(); + static final List<String> SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); + private static final Supplier<SkyblockerConfig.CrystalsWaypoints> CONFIG = () -> SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints; + static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.get().waypointType; + final Category category; + final Text name; + private final Vec3d centerPos; + + CrystalsWaypoint( JsonObject waypoint, String name, BlockPos pos) { + this(Category.get(waypoint), name, pos); + } + + CrystalsWaypoint(Category category, String name, BlockPos pos) { + this( category, Text.of(name), pos); + } + + CrystalsWaypoint( Category category, Text name, BlockPos pos) { + super(pos, TYPE_SUPPLIER, category.colorComponents); + this.category = category; + this.name = name; + this.centerPos = pos.toCenterPos(); + } + + static ToDoubleFunction<CrystalsWaypoint> getSquaredDistanceToFunction(Entity entity) { + return crystalsWaypoint -> entity.squaredDistanceTo(crystalsWaypoint.centerPos); + } + + static Predicate<CrystalsWaypoint> getRangePredicate(Entity entity) { + return crystalsWaypoint -> entity.squaredDistanceTo(crystalsWaypoint.centerPos) <= 36D; + } + + @Override + public boolean shouldRender() { + return super.shouldRender() ; + } + + + @Override + public boolean equals(Object obj) { + return super.equals(obj) || obj instanceof CrystalsWaypoint other && category == other.category && name.equals(other.name) && pos.equals(other.pos); + } + + /** + * Renders the secret waypoint, including a waypoint through {@link Waypoint#render(WorldRenderContext)}, the name, and the distance from the player. + */ + @Override + public void render(WorldRenderContext context) { + //TODO In the future, shrink the box for wither essence and items so its more realistic + super.render(context); + + + Vec3d posUp = centerPos.add(0, 1, 0); + RenderHelper.renderText(context, name, posUp, true); + double distance = context.camera().getPos().distanceTo(centerPos); + RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, 1, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true); + + } + + + + enum Category implements StringIdentifiable { //todo set better colours and remove extra data + JUNGLETEMPLE("Jungle Temple", 0, 255, 0), + MINESOFDIVAN("Mines Of Divan", 255, 0, 0), + GOBLINQUEENSDEN("Goblin Queen's Den", 2, 213, 250), + LOSTPRECURSORCITY("Lost Precursor City", 2, 64, 250), + KHAZADUM("Khazad-dûm", 142, 66, 0), + FAIRYGROTTO("Fairy Grotto", 30, 30, 30), + DRAGONSLAIR("Dragon's Lair", 250, 217, 2), + DEFAULT("default", 190, 255, 252); + + private static final Codec<Category> CODEC = StringIdentifiable.createCodec(Category::values); + private final String name; + + private final float[] colorComponents; + + Category(String name, int... intColorComponents) { + this.name = name; + + colorComponents = new float[intColorComponents.length]; + for (int i = 0; i < intColorComponents.length; i++) { + colorComponents[i] = intColorComponents[i] / 255F; + } + } + + static Category get(JsonObject waypointJson) { + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(LOGGER::error).orElse(Category.DEFAULT); + } + + @Override + public String toString() { + return name; + } + + @Override + public String asString() { + return name; + } + + static class CategoryArgumentType extends EnumArgumentType<Category> { + CategoryArgumentType() { + super(Category.CODEC, Category::values); + } + + static CategoryArgumentType category() { + return new CategoryArgumentType(); + } + + static <S> Category getCategory(CommandContext<S> context, String name) { + return context.getArgument(name, Category.class); + } + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index 3f07622c..a8a0d3d6 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -25,6 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -36,6 +37,8 @@ public class Utils { private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class); private static final String ALTERNATE_HYPIXEL_ADDRESS = System.getProperty("skyblocker.alternateHypixelAddress", ""); private static final String DUNGEONS_LOCATION = "dungeon"; + public static final String CRYSTALS_LOCATION = "crystal_hollows"; + private static final String PROFILE_PREFIX = "Profile: "; private static boolean isOnHypixel = false; private static boolean isOnSkyblock = false; @@ -85,6 +88,9 @@ public class Utils { public static boolean isInDungeons() { return getLocationRaw().equals(DUNGEONS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); } + public static boolean isInCrystals(){ + return getLocationRaw().equals(CRYSTALS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); + } public static boolean isInTheRift() { return getLocationRaw().equals(TheRift.LOCATION); diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 527205cf..903d702e 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -275,6 +275,9 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[2]": "\nClassic: Shows name and percentage in a very simple box.", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.screen": "Dwarven HUD Config...", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Enable Background", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsHud": "Crystal Hollows Map", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsWaypoints": "Crystal Hollows Waypoints", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsWaypoints.findInChat": "Find Waypoints In Chat", "text.autoconfig.skyblocker.option.locations.rift": "The Rift", "text.autoconfig.skyblocker.option.locations.rift.mirrorverseWaypoints": "Enable Mirrorverse Waypoints", diff --git a/src/main/resources/assets/skyblocker/textures/gui/crystals_map.png b/src/main/resources/assets/skyblocker/textures/gui/crystals_map.png Binary files differnew file mode 100644 index 00000000..4e807ea1 --- /dev/null +++ b/src/main/resources/assets/skyblocker/textures/gui/crystals_map.png |