diff --git a/build.gradle.kts b/build.gradle.kts index 03c4096..932b04a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,23 +7,18 @@ plugins { } group = "dev.isxander" -version = "1.0" +version = "1.1.0" repositories { mavenCentral() maven("https://repo.sk1er.club/repository/maven-public") maven("https://maven.terraformersmc.com/releases") maven("https://jitpack.io") + maven("https://maven.shedaniel.me/") } -fun DependencyHandlerScope.includeModImplementation(dependency: Any) { - include(dependency) - modImplementation(dependency) -} - -fun DependencyHandlerScope.includeImplementation(dependency: Any) { - include(dependency) - implementation(dependency) +fun DependencyHandlerScope.includeImplementation(dependency: String, action: Action = Action {}): Dependency? { + return implementation(include(dependency, action)) } dependencies { @@ -42,19 +37,27 @@ dependencies { modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricVersion") modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion+kotlin.$kotlinVersion") - includeModImplementation("gg.essential:vigilance-1.18-fabric:+") + modApi("me.shedaniel.cloth:cloth-config-fabric:6.1.+") { + exclude(group = "net.fabricmc.fabric-api") + } + includeImplementation("dev.isxander:settxi:2.1.0") modImplementation("com.terraformersmc:modmenu:3.0.+") includeImplementation("com.github.llamalad7:mixinextras:0.0.+") annotationProcessor("com.github.llamalad7:mixinextras:0.0.+") } -java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 -} - tasks { + withType { + options.release.set(17) + } + + withType { + kotlinOptions { + jvmTarget = "17" + } + } + processResources { inputs.property("version", project.version) filesMatching("fabric.mod.json") { diff --git a/src/main/kotlin/dev/isxander/zoomify/Zoomify.kt b/src/main/kotlin/dev/isxander/zoomify/Zoomify.kt index a77a1c8..295fb1a 100644 --- a/src/main/kotlin/dev/isxander/zoomify/Zoomify.kt +++ b/src/main/kotlin/dev/isxander/zoomify/Zoomify.kt @@ -6,7 +6,6 @@ import dev.isxander.zoomify.config.ZoomifySettings import dev.isxander.zoomify.utils.mc import dev.isxander.zoomify.zoom.SingleZoomHelper import dev.isxander.zoomify.zoom.TieredZoomHelper -import gg.essential.vigilance.Vigilance import net.fabricmc.api.ClientModInitializer import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper @@ -14,25 +13,31 @@ import net.minecraft.client.option.KeyBinding import net.minecraft.client.util.InputUtil object Zoomify : ClientModInitializer { + val guiKey = KeyBinding("zoomify.key.gui", InputUtil.Type.KEYSYM, InputUtil.GLFW_KEY_F8, "zoomify.key.category") + val zoomKey = KeyBinding("zoomify.key.zoom", InputUtil.Type.KEYSYM, InputUtil.GLFW_KEY_C, "zoomify.key.category") var zooming = false - private val normalZoomHelper = SingleZoomHelper({ ZoomifySettings.initialZoom.toDouble() }, { ZoomifySettings.zoomSpeed.toDouble() }, { ZoomifySettings.zoomTransition }) - private val scrollZoomHelper = TieredZoomHelper({ ZoomifySettings.scrollZoomSpeed.toDouble() }, { ZoomifySettings.scrollZoomTransition }, { 6 }, { ZoomifySettings.maxScrollZoom * 5.0 }) + private val normalZoomHelper = SingleZoomHelper({ ZoomifySettings.initialZoom.toDouble() }, { ZoomifySettings.zoomSpeed.toDouble() / 100.0 }, { ZoomifySettings.zoomTransition }) + private val scrollZoomHelper = TieredZoomHelper({ ZoomifySettings.scrollZoomSpeed.toDouble() / 100.0 }, { ZoomifySettings.scrollZoomTransition }, { 6 }, { ZoomifySettings.maxScrollZoom / 100.0 * 5.0 }) private var scrollSteps = 0 override fun onInitializeClient() { MixinExtrasBootstrap.init() - Vigilance.initialize() - ZoomifySettings.preload() + ZoomifySettings.load() KeyBindingHelper.registerKeyBinding(zoomKey) + KeyBindingHelper.registerKeyBinding(guiKey) ClientTickEvents.END_CLIENT_TICK.register { if (zoomKey.wasPressed() && ZoomifySettings.zoomKeyBehaviour == ZoomKeyBehaviour.TOGGLE) { zooming = !zooming } + + if (guiKey.wasPressed()) { + mc.setScreen(ZoomifySettings.clothGui(mc.currentScreen)) + } } } diff --git a/src/main/kotlin/dev/isxander/zoomify/config/ZoomifySettings.kt b/src/main/kotlin/dev/isxander/zoomify/config/ZoomifySettings.kt index 121f33b..34bb8a0 100644 --- a/src/main/kotlin/dev/isxander/zoomify/config/ZoomifySettings.kt +++ b/src/main/kotlin/dev/isxander/zoomify/config/ZoomifySettings.kt @@ -1,61 +1,87 @@ package dev.isxander.zoomify.config +import dev.isxander.settxi.Setting +import dev.isxander.settxi.impl.boolean +import dev.isxander.settxi.impl.int +import dev.isxander.settxi.impl.option +import dev.isxander.zoomify.utils.SettxiGuiWrapper import dev.isxander.zoomify.utils.TransitionType -import dev.isxander.zoomify.utils.formatEnum import dev.isxander.zoomify.utils.mc -import gg.essential.vigilance.Vigilant +import net.minecraft.text.TranslatableText import java.io.File -object ZoomifySettings : Vigilant(File(mc.runDirectory, "config/zoomify.toml"), "Zoomify") { - var initialZoom = 4f +object ZoomifySettings : SettxiGuiWrapper(TranslatableText("zoomify.gui.title"), File(mc.runDirectory, "config/zoomify.json")) { + override val settings = mutableListOf>() - var maxScrollZoom = 0.75f - private var _scrollZoomTransition = TransitionType.LINEAR.ordinal + var initialZoom by int(4) { + name = "zoomify.gui.initialZoom.name" + description = "zoomify.gui.initialZoom.description" + category = "zoomify.gui.category.behaviour" + range = 1..10 + } + + var maxScrollZoom by int(75) { + name = "zoomify.gui.maxScrollZoom.name" + description = "zoomify.gui.maxScrollZoom.description" + category = "zoomify.gui.category.behaviour" + range = 1..100 + } + + var _scrollZoomTransition by option(TransitionType.values().toOptionContainer { it.translationKey }.options[0]) { + name = "zoomify.gui.scrollZoomTransition.name" + description = "zoomify.gui.scrollZoomTransition.description" + category = "zoomify.gui.category.scrolling" + } var scrollZoomTransition: TransitionType - get() = TransitionType.values()[this._scrollZoomTransition] + get() = TransitionType.values()[this._scrollZoomTransition.ordinal] set(value) { - this._scrollZoomTransition = value.ordinal + this._scrollZoomTransition = _scrollZoomTransition.container.options[value.ordinal] } - var scrollZoomSpeed = 0.5f - var zoomSpeed = 0.5f - private var _zoomTransition = TransitionType.LINEAR.ordinal + var scrollZoomSpeed by int(50) { + name = "zoomify.gui.scrollZoomSpeed.name" + description = "zoomify.gui.scrollZoomSpeed.description" + category = "zoomify.gui.category.scrolling" + range = 1..100 + } + + var zoomSpeed by int(50) { + name = "zoomify.gui.zoomSpeed.name" + description = "zoomify.gui.zoomSpeed.description" + category = "zoomify.gui.category.behaviour" + range = 1..100 + } + + var _zoomTransition by option(TransitionType.values().toOptionContainer { it.translationKey }.options[0]) { + name = "zoomify.gui.zoomTransition.name" + description = "zoomify.gui.zoomTransition.description" + category = "zoomify.gui.category.behaviour" + } var zoomTransition: TransitionType - get() = TransitionType.values()[this._zoomTransition] + get() = TransitionType.values()[this._zoomTransition.ordinal] set(value) { - this._zoomTransition = value.ordinal + this._zoomTransition = _zoomTransition.container.options[value.ordinal] } - private var _zoomKeyBehaviour = ZoomKeyBehaviour.HOLD.ordinal + var _zoomKeyBehaviour by option(ZoomKeyBehaviour.values().toOptionContainer { it.translationKey }.options[0]) { + name = "zoomify.gui.zoomKeyBehaviour.name" + description = "zoomify.gui.zoomKeyBehaviour.description" + category = "zoomify.gui.category.controls" + } var zoomKeyBehaviour: ZoomKeyBehaviour - get() = ZoomKeyBehaviour.values()[this._zoomKeyBehaviour] + get() = ZoomKeyBehaviour.values()[this._zoomKeyBehaviour.ordinal] set(value) { - this._zoomKeyBehaviour = value.ordinal + this._zoomKeyBehaviour = _zoomKeyBehaviour.container.options[value.ordinal] } - var cinematicCam = false + var cinematicCam by boolean(false) { + name = "zoomify.gui.cinematicCam.name" + description = "zoomify.gui.cinematicCam.description" + category = "zoomify.gui.category.controls" + } init { - category("zoomify.gui.category.behaviour") { - decimalSlider(::initialZoom, "zoomify.gui.initialZoom.name", "zoomify.gui.initialZoom.description", min = 1f, max = 10f) - percentSlider(::zoomSpeed, "zoomify.gui.zoomSpeed.name", "zoomify.gui.zoomSpeed.description") - selector(::_zoomTransition, "zoomify.gui.zoomTransition.name", "zoomify.gui.zoomTransition.description", TransitionType.values().map { it.translationKey }) - - subcategory("zoomify.gui.subcategory.scrolling") { - percentSlider(::maxScrollZoom, "zoomify.gui.maxScrollZoom.name", "zoomify.gui.maxScrollZoom.description") - percentSlider(::scrollZoomSpeed, "zoomify.gui.scrollZoomSpeed.name", "zoomify.gui.scrollZoomSpeed.description") - selector(::_scrollZoomTransition, "zoomify.gui.scrollZoomTransition.name", "zoomify.gui.scrollZoomTransition.description", TransitionType.values().map { it.translationKey }) - } - } - - category("zoomify.gui.category.controls") { - selector(::_zoomKeyBehaviour, "zoomify.gui.zoomKeyBehaviour.name", "zoomify.gui.zoomKeyBehaviour.description", ZoomKeyBehaviour.values().map { it.translationKey }) - switch(::cinematicCam, "zoomify.gui.cinematicCam.name", "zoomify.gui.cinematicCam.description") - } - - initialize() - - hidePropertyIf(::zoomSpeed) { zoomTransition == TransitionType.INSTANT } + load() } } diff --git a/src/main/kotlin/dev/isxander/zoomify/integrations/ModMenuIntegration.kt b/src/main/kotlin/dev/isxander/zoomify/integrations/ModMenuIntegration.kt index f95920c..2a6d8de 100644 --- a/src/main/kotlin/dev/isxander/zoomify/integrations/ModMenuIntegration.kt +++ b/src/main/kotlin/dev/isxander/zoomify/integrations/ModMenuIntegration.kt @@ -6,6 +6,6 @@ import dev.isxander.zoomify.config.ZoomifySettings object ModMenuIntegration : ModMenuApi { override fun getModConfigScreenFactory(): ConfigScreenFactory<*> = ConfigScreenFactory { parent -> - ZoomifySettings.gui() ?: parent + ZoomifySettings.clothGui(parent) } } diff --git a/src/main/kotlin/dev/isxander/zoomify/utils/SettxiGuiWrapper.kt b/src/main/kotlin/dev/isxander/zoomify/utils/SettxiGuiWrapper.kt new file mode 100644 index 0000000..e6de8d3 --- /dev/null +++ b/src/main/kotlin/dev/isxander/zoomify/utils/SettxiGuiWrapper.kt @@ -0,0 +1,117 @@ +package dev.isxander.zoomify.utils + +import dev.isxander.settxi.Setting +import dev.isxander.settxi.impl.* +import dev.isxander.settxi.serialization.ConfigProcessor +import dev.isxander.settxi.serialization.asJson +import dev.isxander.settxi.serialization.populateFromJson +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import me.shedaniel.clothconfig2.api.ConfigBuilder +import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder +import net.minecraft.client.gui.screen.Screen +import net.minecraft.text.Text +import net.minecraft.text.TranslatableText +import java.io.File +import java.util.function.Supplier + +abstract class SettxiGuiWrapper(val title: Text, val file: File) : ConfigProcessor { + override val settings = mutableListOf>() + + fun load() { + if (!file.exists()) { + save() + return + } + + settings.populateFromJson(Json.decodeFromString(file.readText())) + } + + fun save() { + file.writeText(Json.encodeToString(settings.asJson())) + } + + fun clothGui(parent: Screen? = null): Screen = + ConfigBuilder.create().apply { + parentScreen = parent + this.title = this@SettxiGuiWrapper.title + + for (setting in settings) { + val category = getOrCreateCategory(TranslatableText(setting.category)) + category.addEntry(clothEntry(setting)) + } + + setSavingRunnable { save() } + }.build() + + private fun ConfigBuilder.clothEntry(setting: Setting<*>) = + when (setting) { + is BooleanSetting -> + entryBuilder().startBooleanToggle(TranslatableText(setting.name), setting.get()).apply { + defaultValue = Supplier { setting.default } + setTooltip(TranslatableText(setting.description)) + setSaveConsumer { setting.set(it) } + } + is DoubleSetting -> + entryBuilder().startDoubleField(TranslatableText(setting.name), setting.get()).apply { + defaultValue = Supplier { setting.default } + setTooltip(TranslatableText(setting.description)) + setSaveConsumer { setting.set(it) } + setMin(setting.range.start) + setMax(setting.range.endInclusive) + } + is FloatSetting -> + entryBuilder().startFloatField(TranslatableText(setting.name), setting.get()).apply { + defaultValue = Supplier { setting.default } + setTooltip(TranslatableText(setting.description)) + setSaveConsumer { setting.set(it) } + setMin(setting.range.start) + setMax(setting.range.endInclusive) + } + is LongSetting -> + entryBuilder().startLongSlider(TranslatableText(setting.name), setting.get(), setting.range.first, setting.range.last).apply { + defaultValue = Supplier { setting.default } + setTooltip(TranslatableText(setting.description)) + setSaveConsumer { setting.set(it) } + } + is IntSetting -> + entryBuilder().startIntSlider(TranslatableText(setting.name), setting.get(), setting.range.first, setting.range.last).apply { + defaultValue = Supplier { setting.default } + setTooltip(TranslatableText(setting.description)) + setSaveConsumer { setting.set(it) } + } + is StringSetting -> + entryBuilder().startStrField(TranslatableText(setting.name), setting.get()).apply { + defaultValue = Supplier { setting.default } + setTooltip(TranslatableText(setting.description)) + setSaveConsumer { setting.set(it) } + } + is OptionSetting -> + entryBuilder().startStringDropdownMenu(TranslatableText(setting.name), setting.get().name) { TranslatableText(it) }.apply { + defaultValue = Supplier { setting.default.name } + setTooltip(TranslatableText(setting.description)) + isSuggestionMode = false + setSelections(setting.options.map { TranslatableText(it.name).string }) + setSaveConsumer { setting.set(setting.options.first { option -> + TranslatableText(option.name).string == it + })} + } + is FileSetting -> + throw UnsupportedOperationException("Cloth config does not support file settings") + + else -> throw IllegalArgumentException("Unknown setting type: ${setting.javaClass}") + }.build() + + protected fun Array.toOptionContainer(nameProvider: (T) -> String): OptionContainer { + return object : OptionContainer() { + init { + for (value in this@toOptionContainer) { + option(nameProvider(value)) + } + } + } + } +} + + diff --git a/src/main/kotlin/dev/isxander/zoomify/zoom/SingleZoomHelper.kt b/src/main/kotlin/dev/isxander/zoomify/zoom/SingleZoomHelper.kt index 01d9e63..e96ab3c 100644 --- a/src/main/kotlin/dev/isxander/zoomify/zoom/SingleZoomHelper.kt +++ b/src/main/kotlin/dev/isxander/zoomify/zoom/SingleZoomHelper.kt @@ -8,7 +8,6 @@ open class SingleZoomHelper(private val _initialZoom: () -> Double, zoomSpeed: ( get() = _initialZoom() private var prevZoomDivisor = 0.0 - private var ticks = 0.0 override fun getZoomDivisor(params: SingleZoomParams): Double { val zooming = params.zooming @@ -22,11 +21,10 @@ open class SingleZoomHelper(private val _initialZoom: () -> Double, zoomSpeed: ( prevZoomDivisor += zoomSpeed / 20 * tickDelta prevZoomDivisor = prevZoomDivisor.coerceAtMost(targetZoom) } else if (targetZoom < prevZoomDivisor) { - prevZoomDivisor -= tickDelta * (zoomSpeed / 20) + prevZoomDivisor -= zoomSpeed / 20 * tickDelta prevZoomDivisor = prevZoomDivisor.coerceAtLeast(targetZoom) } - ticks++ return lerp(1.0, initialZoom, transition.takeUnless { it == TransitionType.INSTANT }?.apply(prevZoomDivisor) ?: prevZoomDivisor) } diff --git a/src/main/resources/assets/zoomify/lang/en_us.json b/src/main/resources/assets/zoomify/lang/en_us.json index 805ebdb..d1ca88c 100644 --- a/src/main/resources/assets/zoomify/lang/en_us.json +++ b/src/main/resources/assets/zoomify/lang/en_us.json @@ -1,7 +1,11 @@ { - "zoomify.key.zoom": "Zooom", + "zoomify.key.zoom": "Zoom", + "zoomify.key.gui": "Open GUI", "zoomify.key.category": "Zoomify", + + "zoomify.gui.title": "Zoomify", + "zoomify.gui.category.behaviour": "Behaviour", "zoomify.gui.initialZoom.name": "Initial Zoom", "zoomify.gui.initialZoom.description": "The zoom level when you first zoomify.", @@ -9,19 +13,22 @@ "zoomify.gui.zoomSpeed.description": "Speed at which the zoom animation will occur.", "zoomify.gui.zoomTransition.name": "Zoom Transition", "zoomify.gui.zoomTransition.description": "The transition type used when zooming.", - "zoomify.gui.subcategory.scrolling": "Scrolling", + + "zoomify.gui.category.scrolling": "Scrolling", "zoomify.gui.maxScrollZoom.name": "Max Scroll Zoom", "zoomify.gui.maxScrollZoom.description": "The maximum zoom level that can be achieved when scrolling.", "zoomify.gui.scrollZoomSpeed.name": "Scroll Zoom Speed", "zoomify.gui.scrollZoomSpeed.description": "Speed at which the scroll zoom animation will occur.", "zoomify.gui.scrollZoomTransition.name": "Scroll Zoom Transition", "zoomify.gui.scrollZoomTransition.description": "The transition type used when scrolling to zoom.", + "zoomify.gui.category.controls": "Controls", "zoomify.gui.zoomKeyBehaviour.name": "Zoom Key Behaviour", "zoomify.gui.zoomKeyBehaviour.description": "The behaviour of the zoom key.", "zoomify.gui.cinematicCam.name": "Cinematic Camera", "zoomify.gui.cinematicCam.description": "Make the camera move smoothly when zoomed.", + "zoomify.transition.instant": "Instant", "zoomify.transition.linear": "Linear", "zoomify.transition.ease_in_sine": "Ease In Sine", @@ -34,6 +41,7 @@ "zoomify.transition.ease_out_cubic": "Ease Out Cubic", "zoomify.transition.ease_in_out_cubic": "Ease In Out Cubic", + "zoomify.zoom_key_behaviour.hold": "Hold", "zoomify.zoom_key_behaviour.toggle": "Toggle" } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index c9b5a7e..9b0071b 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -38,6 +38,9 @@ "fabric-language-kotlin": ">=1.7.1+kotlin.1.6.10", "minecraft": "1.18.x", "java": ">=17", + "cloth-config": "6.x.x" + }, + "suggests": { "modmenu": ">=3.0.0" } }