Skip to content

Commit

Permalink
feat: launching minecraft and non-working asset downloader (will be r…
Browse files Browse the repository at this point in the history
…eplaced by .minecraft's assets)
  • Loading branch information
refactorinqq committed Jun 6, 2024
1 parent 17d6d78 commit 23a7987
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 19 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
build
example/run
.idea
13 changes: 8 additions & 5 deletions example/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import club.aetherium.gradle.extension.RunMode.Companion.tweaker

plugins {
java
id("club.aetherium.gradle")
}

minecraft {
minecraftVersion = "1.8.9"
}

repositories {
mavenCentral()
maven("https://raw.githubusercontent.com/BleachDev/cursed-mappings/main/")
maven("https://maven.legacyfabric.net")
}

dependencies {
add("mappings", "net.legacyfabric:yarn:1.8.9+build.mcp")
mappings("net.legacyfabric:yarn:1.8.9+build.mcp")
}

minecraft {
minecraftVersion = "1.8.9"
runMode = tweaker("club.aetherium.example.Tweaker")
}
48 changes: 48 additions & 0 deletions example/src/main/java/club/aetherium/example/Tweaker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package club.aetherium.example;

import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.LaunchClassLoader;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class Tweaker implements ITweaker {
private final List<String> launchArguments = new ArrayList<>();

@Override
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.launchArguments.addAll(args);

if (!args.contains("--version") && profile != null) {
launchArguments.add("--version");
launchArguments.add(profile);
}

if (!args.contains("--assetsDir") && assetsDir != null) {
launchArguments.add("--assetsDir");
launchArguments.add(assetsDir.getAbsolutePath());
}

if (!args.contains("--gameDir") && gameDir != null) {
launchArguments.add("--gameDir");
launchArguments.add(gameDir.getAbsolutePath());
}
System.out.println("AcceptOptions");
}

@Override
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
System.out.println("InjectIntoClassLoader");
}

@Override
public String getLaunchTarget() {
return "net.minecraft.client.main.Main";
}

@Override
public String[] getLaunchArguments() {
return launchArguments.toArray(new String[0]);
}
}
1 change: 1 addition & 0 deletions plugin-build/plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {
implementation(kotlin("stdlib"))
implementation(gradleApi())

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
implementation("org.vineflower:vineflower:1.10.1")
implementation(libs.gson)
implementation(libs.tiny.remapper)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ package club.aetherium.gradle
import club.aetherium.gradle.extension.MinecraftExtension
import club.aetherium.gradle.tasks.DownloadAndRemapJarTask
import club.aetherium.gradle.tasks.GenerateSourcesTask
import club.aetherium.gradle.tasks.run.DownloadAssetsTask
import club.aetherium.gradle.tasks.run.RunClientTask
import club.aetherium.gradle.utils.NativesTask
import club.aetherium.gradle.utils.manifest.MinecraftManifest
import club.aetherium.gradle.utils.manifest.MinecraftManifest.gson
import club.aetherium.gradle.utils.manifest.data.VersionData
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.internal.TaskInternal
import org.gradle.api.tasks.compile.AbstractCompile
import java.net.URI
import java.net.URL

abstract class AetherGradle : Plugin<Project> {
Expand All @@ -26,6 +31,19 @@ abstract class AetherGradle : Plugin<Project> {
it.dependsOn(downloadAndRemapJarTask)
}

val downloadAssetsTask = project.tasks.register("downloadAssets", DownloadAssetsTask::class.java) {
it.group = "AetherGradle"
}

val runClientTask = project.tasks.register("runClient", RunClientTask::class.java) {
it.group = "AetherGradle"
it.dependsOn(downloadAssetsTask)
it.dependsOn(project.tasks.withType(AbstractCompile::class.java).matching { that ->
!that.name.lowercase().contains("test")
})
it.mainClass.set(extension.runMode.get().mainClass)
}

project.afterEvaluate {
val mcManifest = MinecraftManifest.fromId(extension.minecraftVersion.get())
?: throw RuntimeException("Unknown version specified (${extension.minecraftVersion.get()})")
Expand All @@ -35,22 +53,42 @@ abstract class AetherGradle : Plugin<Project> {
VersionData::class.java
) ?: throw RuntimeException("Failed to fetch version manifest")

// Natives
// Natives
NativesTask.downloadAndExtractNatives(project, extension)

// Deps
project.repositories.add(
project.repositories.maven {
it.url = project.uri("https://libraries.minecraft.net/")
}
)

project.repositories.add(
project.repositories.mavenLocal()
)

// Libraries
manifest.libraries.forEach {
if(!it.name.contains("platform")) {
project.logger.info("Registering library ${it.name}")
project.dependencies.add("implementation", it.name)
project.dependencies.add("implementation",
"com.mojang:minecraft-deobf:${extension.minecraftVersion.get()}")
}
}

// RunMode
val mode = extension.runMode.get()

mode.additionalRepositories.forEach { dep ->
project.repositories.add(project.repositories.maven {
it.url = project.uri(dep)
})
}

mode.additionalDependencies.forEach { dep ->
project.dependencies.add("implementation", dep)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ abstract class MinecraftExtension
private val objects = project.objects

val minecraftVersion: Property<String> = objects.property(String::class.java)
val runMode: Property<RunMode> = objects.property(RunMode::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package club.aetherium.gradle.extension

import org.gradle.api.Project

data class RunMode(
val vmArgs: List<String>,
val runArgs: List<String>,
val additionalDependencies: List<String>,
val additionalRepositories: List<String>,
val mainClass: String
) {
companion object {
val Vanilla = RunMode(emptyList(), emptyList(), emptyList(), emptyList(),
"net.minecraft.client.main.Main")
fun tweaker(vararg tweakClasses: String) = RunMode(
emptyList(),
tweakClasses.map { "--tweakClass=$it" },
listOf("com.github.heni123321:LegacyLauncher:ac106bbe00"),
listOf("https://jitpack.io"),
"net.minecraft.launchwrapper.Launch"
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ abstract class DownloadAndRemapJarTask : DefaultTask() {
val characters = "=".repeat(neededBoxes)
val whitespaces = " ".repeat(totalBoxes - neededBoxes)

project.logger.lifecycle(
print(
"[AetherGradle] Client: [$characters$whitespaces] (${it})\r"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.gradle.api.DefaultTask
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.io.File

Expand All @@ -16,25 +17,38 @@ abstract class GenerateSourcesTask : DefaultTask() {

private val remappedJar: File = project.projectDir.resolve("build")
.resolve(".aether").resolve("client_${minecraftVersion.get()}_remapped.jar")
private val localMavenRepoDir = File("${System.getProperties()["user.home"]}/.m2/repository")
private val group = "com.mojang"
private val artifactId = "minecraft-deobf"
private val version = minecraftVersion.get()

@TaskAction
fun installToMavenLocal() {
val localMavenRepoDir = File("${System.getProperties()["user.home"]}/.m2/repository")
val group = "com.mojang"
val artifactId = "minecraft-deobf"
val version = minecraftVersion.get()
private val targetDirectory = localMavenRepoDir.resolve("${group.replace(".", "/")}/$artifactId/$version")

val targetDirectory = localMavenRepoDir.resolve("$group/$artifactId/$version")
val targetJarFile = targetDirectory.resolve("$artifactId-$version.jar")
@OutputFile
val targetJarFile = targetDirectory.resolve("$artifactId-$version.jar")
@OutputFile
val targetPomFile = targetDirectory.resolve("$artifactId-$version.pom")

@TaskAction
fun installToMavenLocal() {
if(!targetDirectory.exists()) targetDirectory.mkdirs()

remappedJar.copyTo(targetJarFile, true)

targetPomFile.writeText("""
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>${group}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
</project>
""".trimIndent())

project.logger.lifecycle("[AetherGradle] Installed deobfuscated Minecraft version: $version to maven local")
project.logger.lifecycle("[AetherGradle] To use the dependency: ")
project.logger.lifecycle("[AetherGradle] Add this to your repositories block: \nrepositories {\nmavenLocal()\n}")
project.logger.lifecycle("[AetherGradle] Add this to your dependencies block: \ndependencies {\nimplementation(\"$group:$artifactId:$version\")\n}")
project.logger.lifecycle("[AetherGradle] To add Minecraft to your classpath: ")
project.logger.lifecycle("[AetherGradle] Add this to your repositories block: \nrepositories {\n mavenLocal()\n}")
project.logger.lifecycle("[AetherGradle] Add this to your dependencies block: \ndependencies {\n implementation(\"$group:$artifactId:$version\")\n}")
project.logger.lifecycle("\n\n[AetherGradle] Thank you for using AetherGradle <3")
project.logger.lifecycle(" - Made with love by Refactoring")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package club.aetherium.gradle.tasks.run

import club.aetherium.gradle.extension.MinecraftExtension
import club.aetherium.gradle.utils.Downloader
import club.aetherium.gradle.utils.manifest.MinecraftManifest
import club.aetherium.gradle.utils.manifest.MinecraftManifest.gson
import club.aetherium.gradle.utils.manifest.data.VersionData
import com.google.gson.JsonObject
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.provider.Property
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.net.URL
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.CompletableFuture

private const val RESOURCES_URL = "https://resources.download.minecraft.net/"

abstract class DownloadAssetsTask : DefaultTask() {
@OutputDirectory
val assetsDirectory = project.projectDir.resolve("build")
.resolve(".aether").resolve("assets")
private val minecraftVersion: Property<String>
get() = project.extensions.getByType(MinecraftExtension::class.java).minecraftVersion

private val aetherCache = project.projectDir.resolve("build").resolve(".aether")

@TaskAction
fun downloadAssets() {
minecraftVersion.orNull ?: throw GradleException("Version must be set")

val mcManifest = MinecraftManifest.fromId(minecraftVersion.get())
?: throw RuntimeException("Unknown version specified (${minecraftVersion.get()})")

val manifest = gson.fromJson(
URL(mcManifest.url).openStream().reader().readText(),
VersionData::class.java
) ?: throw RuntimeException("Failed to fetch version manifest")

val get = URL(manifest.assetIndex.url).readText()

val assetIndex = aetherCache.resolve("indexes/${manifest.assetIndex.id}.json")

if (!assetIndex.exists()) {
assetIndex.parentFile.mkdirs()
assetIndex.createNewFile()
assetIndex.writeText(get)
}

val json = gson.fromJson(get, JsonObject::class.java)
val objects = json["objects"].asJsonObject

var downloaded = AtomicInteger(0)

fun assetDownloaded() {
val prog = downloaded.get().toFloat() / objects.size().toFloat()

val totalBoxes = 30
val neededBoxes = (prog * totalBoxes).toInt()
val characters = "=".repeat(neededBoxes)
val whitespaces = " ".repeat(totalBoxes - neededBoxes)

logger.lifecycle(
"\r[AetherGradle] Assets: [$characters$whitespaces] (${prog * 100})\r"
)
}

objects.asMap().forEach { (_, value) ->
val hash = value.asJsonObject["hash"]!!.asString
val folder = assetsDirectory.resolve("objects/" + hash.substring(0, 2))
val file = File(folder, hash)
val size = value.asJsonObject["size"]!!.asLong

logger.lifecycle(
"${file.exists()} | ${file.length()} / $size"
)

logger.lifecycle(
"${file.exists()} | ${Downloader.hash(file)} / $hash"
)

if ((!file.exists() || file.length() != size) &&
!Downloader.hash(file).equals(hash, ignoreCase = true)) {
val url = "$RESOURCES_URL${hash.substring(0, 2)}/$hash"
val response = URL(url).readText()

file.parentFile.mkdirs()
file.writeText(response)
downloaded.incrementAndGet()
assetDownloaded()
}
}
}
}
Loading

0 comments on commit 23a7987

Please sign in to comment.