aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-12-08 00:42:01 +0100
committerLinnea Gräf <nea@nea.moe>2024-12-08 00:42:01 +0100
commitfa72dd4ce107190cda7bc56234fed650f20e3aa9 (patch)
tree57a5fa0c224db5bb670e26813c958a768d6bdf90 /src/main/kotlin/moe/nea
parent0a2342c015b310172f933df765d8651013c26f16 (diff)
downloadLocalTransactionLedger-fa72dd4ce107190cda7bc56234fed650f20e3aa9.tar.gz
LocalTransactionLedger-fa72dd4ce107190cda7bc56234fed650f20e3aa9.tar.bz2
LocalTransactionLedger-fa72dd4ce107190cda7bc56234fed650f20e3aa9.zip
feat: Add visitor trading detection
Diffstat (limited to 'src/main/kotlin/moe/nea')
-rw-r--r--src/main/kotlin/moe/nea/ledger/ItemChange.kt33
-rw-r--r--src/main/kotlin/moe/nea/ledger/ItemId.kt34
-rw-r--r--src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt15
-rw-r--r--src/main/kotlin/moe/nea/ledger/ItemUtil.kt3
-rw-r--r--src/main/kotlin/moe/nea/ledger/Ledger.kt4
-rw-r--r--src/main/kotlin/moe/nea/ledger/LedgerEntry.kt28
-rw-r--r--src/main/kotlin/moe/nea/ledger/LedgerLogger.kt102
-rw-r--r--src/main/kotlin/moe/nea/ledger/TransactionType.kt24
-rw-r--r--src/main/kotlin/moe/nea/ledger/modules/VisitorDetection.kt109
9 files changed, 243 insertions, 109 deletions
diff --git a/src/main/kotlin/moe/nea/ledger/ItemChange.kt b/src/main/kotlin/moe/nea/ledger/ItemChange.kt
new file mode 100644
index 0000000..a8bb7e8
--- /dev/null
+++ b/src/main/kotlin/moe/nea/ledger/ItemChange.kt
@@ -0,0 +1,33 @@
+package moe.nea.ledger
+
+data class ItemChange(
+ val itemId: ItemId,
+ val count: Double,
+ val direction: ChangeDirection,
+) {
+ enum class ChangeDirection {
+ GAINED,
+ TRANSFORM,
+ SYNC,
+ CATALYST,
+ LOST;
+ }
+
+ companion object {
+ fun gainCoins(number: Double): ItemChange {
+ return gain(ItemId.COINS, number)
+ }
+
+ fun gain(itemId: ItemId, amount: Number): ItemChange {
+ return ItemChange(itemId, amount.toDouble(), ChangeDirection.GAINED)
+ }
+
+ fun lose(itemId: ItemId, amount: Number): ItemChange {
+ return ItemChange(itemId, amount.toDouble(), ChangeDirection.LOST)
+ }
+
+ fun loseCoins(number: Double): ItemChange {
+ return lose(ItemId.COINS, number)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/moe/nea/ledger/ItemId.kt b/src/main/kotlin/moe/nea/ledger/ItemId.kt
new file mode 100644
index 0000000..74f8e82
--- /dev/null
+++ b/src/main/kotlin/moe/nea/ledger/ItemId.kt
@@ -0,0 +1,34 @@
+package moe.nea.ledger
+
+@JvmInline
+value class ItemId(
+ val string: String
+) {
+ fun singleItem(): Pair<ItemId, Double> {
+ return withStackSize(1)
+ }
+
+ fun withStackSize(size: Number): Pair<ItemId, Double> {
+ return Pair(this, size.toDouble())
+ }
+
+
+ companion object {
+ fun skill(skill: String) = ItemId("SKYBLOCK_SKILL_$skill")
+
+ val GARDEN = skill("GARDEN")
+ val FARMING = skill("FARMING")
+ val GEMSTONE_POWDER = ItemId("SKYBLOCK_POWDER_GEMSTONE")
+ val MITHRIL_POWDER = ItemId("SKYBLOCK_POWDER_MITHRIL")
+ val GOLD_ESSENCE = ItemId("ESSENCE_GOLD")
+ val PELT = ItemId("SKYBLOCK_PELT")
+ val COINS = ItemId("SKYBLOCK_COIN")
+ val FINE_FLOUR = ItemId("FINE_FLOUR")
+ val BITS = ItemId("SKYBLOCK_BIT")
+ val COPPER = ItemId("SKYBLOCK_COPPER")
+ val NIL = ItemId("SKYBLOCK_NIL")
+ val DUNGEON_CHEST_KEY = ItemId("DUNGEON_CHEST_KEY")
+ val BOOSTER_COOKIE = ItemId("BOOSTER_COOKIE")
+ val KISMET_FEATHER = ItemId("KISMET_FEATHER")
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt b/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt
index d6ca05b..f2906b8 100644
--- a/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt
+++ b/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt
@@ -68,8 +68,13 @@ class ItemIdProvider {
}
}
- fun findForName(name: String): ItemId? {
- return knownNames[name]
+ // TODO: make use of colour
+ fun findForName(name: String, fallbackToGenerated: Boolean = true): ItemId? {
+ var id = knownNames[name]
+ if (id == null && fallbackToGenerated) {
+ id = ItemId(name.uppercase().replace(" ", "_"))
+ }
+ return id
}
private val coinRegex = "(?<amount>$SHORT_NUMBER_PATTERN) Coins?".toPattern()
@@ -84,7 +89,7 @@ class ItemIdProvider {
.toList()
}
- fun findStackableItemByName(name: String): Pair<ItemId, Double>? {
+ fun findStackableItemByName(name: String, fallbackToGenerated: Boolean = false): Pair<ItemId, Double>? {
val properName = name.unformattedString()
if (properName == "FREE" || properName == "This Chest is Free!") {
return Pair(ItemId.COINS, 0.0)
@@ -97,12 +102,12 @@ class ItemIdProvider {
parseShortNumber(group("count")))
}
stackedItemRegex.useMatcher(properName) {
- val item = findForName(group("name"))
+ var item = findForName(group("name"), fallbackToGenerated)
if (item != null) {
val count = parseShortNumber(group("count"))
return Pair(item, count)
}
}
- return findForName(properName)?.let { Pair(it, 1.0) }
+ return findForName(properName, fallbackToGenerated)?.let { Pair(it, 1.0) }
}
} \ No newline at end of file
diff --git a/src/main/kotlin/moe/nea/ledger/ItemUtil.kt b/src/main/kotlin/moe/nea/ledger/ItemUtil.kt
index cadcb66..4bbd4cd 100644
--- a/src/main/kotlin/moe/nea/ledger/ItemUtil.kt
+++ b/src/main/kotlin/moe/nea/ledger/ItemUtil.kt
@@ -9,7 +9,8 @@ fun ItemStack.getExtraAttributes(): NBTTagCompound {
return nbt.getCompoundTag("ExtraAttributes")
}
-fun ItemStack.getInternalId(): ItemId? {
+fun ItemStack?.getInternalId(): ItemId? {
+ if (this == null) return null
val extraAttributes = getExtraAttributes()
var id = extraAttributes.getString("id")
id = id.takeIf { it.isNotBlank() }
diff --git a/src/main/kotlin/moe/nea/ledger/Ledger.kt b/src/main/kotlin/moe/nea/ledger/Ledger.kt
index 3b14884..5dafe4a 100644
--- a/src/main/kotlin/moe/nea/ledger/Ledger.kt
+++ b/src/main/kotlin/moe/nea/ledger/Ledger.kt
@@ -18,6 +18,7 @@ import moe.nea.ledger.modules.KatDetection
import moe.nea.ledger.modules.KuudraChestDetection
import moe.nea.ledger.modules.MinionDetection
import moe.nea.ledger.modules.NpcDetection
+import moe.nea.ledger.modules.VisitorDetection
import moe.nea.ledger.utils.DI
import net.minecraft.client.Minecraft
import net.minecraft.command.ICommand
@@ -67,7 +68,7 @@ class Ledger {
// You bought back Potato x3 for 9 Coins!
TODO: TRADING, FORGE, VISITORS / COPPER, CORPSES ÖFFNEN, HIGH / LOW GAMBLES, MINION ITEMS (maybe inferno refuel)
- TODO: DUNGEON / KUUDRA LOOT, PET LEVELING COSTS AT KAT / FANN, SLAYER / MOB DROPS, SLAYER START COST
+ TODO: PET LEVELING COSTS AT FANN, SLAYER / MOB DROPS, SLAYER START COST
*/
companion object {
val dataFolder = File("money-ledger").apply { mkdirs() }
@@ -107,6 +108,7 @@ class Ledger {
LogChatCommand::class.java,
MinionDetection::class.java,
NpcDetection::class.java,
+ VisitorDetection::class.java,
)
di.instantiateAll()
di.getAllInstances().forEach(MinecraftForge.EVENT_BUS::register)
diff --git a/src/main/kotlin/moe/nea/ledger/LedgerEntry.kt b/src/main/kotlin/moe/nea/ledger/LedgerEntry.kt
new file mode 100644
index 0000000..dec0727
--- /dev/null
+++ b/src/main/kotlin/moe/nea/ledger/LedgerEntry.kt
@@ -0,0 +1,28 @@
+package moe.nea.ledger
+
+import com.google.gson.JsonObject
+import java.time.Instant
+import java.util.UUID
+
+data class LedgerEntry(
+ val transactionType: TransactionType,
+ val timestamp: Instant,
+ val items: List<ItemChange>,
+) {
+ fun intoJson(profileId: UUID?): JsonObject {
+ val coinAmount = items.find { it.itemId == ItemId.COINS || it.itemId == ItemId.BITS }?.count
+ val nonCoins = items.find { it.itemId != ItemId.COINS && it.itemId != ItemId.BITS }
+ return JsonObject().apply {
+ addProperty("transactionType", transactionType.name)
+ addProperty("timestamp", timestamp.toEpochMilli().toString())
+ addProperty("totalTransactionValue", coinAmount)
+ addProperty("itemId", nonCoins?.itemId?.string ?: "")
+ addProperty("itemAmount", nonCoins?.count ?: 0.0)
+ addProperty("profileId", profileId.toString())
+ addProperty(
+ "playerId",
+ UUIDUtil.getPlayerUUID().toString()
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/moe/nea/ledger/LedgerLogger.kt b/src/main/kotlin/moe/nea/ledger/LedgerLogger.kt
index 5403d92..fd439c9 100644
--- a/src/main/kotlin/moe/nea/ledger/LedgerLogger.kt
+++ b/src/main/kotlin/moe/nea/ledger/LedgerLogger.kt
@@ -2,7 +2,6 @@ package moe.nea.ledger
import com.google.gson.Gson
import com.google.gson.JsonArray
-import com.google.gson.JsonObject
import moe.nea.ledger.database.DBItemEntry
import moe.nea.ledger.database.DBLogEntry
import moe.nea.ledger.database.Database
@@ -14,7 +13,6 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
import java.io.File
import java.text.SimpleDateFormat
-import java.time.Instant
import java.util.Date
import java.util.UUID
@@ -132,104 +130,4 @@ class LedgerLogger {
}
}
-enum class TransactionType {
- AUCTION_BOUGHT,
- AUCTION_SOLD,
- AUTOMERCHANT_PROFIT_COLLECT,
- BANK_DEPOSIT,
- BANK_WITHDRAW,
- BAZAAR_BUY_INSTANT,
- BAZAAR_BUY_ORDER,
- BAZAAR_SELL_INSTANT,
- BAZAAR_SELL_ORDER,
- BITS_PURSE_STATUS,
- BOOSTER_COOKIE_ATE,
- COMMUNITY_SHOP_BUY,
- DUNGEON_CHEST_OPEN,
- KAT_TIMESKIP,
- KAT_UPGRADE,
- KISMET_REROLL,
- KUUDRA_CHEST_OPEN,
- NPC_BUY,
- NPC_SELL,
-}
-
-@JvmInline
-value class ItemId(
- val string: String
-) {
- fun singleItem(): Pair<ItemId, Double> {
- return withStackSize(1)
- }
-
- fun withStackSize(size: Number): Pair<ItemId, Double> {
- return Pair(this, size.toDouble())
- }
-
-
- companion object {
- val COINS = ItemId("SKYBLOCK_COIN")
- val BITS = ItemId("SKYBLOCK_BIT")
- val NIL = ItemId("SKYBLOCK_NIL")
- val DUNGEON_CHEST_KEY = ItemId("DUNGEON_CHEST_KEY")
- val BOOSTER_COOKIE = ItemId("BOOSTER_COOKIE")
- val KISMET_FEATHER = ItemId("KISMET_FEATHER")
- }
-}
-
-
-data class ItemChange(
- val itemId: ItemId,
- val count: Double,
- val direction: ChangeDirection,
-) {
- enum class ChangeDirection {
- GAINED,
- TRANSFORM,
- SYNC,
- CATALYST,
- LOST;
- }
-
- companion object {
- fun gainCoins(number: Double): ItemChange {
- return gain(ItemId.COINS, number)
- }
-
- fun gain(itemId: ItemId, amount: Number): ItemChange {
- return ItemChange(itemId, amount.toDouble(), ChangeDirection.GAINED)
- }
-
- fun lose(itemId: ItemId, amount: Number): ItemChange {
- return ItemChange(itemId, amount.toDouble(), ChangeDirection.LOST)
- }
-
- fun loseCoins(number: Double): ItemChange {
- return lose(ItemId.COINS, number)
- }
- }
-}
-
-data class LedgerEntry(
- val transactionType: TransactionType,
- val timestamp: Instant,
- val items: List<ItemChange>,
-) {
- fun intoJson(profileId: UUID?): JsonObject {
- val coinAmount = items.find { it.itemId == ItemId.COINS || it.itemId == ItemId.BITS }?.count
- val nonCoins = items.find { it.itemId != ItemId.COINS && it.itemId != ItemId.BITS }
- return JsonObject().apply {
- addProperty("transactionType", transactionType.name)
- addProperty("timestamp", timestamp.toEpochMilli().toString())
- addProperty("totalTransactionValue", coinAmount)
- addProperty("itemId", nonCoins?.itemId?.string ?: "")
- addProperty("itemAmount", nonCoins?.count ?: 0.0)
- addProperty("profileId", profileId.toString())
- addProperty(
- "playerId",
- UUIDUtil.getPlayerUUID().toString()
- )
- }
- }
-}
diff --git a/src/main/kotlin/moe/nea/ledger/TransactionType.kt b/src/main/kotlin/moe/nea/ledger/TransactionType.kt
new file mode 100644
index 0000000..1c941e9
--- /dev/null
+++ b/src/main/kotlin/moe/nea/ledger/TransactionType.kt
@@ -0,0 +1,24 @@
+package moe.nea.ledger
+
+enum class TransactionType {
+ AUCTION_BOUGHT,
+ AUCTION_SOLD,
+ AUTOMERCHANT_PROFIT_COLLECT,
+ BANK_DEPOSIT,
+ BANK_WITHDRAW,
+ BAZAAR_BUY_INSTANT,
+ BAZAAR_BUY_ORDER,
+ BAZAAR_SELL_INSTANT,
+ BAZAAR_SELL_ORDER,
+ BITS_PURSE_STATUS,
+ BOOSTER_COOKIE_ATE,
+ COMMUNITY_SHOP_BUY,
+ DUNGEON_CHEST_OPEN,
+ KAT_TIMESKIP,
+ KAT_UPGRADE,
+ KISMET_REROLL,
+ KUUDRA_CHEST_OPEN,
+ NPC_BUY,
+ NPC_SELL,
+ VISITOR_BARGAIN,
+} \ No newline at end of file
diff --git a/src/main/kotlin/moe/nea/ledger/modules/VisitorDetection.kt b/src/main/kotlin/moe/nea/ledger/modules/VisitorDetection.kt
new file mode 100644
index 0000000..1df0618
--- /dev/null
+++ b/src/main/kotlin/moe/nea/ledger/modules/VisitorDetection.kt
@@ -0,0 +1,109 @@
+package moe.nea.ledger.modules
+
+import moe.nea.ledger.ItemChange
+import moe.nea.ledger.ItemId
+import moe.nea.ledger.ItemIdProvider
+import moe.nea.ledger.LedgerEntry
+import moe.nea.ledger.LedgerLogger
+import moe.nea.ledger.SHORT_NUMBER_PATTERN
+import moe.nea.ledger.TransactionType
+import moe.nea.ledger.events.ExtraSupplyIdEvent
+import moe.nea.ledger.events.GuiClickEvent
+import moe.nea.ledger.getDisplayNameU
+import moe.nea.ledger.getLore
+import moe.nea.ledger.parseShortNumber
+import moe.nea.ledger.unformattedString
+import moe.nea.ledger.useMatcher
+import moe.nea.ledger.utils.Inject
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.time.Instant
+
+class VisitorDetection {
+ @Inject
+ lateinit var logger: LedgerLogger
+
+ @Inject
+ lateinit var idProvider: ItemIdProvider
+
+ @SubscribeEvent
+ fun parseFromItem(event: GuiClickEvent) {
+ val stack = event.slotIn?.stack ?: return
+
+ val displayName = stack.getDisplayNameU()
+ if (displayName != "§aAccept Offer") return
+ val lore = stack.getLore()
+ if (!lore.contains("§eClick to give!")) return
+
+ val rewards = lore
+ .asSequence()
+ .dropWhile { it != "§7Rewards:" }.drop(1)
+ .takeWhile { it != "" }
+ .mapNotNull { parseGardenLoreLine(it) }
+ .map { ItemChange.gain(it.first, it.second) }
+ .toList()
+
+ val cost = lore
+ .asSequence()
+ .dropWhile { it != "§7Items Required:" }.drop(1)
+ .takeWhile { it != "" }
+ .mapNotNull { parseGardenLoreLine(it) }
+ .map { ItemChange.lose(it.first, it.second) }
+ .toList()
+
+ logger.logEntry(LedgerEntry(
+ TransactionType.VISITOR_BARGAIN,
+ Instant.now(),
+ cost + rewards
+ ))
+ }
+
+ private fun parseGardenLoreLine(rewardLine: String): Pair<ItemId, Double>? {
+ val f = rewardLine.unformattedString().trim()
+ return parseSpecialReward(f)
+ ?: idProvider.findStackableItemByName(f, true)
+ }
+
+ private val specialRewardRegex = "\\+(?<amount>${SHORT_NUMBER_PATTERN})x? (?<what>.*)".toPattern()
+
+ private fun parseSpecialReward(specialLine: String): Pair<ItemId, Double>? {
+ specialRewardRegex.useMatcher(specialLine) {
+ val id = when (group("what")) {
+ "Copper" -> ItemId.COPPER
+ "Bits" -> ItemId.BITS
+ "Garden Experience" -> ItemId.GARDEN
+ "Farming XP" -> ItemId.FARMING
+ "Gold Essence" -> ItemId.GOLD_ESSENCE
+ "Gemstone Powder" -> ItemId.GEMSTONE_POWDER
+ "Mithril Powder" -> ItemId.MITHRIL_POWDER
+ "Pelts" -> ItemId.PELT
+ "Fine Flour" -> ItemId.FINE_FLOUR
+ else -> ItemId.NIL
+ }
+ return Pair(id, parseShortNumber(group("amount")))
+ }
+ return null
+ }
+
+
+ @SubscribeEvent
+ fun supplyNames(event: ExtraSupplyIdEvent) {
+ event.store("Carrot", ItemId("CARROT_ITEM"))
+ event.store("Potato", ItemId("POTATO_ITEM"))
+ event.store("Jacob's Ticket", ItemId("JACOBS_TICKET"))
+ event.store("Cocoa Beans", ItemId("INK_SACK:3"))
+ event.store("Enchanted Cocoa Beans", ItemId("ENCHANTED_COCOA"))
+ event.store("Enchanted Red Mushroom Block", ItemId("ENCHANTED_HUGE_MUSHROOM_2"))
+ event.store("Enchanted Brown Mushroom Block", ItemId("ENCHANTED_HUGE_MUSHROOM_1"))
+ event.store("Nether Wart", ItemId("NETHER_STALK"))
+ event.store("Enchanted Nether Wart", ItemId("ENCHANTED_NETHER_STALK"))
+ event.store("Mutant Nether Wart", ItemId("MUTANT_NETHER_STALK"))
+ event.store("Jack o' Lantern", ItemId("JACK_O_LANTERN"))
+ event.store("Cactus Green", ItemId("INK_SACK:2"))
+ event.store("Hay Bale", ItemId("HAY_BLOCK"))
+ event.store("Rabbit's Foot", ItemId("RABBIT_FOOT"))
+ event.store("Raw Porkchop", ItemId("PORK"))
+ event.store("Raw Rabbit", ItemId("RABBIT"))
+ event.store("White Wool", ItemId("WOOL"))
+ event.store("Copper Dye", ItemId("DYE_COPPER"))
+ }
+} \ No newline at end of file