diff options
author | Linnea Gräf <nea@nea.moe> | 2023-08-29 20:25:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-29 20:25:01 +0200 |
commit | 71a6b08b376be7d742107df982905cac0d7ecf70 (patch) | |
tree | a4b5f0cc511444ccd833c281b8600d9ff434231b /src/main/java/at/hannibal2/skyhanni/features/misc | |
parent | 238085dd49de8bca06ed816bc7a8d369390cdf30 (diff) | |
download | skyhanni-71a6b08b376be7d742107df982905cac0d7ecf70.tar.gz skyhanni-71a6b08b376be7d742107df982905cac0d7ecf70.tar.bz2 skyhanni-71a6b08b376be7d742107df982905cac0d7ecf70.zip |
Add default option selector #400
* Allow for update only options
* Clean/Split up mass configuration options
* Merge remote-tracking branch 'origin/beta' into feat/defaultoptions
* Fix merge errors
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/features/misc')
3 files changed, 375 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigFeatures.kt new file mode 100644 index 000000000..72f205b5e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigFeatures.kt @@ -0,0 +1,112 @@ +package at.hannibal2.skyhanni.features.misc.massconfiguration + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.utils.LorenzUtils +import io.github.moulberry.moulconfig.processor.ConfigProcessorDriver +import net.minecraft.client.Minecraft +import net.minecraft.command.CommandBase +import net.minecraft.event.ClickEvent +import net.minecraft.util.ChatComponentText +import net.minecraft.util.ChatStyle +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent + +object DefaultConfigFeatures { + var didNotifyOnce = false + + @SubscribeEvent + fun onTick(event: TickEvent) { + if (didNotifyOnce) return + val player = Minecraft.getMinecraft().thePlayer ?: return + didNotifyOnce = true + val knownToggles = SkyHanniMod.feature.storage.knownFeatureToggles + val updated = SkyHanniMod.version !in knownToggles + val processor = FeatureToggleProcessor() + ConfigProcessorDriver.processConfig(SkyHanniMod.feature.javaClass, SkyHanniMod.feature, processor) + knownToggles[SkyHanniMod.version] = processor.allOptions.map { it.path } + SkyHanniMod.configManager.saveConfig("Updated known feature flags") + if (!SkyHanniMod.feature.storage.hasPlayedBefore) { + SkyHanniMod.feature.storage.hasPlayedBefore = true + player.addChatMessage( + ChatComponentText( + "§e[SkyHanni] Looks like this is the first time you are using SkyHanni." + + " Click here to configure default options, or run /shdefaultoptions." + ).setChatStyle( + ChatStyle().setChatClickEvent( + ClickEvent( + ClickEvent.Action.RUN_COMMAND, + "/shdefaultoptions" + ) + ) + ) + ) + + } else if (updated) { + val mostFeatureFulOldVersion = knownToggles.maxByOrNull { if (it.key != SkyHanniMod.version) it.value.size else -1 } + val command = "/shdefaultoptions ${mostFeatureFulOldVersion?.key} ${SkyHanniMod.version}" + player.addChatMessage( + ChatComponentText( + "§e[SkyHanni] Looks like you updated SkyHanni." + + " Click here to configure the newly introduced options, or run $command." + ).setChatStyle( + ChatStyle().setChatClickEvent( + ClickEvent( + ClickEvent.Action.RUN_COMMAND, + command + ) + ) + ) + ) + } + } + + fun onCommand(old: String, new: String) { + val processor = FeatureToggleProcessor() + ConfigProcessorDriver.processConfig(SkyHanniMod.feature.javaClass, SkyHanniMod.feature, processor) + var optionList = processor.orderedOptions + val knownToggles = SkyHanniMod.feature.storage.knownFeatureToggles + val togglesInNewVersion = knownToggles[new] + if (new != "null" && togglesInNewVersion == null) { + LorenzUtils.chat("§e[SkyHanni] Unknown version $new") + return + } + val togglesInOldVersion = knownToggles[old] + if (old != "null" && togglesInOldVersion == null) { + LorenzUtils.chat("§e[SkyHanni] Unknown version $old") + return + } + optionList = optionList.mapValues { it.value.filter { (togglesInNewVersion == null || it.path in togglesInNewVersion) && (togglesInOldVersion == null || it.path !in togglesInOldVersion) } } + .filter { it.value.isNotEmpty() } + SkyHanniMod.screenToOpen = DefaultConfigOptionGui(optionList, old, new) + } + + fun applyCategorySelections( + resetSuggestionState: MutableMap<FeatureToggleProcessor.Category, DefaultConfigOptionGui.ResetSuggestionState>, + orderedOptions: Map<FeatureToggleProcessor.Category, List<FeatureToggleProcessor.FeatureToggleableOption>> + ) { + orderedOptions.forEach { cat, options -> + for (option in options) { + val resetState = option.toggleOverride ?: resetSuggestionState[cat]!! + if (resetState == DefaultConfigOptionGui.ResetSuggestionState.LEAVE_DEFAULTS) continue + val onState = option.isTrueEnabled + val setTo = if (resetState == DefaultConfigOptionGui.ResetSuggestionState.TURN_ALL_ON) { + onState + } else { + !onState + } + option.setter(setTo) + } + } + } + + fun onComplete(strings: Array<String>): List<String> { + if (strings.size <= 2) + return CommandBase.getListOfStringsMatchingLastWord( + strings, + SkyHanniMod.feature.storage.knownFeatureToggles.keys + listOf("null") + ) + return listOf() + } + + +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt new file mode 100644 index 000000000..00fc88dd4 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt @@ -0,0 +1,193 @@ +package at.hannibal2.skyhanni.features.misc.massconfiguration + +import io.github.moulberry.moulconfig.internal.GlScissorStack +import io.github.moulberry.moulconfig.internal.RenderUtils +import io.github.moulberry.moulconfig.internal.TextRenderUtils +import io.github.moulberry.notenoughupdates.util.Utils +import net.minecraft.client.gui.GuiScreen +import net.minecraft.client.gui.ScaledResolution +import net.minecraft.client.renderer.GlStateManager +import org.lwjgl.input.Mouse + +class DefaultConfigOptionGui( + val orderedOptions: Map<FeatureToggleProcessor.Category, List<FeatureToggleProcessor.FeatureToggleableOption>>, + old: String, + new: String +) : + GuiScreen() { + val title = if (old == "null") { + if (new == "null") + "§5SkyHanni Default Options" + else + "§5SkyHanni Options In Version $new" + } else { + if (new == "null") { + "§5SkyHanni Options since $old" + } else { + "§5SkyHanni Options $old → $new" + } + } + val xSize = 400 + val ySize = 300 + val barSize = 40 + val padding = 10 + var wasMouseDown = false + val cardHeight = 30 + + var currentScrollOffset = 0 + + enum class ResetSuggestionState(val label: String) { + TURN_ALL_OFF("§c§lTurn all off"), + TURN_ALL_ON("§a§lTurn all on"), + LEAVE_DEFAULTS("§b§lLeave unchanged"), ; + + val next get() = entries[(ordinal + 1) % entries.size] + } + + val resetSuggestionState = + orderedOptions.keys.associateWith { ResetSuggestionState.LEAVE_DEFAULTS }.toMutableMap() + + override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) { + super.drawScreen(mouseX, mouseY, partialTicks) + drawDefaultBackground() + RenderUtils.drawFloatingRectDark((width - xSize) / 2, (height - ySize) / 2, xSize, ySize) + val sr = ScaledResolution(mc) + var hoveringTextToDraw: List<String>? = null + var mx = mouseX - ((width - xSize) / 2) - padding + val isMouseDown = Mouse.isButtonDown(0) + val shouldClick = isMouseDown && !wasMouseDown + wasMouseDown = isMouseDown + val isMouseInScrollArea = + mx in 0..xSize && mouseY in ((height - ySize) / 2) + barSize..((height + ySize) / 2 - barSize) + var my = mouseY - ((height - ySize) / 2 + barSize) + currentScrollOffset + + GlStateManager.pushMatrix() + GlStateManager.translate(width / 2F, (height - ySize) / 2F, 0F) + GlStateManager.scale(2f, 2f, 1f) + TextRenderUtils.drawStringCenteredScaledMaxWidth( + title, + mc.fontRendererObj, + 0F, + mc.fontRendererObj.FONT_HEIGHT.toFloat(), + false, + xSize / 2 - padding, + -1 + ) + GlStateManager.popMatrix() + + GlStateManager.pushMatrix() + GlStateManager.translate( + (width - xSize) / 2F + padding, + (height + ySize) / 2F - mc.fontRendererObj.FONT_HEIGHT * 2, + 0F + ) + var i = 0 + fun bt(title: String, tooltip: List<String>, func: () -> Unit) { + val lw = mc.fontRendererObj.getStringWidth(title) + var s = false + if (mouseX - ((width - xSize) / 2 + padding) in i..(i + lw) + && mouseY - (height + ySize) / 2 in -barSize..0 + ) { + s = true + hoveringTextToDraw = tooltip + if (shouldClick) { + func() + } + } + RenderUtils.drawFloatingRectDark(i - 1, -3, lw + 4, 14) + mc.fontRendererObj.drawString(title, 2 + i.toFloat(), 0F, if (s) 0xFF00FF00.toInt() else -1, s) + i += lw + 12 + } + bt("Apply choices", listOf()) { + DefaultConfigFeatures.applyCategorySelections(resetSuggestionState, orderedOptions) + mc.displayGuiScreen(null) + } + bt("Turn all on", listOf()) { + resetSuggestionState.entries.forEach { + it.setValue(ResetSuggestionState.TURN_ALL_ON); + orderedOptions[it.key]!!.forEach { it.toggleOverride = null } + } + } + bt("Turn all off", listOf()) { + resetSuggestionState.entries.forEach { + it.setValue(ResetSuggestionState.TURN_ALL_OFF) + orderedOptions[it.key]!!.forEach { it.toggleOverride = null } + } + } + bt("Leave all untouched", listOf()) { + resetSuggestionState.entries.forEach { + it.setValue(ResetSuggestionState.LEAVE_DEFAULTS) + orderedOptions[it.key]!!.forEach { it.toggleOverride = null } + } + } + bt("Cancel", listOf()) { + mc.displayGuiScreen(null) + } + GlStateManager.popMatrix() + + GlStateManager.pushMatrix() + GlScissorStack.push( + (width - xSize) / 2, + (height - ySize) / 2 + barSize, + (width + xSize) / 2, + (height + ySize) / 2 - barSize, + sr + ) + GlStateManager.translate( + (width - xSize) / 2F + padding, + (height - ySize) / 2F + barSize - currentScrollOffset, + 0F + ) + + for ((cat) in orderedOptions.entries) { + val suggestionState = resetSuggestionState[cat]!! + drawRect(0, 0, xSize - padding * 2, 1, 0xFF808080.toInt()) + drawRect(0, 30, xSize - padding * 2, cardHeight + 1, 0xFF808080.toInt()) + drawRect(0, 0, 1, cardHeight, 0xFF808080.toInt()) + drawRect(xSize - padding * 2 - 1, 0, xSize - padding * 2, cardHeight, 0xFF808080.toInt()) + mc.fontRendererObj.drawString("§e${cat.name} ${suggestionState.label}", 4, 4, -1) + mc.fontRendererObj.drawSplitString("§7${cat.description}", 4, 14, xSize - padding * 2 - 8, -1) + if (isMouseInScrollArea && my in 0..cardHeight) { + hoveringTextToDraw = + listOf( + "§e${cat.name}", + "§7${cat.description}", + "§7Current plan: ${suggestionState.label}", + "§aClick to toggle!", + "§7Hold shift to show all options" + ) + if (isShiftKeyDown()) { + hoveringTextToDraw = listOf( + "§e${cat.name}", + "§7${cat.description}", + ) + orderedOptions[cat]!!.map { "§7 - §a" + it.name } + } + if (shouldClick) { + resetSuggestionState[cat] = suggestionState.next + orderedOptions[cat]!!.forEach { it.toggleOverride = null } + } + } + my -= cardHeight + GlStateManager.translate(0F, cardHeight.toFloat(), 0F) + } + + + GlStateManager.popMatrix() + GlScissorStack.pop(sr) + if (hoveringTextToDraw != null) { + Utils.drawHoveringText(hoveringTextToDraw, mouseX, mouseY, width, height, 100, mc.fontRendererObj) + } + + } + + fun scroll(s: Int) { + currentScrollOffset = + Math.max(0, Math.min(s, (orderedOptions.size + 1) * cardHeight - ySize + barSize + padding * 2)) + } + + override fun handleMouseInput() { + super.handleMouseInput() + if (Mouse.getEventDWheel() != 0) + scroll(currentScrollOffset - Mouse.getEventDWheel()) + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/FeatureToggleProcessor.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/FeatureToggleProcessor.kt new file mode 100644 index 000000000..c6b1beea5 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/FeatureToggleProcessor.kt @@ -0,0 +1,70 @@ +package at.hannibal2.skyhanni.features.misc.massconfiguration + +import at.hannibal2.skyhanni.config.FeatureToggle +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean +import io.github.moulberry.moulconfig.annotations.ConfigOption +import io.github.moulberry.moulconfig.processor.ConfigStructureReader +import java.lang.reflect.Field +import java.util.* + +class FeatureToggleProcessor : ConfigStructureReader { + + var latestCategory: Category? = null + val pathStack = Stack<String>() + + val allOptions = mutableListOf<FeatureToggleableOption>() + val orderedOptions by lazy { + allOptions.groupBy { it.category } + } + + data class FeatureToggleableOption( + val name: String, val description: String, val previouslyEnabled: Boolean, + val isTrueEnabled: Boolean, val category: Category, + val setter: (Boolean) -> Unit, + val path: String, + var toggleOverride: DefaultConfigOptionGui.ResetSuggestionState? = null + ) + + data class Category(val name: String, val description: String) + + override fun beginCategory(baseObject: Any?, field: Field?, name: String, description: String) { + latestCategory = Category(name, description) + } + + override fun endCategory() { + } + + override fun beginAccordion(baseObject: Any?, field: Field?, option: ConfigOption?, id: Int) { + } + + override fun endAccordion() { + } + + override fun pushPath(fieldPath: String) { + pathStack.push(fieldPath) + } + + override fun popPath() { + pathStack.pop() + } + + override fun emitOption(baseObject: Any, field: Field, option: ConfigOption) { + val featureToggle = field.getAnnotation(FeatureToggle::class.java) ?: return + field.getAnnotation(ConfigEditorBoolean::class.java) + ?: error("Feature toggle found without ConfigEditorBoolean: $field") + allOptions.add( + FeatureToggleableOption( + option.name, + option.desc, + field.getBoolean(baseObject), + featureToggle.trueIsEnabled, + latestCategory!!, + { field.setBoolean(baseObject, it) }, + pathStack.joinToString(".") + "." + field.name + ) + ) + } + + override fun emitGuiOverlay(baseObject: Any?, field: Field?, option: ConfigOption?) { + } +}
\ No newline at end of file |