diff --git a/src/main/kotlin/me/partlysanestudios/partlysaneskies/config/OneConfigScreen.kt b/src/main/kotlin/me/partlysanestudios/partlysaneskies/config/OneConfigScreen.kt index 73bb63c5..c7112930 100644 --- a/src/main/kotlin/me/partlysanestudios/partlysaneskies/config/OneConfigScreen.kt +++ b/src/main/kotlin/me/partlysanestudios/partlysaneskies/config/OneConfigScreen.kt @@ -6,6 +6,7 @@ package me.partlysanestudios.partlysaneskies.config import cc.polyfrost.oneconfig.config.Config +import cc.polyfrost.oneconfig.config.annotations.Button import cc.polyfrost.oneconfig.config.annotations.Color import cc.polyfrost.oneconfig.config.annotations.Dropdown import cc.polyfrost.oneconfig.config.annotations.HUD @@ -22,6 +23,8 @@ import cc.polyfrost.oneconfig.config.data.Mod import cc.polyfrost.oneconfig.config.data.ModType import me.partlysanestudios.partlysaneskies.features.debug.ExampleHud import me.partlysanestudios.partlysaneskies.features.gui.hud.CooldownHud +import me.partlysanestudios.partlysaneskies.features.gui.hud.rngdropbanner.RareDropGUI +import me.partlysanestudios.partlysaneskies.utils.MinecraftUtils import org.lwjgl.input.Keyboard object OneConfigScreen : Config( @@ -427,6 +430,18 @@ object OneConfigScreen : Config( ) var blockLegendaryDrops = false + @Button( + name = "Filter Individual Items", + text = "Open Menu", + description = "Click to open a menu to blacklist individual items.", + category = "SkyBlock", + subcategory = "Rare Drop", + size = 2 + ) + val rareDropFilterButton = Runnable { + MinecraftUtils.displayGuiScreen(RareDropGUI()) + } + // Location Banner @Switch( name = "Location Banner", diff --git a/src/main/kotlin/me/partlysanestudios/partlysaneskies/data/skyblockdata/SkyblockDataManager.kt b/src/main/kotlin/me/partlysanestudios/partlysaneskies/data/skyblockdata/SkyblockDataManager.kt index b6bd19a0..c1f83656 100644 --- a/src/main/kotlin/me/partlysanestudios/partlysaneskies/data/skyblockdata/SkyblockDataManager.kt +++ b/src/main/kotlin/me/partlysanestudios/partlysaneskies/data/skyblockdata/SkyblockDataManager.kt @@ -15,6 +15,7 @@ import me.partlysanestudios.partlysaneskies.data.api.RequestsManager.newRequest import me.partlysanestudios.partlysaneskies.data.pssdata.PublicDataManager.getFile import me.partlysanestudios.partlysaneskies.events.SubscribePSSEvent import me.partlysanestudios.partlysaneskies.events.data.LoadPublicDataEvent +import me.partlysanestudios.partlysaneskies.utils.StringUtils.removeColorCodes import java.io.IOException import java.net.MalformedURLException @@ -79,8 +80,8 @@ object SkyblockDataManager { en.get("unstackable")?.asBoolean ?: false, ) - idToItemMap[en.get("itemId").asString] = skyblockItem - nameToIdMap[en.get("name").asString] = en.get("itemId").asString + idToItemMap[skyblockItem.id] = skyblockItem + nameToIdMap[skyblockItem.name.removeColorCodes()] = skyblockItem.id } }, inMainThread = false, @@ -101,14 +102,10 @@ object SkyblockDataManager { } } - fun getId(name: String): String = nameToIdMap[name] ?: "" + fun getId(name: String): String = nameToIdMap[name.removeColorCodes()] ?: "" + + fun getItem(id: String): SkyblockItem? = idToItemMap[id] - fun getItem(id: String): SkyblockItem? = - if (!idToItemMap.containsKey(id)) { - null - } else { - idToItemMap[id] - } fun runUpdaterTick() { if (checkLastUpdate()) { @@ -124,6 +121,8 @@ object SkyblockDataManager { } } + fun getAllItems(): List = idToItemMap.keys.toList() + // --------------------------- Skills --------------------------- private var idToSkillMap = HashMap() diff --git a/src/main/kotlin/me/partlysanestudios/partlysaneskies/features/gui/hud/rngdropbanner/RareDropGUI.kt b/src/main/kotlin/me/partlysanestudios/partlysaneskies/features/gui/hud/rngdropbanner/RareDropGUI.kt index 0e74bdaf..888ddfc6 100644 --- a/src/main/kotlin/me/partlysanestudios/partlysaneskies/features/gui/hud/rngdropbanner/RareDropGUI.kt +++ b/src/main/kotlin/me/partlysanestudios/partlysaneskies/features/gui/hud/rngdropbanner/RareDropGUI.kt @@ -1,5 +1,5 @@ // -// Written by J10an15. +// Written by J10an15 and Su386. // See LICENSE for copyright and license notices. // @@ -21,12 +21,18 @@ import gg.essential.elementa.dsl.constrain import gg.essential.elementa.dsl.constraint import gg.essential.elementa.dsl.percent import gg.essential.elementa.dsl.pixels +import gg.essential.elementa.dsl.plus +import me.partlysanestudios.partlysaneskies.data.skyblockdata.Rarity +import me.partlysanestudios.partlysaneskies.data.skyblockdata.SkyblockDataManager import me.partlysanestudios.partlysaneskies.features.gui.hud.rngdropbanner.RareDropGUIManager.currentFilter import me.partlysanestudios.partlysaneskies.features.gui.hud.rngdropbanner.RareDropGUIManager.currentFilterType import me.partlysanestudios.partlysaneskies.features.themes.ThemeManager import me.partlysanestudios.partlysaneskies.features.themes.ThemeManager.primaryColor import me.partlysanestudios.partlysaneskies.render.gui.components.PSSButton import me.partlysanestudios.partlysaneskies.render.gui.constraints.ScaledPixelConstraint.Companion.scaledPixels +import me.partlysanestudios.partlysaneskies.utils.ImageUtils.minus +import me.partlysanestudios.partlysaneskies.utils.StringUtils.colorCodeToColor +import org.lwjgl.input.Keyboard import java.awt.Color class RareDropGUI : WindowScreen(ElementaVersion.V5) { @@ -38,7 +44,6 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { color = Color(0, 0, 0, 0).constraint } childOf window - /** * Create Filter Container */ @@ -53,52 +58,61 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { width = 90.percent x = 5.percent y = 2.percent - textScale = 1.5.scaledPixels - color = Color.gray.constraint + textScale = 2.5.scaledPixels + color = Color.lightGray.constraint } childOf createFilterContainer - private val createFiltersInput = UITextInput("Create a ${currentFilterType.displayName} Filter...").constrain { + private val createFiltersSearchBar = UITextInput("Search Items...").constrain { width = 90.percent - height = 5.percent + height = 3.percent x = 5.percent - y = 7.percent + y = SiblingConstraint() + 2.percent + textScale = 1.5.scaledPixels + color = Color.gray.constraint }.onMouseClick { grabWindowFocus() - } as UITextInput childOf createFilterContainer + }.onKeyType {_, key -> + if (key == Keyboard.KEY_NUMPADENTER || key == Keyboard.KEY_RETURN){ + val text = (this as UITextInput).getText() + if (text.isBlank()) return@onKeyType + RareDropGUIManager.addFilter(text) + this.setText("") + updateFilterList() + } - private val createFiltersScrollComponent = ScrollComponent( - scrollIconColor = primaryColor.toJavaColor(), - innerPadding = 10f, - scrollAcceleration = 2f, - ).constrain { - width = 100.percent - height = 90.percent - x = 0.percent - y = 10.percent - } childOf createFilterContainer + this.setColor(Color.lightGray) + + updateCreateFilterAutocomplete() + }.onMouseEnter { + this.setColor(Color.lightGray) + }.onMouseLeave { + if ((this as UITextInput).getText().isEmpty()) { + this.setColor(Color.gray) + } + } as UITextInput childOf createFilterContainer private val createFilterButton = PSSButton() - .setText("Add ${currentFilterType.displayName} Filter") - .setX(5.percent) - .setY(15.percent) - .setHeight(50.pixels) - .setWidth(60.pixels) + .setText("Add to ${currentFilterType.displayName} Filter") + .setX(CramSiblingConstraint() + 5.percent) + .setY(CramSiblingConstraint() + 2.percent) + .setHeight(50.scaledPixels) + .setWidth(60.scaledPixels) .setChildOf(createFilterContainer) .onMouseClickConsumer { - val text = createFiltersInput.getText() + val text = createFiltersSearchBar.getText() if (text.isBlank()) return@onMouseClickConsumer RareDropGUIManager.addFilter(text) - createFiltersInput.setText("") + createFiltersSearchBar.setText("") updateFilterList() } private var opposite = RareDropGUIManager.FilterType.entries.first { it != currentFilterType } private val switchTypeButton = PSSButton() .setText("Switch to ${opposite.displayName}") - .setX(5.percent) - .setY(SiblingConstraint(5f)) - .setHeight(50.pixels) - .setWidth(60.pixels) + .setX(CramSiblingConstraint() + 2.percent) + .setY(CramSiblingConstraint()) + .setHeight(50.scaledPixels) + .setWidth(90.scaledPixels) .setChildOf(createFilterContainer) .onMouseClickConsumer { currentFilterType = opposite @@ -107,6 +121,14 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { update() } + private val autoCompleteScrollComponent = ScrollComponent().constrain { + x = CenterConstraint() + y = SiblingConstraint() + 2.percent + width = 90.percent + height = 70.percent + color = Color.red.constraint + } childOf createFilterContainer + /** * Active Filter Container */ @@ -117,23 +139,31 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { y = 0.percent } childOf backgroundBox - private val activeFiltersHeading = UIWrappedText("${currentFilterType.displayName} Filters:").constrain { + private val activeFiltersHeading = UIWrappedText("Active ${currentFilterType.displayName} Filters:").constrain { width = 90.percent x = 5.percent y = 2.percent - textScale = 1.5.scaledPixels + textScale = 2.5.scaledPixels color = Color.green.constraint } childOf activeFiltersContainer - private val activeFiltersSearchBar: UITextInput = UITextInput("Search...").constrain { + private val activeFiltersSearchBar: UITextInput = UITextInput("Search Filters...").constrain { width = 90.percent - height = 5.percent + height = 3.percent x = 5.percent - y = 7.percent + y = SiblingConstraint() + 2.percent + textScale = 1.5.scaledPixels + color = Color.gray.constraint }.onMouseClick { grabWindowFocus() }.onKeyType { _, _ -> updateFilterList() + }.onMouseEnter { + this.setColor(Color.lightGray) + }.onMouseLeave { + if ((this as UITextInput).getText().isEmpty()) { + this.setColor(Color.gray) + } } as UITextInput childOf activeFiltersContainer private val activeFiltersScrollComponent = ScrollComponent( @@ -143,7 +173,7 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { width = 100.percent height = 90.percent x = 0.percent - y = 10.percent + y = SiblingConstraint() + 1.percent } childOf activeFiltersContainer @@ -157,13 +187,21 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { y = 80.percent } childOf backgroundBox + private val presetsHeading = UIWrappedText("Add Bulk Items:").constrain { + x = 4.percent + y = 10.percent + width = 92.percent + textScale = 1.5.scaledPixels + color = Color.green.constraint + } childOf presetsContainer + private val presetButtons = RareDropGUIManager.presets.forEachIndexed { columnIndex, (presetName, items) -> PSSButton() .setText(presetName) .setX((15 * columnIndex + 5).percent) - .setY(CenterConstraint()) - .setHeight(50.pixels) - .setWidth(60.pixels) + .setY(CenterConstraint() + 10.percent) + .setHeight(50.scaledPixels) + .setWidth(60.scaledPixels) .setChildOf(presetsContainer) .onMouseClickConsumer { RareDropGUIManager.addFilter(*items.toTypedArray()) @@ -175,42 +213,158 @@ class RareDropGUI : WindowScreen(ElementaVersion.V5) { update() } + private fun createAutoCompletedItem(itemName: String, itemColor: Color) { + val boundingBox = UIBlock().constrain { + x = CramSiblingConstraint(10f) + y = CramSiblingConstraint(10f) + width = 48.percent + height = 8.5.percent + color = Color(0,0 ,0, 0).constraint + } childOf autoCompleteScrollComponent + + + val text = UIWrappedText(itemName).constrain { + x = 0.pixels + y = CenterConstraint() + width = 100.percent + textScale = 1.5.scaledPixels + color = itemColor.constraint + } + + val textHitbox = UIBlock().constrain { + x = 0.pixels + y = CenterConstraint() + width = 90.percent + height = 100.percent + color = Color(0, 0, 0, 0).constraint + }.onMouseClick { + if (it.mouseButton != 0) { + return@onMouseClick + } + + RareDropGUIManager.addFilter(itemName) + updateFilterList() + }.onMouseEnter { + text.setColor(itemColor - Color(66, 66, 66)) + }.onMouseLeave { + text.setColor(itemColor) + } childOf boundingBox + + text childOf textHitbox + + val fillArrow = UIWrappedText("↖", centered = true).constrain { + x = 0.pixels(alignOpposite = true) + y = CenterConstraint() + width = 10.percent + height = 100.percent + textScale = 3.scaledPixels + color = Color.lightGray.constraint + }.onMouseClick { + if (it.mouseButton != 0) { + return@onMouseClick + } + createFiltersSearchBar.setText(itemName) + updateCreateFilterAutocomplete() + }.onMouseEnter { + this.setColor(Color.gray) + }.onMouseLeave { + this.setColor(Color.lightGray) + } childOf boundingBox + } + + private fun updateCreateFilterAutocomplete() { + autoCompleteScrollComponent.clearChildren() + val searchText = createFiltersSearchBar.getText() + + createFiltersSearchBar.setColor(if (searchText.isBlank()) Color.gray else Color.lightGray) + + val addedNames = mutableSetOf() + + SkyblockDataManager.getAllItems() + .sorted() + .asSequence() + .mapNotNull { id -> + SkyblockDataManager.getItem(id)?.takeIf { + id.contains(searchText, ignoreCase = true) || it.name.contains(searchText, ignoreCase = true) + }?.let { item -> + item.name to if (item.rarity == Rarity.UNKNOWN) { + Color.white + } else { + item.rarity.colorCode.colorCodeToColor() + } + } + } + .filter { (name, _) -> + addedNames.add(name) + } + .take(100) + .forEach { (name, color) -> + createAutoCompletedItem(name, color) + } + } + private fun update() { updateFilterList() updateTitles() + updateCreateFilterAutocomplete() } private fun updateTitles() { - activeFiltersHeading.setText("${currentFilterType.displayName} Filters:") - createFilterButton.setText("Add ${currentFilterType.displayName} Filter") - switchTypeButton.setText("Switch to ${opposite.displayName}") + activeFiltersHeading.setText("Active ${currentFilterType.displayName} Filters:") + createFilterButton.setText("Add to ${currentFilterType.displayName}") + switchTypeButton.setText("Switch to ${opposite.displayName} Mode") } private fun updateFilterList() { activeFiltersScrollComponent.clearChildren() + if (activeFiltersSearchBar.getText().isBlank()) { + activeFiltersSearchBar.setColor(Color.gray) + } else { + activeFiltersSearchBar.setColor(Color.lightGray) + } + currentFilter .filter { it.contains(activeFiltersSearchBar.getText(), ignoreCase = true) } .forEach { filter -> - val xText = UIText("§cx").constrain { + val box = UIBlock() childOf activeFiltersScrollComponent + val xText = UIWrappedText("§cx", centered = true).constrain { + x = 0.pixels + y = CenterConstraint() + width = 10.percent + textScale = 1.5.scaledPixels + } childOf box + + val filterText = UIWrappedText(filter).constrain { + x = SiblingConstraint(4f) + y = CenterConstraint() + textScale = 1.5.scaledPixels + width = 90.percent + } childOf box + + box.constrain { x = 0.percent y = SiblingConstraint(4f) + height = 4.percent + width = 90.percent + color = Color(0, 0, 0, 0).constraint }.onMouseClick { currentFilter -= filter RareDropGUIManager.saveData() updateFilterList() - } childOf activeFiltersScrollComponent - - val filterText = UIText(filter).constrain { - x = 5.percent - y = CramSiblingConstraint() - } childOf activeFiltersScrollComponent - - xText.onMouseEnter { + }.onMouseEnter { filterText.setText("§m$filter") }.onMouseLeave { filterText.setText(filter) } + + val id = SkyblockDataManager.getId(filter) + val color = if (id.isNotBlank()) { + SkyblockDataManager.getItem(id)?.rarity?.colorCode?.colorCodeToColor() ?: Color.lightGray + } else { + Color.lightGray + } + filterText.setColor(color) } } } diff --git a/src/main/kotlin/me/partlysanestudios/partlysaneskies/render/gui/components/PSSButton.kt b/src/main/kotlin/me/partlysanestudios/partlysaneskies/render/gui/components/PSSButton.kt index 6d0ba7bb..0d384a51 100644 --- a/src/main/kotlin/me/partlysanestudios/partlysaneskies/render/gui/components/PSSButton.kt +++ b/src/main/kotlin/me/partlysanestudios/partlysaneskies/render/gui/components/PSSButton.kt @@ -20,6 +20,9 @@ import gg.essential.elementa.dsl.percent import gg.essential.elementa.events.UIClickEvent import me.partlysanestudios.partlysaneskies.features.themes.ThemeManager.currentButtonUIImage import me.partlysanestudios.partlysaneskies.features.themes.ThemeManager.getCurrentButtonUIImage +import me.partlysanestudios.partlysaneskies.render.gui.constraints.ScaledPixelConstraint.Companion.scaledPixels +import me.partlysanestudios.partlysaneskies.utils.ImageUtils.minus +import me.partlysanestudios.partlysaneskies.utils.ImageUtils.plus import java.awt.Color import java.util.function.Consumer @@ -45,13 +48,13 @@ class PSSButton { height = 100.percent } childOf backgroundBlock - private val textComponent = UIWrappedText(text, false, Color(0, 0, 0, 0), true) - .constrain { - x = CenterConstraint() - y = CenterConstraint() - width = 100.percent - color = Color.white.constraint - } childOf backgroundBlock + private val textComponent = UIWrappedText(text, false, Color(0, 0, 0, 0), true).constrain { + x = CenterConstraint() + y = CenterConstraint() + width = 100.percent + color = Color.lightGray.constraint + textScale = 1.scaledPixels + } childOf backgroundBlock constructor() { text = "" @@ -66,6 +69,18 @@ class PSSButton { this.color = color } + init { + backgroundBlock.onMouseEnter { + buttonTexture.setWidth(105.percent) + buttonTexture.setHeight(105.percent) + textComponent.setColor(textComponent.getColor() - Color(68, 68, 68)) + }.onMouseLeave { + buttonTexture.setWidth(100.percent) + buttonTexture.setHeight(100.percent) + textComponent.setColor(textComponent.getColor() + Color(68, 68, 68)) + } + } + fun setHeight(height: HeightConstraint): PSSButton { backgroundBlock.setHeight(height) return this diff --git a/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/ImageUtils.kt b/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/ImageUtils.kt index 519aaaa0..0653dc5d 100644 --- a/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/ImageUtils.kt +++ b/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/ImageUtils.kt @@ -52,6 +52,45 @@ object ImageUtils { fun Color.applyOpacity(opacity: Int): Color = Color(red, green, blue, opacity) + operator fun Color.plus(color: Color): Color { + val red = if (this.red + color.red > 255) { + 255 + } else { + this.red + color.red + } + val blue = if (this.blue + color.blue > 255) { + 255 + } else { + this.blue + color.blue + } + val green = if (this.green + color.green > 255) { + 255 + } else { + this.green + color.green + } + + return Color(red, green, blue) + } + + operator fun Color.minus(color: Color): Color { + val red = if (this.red - color.red < 0) { + 0 + } else { + this.red - color.red + } + val blue = if (this.blue - color.blue < 0) { + 0 + } else { + this.blue - color.blue + } + val green = if (this.green - color.green < 0) { + 0 + } else { + this.green - color.green + } + + return Color(red, green, blue) + } val Color.asHex: Int get() = red shl 16 or (green shl 8) or blue } diff --git a/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/StringUtils.kt b/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/StringUtils.kt index 81a7f060..a06b223b 100644 --- a/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/StringUtils.kt +++ b/src/main/kotlin/me/partlysanestudios/partlysaneskies/utils/StringUtils.kt @@ -354,7 +354,7 @@ object StringUtils { "§c" -> Color(255, 85, 85) "§d" -> Color(255, 85, 255) "§e" -> Color(255, 255, 85) - "§f" -> Color(0, 0, 0) + "§f" -> Color(255, 255, 255) "§1" -> Color(0, 0, 170) "§2" -> Color(0, 170, 0) "§3" -> Color(0, 170, 170)