Compare commits

..

No commits in common. "1.20" and "1.19.4" have entirely different histories.
1.20 ... 1.19.4

17 changed files with 101 additions and 122 deletions

View File

@ -13,11 +13,11 @@ buildscript {
}
plugins {
kotlin("jvm") version "1.9.24"
kotlin("plugin.serialization") version "1.9.24"
kotlin("jvm") version "1.9.22"
kotlin("plugin.serialization") version "1.9.22"
id("com.github.johnrengelman.shadow") version "8.1.1" apply false
id("architectury-plugin") version "[3.4.124, 3.5["
id("dev.architectury.loom") version "1.5-SNAPSHOT" apply false
id("dev.architectury.loom") version "1.4-SNAPSHOT" apply false
id("com.github.ben-manes.versions") version "0.51.0"
id("net.kyori.indra.git") version "3.1.3"
id("org.cqfn.diktat.diktat-gradle-plugin") version "1.2.5"
@ -25,7 +25,7 @@ plugins {
}
group = "fr.username404"
version = "0.3.7"
version = "0.3.4"
val groupAndName = "${rootProject.group}.${rootProject.name.toLowerCase()}"
val javaVer: String = "17"
@ -51,7 +51,7 @@ subprojects {
apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
extensions.configure<LoomGradleExtension>("loom") {
mappingsDep = layered {
officialMojangMappings().parchment("org.parchmentmc.data:parchment-1.20.1:2023.06.26")
officialMojangMappings().parchment("org.parchmentmc.data:parchment-1.19.4:2023.06.26")
}
silentMojangMappingsLicense()
val refmap = "snowygui-${project.name}-refmap.json"
@ -75,8 +75,8 @@ subprojects {
implementation("$kotlinX:kotlinx-serialization-core:$serializationVer")
implementation("$kotlinX:kotlinx-serialization-json:$serializationVer")
listOf(
"com.typesafe:config:1.4.3",
"io.github.config4k:config4k:0.6.0",
"com.typesafe:config:1.4.2",
"io.github.config4k:config4k:0.5.0",
"com.github.Vatuu:discord-rpc:1.6.2"
).forEach { implementation(it); shadowC(it) { isTransitive = false; exclude("com.sun.jna") } }
"minecraft"("com.mojang:minecraft:${rootProject.property("minecraft")}")

View File

@ -1,4 +1,4 @@
architectury { common("fabric", "forge"); injectInjectables = true }
architectury { common("fabric", "forge"); injectInjectables = false }
dependencies {
modImplementation("net.fabricmc:fabric-loader:${rootProject.property("fabric_loader_version")}")
modImplementation("me.shedaniel.cloth:cloth-config:${rootProject.property("clothconfig_version")}") {

View File

@ -14,29 +14,17 @@ object ClickGui: SnowyScreen() {
private inline fun buttonsContext(args: ColoredElement.() -> Unit) = boxContext { buttons.forEach {
if (it.y > y + height) it.args()
} }
private var draggingBox: String? = null
private inline fun currentBoxContext(args: ClickBox.() -> Unit): Unit? = draggingBox?.run { boxContext { if (name.string == draggingBox) args() } }
private var offsetX: Double = 0.0;
private var offsetY: Double = 0.0;
override fun mouseClicked(d: Double, e: Double, i: Int): Boolean {
if (i == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
clickBoxes.find { it.isWithinBounds(d, e) }?.let { draggingBox = it.name.string }
currentBoxContext {
offsetX = d - (x + width)
offsetY = e - (y + height)
}
}
buttonsContext { this.mouseClicked(d, e, i) }; return super.mouseClicked(d, e, i);
}
override fun mouseReleased(d: Double, e: Double, i: Int): Boolean { draggingBox = null; buttonsContext { this.mouseReleased(d, e, i) }; return false }
override fun mouseClicked(d: Double, e: Double, i: Int): Boolean { buttonsContext { this.mouseClicked(d, e, i) }; return false }
override fun mouseReleased(d: Double, e: Double, i: Int): Boolean { buttonsContext { this.mouseReleased(d, e, i) }; return false }
override fun mouseScrolled(d: Double, e: Double, f: Double): Boolean { boxContext { scroll(d, e, f) }; return false }
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
if (i == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
currentBoxContext {
x = (d + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble())
y = (e + offsetY).coerceIn(0.0..this@ClickGui.height - height.toDouble())
components.forEach {
if (it.isWithinBounds(d.minus(f), e.minus(g)) && !isDragging) {
isDragging = true
it.x = d.minus(f) + (d - (it.x + it.width))
it.y = e.minus(g) + (e - (it.y + it.height))
} else isDragging = false
}
}
return super.mouseDragged(d, e, i, f, g)

View File

@ -1,6 +1,8 @@
package fr.username404.snowygui.config
import com.mojang.blaze3d.vertex.PoseStack
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.utils.FontUtil
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
@ -9,8 +11,6 @@ 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 net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.Component.translatable
@ -27,9 +27,9 @@ private fun supplyComponent(string: String?): Optional<Component> = string?.run
val SnowyConfigScreen: Screen = object: Screen(translationComponent) {
override fun isPauseScreen(): Boolean = false
override fun render(guiGraphics: GuiGraphics, i: Int, j: Int, f: Float) {
super.renderBackground(guiGraphics)
FontUtil.drawScaled(guiGraphics,
override fun render(poseStack: PoseStack, i: Int, j: Int, f: Float) {
super.renderBackground(poseStack)
FontUtil.drawScaled(poseStack,
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
)

View File

@ -8,30 +8,34 @@ import com.typesafe.config.ConfigFactory.parseFile
import com.typesafe.config.ConfigFactory.parseString
import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValueFactory
import dev.architectury.injectables.targets.ArchitecturyTarget
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.Snowy
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.Macro
import fr.username404.snowygui.gui.feature.shouldSave
import io.github.config4k.extract
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.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.TranslatableContents
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.KProperty
import kotlin.reflect.full.isSuperclassOf
@OptIn(ExperimentalSerializationApi::class)
object Configuration {
@Deprecated("Use the getValue or setValue methods instead", level = DeprecationLevel.ERROR)
@JvmStatic
@ -50,19 +54,7 @@ object Configuration {
}.toTypedArray()),
)
}
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.minecraftforge.fml.loading.FMLPaths")
.getField("CONFIGDIR")
.get(null)
.let { enum ->
enum.javaClass.getMethod("get").invoke(enum)
}
} as Path).absolutePathString()
private val configDirectory: String = (Minecraft.getInstance().gameDirectory.absolutePath + File.separator + "config").also { File(it).mkdir() }
private val file: File = File(configDirectory + File.separator + "snowy.conf")
private val obtained: Config = run {
var result: Config = empty()
@ -95,7 +87,11 @@ object Configuration {
val enabledFeatures = mutableMapOf<String, Boolean>().apply {
"enabledFeatures".let { obtained.run {
if (hasPath(it)) {
putAll(extract<Map<out String, Boolean>>(it))
putAll(extract<Map<out String, Boolean>>(it).filterKeys { keyName -> ClickGui.clickBoxes.any {
it.buttons.any { button ->
button.info.shouldSave() && button.title == keyName
}
}})
}
} }
}

View File

@ -5,11 +5,10 @@ import fr.username404.snowygui.Snowy
import fr.username404.snowygui.gui.feature.Colors
import fr.username404.snowygui.utils.RenderingUtil
import fr.username404.snowygui.utils.RenderingUtil.colorEnd
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.events.GuiEventListener
fun interface Renderable {
fun render(guiGraphics: GuiGraphics?)
fun render(poseStack: PoseStack?)
}
abstract class Element(
@ -29,13 +28,13 @@ abstract class Element(
private var caughtError: Boolean = false
fun fromRenderable(r: Renderable, x: Double, y: Double, width: Int, height: Int): Element {
return object: Element(x, y, width, height) {
override fun render(guiGraphics: GuiGraphics?) = r.render(guiGraphics)
override fun render(poseStack: PoseStack?) = r.render(poseStack)
}
}
}
open fun display(guiGraphics: GuiGraphics? = null) {
open fun display(stack: PoseStack? = null) {
if (!hidden && !caughtError) try {
render(guiGraphics)
render(stack)
} catch (t: Throwable) {
with(Snowy.logs) {
error("An element from snowy threw an error: \n\t$t")

View File

@ -1,14 +1,14 @@
package fr.username404.snowygui.gui
import net.minecraft.client.gui.GuiGraphics
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component.translatable
abstract class SnowyScreen(translatableString: String = "screen.snowy.gui", private val willPauseScreen: Boolean = false): Screen(translatable(translatableString)) {
abstract val components: MutableCollection<Element>
override fun render(guiGraphics: GuiGraphics, i: Int, j: Int, f: Float) {
override fun render(poseStack: PoseStack, i: Int, j: Int, f: Float) {
components.forEach {
it.display(guiGraphics)
it.display(poseStack)
}
}
override fun isPauseScreen(): Boolean = willPauseScreen

View File

@ -1,6 +1,7 @@
package fr.username404.snowygui.gui.elements
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import fr.username404.snowygui.Snowy.Companion.MissingComponent
import fr.username404.snowygui.config.Configuration
import com.mojang.blaze3d.vertex.VertexFormat
@ -15,8 +16,6 @@ import fr.username404.snowygui.utils.RenderingUtil.prepareDraw
import fr.username404.snowygui.utils.RenderingUtil.tessellator
import io.github.config4k.extract
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import org.jetbrains.annotations.ApiStatus
import java.util.TreeSet
@ -33,9 +32,9 @@ class ClickBox(
if (sortAlphabetically)
TreeSet(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
else LinkedHashSet()
override fun display(guiGraphics: GuiGraphics?) {
override fun display(stack: PoseStack?) {
hidden = buttons.isEmpty() || hidden
super.display(guiGraphics)
super.display(stack)
}
@JvmField
@ -45,7 +44,7 @@ class ClickBox(
opacity = 0.75F
) {
override val color: Int get() = this@ClickBox.color
override fun render(guiGraphics: GuiGraphics?) {
override fun render(poseStack: PoseStack?) {
prepareDraw()
colorShader(); defaultRectFunc()
endDraw()
@ -77,7 +76,7 @@ class ClickBox(
const val clickboxHeightOffset: Int = 80
private const val inclination: Double = 2.5
}
override fun render(guiGraphics: GuiGraphics?) {
override fun render(poseStack: PoseStack?) {
val currentHeight = y + (height + clickboxHeightOffset)
prepareDraw()
with(buffer) {
@ -106,23 +105,18 @@ class ClickBox(
buttonsProgressBar.apply {
x = this@ClickBox.x + this@ClickBox.width - 3
y = this@ClickBox.y + this@ClickBox.height + 3
}.display(guiGraphics)
}.display(poseStack)
buttons.forEachIndexed { num, button ->
val fullHeight = (y + height.toDouble())..(y + height + clickboxHeightOffset)
button.also {
it.x = x + 3
it.y = y + 3 + height + (((num + 1) - barStage) * 9)
it.hidden = if ((num + 1) <= 8) ((it.y) !in fullHeight) else ((it.y + it.height) !in fullHeight)
}.display(guiGraphics)
}.display(poseStack)
}
}
guiGraphics?.run {
with(Minecraft.getInstance().font) {
drawInBatch(name.string,
(x + 5).toFloat(), (y + 2).toFloat(), Colors.TRANSPARENT.hexValue, false,
pose().last().pose(), bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880, isBidirectional
)
}
if (poseStack != null) {
Minecraft.getInstance().font.draw(poseStack, name.string, x.toFloat() + 5, y.toFloat() + 1.5F, Colors.TRANSPARENT.hexValue)
}
}
}

View File

@ -1,15 +1,15 @@
package fr.username404.snowygui.gui.feature
import com.mojang.blaze3d.vertex.PoseStack
import fr.username404.snowygui.ClickGui
import fr.username404.snowygui.Snowy
import fr.username404.snowygui.config.Configuration
import fr.username404.snowygui.gui.ColoredElement
import fr.username404.snowygui.gui.feature.ButtonInfo.Companion.Type
import fr.username404.snowygui.utils.FontUtil
import fr.username404.snowygui.utils.RenderingUtil.colorShader
import fr.username404.snowygui.gui.feature.ButtonInfo.Companion.Type
import fr.username404.snowygui.utils.RenderingUtil.endDraw
import fr.username404.snowygui.utils.RenderingUtil.prepareDraw
import net.minecraft.client.gui.GuiGraphics
import fr.username404.snowygui.utils.RenderingUtil.colorShader
import kotlin.reflect.full.findAnnotation
sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
@ -17,20 +17,25 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
private fun addButtons(vararg buttons: ButtonImpl) {
buttons.groupBy { impl ->
ClickGui.clickBoxes.find { box ->
box.isCategory(impl.info.parent)
}
}.entries.forEach { entry -> entry.run {
key?.buttons?.clear()
value.forEach { if (!it.isDisabled) {
key?.buttons?.add(it.apply {
with(impl) {
if (info.shouldSave() && !info.parent.shouldHide) {
Configuration.enabledFeatures[title]?.let { 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
fun initButtons() = addButtons(
@ -85,12 +90,12 @@ sealed class ButtonImpl: ColoredElement(0.0, 0.0, 73, 8, opacity = 0.60F) {
lightDown()
}; return false
}
final override fun render(guiGraphics: GuiGraphics?) {
final override fun render(poseStack: PoseStack?) {
prepareDraw()
colorShader(); defaultRectFunc()
endDraw()
if (guiGraphics != null) {
FontUtil.drawScaled(guiGraphics, title, x + 1, y + 1, 0.75F)
if (poseStack != null) {
FontUtil.drawScaled(poseStack, title, x + 1, y + 1, 0.75F)
}
}
}

View File

@ -1,13 +1,13 @@
package fr.username404.snowygui.gui.feature
import com.mojang.blaze3d.vertex.PoseStack
import fr.username404.snowygui.EventSnowy
import fr.username404.snowygui.argsLambda
import fr.username404.snowygui.gui.Renderable
import net.minecraft.client.gui.GuiGraphics
sealed class ButtonImplWithHud: ButtonImpl() {
protected abstract val hudRenderLambda: Renderable
private val generatedLambda: argsLambda = { hudRenderLambda.render(it.first() as GuiGraphics?) }
private val generatedLambda: argsLambda = { hudRenderLambda.render(it.first() as PoseStack?) }
final override fun execAction() {
EventSnowy["HudRender"].run {
if (toggled) add(generatedLambda)

View File

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

View File

@ -1,12 +1,12 @@
package fr.username404.snowygui.gui.feature
import com.mojang.blaze3d.vertex.PoseStack
import fr.username404.snowygui.config.Configuration
import fr.username404.snowygui.gui.ColoredElement
import fr.username404.snowygui.gui.Renderable
import fr.username404.snowygui.utils.FontUtil
import fr.username404.snowygui.utils.RenderingUtil
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
@ButtonInfo(Category.HUD)
object Keystrokes: ButtonImplWithHud() {
@ -41,14 +41,14 @@ object Keystrokes: ButtonImplWithHud() {
return dynamicOpacity[i]
}
private fun drawKey(x: Double, y: Double, key: Int, guiGraphics: GuiGraphics?) {
private fun drawKey(x: Double, y: Double, key: Int, poseStack: PoseStack? = null) {
RenderingUtil.prepareDraw()
RenderingUtil.drawRectangle(
x, y, height / 2, height / 2,
color = color, opacity = getDynamicOpacity(key).toFloat()
)
RenderingUtil.endDraw()
guiGraphics?.let {
poseStack?.let {
FontUtil.drawScaled(
it, keysArray.first[key].translatedKeyMessage.string.uppercase(),
x + height.toDouble() / 5.5, y + height.toDouble() / 6.5,
@ -57,11 +57,11 @@ object Keystrokes: ButtonImplWithHud() {
}
}
private fun getNewPos(i: Int) = x + (i * (2 + (height / 2)))
override fun render(guiGraphics: GuiGraphics?) = with(RenderingUtil) {
override fun render(poseStack: PoseStack?) = with(RenderingUtil) {
for (i in 0 until 3) {
drawKey(getNewPos(i), y, i, guiGraphics)
drawKey(getNewPos(i), y, i, poseStack)
}
drawKey(getNewPos(1), y - (height / 2) - 2, 3, guiGraphics)
drawKey(getNewPos(1), y - (height / 2) - 2, 3, poseStack)
}
}
override val hudRenderLambda = Renderable {

View File

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

View File

@ -8,7 +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.EVENT
import net.fabricmc.loader.api.FabricLoader
import net.minecraft.client.gui.GuiGraphics
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.listDirectoryEntries
@ -21,7 +20,7 @@ class FabricInit: Snowy(), ClientModInitializer {
EVENT.register(
object: HudRenderCallback, EventSnowy {
override val type: String = "HudRender"
override fun onHudRender(guiGraphics: GuiGraphics?, tickDelta: Float) = fire(guiGraphics)
override fun onHudRender(matrixStack: PoseStack?, tickDelta: Float) = fire(matrixStack)
}
)
}

View File

@ -8,6 +8,6 @@ object HudHandler: EventSnowy {
override val type: String = "HudRender"
@SubscribeEvent
fun handleRendering(event: RenderGuiEvent.Post) {
fire(event.guiGraphics)
fire(event.poseStack)
}
}

View File

@ -7,16 +7,16 @@ org.gradle.parallel=true
org.gradle.unsafe.configuration-cache=on
org.gradle.vfs.watch=true
minecraft=1.20
forge_version=46.0
kotlinforforge=4.3.0
kotlinVer=1.8.22
kotlin_coroutines_version=1.7.1
serializationVer=1.5.1
minecraft=1.19.4
forge_version=45.0
kotlinforforge=4.1.0
kotlinVer=1.8.20
kotlin_coroutines_version=1.7.0-RC
serializationVer=1.5.0
fabric_loader_version=0.14.19
fabric_language_kotlin=1.9.5+kotlin.1.8.22
fabric_resource_loader_version=0.11.7+f7923f6d27
fabric_rendering_api_version=3.0.6+b3afc78b27
fabric_api_base_version=0.4.29+b04edc7a27
clothconfig_version=11.0.99
modmenu_version=7.0.0
fabric_language_kotlin=1.9.3+kotlin.1.8.20
fabric_resource_loader_version=0.11.4+bd913b0d4e
fabric_rendering_api_version=2.1.1+8f878217f4
fabric_api_base_version=0.4.5+ec94c6f6e0
clothconfig_version=10.0.96
modmenu_version=6.2.1

View File

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