Skip to content
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
31 changes: 31 additions & 0 deletions src/tel/eden/mod/EdenModClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ public String liveDiscordRank() {
}

private boolean onWynncraft;

public boolean onWynncraft() {
return onWynncraft;
}
// Mutated on the inbound-message path and read from GUI screens on the render
// thread. Each change publishes one immutable snapshot through this volatile field,
// so readers cannot observe the remove/add or clear/addAll halves of an update.
Expand Down Expand Up @@ -518,6 +522,7 @@ public boolean isChiefOwnerOrStrategist() {
public void onWorldRespawn() {
enteredWynnGameWorld = true;
guildLogSync.onWorldJoin();
tel.eden.mod.raid.WitnessCooldownTracker.reset();
}

/** Packet hooks for the invisible guild-log query (mirrors Wynntils' query path). */
Expand Down Expand Up @@ -639,6 +644,7 @@ public void release() {
HudRenderCallback.EVENT.register((graphics, tickCounter) -> {
if (onWynncraft) {
WarHud.render(config, graphics);
tel.eden.mod.raid.WitnessCooldownTracker.render(config, graphics);
}
});
// War-suite territory outlines, added to the per-frame gizmo collector during
Expand All @@ -663,6 +669,7 @@ public void release() {
AllianceMenuScraper.reset();
GuildMenuScraper.reset();
AttackTimerMenu.onWorldJoin();
tel.eden.mod.raid.WitnessCooldownTracker.reset();
tel.eden.mod.war.radiance.RadianceTracker.onJoin();
guildAllyManager.requestCancel();
// Connect if applicable; the backend reports link/membership standing via
Expand Down Expand Up @@ -1085,6 +1092,27 @@ public void onRadianceCast(String sender, String senderUuid, String groupKey, in
});
}

@Override
public void onWitnessKill(String sender, String senderUuid, long timestamp) {
Minecraft mc = Minecraft.getInstance();
mc.execute(() -> {
if (mc.player == null) {
return;
}
String myUuid = mc.player.getUUID().toString().replace("-", "");
String cleanSenderUuid = senderUuid != null ? senderUuid.replace("-", "").trim() : "";
if (!cleanSenderUuid.isEmpty() && cleanSenderUuid.equalsIgnoreCase(myUuid)) {
return;
}
if (sender != null && !sender.isBlank()) {
if (sender.equalsIgnoreCase(mc.player.getGameProfile().name()) || sender.equalsIgnoreCase(mc.player.getName().getString())) {
return;
}
}
tel.eden.mod.raid.WitnessCooldownTracker.onRemoteWitnessKill(sender);
});
}

@Override
public void onConnectionRejected(String code) {
pendingConnectionCode = code;
Expand Down Expand Up @@ -2371,6 +2399,7 @@ private synchronized void disconnect() {
RaidReadyTracker.reset();
PartyHealthTracker.reset();
ChatReplyManager.reset();
tel.eden.mod.raid.WitnessCooldownTracker.reset();
tel.eden.mod.war.radiance.RadianceTracker.onDisconnect();
guildAllyManager.requestCancel();
territoryDefendedTracker.clear();
Expand Down Expand Up @@ -2425,6 +2454,7 @@ public void handleSystemChat(Component message) {
DiscordChatFormatter.onServerChatLine();
if (onWynncraft) {
RaidReadyTracker.onSystemChat(message);
tel.eden.mod.raid.WitnessCooldownTracker.onChatMessage(message);
// War chat cues (start countdown → attendance capture; end → HUD summary)
// work even while the bridge socket is down. Keep these deferred until after
// this packet handler returns, alongside the rest of the client-tick state.
Expand Down Expand Up @@ -2452,6 +2482,7 @@ public void handleSystemChat(Component message) {
// needs a new bounded startup-recovery window for it.
guildLogSync.onWorldJoin();
territoryDefendedTracker.clear();
tel.eden.mod.raid.WitnessCooldownTracker.reset();
setInGameWorld(true);
}
BridgeWebSocketClient current = socket;
Expand Down
3 changes: 3 additions & 0 deletions src/tel/eden/mod/config/BridgeConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ public void sanitize() {
/** Disallow readying up in the raid menu if the raid is not a guild raid. */
public boolean requireGuildRaid = false;

/** Witness cooldown HUD timer for Orphion's Nexus of Light Room 2. */
public boolean witnessCooldownTracker = true;

/** Custom palette for the 10 party slots. Defaults to PartyHighlightManager.DEFAULT_PALETTE. */
public List<Integer> partyColors = new ArrayList<>(tel.eden.mod.party.PartyHighlightManager.DEFAULT_PALETTE);

Expand Down
1 change: 1 addition & 0 deletions src/tel/eden/mod/gui/BridgeConfigScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ protected void init() {
IntConfigSlider gambitSlider = new IntConfigSlider(CONTROL_W, 20, 0, 3, 1, () -> config.raidGambitMinimum, v -> config.raidGambitMinimum = v, v -> Component.literal(v == 0 ? "Off (0)" : String.valueOf(v)));
addSliderRow(Category.PARTY_RAIDS, "Minimum raid gambits", gambitSlider, gambitSlider::syncFromConfig, () -> config.raidGambitMinimum = 1);
addToggleRow(Category.PARTY_RAIDS, "Require guild raid to ready", () -> config.requireGuildRaid, v -> config.requireGuildRaid = v, "On", "Off", false);
addToggleRow(Category.PARTY_RAIDS, "Witness cooldown timer", () -> config.witnessCooldownTracker, v -> config.witnessCooldownTracker = v, "On", "Off", true);

// War & Territory
addToggleRow(Category.WAR, "Attack timers HUD", () -> config.warAttackTimers, v -> config.warAttackTimers = v, "On", "Off", true);
Expand Down
2 changes: 1 addition & 1 deletion src/tel/eden/mod/hud/HudPanels.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
*/
public record HudPanels(String name, String label, float defaultX, float defaultY, int previewWidth, int previewHeight) {

public static final List<HudPanels> ALL = List.of(new HudPanels("attackTimers", "Attack timers", 0.40f, 0.14f, 130, 44), new HudPanels("warInfo", "War info overlay", 0.015f, 0.30f, 150, 74), new HudPanels("weeklyWars", "Weekly war count", 0.83f, 0.04f, 60, 12), new HudPanels("radianceTracker", "Radiance tracker", 0.50f, 0.35f, 110, 24));
public static final List<HudPanels> ALL = List.of(new HudPanels("attackTimers", "Attack timers", 0.40f, 0.14f, 130, 44), new HudPanels("warInfo", "War info overlay", 0.015f, 0.30f, 150, 74), new HudPanels("weeklyWars", "Weekly war count", 0.83f, 0.04f, 60, 12), new HudPanels("radianceTracker", "Radiance tracker", 0.50f, 0.35f, 110, 24), new HudPanels("witnessCooldown", "Witness cooldown", 0.45f, 0.40f, 90, 16));
}
6 changes: 5 additions & 1 deletion src/tel/eden/mod/mixin/ClientPacketListenerMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class ClientPacketListenerMixin {
EdenModClient mod = EdenModClient.instance();
if (mod != null) {
mod.handleWynncraftActionBar(packet.text());
if (mod.onWynncraft()) {
tel.eden.mod.raid.WitnessCooldownTracker.onMessage(packet.text());
}
}
}
}
Expand Down Expand Up @@ -122,8 +125,9 @@ public class ClientPacketListenerMixin {
if (packet.overlay()) {
// Reward feedback may be rendered as Wynncraft's ticker/action bar rather than a
// chat line. It is bookkeeping input, but must not enter the general chat relay.
if (mod != null) {
if (mod != null && mod.onWynncraft()) {
mod.handleRewardFeedback(packet.content());
tel.eden.mod.raid.WitnessCooldownTracker.onMessage(packet.content());
}
return;
}
Expand Down
34 changes: 34 additions & 0 deletions src/tel/eden/mod/net/BridgeWebSocketClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ default void onRadianceCast(String sender, String groupKey, int tier, long remai
default void onRadianceGroupCount(String groupKey, int count) {
}

/** A raid party member or group peer reported an Athanatic Witness kill. */
default void onWitnessKill(String sender, String senderUuid, long timestamp) {
}

/**
* The Mojang session was verified ({@code authOk}); {@code linked} and
* {@code member} report this player's backend standing. Both true means full
Expand Down Expand Up @@ -658,6 +662,35 @@ public boolean sendRadianceCast(String groupKey, int tier, long remainingMs) {
return true;
}

/**
* Broadcast an Athanatic Witness kill to the raid party.
*
* @return whether the message was queued on a connected socket
*/
public boolean sendWitnessKill(java.util.List<String> partyMembers) {
WebSocket current = socket;
if (current == null) {
return false;
}
enqueueSend(current, witnessKillPayload(partyMembers).toString());
return true;
}

static JsonObject witnessKillPayload(java.util.List<String> partyMembers) {
JsonObject obj = new JsonObject();
obj.addProperty("type", "witnessKill");
if (partyMembers != null && !partyMembers.isEmpty()) {
com.google.gson.JsonArray arr = new com.google.gson.JsonArray();
for (String member : partyMembers) {
if (member != null && !member.isBlank()) {
arr.add(member.trim());
}
}
obj.add("party", arr);
}
return obj;
}

/**
* Toggle this player's "heading to {@code territory}" marker (right-click on a timer
* row). One assignment per player: marking a new territory moves them, re-marking the
Expand Down Expand Up @@ -1136,6 +1169,7 @@ private void handlePayload(String payload) {
case "warBoard" -> sink.onWarBoard(parseWarBoard(obj));
case "radianceGroupCount" -> sink.onRadianceGroupCount(get(obj, "groupKey"), getInt(obj, "count", 0));
case "radianceCast" -> sink.onRadianceCast(get(obj, "sender"), get(obj, "senderUuid"), get(obj, "groupKey"), getInt(obj, "tier", 0), getLong(obj, "remainingMs", 0L), getLong(obj, "timestamp", System.currentTimeMillis()));
case "witnessKill" -> sink.onWitnessKill(get(obj, "sender"), get(obj, "senderUuid"), getLong(obj, "timestamp", System.currentTimeMillis()));
case "authChallenge" -> handleAuthChallenge(get(obj, "serverId"));
case "authOk" -> {
// Session verified: reset backoff and hand the backend-reported
Expand Down
10 changes: 10 additions & 0 deletions src/tel/eden/mod/party/PartyHealthTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ public static PlayerHealthData getHealth(UUID uuid) {
return HEALTH_BY_UUID.get(uuid);
}

public static List<String> getTrackedPartyNames() {
List<String> names = new ArrayList<>();
for (PlayerHealthData data : HEALTH_BY_UUID.values()) {
if (data.name() != null && !data.name().isBlank()) {
names.add(data.name());
}
}
return names;
}

public static void tick() {
tickCounter++;
if (tickCounter % 5 != 0) {
Expand Down
Loading
Loading