aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorKevin <92656833+kevinthegreat1@users.noreply.github.com>2024-01-21 13:05:51 -0500
committerGitHub <noreply@github.com>2024-01-21 13:05:51 -0500
commita092f33ab7e52006cbca75adb6974ccf67f7e890 (patch)
tree07412faeffd41b7d2aea72c8d75269db373ce194 /src/main
parent08444dc32b39b8cdf8bf6a1e47248fc4d871d2d7 (diff)
parentcbf7f80faf78764f7787122be194e8d26e8b1f9e (diff)
downloadSkyblocker-a092f33ab7e52006cbca75adb6974ccf67f7e890.tar.gz
Skyblocker-a092f33ab7e52006cbca75adb6974ccf67f7e890.tar.bz2
Skyblocker-a092f33ab7e52006cbca75adb6974ccf67f7e890.zip
Merge pull request #500 from Emirlol/clientside-dungeon-score
Add dungeon score calculation on client-side
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java29
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java52
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java16
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java16
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java48
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java429
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScoreHUD.java44
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/filters/DeathFilter.java25
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/filters/MimicFilter.java28
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java30
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java8
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json16
14 files changed, 664 insertions, 99 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index aa6e5d24..9477fbed 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -606,6 +606,9 @@ public class SkyblockerConfig {
public DungeonChestProfit dungeonChestProfit = new DungeonChestProfit();
@SerialEntry
+ public MimicMessage mimicMessage = new MimicMessage();
+
+ @SerialEntry
public boolean croesusHelper = true;
@SerialEntry
@@ -757,6 +760,18 @@ public class SkyblockerConfig {
@SerialEntry
public String dungeonScore300Message = "300 Score Reached!";
+
+ @SerialEntry
+ public boolean enableScoreHUD = true;
+
+ @SerialEntry
+ public int scoreX = 29;
+
+ @SerialEntry
+ public int scoreY = 134;
+
+ @SerialEntry
+ public float scoreScaling = 1f;
}
public static class DungeonChestProfit {
@@ -785,6 +800,14 @@ public class SkyblockerConfig {
public Formatting incompleteColor = Formatting.BLUE;
}
+ public static class MimicMessage {
+ @SerialEntry
+ public boolean sendMimicMessage = true;
+
+ @SerialEntry
+ public String mimicMessage = "Mimic dead!";
+ }
+
public static class LividColor {
@SerialEntry
public boolean enableLividColorGlow = true;
@@ -970,6 +993,12 @@ public class SkyblockerConfig {
public ChatFilterResult hideToggleSkyMall = ChatFilterResult.PASS;
@SerialEntry
+ public ChatFilterResult hideMimicKill = ChatFilterResult.PASS;
+
+ @SerialEntry
+ public ChatFilterResult hideDeath = ChatFilterResult.PASS;
+
+ @SerialEntry
public boolean hideMana = false;
}
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
index 583bc166..3b685f9a 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
@@ -2,17 +2,12 @@ package de.hysky.skyblocker.config.categories;
import de.hysky.skyblocker.config.ConfigUtils;
import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.skyblock.dungeon.DungeonMapConfigScreen;
import de.hysky.skyblocker.utils.waypoint.Waypoint.Type;
-import dev.isxander.yacl3.api.ButtonOption;
-import dev.isxander.yacl3.api.ConfigCategory;
-import dev.isxander.yacl3.api.Option;
-import dev.isxander.yacl3.api.OptionDescription;
-import dev.isxander.yacl3.api.OptionFlag;
-import dev.isxander.yacl3.api.OptionGroup;
+import dev.isxander.yacl3.api.*;
import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder;
import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder;
import dev.isxander.yacl3.api.controller.StringControllerBuilder;
-import de.hysky.skyblocker.skyblock.dungeon.DungeonMapConfigScreen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
@@ -235,6 +230,25 @@ public class DungeonsCategory {
newValue -> config.locations.dungeons.dungeonScore.dungeonScore300Message = newValue)
.controller(StringControllerBuilder::create)
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonScore.enableScoreHUD"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonScore.enableScoreHUD.@Tooltip"), Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonScore.enableScoreHUD.deathMessagesNote")))
+ .binding(defaults.locations.dungeons.dungeonScore.enableScoreHUD,
+ () -> config.locations.dungeons.dungeonScore.enableScoreHUD,
+ newValue -> config.locations.dungeons.dungeonScore.enableScoreHUD = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Float>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonScore.scoreScaling"))
+ .binding(defaults.locations.dungeons.dungeonScore.scoreScaling,
+ () -> config.locations.dungeons.dungeonScore.scoreScaling,
+ newValue -> {
+ config.locations.dungeons.dungeonScore.scoreX = config.locations.dungeons.dungeonScore.scoreX + (int) ((config.locations.dungeons.dungeonScore.scoreScaling - newValue) * 38.0);
+ config.locations.dungeons.dungeonScore.scoreY = config.locations.dungeons.dungeonScore.scoreY + (int) ((config.locations.dungeons.dungeonScore.scoreScaling - newValue) * MinecraftClient.getInstance().textRenderer.fontHeight / 2.0);
+ config.locations.dungeons.dungeonScore.scoreScaling = newValue;
+ })
+ .controller(FloatFieldControllerBuilder::create)
+ .build())
.build())
//Dungeon Chest Profit
@@ -419,7 +433,29 @@ public class DungeonsCategory {
.controller(ConfigUtils::createBooleanController)
.build())
- // Livid Color
+ //Mimic Message
+ .group(OptionGroup.createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage"))
+ .collapsed(true)
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage.sendMimicMessage"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage.sendMimicMessage.@Tooltip")))
+ .binding(defaults.locations.dungeons.mimicMessage.sendMimicMessage,
+ () -> config.locations.dungeons.mimicMessage.sendMimicMessage,
+ newValue -> config.locations.dungeons.mimicMessage.sendMimicMessage = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<String>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage.mimicMessage"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage.mimicMessage.@Tooltip")))
+ .binding(defaults.locations.dungeons.mimicMessage.mimicMessage,
+ () -> config.locations.dungeons.mimicMessage.mimicMessage,
+ newValue -> config.locations.dungeons.mimicMessage.mimicMessage = newValue)
+ .controller(StringControllerBuilder::create)
+ .build())
+ .build())
+
+ //Livid Color
.group(OptionGroup.createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor"))
.collapsed(true)
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java
index 37f24d8c..ce349049 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java
@@ -102,6 +102,22 @@ public class MessageFilterCategory {
newValue -> config.messages.hideMana = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
+ .option(Option.<ChatFilterResult>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.messages.hideMimicKill"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.messages.hideMimicKill.@Tooltip")))
+ .binding(defaults.messages.hideMimicKill,
+ () -> config.messages.hideMimicKill,
+ newValue -> config.messages.hideMimicKill = newValue)
+ .controller(ConfigUtils::createEnumCyclingListController)
+ .build())
+ .option(Option.<ChatFilterResult>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.messages.hideDeath"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.messages.hideDeath.@Tooltip")))
+ .binding(defaults.messages.hideDeath,
+ () -> config.messages.hideDeath,
+ newValue -> config.messages.hideDeath = newValue)
+ .controller(ConfigUtils::createEnumCyclingListController)
+ .build())
.build();
}
}
diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
index 4015dfa5..a8537088 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
@@ -1,19 +1,23 @@
package de.hysky.skyblocker.mixin;
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import de.hysky.skyblocker.skyblock.FishingHelper;
+import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityStatuses;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
+import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket;
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
import net.minecraft.util.Identifier;
-
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -49,12 +53,12 @@ public abstract class ClientPlayNetworkHandlerMixin {
private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) {
return !Utils.isOnHypixel();
}
-
+
@WrapWithCondition(method = { "onScoreboardScoreUpdate", "onScoreboardScoreReset" }, at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$cancelUnknownScoreboardObjectiveWarnings(Logger instance, String message, Object objectiveName) {
return !Utils.isOnHypixel();
}
-
+
@WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) {
return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion"));
@@ -64,4 +68,10 @@ public abstract class ClientPlayNetworkHandlerMixin {
private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) {
MythologicalRitual.onParticle(packet);
}
+
+ @ModifyExpressionValue(method = "onEntityStatus", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityStatusS2CPacket;getEntity(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;"))
+ private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) {
+ if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) DungeonScore.handleEntityDeath(entity);
+ return entity;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java b/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java
index 0ee7b528..df7cbdea 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java
@@ -5,9 +5,11 @@ import com.llamalad7.mixinextras.sugar.Local;
import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.FancyStatusBars;
+import de.hysky.skyblocker.skyblock.dungeon.DungeonMap;
+import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
+import de.hysky.skyblocker.skyblock.dungeon.DungeonScoreHUD;
import de.hysky.skyblocker.skyblock.item.HotbarSlotLock;
import de.hysky.skyblocker.skyblock.item.ItemCooldowns;
-import de.hysky.skyblocker.skyblock.dungeon.DungeonMap;
import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds;
import de.hysky.skyblocker.utils.Utils;
import net.fabricmc.api.EnvType;
@@ -64,8 +66,10 @@ public abstract class InGameHudMixin {
if (statusBars.render(context, scaledWidth, scaledHeight))
ci.cancel();
- if (Utils.isInDungeons() && SkyblockerConfigManager.get().locations.dungeons.enableMap)
- DungeonMap.render(context.getMatrices());
+ if (Utils.isInDungeons() && DungeonScore.isDungeonStarted()) {
+ if (SkyblockerConfigManager.get().locations.dungeons.enableMap) DungeonMap.render(context.getMatrices());
+ if (SkyblockerConfigManager.get().locations.dungeons.dungeonScore.enableScoreHUD) DungeonScoreHUD.render(context);
+ }
}
@Inject(method = "renderMountHealth", at = @At("HEAD"), cancellable = true)
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java
index e1af85ea..293d301f 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java
@@ -5,7 +5,6 @@ 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.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.render.MapRenderer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
@@ -13,12 +12,9 @@ import net.minecraft.item.FilledMapItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.map.MapState;
import net.minecraft.nbt.NbtCompound;
-import net.minecraft.util.Identifier;
import org.apache.commons.lang3.StringUtils;
public class DungeonMap {
- private static final Identifier MAP_BACKGROUND = new Identifier("textures/map/map_background.png");
-
public static void render(MatrixStack matrices) {
MinecraftClient client = MinecraftClient.getInstance();
if (client.player == null || client.world == null) return;
@@ -46,13 +42,7 @@ public class DungeonMap {
}
}
- public static void renderHUDMap(DrawContext context, int x, int y) {
- float scaling = SkyblockerConfigManager.get().locations.dungeons.mapScaling;
- int size = (int) (128 * scaling);
- context.drawTexture(MAP_BACKGROUND, x, y, 0, 0, size, size, size, size);
- }
-
- public static void init() {
+ public static void init() { //Todo: consider renaming the command to a more general name since it'll also have dungeon score and maybe other stuff in the future
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker")
.then(ClientCommandManager.literal("hud")
.then(ClientCommandManager.literal("dungeonmap")
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java
index 02b08254..0f42c495 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java
@@ -5,13 +5,17 @@ import de.hysky.skyblocker.utils.render.RenderHelper;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
import java.awt.*;
public class DungeonMapConfigScreen extends Screen {
- private int hudX = SkyblockerConfigManager.get().locations.dungeons.mapX;
- private int hudY = SkyblockerConfigManager.get().locations.dungeons.mapY;
+ private int mapX = SkyblockerConfigManager.get().locations.dungeons.mapX;
+ private int mapY = SkyblockerConfigManager.get().locations.dungeons.mapY;
+ private int scoreX = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreX;
+ private int scoreY = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreY;
+ private static final Identifier MAP_BACKGROUND = new Identifier("textures/map/map_background.png");
private final Screen parent;
protected DungeonMapConfigScreen() {
@@ -27,17 +31,23 @@ public class DungeonMapConfigScreen extends Screen {
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);
renderBackground(context, mouseX, mouseY, delta);
- DungeonMap.renderHUDMap(context, hudX, hudY);
+ renderHUDMap(context, mapX, mapY);
+ renderHUDScore(context, scoreX, scoreY);
context.drawCenteredTextWithShadow(textRenderer, "Right Click To Reset Position", width >> 1, height >> 1, Color.GRAY.getRGB());
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
- float scaling = SkyblockerConfigManager.get().locations.dungeons.mapScaling;
- int size = (int) (128 * scaling);
- if (RenderHelper.pointIsInArea(mouseX, mouseY, hudX, hudY, hudX + size, hudY + size) && button == 0) {
- hudX = (int) Math.max(Math.min(mouseX - (size >> 1), this.width - size), 0);
- hudY = (int) Math.max(Math.min(mouseY - (size >> 1), this.height - size), 0);
+ int mapSize = (int) (128 * SkyblockerConfigManager.get().locations.dungeons.mapScaling);
+ float scoreScaling = SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreScaling;
+ int scoreWidth = (int) (textRenderer.getWidth(DungeonScoreHUD.getFormattedScoreText()) * scoreScaling);
+ int scoreHeight = (int) (textRenderer.fontHeight * scoreScaling);
+ if (RenderHelper.pointIsInArea(mouseX, mouseY, mapX, mapY, mapX + mapSize, mapY + mapSize) && button == 0) {
+ mapX = (int) Math.max(Math.min(mouseX - (mapSize >> 1), this.width - mapSize), 0);
+ mapY = (int) Math.max(Math.min(mouseY - (mapSize >> 1), this.height - mapSize), 0);
+ } else if (RenderHelper.pointIsInArea(mouseX, mouseY, scoreX, scoreY, scoreX + scoreWidth, scoreY + scoreHeight) && button == 0) {
+ scoreX = (int) Math.max(Math.min(mouseX - (scoreWidth >> 1), this.width - scoreWidth), 0);
+ scoreY = (int) Math.max(Math.min(mouseY - (scoreHeight >> 1), this.height - scoreHeight), 0);
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
@@ -45,8 +55,10 @@ public class DungeonMapConfigScreen extends Screen {
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (button == 1) {
- hudX = 2;
- hudY = 2;
+ mapX = 2;
+ mapY = 2;
+ scoreX = Math.max((int) ((mapX + (64 * SkyblockerConfigManager.get().locations.dungeons.mapScaling)) - textRenderer.getWidth(DungeonScoreHUD.getFormattedScoreText()) * SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreScaling / 2), 0);
+ scoreY = (int) (mapY + (128 * SkyblockerConfigManager.get().locations.dungeons.mapScaling) + 4);
}
return super.mouseClicked(mouseX, mouseY, button);
@@ -54,10 +66,22 @@ public class DungeonMapConfigScreen extends Screen {
@Override
public void close() {
- SkyblockerConfigManager.get().locations.dungeons.mapX = hudX;
- SkyblockerConfigManager.get().locations.dungeons.mapY = hudY;
+ SkyblockerConfigManager.get().locations.dungeons.mapX = mapX;
+ SkyblockerConfigManager.get().locations.dungeons.mapY = mapY;
+ SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreX = scoreX;
+ SkyblockerConfigManager.get().locations.dungeons.dungeonScore.scoreY = scoreY;
SkyblockerConfigManager.save();
this.client.setScreen(parent);
}
+
+ public void renderHUDMap(DrawContext context, int x, int y) {
+ float scaling = SkyblockerConfigManager.get().locations.dungeons.mapScaling;
+ int size = (int) (128 * scaling);
+ context.drawTexture(MAP_BACKGROUND, x, y, 0, 0, size, size, size, size);
+ }
+
+ public void renderHUDScore(DrawContext context, int x, int y) {
+ DungeonScoreHUD.render(context, x, y);
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java
index d67d6988..10605d8b 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java
@@ -1,76 +1,389 @@
package de.hysky.skyblocker.skyblock.dungeon;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
import de.hysky.skyblocker.config.SkyblockerConfig;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.events.SkyblockEvents;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
+import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
+import de.hysky.skyblocker.utils.ApiUtils;
import de.hysky.skyblocker.utils.Constants;
+import de.hysky.skyblocker.utils.Http;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.minecraft.client.MinecraftClient;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.mob.ZombieEntity;
+import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundEvents;
+import net.minecraft.util.collection.DefaultedList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.StreamSupport;
public class DungeonScore {
- private static final SkyblockerConfig.DungeonScore CONFIG = SkyblockerConfigManager.get().locations.dungeons.dungeonScore;
- private static final Pattern DUNGEON_CLEARED_PATTERN = Pattern.compile("Cleared: (?<cleared>\\d+)% \\((?<score>\\d+)\\)");
- private static boolean sent270;
- private static boolean sent300;
-
- public static void init() {
- Scheduler.INSTANCE.scheduleCyclic(DungeonScore::tick, 20);
- ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset());
- }
-
- public static void tick() {
- MinecraftClient client = MinecraftClient.getInstance();
- if (!Utils.isInDungeons() || client.player == null) {
- reset();
- return;
- }
-
- for (String sidebarLine : Utils.STRING_SCOREBOARD) {
- Matcher dungeonClearedMatcher = DUNGEON_CLEARED_PATTERN.matcher(sidebarLine);
- if (!dungeonClearedMatcher.matches()) {
- continue;
- }
- int score = Integer.parseInt(dungeonClearedMatcher.group("score"));
- if (!DungeonManager.isInBoss()) score += 28;
- if (!sent270 && score >= 270 && score < 300) {
- if (CONFIG.enableDungeonScore270Message) {
- MessageScheduler.INSTANCE.sendMessageAfterCooldown(Constants.PREFIX.get().getString() + CONFIG.dungeonScore270Message.replaceAll("\\[score]", "270"));
- }
- if (CONFIG.enableDungeonScore270Title) {
- client.inGameHud.setDefaultTitleFade();
- client.inGameHud.setTitle(Constants.PREFIX.get().append(CONFIG.dungeonScore270Message.replaceAll("\\[score]", "270")));
- }
- if (CONFIG.enableDungeonScore270Sound) {
- client.player.playSound(SoundEvents.BLOCK_NOTE_BLOCK_PLING.value(), 100f, 0.1f);
- }
- sent270 = true;
- }
- if (!sent300 && score >= 300) {
- if (CONFIG.enableDungeonScore300Message) {
- MessageScheduler.INSTANCE.sendMessageAfterCooldown(Constants.PREFIX.get().getString() + CONFIG.dungeonScore300Message.replaceAll("\\[score]", "300"));
- }
- if (CONFIG.enableDungeonScore300Title) {
- client.inGameHud.setDefaultTitleFade();
- client.inGameHud.setTitle(Constants.PREFIX.get().append(CONFIG.dungeonScore300Message.replaceAll("\\[score]", "300")));
- }
- if (CONFIG.enableDungeonScore300Sound) {
- client.player.playSound(SoundEvents.BLOCK_NOTE_BLOCK_PLING.value(), 100f, 0.1f);
- }
- sent300 = true;
- }
- break;
- }
- }
-
- private static void reset() {
- sent270 = false;
- sent300 = false;
- }
+ private static final SkyblockerConfig.DungeonScore SCORE_CONFIG = SkyblockerConfigManager.get().locations.dungeons.dungeonScore;
+ private static final SkyblockerConfig.MimicMessage MIMIC_MESSAGE_CONFIG = SkyblockerConfigManager.get().locations.dungeons.mimicMessage;
+ private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Dungeon Score");
+ //Scoreboard patterns
+ private static final Pattern CLEARED_PATTERN = Pattern.compile("Cleared: (?<cleared>\\d+)%.*");
+ private static final Pattern FLOOR_PATTERN = Pattern.compile(".*?(?=T)The Catacombs \\((?<floor>[EFM]\\D*\\d*)\\)");
+ //Playerlist patterns
+ private static final Pattern SECRETS_PATTERN = Pattern.compile("Secrets Found: (?<secper>\\d+\\.?\\d*)%");
+ private static final Pattern PUZZLES_PATTERN = Pattern.compile(".+?(?=:): \\[(?<state>.)](?: \\(\\w+\\))?");
+ private static final Pattern PUZZLE_COUNT_PATTERN = Pattern.compile("Puzzles: \\((?<count>\\d+)\\)");
+ private static final Pattern CRYPTS_PATTERN = Pattern.compile("Crypts: (?<crypts>\\d+)");
+ private static final Pattern COMPLETED_ROOMS_PATTERN = Pattern.compile(" *Completed Rooms: (?<rooms>\\d+)");
+ //Chat patterns
+ private static final Pattern DEATHS_PATTERN = Pattern.compile(" \\u2620 (?<whodied>\\S+) .*");
+ private static final Pattern MIMIC_PATTERN = Pattern.compile(".*?(?:Mimic dead!?|Mimic Killed!|\\$SKYTILS-DUNGEON-SCORE-MIMIC\\$|\\Q" + MIMIC_MESSAGE_CONFIG.mimicMessage + "\\E)$");
+ //Other patterns
+ private static final Pattern MIMIC_FLOORS_PATTERN = Pattern.compile("[FM][67]");
+
+ private static FloorRequirement floorRequirement;
+ private static String currentFloor;
+ private static boolean isCurrentFloorEntrance;
+ private static boolean floorHasMimics;
+ private static boolean sent270;
+ private static boolean sent300;
+ private static boolean mimicKilled;
+ private static boolean dungeonStarted;
+ private static boolean isMayorPaul;
+ private static boolean firstDeathHasSpiritPet;
+ private static boolean bloodRoomCompleted;
+ private static long startingTime;
+ private static int puzzleCount;
+ private static int deathCount;
+ private static int score;
+ private static final Map<String, Boolean> SpiritPetCache = new HashMap<>();
+
+ public static void init() {
+ Scheduler.INSTANCE.scheduleCyclic(DungeonScore::tick, 20);
+ SkyblockEvents.LEAVE.register(SpiritPetCache::clear);
+ ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset());
+ ClientReceiveMessageEvents.GAME.register((message, overlay) -> {
+ if (overlay || !Utils.isInDungeons()) return;
+ String str = message.getString();
+ if (!dungeonStarted) {
+ checkMessageForMort(str);
+ } else {
+ checkMessageForDeaths(str);
+ checkMessageForWatcher(str);
+ if (floorHasMimics) checkMessageForMimic(str); //Only called when the message is not cancelled & isn't on the action bar, complementing MimicFilter
+ }
+ });
+ ClientReceiveMessageEvents.GAME_CANCELED.register((message, overlay) -> {
+ if (overlay || !Utils.isInDungeons() || !dungeonStarted) return;
+ checkMessageForDeaths(message.getString());
+ });
+ }
+
+ public static void tick() {
+ MinecraftClient client = MinecraftClient.getInstance();
+ if (!Utils.isInDungeons() || client.player == null) {
+ reset();
+ return;
+ }
+ if (!dungeonStarted) return;
+
+ score = calculateScore();
+ if (!sent270 && !sent300 && score >= 270 && score < 300) {
+ if (SCORE_CONFIG.enableDungeonScore270Message) {
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown("/pc " + Constants.PREFIX.get().getString() + SCORE_CONFIG.dungeonScore270Message.replaceAll("\\[score]", "270"));
+ }
+ if (SCORE_CONFIG.enableDungeonScore270Title) {
+ client.inGameHud.setDefaultTitleFade();
+ client.inGameHud.setTitle(Constants.PREFIX.get().append(SCORE_CONFIG.dungeonScore270Message.replaceAll("\\[score]", "270")));
+ }
+ if (SCORE_CONFIG.enableDungeonScore270Sound) {
+ client.player.playSound(SoundEvents.BLOCK_NOTE_BLOCK_PLING.value(), 100f, 0.1f);
+ }
+ sent270 = true;
+ }
+ if (!sent300 && score >= 300) {
+ if (SCORE_CONFIG.enableDungeonScore300Message) {
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown("/pc " + Constants.PREFIX.get().getString() + SCORE_CONFIG.dungeonScore300Message.replaceAll("\\[score]", "300"));
+ }
+ if (SCORE_CONFIG.enableDungeonScore300Title) {
+ client.inGameHud.setDefaultTitleFade();
+ client.inGameHud.setTitle(Constants.PREFIX.get().append(SCORE_CONFIG.dungeonScore300Message.replaceAll("\\[score]", "300")));
+ }
+ if (SCORE_CONFIG.enableDungeonScore300Sound) {
+ client.player.playSound(SoundEvents.BLOCK_NOTE_BLOCK_PLING.value(), 100f, 0.1f);
+ }
+ sent300 = true;
+ }
+ }
+
+ private static void reset() {
+ floorRequirement = null;
+ currentFloor = "";
+ isCurrentFloorEntrance = false;
+ floorHasMimics = false;
+ sent270 = false;
+ sent300 = false;
+ mimicKilled = false;
+ dungeonStarted = false;
+ isMayorPaul = false;
+ firstDeathHasSpiritPet = false;
+ bloodRoomCompleted = false;
+ startingTime = 0L;
+ puzzleCount = 0;
+ deathCount = 0;
+ score = 0;
+ }
+
+ private static void onDungeonStart() {
+ setCurrentFloor();
+ dungeonStarted = true;
+ puzzleCount = getPuzzleCount();
+ isMayorPaul = Utils.getMayor().equals("Paul");
+ startingTime = System.currentTimeMillis();
+ floorRequirement = FloorRequirement.valueOf(currentFloor);
+ floorHasMimics = MIMIC_FLOORS_PATTERN.matcher(currentFloor).matches();
+ if (currentFloor.equals("E")) isCurrentFloorEntrance = true;
+ }
+
+ private static int calculateScore() {
+ if (isCurrentFloorEntrance) return Math.round(calculateTimeScore() * 0.7f) + Math.round(calculateExploreScore() * 0.7f) + Math.round(calculateSkillScore() * 0.7f) + Math.round(calculateBonusScore() * 0.7f);
+ return calculateTimeScore() + calculateExploreScore() + calculateSkillScore() + calculateBonusScore();
+ }
+
+ private static int calculateSkillScore() {
+ int totalRooms = getTotalRooms(); //This is necessary to avoid division by 0 at the start of dungeons, which results in infinite score
+ return 20 + Math.max((totalRooms != 0 ? (int) (80.0 * (getCompletedRooms() + getExtraCompletedRooms()) / totalRooms) : 0) - getPuzzlePenalty() - getDeathScorePenalty(), 0); //Can't go below 20 skill score
+ }
+
+ private static int calculateExploreScore() {
+ int totalRooms = getTotalRooms(); //This is necessary to avoid division by 0 at the start of dungeons, which results in infinite score
+ int completedRoomScore = totalRooms != 0 ? (int) (60.0 * (getCompletedRooms() + getExtraCompletedRooms()) / totalRooms) : 0;
+ int secretsScore = (int) (40 * Math.min(floorRequirement.percentage, getSecretsPercentage()) / floorRequirement.percentage);
+ return Math.max(completedRoomScore + secretsScore, 0);
+ }
+
+ private static int calculateTimeScore() {
+ int score = 100;
+ int timeSpent = (int) (System.currentTimeMillis() - startingTime) / 1000;
+ if (timeSpent < floorRequirement.timeLimit) return score;
+
+ double timePastRequirement = ((double) (timeSpent - floorRequirement.timeLimit) / floorRequirement.timeLimit) * 100;
+ if (timePastRequirement < 20) return score - (int) timePastRequirement / 2;
+ if (timePastRequirement < 40) return score - (int) (10 + (timePastRequirement - 20) / 4);
+ if (timePastRequirement < 50) return score - (int) (15 + (timePastRequirement - 40) / 5);
+ if (timePastRequirement < 60) return score - (int) (17 + (timePastRequirement - 50) / 6);
+ return Math.max(score - (int) (18 + (2.0 / 3.0) + (timePastRequirement - 60) / 7), 0); //This can theoretically go down to -20 if the time limit is one of the lower ones like 480, but individual score categories can't go below 0
+ }
+
+ private static int calculateBonusScore() {
+ int paulScore = isMayorPaul ? 10 : 0;
+ int cryptsScore = Math.min(getCrypts(), 5);
+ int mimicScore = mimicKilled ? 2 : 0;
+ if (getSecretsPercentage() >= 100 && floorHasMimics) mimicScore = 2; //If mimic kill is not announced but all secrets are found, mimic must've been killed
+ return paulScore + cryptsScore + mimicScore;
+ }
+
+ public static boolean isEntityMimic(Entity entity) {
+ if (!Utils.isInDungeons() || !floorHasMimics || !(entity instanceof ZombieEntity zombie) || !zombie.isBaby()) return false;
+ try {
+ DefaultedList<ItemStack> armor = (DefaultedList<ItemStack>) zombie.getArmorItems();
+ return armor.stream().allMatch(ItemStack::isEmpty);
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker] Failed to check if entity is a mimic!", e);
+ return false;
+ }
+ }
+
+ public static void handleEntityDeath(Entity entity) {
+ if (mimicKilled) return;
+ if (!isEntityMimic(entity)) return;
+ if (MIMIC_MESSAGE_CONFIG.sendMimicMessage) MessageScheduler.INSTANCE.sendMessageAfterCooldown(MIMIC_MESSAGE_CONFIG.mimicMessage);
+ mimicKilled = true;
+ }
+
+ public static void onMimicKill() {