Skip to content

Commit 870428b

Browse files
committed
1.4.0
1 parent e94670b commit 870428b

31 files changed

+1932
-80
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ minecraft_version=1.21.8
77
loader_version=0.16.4
88
kotlin_loader_version=1.13.4+kotlin.2.2.0
99
# Mod Properties
10-
mod_version=1.3.0
10+
mod_version=1.4.0
1111
maven_group=cc.pe3epwithyou
1212
archives_base_name=island++
1313
# Dependencies

src/main/java/cc/pe3epwithyou/trident/mixin/AbstractContainerScreenMixin.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import cc.pe3epwithyou.trident.config.Config;
55
import cc.pe3epwithyou.trident.feature.BlueprintIndicators;
66
import cc.pe3epwithyou.trident.feature.CraftableIndicator;
7+
import cc.pe3epwithyou.trident.net.IslandExchangeService;
8+
import cc.pe3epwithyou.trident.utils.TradeableDetector;
79
import cc.pe3epwithyou.trident.feature.fishing.TideWindIndicator;
810
import cc.pe3epwithyou.trident.feature.rarityslot.RaritySlot;
911
import cc.pe3epwithyou.trident.state.MCCIState;
@@ -14,6 +16,8 @@
1416
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
1517
import net.minecraft.client.gui.screens.inventory.ContainerScreen;
1618
import net.minecraft.network.chat.Component;
19+
import net.minecraft.network.chat.Style;
20+
import net.minecraft.ChatFormatting;
1721
import net.minecraft.world.inventory.Slot;
1822
import org.spongepowered.asm.mixin.Mixin;
1923
import org.spongepowered.asm.mixin.injection.At;

src/main/java/cc/pe3epwithyou/trident/mixin/JoinIslandMixin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import cc.pe3epwithyou.trident.modrinth.UpdateChecker;
44
import cc.pe3epwithyou.trident.interfaces.DialogCollection;
5+
import cc.pe3epwithyou.trident.net.IslandExchangeService;
56
import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
67
import net.minecraft.client.multiplayer.ServerData;
78
import net.minecraft.network.protocol.login.ClientboundLoginFinishedPacket;
@@ -24,5 +25,6 @@ private void loginFinished(ClientboundLoginFinishedPacket clientboundLoginFinish
2425
if (this.serverData == null) return;
2526
if (!this.serverData.ip.toLowerCase().contains("mccisland.net")) return;
2627
UpdateChecker.INSTANCE.checkForUpdates();
28+
IslandExchangeService.INSTANCE.refreshNow("JoinIslandMixin");
2729
}
2830
}

src/main/kotlin/cc/pe3epwithyou/trident/client/TridentClient.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ import cc.pe3epwithyou.trident.client.events.QuestingEvents
44
import cc.pe3epwithyou.trident.client.listeners.ChatEventListener
55
import cc.pe3epwithyou.trident.client.listeners.ChestScreenListener
66
import cc.pe3epwithyou.trident.client.listeners.SpotEntityListener
7+
import cc.pe3epwithyou.trident.client.listeners.TooltipExchangeListener
78
import cc.pe3epwithyou.trident.client.listeners.KillChatListener
89
import cc.pe3epwithyou.trident.client.listeners.TideWindBossbarListener
10+
import cc.pe3epwithyou.trident.client.listeners.MeterResetListener
11+
import cc.pe3epwithyou.trident.client.listeners.UtilitiesRefreshListener
912
import cc.pe3epwithyou.trident.config.Config
1013
import cc.pe3epwithyou.trident.feature.fishing.DepletedDisplay
1114
import cc.pe3epwithyou.trident.feature.fishing.SuppliesModuleTimer
1215
import cc.pe3epwithyou.trident.feature.questing.QuestListener
1316
import cc.pe3epwithyou.trident.feature.questing.QuestStorage
1417
import cc.pe3epwithyou.trident.interfaces.DialogCollection
1518
import cc.pe3epwithyou.trident.interfaces.fishing.SuppliesDialog
19+
import cc.pe3epwithyou.trident.interfaces.UtilitiesDialog
1620
import cc.pe3epwithyou.trident.interfaces.questing.QuestingDialog
1721
import cc.pe3epwithyou.trident.interfaces.fishing.UpgradesDialog
1822
import cc.pe3epwithyou.trident.interfaces.fishing.ChanceDialog
@@ -22,6 +26,9 @@ import cc.pe3epwithyou.trident.interfaces.fishing.RodChanceDialog
2226
import cc.pe3epwithyou.trident.interfaces.fishing.PotChanceDialog
2327
import cc.pe3epwithyou.trident.interfaces.fishing.ChancePerksDialog
2428
import cc.pe3epwithyou.trident.interfaces.fishing.SpotDialog
29+
import cc.pe3epwithyou.trident.interfaces.fishing.FishDialog
30+
import cc.pe3epwithyou.trident.net.McciApi
31+
import cc.pe3epwithyou.trident.feature.fishing.FishCollectionService
2532
import cc.pe3epwithyou.trident.state.MCCIState
2633
import cc.pe3epwithyou.trident.state.PlayerState
2734
import cc.pe3epwithyou.trident.state.PlayerStateIO
@@ -49,6 +56,7 @@ class TridentClient : ClientModInitializer {
4956

5057
private val debugDialogs = mapOf(
5158
"supplies" to ::SuppliesDialog,
59+
"utilities" to ::UtilitiesDialog,
5260
"questing" to ::QuestingDialog,
5361
"upgrades" to ::UpgradesDialog,
5462
"chances" to ::ChanceDialog,
@@ -57,6 +65,7 @@ class TridentClient : ClientModInitializer {
5765
"rodchances" to ::RodChanceDialog,
5866
"potchances" to ::PotChanceDialog,
5967
"chanceperks" to ::ChancePerksDialog,
68+
//"fishcollection" to ::FishDialog,
6069
"spot" to ::SpotDialog,
6170
)
6271

@@ -67,7 +76,7 @@ class TridentClient : ClientModInitializer {
6776
}
6877

6978
private val debugCommands: LiteralArgumentBuilder<FabricClientCommandSource> =
70-
ClientCommandManager.literal("trident")
79+
ClientCommandManager.literal("islandplusplus")
7180
.then(
7281
ClientCommandManager.literal("open").then(
7382
ClientCommandManager.argument("dialog", StringArgumentType.string())
@@ -106,6 +115,15 @@ class TridentClient : ClientModInitializer {
106115
0
107116
}
108117
)).then(
118+
ClientCommandManager.literal("fish").then(
119+
ClientCommandManager.literal("reset")
120+
.executes { _ ->
121+
FishCollectionService.resetCollection()
122+
ChatUtils.sendMessage(Component.literal("Fish collection reset").withStyle(ChatFormatting.AQUA))
123+
0
124+
}
125+
)
126+
).then(
109127
ClientCommandManager.literal("resetDialogPositions")
110128
.executes { _ ->
111129
DialogCollection.resetDialogPositions()
@@ -191,10 +209,13 @@ class TridentClient : ClientModInitializer {
191209
SpotEntityListener.register()
192210
DepletedDisplay.DepletedTimer.register()
193211
TideWindBossbarListener.register()
212+
MeterResetListener.register()
194213
SuppliesModuleTimer.register()
195214
KillChatListener.register()
215+
UtilitiesRefreshListener.register()
196216
DelayedAction.init()
197217
QuestListener.register()
218+
TooltipExchangeListener.register()
198219

199220
// Register keybinding
200221
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { client: Minecraft ->

src/main/kotlin/cc/pe3epwithyou/trident/client/listeners/ChatEventListener.kt

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package cc.pe3epwithyou.trident.client.listeners
33
import cc.pe3epwithyou.trident.client.TridentClient
44
import cc.pe3epwithyou.trident.config.Config
55
import cc.pe3epwithyou.trident.feature.fishing.DepletedDisplay
6+
import cc.pe3epwithyou.trident.feature.fishing.FishCollectionService
67
import cc.pe3epwithyou.trident.interfaces.DialogCollection
8+
import cc.pe3epwithyou.trident.interfaces.meter.MeterCalculator
79
import cc.pe3epwithyou.trident.state.MCCIState
10+
import cc.pe3epwithyou.trident.state.PlayerStateIO
811
import cc.pe3epwithyou.trident.utils.Resources
912
import cc.pe3epwithyou.trident.utils.extensions.WindowExtensions.focusWindowIfInactive
1013
import cc.pe3epwithyou.trident.utils.extensions.WindowExtensions.requestAttentionIfInactive
@@ -39,6 +42,7 @@ object ChatEventListener {
3942
private fun Component.isCaughtMessage() = Regex("^\\(.\\) You caught: \\[.+].*").matches(this.string)
4043
private fun Component.isIconMessage() = Regex("^\\s*. (Triggered|Special): .+").matches(this.string)
4144
private fun Component.isXPMessage() = Regex("^\\s*. You earned: .+").matches(this.string)
45+
private fun Component.isMinigameXPMessage() = Regex("^\\s*. You receive: .+Island XP.*", RegexOption.IGNORE_CASE).matches(this.string)
4246
private fun Component.isReceivedItem() = Regex("^\\(.\\) You receive: .+").matches(this.string)
4347
private fun Component.isDepletedSpot() =
4448
Regex("^\\[.] This spot is Depleted, so you can no longer fish here\\.").matches(this.string)
@@ -112,6 +116,8 @@ object ChatEventListener {
112116
triggerBait = !checkJunk(message)
113117
lastCaughtMessage = message
114118
lastSpecial = false
119+
// Additively record fish from hover menu immediately to keep local collection fresh
120+
FishCollectionService.noteCatchFromChatHover(message)
115121
}
116122

117123
if (message.isIconMessage()) {
@@ -132,12 +138,13 @@ object ChatEventListener {
132138
ps.dailyMeter.sessionXpGained += earned
133139
ps.weeklyMeter.sessionXpGained += earned
134140
if (ps.dailyMeter.progressTarget > 0) {
135-
cc.pe3epwithyou.trident.interfaces.meter.MeterCalculator.applyXpToDaily(earned.toInt())
141+
MeterCalculator.applyXpToDaily(earned.toInt())
136142
}
137143
if (ps.weeklyMeter.progressTarget > 0) {
138-
cc.pe3epwithyou.trident.interfaces.meter.MeterCalculator.applyXpToWeekly(earned.toInt())
144+
MeterCalculator.applyXpToWeekly(earned.toInt())
139145
}
140146
DialogCollection.refreshDialog("meter")
147+
PlayerStateIO.save()
141148
}
142149

143150
if (isSupplyPreserve) {
@@ -167,7 +174,7 @@ object ChatEventListener {
167174
val isJunk = if (caughtMsg != null) checkJunk(caughtMsg) else false
168175
val caughtFish = caughtText.isNotEmpty() && !caughtSpirit && !caughtTreasure && !caughtPearl && !isJunk
169176
val caughtElusive = lastSpecial
170-
ChatUtils.debugLog(
177+
/*ChatUtils.debugLog(
171178
(
172179
"""
173180
Fishing catch parse:
@@ -182,7 +189,7 @@ object ChatEventListener {
182189
- ElusiveFish: $caughtElusive
183190
"""
184191
).trimIndent()
185-
)
192+
)*/
186193
augments.forEach { a ->
187194
if (a.paused) return@forEach
188195
val cond = a.useCondition
@@ -212,6 +219,25 @@ object ChatEventListener {
212219
DialogCollection.refreshDialog("supplies")
213220
}
214221

222+
// Minigames: end-of-game XP message "You receive: xxx Island XP"
223+
if (message.isMinigameXPMessage()) {
224+
val m = Regex("(?i)You receive:\\s*([0-9,]+)\\s*Island XP").find(message.string)
225+
val earned = m?.groupValues?.get(1)?.replace(",", "")?.toLongOrNull() ?: 0L
226+
if (earned > 0) {
227+
val ps = TridentClient.playerState
228+
ps.dailyMeter.sessionXpGained += earned
229+
ps.weeklyMeter.sessionXpGained += earned
230+
if (ps.dailyMeter.progressTarget > 0) {
231+
MeterCalculator.applyXpToDaily(earned.toInt())
232+
}
233+
if (ps.weeklyMeter.progressTarget > 0) {
234+
MeterCalculator.applyXpToWeekly(earned.toInt())
235+
}
236+
DialogCollection.refreshDialog("meter")
237+
PlayerStateIO.save()
238+
}
239+
}
240+
215241
true
216242
}
217243
}

src/main/kotlin/cc/pe3epwithyou/trident/client/listeners/ChestScreenListener.kt

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import cc.pe3epwithyou.trident.feature.questing.QuestStorage
77
import cc.pe3epwithyou.trident.feature.questing.QuestingParser
88
import cc.pe3epwithyou.trident.interfaces.DialogCollection
99
import cc.pe3epwithyou.trident.interfaces.questing.QuestingDialog
10+
import cc.pe3epwithyou.trident.state.MCCIState
1011
import cc.pe3epwithyou.trident.state.Rarity
1112
import cc.pe3epwithyou.trident.state.fishing.Augment
1213
import cc.pe3epwithyou.trident.state.MutableAugment
@@ -34,6 +35,7 @@ object ChestScreenListener {
3435
}
3536

3637
private fun handleScreen(screen: ContainerScreen) {
38+
if (!MCCIState.isOnIsland()) return
3739
if ("FISHING SUPPLIES" in screen.title.string) {
3840
DelayedAction.delayTicks(2L) {
3941
findAugments(screen)
@@ -106,6 +108,20 @@ object ChestScreenListener {
106108
return Pair(cur, max)
107109
}
108110

111+
private fun parseResetMillisFrom(line: String, label: String): Long? {
112+
// Accept variations like "Resets in:" or "Rests in:" or "Claimable in:"
113+
val norm = line.lowercase()
114+
if (!norm.contains(label.lowercase())) return null
115+
// Extract segments like 2d 3h 4m 5s (any subset, any order typical d h m, or just s)
116+
fun grab(regex: Regex): Long = regex.find(norm)?.groupValues?.get(1)?.toLongOrNull() ?: 0L
117+
val days = grab(Regex("(\\d+)d"))
118+
val hours = grab(Regex("(\\d+)h"))
119+
val mins = grab(Regex("(\\d+)m"))
120+
val secs = grab(Regex("(\\d+)s"))
121+
val totalMs = days * 86_400_000L + hours * 3_600_000L + mins * 60_000L + secs * 1_000L
122+
return if (totalMs <= 0L) null else (System.currentTimeMillis() + totalMs)
123+
}
124+
109125
fun findMeters(screen: ContainerScreen) {
110126
if ("ISLAND REWARDS" !in screen.title.string) return
111127
val slots = screen.menu.slots
@@ -116,27 +132,41 @@ object ChestScreenListener {
116132
val lore = slot.item.getLore().map { it.string }
117133
when {
118134
name.contains("Daily Meter", ignoreCase = true) -> {
135+
val st = TridentClient.playerState.dailyMeter
119136
lore.forEach { line ->
120137
parseMeterProgress(line)?.let { (cur, max) ->
121-
TridentClient.playerState.dailyMeter.progressCurrent = cur
122-
TridentClient.playerState.dailyMeter.progressTarget = max
138+
// Only additive for progress current; target follows menu
139+
// Do not count full bar (cur == max) as progress as that implies unclaimed reward
140+
// Target should NOT follow the menu; derive from current claims to avoid desync
141+
st.progressTarget = cc.pe3epwithyou.trident.interfaces.meter.MeterCalculator.nextDailyTargetFromClaims(
142+
st.claimsCurrent,
143+
st.claimsMax
144+
)
145+
if (cur > st.progressCurrent && cur < max) st.progressCurrent = cur
123146
}
124147
parseMeterClaims(line, "Daily Claims")?.let { (cur, max) ->
125-
TridentClient.playerState.dailyMeter.claimsCurrent = cur
126-
TridentClient.playerState.dailyMeter.claimsMax = max
148+
if (cur > st.claimsCurrent) st.claimsCurrent = cur
149+
if (max > st.claimsMax) st.claimsMax = max
127150
}
151+
// Resets in: xxh xxm or xxs
152+
parseResetMillisFrom(line, "Resets in:")?.let { ts -> st.nextResetAtMs = ts }
128153
}
129154
}
130155
name.contains("Weekly Vault", ignoreCase = true) -> {
156+
val st = TridentClient.playerState.weeklyMeter
131157
lore.forEach { line ->
132158
parseMeterProgress(line)?.let { (cur, max) ->
133-
TridentClient.playerState.weeklyMeter.progressCurrent = cur
134-
TridentClient.playerState.weeklyMeter.progressTarget = max
159+
// Always read from menu for weekly vault
160+
st.progressCurrent = cur
161+
st.progressTarget = max
135162
}
136163
parseMeterClaims(line, "Stored Rewards")?.let { (cur, max) ->
137-
TridentClient.playerState.weeklyMeter.claimsCurrent = cur
138-
TridentClient.playerState.weeklyMeter.claimsMax = max
164+
st.claimsCurrent = cur
165+
st.claimsMax = max
139166
}
167+
// Weekly may show days: Claimable in: xxd xxh xxm (or Resets in)
168+
parseResetMillisFrom(line, "Resets in:")?.let { ts -> st.nextResetAtMs = ts }
169+
parseResetMillisFrom(line, "Claimable in:")?.let { ts -> st.nextResetAtMs = ts }
140170
}
141171
}
142172
}
@@ -224,24 +254,35 @@ object ChestScreenListener {
224254
)
225255
TridentClient.playerState.supplies.augmentsAvailable = availableSlots
226256
// Parse uses for each augment; keep length aligned with augments list, skip locked/empty
257+
val previousAugmentsByType = TridentClient.playerState.supplies.augments.associateBy { it.augment }
227258
val mutableAugments = mutableListOf<MutableAugment>()
228259
augmentItems.forEachIndexed { idx, item ->
229260
val name = item.displayName.string
230261
if (name.contains("Locked Supply Slot") || name.contains("Empty Supply Slot")) {
231262
// skip placeholders in new structure
232263
} else {
233264
val parsed = ItemParser.getAugmentUses(item)
265+
val repair = ItemParser.parseAugmentRepairInfo(item)
234266
val augment = parsedAugments.getOrNull(idx)
235267
if (augment != null) {
236268
val meta = ItemParser.getAugmentUseCondition(item)
237269
val paused = ItemParser.isAugmentPaused(item)
270+
val prev = previousAugmentsByType[augment]
271+
val resolvedMax = parsed?.second ?: prev?.usesMax
272+
val resolvedCur = when {
273+
repair.broken -> 0
274+
else -> parsed?.first ?: prev?.usesCurrent
275+
}
238276
val mutable = MutableAugment(
239277
augment = augment,
240-
usesCurrent = parsed?.first,
241-
usesMax = parsed?.second,
278+
usesCurrent = resolvedCur,
279+
usesMax = resolvedMax,
242280
useCondition = meta.condition,
243281
paused = paused,
244-
bannedInGrotto = meta.bannedInGrotto
282+
bannedInGrotto = meta.bannedInGrotto,
283+
repairedBefore = repair.repairedBefore,
284+
broken = repair.broken,
285+
repairCost = repair.repairCost
245286
)
246287
mutableAugments.add(mutable)
247288
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package cc.pe3epwithyou.trident.client.listeners
2+
3+
import cc.pe3epwithyou.trident.client.TridentClient
4+
import cc.pe3epwithyou.trident.state.MCCIState
5+
import cc.pe3epwithyou.trident.interfaces.DialogCollection
6+
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
7+
import net.minecraft.client.Minecraft
8+
9+
object MeterResetListener : ClientTickEvents.EndTick {
10+
fun register() {
11+
ClientTickEvents.END_CLIENT_TICK.register(this)
12+
}
13+
14+
override fun onEndTick(client: Minecraft) {
15+
if (!MCCIState.isOnIsland()) return
16+
val now = System.currentTimeMillis()
17+
fun maybeReset(st: cc.pe3epwithyou.trident.state.MeterState): Boolean {
18+
val next = st.nextResetAtMs
19+
if (next <= 0L) return false
20+
if (st.lastAppliedResetAtMs >= next) return false
21+
if (now < next) return false
22+
st.progressCurrent = 0
23+
st.progressTarget = 0
24+
st.claimsCurrent = 0
25+
st.lastAppliedResetAtMs = next
26+
return true
27+
}
28+
var changed = false
29+
changed = maybeReset(TridentClient.playerState.dailyMeter) || changed
30+
changed = maybeReset(TridentClient.playerState.weeklyMeter) || changed
31+
if (changed) DialogCollection.refreshDialog("meter")
32+
}
33+
}
34+
35+

0 commit comments

Comments
 (0)