Skip to content

Commit

Permalink
Class-based player glow
Browse files Browse the repository at this point in the history
  • Loading branch information
AzureAaron committed Dec 29, 2024
1 parent 7ce731f commit 854c45d
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
newValue -> config.dungeons.playerSecretsTracker = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.dungeons.classBasedPlayerGlow"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.classBasedPlayerGlow.@Tooltip")))
.binding(defaults.dungeons.classBasedPlayerGlow,
() -> config.dungeons.classBasedPlayerGlow,
newValue -> config.dungeons.classBasedPlayerGlow = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.dungeons.starredMobGlow"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobGlow.@Tooltip")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public class DungeonsConfig {
@SerialEntry
public boolean playerSecretsTracker = false;

@SerialEntry
public boolean classBasedPlayerGlow = false;

@SerialEntry
public boolean starredMobGlow = false;

Expand Down
48 changes: 30 additions & 18 deletions src/main/java/de/hysky/skyblocker/events/DungeonEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,36 @@
import net.fabricmc.fabric.api.event.EventFactory;

public class DungeonEvents {
public static final Event<RoomMatched> PUZZLE_MATCHED = EventFactory.createArrayBacked(RoomMatched.class, callbacks -> room -> {
for (RoomMatched callback : callbacks) {
callback.onRoomMatched(room);
}
});
public static final Event<RoomMatched> PUZZLE_MATCHED = EventFactory.createArrayBacked(RoomMatched.class, callbacks -> room -> {
for (RoomMatched callback : callbacks) {
callback.onRoomMatched(room);
}
});

public static final Event<RoomMatched> ROOM_MATCHED = EventFactory.createArrayBacked(RoomMatched.class, callbacks -> room -> {
for (RoomMatched callback : callbacks) {
callback.onRoomMatched(room);
}
if (room.getType() == Room.Type.PUZZLE) {
PUZZLE_MATCHED.invoker().onRoomMatched(room);
}
});
public static final Event<RoomMatched> ROOM_MATCHED = EventFactory.createArrayBacked(RoomMatched.class, callbacks -> room -> {
for (RoomMatched callback : callbacks) {
callback.onRoomMatched(room);
}
if (room.getType() == Room.Type.PUZZLE) {
PUZZLE_MATCHED.invoker().onRoomMatched(room);
}
});

@Environment(EnvType.CLIENT)
@FunctionalInterface
public interface RoomMatched {
void onRoomMatched(Room room);
}
public static final Event<DungeonStarted> DUNGEON_STARTED = EventFactory.createArrayBacked(DungeonStarted.class, callbacks -> () -> {
for (DungeonStarted callback : callbacks) {
callback.onDungeonStarted();
}
});

@Environment(EnvType.CLIENT)
@FunctionalInterface
public interface RoomMatched {
void onRoomMatched(Room room);
}

@Environment(EnvType.CLIENT)
@FunctionalInterface
public interface DungeonStarted {
void onDungeonStarted();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package de.hysky.skyblocker.skyblock.dungeon;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import de.hysky.skyblocker.skyblock.entity.MobGlow;

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

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;

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

public String displayName() {
return this.name;
}

/**
* @return The color of the class in RGB format.
*/
public int color() {
return this.color;
}

public static DungeonClass from(String name) {
return CLASSES.getOrDefault(name, UNKNOWN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import de.hysky.skyblocker.annotations.Init;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.DungeonsConfig;
import de.hysky.skyblocker.events.DungeonEvents;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import de.hysky.skyblocker.utils.Constants;
Expand Down Expand Up @@ -67,12 +68,11 @@ public class DungeonScore {
public static void init() {
Scheduler.INSTANCE.scheduleCyclic(DungeonScore::tick, 20);
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset());
DungeonEvents.DUNGEON_STARTED.register(DungeonScore::onDungeonStart);
ClientReceiveMessageEvents.GAME.register((message, overlay) -> {
if (overlay || !Utils.isInDungeons()) return;
String str = message.getString();
if (!dungeonStarted) {
checkMessageForMort(str);
} else {
if (dungeonStarted) {
checkMessageForDeaths(str);
checkMessageForWatcher(str);
if (floorHasMimics) checkMessageForMimic(str); //Only called when the message is not cancelled & isn't on the action bar, complementing MimicFilter
Expand Down Expand Up @@ -315,11 +315,6 @@ private static void checkMessageForWatcher(String message) {
if (message.equals("[BOSS] The Watcher: You have proven yourself. You may pass.")) bloodRoomCompleted = true;
}

private static void checkMessageForMort(String message) {
if (!message.equals("§e[NPC] §bMort§f: You should find it useful if you get lost.")) return;
onDungeonStart();
}

private static void checkMessageForMimic(String message) {
if (!MIMIC_PATTERN.matcher(message).matches()) return;
onMimicKill();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.DungeonsConfig;
import de.hysky.skyblocker.debug.Debug;
import de.hysky.skyblocker.events.DungeonEvents;
import de.hysky.skyblocker.skyblock.dungeon.DungeonBoss;
import de.hysky.skyblocker.skyblock.dungeon.DungeonMap;
import de.hysky.skyblocker.utils.Constants;
Expand Down Expand Up @@ -677,6 +678,10 @@ private static void onChatMessage(Text text, boolean overlay) {
}
}

if (message.equals("§e[NPC] §bMort§f: You should find it useful if you get lost.")) {
DungeonEvents.DUNGEON_STARTED.invoker().onDungeonStarted();
}

var newBoss = DungeonBoss.fromMessage(message);
if (!isInBoss() && newBoss.isInBoss()) {
reset();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package de.hysky.skyblocker.skyblock.dungeon.secrets;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jetbrains.annotations.Range;

import de.hysky.skyblocker.annotations.Init;
import de.hysky.skyblocker.events.DungeonEvents;
import de.hysky.skyblocker.skyblock.dungeon.DungeonClass;
import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import it.unimi.dsi.fastutil.objects.Object2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
import net.minecraft.entity.player.PlayerEntity;

public class DungeonPlayerManager {
/**
* @implNote Same as {@link de.hysky.skyblocker.skyblock.tabhud.widget.DungeonPlayerWidget#PLAYER_PATTERN}
*/
private static final Pattern PLAYER_TAB_PATTERN = Pattern.compile("\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?<name>[A-Za-z0-9_]*) (?:.* )?\\((?<class>\\S*) ?(?<level>[LXVI]*)\\)");
private static final Object2ReferenceMap<String, DungeonClass> PLAYER_CLASSES = new Object2ReferenceOpenHashMap<>(5);

@Init
public static void init() {
DungeonEvents.DUNGEON_STARTED.register(DungeonPlayerManager::onDungeonStart);
}

public static DungeonClass getClassFromPlayer(PlayerEntity player) {
String name = player.getGameProfile().getName();

return PLAYER_CLASSES.getOrDefault(name, DungeonClass.UNKNOWN);
}

private static void onDungeonStart() {
reset();

for (int i = 0; i < 5; i++) {
Matcher matcher = getPlayerFromTab(i + 1);

if (matcher != null) {
String name = matcher.group("name");
DungeonClass dungeonClass = DungeonClass.from(matcher.group("class"));

if (dungeonClass != DungeonClass.UNKNOWN) PLAYER_CLASSES.put(name, dungeonClass);
}
}
}

private static void reset() {
PLAYER_CLASSES.clear();
}

private static Matcher getPlayerFromTab(@Range(from = 1, to = 5) int index) {
return PlayerListMgr.regexAt(1 + (index - 1) * 4, PLAYER_TAB_PATTERN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.google.gson.JsonParser;
import de.hysky.skyblocker.annotations.Init;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.events.DungeonEvents;
import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import de.hysky.skyblocker.skyblock.tabhud.widget.DungeonPlayerWidget;
import de.hysky.skyblocker.utils.ApiUtils;
Expand Down Expand Up @@ -41,6 +42,7 @@ public class SecretsTracker {
@Init
public static void init() {
ClientReceiveMessageEvents.GAME.register(SecretsTracker::onMessage);
DungeonEvents.DUNGEON_STARTED.register(() -> calculate(RunPhase.START));
}

private static void calculate(RunPhase phase) {
Expand Down Expand Up @@ -101,7 +103,6 @@ private static void calculate(RunPhase phase) {
}

private static void sendResultMessage(String player, SecretData secretData, boolean success) {
@SuppressWarnings("resource")
PlayerEntity playerEntity = MinecraftClient.getInstance().player;
if (playerEntity != null) {
if (success) {
Expand All @@ -122,7 +123,6 @@ private static void onMessage(Text text, boolean overlay) {
String message = Formatting.strip(text.getString());

try {
if (message.equals("[NPC] Mort: Here, I found this map when I first entered the dungeon.")) calculate(RunPhase.START);
if (TEAM_SCORE_PATTERN.matcher(message).matches()) calculate(RunPhase.END);
} catch (Exception e) {
LOGGER.error("[Skyblocker] Encountered an unknown error while trying to track player secrets!", e);
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import de.hysky.skyblocker.config.configs.SlayersConfig;
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.LividColor;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager;
import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.slayers.SlayerManager;
import de.hysky.skyblocker.skyblock.slayers.SlayerType;
Expand All @@ -32,6 +34,7 @@
import java.util.List;

public class MobGlow {
public static final int NO_GLOW = 0;
/**
* The Nukekubi head texture id is eb07594e2df273921a77c101d0bfdfa1115abed5b9b2029eb496ceba9bdbb4b3.
*/
Expand All @@ -58,7 +61,7 @@ public static boolean hasOrComputeMobGlow(Entity entity) {
return true;
}
int color = computeMobGlow(entity);
if (color != 0) {
if (color != NO_GLOW) {
CACHE.put(entity, color);
return true;
}
Expand Down Expand Up @@ -93,6 +96,9 @@ private static int computeMobGlow(Entity entity) {
case PlayerEntity p when SkyblockerConfigManager.get().dungeons.starredMobGlow && !DungeonManager.getBoss().isFloor(4) && name.equals("Diamond Guy") -> 0x57c2f7;
case PlayerEntity p when entity.getId() == LividColor.getCorrectLividId() && LividColor.shouldGlow(name) -> LividColor.getGlowColor(name);

//Class-based glow
case PlayerEntity p when SkyblockerConfigManager.get().dungeons.classBasedPlayerGlow && DungeonScore.isDungeonStarted() -> DungeonPlayerManager.getClassFromPlayer(p).color();

// Bats
case BatEntity b when SkyblockerConfigManager.get().dungeons.starredMobGlow -> 0xf57738;

Expand All @@ -104,7 +110,7 @@ private static int computeMobGlow(Entity entity) {

// Regular Mobs
case Entity e when SkyblockerConfigManager.get().dungeons.starredMobGlow && isStarred(entity) -> 0xf57738;
default -> 0;
default -> NO_GLOW;
};
}

Expand Down Expand Up @@ -137,7 +143,7 @@ private static int computeMobGlow(Entity entity) {
case WitherSkeletonEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW && SlayerManager.isInSlayerType(SlayerType.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15 -> AttunementColors.getColor(e);
case ZombifiedPiglinEntity e when SkyblockerConfigManager.get().slayers.highlightBosses == SlayersConfig.HighlightSlayerEntities.GLOW && SlayerManager.isInSlayerType(SlayerType.DEMONLORD) && e.distanceTo(MinecraftClient.getInstance().player) <= 15 -> AttunementColors.getColor(e);

default -> 0;
default -> NO_GLOW;
};
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/assets/skyblocker/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
"skyblocker.config.dungeons.croesusHelper": "Croesus Helper",
"skyblocker.config.dungeons.croesusHelper.@Tooltip": "Gray out chests that have already been opened.",

"skyblocker.config.dungeons.classBasedPlayerGlow": "Class-based Player Glow",
"skyblocker.config.dungeons.classBasedPlayerGlow.@Tooltip": "Changes the color of your teammates glow to be based on their class rather than their rank.",

"skyblocker.config.dungeons.goldorWaypoints": "Goldor Tasks Waypoints (F7/M7)",
"skyblocker.config.dungeons.goldorWaypoints.enableGoldorWaypoints": "Enable waypoints for terminals/devices/levers during Goldor",
"skyblocker.config.dungeons.goldorWaypoints.waypointType": "Task waypoint type",
Expand Down

0 comments on commit 854c45d

Please sign in to comment.