diff options
Diffstat (limited to 'mod/src')
18 files changed, 242 insertions, 12 deletions
diff --git a/mod/src/main/java/moe/nea/ledger/init/AutoDiscoveryMixinPlugin.java b/mod/src/main/java/moe/nea/ledger/init/AutoDiscoveryMixinPlugin.java index 56841b5..64fa6c2 100644 --- a/mod/src/main/java/moe/nea/ledger/init/AutoDiscoveryMixinPlugin.java +++ b/mod/src/main/java/moe/nea/ledger/init/AutoDiscoveryMixinPlugin.java @@ -96,6 +96,8 @@ public class AutoDiscoveryMixinPlugin implements IMixinConfigPlugin { * @param className the name or path of a class to be registered as a mixin. */ public void tryAddMixinClass(String className) { + if (!className.endsWith(".class")) return; + if (className.indexOf('$') >= 0) return; String norm = (className.endsWith(".class") ? className.substring(0, className.length() - ".class".length()) : className) .replace("\\", "/") .replace("/", "."); diff --git a/mod/src/main/java/moe/nea/ledger/mixin/AccessorContainerDispenser.java b/mod/src/main/java/moe/nea/ledger/mixin/AccessorContainerDispenser.java new file mode 100644 index 0000000..a3d32c4 --- /dev/null +++ b/mod/src/main/java/moe/nea/ledger/mixin/AccessorContainerDispenser.java @@ -0,0 +1,12 @@ +package moe.nea.ledger.mixin; + +import net.minecraft.inventory.ContainerDispenser; +import net.minecraft.inventory.IInventory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ContainerDispenser.class) +public interface AccessorContainerDispenser { + @Accessor("dispenserInventory") + IInventory getDispenserInventory_ledger(); +} diff --git a/mod/src/main/java/moe/nea/ledger/mixin/AccessorContainerHopper.java b/mod/src/main/java/moe/nea/ledger/mixin/AccessorContainerHopper.java new file mode 100644 index 0000000..ee29d4f --- /dev/null +++ b/mod/src/main/java/moe/nea/ledger/mixin/AccessorContainerHopper.java @@ -0,0 +1,13 @@ +package moe.nea.ledger.mixin; + +import net.minecraft.inventory.ContainerDispenser; +import net.minecraft.inventory.ContainerHopper; +import net.minecraft.inventory.IInventory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ContainerHopper.class) +public interface AccessorContainerHopper { + @Accessor("hopperInventory") + IInventory getHopperInventory_ledger(); +} diff --git a/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt b/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt index 0bacf32..ff2c691 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt @@ -20,12 +20,12 @@ class ItemIdProvider { @SubscribeEvent fun onMouseInput(event: GuiScreenEvent.MouseInputEvent.Pre) { if (Mouse.getEventButton() == -1) return - MinecraftForge.EVENT_BUS.post(BeforeGuiAction(event.gui)) + BeforeGuiAction(event.gui).post() } @SubscribeEvent fun onKeyInput(event: GuiScreenEvent.KeyboardInputEvent.Pre) { - MinecraftForge.EVENT_BUS.post(BeforeGuiAction(event.gui)) + BeforeGuiAction(event.gui).post() } private val knownNames = mutableMapOf<String, ItemId>() diff --git a/mod/src/main/kotlin/moe/nea/ledger/Ledger.kt b/mod/src/main/kotlin/moe/nea/ledger/Ledger.kt index 134d519..6d3c592 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/Ledger.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/Ledger.kt @@ -22,6 +22,7 @@ import moe.nea.ledger.modules.BazaarDetection import moe.nea.ledger.modules.BazaarOrderDetection import moe.nea.ledger.modules.BitsDetection import moe.nea.ledger.modules.BitsShopDetection +import moe.nea.ledger.modules.CaducousFeederDetection import moe.nea.ledger.modules.DragonEyePlacementDetection import moe.nea.ledger.modules.DragonSacrificeDetection import moe.nea.ledger.modules.DungeonChestDetection @@ -29,6 +30,7 @@ import moe.nea.ledger.modules.ExternalDataProvider import moe.nea.ledger.modules.EyedropsDetection import moe.nea.ledger.modules.ForgeDetection import moe.nea.ledger.modules.GambleDetection +import moe.nea.ledger.modules.GhostCoinDropDetection import moe.nea.ledger.modules.GodPotionDetection import moe.nea.ledger.modules.GodPotionMixinDetection import moe.nea.ledger.modules.GummyPolarBearDetection @@ -40,6 +42,7 @@ import moe.nea.ledger.modules.NpcDetection import moe.nea.ledger.modules.PestRepellentDetection import moe.nea.ledger.modules.UpdateChecker import moe.nea.ledger.modules.VisitorDetection +import moe.nea.ledger.telemetry.TelemetryProvider import moe.nea.ledger.utils.ErrorUtil import moe.nea.ledger.utils.MinecraftExecutor import moe.nea.ledger.utils.di.DI @@ -110,7 +113,9 @@ class Ledger { tickQueue.add(runnable) } - val di = DI() + private val di = DI() + + fun leakDI() = di } @Mod.EventHandler @@ -135,6 +140,7 @@ class Ledger { BazaarOrderDetection::class.java, BitsDetection::class.java, BitsShopDetection::class.java, + CaducousFeederDetection::class.java, ConfigCommand::class.java, DebugDataCommand::class.java, DragonEyePlacementDetection::class.java, @@ -145,6 +151,7 @@ class Ledger { EyedropsDetection::class.java, ForgeDetection::class.java, GambleDetection::class.java, + GhostCoinDropDetection::class.java, GodPotionDetection::class.java, GodPotionMixinDetection::class.java, GummyPolarBearDetection::class.java, diff --git a/mod/src/main/kotlin/moe/nea/ledger/QueryCommand.kt b/mod/src/main/kotlin/moe/nea/ledger/QueryCommand.kt index abdc13a..80dd54c 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/QueryCommand.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/QueryCommand.kt @@ -172,7 +172,7 @@ class QueryCommand : CommandBase() { override val name: String get() = "withitem" - private val itemIdProvider = Ledger.di.provide<ItemIdProvider>() // TODO: close this escape hatch + private val itemIdProvider = Ledger.leakDI().provide<ItemIdProvider>() // TODO: close this escape hatch override fun getFilter(text: String): BooleanExpression { return Clause { column(DBItemEntry.itemId) like text } } diff --git a/mod/src/main/kotlin/moe/nea/ledger/config/DebugOptions.kt b/mod/src/main/kotlin/moe/nea/ledger/config/DebugOptions.kt index fd5ed3d..6b4e51c 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/config/DebugOptions.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/config/DebugOptions.kt @@ -2,6 +2,7 @@ package moe.nea.ledger.config import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean import io.github.notenoughupdates.moulconfig.annotations.ConfigOption +import moe.nea.ledger.DevUtil class DebugOptions { @ConfigOption(name = "Log entries to chat", @@ -9,5 +10,5 @@ class DebugOptions { @Transient @ConfigEditorBoolean @JvmField - var logEntries = false + var logEntries = DevUtil.isDevEnv } diff --git a/mod/src/main/kotlin/moe/nea/ledger/events/BeforeGuiAction.kt b/mod/src/main/kotlin/moe/nea/ledger/events/BeforeGuiAction.kt index 098912a..7f6eae9 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/events/BeforeGuiAction.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/events/BeforeGuiAction.kt @@ -1,11 +1,21 @@ package moe.nea.ledger.events +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import moe.nea.ledger.telemetry.GuiContextValue +import moe.nea.ledger.utils.telemetry.ContextValue import net.minecraft.client.gui.GuiScreen import net.minecraft.client.gui.inventory.GuiChest +import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.inventory.ContainerChest import net.minecraftforge.fml.common.eventhandler.Event -data class BeforeGuiAction(val gui: GuiScreen) : Event() { +data class BeforeGuiAction(val gui: GuiScreen) : LedgerEvent() { val chest = gui as? GuiChest val chestSlots = chest?.inventorySlots as ContainerChest? + override fun serialize(): JsonElement { + return JsonObject().apply { + add("gui", GuiContextValue(gui).serialize()) + } + } } diff --git a/mod/src/main/kotlin/moe/nea/ledger/events/LedgerEvent.kt b/mod/src/main/kotlin/moe/nea/ledger/events/LedgerEvent.kt new file mode 100644 index 0000000..cbb3f81 --- /dev/null +++ b/mod/src/main/kotlin/moe/nea/ledger/events/LedgerEvent.kt @@ -0,0 +1,22 @@ +package moe.nea.ledger.events + +import moe.nea.ledger.Ledger +import moe.nea.ledger.utils.ErrorUtil +import moe.nea.ledger.utils.telemetry.CommonKeys +import moe.nea.ledger.utils.telemetry.ContextValue +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.eventhandler.Event + +abstract class LedgerEvent : Event(), ContextValue { + fun post() { + Ledger.leakDI() + .provide<ErrorUtil>() + .catch( + CommonKeys.EVENT_MESSAGE to ContextValue.string("Error during event execution"), + "event_instance" to this, + "event_type" to ContextValue.string(javaClass.name) + ) { + MinecraftForge.EVENT_BUS.post(this) + } + } +}
\ No newline at end of file diff --git a/mod/src/main/kotlin/moe/nea/ledger/modules/CaducousFeederDetection.kt b/mod/src/main/kotlin/moe/nea/ledger/modules/CaducousFeederDetection.kt new file mode 100644 index 0000000..b64c7e5 --- /dev/null +++ b/mod/src/main/kotlin/moe/nea/ledger/modules/CaducousFeederDetection.kt @@ -0,0 +1,48 @@ +package moe.nea.ledger.modules + +import moe.nea.ledger.ItemChange +import moe.nea.ledger.ItemId +import moe.nea.ledger.LedgerEntry +import moe.nea.ledger.LedgerLogger +import moe.nea.ledger.TransactionType +import moe.nea.ledger.events.GuiClickEvent +import moe.nea.ledger.gen.ItemIds +import moe.nea.ledger.getDisplayNameU +import moe.nea.ledger.getInternalId +import moe.nea.ledger.unformattedString +import moe.nea.ledger.utils.di.Inject +import net.minecraft.client.Minecraft +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.time.Instant + +class CaducousFeederDetection { + + @Inject + lateinit var logger: LedgerLogger + + @Inject + lateinit var minecraft: Minecraft + + @SubscribeEvent + fun onFeederClick(event: GuiClickEvent) { + val slot = event.slotIn ?: return + val displayName = slot.inventory.displayName.unformattedText + if (!displayName.unformattedString().contains("Confirm Caducous Feeder")) return + val stack = slot.stack ?: return + val player = minecraft.thePlayer ?: return + if (!player.inventory.mainInventory.any { it?.getInternalId() == ItemIds.ULTIMATE_CARROT_CANDY }) return + if (stack.getDisplayNameU() != "§aUse Caducous Feeder") return + val petId = slot.inventory.getStackInSlot(13)?.getInternalId() ?: ItemId.NIL + + logger.logEntry( + LedgerEntry( + TransactionType.CADUCOUS_FEEDER_USED, + Instant.now(), + listOf( + ItemChange.lose(ItemIds.ULTIMATE_CARROT_CANDY, 1), + ItemChange(petId, 1.0, ItemChange.ChangeDirection.TRANSFORM), + ) + ) + ) + } +}
\ No newline at end of file diff --git a/mod/src/main/kotlin/moe/nea/ledger/modules/ExternalDataProvider.kt b/mod/src/main/kotlin/moe/nea/ledger/modules/ExternalDataProvider.kt index 93bb453..42a1f42 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/modules/ExternalDataProvider.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/modules/ExternalDataProvider.kt @@ -14,6 +14,7 @@ import java.util.concurrent.CompletableFuture class ExternalDataProvider @Inject constructor( val requestUtil: RequestUtil ) { + // TODO: Save all the data locally, so in case of a failed request older versions can be used fun createAuxillaryDataRequest(path: String): Request { return requestUtil.createRequest("https://github.com/nea89o/ledger-auxiliary-data/raw/refs/heads/master/$path") @@ -22,7 +23,9 @@ class ExternalDataProvider @Inject constructor( private val itemNameFuture: CompletableFuture<Map<String, String>> = CompletableFuture.supplyAsync { val request = createAuxillaryDataRequest("data/item_names.json") val response = request.execute(requestUtil) - val nameMap = response.json(GsonUtil.typeToken<Map<String, String>>()) + val nameMap = + response?.json(GsonUtil.typeToken<Map<String, String>>()) + ?: mapOf() return@supplyAsync nameMap } diff --git a/mod/src/main/kotlin/moe/nea/ledger/modules/GhostCoinDropDetection.kt b/mod/src/main/kotlin/moe/nea/ledger/modules/GhostCoinDropDetection.kt new file mode 100644 index 0000000..42084e2 --- /dev/null +++ b/mod/src/main/kotlin/moe/nea/ledger/modules/GhostCoinDropDetection.kt @@ -0,0 +1,38 @@ +package moe.nea.ledger.modules + +import moe.nea.ledger.ItemChange +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.ChatReceived +import moe.nea.ledger.parseShortNumber +import moe.nea.ledger.useMatcher +import moe.nea.ledger.utils.di.Inject +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Pattern + +class GhostCoinDropDetection { + + val ghostCoinPattern = + Pattern.compile("The ghost's death materialized (?<coins>$SHORT_NUMBER_PATTERN) coins from the mists!") + + @Inject + lateinit var logger: LedgerLogger + + @SubscribeEvent + fun onGhostCoinDrop(event: ChatReceived) { + ghostCoinPattern.useMatcher(event.message) { + logger.logEntry( + LedgerEntry( + // TODO: merge this into a generic mob drop tt + TransactionType.GHOST_COIN_DROP, + event.timestamp, + listOf( + ItemChange.gainCoins(parseShortNumber(group("coins"))), + ) + ) + ) + } + } +} diff --git a/mod/src/main/kotlin/moe/nea/ledger/telemetry/GuiContextValue.kt b/mod/src/main/kotlin/moe/nea/ledger/telemetry/GuiContextValue.kt new file mode 100644 index 0000000..2d7db39 --- /dev/null +++ b/mod/src/main/kotlin/moe/nea/ledger/telemetry/GuiContextValue.kt @@ -0,0 +1,16 @@ +package moe.nea.ledger.telemetry + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import moe.nea.ledger.utils.ScreenUtil +import moe.nea.ledger.utils.telemetry.ContextValue +import net.minecraft.client.gui.GuiScreen + +class GuiContextValue(val gui: GuiScreen) : ContextValue { + override fun serialize(): JsonElement { + return JsonObject().apply { + addProperty("class", gui.javaClass.name) + addProperty("name", ScreenUtil.estimateName(gui)) + } + } +} diff --git a/mod/src/main/kotlin/moe/nea/ledger/TelemetryProvider.kt b/mod/src/main/kotlin/moe/nea/ledger/telemetry/TelemetryProvider.kt index d9c7108..c2fff23 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/TelemetryProvider.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/telemetry/TelemetryProvider.kt @@ -1,8 +1,10 @@ -package moe.nea.ledger +package moe.nea.ledger.telemetry import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject +import moe.nea.ledger.DevUtil +import moe.nea.ledger.Ledger import moe.nea.ledger.gen.BuildConfig import moe.nea.ledger.utils.di.DI import moe.nea.ledger.utils.di.DIProvider @@ -40,7 +42,7 @@ object TelemetryProvider { } fun setupDefaultSpan() { - val sp = Span.current() + val sp = Span.rootSpan sp.add(USER, MinecraftUser(Minecraft.getMinecraft().session)) sp.add(MINECRAFT_VERSION, ContextValue.compound( "static" to "1.8.9", diff --git a/mod/src/main/kotlin/moe/nea/ledger/utils/ScreenUtil.kt b/mod/src/main/kotlin/moe/nea/ledger/utils/ScreenUtil.kt new file mode 100644 index 0000000..0305126 --- /dev/null +++ b/mod/src/main/kotlin/moe/nea/ledger/utils/ScreenUtil.kt @@ -0,0 +1,29 @@ +package moe.nea.ledger.utils + +import moe.nea.ledger.mixin.AccessorContainerDispenser +import moe.nea.ledger.mixin.AccessorContainerHopper +import net.minecraft.client.gui.GuiScreen +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.inventory.ContainerChest +import net.minecraft.inventory.IInventory + +object ScreenUtil { + fun estimateInventory(screen: GuiScreen?): IInventory? { + if (screen !is GuiContainer) { + return null + } + val container = screen.inventorySlots ?: return null + if (container is ContainerChest) + return container.lowerChestInventory + if (container is AccessorContainerDispenser) + return container.dispenserInventory_ledger + if (container is AccessorContainerHopper) + return container.hopperInventory_ledger + return null + + } + + fun estimateName(screen: GuiScreen?): String? { + return estimateInventory(screen)?.name + } +}
\ No newline at end of file diff --git a/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestTrace.kt b/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestTrace.kt new file mode 100644 index 0000000..3953e09 --- /dev/null +++ b/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestTrace.kt @@ -0,0 +1,21 @@ +package moe.nea.ledger.utils.network + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import moe.nea.ledger.utils.telemetry.ContextValue + +class RequestTrace(val request: Request) : ContextValue { + override fun serialize(): JsonElement { + return JsonObject().apply { + addProperty("url", request.url.toString()) + addProperty("method", request.method.name) + addProperty("content-type", request.headers["content-type"]) + addProperty("accept", request.headers["accept"]) + } + } + + companion object { + val KEY = "http_request" + fun createTrace(request: Request): Pair<String, RequestTrace> = KEY to RequestTrace(request) + } +}
\ No newline at end of file diff --git a/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestUtil.kt b/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestUtil.kt index a49c65a..8101527 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestUtil.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/utils/network/RequestUtil.kt @@ -2,6 +2,8 @@ package moe.nea.ledger.utils.network import moe.nea.ledger.utils.ErrorUtil import moe.nea.ledger.utils.di.Inject +import moe.nea.ledger.utils.telemetry.CommonKeys +import moe.nea.ledger.utils.telemetry.ContextValue import java.net.URL import java.net.URLConnection import java.security.KeyStore @@ -38,7 +40,10 @@ class RequestUtil @Inject constructor(val errorUtil: ErrorUtil) { fun createRequest(url: String) = createRequest(URL(url)) fun createRequest(url: URL) = Request(url, Request.Method.GET, null, mapOf()) - fun executeRequest(request: Request): Response { + fun executeRequest(request: Request): Response? = errorUtil.catch( + CommonKeys.EVENT_MESSAGE to ContextValue.string("Failed to execute request"), + RequestTrace.createTrace(request) + ) { val connection = request.url.openConnection() enhanceConnection(connection) connection.setRequestProperty("accept-encoding", "gzip") @@ -56,7 +61,7 @@ class RequestUtil @Inject constructor(val errorUtil: ErrorUtil) { val text = stream.bufferedReader().readText() stream.close() // Do NOT call connection.disconnect() to allow for connection reuse - return Response(request, text, connection.headerFields) + return@catch Response(request, text, connection.headerFields) } diff --git a/mod/src/main/kotlin/moe/nea/ledger/utils/telemetry/Span.kt b/mod/src/main/kotlin/moe/nea/ledger/utils/telemetry/Span.kt index 0d680a9..8b8e284 100644 --- a/mod/src/main/kotlin/moe/nea/ledger/utils/telemetry/Span.kt +++ b/mod/src/main/kotlin/moe/nea/ledger/utils/telemetry/Span.kt @@ -2,9 +2,10 @@ package moe.nea.ledger.utils.telemetry class Span(val parent: Span?) : AutoCloseable { companion object { + val rootSpan = Span(null) private val _current = object : InheritableThreadLocal<Span>() { override fun initialValue(): Span { - return Span(null) + return Span(rootSpan) } override fun childValue(parentValue: Span?): Span { |