Compare commits

..

6 Commits

Author SHA1 Message Date
0afa43168d
Bump version to 0.3.7
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-24 18:27:23 +02:00
c0f008c187
Fix bb90bad1 on 1.20
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-24 18:26:23 +02:00
fcba61b050
Put the right minecraft version in fabric.mod.json
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-25 23:43:08 +02:00
c8ac0629c3
Bump version to 0.3.6
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 20:46:46 +02:00
bc14627b97
Fix my stupid configuration system
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 20:46:24 +02:00
bb90bad1d1
Fix the mod on neoforge 1.21.5 by notably using the mod loader configuration directories
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 20:46:17 +02:00
52 changed files with 369 additions and 612 deletions

View File

@ -1,27 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="SnowyGUI [build]" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-PdevBuild=true" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<ExternalSystemDebugDisabled>false</ExternalSystemDebugDisabled>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<GradleProfilingDisabled>false</GradleProfilingDisabled>
<GradleCoverageDisabled>false</GradleCoverageDisabled>
<method v="2" />
</configuration>
</component>

View File

@ -1,27 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="SnowyGUI [build-release]" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-PdevBuild=false" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="build" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<ExternalSystemDebugDisabled>false</ExternalSystemDebugDisabled>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<GradleProfilingDisabled>false</GradleProfilingDisabled>
<GradleCoverageDisabled>false</GradleCoverageDisabled>
<method v="2" />
</configuration>
</component>

View File

@ -1,25 +1,23 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.modrinth.minotaur.ModrinthExtension import com.modrinth.minotaur.ModrinthExtension
import com.modrinth.minotaur.dependencies.DependencyType
import masecla.modrinth4j.model.version.ProjectVersion.VersionType import masecla.modrinth4j.model.version.ProjectVersion.VersionType
import com.modrinth.minotaur.dependencies.DependencyType
import net.fabricmc.loom.LoomGradleExtension import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript { buildscript {
dependencies { dependencies {
classpath("com.guardsquare:proguard-gradle:[7.8, 7.9[") { classpath("com.guardsquare:proguard-gradle:[7.4, 7.5[") {
exclude("com.android.tools.build") exclude("com.android.tools.build")
} }
} }
} }
plugins { plugins {
kotlin("jvm") version "2.3.0" kotlin("jvm") version "1.9.24"
kotlin("plugin.serialization") version "2.3.0" kotlin("plugin.serialization") version "1.9.24"
id("com.github.johnrengelman.shadow") version "8.1.1" apply false id("com.github.johnrengelman.shadow") version "8.1.1" apply false
id("architectury-plugin") version "[3.4.160, 3.5[" id("architectury-plugin") version "[3.4.124, 3.5["
id("dev.architectury.loom") version "[1.13.464, 1.14[" apply false id("dev.architectury.loom") version "1.5-SNAPSHOT" apply false
id("com.github.ben-manes.versions") version "0.51.0" id("com.github.ben-manes.versions") version "0.51.0"
id("net.kyori.indra.git") version "3.1.3" id("net.kyori.indra.git") version "3.1.3"
id("org.cqfn.diktat.diktat-gradle-plugin") version "1.2.5" id("org.cqfn.diktat.diktat-gradle-plugin") version "1.2.5"
@ -27,10 +25,10 @@ plugins {
} }
group = "fr.username404" group = "fr.username404"
version = "0.4.2" version = "0.3.7"
val groupAndName = "${rootProject.group}.${rootProject.name.lowercase()}" val groupAndName = "${rootProject.group}.${rootProject.name.toLowerCase()}"
val javaVer: String = "21" val javaVer: String = "17"
val sourceJavaVer: String = javaVer val sourceJavaVer: String = javaVer
val kotlinVer: String by rootProject val kotlinVer: String by rootProject
val kotlinSplitVersion = kotlinVer.split('.') val kotlinSplitVersion = kotlinVer.split('.')
@ -39,7 +37,6 @@ val minecraftVersion: String = (rootProject.property("minecraft") as String).als
architectury { minecraft = it } architectury { minecraft = it }
} }
val kotlinX: String = "org.jetbrains.kotlinx" val kotlinX: String = "org.jetbrains.kotlinx"
val devBuild = rootProject.hasProperty("devBuild") && rootProject.property("devBuild").toString().toBoolean()
subprojects { subprojects {
group = rootProject.group.toString() group = rootProject.group.toString()
@ -53,12 +50,18 @@ subprojects {
apply(plugin = "dev.architectury.loom") apply(plugin = "dev.architectury.loom")
apply(plugin = "org.jetbrains.kotlin.plugin.serialization") apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
extensions.configure<LoomGradleExtension>("loom") { extensions.configure<LoomGradleExtension>("loom") {
if (this@subprojects.project.name != "common") {
accessWidenerPath.set(project(":common").extensions.getByType<LoomGradleExtensionAPI>().accessWidenerPath)
}
mappingsDep = layered { mappingsDep = layered {
officialMojangMappings().parchment("org.parchmentmc.data:parchment-1.20.1:2023.06.26")
}
silentMojangMappingsLicense() silentMojangMappingsLicense()
officialMojangMappings().parchment("org.parchmentmc.data:parchment-1.21.11:2025.12.20") val refmap = "snowygui-${project.name}-refmap.json"
mixin {
defaultRefmapName.set(refmap)
if (isForge) {
forge {
mixinConfigs("snowygui-common.mixins.json", "snowygui-forge.mixins.json")
}
}
} }
} }
apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "com.github.johnrengelman.shadow")
@ -164,16 +167,12 @@ subprojects {
mergeinterfacesaggressively() mergeinterfacesaggressively()
} }
withType(net.fabricmc.loom.task.RemapJarTask::class) { withType(net.fabricmc.loom.task.RemapJarTask::class) {
if (!devBuild) {
dependsOn(shrinkJar) dependsOn(shrinkJar)
val shrinkedJar = shrinkJar.get().outJarFileCollection.singleFile val shrinkedJar = shrinkJar.get().outJarFileCollection.singleFile
inputFile.set(shrinkedJar)
} else inputFile.set(shadowJar.archiveFile)
archiveBaseName.set(shadowJar.archiveBaseName) archiveBaseName.set(shadowJar.archiveBaseName)
archiveVersion.set("[${rootProject.version}+$minecraftVersion]") archiveVersion.set("[${rootProject.version}+$minecraftVersion]")
archiveClassifier.set(this@subprojects.name) archiveClassifier.set(this@subprojects.name)
if (this@subprojects.name.contains("forge")) inputFile.set(shrinkedJar)
atAccessWideners.set(listOf("${rootProject.name.lowercase()}.accessWidener"))
if (!archiveFileName.get().contains("common")) destinationDirectory.set(file("$rootDir/remappedJars")) if (!archiveFileName.get().contains("common")) destinationDirectory.set(file("$rootDir/remappedJars"))
} }
getByName("modrinth").dependsOn(build) getByName("modrinth").dependsOn(build)
@ -200,18 +199,18 @@ allprojects {
} }
tasks { tasks {
withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) {
compilerOptions { with(kotlinOptions) {
// https://github.com/JetBrains/kotlin/blob/master/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt // https://github.com/JetBrains/kotlin/blob/master/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt
freeCompilerArgs = listOf( freeCompilerArgs = listOf(
"-Xjvm-default=all", "-Xlambdas=indy", "-Xtype-enhancement-improvements-strict-mode", "-Xjvm-default=all", "-Xlambdas=indy", "-Xtype-enhancement-improvements-strict-mode",
"-Xmultifile-parts-inherit", "-Xmultifile-parts-inherit",
"-Xbackend-threads=0", "-Xno-param-assertions", "-Xno-call-assertions", "-Xbackend-threads=0", "-Xno-param-assertions", "-Xno-call-assertions",
"-opt-in=kotlin.RequiresOptIn", "-Xassertions=jvm", "-progressive" "-opt-in=kotlin.RequiresOptIn", "-Xextended-compiler-checks", "-Xassertions=jvm", "-progressive"
) )
//languageVersion = (kotlinSplitVersion[0] + '.' + (kotlinSplitVersion[1].toShort() + 1).toString()) jvmTarget = javaVer
//apiVersion = "${kotlinSplitVersion[0]}.${kotlinSplitVersion[1]}" languageVersion = (kotlinSplitVersion[0] + '.' + (kotlinSplitVersion[1].toShort() + 1).toString())
apiVersion = "${kotlinSplitVersion[0]}.${kotlinSplitVersion[1]}"
} }
compilerOptions.jvmTarget.set(JvmTarget.fromTarget(javaVer))
} }
withType(JavaCompile::class) { withType(JavaCompile::class) {
with(options) { with(options) {
@ -237,10 +236,10 @@ allprojects {
"kotlinforforge" to rootProject.property("kotlinforforge"), "kotlinforforge" to rootProject.property("kotlinforforge"),
"clothconfig" to rootProject.property("clothconfig_version"), "clothconfig" to rootProject.property("clothconfig_version"),
"fabric_loader" to rootProject.property("fabric_loader_version"), "fabric_loader" to rootProject.property("fabric_loader_version"),
"forge_version" to rootProject.property("forge_version") "forge_version" to rootProject.property("forge_version").toString().dropLast(2)
) )
inputs.properties(modProperties) inputs.properties(modProperties)
filesNotMatching(listOf("*.png", "*.accessWidener")) { filesNotMatching(listOf("*.png")) {
expand(modProperties) expand(modProperties)
} }
} }

View File

@ -1,4 +1,4 @@
architectury { common("fabric", "neoforge"); injectInjectables = true } architectury { common("fabric", "forge"); injectInjectables = true }
dependencies { dependencies {
modImplementation("net.fabricmc:fabric-loader:${rootProject.property("fabric_loader_version")}") modImplementation("net.fabricmc:fabric-loader:${rootProject.property("fabric_loader_version")}")
modImplementation("me.shedaniel.cloth:cloth-config:${rootProject.property("clothconfig_version")}") { modImplementation("me.shedaniel.cloth:cloth-config:${rootProject.property("clothconfig_version")}") {
@ -6,8 +6,4 @@ dependencies {
} }
} }
loom {
accessWidenerPath = file("src/main/resources/${rootProject.name.lowercase()}.accessWidener")
}
tasks.getByName("shrinkJar").enabled = false tasks.getByName("shrinkJar").enabled = false

View File

@ -1,23 +0,0 @@
package fr.username404.snowygui.mixins;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import fr.username404.snowygui.gui.feature.GammaBoost;
import net.minecraft.client.renderer.LightTexture;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(LightTexture.class)
abstract class GammaMixin {
@ModifyExpressionValue(
method = "updateLightTexture(F)V", at = @At(
value = "INVOKE",
target = "Ljava/lang/Double;floatValue()F",
ordinal = 1
)
)
public float highGamma(float original) {
if (GammaBoost.INSTANCE.getToggled())
return GammaBoost.BOOST;
return original;
}
}

View File

@ -25,11 +25,14 @@ abstract class KeyMappings {
@Inject(method = "<init>*", at = @At("RETURN")) @Inject(method = "<init>*", at = @At("RETURN"))
private void onSettingsConstructed(Minecraft minecraft, File file, CallbackInfo ci) { private void onSettingsConstructed(Minecraft minecraft, File file, CallbackInfo ci) {
final var categoryList = KeysAccessor.getSortedCategoryList(); final var categoryMap = KeysAccessor.getSortedCategoryMap();
var newKeys = Lists.newArrayList(keyMappings); var newKeys = Lists.newArrayList(keyMappings);
for (KeyMapping key : keysToAdd) { for (KeyMapping key : keysToAdd) {
if (!categoryList.contains(key.getCategory())) if (!categoryMap.containsKey(key.getCategory())) {
categoryList.add(key.getCategory()); Optional<Integer> biggest = categoryMap.values().stream().max(Integer::compareTo);
int biggestInt = biggest.orElse(0);
categoryMap.put(key.getCategory(), biggestInt + 1);
}
newKeys.remove(key); newKeys.remove(key);
newKeys.add(key); newKeys.add(key);
} }

View File

@ -4,10 +4,10 @@ import net.minecraft.client.KeyMapping;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List; import java.util.Map;
@Mixin(KeyMapping.Category.class) @Mixin(KeyMapping.class)
public interface KeysAccessor { public interface KeysAccessor {
@Accessor("SORT_ORDER") @Accessor("CATEGORY_SORT_ORDER")
static List<KeyMapping.Category> getSortedCategoryList() { throw new AssertionError(); } static Map<String, Integer> getSortedCategoryMap() { throw new AssertionError(); }
} }

View File

@ -0,0 +1,11 @@
package fr.username404.snowygui.mixins;
import net.minecraft.client.OptionInstance;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(OptionInstance.class)
public interface OptionValueAccessor {
@Accessor("value")
void setValue(Object value);
}

View File

@ -4,17 +4,16 @@ import fr.username404.snowygui.ClickGui;
import fr.username404.snowygui.gui.feature.ButtonImpl; import fr.username404.snowygui.gui.feature.ButtonImpl;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class) @Mixin(TitleScreen.class)
abstract class TitleScreenMixin { abstract class TitleScreenMixin {
@Unique private static boolean buttonsInitialized = false; private static boolean buttonsInitialized = false;
@Unique private static synchronized void setButtonsInitialized() { buttonsInitialized = true; } private static synchronized void setButtonsInitialized() { buttonsInitialized = true; }
@Inject(method = "createNormalMenuOptions", at = @At(value = "RETURN")) @Inject(method = "createNormalMenuOptions", at = @At(value = "RETURN"))
public void createNormalMenuOptions(int i, int j, CallbackInfoReturnable<Integer> cir) { public void createNormalMenuOptions(int i, int j, CallbackInfo ci) {
if (!buttonsInitialized) { if (!buttonsInitialized) {
ClickGui.INSTANCE.tick(); ClickGui.INSTANCE.tick();
ButtonImpl.initButtons(); ButtonImpl.initButtons();

View File

@ -4,9 +4,7 @@ import fr.username404.snowygui.gui.ColoredElement
import fr.username404.snowygui.gui.Element import fr.username404.snowygui.gui.Element
import fr.username404.snowygui.gui.SnowyScreen import fr.username404.snowygui.gui.SnowyScreen
import fr.username404.snowygui.gui.elements.ClickBox import fr.username404.snowygui.gui.elements.ClickBox
import net.minecraft.client.input.MouseButtonEvent
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
import kotlin.math.roundToInt
object ClickGui: SnowyScreen() { object ClickGui: SnowyScreen() {
override val components = mutableSetOf<Element>() override val components = mutableSetOf<Element>()
@ -19,32 +17,28 @@ object ClickGui: SnowyScreen() {
private var draggingBox: String? = null private var draggingBox: String? = null
private inline fun currentBoxContext(args: ClickBox.() -> Unit): Unit? = draggingBox?.run { boxContext { if (name.string == draggingBox) args() } } private inline fun currentBoxContext(args: ClickBox.() -> Unit): Unit? = draggingBox?.run { boxContext { if (name.string == draggingBox) args() } }
private var offsetX: Double = 0.0 private var offsetX: Double = 0.0;
private var offsetY: Double = 0.0 private var offsetY: Double = 0.0;
override fun mouseClicked(event: MouseButtonEvent, isDoubleClick: Boolean): Boolean { override fun mouseClicked(d: Double, e: Double, i: Int): Boolean {
if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (i == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
clickBoxes.find { it.isWithinBounds(event.x, event.y) }?.let { draggingBox = it.name.string } clickBoxes.find { it.isWithinBounds(d, e) }?.let { draggingBox = it.name.string }
currentBoxContext { currentBoxContext {
offsetX = event.x - (x + width) offsetX = d - (x + width)
offsetY = event.y - (y + height) offsetY = e - (y + height)
} }
} }
buttonsContext { this.mouseClicked(event, isDoubleClick) }; return super.mouseClicked(event, isDoubleClick); buttonsContext { this.mouseClicked(d, e, i) }; return super.mouseClicked(d, e, i);
} }
override fun mouseReleased(event: MouseButtonEvent): Boolean { draggingBox = null; buttonsContext { this.mouseReleased(event) }; return false } override fun mouseReleased(d: Double, e: Double, i: Int): Boolean { draggingBox = null; buttonsContext { this.mouseReleased(d, e, i) }; return false }
override fun mouseScrolled(d: Double, e: Double, f: Double, scrollY: Double): Boolean { boxContext { scroll(d, e, scrollY) }; return false } override fun mouseScrolled(d: Double, e: Double, f: Double): Boolean { boxContext { scroll(d, e, f) }; return false }
override fun mouseDragged(event: MouseButtonEvent, mouseX: Double, mouseY: Double): Boolean { override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (i == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
currentBoxContext { currentBoxContext {
val targetX = (event.x + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble()) x = (d + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble())
val targetY = (event.y + offsetY).coerceIn(0.0..this@ClickGui.height - height.toDouble()) y = (e + offsetY).coerceIn(0.0..this@ClickGui.height - height.toDouble())
// Snap to integer pixels => stable spacing
x = targetX.roundToInt().toDouble()
y = targetY.roundToInt().toDouble()
} }
} }
return super.mouseDragged(event, mouseX, mouseY) return super.mouseDragged(d, e, i, f, g)
} }
} }

View File

@ -1,7 +1,8 @@
package fr.username404.snowygui package fr.username404.snowygui
import fr.username404.snowygui.config.LazyConfiguration import fr.username404.snowygui.config.Configuration
import fr.username404.snowygui.gui.feature.ButtonImpl import fr.username404.snowygui.gui.feature.ButtonImpl
import fr.username404.snowygui.gui.feature.ButtonImpl.Companion.initButtons
import fr.username404.snowygui.gui.feature.ButtonInfo import fr.username404.snowygui.gui.feature.ButtonInfo
import fr.username404.snowygui.misc.AddKeyMaps import fr.username404.snowygui.misc.AddKeyMaps
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -13,30 +14,30 @@ import java.lang.reflect.Modifier
abstract class Snowy { abstract class Snowy {
protected fun Class<*>.isValidForButtonCollection(): Boolean = protected fun Class<*>.isValidForButtonCollection(): Boolean =
!Modifier.isAbstract(modifiers) && declaredAnnotations.any { it is ButtonInfo && !it.ignored } !Modifier.isAbstract(modifiers) && declaredAnnotations.any { it is ButtonInfo && !it.ignored }
private val displayInitMessage: Lazy<Boolean> by LazyConfiguration private val displayInitMessage: Boolean by Configuration
abstract val annotatedButtons: Lazy<Set<Class<out ButtonImpl>>> abstract val annotatedButtons: Set<Class<out ButtonImpl>>
companion object { companion object {
val MissingComponent: Component = translatable("MISSING_COMPONENT") val MissingComponent: Component = translatable("MISSING_COMPONENT")
@Suppress("JVM_STATIC_ON_CONST_OR_JVM_FIELD") // See KT-39868 @Suppress("JVM_STATIC_ON_CONST_OR_JVM_FIELD") // See KT-39868
@JvmStatic @JvmStatic
protected const val FEATURE_PACKAGE: String = "fr.username404.snowygui.gui.feature" protected const val FeaturePackage: String = "fr.username404.snowygui.gui.feature"
lateinit var annotatedButtons: () -> Set<Class<out ButtonImpl>> lateinit var annotatedButtons: () -> Set<Class<out ButtonImpl>>
fun onEvent(e: Any, lambda: argsLambda) = EventSnowy[e.toString()].add(lambda) fun onEvent(e: Any, lambda: argsLambda) = EventSnowy[e.toString()].add(lambda)
@JvmField @JvmField
val logs: Logger = LogManager.getLogger() val logs: Logger = LogManager.getLogger()
} }
init { Companion.annotatedButtons = { annotatedButtons.value } } init { Companion.annotatedButtons = ::annotatedButtons::get }
private fun eventsInit() { private fun eventsInit() {
onEvent("EndTick") { onEvent("EndTick") {
for (key in AddKeyMaps.list.keys) { for (Key in AddKeyMaps.list.keys) {
if (key.isDown) { if (Key.isDown) {
AddKeyMaps.list[key]?.invoke() AddKeyMaps.list[Key]?.invoke()
} }
} }
} }
} }
fun atInit() { fun atInit() {
if (displayInitMessage.value) logs.info("Init point of SnowyGUI hit.") if (displayInitMessage) logs.info("Init point of SnowyGUI hit.")
eventsInit() eventsInit()
} }
} }

View File

@ -2,10 +2,14 @@ package fr.username404.snowygui.config
import fr.username404.snowygui.ClickGui import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.gui.elements.ClickBox import fr.username404.snowygui.gui.elements.ClickBox
import fr.username404.snowygui.gui.elements.ClickBox.Companion.buttonsMax
import fr.username404.snowygui.gui.elements.ClickBox.Companion.sortAlphabetically import fr.username404.snowygui.gui.elements.ClickBox.Companion.sortAlphabetically
import fr.username404.snowygui.gui.feature.* import fr.username404.snowygui.gui.feature.Category
import fr.username404.snowygui.gui.feature.Colors
import fr.username404.snowygui.gui.feature.Macro
import fr.username404.snowygui.gui.feature.Keystrokes
import fr.username404.snowygui.gui.feature.Zoom
import fr.username404.snowygui.utils.FontUtil import fr.username404.snowygui.utils.FontUtil
import me.shedaniel.clothconfig2.gui.entries.StringListListEntry
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -23,8 +27,8 @@ private fun supplyComponent(string: String?): Optional<Component> = string?.run
val SnowyConfigScreen: Screen = object: Screen(translationComponent) { val SnowyConfigScreen: Screen = object: Screen(translationComponent) {
override fun isPauseScreen(): Boolean = false override fun isPauseScreen(): Boolean = false
override fun render(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, pTick: Float) { override fun render(guiGraphics: GuiGraphics, i: Int, j: Int, f: Float) {
super.renderBackground(guiGraphics, mouseX, mouseY, pTick) super.renderBackground(guiGraphics)
FontUtil.drawScaled(guiGraphics, FontUtil.drawScaled(guiGraphics,
text = "An appropriate version of the Cloth Config mod is required for the configuration of snowygui.", 16.0, 16.0, text = "An appropriate version of the Cloth Config mod is required for the configuration of snowygui.", 16.0, 16.0,
color = Colors.WHITE, scaleFactor = 0.85F color = Colors.WHITE, scaleFactor = 0.85F
@ -49,9 +53,9 @@ val SnowyConfigScreen: Screen = object: Screen(translationComponent) {
startBooleanToggle(translatable("$confPrefix.behavior.sortalphabetically"), sortAlphabetically) startBooleanToggle(translatable("$confPrefix.behavior.sortalphabetically"), sortAlphabetically)
.setDefaultValue(true).requireRestart() .setDefaultValue(true).requireRestart()
.setSaveConsumer { sortAlphabetically = it }.build(), .setSaveConsumer { sortAlphabetically = it }.build(),
startFloatField(translatable("$confPrefix.behavior.zoom.factor"), Zoom.zoomFactor).setSaveConsumer { startDoubleField(translatable("$confPrefix.behavior.zoom.factor"), Zoom.zoomFactor).setSaveConsumer {
Zoom.zoomFactor = it Zoom.zoomFactor = it
}.setMin(1.1F).build(), }.setMin(1.1).build(),
startBooleanToggle(translatable("$confPrefix.behavior.zoom.smoothcamera"), Zoom.smoothCameraOnZoom).setSaveConsumer { startBooleanToggle(translatable("$confPrefix.behavior.zoom.smoothcamera"), Zoom.smoothCameraOnZoom).setSaveConsumer {
Zoom.smoothCameraOnZoom = it Zoom.smoothCameraOnZoom = it
Zoom.execAction() Zoom.execAction()
@ -75,9 +79,9 @@ val SnowyConfigScreen: Screen = object: Screen(translationComponent) {
}.build()).addEntry(startStrList( }.build()).addEntry(startStrList(
Category.MACROS.box.name, Category.MACROS.box.name,
macrosButtons.getTitleCommand() macrosButtons.getTitleCommand()
).setCreateNewInstance { ).setInsertInFront(false).setDefaultValue(Configuration.foundMacros.getTitleCommand()).setErrorSupplier { list ->
entry -> StringListListEntry.StringListCell("ExampleMacro: say hello", entry) supplyComponent(if (list.size > buttonsMax) "$confPrefix.general.macros.toomuchbuttons" else null)
}.setInsertInFront(false).setDefaultValue(Configuration.foundMacros.getTitleCommand()).setCellErrorSupplier { cell -> }.setCellErrorSupplier { cell ->
with(cell.split(":")) { with(cell.split(":")) {
supplyComponent( supplyComponent(
when { when {

View File

@ -21,6 +21,7 @@ import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import net.minecraft.network.chat.contents.TranslatableContents import net.minecraft.network.chat.contents.TranslatableContents
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
@ -55,7 +56,7 @@ object Configuration {
getMethod("getConfigDir").invoke(getMethod("getInstance").invoke(null)) getMethod("getConfigDir").invoke(getMethod("getInstance").invoke(null))
} }
} else { } else {
Class.forName("net.neoforged.fml.loading.FMLPaths") Class.forName("net.minecraftforge.fml.loading.FMLPaths")
.getField("CONFIGDIR") .getField("CONFIGDIR")
.get(null) .get(null)
.let { enum -> .let { enum ->
@ -175,9 +176,3 @@ object Configuration {
operator fun <T> setValue(ref: Any?, property: KProperty<*>, value: T) = @Suppress("DEPRECATION_ERROR") operator fun <T> setValue(ref: Any?, property: KProperty<*>, value: T) = @Suppress("DEPRECATION_ERROR")
ModifiableValues.setValue(ref, property, value) ModifiableValues.setValue(ref, property, value)
} }
object LazyConfiguration {
inline operator fun <reified T: Any> getValue(ref: Any?, property: KProperty<*>): Lazy<T> = lazy {
Configuration.getValue<T>(ref, property);
}
}

View File

@ -1,9 +1,10 @@
package fr.username404.snowygui.gui package fr.username404.snowygui.gui
import com.mojang.blaze3d.vertex.VertexConsumer import com.mojang.blaze3d.vertex.*
import fr.username404.snowygui.Snowy import fr.username404.snowygui.Snowy
import fr.username404.snowygui.gui.feature.Colors import fr.username404.snowygui.gui.feature.Colors
import fr.username404.snowygui.utils.RenderingUtil import fr.username404.snowygui.utils.RenderingUtil
import fr.username404.snowygui.utils.RenderingUtil.colorEnd
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.events.GuiEventListener import net.minecraft.client.gui.components.events.GuiEventListener
@ -54,16 +55,12 @@ abstract class ColoredElement(
companion object { companion object {
@JvmStatic protected fun VertexConsumer.colorIt(color: Int, opacity: Float = 1F): VertexConsumer { @JvmStatic protected fun VertexConsumer.colorIt(color: Int, opacity: Float = 1F): VertexConsumer {
with(hextoRGB(color)) { with(hextoRGB(color)) {
return this@colorIt.setColor(get(0), get(1), get(2), opacity) return this@colorIt.color(get(0), get(1), get(2), opacity)
} }
} }
} }
internal fun VertexConsumer.colorEnd(color: Int = this@ColoredElement.color) = colorEnd(color, opacity)
internal fun VertexConsumer.colorEnd(color: Int = this@ColoredElement.color) = colorIt(color, opacity) protected fun defaultRectFunc() = RenderingUtil.drawRectangle(x, y, height, width, color, opacity)
protected fun defaultRectFunc(guiGraphics: GuiGraphics?) = guiGraphics?.let {
RenderingUtil.drawRectangle(it, x, y, height, width, color, opacity)
}
} }
fun hextoRGB(hex: Int): MutableList<Float> { fun hextoRGB(hex: Int): MutableList<Float> {

View File

@ -1,21 +1,23 @@
package fr.username404.snowygui.gui.elements package fr.username404.snowygui.gui.elements
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import fr.username404.snowygui.Snowy.Companion.MissingComponent import fr.username404.snowygui.Snowy.Companion.MissingComponent
import fr.username404.snowygui.config.Configuration import fr.username404.snowygui.config.Configuration
import com.mojang.blaze3d.vertex.VertexFormat
import fr.username404.snowygui.gui.ColoredElement import fr.username404.snowygui.gui.ColoredElement
import fr.username404.snowygui.gui.feature.ButtonImpl import fr.username404.snowygui.gui.feature.ButtonImpl
import fr.username404.snowygui.gui.feature.Category import fr.username404.snowygui.gui.feature.Category
import fr.username404.snowygui.gui.feature.Colors import fr.username404.snowygui.gui.feature.Colors
import fr.username404.snowygui.utils.RenderingUtil import fr.username404.snowygui.utils.RenderingUtil.buffer
import fr.username404.snowygui.utils.RenderingUtil.colorShader
import fr.username404.snowygui.utils.RenderingUtil.endDraw
import fr.username404.snowygui.utils.RenderingUtil.prepareDraw
import fr.username404.snowygui.utils.RenderingUtil.tessellator
import io.github.config4k.extract import io.github.config4k.extract
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.util.ARGB
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import java.util.TreeSet import java.util.TreeSet
import kotlin.collections.LinkedHashSet import kotlin.collections.LinkedHashSet
@ -44,28 +46,24 @@ class ClickBox(
) { ) {
override val color: Int get() = this@ClickBox.color override val color: Int get() = this@ClickBox.color
override fun render(guiGraphics: GuiGraphics?) { override fun render(guiGraphics: GuiGraphics?) {
defaultRectFunc(guiGraphics) prepareDraw()
colorShader(); defaultRectFunc()
endDraw()
} }
init { height = 8 } init { height = 8 }
} }
var barStage: Int = 1; private set
var barStage: Int = 0; private set
fun scroll(d: Double, e: Double, supplied: Double) { fun scroll(d: Double, e: Double, supplied: Double) {
if (!isWithinBounds(d, e, offsetHeight = clickboxHeightOffset.toDouble())) return if (isWithinBounds(d, e, offsetHeight = clickboxHeightOffset.toDouble())) {
if (buttons.isEmpty()) return with(buttonsProgressBar) {
if ((height > 8 || (supplied < 0)) && (((height < (buttons.size * 8)) && (height < originalHeight)) || (supplied > 0))) {
// This allows scrolling until only the last button is visible at the top height -= supplied.toInt()
val maxScroll = max(0, buttons.size - 1) if (buttons.isNotEmpty()) (height / 8).let {
if (it > 0) barStage = it
val step = when { }
supplied < 0 -> 1 }
supplied > 0 -> -1 }
else -> 0
} }
if (step == 0) return
barStage = (barStage + step).coerceIn(0, maxScroll)
} }
companion object { companion object {
@ -75,96 +73,56 @@ class ClickBox(
} }
} }
var sortAlphabetically: Boolean by Configuration var sortAlphabetically: Boolean by Configuration
const val buttonsMax: Short = 16 // TODO Remove the buttons limit
const val clickboxHeightOffset: Int = 80 const val clickboxHeightOffset: Int = 80
private const val inclination: Float = 2.5F private const val inclination: Double = 2.5
} }
override fun render(guiGraphics: GuiGraphics?) { override fun render(guiGraphics: GuiGraphics?) {
val xi = floor(x).toInt() val currentHeight = y + (height + clickboxHeightOffset)
val yi = floor(y).toInt() prepareDraw()
with(buffer) {
begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
// Render the header:
vertex(x, y + height, 0.0).colorEnd()
vertex(x + width + inclination, y + height, 0.0).colorEnd()
vertex(x + width, y, 0.0).colorEnd()
vertex(x + inclination, y, 0.0).colorEnd()
// Header // Render the box:
RenderingUtil.drawSlantedHeader( vertex(x, currentHeight, 0.0).colorEnd()
guiGraphics = guiGraphics, vertex(x + width + inclination, currentHeight, 0.0).colorEnd()
x = xi, vertex(x + width + inclination, y + height, 0.0).colorEnd()
y = yi, tessellator.end()
width = width,
height = height,
slantTop = inclination,
color = color,
opacity = opacity
)
// Body colorShader()
RenderingUtil.drawRectangle( begin(VertexFormat.Mode.DEBUG_LINES, DefaultVertexFormat.POSITION_COLOR)
guiGraphics = guiGraphics, vertex(x + inclination, y + height, 0.0).colorEnd(Colors.WHITE_LINES.hexValue)
x = xi.toDouble(), vertex(x + width, y + height, 0.0).colorEnd(Colors.WHITE_LINES.hexValue)
y = (yi + height).toDouble(), tessellator.end()
height = clickboxHeightOffset, }
width = width + inclination.roundToInt(), endDraw()
color = color,
opacity = opacity
)
// Separator line
RenderingUtil.hLine(
guiGraphics = guiGraphics,
x1 = (xi + inclination).toInt(),
x2 = (xi + width),
y = (yi + height),
rgb = Colors.WHITE_LINES.hexValue,
opacity = 1f
)
if (buttons.isNotEmpty()) { if (buttons.isNotEmpty()) {
val barWidth = 3
val leftPadding = 3
val gapToBar = 1
val rowHeight = 9
val visibleRows = 8
val maxScroll = max(0, buttons.size - visibleRows)
val actualContentHeight = min(buttons.size, visibleRows) * rowHeight
val minBarH = 8
val currentBarH = if (maxScroll == 0) minBarH*(barStage + 1)
else minBarH + ((actualContentHeight - minBarH).toFloat() * barStage / maxScroll).roundToInt()
buttonsProgressBar.apply { buttonsProgressBar.apply {
this.width = barWidth x = this@ClickBox.x + this@ClickBox.width - 3
this.height = currentBarH.coerceAtMost(actualContentHeight) y = this@ClickBox.y + this@ClickBox.height + 3
this.x = (xi + this@ClickBox.width - barWidth).toDouble()
this.y = (yi + this@ClickBox.height + 3).toDouble()
}.display(guiGraphics) }.display(guiGraphics)
val buttonWidth = (this@ClickBox.width - leftPadding - barWidth - gapToBar).coerceAtLeast(10)
val contentStartY = yi + height + 3
val maxContentY = contentStartY + (8 * 9)
buttons.forEachIndexed { num, button -> buttons.forEachIndexed { num, button ->
val rowOffset = num - barStage val fullHeight = (y + height.toDouble())..(y + height + clickboxHeightOffset)
val yPos = contentStartY + (rowOffset * 9)
button.also { button.also {
it.x = (xi + leftPadding).toDouble() it.x = x + 3
it.y = yPos.toDouble() it.y = y + 3 + height + (((num + 1) - barStage) * 9)
it.width = buttonWidth it.hidden = if ((num + 1) <= 8) ((it.y) !in fullHeight) else ((it.y + it.height) !in fullHeight)
it.hidden = (rowOffset < 0) || (yPos + it.height > maxContentY)
}.display(guiGraphics) }.display(guiGraphics)
} }
} }
guiGraphics?.run {
with(Minecraft.getInstance().font) { with(Minecraft.getInstance().font) {
guiGraphics?.drawString( drawInBatch(name.string,
this, (x + 5).toFloat(), (y + 2).toFloat(), Colors.TRANSPARENT.hexValue, false,
Component.nullToEmpty(name.string), pose().last().pose(), bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880, isBidirectional
(xi + 5 + (inclination / 2f)).toInt(),
(yi + 2),
ARGB.opaque(Colors.WHITE.hexValue),
false
) )
} }
} }
} }
}

View File

@ -6,12 +6,14 @@ import fr.username404.snowygui.config.Configuration
import fr.username404.snowygui.gui.ColoredElement import fr.username404.snowygui.gui.ColoredElement
import fr.username404.snowygui.gui.feature.ButtonInfo.Companion.Type import fr.username404.snowygui.gui.feature.ButtonInfo.Companion.Type
import fr.username404.snowygui.utils.FontUtil import fr.username404.snowygui.utils.FontUtil
import fr.username404.snowygui.utils.RenderingUtil.colorShader
import fr.username404.snowygui.utils.RenderingUtil.endDraw
import fr.username404.snowygui.utils.RenderingUtil.prepareDraw
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.input.MouseButtonEvent
import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotation
sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) { sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
companion object { internal companion object {
private fun addButtons(vararg buttons: ButtonImpl) { private fun addButtons(vararg buttons: ButtonImpl) {
buttons.groupBy { impl -> buttons.groupBy { impl ->
ClickGui.clickBoxes.find { box -> ClickGui.clickBoxes.find { box ->
@ -43,26 +45,20 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
}.plus(Configuration.foundMacros).toTypedArray() }.plus(Configuration.foundMacros).toTypedArray()
) )
} }
var isDisabled: Boolean = false; set(value) { var isDisabled: Boolean = false; set(value) {
field = value field = value
hidden = value hidden = value
} }
@JvmField @JvmField
val info = this::class.findAnnotation<ButtonInfo>() ?: throw Exception("Missing @ButtonInfo annotaton") val info = this::class.findAnnotation<ButtonInfo>() ?: throw Exception("Missing @ButtonInfo annotaton")
final override var color = info.parent.categoryColor; get() { final override var color = info.parent.categoryColor; get() {
return info.parent.box.color.let { return info.parent.box.color.let {
if (field == it) field else it if (field == it) field else it
} }
} }
open val title: String = this@ButtonImpl::class.simpleName.toString() open val title: String = this@ButtonImpl::class.simpleName.toString()
protected open fun execAction() = Unit protected open fun execAction() = Unit
private var wasWithinBounds: Boolean = false private var wasWithinBounds: Boolean = false
var toggled: Boolean = false; private set(value) { var toggled: Boolean = false; private set(value) {
if (field xor value) { if (field xor value) {
if (value) lightUp() else lightDown() if (value) lightUp() else lightDown()
@ -70,12 +66,10 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
execAction() execAction()
} else field = value } else field = value
} }
private fun lightUp() { opacity += ButtonInfo.lightningFactor } private fun lightUp() { opacity += ButtonInfo.lightningFactor }
private fun lightDown() { opacity -= ButtonInfo.lightningFactor } private fun lightDown() { opacity -= ButtonInfo.lightningFactor }
final override fun mouseClicked(d: Double, e: Double, i: Int): Boolean {
final override fun mouseClicked(event: MouseButtonEvent, isDoubleClick: Boolean): Boolean { wasWithinBounds = isWithinBounds(d, e).also {
wasWithinBounds = isWithinBounds(event.x, event.y).also {
if (it) { if (it) {
if (info.kind == Type.TOGGLE) { if (info.kind == Type.TOGGLE) {
toggled = !toggled toggled = !toggled
@ -85,16 +79,16 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
return false return false
} }
final override fun mouseReleased(event: MouseButtonEvent): Boolean { final override fun mouseReleased(d: Double, e: Double, i: Int): Boolean {
if (wasWithinBounds && (info.kind == Type.CLICK)) { if (wasWithinBounds && (info.kind == Type.CLICK)) {
execAction() execAction()
lightDown() lightDown()
}; return false
} }
return false
}
final override fun render(guiGraphics: GuiGraphics?) { final override fun render(guiGraphics: GuiGraphics?) {
defaultRectFunc(guiGraphics) prepareDraw()
colorShader(); defaultRectFunc()
endDraw()
if (guiGraphics != null) { if (guiGraphics != null) {
FontUtil.drawScaled(guiGraphics, title, x + 1, y + 1, 0.75F) FontUtil.drawScaled(guiGraphics, title, x + 1, y + 1, 0.75F)
} }

View File

@ -3,16 +3,11 @@ package fr.username404.snowygui.gui.feature
import fr.username404.snowygui.EventSnowy import fr.username404.snowygui.EventSnowy
import fr.username404.snowygui.argsLambda import fr.username404.snowygui.argsLambda
import fr.username404.snowygui.gui.Renderable import fr.username404.snowygui.gui.Renderable
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
sealed class ButtonImplWithHud: ButtonImpl() { sealed class ButtonImplWithHud: ButtonImpl() {
protected abstract val hudRenderLambda: Renderable protected abstract val hudRenderLambda: Renderable
private val generatedLambda: argsLambda = { private val generatedLambda: argsLambda = { hudRenderLambda.render(it.first() as GuiGraphics?) }
if (!Minecraft.getInstance().options.hideGui) {
hudRenderLambda.render(it.first() as GuiGraphics?)
}
}
final override fun execAction() { final override fun execAction() {
EventSnowy["HudRender"].run { EventSnowy["HudRender"].run {
if (toggled) add(generatedLambda) if (toggled) add(generatedLambda)

View File

@ -28,7 +28,7 @@ annotation class ButtonInfo(
HUD("snowy.clickbox.hud", Colors.DARK_PURPLE), HUD("snowy.clickbox.hud", Colors.DARK_PURPLE),
MACROS("snowy.clickbox.macros", Colors.GREEN); MACROS("snowy.clickbox.macros", Colors.GREEN);
companion object { companion object {
fun fromBox(box: ClickBox): Category? = entries.find { fun fromBox(box: ClickBox): Category? = values().find {
box.isCategory(it) box.isCategory(it)
} }
} }

View File

@ -1,6 +1,20 @@
package fr.username404.snowygui.gui.feature package fr.username404.snowygui.gui.feature
import fr.username404.snowygui.mixins.OptionValueAccessor
import net.minecraft.client.Minecraft
@ButtonInfo(Category.MISC) @ButtonInfo(Category.MISC)
object GammaBoost: ButtonImpl() { object GammaBoost: ButtonImpl() {
const val BOOST = 1400.0F private const val boost = 1400.0
private var oldGamma = 0.0
override fun execAction() {
with(Minecraft.getInstance().options) {
val gamma = gamma().get()
@Suppress("KotlinConstantConditions")
(gamma() as OptionValueAccessor).setValue(if (toggled) {
if (gamma < boost) oldGamma = gamma
boost
} else oldGamma)
}
}
} }

View File

@ -44,7 +44,7 @@ object Keystrokes: ButtonImplWithHud() {
private fun drawKey(x: Double, y: Double, key: Int, guiGraphics: GuiGraphics?) { private fun drawKey(x: Double, y: Double, key: Int, guiGraphics: GuiGraphics?) {
RenderingUtil.prepareDraw() RenderingUtil.prepareDraw()
RenderingUtil.drawRectangle( RenderingUtil.drawRectangle(
guiGraphics, x, y, height / 2, height / 2, x, y, height / 2, height / 2,
color = color, opacity = getDynamicOpacity(key).toFloat() color = color, opacity = getDynamicOpacity(key).toFloat()
) )
RenderingUtil.endDraw() RenderingUtil.endDraw()
@ -68,7 +68,7 @@ object Keystrokes: ButtonImplWithHud() {
hud.display(it) hud.display(it)
} }
init { init {
if (!Position.entries.map { it.value }.contains(currentPosition)) { if (!Position.values().map { it.value }.contains(currentPosition)) {
currentPosition = Position.LEFT.value currentPosition = Position.LEFT.value
} }
} }

View File

@ -3,7 +3,6 @@ package fr.username404.snowygui.gui.feature
import fr.username404.snowygui.gui.feature.ButtonInfo.Companion.Type import fr.username404.snowygui.gui.feature.ButtonInfo.Companion.Type
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.server.permissions.Permissions
/** /**
* @property command The command to execute * @property command The command to execute
@ -18,7 +17,7 @@ data class Macro(
override fun execAction(): Unit = with(Minecraft.getInstance().player!!) { override fun execAction(): Unit = with(Minecraft.getInstance().player!!) {
connection.run { connection.run {
command.let { command.let {
if (it.startsWith("say") && !this@with.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER)) { if (it.startsWith("say") && !hasPermissions(2)) {
sendChat(it.drop(4)) sendChat(it.drop(4))
} else sendCommand(it) } else sendCommand(it)
} }

View File

@ -6,9 +6,9 @@ import net.minecraft.client.Minecraft
@ButtonInfo(Category.MISC, shouldSave = false) @ButtonInfo(Category.MISC, shouldSave = false)
object Zoom: ButtonImpl() { object Zoom: ButtonImpl() {
var smoothCameraOnZoom: Boolean by Configuration var smoothCameraOnZoom: Boolean by Configuration
var zoomFactor: Float by Configuration var zoomFactor: Double by Configuration
@JvmStatic @JvmStatic
fun getNewZoom(fov: Float): Float = fov / zoomFactor fun getNewZoom(fov: Double): Double = fov / zoomFactor
public override fun execAction() { public override fun execAction() {
Minecraft.getInstance().options.smoothCamera = toggled && smoothCameraOnZoom Minecraft.getInstance().options.smoothCamera = toggled && smoothCameraOnZoom
} }

View File

@ -6,26 +6,20 @@ import fr.username404.snowygui.config.SnowyConfigScreen
import fr.username404.snowygui.config.configScreenParent import fr.username404.snowygui.config.configScreenParent
import net.minecraft.client.KeyMapping import net.minecraft.client.KeyMapping
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.resources.Identifier
import org.lwjgl.glfw.GLFW.GLFW_KEY_U import org.lwjgl.glfw.GLFW.GLFW_KEY_U
import org.lwjgl.glfw.GLFW.GLFW_KEY_Y import org.lwjgl.glfw.GLFW.GLFW_KEY_Y
private typealias privateLambda = (() -> Unit)? private typealias privateLambda = (() -> Unit)?
object AddKeyMaps { object AddKeyMaps {
private const val prefix = "snowy" private const val prefix = "snowy"
var category: KeyMapping.Category? = null; private set
@JvmOverloads @JvmOverloads
internal fun mkMap( internal fun mkMap(
translationSuffix: String, translationSuffix: String,
key: Int, category: String = "controls", key: Int, category: String = "keycategory",
lambda: privateLambda = null lambda: privateLambda = null
): Pair<KeyMapping, privateLambda> = KeyMapping( ): Pair<KeyMapping, privateLambda> = KeyMapping(
"key.$prefix.$translationSuffix", InputConstants.Type.KEYSYM, "key.$prefix.$translationSuffix", InputConstants.Type.KEYSYM,
key, this.category ?: run { key, "category.$prefix.$category"
this.category = KeyMapping.Category.register(
Identifier.fromNamespaceAndPath("snowygui", category)
); this.category
}!!
) to lambda ) to lambda
val list: MutableMap<KeyMapping, privateLambda> = with(Minecraft.getInstance()) { val list: MutableMap<KeyMapping, privateLambda> = with(Minecraft.getInstance()) {
mutableMapOf( mutableMapOf(

View File

@ -3,18 +3,13 @@ package fr.username404.snowygui.utils
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import fr.username404.snowygui.gui.feature.Colors import fr.username404.snowygui.gui.feature.Colors
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.util.ARGB
object FontUtil { object FontUtil {
fun drawScaled(guiGraphics: GuiGraphics, text: String, x: Double, y: Double, scaleFactor: Float, color: Colors = Colors.BLACK) { fun drawScaled(guiGraphics: GuiGraphics, text: String, x: Double, y: Double, scaleFactor: Float, color: Colors = Colors.BLACK) {
val stack = guiGraphics.pose() val stack = guiGraphics.pose()
stack.scale(scaleFactor, scaleFactor) stack.scale(scaleFactor, scaleFactor, scaleFactor)
guiGraphics.drawString( guiGraphics.drawString(Minecraft.getInstance().font, text, (x / scaleFactor).toInt(), (y / scaleFactor).toInt(), color.hexValue, false)
Minecraft.getInstance().font, text,
(x / scaleFactor).toInt(), (y / scaleFactor).toInt(),
ARGB.opaque(color.hexValue), false
)
val factorToOriginal = 1F / scaleFactor val factorToOriginal = 1F / scaleFactor
stack.scale(factorToOriginal, factorToOriginal) stack.scale(factorToOriginal, factorToOriginal, factorToOriginal)
} }
} }

View File

@ -1,104 +1,45 @@
package fr.username404.snowygui.utils package fr.username404.snowygui.utils
import com.mojang.blaze3d.opengl.GlStateManager import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferBuilder
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.Tesselator
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.blaze3d.vertex.VertexFormat
import fr.username404.snowygui.gui.feature.Colors import fr.username404.snowygui.gui.feature.Colors
import net.minecraft.client.gui.GuiGraphics import fr.username404.snowygui.gui.hextoRGB
import net.minecraft.util.ARGB import net.minecraft.client.renderer.GameRenderer
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
object RenderingUtil { object RenderingUtil {
fun prepareDraw() = GlStateManager._enableBlend() @JvmField val tessellator: Tesselator = Tesselator.getInstance()
fun endDraw() = GlStateManager._disableBlend() @JvmField val buffer: BufferBuilder = tessellator.builder
@JvmStatic
private fun argbFromRgb(rgb: Int, opacity: Float = 1f): Int { fun VertexConsumer.colorIt(color: Int, opacity: Float = 1F): VertexConsumer = hextoRGB(color).run {
return ARGB.color( color(get(0), get(1), get(2), opacity)
(opacity.coerceIn(0f, 1f) * 255f).toInt().coerceIn(0, 255), }
(rgb shr 16) and 0xFF, fun VertexConsumer.colorEnd(color: Int, opacity: Float = 1F) = colorIt(color, opacity).endVertex()
(rgb shr 8) and 0xFF, fun colorShader() {
rgb and 0xFF RenderSystem.setShader(GameRenderer::getPositionColorShader)
) RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
}
fun prepareDraw() {
colorShader()
RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc()
}
fun endDraw() {
RenderSystem.disableBlend()
} }
fun drawRectangle( fun drawRectangle(
guiGraphics: GuiGraphics?, x: Double, y: Double, height: Int, width: Int,
x: Double, color: Int = Colors.TRANSPARENT(), opacity: Float = 1F
y: Double, ): Unit = buffer.run {
height: Int, fun VertexConsumer.colorEnd() = colorEnd(color, opacity)
width: Int, begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
color: Int = Colors.TRANSPARENT(), vertex(x, y + height, 0.0).colorEnd()
opacity: Float = 1F vertex(x + width, y + height, 0.0).colorEnd()
) { vertex(x + width, y, 0.0).colorEnd()
if (guiGraphics == null) return vertex(x, y, 0.0).colorEnd()
tessellator.end()
val x1 = floor(x).toInt()
val y1 = floor(y).toInt()
val x2 = ceil(x + width).toInt()
val y2 = ceil(y + height).toInt()
prepareDraw()
guiGraphics.fill(x1, y1, x2, y2, argbFromRgb(color, opacity))
endDraw()
}
fun drawSlantedHeader(
guiGraphics: GuiGraphics?,
x: Int,
y: Int,
width: Int,
height: Int,
slantTop: Float,
color: Int,
opacity: Float
) {
if (guiGraphics == null) return
if (width <= 0 || height <= 0) return
val slant = slantTop.toDouble()
val baseArgb = argbFromRgb(color, opacity)
prepareDraw()
for (dy in 0 until height) {
val t = if (height == 1) 0.0 else dy.toDouble() / (height - 1).toDouble()
val leftF = x + slant * (1.0 - t)
val rightF = x + width + slant * t
val left = min(leftF, rightF)
val right = max(leftF, rightF)
val lx = floor(left).toInt()
val rx = floor(right).toInt()
val yy = y + dy
val midStart = lx + 1
val midEnd = rx
if (midEnd > midStart) {
guiGraphics.fill(midStart, yy, midEnd, yy + 1, baseArgb)
}
val leftFrac = (left - floor(left)).toFloat().coerceIn(0f, 1f)
val rightFrac = (right - floor(right)).toFloat().coerceIn(0f, 1f)
val leftAlpha = (1f - leftFrac) * opacity
val rightAlpha = rightFrac * opacity
if (leftAlpha > 0f) guiGraphics.fill(lx, yy, lx + 1, yy + 1, argbFromRgb(color, leftAlpha))
if (rightAlpha > 0f) guiGraphics.fill(rx, yy, rx + 1, yy + 1, argbFromRgb(color, rightAlpha))
if (rx <= lx) {
guiGraphics.fill(lx, yy, lx + 1, yy + 1, baseArgb)
}
}
endDraw()
}
fun hLine(guiGraphics: GuiGraphics?, x1: Int, x2: Int, y: Int, rgb: Int, opacity: Float = 1f) {
if (guiGraphics == null) return
prepareDraw()
guiGraphics.hLine(x1, x2, y, argbFromRgb(rgb, opacity))
endDraw()
} }
} }

View File

@ -7,13 +7,14 @@
"screen.snowy.config.general.macros.missingelement": "Missing element(s) next to the separator", "screen.snowy.config.general.macros.missingelement": "Missing element(s) next to the separator",
"screen.snowy.config.general.macros.toomuchdelimiters": "Too much separators (only one is allowed)", "screen.snowy.config.general.macros.toomuchdelimiters": "Too much separators (only one is allowed)",
"screen.snowy.config.general.macros.toomuchcharacters": "Too much characters (16 is the maximum)", "screen.snowy.config.general.macros.toomuchcharacters": "Too much characters (16 is the maximum)",
"screen.snowy.config.general.macros.toomuchbuttons": "Too much entries (16 is the maximum)",
"screen.snowy.config.colors": "Box colors", "screen.snowy.config.colors": "Box colors",
"screen.snowy.config.behavior": "Behavior", "screen.snowy.config.behavior": "Behavior",
"screen.snowy.config.behavior.sortalphabetically": "Sort buttons alphabetically", "screen.snowy.config.behavior.sortalphabetically": "Sort buttons alphabetically",
"screen.snowy.config.behavior.zoom.factor": "Zoom factor", "screen.snowy.config.behavior.zoom.factor": "Zoom factor",
"screen.snowy.config.behavior.zoom.smoothcamera": "Smooth camera on zoom", "screen.snowy.config.behavior.zoom.smoothcamera": "Smooth camera on zoom",
"screen.snowy.config.behavior.keystrokes.position": "Position of the keystrokes HUD element", "screen.snowy.config.behavior.keystrokes.position": "Position of the keystrokes HUD element",
"key.category.snowygui.controls": "SnowyGUI", "category.snowy.keycategory": "SnowyGUI",
"key.snowy.opengui": "Open the snowy gui", "key.snowy.opengui": "Open the snowy gui",
"key.snowy.configkey": "Open the snowy configuration screen", "key.snowy.configkey": "Open the snowy configuration screen",
"snowy.clickbox.misc": "Miscellaneous", "snowy.clickbox.misc": "Miscellaneous",

View File

@ -7,13 +7,14 @@
"screen.snowy.config.general.macros.missingelement": "Élément(s) manquant(s) avant ou après le séparateur", "screen.snowy.config.general.macros.missingelement": "Élément(s) manquant(s) avant ou après le séparateur",
"screen.snowy.config.general.macros.toomuchdelimiters": "Séparateurs trop nombreux (un seul est autorisé)", "screen.snowy.config.general.macros.toomuchdelimiters": "Séparateurs trop nombreux (un seul est autorisé)",
"screen.snowy.config.general.macros.toomuchcharacters": "Trop de caractères (le maximum est de 16)", "screen.snowy.config.general.macros.toomuchcharacters": "Trop de caractères (le maximum est de 16)",
"screen.snowy.config.general.macros.toomuchbuttons": "Trop d'entrées (le maximum est de 16)",
"screen.snowy.config.colors": "Couleurs des boîtes", "screen.snowy.config.colors": "Couleurs des boîtes",
"screen.snowy.config.behavior": "Comportement", "screen.snowy.config.behavior": "Comportement",
"screen.snowy.config.behavior.sortalphabetically": "Trier les boutons alphabétiquement", "screen.snowy.config.behavior.sortalphabetically": "Trier les boutons alphabétiquement",
"screen.snowy.config.behavior.zoom.factor": "Facteur de zoom", "screen.snowy.config.behavior.zoom.factor": "Facteur de zoom",
"screen.snowy.config.behavior.zoom.smoothcamera": "Caméra fluide pendant le zoom", "screen.snowy.config.behavior.zoom.smoothcamera": "Caméra fluide pendant le zoom",
"screen.snowy.config.behavior.keystrokes.position": "Position de l'élément keystrokes de l'ATH", "screen.snowy.config.behavior.keystrokes.position": "Position de l'élément keystrokes de l'ATH",
"key.category.snowygui.controls": "SnowyGUI", "category.snowy.keycategory": "SnowyGUI",
"key.snowy.opengui": "Ouvrir l'interface de snowy", "key.snowy.opengui": "Ouvrir l'interface de snowy",
"key.snowy.configkey": "Ouvrir l'écran de configuration de snowy", "key.snowy.configkey": "Ouvrir l'écran de configuration de snowy",
"snowy.clickbox.misc": "Divers", "snowy.clickbox.misc": "Divers",

View File

@ -1,12 +1,17 @@
{ {
"required": true, "required": true,
"package": "fr.username404.snowygui.mixins", "package": "fr.username404.snowygui.mixins",
"compatibilityLevel": "JAVA_18", "compatibilityLevel": "JAVA_8",
"client": [ "client": [
"GammaMixin" "KeysAccessor",
"KeyMappings",
"EndTickMixin",
"TitleScreenMixin",
"OptionValueAccessor"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1
}, },
"minVersion": "0.8" "minVersion": "0.8",
"refmap": "snowygui-common-refmap.json"
} }

View File

@ -1,9 +0,0 @@
accessWidener v2 named
accessible field net/minecraft/client/OptionInstance value Ljava/lang/Object;
mutable field net/minecraft/client/OptionInstance value Ljava/lang/Object;
accessible field com/mojang/blaze3d/opengl/GlCommandEncoder inRenderPass Z
mutable field com/mojang/blaze3d/opengl/GlCommandEncoder inRenderPass Z
accessible method net/minecraft/client/KeyMapping$Category register (Ljava/lang/String;)Lnet/minecraft/client/KeyMapping$Category;

View File

@ -1,3 +0,0 @@
{
"accessWidener": "snowygui.accessWidener"
}

View File

@ -14,10 +14,10 @@ architectury { platformSetupLoomIde(); fabric() }
dependencies { dependencies {
modImplementation("${Groups.Fabric}:fabric-loader:${rootProject.property("fabric_loader_version")}") modImplementation("${Groups.Fabric}:fabric-loader:${rootProject.property("fabric_loader_version")}")
modApi("${Groups.FabricApi}:fabric-rendering-v1:${rootProject.property("fabric_rendering_api_version")}") include(modApi("${Groups.FabricApi}:fabric-rendering-v1:${rootProject.property("fabric_rendering_api_version")}")!!)
modApi("${Groups.FabricApi}:fabric-api-base:${rootProject.property("fabric_api_base_version")}") include(modApi("${Groups.FabricApi}:fabric-api-base:${rootProject.property("fabric_api_base_version")}")!!)
modApi("me.shedaniel.cloth:cloth-config-fabric:${rootProject.property("clothconfig_version")}") { exclude(group = Groups.FabricApi) } modApi("me.shedaniel.cloth:cloth-config-fabric:${rootProject.property("clothconfig_version")}") { exclude(group = Groups.FabricApi) }
modImplementation("${Groups.FabricApi}:fabric-resource-loader-v0:${rootProject.property("fabric_resource_loader_version")}") include(modImplementation("${Groups.FabricApi}:fabric-resource-loader-v0:${rootProject.property("fabric_resource_loader_version")}")!!)
modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = rootProject.property("fabric_language_kotlin") as String) modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = rootProject.property("fabric_language_kotlin") as String)
modImplementation("com.terraformersmc:modmenu:${rootProject.property("modmenu_version")}") { modImplementation("com.terraformersmc:modmenu:${rootProject.property("modmenu_version")}") {
exclude(group = Groups.FabricApi, module = "fabric-api-base") exclude(group = Groups.FabricApi, module = "fabric-api-base")

View File

@ -11,8 +11,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(GameRenderer.class) @Mixin(GameRenderer.class)
abstract class ZoomMixin { abstract class ZoomMixin {
@Inject(at = @At(value = "RETURN"), method = "getFov(Lnet/minecraft/client/Camera;FZ)F", cancellable = true) @Inject(at = @At(value = "RETURN"), method = "getFov(Lnet/minecraft/client/Camera;FZ)D", cancellable = true)
private void getFov(Camera camera, float f, boolean bl, CallbackInfoReturnable<Float> cir) { private void getFov(Camera camera, float f, boolean bl, CallbackInfoReturnable<Double> cir) {
if (Zoom.INSTANCE.getToggled() && !OkZoomerCompatKt.isOkZoomerPresent) { if (Zoom.INSTANCE.getToggled() && !OkZoomerCompatKt.isOkZoomerPresent) {
cir.setReturnValue(Zoom.getNewZoom(cir.getReturnValue())); cir.setReturnValue(Zoom.getNewZoom(cir.getReturnValue()));
} }

View File

@ -1,5 +1,6 @@
package fr.username404.snowygui.fabric package fr.username404.snowygui.fabric
import com.mojang.blaze3d.vertex.PoseStack
import fr.username404.snowygui.EventSnowy import fr.username404.snowygui.EventSnowy
import fr.username404.snowygui.Snowy import fr.username404.snowygui.Snowy
import fr.username404.snowygui.gui.feature.ButtonImpl import fr.username404.snowygui.gui.feature.ButtonImpl
@ -7,8 +8,6 @@ import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback.EVENT import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback.EVENT
import net.fabricmc.loader.api.FabricLoader import net.fabricmc.loader.api.FabricLoader
import net.fabricmc.loader.launch.common.FabricLauncherBase
import net.minecraft.client.DeltaTracker
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import kotlin.io.path.exists import kotlin.io.path.exists
import kotlin.io.path.isDirectory import kotlin.io.path.isDirectory
@ -22,25 +21,20 @@ class FabricInit: Snowy(), ClientModInitializer {
EVENT.register( EVENT.register(
object: HudRenderCallback, EventSnowy { object: HudRenderCallback, EventSnowy {
override val type: String = "HudRender" override val type: String = "HudRender"
override fun onHudRender(guiGraphics: GuiGraphics, tickCounter: DeltaTracker) = fire(guiGraphics) override fun onHudRender(guiGraphics: GuiGraphics?, tickDelta: Float) = fire(guiGraphics)
} }
) )
} }
override val annotatedButtons = lazy { override val annotatedButtons = FabricLoader.getInstance().allMods.mapNotNull {
FabricLoader.getInstance().allMods.mapNotNull { it.findPath(FeaturePackage.replace('.', '/')).getOrNull()
it.findPath(FEATURE_PACKAGE.replace('.', '/')).getOrNull()
}.filter { it.exists() && it.isDirectory() }.flatMap { buttonsDirectory -> }.filter { it.exists() && it.isDirectory() }.flatMap { buttonsDirectory ->
buttonsDirectory.listDirectoryEntries("*.class").mapNotNull { file -> mutableSetOf<Class<out ButtonImpl>>().apply {
@Suppress("DEPRECATION") buttonsDirectory.listDirectoryEntries("*.class").forEach { file ->
FabricLauncherBase.getClass( @Suppress("DEPRECATION") net.fabricmc.loader.launch.common.
file.pathString.drop(1) FabricLauncherBase.getClass(file.pathString.drop(1).replace('/', '.').removeSuffix(".class")).let { foundClass ->
.replace('/', '.').removeSuffix(".class") if (foundClass.isValidForButtonCollection()) add(foundClass.asSubclass(ButtonImpl::class.java))
).let { foundClass -> }
if (foundClass.isValidForButtonCollection())
foundClass.asSubclass(ButtonImpl::class.java)
else null
} }
} }
}.toSet() }.toSet()
} }
}

View File

@ -32,7 +32,6 @@
"snowygui-common.mixins.json", "snowygui-common.mixins.json",
"snowygui-fabric.mixins.json" "snowygui-fabric.mixins.json"
], ],
"accessWidener": "snowygui.accessWidener",
"depends": { "depends": {
"fabricloader": ">=${fabric_loader}", "fabricloader": ">=${fabric_loader}",
"fabric-language-kotlin": ">=${fabric_kotlin}", "fabric-language-kotlin": ">=${fabric_kotlin}",

View File

@ -1,12 +1,8 @@
{ {
"required": true, "required": true,
"package": "fr.username404.snowygui.mixins", "package": "fr.username404.snowygui.mixins",
"compatibilityLevel": "JAVA_18", "compatibilityLevel": "JAVA_8",
"client": [ "client": [
"EndTickMixin",
"TitleScreenMixin",
"KeysAccessor",
"KeyMappings",
"ZoomMixin", "ZoomMixin",
"OkZoomerAlternativeMixin" "OkZoomerAlternativeMixin"
], ],

25
forge/build.gradle.kts Normal file
View File

@ -0,0 +1,25 @@
architectury { platformSetupLoomIde(); forge() }
repositories {
maven(url = "https://thedarkcolour.github.io/KotlinForForge/")
}
dependencies {
forge("net.minecraftforge:forge:${rootProject.architectury.minecraft}-${rootProject.property("forge_version")}.+")
implementation("thedarkcolour:kotlinforforge:${rootProject.property("kotlinforforge")}")
modApi("me.shedaniel.cloth:cloth-config-forge:${rootProject.property("clothconfig_version")}")
implementation(project(path = ":common", configuration = "namedElements")) { isTransitive = false }
add("developmentForge", project(path = ":common")) { isTransitive = false }
shadowC(project(path = ":common", configuration = "transformProductionForge")) { isTransitive = false }
}; loom {
if (JavaVersion.current().isJava9Compatible) {
runs {
val args: MutableList<String> = mutableListOf("-Dfml.earlyprogresswindow=false")
args += if (JavaVersion.current() < JavaVersion.VERSION_17) {
listOf("--add-exports java.base/sun.security.util=ALL-UNNAMED", "--add-opens java.base/java.util.jar=ALL-UNNAMED")
} else listOf("--illegal-access=permit")
this.forEach {
it.vmArgs(args)
}
}
}
}

1
forge/gradle.properties Normal file
View File

@ -0,0 +1 @@
loom.platform=forge

View File

@ -0,0 +1,46 @@
package fr.username404.snowygui.forge
import fr.username404.snowygui.Snowy
import fr.username404.snowygui.config.SnowyConfigScreen
import fr.username404.snowygui.config.configScreenParent
import fr.username404.snowygui.gui.feature.ButtonImpl
import net.minecraftforge.fml.ModList
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent
import net.minecraftforge.client.ConfigScreenHandler
import net.minecraftforge.forgespi.language.ModFileScanData
import org.objectweb.asm.Type
import thedarkcolour.kotlinforforge.forge.FORGE_BUS
import thedarkcolour.kotlinforforge.forge.LOADING_CONTEXT
import thedarkcolour.kotlinforforge.forge.MOD_BUS
@Mod("snowygui")
@Suppress("UNUSED_PARAMETER")
class ForgeInit: Snowy() {
private fun initSetup(event: FMLClientSetupEvent) = atInit()
private fun configSetup(event: FMLClientSetupEvent) {
LOADING_CONTEXT.registerExtensionPoint(
ConfigScreenHandler.ConfigScreenFactory::class.java
) { ConfigScreenHandler.ConfigScreenFactory { _, parent -> configScreenParent = parent; SnowyConfigScreen } }
}
override val annotatedButtons = ModList.get() // Forge-specific reflection
.allScanData
.flatMap { obj: ModFileScanData -> obj.classes }
.filter { data: ModFileScanData.ClassData? ->
(data!!.javaClass.getDeclaredField("clazz").apply { isAccessible = true }.get(data) as Type).className.let { classname ->
classname.startsWith(FeaturePackage) && Class.forName(classname).isValidForButtonCollection()
}
}
.map { Class.forName((it!!.javaClass.getDeclaredField("clazz").apply { isAccessible = true }.get(it) as Type).className).asSubclass(ButtonImpl::class.java)}
.toSet()
init {
with(MOD_BUS) {
addListener(this@ForgeInit::initSetup)
addListener(this@ForgeInit::configSetup)
}
with(FORGE_BUS) {
register(HudHandler)
register(ZoomHandler)
}
}
}

View File

@ -1,8 +1,8 @@
package fr.username404.snowygui.forge package fr.username404.snowygui.forge
import fr.username404.snowygui.EventSnowy import fr.username404.snowygui.EventSnowy
import net.neoforged.bus.api.SubscribeEvent import net.minecraftforge.client.event.RenderGuiEvent
import net.neoforged.neoforge.client.event.RenderGuiEvent import net.minecraftforge.eventbus.api.SubscribeEvent
object HudHandler: EventSnowy { object HudHandler: EventSnowy {
override val type: String = "HudRender" override val type: String = "HudRender"

View File

@ -1,12 +1,12 @@
package fr.username404.snowygui.forge package fr.username404.snowygui.forge
import fr.username404.snowygui.gui.feature.Zoom import fr.username404.snowygui.gui.feature.Zoom
import net.neoforged.bus.api.SubscribeEvent import net.minecraftforge.client.event.ComputeFovModifierEvent
import net.neoforged.neoforge.client.event.ComputeFovModifierEvent import net.minecraftforge.eventbus.api.SubscribeEvent
object ZoomHandler { object ZoomHandler {
@SubscribeEvent @SubscribeEvent
fun onFOVEvent(event: ComputeFovModifierEvent) { fun onFOVEvent(event: ComputeFovModifierEvent) {
if (Zoom.toggled) event.newFovModifier = Zoom.getNewZoom(event.newFovModifier) if (Zoom.toggled) event.newFovModifier = Zoom.getNewZoom(event.newFovModifier.toDouble()).toFloat()
} }
} }

View File

@ -14,14 +14,14 @@ A cross-platform mod offering a useful interface.
logoFile = "icon.png" logoFile = "icon.png"
[[dependencies.snowygui]] [[dependencies.snowygui]]
modId = "cloth_config" modId = "cloth-config"
mandatory = false mandatory = false
versionRange = "[${clothconfig},)" versionRange = "[${clothconfig},)"
ordering = "BEFORE" ordering = "BEFORE"
side = "CLIENT" side = "CLIENT"
[[dependencies.snowygui]] [[dependencies.snowygui]]
modId = "neoforge" modId = "forge"
mandatory = true mandatory = true
versionRange = "[${forge_version},)" versionRange = "[${forge_version},)"
ordering = "NONE" ordering = "NONE"
@ -33,9 +33,3 @@ mandatory = true
versionRange = "[${minecraft_version},)" versionRange = "[${minecraft_version},)"
ordering = "NONE" ordering = "NONE"
side = "BOTH" side = "BOTH"
[[mixins]]
config = "snowygui-common.mixins.json"
[[mixins]]
config = "snowygui-neoforge.mixins.json"

View File

@ -1,7 +1,7 @@
{ {
"required": false, "required": false,
"package": "fr.username404.snowygui.mixins", "package": "fr.username404.snowygui.mixins",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_8",
"client": [], "client": [],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -1,22 +1,22 @@
org.gradle.daemon=false org.gradle.daemon=false
kotlin.code.style=official kotlin.code.style=official
org.gradle.jvmargs=-Xmx2G -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+AlwaysPreTouch org.gradle.jvmargs=-Xmx2G -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+AlwaysPreTouch
kotlin.incremental=true kotlin.incremental=true
org.gradle.caching=true org.gradle.caching=true
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.unsafe.configuration-cache=on org.gradle.unsafe.configuration-cache=on
org.gradle.vfs.watch=true org.gradle.vfs.watch=true
minecraft=1.21.11 minecraft=1.20
forge_version=21.11.38-beta forge_version=46.0
kotlinforforge=6.1.0 kotlinforforge=4.3.0
kotlinVer=2.3.0 kotlinVer=1.8.22
kotlin_coroutines_version=1.10.2 kotlin_coroutines_version=1.7.1
serializationVer=1.9.0 serializationVer=1.5.1
fabric_loader_version=0.18.4 fabric_loader_version=0.14.19
fabric_language_kotlin=1.13.8+kotlin.2.3.0 fabric_language_kotlin=1.9.5+kotlin.1.8.22
fabric_resource_loader_version=3.3.4+4fc5413f53 fabric_resource_loader_version=0.11.7+f7923f6d27
fabric_rendering_api_version=16.2.5+1fb1cde953 fabric_rendering_api_version=3.0.6+b3afc78b27
fabric_api_base_version=1.0.5+4ebb5c0853 fabric_api_base_version=0.4.29+b04edc7a27
clothconfig_version=21.11.151 clothconfig_version=11.0.99
modmenu_version=17.0.0-beta.2 modmenu_version=7.0.0

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -1,26 +0,0 @@
architectury { platformSetupLoomIde(); neoForge() }
repositories {
maven(url = "https://maven.neoforged.net/releases/")
maven(url = "https://thedarkcolour.github.io/KotlinForForge/")
}
dependencies {
neoForge("net.neoforged:neoforge:${rootProject.property("forge_version").toString().let {
return@let if (it.length > 4) it else "$it.+"
}}")
implementation("thedarkcolour:kotlinforforge:${rootProject.property("kotlinforforge")}")
modApi("me.shedaniel.cloth:cloth-config-neoforge:${rootProject.property("clothconfig_version")}")
implementation(project(path = ":common", configuration = "namedElements")) { isTransitive = false }
add("developmentNeoForge", project(path = ":common")) { isTransitive = false }
shadowC(project(path = ":common", configuration = "transformProductionNeoForge")) { isTransitive = false }
}; loom {
runs {
val args: MutableList<String> = mutableListOf("-Dfml.earlyprogresswindow=false")
args += listOf("--illegal-access=permit")
this.forEach {
it.vmArgs(args)
}
}
}

View File

@ -1 +0,0 @@
loom.platform=neoforge

View File

@ -1,11 +0,0 @@
package fr.username404.snowygui.forge
import fr.username404.snowygui.EventSnowy
import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.client.event.ClientTickEvent
object EndTickHandler: EventSnowy {
override val type: String = "EndTick"
@SubscribeEvent
fun handleEndTick(event: ClientTickEvent.Post) = fire<Any>()
}

View File

@ -1,53 +0,0 @@
package fr.username404.snowygui.forge
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.Snowy
import fr.username404.snowygui.config.SnowyConfigScreen
import fr.username404.snowygui.config.configScreenParent
import fr.username404.snowygui.gui.feature.ButtonImpl
import net.neoforged.fml.ModContainer
import net.neoforged.fml.ModList
import net.neoforged.fml.common.Mod
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent
import net.neoforged.neoforge.client.gui.IConfigScreenFactory
import net.neoforged.neoforge.common.NeoForge
import net.neoforged.neoforgespi.language.ModFileScanData
@Mod("snowygui")
@Suppress("UNUSED_PARAMETER")
class ForgeInit(container: ModContainer): Snowy() {
private fun initSetup(event: FMLClientSetupEvent) {
atInit()
ClickGui.tick()
ButtonImpl.initButtons()
}
override val annotatedButtons = lazy { // Forge-specific reflection
ModList.get()
.allScanData
.flatMap { obj: ModFileScanData -> obj.classes }
.filter { data: ModFileScanData.ClassData? ->
data!!.clazz.className.startsWith(FEATURE_PACKAGE)
}
.mapNotNull {
Class.forName((it!!.clazz.className), false, this::class.java.classLoader).run {
takeIf { isValidForButtonCollection() }
}?.asSubclass(ButtonImpl::class.java)
}
.toSet()
}
init {
container.eventBus!!.run {
addListener(this@ForgeInit::initSetup)
register(MiscModBusHandlers)
}
NeoForge.EVENT_BUS.run {
register(EndTickHandler)
register(HudHandler)
register(ZoomHandler)
}
container.registerExtensionPoint(
IConfigScreenFactory::class.java,
IConfigScreenFactory { _, parent -> configScreenParent = parent; SnowyConfigScreen }
)
}
}

View File

@ -1,14 +0,0 @@
package fr.username404.snowygui.forge
import fr.username404.snowygui.misc.AddKeyMaps
import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent
object MiscModBusHandlers {
@SubscribeEvent
fun handleKeys(event: RegisterKeyMappingsEvent) {
AddKeyMaps.list.forEach {
event.register(it.key)
}
}
}

View File

@ -2,7 +2,7 @@ pluginManagement {
repositories { repositories {
maven(url = "https://maven.fabricmc.net/") maven(url = "https://maven.fabricmc.net/")
maven(url = "https://maven.architectury.dev/") maven(url = "https://maven.architectury.dev/")
maven(url = "https://maven.neoforged.net/releases/") maven(url = "https://maven.minecraftforge.net/")
mavenCentral() mavenCentral()
mavenLocal() mavenLocal()
gradlePluginPortal() gradlePluginPortal()
@ -11,7 +11,7 @@ pluginManagement {
include("common") include("common")
include("fabric") include("fabric")
include("neoforge") include("forge")
rootProject.name = "SnowyGUI" rootProject.name = "SnowyGUI"