Compare commits

...

60 Commits
1.21.2 ... 26.2

Author SHA1 Message Date
b408e703c5
Update to 26.2-snapshot-1
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-16 16:47:04 +02:00
a67cd762c8
Bump version to 0.4.4
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-16 16:46:20 +02:00
23cbd6c4ad
Make cloth config optional on neoforge too
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-16 16:46:16 +02:00
3225340b57
Fix crash in the SnowyConfigScreen
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-16 16:21:26 +02:00
b5332aa3c1
Remove unused fields in snowygui.accessWidener
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-16 15:37:38 +02:00
ca303c6b57
Remove minotaur plugin from build.gradle.kts
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-15 23:20:21 +02:00
40f82f8489
Bump version to 0.4.3
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-15 22:06:39 +02:00
1da76930a8
Update Ok Zoomer compatibility
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-15 22:05:24 +02:00
445053f69d
Update to 26.1
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-15 22:04:27 +02:00
9116e6c3d1
Update gradle for 26.1
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-04-15 19:49:38 +02:00
968b184cbe
Bump version to 0.4.2
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-22 03:30:22 +01:00
630afa2e53
Set default strings for macros in ConfigScreen
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-22 03:24:27 +01:00
d8b37fc4ab
Fix a crash on launch when macros exist on neoforge
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-22 03:14:34 +01:00
2341dafe1b
Fix FontUtil.drawScaled
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-22 01:44:14 +01:00
58d6f02fb1
Bump version to 0.4.1
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 22:20:36 +01:00
54dc2169fc
Make Snowy.annotatedButtons lazy
Fixes usage on neoforge

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 22:15:59 +01:00
e647bfb286
Refactor ForgeInit annotatedButtons again
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 21:01:13 +01:00
d534e2d0b5
Fix missing space indent in ForgeInit.kt
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 17:44:25 +01:00
f3c1b4f0c8
Improve indentation a bit in Configuration.kt
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 16:32:53 +01:00
ed3d5d447a
Remove unused import in Configuration.kt
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 16:24:41 +01:00
d3e842be1f
Fix some things not being lowercase/uppercase in Snowy.kt
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 15:43:26 +01:00
da26662668
Ensure the architectury-loom version has the no refmaps default
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 15:39:11 +01:00
c20129457f
Remove refmaps usage
They're not needed anymore in recent minecraft + architectury-loom versions

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 15:32:26 +01:00
a30fda1262
Use a mixin for the gamma boost feature
Fixes it being reset by the graphics settings screen, and doesn't need to modify the option

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 15:06:57 +01:00
6b113b7750
Hide SnowyGUI HUD on F1
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 02:29:51 +01:00
e86b7e92fe
Add build & build-release IntelliJ build run configurations
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-21 01:23:58 +01:00
ca47028e7e
Fix controls category name
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-09 00:11:56 +01:00
21c53e496a
Use entries instead of values() in ButtonInfo.kt
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-09 00:03:58 +01:00
5bbca6c529
Simplify reflection in ForgeInit.kt
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-08 16:22:41 +01:00
2b48e68f77
Don't include fabric apis anymore
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 03:45:07 +01:00
beddf5f7af
Bump version to 0.4.0
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 03:27:39 +01:00
16bcccdded
Fix position of text on buttons
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 03:27:03 +01:00
79de0eedaa
Animate scroll even with no next pages
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 03:22:03 +01:00
965421b99f
Remove the buttons limit
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 03:10:14 +01:00
174f840226
Finish remaking UI rendering
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 01:35:50 +01:00
a20a2d2d8c
Fix box width
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-06 00:16:01 +01:00
1c43549b8f
Start remaking UI rendering
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-05 23:44:41 +01:00
b51e0ec2e0
Remove deprecated kotlin compiler option
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-05 21:24:30 +01:00
019e62f33b
Finish first try at porting to 1.21.11
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-05 21:23:57 +01:00
90d4e7b8b4
Revert "Improve writeTransform call"
This reverts commit 80204fcb01.

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-05 21:12:04 +01:00
4dd188d721
Try porting to 1.21.11
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-05 21:04:28 +01:00
fb83b10894
Update build dependencies for 1.21.11
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2026-02-05 20:02:35 +01:00
202c06bead
Update kotlinforforge to 5.9.0
To fully support NeoForged 1.21.6

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-29 09:43:44 +02:00
80204fcb01
Improve writeTransform call
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-27 02:43:06 +02:00
d0f46afc28
Actually use a value of 40 for BufferType.VERTICES, and continue porting effort
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-27 02:38:39 +02:00
04873a7a64
Fix renderPass draw call
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-27 01:11:42 +02:00
50db20d855
Fix arguments to createRenderPass
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-27 01:01:25 +02:00
8e96814e12
Use a value of 40 for BufferType.VERTICES
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-27 00:28:47 +02:00
38df17d90f
Start trying to port to 1.21.6
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-26 21:23:53 +02:00
9e0f5e696c
Update gradle
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-06-26 21:23:26 +02:00
daaf911a36
Put the right minecraft version in fabric.mod.json
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-25 23:42:07 +02:00
928e691cc9
Remove createRenderPassRewrite.kt
I forgot it

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-21 14:23:17 +02:00
8c526473e1
Less stupid workaround
Should fix compatibility with iris

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-20 17:31:36 +02:00
7b310399cf
Update parchmentmc
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-19 16:14:39 +02:00
2aaeb7b039
Bump version to 0.3.6
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 20:24:34 +02:00
6416a03001
Fix my stupid configuration system
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 20:20:05 +02:00
e96c2adb68
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 17:29:49 +02:00
5d98234d39
Fix and improve UI rendering
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 04:41:17 +02:00
6eed08aa53
Add a devBuild gradle property
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 03:08:55 +02:00
92c8e36c71
Update to 1.21.5
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2025-04-16 02:46:59 +02:00
40 changed files with 537 additions and 374 deletions

View File

@ -0,0 +1,27 @@
<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 --stacktrace" />
<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

@ -0,0 +1,27 @@
<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 --stacktrace" />
<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,35 +1,32 @@
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.dependencies.DependencyType
import masecla.modrinth4j.model.version.ProjectVersion.VersionType
import net.fabricmc.loom.LoomGradleExtension import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.api.LoomGradleExtensionAPI import net.fabricmc.loom.api.LoomGradleExtensionAPI
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript { buildscript {
dependencies { dependencies {
classpath("com.guardsquare:proguard-gradle:[7.5, 7.7[") { classpath("com.guardsquare:proguard-gradle:[7.8, 7.9[") {
exclude("com.android.tools.build") exclude("com.android.tools.build")
} }
} }
} }
plugins { plugins {
kotlin("jvm") version "2.0.0" kotlin("jvm") version "2.3.10"
kotlin("plugin.serialization") version "2.0.0" kotlin("plugin.serialization") version "2.3.10"
id("com.github.johnrengelman.shadow") version "8.1.1" apply false id("com.gradleup.shadow") version "9.4.1" apply false
id("architectury-plugin") version "[3.4.160, 3.5[" id("architectury-plugin") version "[3.5.166, 3.6["
id("dev.architectury.loom") version "1.9-SNAPSHOT" apply false id("dev.architectury.loom-no-remap") version "[1.14.473, 1.15[" 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"
id("com.modrinth.minotaur") version "2.8.7" apply false
} }
group = "fr.username404" group = "fr.username404"
version = "0.3.5" version = "0.4.4"
val groupAndName = "${rootProject.group}.${rootProject.name.lowercase()}" val groupAndName = "${rootProject.group}.${rootProject.name.lowercase()}"
val javaVer: String = "21" val javaVer: String = "25"
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('.')
@ -38,6 +35,7 @@ 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()
@ -48,27 +46,17 @@ subprojects {
ignoreFailures = true ignoreFailures = true
} }
lateinit var mappingsDep: Dependency lateinit var mappingsDep: Dependency
apply(plugin = "dev.architectury.loom") apply(plugin = "dev.architectury.loom-no-remap")
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") { if (this@subprojects.project.name != "common") {
accessWidenerPath.set(project(":common").extensions.getByType<LoomGradleExtensionAPI>().accessWidenerPath) accessWidenerPath.set(project(":common").extensions.getByType<LoomGradleExtensionAPI>().accessWidenerPath)
} }
mappingsDep = layered {
silentMojangMappingsLicense()
officialMojangMappings().parchment("org.parchmentmc.data:parchment-1.21:2024.06.23")
}
val refmap = "snowygui-${project.name}-refmap.json"
mixin {
useLegacyMixinAp = true
defaultRefmapName = refmap
}
} }
apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "com.gradleup.shadow")
val shadowC by configurations.creating val shadowC by configurations.creating
repositories { repositories {
maven(url = "https://jitpack.io"); mavenCentral() maven(url = "https://jitpack.io"); mavenCentral()
maven(url = "https://maven.parchmentmc.org")
} }
dependencies { dependencies {
implementation("$kotlinX:kotlinx-coroutines-jdk8:${rootProject.property("kotlin_coroutines_version")}") implementation("$kotlinX:kotlinx-coroutines-jdk8:${rootProject.property("kotlin_coroutines_version")}")
@ -80,20 +68,6 @@ subprojects {
"com.github.Vatuu:discord-rpc:1.6.2" "com.github.Vatuu:discord-rpc:1.6.2"
).forEach { implementation(it); shadowC(it) { isTransitive = false; exclude("com.sun.jna") } } ).forEach { implementation(it); shadowC(it) { isTransitive = false; exclude("com.sun.jna") } }
"minecraft"("com.mojang:minecraft:${rootProject.property("minecraft")}") "minecraft"("com.mojang:minecraft:${rootProject.property("minecraft")}")
"mappings"(mappingsDep)
}
apply(plugin = "com.modrinth.minotaur")
extensions.configure<ModrinthExtension>("modrinth") {
projectId.set("OuGyGg6A")
syncBodyFrom.set("$rootDir/README.md")
gameVersions.add(minecraftVersion)
if (project.name == "forge") dependencies.add(com.modrinth.minotaur.dependencies.ModDependency("ordsPcFz", DependencyType.REQUIRED)) // Kotlinforforge dependency
versionNumber.set(rootProject.version.toString() + "-${project.name}")
versionType.set(VersionType.ALPHA.name)
detectLoaders.set(false)
loaders.add(project.name)
versionName.set("${rootProject.name} ${rootProject.version}")
uploadFile.set(fileTree("$rootDir/remappedJars/").files.find { it.name.contains(project.name) })
} }
tasks { tasks {
apply(plugin = "net.kyori.indra.git") apply(plugin = "net.kyori.indra.git")
@ -111,14 +85,16 @@ subprojects {
exclude("**/*.kotlin_metadata") exclude("**/*.kotlin_metadata")
exclude("**/*.kotlin_builtins") exclude("**/*.kotlin_builtins")
exclude("META-INF/maven/**/*") exclude("META-INF/maven/**/*")
archiveClassifier.set("shadow-${this@subprojects.name}") archiveVersion.set("[${rootProject.version}+$minecraftVersion]")
archiveClassifier.set(this@subprojects.name)
destinationDirectory.set(file("$rootDir/jars"))
} }
val shadowJar = getByName("shadowJar") as ShadowJar val shadowJar = getByName("shadowJar") as ShadowJar
val shrinkJar = register("shrinkJar", proguard.gradle.ProGuardTask::class) { group = this@subprojects.group as String val shrinkJar = register("shrinkJar", proguard.gradle.ProGuardTask::class) { group = this@subprojects.group as String
val dictionariesDir = "$rootDir/obfuscation" val dictionariesDir = "$rootDir/obfuscation"
dependsOn(shadowJar) dependsOn(shadowJar)
injars(shadowJar) injars(shadowJar)
outjars("$buildDir/shrinkedJar/${shadowJar.outputs.files.singleFile.name}") outjars("$rootDir/jars/shrinkedJar/${shadowJar.outputs.files.singleFile.name}")
keep("class $group.snowygui.mixins.* { * ; }") keep("class $group.snowygui.mixins.* { * ; }")
keep("class $group.snowygui.fabric.FabricInit") keep("class $group.snowygui.fabric.FabricInit")
keep("class $group.snowygui.fabric.ModMenuConf") keep("class $group.snowygui.fabric.ModMenuConf")
@ -166,18 +142,7 @@ subprojects {
overloadaggressively() overloadaggressively()
mergeinterfacesaggressively() mergeinterfacesaggressively()
} }
withType(net.fabricmc.loom.task.RemapJarTask::class) { build.get().dependsOn(if (devBuild) shadowJar else shrinkJar)
dependsOn(shrinkJar)
val shrinkedJar = shrinkJar.get().outJarFileCollection.singleFile
archiveBaseName.set(shadowJar.archiveBaseName)
archiveVersion.set("[${rootProject.version}+$minecraftVersion]")
archiveClassifier.set(this@subprojects.name)
if (this@subprojects.name.contains("forge"))
atAccessWideners.set(listOf("${rootProject.name.lowercase()}.accessWidener"))
inputFile.set(shrinkedJar)
if (!archiveFileName.get().contains("common")) destinationDirectory.set(file("$rootDir/remappedJars"))
}
getByName("modrinth").dependsOn(build)
} }
} }
@ -201,19 +166,18 @@ allprojects {
} }
tasks { tasks {
withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) {
with(kotlinOptions) { compilerOptions {
// 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", "-jvm-default=enable", "-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", "-Xextended-compiler-checks", "-Xassertions=jvm", "-progressive" "-opt-in=kotlin.RequiresOptIn", "-Xassertions=jvm", "-progressive"
) )
jvmTarget = javaVer
// Uncomment when updating to architectury-loom 1.9
//languageVersion = (kotlinSplitVersion[0] + '.' + (kotlinSplitVersion[1].toShort() + 1).toString()) //languageVersion = (kotlinSplitVersion[0] + '.' + (kotlinSplitVersion[1].toShort() + 1).toString())
//apiVersion = "${kotlinSplitVersion[0]}.${kotlinSplitVersion[1]}" //apiVersion = "${kotlinSplitVersion[0]}.${kotlinSplitVersion[1]}"
} }
compilerOptions.jvmTarget.set(JvmTarget.fromTarget(javaVer))
} }
withType(JavaCompile::class) { withType(JavaCompile::class) {
with(options) { with(options) {
@ -232,7 +196,7 @@ allprojects {
} }
val modProperties = mapOf( val modProperties = mapOf(
"mod_version" to (rootProject.version as String), "mod_version" to (rootProject.version as String),
"minecraft_version" to minecraftVersion, "minecraft_version" to minecraftVersion.replace("snapshot-", "alpha."),
"java_version" to javaVer, "java_version" to javaVer,
"mod_group" to this@allprojects.group, "mod_group" to this@allprojects.group,
"fabric_kotlin" to rootProject.property("fabric_language_kotlin"), "fabric_kotlin" to rootProject.property("fabric_language_kotlin"),

View File

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

View File

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

View File

@ -4,7 +4,9 @@ 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>()
@ -17,28 +19,32 @@ 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(d: Double, e: Double, i: Int): Boolean { override fun mouseClicked(event: MouseButtonEvent, isDoubleClick: Boolean): Boolean {
if (i == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
clickBoxes.find { it.isWithinBounds(d, e) }?.let { draggingBox = it.name.string } clickBoxes.find { it.isWithinBounds(event.x, event.y) }?.let { draggingBox = it.name.string }
currentBoxContext { currentBoxContext {
offsetX = d - (x + width) offsetX = event.x - (x + width)
offsetY = e - (y + height) offsetY = event.y - (y + height)
} }
} }
buttonsContext { this.mouseClicked(d, e, i) }; return super.mouseClicked(d, e, i); buttonsContext { this.mouseClicked(event, isDoubleClick) }; return super.mouseClicked(event, isDoubleClick);
} }
override fun mouseReleased(d: Double, e: Double, i: Int): Boolean { draggingBox = null; buttonsContext { this.mouseReleased(d, e, i) }; return false } override fun mouseReleased(event: MouseButtonEvent): Boolean { draggingBox = null; buttonsContext { this.mouseReleased(event) }; 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, scrollY: Double): Boolean { boxContext { scroll(d, e, scrollY) }; return false }
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean { override fun mouseDragged(event: MouseButtonEvent, mouseX: Double, mouseY: Double): Boolean {
if (i == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
currentBoxContext { currentBoxContext {
x = (d + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble()) val targetX = (event.x + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble())
y = (e + offsetY).coerceIn(0.0..this@ClickGui.height - height.toDouble()) val targetY = (event.y + 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(d, e, i, f, g) return super.mouseDragged(event, mouseX, mouseY)
} }
} }

View File

@ -1,6 +1,6 @@
package fr.username404.snowygui package fr.username404.snowygui
import fr.username404.snowygui.config.Configuration import fr.username404.snowygui.config.LazyConfiguration
import fr.username404.snowygui.gui.feature.ButtonImpl import fr.username404.snowygui.gui.feature.ButtonImpl
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
@ -13,30 +13,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: Boolean by Configuration private val displayInitMessage: Lazy<Boolean> by LazyConfiguration
abstract val annotatedButtons: Set<Class<out ButtonImpl>> abstract val annotatedButtons: Lazy<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 FeaturePackage: String = "fr.username404.snowygui.gui.feature" protected const val FEATURE_PACKAGE: 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::get } init { Companion.annotatedButtons = { annotatedButtons.value } }
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) logs.info("Init point of SnowyGUI hit.") if (displayInitMessage.value) logs.info("Init point of SnowyGUI hit.")
eventsInit() eventsInit()
} }
} }

View File

@ -2,11 +2,11 @@ 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.*
import fr.username404.snowygui.utils.FontUtil import fr.username404.snowygui.utils.FontUtil
import net.minecraft.client.gui.GuiGraphics import me.shedaniel.clothconfig2.gui.entries.StringListListEntry
import net.minecraft.client.gui.GuiGraphicsExtractor as 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
import net.minecraft.network.chat.Component.translatable import net.minecraft.network.chat.Component.translatable
@ -23,14 +23,13 @@ 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 extractRenderState(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, pTick: Float) {
super.renderBackground(guiGraphics, mouseX, mouseY, pTick)
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
) )
} }
override fun onClose() { minecraft?.screen = configScreenParent } override fun onClose() = minecraft.gui.setScreen(configScreenParent)
}; get() = try { }; get() = try {
Class.forName("me.shedaniel.clothconfig2.api.ConfigBuilder") Class.forName("me.shedaniel.clothconfig2.api.ConfigBuilder")
val macrosBox: ClickBox? = ClickGui.components.find { val macrosBox: ClickBox? = ClickGui.components.find {
@ -75,9 +74,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()
).setInsertInFront(false).setDefaultValue(Configuration.foundMacros.getTitleCommand()).setErrorSupplier { list -> ).setCreateNewInstance {
supplyComponent(if (list.size > buttonsMax) "$confPrefix.general.macros.toomuchbuttons" else null) entry -> StringListListEntry.StringListCell("ExampleMacro: say hello", entry)
}.setCellErrorSupplier { cell -> }.setInsertInFront(false).setDefaultValue(Configuration.foundMacros.getTitleCommand()).setCellErrorSupplier { cell ->
with(cell.split(":")) { with(cell.split(":")) {
supplyComponent( supplyComponent(
when { when {

View File

@ -8,34 +8,29 @@ import com.typesafe.config.ConfigFactory.parseFile
import com.typesafe.config.ConfigFactory.parseString import com.typesafe.config.ConfigFactory.parseString
import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValueFactory import com.typesafe.config.ConfigValueFactory
import dev.architectury.injectables.targets.ArchitecturyTarget
import fr.username404.snowygui.ClickGui import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.Snowy import fr.username404.snowygui.Snowy
import fr.username404.snowygui.Snowy.Companion.MissingComponent import fr.username404.snowygui.Snowy.Companion.MissingComponent
import fr.username404.snowygui.gui.feature.shouldSave
import fr.username404.snowygui.gui.feature.Category import fr.username404.snowygui.gui.feature.Category
import fr.username404.snowygui.gui.feature.Macro import fr.username404.snowygui.gui.feature.Macro
import fr.username404.snowygui.gui.feature.shouldSave
import io.github.config4k.extract import io.github.config4k.extract
import io.github.config4k.getValue import io.github.config4k.getValue
import net.minecraft.client.Minecraft
import java.io.File
import kotlin.reflect.KProperty
import kotlinx.coroutines.CoroutineStart 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.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.TranslatableContents import net.minecraft.network.chat.contents.TranslatableContents
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import java.io.File
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.full.isSuperclassOf import kotlin.reflect.full.isSuperclassOf
@OptIn(ExperimentalSerializationApi::class)
object Configuration { object Configuration {
@Deprecated("Use the getValue or setValue methods instead", level = DeprecationLevel.ERROR) @Deprecated("Use the getValue or setValue methods instead", level = DeprecationLevel.ERROR)
@JvmStatic @JvmStatic
@ -54,7 +49,19 @@ object Configuration {
}.toTypedArray()), }.toTypedArray()),
) )
} }
private val configDirectory: String = (Minecraft.getInstance().gameDirectory.absolutePath + File.separator + "config").also { File(it).mkdir() } private val configDirectory: String =
(if (ArchitecturyTarget.getCurrentTarget() == "fabric") {
Class.forName("net.fabricmc.loader.api.FabricLoader").run {
getMethod("getConfigDir").invoke(getMethod("getInstance").invoke(null))
}
} else {
Class.forName("net.neoforged.fml.loading.FMLPaths")
.getField("CONFIGDIR")
.get(null)
.let { enum ->
enum.javaClass.getMethod("get").invoke(enum)
}
} as Path).absolutePathString()
private val file: File = File(configDirectory + File.separator + "snowy.conf") private val file: File = File(configDirectory + File.separator + "snowy.conf")
private val obtained: Config = run { private val obtained: Config = run {
var result: Config = empty() var result: Config = empty()
@ -87,11 +94,7 @@ object Configuration {
val enabledFeatures = mutableMapOf<String, Boolean>().apply { val enabledFeatures = mutableMapOf<String, Boolean>().apply {
"enabledFeatures".let { obtained.run { "enabledFeatures".let { obtained.run {
if (hasPath(it)) { if (hasPath(it)) {
putAll(extract<Map<out String, Boolean>>(it).filterKeys { keyName -> ClickGui.clickBoxes.any { putAll(extract<Map<out String, Boolean>>(it))
it.buttons.any { button ->
button.info.shouldSave() && button.title == keyName
}
}})
} }
} } } }
} }
@ -115,13 +118,13 @@ object Configuration {
) )
} }
private fun Config.withFullModifiableValues() = @Suppress("DEPRECATION_ERROR") private fun Config.withFullModifiableValues() = @Suppress("DEPRECATION_ERROR")
ModifiableValues.entries.fold(this) { previous, entry -> ModifiableValues.entries.fold(this) { previous, entry ->
previous.withValue(entry.key, entry.value.let { previous.withValue(entry.key, entry.value.let {
ConfigValueFactory.fromAnyRef( ConfigValueFactory.fromAnyRef(
if (it !is Lazy<*>) it else it.value if (it !is Lazy<*>) it else it.value
) )
}) })
} }
private suspend fun writeConfig(c: Config) = coroutineScope { private suspend fun writeConfig(c: Config) = coroutineScope {
launch(start = CoroutineStart.UNDISPATCHED) { launch(start = CoroutineStart.UNDISPATCHED) {
file.writeText( file.writeText(
@ -170,5 +173,11 @@ object Configuration {
convertValue(T::class) ?: throw e convertValue(T::class) ?: throw e
} }
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,10 +1,10 @@
package fr.username404.snowygui.gui package fr.username404.snowygui.gui
import com.mojang.blaze3d.vertex.* import com.mojang.blaze3d.vertex.VertexConsumer
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 net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
import net.minecraft.client.gui.components.events.GuiEventListener import net.minecraft.client.gui.components.events.GuiEventListener
fun interface Renderable { fun interface Renderable {
@ -58,8 +58,12 @@ abstract class ColoredElement(
} }
} }
} }
internal fun VertexConsumer.colorEnd(color: Int = this@ColoredElement.color) = colorIt(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,12 +1,12 @@
package fr.username404.snowygui.gui package fr.username404.snowygui.gui
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component.translatable import net.minecraft.network.chat.Component.translatable
abstract class SnowyScreen(translatableString: String = "screen.snowy.gui", private val willPauseScreen: Boolean = false): Screen(translatable(translatableString)) { abstract class SnowyScreen(translatableString: String = "screen.snowy.gui", private val willPauseScreen: Boolean = false): Screen(translatable(translatableString)) {
abstract val components: MutableCollection<Element> abstract val components: MutableCollection<Element>
override fun render(guiGraphics: GuiGraphics, i: Int, j: Int, f: Float) { override fun extractRenderState(guiGraphics: GuiGraphics, i: Int, j: Int, f: Float) {
components.forEach { components.forEach {
it.display(guiGraphics) it.display(guiGraphics)
} }

View File

@ -1,23 +1,21 @@
package fr.username404.snowygui.gui.elements package fr.username404.snowygui.gui.elements
import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.VertexFormat
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 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.colorShader import fr.username404.snowygui.utils.RenderingUtil
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.GuiGraphicsExtractor as 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
@ -27,7 +25,7 @@ class ClickBox(
x: Double, y: Double, x: Double, y: Double,
val name: Component = MissingComponent, val name: Component = MissingComponent,
override var color: Int = savedColors?.get(name.string) ?: Colors.BLUE.hexValue, override var color: Int = savedColors?.get(name.string) ?: Colors.BLUE.hexValue,
): ColoredElement(x, y, 80, 10, color, 0.5F) { ) : ColoredElement(x, y, 80, 10, color, 0.5F) {
fun isCategory(c: Category): Boolean = (name.string == c.box.name.string) fun isCategory(c: Category): Boolean = (name.string == c.box.name.string)
val buttons: MutableSet<ButtonImpl> = val buttons: MutableSet<ButtonImpl> =
if (sortAlphabetically) if (sortAlphabetically)
@ -46,24 +44,28 @@ 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?) {
prepareDraw() defaultRectFunc(guiGraphics)
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())) { if (!isWithinBounds(d, e, offsetHeight = clickboxHeightOffset.toDouble())) return
with(buttonsProgressBar) { if (buttons.isEmpty()) return
if ((height > 8 || (supplied < 0)) && (((height < (buttons.size * 8)) && (height < originalHeight)) || (supplied > 0))) {
height -= supplied.toInt() // This allows scrolling until only the last button is visible at the top
if (buttons.isNotEmpty()) (height / 8).let { val maxScroll = max(0, buttons.size - 1)
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 {
@ -73,58 +75,96 @@ 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: Float = 2.5F
} }
override fun render(guiGraphics: GuiGraphics?) { override fun render(guiGraphics: GuiGraphics?) {
val x = x.toFloat() val xi = floor(x).toInt()
val y = y.toFloat() val yi = floor(y).toInt()
val currentHeight = y + (height + clickboxHeightOffset)
prepareDraw()
with(tessellator.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)) {
// Render the header:
addVertex(x, y + height, 0.0F).colorEnd()
addVertex(x + width + inclination, y + height, 0.0F).colorEnd()
addVertex(x + width, y, 0.0F).colorEnd()
addVertex(x + inclination, y, 0.0F).colorEnd()
// Render the box: // Header
addVertex(x, currentHeight, 0.0F).colorEnd() RenderingUtil.drawSlantedHeader(
addVertex(x + width + inclination, currentHeight, 0.0F).colorEnd() guiGraphics = guiGraphics,
addVertex(x + width + inclination, y + height, 0.0F).colorEnd() x = xi,
BufferUploader.drawWithShader(buildOrThrow()) y = yi,
width = width,
height = height,
slantTop = inclination,
color = color,
opacity = opacity
)
colorShader() // Body
with(tessellator.begin(VertexFormat.Mode.DEBUG_LINES, DefaultVertexFormat.POSITION_COLOR)) { RenderingUtil.drawRectangle(
addVertex(x + inclination, y + height, 0.0F).colorEnd(Colors.WHITE_LINES.hexValue) guiGraphics = guiGraphics,
addVertex(x + width, y + height, 0.0F).colorEnd(Colors.WHITE_LINES.hexValue) x = xi.toDouble(),
BufferUploader.drawWithShader(buildOrThrow()) y = (yi + height).toDouble(),
} 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.x = this@ClickBox.x + this@ClickBox.width - 3 this.width = barWidth
this.y = this@ClickBox.y + this@ClickBox.height + 3 this.height = currentBarH.coerceAtMost(actualContentHeight)
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 fullHeight = (y + height.toDouble())..(this.y + height + clickboxHeightOffset) val rowOffset = num - barStage
val yPos = contentStartY + (rowOffset * 9)
button.also { button.also {
it.x = this.x + 3 it.x = (xi + leftPadding).toDouble()
it.y = this.y + 3 + height + (((num + 1) - barStage) * 9) it.y = yPos.toDouble()
it.hidden = if ((num + 1) <= 8) ((it.y) !in fullHeight) else ((it.y + it.height) !in fullHeight) it.width = buttonWidth
it.hidden = (rowOffset < 0) || (yPos + it.height > maxContentY)
}.display(guiGraphics) }.display(guiGraphics)
} }
} }
guiGraphics?.run {
with(Minecraft.getInstance().font) { with(Minecraft.getInstance().font) {
drawInBatch(Component.nullToEmpty(name.string), guiGraphics?.text(
(x + 5), (y + 2), Colors.TRANSPARENT.hexValue, false, this,
pose().last().pose(), bufferSource, Font.DisplayMode.NORMAL, 0, 15728880, isBidirectional Component.nullToEmpty(name.string),
) (xi + 5 + (inclination / 2f)).toInt(),
} (yi + 2),
ARGB.opaque(Colors.WHITE.hexValue),
false
)
} }
} }
} }

View File

@ -6,10 +6,8 @@ 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 net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
import fr.username404.snowygui.utils.RenderingUtil.endDraw import net.minecraft.client.input.MouseButtonEvent
import fr.username404.snowygui.utils.RenderingUtil.prepareDraw
import net.minecraft.client.gui.GuiGraphics
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) {
@ -17,25 +15,20 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
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 ->
with(impl) { box.isCategory(impl.info.parent)
}
}.entries.forEach { entry -> entry.run {
key?.buttons?.clear()
value.forEach { if (!it.isDisabled) {
key?.buttons?.add(it.apply {
if (info.shouldSave() && !info.parent.shouldHide) { if (info.shouldSave() && !info.parent.shouldHide) {
Configuration.enabledFeatures[title]?.let { bool -> Configuration.enabledFeatures[title]?.let { bool ->
toggled = bool toggled = bool
} }
} }
box.isCategory(info.parent) })
} } }
} } }
}.entries.forEach { entry ->
with(entry) {
key?.buttons?.clear()
value.forEach {
if (!it.isDisabled) {
key?.buttons?.add(it)
}
}
}
}
} }
@JvmStatic @JvmStatic
fun initButtons() = addButtons( fun initButtons() = addButtons(
@ -50,20 +43,26 @@ 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()
@ -71,10 +70,12 @@ 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 {
wasWithinBounds = isWithinBounds(d, e).also { final override fun mouseClicked(event: MouseButtonEvent, isDoubleClick: Boolean): Boolean {
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
@ -84,16 +85,16 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
return false return false
} }
final override fun mouseReleased(d: Double, e: Double, i: Int): Boolean { final override fun mouseReleased(event: MouseButtonEvent): 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?) {
prepareDraw() defaultRectFunc(guiGraphics)
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,11 +3,16 @@ 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.gui.GuiGraphics import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
sealed class ButtonImplWithHud: ButtonImpl() { sealed class ButtonImplWithHud: ButtonImpl() {
protected abstract val hudRenderLambda: Renderable protected abstract val hudRenderLambda: Renderable
private val generatedLambda: argsLambda = { hudRenderLambda.render(it.first() as GuiGraphics?) } private val generatedLambda: argsLambda = {
if (!Minecraft.getInstance().gui.hud.isHidden) {
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? = values().find { fun fromBox(box: ClickBox): Category? = entries.find {
box.isCategory(it) box.isCategory(it)
} }
} }

View File

@ -9,12 +9,13 @@ import net.arikia.dev.drpc.DiscordRPC as discord_rpc
@ButtonInfo(Category.MISC) @ButtonInfo(Category.MISC)
object DiscordRPC: ButtonImpl() { object DiscordRPC: ButtonImpl() {
private val RPCHandlers: DiscordEventHandlers = DiscordEventHandlers.Builder().build() private val RPCHandlers: DiscordEventHandlers = DiscordEventHandlers.Builder().build()
private val RichPresence: DiscordRichPresence.Builder = DiscordRichPresence private val RichPresence: Lazy<DiscordRichPresence.Builder> = lazy { DiscordRichPresence
.Builder("Playing Minecraft ${Minecraft.getInstance().launchedVersion}") .Builder("Playing Minecraft ${Minecraft.getInstance().launchedVersion}")
.setDetails("Launched with ${Minecraft.getInstance().versionType}") .setDetails("Launched with ${Minecraft.getInstance().versionType}")
.setBigImage("icon", "SnowyGUI") .setBigImage("icon", "SnowyGUI")
}
override fun execAction() { override fun execAction() {
if (toggled) discord_rpc.discordUpdatePresence(RichPresence.build()) if (toggled) discord_rpc.discordUpdatePresence(RichPresence.value.build())
else discord_rpc.discordClearPresence() else discord_rpc.discordClearPresence()
} }
init { init {

View File

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

View File

@ -6,7 +6,7 @@ import fr.username404.snowygui.gui.Renderable
import fr.username404.snowygui.utils.FontUtil import fr.username404.snowygui.utils.FontUtil
import fr.username404.snowygui.utils.RenderingUtil import fr.username404.snowygui.utils.RenderingUtil
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
@ButtonInfo(Category.HUD) @ButtonInfo(Category.HUD)
object Keystrokes: ButtonImplWithHud() { object Keystrokes: ButtonImplWithHud() {
@ -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(
x, y, height / 2, height / 2, guiGraphics, 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.values().map { it.value }.contains(currentPosition)) { if (!Position.entries.map { it.value }.contains(currentPosition)) {
currentPosition = Position.LEFT.value currentPosition = Position.LEFT.value
} }
} }

View File

@ -3,6 +3,7 @@ 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
@ -17,7 +18,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") && !hasPermissions(2)) { if (it.startsWith("say") && !this@with.permissions().hasPermission(Permissions.COMMANDS_GAMEMASTER)) {
sendChat(it.drop(4)) sendChat(it.drop(4))
} else sendCommand(it) } else sendCommand(it)
} }

View File

@ -6,25 +6,34 @@ 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 = "keycategory", key: Int, category: String = "controls",
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, "category.$prefix.$category" key, this.category ?: run {
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(
mkMap("opengui", GLFW_KEY_Y) { setScreen(ClickGui) }, mkMap("opengui", GLFW_KEY_Y) { Minecraft.getInstance().setScreenAndShow(ClickGui) },
mkMap("configkey", GLFW_KEY_U) { setScreen(run { configScreenParent = null; SnowyConfigScreen }) } mkMap("configkey", GLFW_KEY_U) {
configScreenParent = null
Minecraft.getInstance().setScreenAndShow(SnowyConfigScreen)
}
) )
} }
} }

View File

@ -2,14 +2,19 @@ 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.GuiGraphicsExtractor as 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, scaleFactor) stack.scale(scaleFactor, scaleFactor)
guiGraphics.drawString(Minecraft.getInstance().font, text, (x / scaleFactor).toInt(), (y / scaleFactor).toInt(), color.hexValue, false) guiGraphics.text(
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, factorToOriginal) stack.scale(factorToOriginal, factorToOriginal)
} }
} }

View File

@ -1,43 +1,103 @@
package fr.username404.snowygui.utils package fr.username404.snowygui.utils
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferUploader
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 fr.username404.snowygui.gui.hextoRGB import net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
import net.minecraft.client.renderer.CoreShaders import net.minecraft.util.ARGB
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
object RenderingUtil { object RenderingUtil {
@JvmField val tessellator: Tesselator = Tesselator.getInstance() fun prepareDraw() = Unit
@JvmStatic fun endDraw() = Unit
fun VertexConsumer.colorIt(color: Int, opacity: Float = 1F): VertexConsumer = hextoRGB(color).run {
setColor(get(0), get(1), get(2), opacity) private fun argbFromRgb(rgb: Int, opacity: Float = 1f): Int {
} return ARGB.color(
fun colorShader() { (opacity.coerceIn(0f, 1f) * 255f).toInt().coerceIn(0, 255),
RenderSystem.setShader(CoreShaders.POSITION_COLOR) (rgb shr 16) and 0xFF,
RenderSystem.setShaderColor(1F, 1F, 1F, 1F) (rgb shr 8) and 0xFF,
} rgb and 0xFF
fun prepareDraw() { )
colorShader()
RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc()
}
fun endDraw() {
RenderSystem.disableBlend()
} }
fun drawRectangle( fun drawRectangle(
x: Double, y: Double, height: Int, width: Int, guiGraphics: GuiGraphics?,
color: Int = Colors.TRANSPARENT(), opacity: Float = 1F x: Double,
): Unit = tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR).run { y: Double,
fun VertexConsumer.colorIt() = colorIt(color, opacity) height: Int,
val x = x.toFloat() ; val y = y.toFloat() width: Int,
addVertex(x, y + height, 0.0F).colorIt() color: Int = Colors.TRANSPARENT(),
addVertex(x + width, y + height, 0.0F).colorIt() opacity: Float = 1F
addVertex(x + width, y, 0.0F).colorIt() ) {
addVertex(x, y, 0.0F).colorIt() if (guiGraphics == null) return
BufferUploader.drawWithShader(buildOrThrow())
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.horizontalLine(x1, x2, y, argbFromRgb(rgb, opacity))
endDraw()
} }
} }

View File

@ -7,14 +7,13 @@
"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",
"category.snowy.keycategory": "SnowyGUI", "key.category.snowygui.controls": "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,14 +7,13 @@
"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",
"category.snowy.keycategory": "SnowyGUI", "key.category.snowygui.controls": "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

@ -2,10 +2,11 @@
"required": true, "required": true,
"package": "fr.username404.snowygui.mixins", "package": "fr.username404.snowygui.mixins",
"compatibilityLevel": "JAVA_18", "compatibilityLevel": "JAVA_18",
"client": [], "client": [
"GammaMixin"
],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1
}, },
"minVersion": "0.8", "minVersion": "0.8"
"refmap": "snowygui-common-refmap.json"
} }

View File

@ -1,6 +1,3 @@
accessWidener v2 named accessWidener v2 official
accessible field net/minecraft/client/OptionInstance value Ljava/lang/Object; accessible method net/minecraft/client/KeyMapping$Category register (Ljava/lang/String;)Lnet/minecraft/client/KeyMapping$Category;
mutable field net/minecraft/client/OptionInstance value Ljava/lang/Object;
accessible field net/minecraft/client/gui/GuiGraphics bufferSource Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;

View File

@ -13,17 +13,17 @@ object Groups {
architectury { platformSetupLoomIde(); fabric() } architectury { platformSetupLoomIde(); fabric() }
dependencies { dependencies {
modImplementation("${Groups.Fabric}:fabric-loader:${rootProject.property("fabric_loader_version")}") implementation("${Groups.Fabric}:fabric-loader:${rootProject.property("fabric_loader_version")}")
include(modApi("${Groups.FabricApi}:fabric-rendering-v1:${rootProject.property("fabric_rendering_api_version")}")!!) api("${Groups.FabricApi}:fabric-rendering-v1:${rootProject.property("fabric_rendering_api_version")}")
include(modApi("${Groups.FabricApi}:fabric-api-base:${rootProject.property("fabric_api_base_version")}")!!) api("${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) } api("me.shedaniel.cloth:cloth-config-fabric:${rootProject.property("clothconfig_version")}") { exclude(group = Groups.FabricApi) }
include(modImplementation("${Groups.FabricApi}:fabric-resource-loader-v0:${rootProject.property("fabric_resource_loader_version")}")!!) implementation("${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) implementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = rootProject.property("fabric_language_kotlin") as String)
modImplementation("com.terraformersmc:modmenu:${rootProject.property("modmenu_version")}") { implementation("com.terraformersmc:modmenu:${rootProject.property("modmenu_version")}") {
exclude(group = Groups.FabricApi, module = "fabric-api-base") exclude(group = Groups.FabricApi, module = "fabric-api-base")
exclude(group = Groups.FabricApi, module = "fabric-resource-loader-v0") exclude(group = Groups.FabricApi, module = "fabric-resource-loader-v0")
} }
implementation(project(path = ":common", configuration = "namedElements")) { isTransitive = false } implementation(project(path = ":common")) { isTransitive = false }
add("developmentFabric", project(path = ":common")) { isTransitive = false } add("developmentFabric", project(path = ":common")) { isTransitive = false }
shadowC(project(path = ":common", configuration = "transformProductionFabric")) { isTransitive = false } shadowC(project(path = ":common", configuration = "transformProductionFabric")) { isTransitive = false }
} }

View File

@ -25,14 +25,11 @@ 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 categoryMap = KeysAccessor.getSortedCategoryMap(); final var categoryList = KeysAccessor.getSortedCategoryList();
var newKeys = Lists.newArrayList(keyMappings); var newKeys = Lists.newArrayList(keyMappings);
for (KeyMapping key : keysToAdd) { for (KeyMapping key : keysToAdd) {
if (!categoryMap.containsKey(key.getCategory())) { if (!categoryList.contains(key.getCategory()))
Optional<Integer> biggest = categoryMap.values().stream().max(Integer::compareTo); categoryList.add(key.getCategory());
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.Map; import java.util.List;
@Mixin(KeyMapping.class) @Mixin(KeyMapping.Category.class)
public interface KeysAccessor { public interface KeysAccessor {
@Accessor("CATEGORY_SORT_ORDER") @Accessor("SORT_ORDER")
static Map<String, Integer> getSortedCategoryMap() { throw new AssertionError(); } static List<KeyMapping.Category> getSortedCategoryList() { throw new AssertionError(); }
} }

View File

@ -1,20 +1,19 @@
package fr.username404.snowygui.mixins; package fr.username404.snowygui.mixins;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import fr.username404.snowygui.fabric.OkZoomerCompatKt; import fr.username404.snowygui.fabric.OkZoomerCompatKt;
import fr.username404.snowygui.gui.feature.Zoom; import fr.username404.snowygui.gui.feature.Zoom;
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
import net.minecraft.client.renderer.GameRenderer;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
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.callback.CallbackInfoReturnable;
@Mixin(GameRenderer.class) @Mixin(Camera.class)
abstract class ZoomMixin { abstract class ZoomMixin {
@Inject(at = @At(value = "RETURN"), method = "getFov(Lnet/minecraft/client/Camera;FZ)F", cancellable = true) @ModifyReturnValue(at = @At(value = "RETURN"), method = "calculateFov")
private void getFov(Camera camera, float f, boolean bl, CallbackInfoReturnable<Float> cir) { private static float getFov(float original) {
if (Zoom.INSTANCE.getToggled() && !OkZoomerCompatKt.isOkZoomerPresent) { if (Zoom.INSTANCE.getToggled() && !OkZoomerCompatKt.isOkZoomerPresent) {
cir.setReturnValue(Zoom.getNewZoom(cir.getReturnValue())); return Zoom.getNewZoom(original);
} }
return original;
} }
} }

View File

@ -4,11 +4,13 @@ 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
import net.fabricmc.api.ClientModInitializer import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElement
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback.EVENT import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry
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.DeltaTracker
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphicsExtractor as GuiGraphics
import net.minecraft.resources.Identifier
import kotlin.io.path.exists import kotlin.io.path.exists
import kotlin.io.path.isDirectory import kotlin.io.path.isDirectory
import kotlin.io.path.listDirectoryEntries import kotlin.io.path.listDirectoryEntries
@ -18,23 +20,28 @@ import kotlin.jvm.optionals.getOrNull
class FabricInit: Snowy(), ClientModInitializer { class FabricInit: Snowy(), ClientModInitializer {
override fun onInitializeClient() { override fun onInitializeClient() {
atInit() atInit()
EVENT.register( HudElementRegistry.addLast(Identifier.fromNamespaceAndPath("snowygui", "hud"),
object: HudRenderCallback, EventSnowy { object: HudElement, EventSnowy {
override val type: String = "HudRender" override val type: String = "HudRender"
override fun onHudRender(guiGraphics: GuiGraphics?, tickCounter: DeltaTracker?) = fire(guiGraphics) override fun extractRenderState(guiGraphics: GuiGraphics, tickCounter: DeltaTracker) = fire(guiGraphics)
} }
) )
} }
override val annotatedButtons = FabricLoader.getInstance().allMods.mapNotNull { override val annotatedButtons = lazy {
it.findPath(FeaturePackage.replace('.', '/')).getOrNull() FabricLoader.getInstance().allMods.mapNotNull {
}.filter { it.exists() && it.isDirectory() }.flatMap { buttonsDirectory -> it.findPath(FEATURE_PACKAGE.replace('.', '/')).getOrNull()
mutableSetOf<Class<out ButtonImpl>>().apply { }.filter { it.exists() && it.isDirectory() }.flatMap { buttonsDirectory ->
buttonsDirectory.listDirectoryEntries("*.class").forEach { file -> buttonsDirectory.listDirectoryEntries("*.class").mapNotNull { file ->
@Suppress("DEPRECATION") net.fabricmc.loader.launch.common. @Suppress("DEPRECATION")
FabricLauncherBase.getClass(file.pathString.drop(1).replace('/', '.').removeSuffix(".class")).let { foundClass -> FabricLauncherBase.getClass(
if (foundClass.isValidForButtonCollection()) add(foundClass.asSubclass(ButtonImpl::class.java)) file.pathString.drop(1)
.replace('/', '.').removeSuffix(".class")
).let { foundClass ->
if (foundClass.isValidForButtonCollection())
foundClass.asSubclass(ButtonImpl::class.java)
else null
} }
} }
} }.toSet()
}.toSet() }
} }

View File

@ -4,20 +4,13 @@ import fr.username404.snowygui.gui.feature.Zoom
import net.fabricmc.loader.api.FabricLoader import net.fabricmc.loader.api.FabricLoader
@JvmField @JvmField
var isOkZoomerPresent: Boolean = FabricLoader.getInstance().isModLoaded("okzoomer") var isOkZoomerPresent: Boolean = FabricLoader.getInstance().isModLoaded("ok_zoomer")
private val okZoomerPairs by lazy {
with(Class.forName("io.github.ennuil.okzoomer.utils.ZoomUtils").getDeclaredField("ZOOMER_ZOOM")) {
get(null).javaClass.run {
(getDeclaredField("zoomDivisor") to this@with.get(null)) to (getDeclaredField("zoom") to this@with.get(null))
}
}.apply { first.first.isAccessible = true; second.first.isAccessible = true; }
}
fun fabricZoom() { fun fabricZoom() {
try { try {
with(okZoomerPairs) { with(Class.forName("page.langeweile.ok_zoomer.zoom.Zoom")) {
first.run { first.setFloat(second, Zoom.zoomFactor.toFloat()) } getDeclaredMethod("setZoomDivisor", Double::class.java)(null, Zoom.zoomFactor);
second.run { first.setBoolean(second, Zoom.toggled) } getDeclaredMethod("setZooming", Boolean::class.java)(null, Zoom.toggled)
} }
} catch (e: Exception) { } catch (e: Exception) {
isOkZoomerPresent = false isOkZoomerPresent = false

View File

@ -38,7 +38,7 @@
"fabric-language-kotlin": ">=${fabric_kotlin}", "fabric-language-kotlin": ">=${fabric_kotlin}",
"fabric-resource-loader-v0": "*", "fabric-resource-loader-v0": "*",
"fabric-rendering-v1": "*", "fabric-rendering-v1": "*",
"minecraft": ">=1.19-alpha.22.16.b" "minecraft": ">=${minecraft_version}"
}, },
"recommends": { "recommends": {
"cloth-config2": ">=${clothconfig}" "cloth-config2": ">=${clothconfig}"

View File

@ -1,22 +1,23 @@
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:+UseShenandoahGC -XX:+AlwaysPreTouch org.gradle.jvmargs=-Xmx2G -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -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.2 minecraft=26.2-snapshot-1
forge_version=21.2.1-beta # TODO: 26.2.0.1-beta
kotlinforforge=5.7.0 forge_version=26.1.0.19-beta
kotlinVer=2.1.0 kotlinforforge=6.2.0
kotlin_coroutines_version=1.9.0 kotlinVer=2.3.10
serializationVer=1.7.3 kotlin_coroutines_version=1.10.2
fabric_loader_version=0.14.20 serializationVer=1.10.0
fabric_language_kotlin=1.13.0+kotlin.2.1.0 fabric_loader_version=0.19.1
fabric_resource_loader_version=3.0.5+c47b9d4373 fabric_language_kotlin=1.13.9+kotlin.2.3.10
fabric_rendering_api_version=8.0.5+c47b9d4373 fabric_resource_loader_version=3.3.16+4fc5413f92
fabric_api_base_version=0.4.48+c47b9d4373 fabric_rendering_api_version=23.0.5+086d547a92
clothconfig_version=16.0.143 fabric_api_base_version=2.0.3+ece0632392
modmenu_version=12.0.0 clothconfig_version=26.1.154
modmenu_version=18.0.0-alpha.8

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-rc-1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-rc-2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -10,8 +10,8 @@ dependencies {
return@let if (it.length > 4) it else "$it.+" return@let if (it.length > 4) it else "$it.+"
}}") }}")
implementation("thedarkcolour:kotlinforforge:${rootProject.property("kotlinforforge")}") implementation("thedarkcolour:kotlinforforge:${rootProject.property("kotlinforforge")}")
modApi("me.shedaniel.cloth:cloth-config-neoforge:${rootProject.property("clothconfig_version")}") api("me.shedaniel.cloth:cloth-config-neoforge:${rootProject.property("clothconfig_version")}")
implementation(project(path = ":common", configuration = "namedElements")) { isTransitive = false } implementation(project(path = ":common")) { isTransitive = false }
add("developmentNeoForge", project(path = ":common")) { isTransitive = false } add("developmentNeoForge", project(path = ":common")) { isTransitive = false }
shadowC(project(path = ":common", configuration = "transformProductionNeoForge")) { isTransitive = false } shadowC(project(path = ":common", configuration = "transformProductionNeoForge")) { isTransitive = false }

View File

@ -1,5 +1,6 @@
package fr.username404.snowygui.forge package fr.username404.snowygui.forge
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.Snowy import fr.username404.snowygui.Snowy
import fr.username404.snowygui.config.SnowyConfigScreen import fr.username404.snowygui.config.SnowyConfigScreen
import fr.username404.snowygui.config.configScreenParent import fr.username404.snowygui.config.configScreenParent
@ -11,22 +12,29 @@ import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent
import net.neoforged.neoforge.client.gui.IConfigScreenFactory import net.neoforged.neoforge.client.gui.IConfigScreenFactory
import net.neoforged.neoforge.common.NeoForge import net.neoforged.neoforge.common.NeoForge
import net.neoforged.neoforgespi.language.ModFileScanData import net.neoforged.neoforgespi.language.ModFileScanData
import org.objectweb.asm.Type
@Mod("snowygui") @Mod("snowygui")
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
class ForgeInit(container: ModContainer): Snowy() { class ForgeInit(container: ModContainer): Snowy() {
private fun initSetup(event: FMLClientSetupEvent) = atInit() private fun initSetup(event: FMLClientSetupEvent) {
override val annotatedButtons = ModList.get() // Forge-specific reflection atInit()
.allScanData ClickGui.tick()
.flatMap { obj: ModFileScanData -> obj.classes } ButtonImpl.initButtons()
.filter { data: ModFileScanData.ClassData? -> }
(data!!.javaClass.getDeclaredField("clazz").apply { isAccessible = true }.get(data) as Type).className.let { classname -> override val annotatedButtons = lazy { // Forge-specific reflection
classname.startsWith(FeaturePackage) && Class.forName(classname).isValidForButtonCollection() ModList.get()
.allScanData
.flatMap { obj: ModFileScanData -> obj.classes }
.filter { data: ModFileScanData.ClassData? ->
data!!.clazz.className.startsWith(FEATURE_PACKAGE)
} }
} .mapNotNull {
.map { Class.forName((it!!.javaClass.getDeclaredField("clazz").apply { isAccessible = true }.get(it) as Type).className).asSubclass(ButtonImpl::class.java)} Class.forName((it!!.clazz.className), false, this::class.java.classLoader).run {
.toSet() takeIf { isValidForButtonCollection() }
}?.asSubclass(ButtonImpl::class.java)
}
.toSet()
}
init { init {
container.eventBus!!.run { container.eventBus!!.run {
addListener(this@ForgeInit::initSetup) addListener(this@ForgeInit::initSetup)

View File

@ -1,18 +1,10 @@
package fr.username404.snowygui.forge package fr.username404.snowygui.forge
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.gui.feature.ButtonImpl
import fr.username404.snowygui.misc.AddKeyMaps import fr.username404.snowygui.misc.AddKeyMaps
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent
import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent
object MiscModBusHandlers { object MiscModBusHandlers {
@SubscribeEvent
fun handleClickGuiInit(event: RegisterMenuScreensEvent) {
ClickGui.tick()
ButtonImpl.initButtons()
}
@SubscribeEvent @SubscribeEvent
fun handleKeys(event: RegisterKeyMappingsEvent) { fun handleKeys(event: RegisterKeyMappingsEvent) {
AddKeyMaps.list.forEach { AddKeyMaps.list.forEach {

View File

@ -19,6 +19,7 @@ mandatory = false
versionRange = "[${clothconfig},)" versionRange = "[${clothconfig},)"
ordering = "BEFORE" ordering = "BEFORE"
side = "CLIENT" side = "CLIENT"
type = "optional"
[[dependencies.snowygui]] [[dependencies.snowygui]]
modId = "neoforge" modId = "neoforge"

View File

@ -11,7 +11,7 @@ pluginManagement {
include("common") include("common")
include("fabric") include("fabric")
include("neoforge") //include("neoforge")
rootProject.name = "SnowyGUI" rootProject.name = "SnowyGUI"