diff --git a/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt index 3dd765a82b31..0c308125de86 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CollectionAPI.kt @@ -122,6 +122,8 @@ object CollectionAPI { fun isCollectionTier0(lore: List) = lore.any { collectionTier0Pattern.matches(it) } fun getCollectionCounter(internalName: NEUInternalName): Long? = collectionValue[internalName] + fun NEUInternalName.getMultipleMap() = CollectionAPI.findAllMultiples()[this] ?: mapOf(this to 1) + fun findAllMultiples(): Map> { val entries = mutableMapOf>() NEUItems.allInternalNames.values.filter { diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt index 7cbaca0c9cf6..90a57212fbf4 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt @@ -32,7 +32,7 @@ import at.hannibal2.skyhanni.features.garden.fortuneguide.FarmingItems import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker import at.hannibal2.skyhanni.features.garden.pests.VinylType import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward -import at.hannibal2.skyhanni.features.gui.ShTrack +import at.hannibal2.skyhanni.features.gui.shtrack.TrackingList import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker import at.hannibal2.skyhanni.features.inventory.wardrobe.WardrobeAPI.WardrobeData @@ -838,5 +838,5 @@ class ProfileSpecificStorage { } @Expose - val tracking: ShTrack.TrackingList = ShTrack.TrackingList() + val tracking: TrackingList = TrackingList() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemGroupElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemGroupElement.kt new file mode 100644 index 000000000000..00b6ccd2e4fe --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemGroupElement.kt @@ -0,0 +1,56 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import at.hannibal2.skyhanni.utils.CommandUtils +import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.PrimitiveItemStack +import at.hannibal2.skyhanni.utils.renderables.Renderable + +// TODO remove +@Deprecated("Not needed anymore") +class ItemGroupElement( + val group: CommandUtils.ItemGroup, + override var current: Long, + override val target: Long?, + override val includeSack: Boolean, +) : ItemTrackingInterface() { + + override val name = group.name + override val saveName = group.name + + override fun similarElement(other: TrackingElement<*>): Boolean { + if (other !is ItemGroupElement) return false + return other.group == this.group + } + + override fun atRemove() { + for (item in group.items.keys) { + ShTrack.itemTrackers[item]?.remove(this) + } + } + + override fun atAdd() { + for (item in group.items.keys) { + ShTrack.itemTrackers.compute(item) { _, v -> + v?.also { it.add(this) } ?: mutableListOf(this) + } + } + } + + override fun internalUpdate(amount: Number) { + current += amount.toLong() + if (target != null && current >= target) { + handleDone("${group.name} §adone") + } + } + + override fun generateLine() = listOf( + Renderable.itemStack(group.icon.getItemStack()), + Renderable.string(group.name), + Renderable.string(current.toString() + ((target?.let { " / $it" }).orEmpty())), + ) + + override fun itemChange(item: PrimitiveItemStack) { + val multiple = group.items[item.internalName] ?: throw IllegalStateException("You should not be here!") + update(item.amount * multiple) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemTrackingElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemTrackingElement.kt new file mode 100644 index 000000000000..45d7d999bec6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemTrackingElement.kt @@ -0,0 +1,61 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import at.hannibal2.skyhanni.utils.ItemUtils.itemName +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.PrimitiveItemStack +import at.hannibal2.skyhanni.utils.renderables.Renderable +import com.google.gson.JsonElement + +class ItemTrackingElement( + val item: NEUInternalName, + override var current: Long, + override val target: Long?, + override val includeSack: Boolean, +) : ItemTrackingInterface() { + + override val name get() = item.itemName + override val saveName = item.asString() + + override fun similarElement(other: TrackingElement<*>): Boolean { + if (other !is ItemTrackingElement) return false + return other.item == this.item + } + + override fun atRemove() { + ShTrack.itemTrackers[item]?.remove(this) + } + + override fun atAdd() { + ShTrack.itemTrackers.compute(item) { _, v -> + v?.also { it.add(this) } ?: mutableListOf(this) + } + } + + override fun internalUpdate(amount: Number) { + current += amount.toLong() + if (target != null && current >= target) { + handleDone("$name §adone") + } + } + + override fun generateLine() = listOf( + Renderable.itemStack(item.getItemStack()), + Renderable.string(item.itemName), + Renderable.string(current.toString() + ((target?.let { " / $it" }).orEmpty())), + ) + + override fun itemChange(item: PrimitiveItemStack) { + update(item.amount) + } + + companion object { + fun fromJson(read: Map): ItemsStackElement = ItemsStackElement( + read["name"]!!.asString.toInternalName(), + read["current"]?.asLong ?: 0, + read["target"]?.asLong, + read["sack"]?.asBoolean ?: false, + ) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemTrackingInterface.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemTrackingInterface.kt new file mode 100644 index 000000000000..713fe2f40a70 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemTrackingInterface.kt @@ -0,0 +1,16 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import at.hannibal2.skyhanni.utils.PrimitiveItemStack +import com.google.gson.stream.JsonWriter + +abstract class ItemTrackingInterface() : TrackingElement() { + + abstract fun itemChange(item: PrimitiveItemStack) + + abstract val includeSack: Boolean + + override fun toJson(out: JsonWriter) { + super.toJson(out) + out.name("sack").value(includeSack) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemsStackElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemsStackElement.kt new file mode 100644 index 000000000000..afabc9d0f210 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ItemsStackElement.kt @@ -0,0 +1,74 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import at.hannibal2.skyhanni.api.CollectionAPI.getMultipleMap +import at.hannibal2.skyhanni.utils.ItemUtils.itemName +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.PrimitiveItemStack +import at.hannibal2.skyhanni.utils.renderables.Renderable +import com.google.gson.JsonElement + +class ItemsStackElement( + val main: NEUInternalName, + override var current: Long, + override val target: Long?, + override val includeSack: Boolean, +) : ItemTrackingInterface() { + + override val name get() = main.itemName + override val saveName = main.asString() + + val map = NEUItems.getPrimitiveMultiplier(main).internalName.getMultipleMap() + + private val mappedCurrent get() = map[main]?.let { current.div(it) } ?: current + + override fun similarElement(other: TrackingElement<*>): Boolean { + if (other !is ItemsStackElement) return false + return other.main == this.main + } + + override fun atRemove() { + for (item in map.keys) { + ShTrack.itemTrackers[item]?.remove(this) + } + } + + override fun atAdd() { + for (item in map.keys) { + ShTrack.itemTrackers.compute(item) { _, v -> + v?.also { it.add(this) } ?: mutableListOf(this) + } + } + } + + override fun internalUpdate(amount: Number) { + current += amount.toLong() + if (target != null && mappedCurrent >= target) { + handleDone("$name §adone") + } + } + + override fun generateLine() = listOf( + Renderable.itemStack(main.getItemStack()), + Renderable.string(main.itemName), + + Renderable.string(mappedCurrent.toString() + ((target?.let { " / $it" }).orEmpty())), + ) + + override fun itemChange(item: PrimitiveItemStack) { + val multiple = map[item.internalName] ?: throw IllegalStateException("You should not be here!") + update(item.amount * multiple) + } + + companion object { + + fun fromJson(read: Map): ItemsStackElement = ItemsStackElement( + read["name"]!!.asString.toInternalName(), + read["current"]?.asLong ?: 0, + read["target"]?.asLong, + read["sack"]?.asBoolean ?: false, + ) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/PowderTrackingElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/PowderTrackingElement.kt new file mode 100644 index 000000000000..f462bd8ac24f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/PowderTrackingElement.kt @@ -0,0 +1,46 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import at.hannibal2.skyhanni.api.HotmAPI +import at.hannibal2.skyhanni.utils.renderables.Renderable +import com.google.gson.JsonElement + +class PowderTrackingElement(val type: HotmAPI.PowderType, override var current: Long, override val target: Long?) : + TrackingElement() { + + override val name = "${type.displayNameWithColor} Powder" + override val saveName = type.name + + override fun internalUpdate(amount: Number) { + current += amount.toLong() + if (target != null && current >= target) { + handleDone("${type.displayName} §adone") + } + } + + override fun generateLine() = listOf( + Renderable.itemStack(type.icon), + Renderable.string(type.displayName), + Renderable.string(current.toString() + ((target?.let { " / $it" }).orEmpty())), + ) + + override fun similarElement(other: TrackingElement<*>): Boolean { + if (other !is PowderTrackingElement) return false + return other.type == this.type + } + + override fun atRemove() { + ShTrack.powderTracker.remove(this) + } + + override fun atAdd() { + ShTrack.powderTracker.add(this) + } + + companion object { + fun fromJson(read: Map): PowderTrackingElement = + PowderTrackingElement(extractType(read), read["current"]?.asLong ?: 0, read["target"]?.asLong) + + private fun extractType(read: Map) = HotmAPI.PowderType.getValue(read["name"]!!.asString)!! + } + +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/ShTrack.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ShTrack.kt similarity index 53% rename from src/main/java/at/hannibal2/skyhanni/features/gui/ShTrack.kt rename to src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ShTrack.kt index 9bfefabaef62..21e291a23a2f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/ShTrack.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/ShTrack.kt @@ -1,7 +1,8 @@ -package at.hannibal2.skyhanni.features.gui +package at.hannibal2.skyhanni.features.gui.shtrack import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.CollectionAPI +import at.hannibal2.skyhanni.api.CollectionAPI.getMultipleMap import at.hannibal2.skyhanni.api.HotmAPI import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.commands.CommandCategory @@ -14,9 +15,10 @@ import at.hannibal2.skyhanni.events.ItemAddEvent import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.events.ProfileLeaveEvent import at.hannibal2.skyhanni.events.mining.PowderGainEvent -import at.hannibal2.skyhanni.features.gui.ShTrack.DocumentationExcludes.itemTrack +import at.hannibal2.skyhanni.features.gui.shtrack.ShTrack.DocumentationExcludes.itemTrack import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.CollectionUtils.move import at.hannibal2.skyhanni.utils.CommandArgument import at.hannibal2.skyhanni.utils.CommandContextAwareObject import at.hannibal2.skyhanni.utils.CommandUtils @@ -24,17 +26,11 @@ import at.hannibal2.skyhanni.utils.CommandUtils.ItemGroup import at.hannibal2.skyhanni.utils.CommandUtils.itemCheck import at.hannibal2.skyhanni.utils.CommandUtils.numberCalculate import at.hannibal2.skyhanni.utils.InventoryUtils.getAmountInInventory -import at.hannibal2.skyhanni.utils.ItemUtils.itemName -import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NEUItems -import at.hannibal2.skyhanni.utils.NEUItems.getItemStack -import at.hannibal2.skyhanni.utils.PrimitiveItemStack import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable -import at.hannibal2.skyhanni.utils.SoundUtils import at.hannibal2.skyhanni.utils.json.BaseGsonBuilder import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.renderables.RenderableTooltips @@ -43,8 +39,6 @@ import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonWriter import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import java.util.function.Predicate -import kotlin.time.Duration.Companion.seconds @SkyHanniModule object ShTrack { @@ -96,7 +90,7 @@ object ShTrack { CommandArgument( " - Item to be tracked", defaultPosition = 0, - validity = ::validIfItemState, + validity = ShTrack::validIfItemState, tabComplete = CommandUtils::itemTabComplete, ) { a, c -> val r = itemCheck(a, c) @@ -121,12 +115,12 @@ object ShTrack { CommandArgument( "<> - Sets the current amount from sacks and inventory", "-s", - validity = ::validIfItemState, + validity = ShTrack::validIfItemState, ) { _, c -> c.currentFetch = ContextObject.CurrentFetch.SACKS 0 }, - CommandArgument("<> - Sets the current amount from inventory", "-v", validity = ::validIfItemState) { _, c -> + CommandArgument("<> - Sets the current amount from inventory", "-v", validity = ShTrack::validIfItemState) { _, c -> c.currentFetch = ContextObject.CurrentFetch.INVENTORY 0 }, @@ -150,7 +144,7 @@ object ShTrack { c.notify = true 0 }, - CommandArgument("<> - Uses all tiers of an item", "-m", validity = ::validIfItemState) { _, c -> + CommandArgument("<> - Uses all tiers of an item", "-m", validity = ShTrack::validIfItemState) { _, c -> c.multiItem = true 0 }, @@ -166,10 +160,6 @@ object ShTrack { private fun validIfItemState(context: ContextObject) = context.state == ContextObject.StateType.ITEM - init { - ItemGroup("GOLD", "GOLD_INGOT" to 1, "GOLD_BLOCK" to 9, "ENCHANTED_GOLD" to 160, "ENCHANTED_GOLD_BLOCK" to 160 * 160) - } - class ContextObject : CommandContextAwareObject { var allowDupe = false @@ -333,117 +323,6 @@ object ShTrack { } } - private val tracker get() = ProfileStorageData.profileSpecific?.tracking - - class TrackingList : ArrayList>(), MutableList> { - - var isActive = false - - fun activate() { - if (isActive) return - isActive = true - forEach { - it.atAdd() - it.line = it.generateLine() - } - updateDisplay() - } - - fun deactivate() { - if (!isActive) return - isActive = false - forEach { - it.atRemove() - it.line = emptyList() - } - } - - override fun clear() { - forEach { - it.atRemove() - } - super.clear() - updateDisplay() - } - - override fun addAll(elements: Collection>): Boolean { - elements.forEach { it.atAdd() } - val r = super.addAll(elements) - updateDisplay() - return r - } - - override fun remove(element: TrackingElement<*>): Boolean = indexOf(element).let { - if (it == -1) false else { - removeAt(it) - true - } - } - - override fun removeAt(index: Int): TrackingElement<*> { - this[index].atRemove() - val r = super.removeAt(index) - updateDisplay() - return r - } - - override fun set(index: Int, element: TrackingElement<*>): TrackingElement<*> { - this.getOrNull(index)?.atRemove() - element.atAdd() - val r = super.set(index, element) - updateDisplay() - return r - } - - override fun add(element: TrackingElement<*>): Boolean { - element.atAdd() - val r = super.add(element) - updateDisplay() - return r - } - - override fun add(index: Int, element: TrackingElement<*>) { - element.atAdd() - val r = super.add(index, element) - updateDisplay() - return r - } - - override fun addAll(index: Int, elements: Collection>): Boolean { - elements.forEach { it.atAdd() } - val r = super.addAll(index, elements) - updateDisplay() - return r - } - - override fun removeRange(fromIndex: Int, toIndex: Int) { - (fromIndex..>): Boolean { - var r = true - elements.forEach { if (!remove(it)) r = false } - return r - } - - override fun removeIf(filter: Predicate>): Boolean { - var r = false - val iter = iterator() - while (iter.hasNext()) { - val it = iter.next() - if (filter.test(it)) { - r = true - it.atRemove() - iter.remove() - } - } - updateDisplay() - return r - } - } - val typeAdapter = object : TypeAdapter>() { override fun write(out: JsonWriter, value: TrackingElement<*>) { if (!value.shouldSave) { @@ -470,6 +349,7 @@ object ShTrack { reader.endObject() try { + // New Tracking Elements need to be added to when below val tracker: TrackingElement<*> = when (map["type"]?.asString) { PowderTrackingElement::class.simpleName -> PowderTrackingElement.fromJson(map) ItemsStackElement::class.simpleName -> ItemsStackElement.fromJson(map) @@ -488,12 +368,45 @@ object ShTrack { } } - private val itemTrackers: MutableMap> = mutableMapOf() - private val powderTracker = mutableListOf() + val itemTrackers: MutableMap> = mutableMapOf() + val powderTracker = mutableListOf() - private var display: Renderable = Renderable.placeholder(0, 0) + @HandleEvent + fun onItemAdd(event: ItemAddEvent) { + val trackers = itemTrackers[event.internalName] ?: return + if (event.source == ItemAddManager.Source.SACKS) { + for (tracker in trackers) { + if (!tracker.includeSack) continue + tracker.itemChange(event.pStack) + } + } else { + for (tracker in trackers) { + tracker.itemChange(event.pStack) + } + } + } + + @HandleEvent + fun onPowderGain(event: PowderGainEvent) { + powderTracker.forEach { + if (it.type == event.powder) { + it.update(event.amount) + } + } + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.enable + + val tracker get() = ProfileStorageData.profileSpecific?.tracking + + private var display: Renderable = Renderable.placeholder(0, 0) private var hasGrab = false + private var scheduledUpdate = false + + fun updateDisplay() { + scheduledUpdate = true + } @HandleEvent fun onProfileLeave(event: ProfileLeaveEvent) { @@ -507,7 +420,7 @@ object ShTrack { @SubscribeEvent fun onGuiRenderGuiOverlayRender(event: GuiRenderEvent) { - if (!LorenzUtils.inSkyBlock) return + if (!isEnabled()) return val tracker = tracker if (scheduledUpdate && tracker != null) { display = Renderable.verticalEditTable( @@ -533,344 +446,4 @@ object ShTrack { } config.position.renderRenderable(display, posLabel = "Tracker") } - - @HandleEvent - fun onItemAdd(event: ItemAddEvent) { - val trackers = itemTrackers[event.internalName] ?: return - if (event.source == ItemAddManager.Source.SACKS) { - for (tracker in trackers) { - if (!tracker.includeSack) continue - tracker.itemChange(event.pStack) - } - } else { - for (tracker in trackers) { - tracker.itemChange(event.pStack) - } - } - - } - - @HandleEvent - fun onPowderGain(event: PowderGainEvent) { - powderTracker.forEach { - if (it.type == event.powder) { - it.update(event.amount) - } - } - } - - private var scheduledUpdate = false - - fun updateDisplay() { - scheduledUpdate = true - } - - private abstract class ItemTrackingInterface() : TrackingElement() { - - abstract fun itemChange(item: PrimitiveItemStack) - - abstract val includeSack: Boolean - - override fun toJson(out: JsonWriter) { - super.toJson(out) - out.name("sack").value(includeSack) - } - } - - private class ItemTrackingElement( - val item: NEUInternalName, - override var current: Long, - override val target: Long?, - override val includeSack: Boolean, - ) : ItemTrackingInterface() { - - override val name get() = item.itemName - override val saveName = item.asString() - - override fun similarElement(other: TrackingElement<*>): Boolean { - if (other !is ItemTrackingElement) return false - return other.item == this.item - } - - override fun atRemove() { - itemTrackers[item]?.remove(this) - } - - override fun atAdd() { - itemTrackers.compute(item) { _, v -> - v?.also { it.add(this) } ?: mutableListOf(this) - } - } - - override fun internalUpdate(amount: Number) { - current += amount.toLong() - if (target != null && current >= target) { - handleDone("$name §adone") - } - } - - override fun generateLine() = listOf( - Renderable.itemStack(item.getItemStack()), - Renderable.string(item.itemName), - Renderable.string(current.toString() + ((target?.let { " / $it" }).orEmpty())), - ) - - override fun itemChange(item: PrimitiveItemStack) { - update(item.amount) - } - - companion object { - fun fromJson(read: Map): ItemsStackElement = ItemsStackElement( - read["name"]!!.asString.toInternalName(), - read["current"]?.asLong ?: 0, - read["target"]?.asLong, - read["sack"]?.asBoolean ?: false, - ) - } - } - - private fun NEUInternalName.getMultipleMap() = CollectionAPI.findAllMultiples()[this] ?: mapOf(this to 1) - - private class ItemsStackElement( - val main: NEUInternalName, - override var current: Long, - override val target: Long?, - override val includeSack: Boolean, - ) : ItemTrackingInterface() { - - override val name get() = main.itemName - override val saveName = main.asString() - - val map = NEUItems.getPrimitiveMultiplier(main).internalName.getMultipleMap() - - private val mappedCurrent get() = map[main]?.let { current.div(it) } ?: current - - override fun similarElement(other: TrackingElement<*>): Boolean { - if (other !is ItemsStackElement) return false - return other.main == this.main - } - - override fun atRemove() { - for (item in map.keys) { - itemTrackers[item]?.remove(this) - } - } - - override fun atAdd() { - for (item in map.keys) { - itemTrackers.compute(item) { _, v -> - v?.also { it.add(this) } ?: mutableListOf(this) - } - } - } - - override fun internalUpdate(amount: Number) { - current += amount.toLong() - if (target != null && mappedCurrent >= target) { - handleDone("$name §adone") - } - } - - override fun generateLine() = listOf( - Renderable.itemStack(main.getItemStack()), - Renderable.string(main.itemName), - - Renderable.string(mappedCurrent.toString() + ((target?.let { " / $it" }).orEmpty())), - ) - - override fun itemChange(item: PrimitiveItemStack) { - val multiple = map[item.internalName] ?: throw IllegalStateException("You should not be here!") - update(item.amount * multiple) - } - - companion object { - - fun fromJson(read: Map): ItemsStackElement = ItemsStackElement( - read["name"]!!.asString.toInternalName(), - read["current"]?.asLong ?: 0, - read["target"]?.asLong, - read["sack"]?.asBoolean ?: false, - ) - } - } - - // TODO remove - @Deprecated("Not needed anymore") - private class ItemGroupElement( - val group: ItemGroup, - override var current: Long, - override val target: Long?, - override val includeSack: Boolean, - ) : ItemTrackingInterface() { - - override val name = group.name - override val saveName = group.name - - override fun similarElement(other: TrackingElement<*>): Boolean { - if (other !is ItemGroupElement) return false - return other.group == this.group - } - - override fun atRemove() { - for (item in group.items.keys) { - itemTrackers[item]?.remove(this) - } - } - - override fun atAdd() { - for (item in group.items.keys) { - itemTrackers.compute(item) { _, v -> - v?.also { it.add(this) } ?: mutableListOf(this) - } - } - } - - override fun internalUpdate(amount: Number) { - current += amount.toLong() - if (target != null && current >= target) { - handleDone("${group.name} §adone") - } - } - - override fun generateLine() = listOf( - Renderable.itemStack(group.icon.getItemStack()), - Renderable.string(group.name), - Renderable.string(current.toString() + ((target?.let { " / $it" }).orEmpty())), - ) - - override fun itemChange(item: PrimitiveItemStack) { - val multiple = group.items[item.internalName] ?: throw IllegalStateException("You should not be here!") - update(item.amount * multiple) - } - } - - private class PowderTrackingElement(val type: HotmAPI.PowderType, override var current: Long, override val target: Long?) : - TrackingElement() { - - override val name = "${type.displayNameWithColor} Powder" - override val saveName = type.name - - override fun internalUpdate(amount: Number) { - current += amount.toLong() - if (target != null && current >= target) { - handleDone("${type.displayName} §adone") - } - } - - override fun generateLine() = listOf( - Renderable.itemStack(type.icon), - Renderable.string(type.displayName), - Renderable.string(current.toString() + ((target?.let { " / $it" }).orEmpty())), - ) - - override fun similarElement(other: TrackingElement<*>): Boolean { - if (other !is PowderTrackingElement) return false - return other.type == this.type - } - - override fun atRemove() { - powderTracker.remove(this) - } - - override fun atAdd() { - powderTracker.add(this) - } - - companion object { - fun fromJson(read: Map): PowderTrackingElement = - PowderTrackingElement(extractType(read), read["current"]?.asLong ?: 0, read["target"]?.asLong) - - private fun extractType(read: Map) = HotmAPI.PowderType.getValue(read["name"]!!.asString)!! - } - - } - - abstract class TrackingElement { - - var shouldNotify = false - var shouldAutoDelete = false - var shouldSave = false - - abstract var current: T - abstract val target: T? - - abstract val name: String - abstract val saveName: String - - fun update(amount: Number) { - if (amount == 0) return - internalUpdate(amount) - line = generateLine() - updateDisplay() - } - - fun handleDone(notify: String) { - if (shouldNotify) { - notify(notify) - } - if (shouldAutoDelete) { - delete() - } - } - - fun notify(string: String) { - shouldNotify = false - SoundUtils.playPlingSound() - LorenzUtils.sendTitle(string, 4.0.seconds) - } - - fun delete() { - tracker?.remove(this) ?: ErrorManager.logErrorStateWithData( - "Could not delete tracker element.", - "Tracker is null", - "element" to this, - ) - } - - protected abstract fun internalUpdate(amount: Number) - - var line: List = emptyList() - - abstract fun similarElement(other: TrackingElement<*>): Boolean - - abstract fun atRemove() - - abstract fun atAdd() - - abstract fun generateLine(): List - open fun generateHover(): List = listOf( - "$name §eTracker", - "§e§lRIGHT CLICK §r§eto §cdelete", - ) - - open fun handleUserInput() { - if ((-99).isKeyClicked()) { // Right Click - delete() - } - } - - open fun toJson(out: JsonWriter) { - out.name("type").value(this::class.simpleName) - out.name("name").value(saveName) - out.name("target").value(target) - out.name("current").value(current) - out.name("shouldAutoDelete").value(shouldAutoDelete) - out.name("shouldNotify").value(shouldNotify) - } - } - - private fun > T.applyMetaOptions(read: Map) { - shouldSave = true - shouldAutoDelete = read["shouldAutoDelete"]?.asBoolean ?: false - shouldNotify = read["shouldNotify"]?.asBoolean ?: false - } - - fun isEnabled() = LorenzUtils.inSkyBlock && config.enable - -} - -private fun MutableList.move(from: Int, to: Int) { - val element = this[from] - this.removeAt(from) - add(to, element) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/TrackingElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/TrackingElement.kt new file mode 100644 index 000000000000..c97c332364ad --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/TrackingElement.kt @@ -0,0 +1,94 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.renderables.Renderable +import com.google.gson.JsonElement +import com.google.gson.stream.JsonWriter +import kotlin.time.Duration.Companion.seconds + +/** The Base for any Tracking Element + * + * If you want to add a new type of Element you need to add the class in the [ShTrack.typeAdapter] + * */ +abstract class TrackingElement { + + var shouldNotify = false + var shouldAutoDelete = false + var shouldSave = false + + abstract var current: T + abstract val target: T? + + abstract val name: String + abstract val saveName: String + + fun update(amount: Number) { + if (amount == 0) return + internalUpdate(amount) + line = generateLine() + ShTrack.updateDisplay() + } + + fun handleDone(notify: String) { + if (shouldNotify) { + notify(notify) + } + if (shouldAutoDelete) { + delete() + } + } + + fun notify(string: String) { + shouldNotify = false + SoundUtils.playPlingSound() + LorenzUtils.sendTitle(string, 4.0.seconds) + } + + fun delete() { + ShTrack.tracker?.remove(this) ?: ErrorManager.logErrorStateWithData( + "Could not delete tracker element.", + "Tracker is null", + "element" to this, + ) + } + + protected abstract fun internalUpdate(amount: Number) + + var line: List = emptyList() + + abstract fun similarElement(other: TrackingElement<*>): Boolean + + abstract fun atRemove() + + abstract fun atAdd() + + abstract fun generateLine(): List + open fun generateHover(): List = listOf( + "$name §eTracker", + "§e§lRIGHT CLICK §r§eto §cdelete", + ) + + open fun handleUserInput() { + if ((-99).isKeyClicked()) { // Right Click + delete() + } + } + + open fun toJson(out: JsonWriter) { + out.name("type").value(this::class.simpleName) + out.name("name").value(saveName) + out.name("target").value(target) + out.name("current").value(current) + out.name("shouldAutoDelete").value(shouldAutoDelete) + out.name("shouldNotify").value(shouldNotify) + } + + fun applyMetaOptions(read: Map) { + shouldSave = true + shouldAutoDelete = read["shouldAutoDelete"]?.asBoolean ?: false + shouldNotify = read["shouldNotify"]?.asBoolean ?: false + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/TrackingList.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/TrackingList.kt new file mode 100644 index 000000000000..4fc9e112b889 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/shtrack/TrackingList.kt @@ -0,0 +1,112 @@ +package at.hannibal2.skyhanni.features.gui.shtrack + +import java.util.function.Predicate + +class TrackingList : ArrayList>(), MutableList> { + + var isActive = false + + fun activate() { + if (isActive) return + isActive = true + forEach { + it.atAdd() + it.line = it.generateLine() + } + ShTrack.updateDisplay() + } + + fun deactivate() { + if (!isActive) return + isActive = false + forEach { + it.atRemove() + it.line = emptyList() + } + } + + override fun clear() { + forEach { + it.atRemove() + } + super.clear() + ShTrack.updateDisplay() + } + + override fun addAll(elements: Collection>): Boolean { + elements.forEach { it.atAdd() } + val r = super.addAll(elements) + ShTrack.updateDisplay() + return r + } + + override fun remove(element: TrackingElement<*>): Boolean = indexOf(element).let { + if (it == -1) false else { + removeAt(it) + true + } + } + + override fun removeAt(index: Int): TrackingElement<*> { + this[index].atRemove() + val r = super.removeAt(index) + ShTrack.updateDisplay() + return r + } + + override fun set(index: Int, element: TrackingElement<*>): TrackingElement<*> { + this.getOrNull(index)?.atRemove() + element.atAdd() + val r = super.set(index, element) + ShTrack.updateDisplay() + return r + } + + override fun add(element: TrackingElement<*>): Boolean { + element.atAdd() + val r = super.add(element) + ShTrack.updateDisplay() + return r + } + + override fun add(index: Int, element: TrackingElement<*>) { + element.atAdd() + val r = super.add(index, element) + ShTrack.updateDisplay() + return r + } + + override fun addAll(index: Int, elements: Collection>): Boolean { + elements.forEach { it.atAdd() } + val r = super.addAll(index, elements) + ShTrack.updateDisplay() + return r + } + + override fun removeRange(fromIndex: Int, toIndex: Int) { + (fromIndex..>): Boolean { + var r = true + elements.forEach { if (!remove(it)) r = false } + return r + } + + override fun removeIf(filter: Predicate>): Boolean { + var r = false + val iter = iterator() + while (iter.hasNext()) { + val it = iter.next() + if (filter.test(it)) { + r = true + it.atRemove() + iter.remove() + } + } + ShTrack.updateDisplay() + return r + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt index 23c7b7266e90..2becf3cb2d39 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt @@ -273,7 +273,6 @@ object CollectionUtils { fun Collection.takeIfNotEmpty(): Collection? = takeIf { it.isNotEmpty() } - fun List.toPair(): Pair? = if (size == 2) this[0] to this[1] else null fun Pair.equalsIgnoreOrder(other: Pair): Boolean = toSet() == other.toSet() @@ -456,6 +455,12 @@ object CollectionUtils { return sum } + fun MutableList.move(from: Int, to: Int) { + val element = this[from] + this.removeAt(from) + add(to, element) + } + inline fun Iterable.zipWithNext3(transform: (a: T, b: T, c: T) -> R): List { val iterator = iterator() if (!iterator.hasNext()) return emptyList() diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt index 96e93551f0b4..4e4c656c9b8a 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt @@ -2,8 +2,8 @@ package at.hannibal2.skyhanni.utils.json import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity -import at.hannibal2.skyhanni.features.gui.ShTrack -import at.hannibal2.skyhanni.features.gui.ShTrack.TrackingElement +import at.hannibal2.skyhanni.features.gui.shtrack.ShTrack +import at.hannibal2.skyhanni.features.gui.shtrack.TrackingElement import at.hannibal2.skyhanni.utils.KotlinTypeAdapterFactory import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.LorenzVec