aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/ledger/modules/AuctionHouseDetection.kt
blob: d02095d2c045138d2f18d42a4740e44741010c2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package moe.nea.ledger.modules

import moe.nea.ledger.ExpiringValue
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.BeforeGuiAction
import moe.nea.ledger.events.ChatReceived
import moe.nea.ledger.getInternalId
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.di.Inject
import net.minecraft.client.gui.inventory.GuiChest
import net.minecraft.inventory.ContainerChest
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.util.regex.Pattern
import kotlin.time.Duration.Companion.seconds

class AuctionHouseDetection @Inject constructor(val ledger: LedgerLogger, val ids: ItemIdProvider) {
	data class LastViewedItem(
		val count: Int,
		val id: ItemId,
	)
	/*
		You collected 8,712,000 coins from selling Ultimate Carrot Candy Upgrade to [VIP] kodokush in an auction!
		You collected 60,000 coins from selling Walnut to [MVP++] Alea1337 in an auction!
		You purchased 2x Walnut for 69 coins!
		You purchased ◆ Ice Rune I for 4,000 coins!
	 */

	val createAuctionScreen = "Confirm( BIN)? Auction".toPattern()
	val auctionCreationCostPattern = "Cost: (?<cost>$SHORT_NUMBER_PATTERN) coins?".toPattern()

	val auctionCreatedChatPattern = "(BIN )?Auction started for .*".toPattern()

	var lastCreationCost: ExpiringValue<Double> = ExpiringValue.empty()

	@SubscribeEvent
	fun onCreateAuctionClick(event: BeforeGuiAction) {
		val slots = event.chestSlots ?: return
		if (!createAuctionScreen.asPredicate().test(slots.lowerChestInventory.name)) return
		val auctionSlot = slots.lowerChestInventory.getStackInSlot(9 + 2) ?: return
		val creationCost = auctionSlot.getLore().firstNotNullOfOrNull {
			auctionCreationCostPattern.useMatcher(it.unformattedString()) { parseShortNumber(group("cost")) }
		}
		if (creationCost != null) {
			lastCreationCost = ExpiringValue(creationCost)
		}
	}

	@SubscribeEvent
	fun onCreateAuctionChat(event: ChatReceived) {
		auctionCreatedChatPattern.useMatcher(event.message) {
			lastCreationCost.consume(3.seconds)?.let { cost ->
				ledger.logEntry(LedgerEntry(
					TransactionType.AUCTION_LISTING_CHARGE,
					event.timestamp,
					listOf(ItemChange.loseCoins(cost))
				))
			}
		}
	}

	val collectSold =
		Pattern.compile("You collected (?<coins>$SHORT_NUMBER_PATTERN) coins? from selling (?<what>.*) to (?<buyer>.*) in an auction!")
	val purchased =
		Pattern.compile("You purchased (?:(?<amount>[0-9]+)x )?(?<what>.*) for (?<coins>$SHORT_NUMBER_PATTERN) coins!")
	var lastViewedItems: MutableList<LastViewedItem> = mutableListOf()

	@SubscribeEvent
	fun onEvent(event: ChatReceived) {
		collectSold.useMatcher(event.message) {
			val lastViewedItem = lastViewedItems.removeLastOrNull()
			ledger.logEntry(
				LedgerEntry(
					TransactionType.AUCTION_SOLD,
					event.timestamp,
					listOfNotNull(
						ItemChange.gainCoins(parseShortNumber(group("coins"))),
						lastViewedItem?.let { ItemChange.lose(it.id, it.count) }
					),
				)
			)
		}
		purchased.useMatcher(event.message) {
			ledger.logEntry(
				LedgerEntry(
					TransactionType.AUCTION_BOUGHT,
					event.timestamp,
					listOf(
						ItemChange.loseCoins(parseShortNumber(group("coins"))),
						ItemChange.gain(
							ids.findForName(group("what")) ?: ItemId.NIL,
							group("amount")?.toInt() ?: 1
						)
					)
				)
			)
		}
	}

	@SubscribeEvent
	fun onBeforeAuctionCollected(event: BeforeGuiAction) {
		val chest = (event.gui as? GuiChest) ?: return
		val slots = chest.inventorySlots as ContainerChest
		val name = slots.lowerChestInventory.displayName.unformattedText.unformattedString()

		if (name == "BIN Auction View" || name == "Auction View") {
			handleCollectSingleAuctionView(slots)
		}
		if (name == "Manage Auctions") {
			handleCollectMultipleAuctionsView(slots)
		}
	}

	private fun handleCollectMultipleAuctionsView(slots: ContainerChest) {
		lastViewedItems =
			(0 until slots.lowerChestInventory.sizeInventory)
				.mapNotNull { slots.lowerChestInventory.getStackInSlot(it) }
				.filter {
					it.getLore().contains("§7Status: §aSold!") // BINs
							|| it.getLore().contains("§7Status: §aEnded!") // Auctions
				}
				.mapNotNull { LastViewedItem(it.stackSize, it.getInternalId() ?: return@mapNotNull null) }
				.toMutableList()
	}


	fun handleCollectSingleAuctionView(slots: ContainerChest) {
		val soldItem = slots.lowerChestInventory.getStackInSlot(9 + 4) ?: return
		val id = soldItem.getInternalId() ?: return
		val count = soldItem.stackSize
		lastViewedItems = mutableListOf(LastViewedItem(count, id))
	}


}