Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ loom {
"MISSING_INJECTOR_DESC_SINGLETARGET" to "error"
))
}

runs {
configureEach {
vmArg("--add-modules=jdk.zipfs")
}
}
}

allprojects {
Expand Down Expand Up @@ -690,4 +696,4 @@ fun getVersionMetadata(): String {
System.getenv("GITHUB_SHA") ?: grgit.head().abbreviatedId

return "+build.${commitHash.subSequence(0, 6)}${if (System.getenv("GITHUB_RUN_NUMBER") == null) "-local" else if (!isRelease()) "-nightly" else ""}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package xyz.bluspring.kilt.mixin.compat.fabric_api;

import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
import net.fabricmc.loader.api.ModContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import java.nio.file.Path;
import java.nio.file.ProviderNotFoundException;
import java.util.Collections;
import java.util.List;

@Mixin(value = ModNioResourcePack.class, remap = false)
public class ModNioResourcePackMixin {
@Redirect(method = "create", at = @At(value = "INVOKE", target = "Lnet/fabricmc/loader/api/ModContainer;getRootPaths()Ljava/util/List;"))
private static List<Path> kilt$skipMissingJarFileSystems(ModContainer instance) {
try {
return instance.getRootPaths();
} catch (ProviderNotFoundException exception) {
return Collections.emptyList();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package xyz.bluspring.kilt.mixin.compat.fabric_api;

import net.fabricmc.fabric.impl.resource.loader.ServerLanguageUtil;
import net.fabricmc.loader.api.ModContainer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import java.nio.file.Path;
import java.nio.file.ProviderNotFoundException;
import java.util.Collections;
import java.util.List;

@Mixin(value = ServerLanguageUtil.class, remap = false)
public class ServerLanguageUtilMixin {
@Redirect(method = "getModLanguageFiles", at = @At(value = "INVOKE", target = "Lnet/fabricmc/loader/api/ModContainer;getRootPaths()Ljava/util/List;"))
private static List<Path> kilt$skipMissingJarFileSystems(ModContainer instance) {
try {
return instance.getRootPaths();
} catch (ProviderNotFoundException exception) {
return Collections.emptyList();
}
}
}
42 changes: 39 additions & 3 deletions src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {
if (url.file.contains(".jar") && url.file.contains("!/META-INF/mods.toml")) // Prevent Fabric mods with broken Forge metadata from loading in the dev env
continue

val path = Path(url.path.removePrefix("file:/"))
val path = url.toURI().toPath()

val toml = tomlParser.parse(url)
modsList.addAll(parseModsToml(path, toml, null, isBuiltIn = true))
Expand Down Expand Up @@ -524,6 +524,7 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {
launch(Dispatchers.Default) {
// Load Forge scan data immediately, then we can assign it when we need to.
val forgeScanData = ModFileScanData()
val forgeScanDataLock = Any()

KiltHelper.getForgeClassNodes().asFlow().collect {
val visitor = ModClassVisitor()
Expand All @@ -543,7 +544,9 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {
if (mod.modFile == null) { // This is usually a Forge built-in, we don't have to worry about scanning this.
// If it is in fact a built-in, let's assign the scan data.
if (mod.definition.isBuiltin) {
forgeScanData.addModFileInfo(ModFileInfo(mod))
synchronized(forgeScanDataLock) {
forgeScanData.addModFileInfo(ModFileInfo(mod))
}
mod.scanData = forgeScanData
}

Expand Down Expand Up @@ -670,6 +673,13 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {

Kilt.logger.debug("Automatically registered event ${annotation.clazz.className} from mod ID $modId under bus ${busType.name}")
} catch (e: Throwable) {
ModLoadingContext.kiltActiveModId = null

if (isEnvironmentClassLoadingIssue(e)) {
Kilt.logger.debug("Skipping automatic event registration for ${annotation.clazz.className} due to environment mismatch.")
return@collect
}

Kilt.logger.error("Failed to register event ${annotation.clazz.className} from mod ${mod.modId}!")
val ex = RuntimeException("Failed to register event ${annotation.clazz.className} from mod ${mod.modId}!", e)
ex.printStackTrace()
Expand Down Expand Up @@ -785,6 +795,15 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {

ModLoadingContext.kiltActiveModId = null
} catch (e: Throwable) {
ModLoadingContext.kiltActiveModId = null

val envMismatch = isEnvironmentClassLoadingIssue(e) || isEnvironmentClassLoadingIssue(extraThrowable)
if (envMismatch) {
Kilt.logger.debug("Skipping mod class ${it.clazz.className} for ${mod.modId} due to environment mismatch.")
hasErrored = true
return@collect
}

e.printStackTrace()
if (extraThrowable != null)
exception.addSuppressed(extraThrowable)
Expand All @@ -802,6 +821,23 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {
}
}

private fun isEnvironmentClassLoadingIssue(throwable: Throwable?): Boolean {
var current = throwable
while (current != null) {
val message = current.message
if (message != null &&
message.startsWith("Cannot load class ") &&
(message.contains("in environment type SERVER") || message.contains("in environment type CLIENT"))
) {
return true
}

current = current.cause
}

return false
}

private fun loadTransformers(mod: ForgeMod) {
if (mod.modFile == null || mod.definition.isBuiltin) {
val accessTransformer = KiltLoader::class.java.getResource("META-INF/accesstransformer.cfg")
Expand Down Expand Up @@ -935,4 +971,4 @@ class KiltLoader : KnitModLoader<ForgeMod>(Kilt.MOD_ID, "Forge") {
runCatching { this.createDirectories() }
}
}
}
}
64 changes: 59 additions & 5 deletions src/main/kotlin/xyz/bluspring/kilt/loader/remap/KiltRemapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ import xyz.bluspring.kilt.util.KiltHelper
import xyz.bluspring.knit.loader.mod.ModDefinition
import xyz.bluspring.knit.loader.util.*
import java.io.File
import java.net.URI
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.ProviderNotFoundException
import java.nio.file.StandardOpenOption
import java.util.*
import java.util.function.Consumer
Expand Down Expand Up @@ -90,6 +93,57 @@ object KiltRemapper {
else
FabricLoader.getInstance().mappingResolver

private fun ClassProvider.Builder.addLibrarySafe(path: Path) {
val isDirectory = runCatching { path.isDirectory() }.getOrDefault(false)
if (!isDirectory) {
val isRegularFile = runCatching { path.isRegularFile() }.getOrDefault(false)
if (!isRegularFile) {
return
}

val name = path.fileName?.toString()?.lowercase(Locale.ROOT)
val isArchive = name?.endsWith(".jar") == true || name?.endsWith(".zip") == true || name?.endsWith(".jmod") == true
if (!isArchive) {
return
}
}

try {
addLibrary(path)
return
} catch (_: ProviderNotFoundException) {
// Some classpath entries are backed by non-default file systems in dev runs.
// Normalize them to a physical path that AutoRenamingTool can open.
}

val fallbackPath = runCatching {
val uri = path.toUri()
when (uri.scheme) {
"jar" -> {
val nested = uri.toString().removePrefix("jar:").substringBefore("!/")
Paths.get(URI(nested))
}
"file" -> Paths.get(uri)
else -> null
}
}.getOrNull()

if (fallbackPath != null) {
try {
addLibrary(fallbackPath)
return
} catch (exception: ProviderNotFoundException) {
throw RuntimeException(
"Failed to add class library path '$path' (uri=${runCatching { path.toUri() }.getOrNull()}) " +
"using fallback '$fallbackPath' (uri=${runCatching { fallbackPath.toUri() }.getOrNull()})",
exception
)
}
}

throw RuntimeException("Could not normalize class library path '$path' (uri=${runCatching { path.toUri() }.getOrNull()}).")
}

// This is created automatically using https://github.com/BluSpring/srg2intermediary
// srg -> intermediary
val srgIntermediaryMapping: IMappingFile = this::class.java.getResourceAsStream("/srg_intermediary.tiny")!!.buffered().use { IMappingFile.load(it) }
Expand Down Expand Up @@ -284,7 +338,7 @@ object KiltRemapper {
// in order to use mods lmao
*modLoadingQueue.map { mod -> mod.path }.toTypedArray()
).forEach {
addLibrary(it)
addLibrarySafe(it)
}
}.build()

Expand All @@ -298,7 +352,7 @@ object KiltRemapper {
ClassProvider.builder().apply {
// time to add Intermediary mappings to the mix! :,D
if (FabricLoader.getInstance().isDevelopmentEnvironment && !forceProductionRemap) {
addLibrary(intermediaryMap)
intermediaryMap?.let { addLibrarySafe(it) }
}

// IMPORTANT: this cannot be a flow or use merge, otherwise the order isn't retained. srgGamePath MUST be at the top of the list.
Expand All @@ -314,7 +368,7 @@ object KiltRemapper {
// in order to use mods lmao
*modLoadingQueue.map { mod -> mod.path }.toTypedArray()
).forEach {
addLibrary(it)
addLibrarySafe(it)
}
}.build()
}
Expand Down Expand Up @@ -717,9 +771,9 @@ object KiltRemapper {
val startTime = System.currentTimeMillis()

val classProvider = ClassProvider.builder().apply {
this.addLibrary(gameFile)
this.addLibrarySafe(gameFile)
for (path in getGameClassPath()) {
this.addLibrary(path)
this.addLibrarySafe(path)
}
}.build()
val srgRemapper = EnhancedRemapper(classProvider, mappingFile, logConsumer)
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/Kilt.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
"compat.fabric_api.BlockInitTrackerMixin",
"compat.fabric_api.FabricItemMixin",
"compat.fabric_api.Int2ObjectMapTrackerMixin",
"compat.fabric_api.ModNioResourcePackMixin",
"compat.fabric_api.PackRepositoryMixin",
"compat.fabric_api.ServerLanguageUtilMixin",
"compat.forge.alexscaves.PotionUtilsMixin",
"compat.forge.blueprint.RemoldedResourceManagerMixin",
"compat.forge.decocraft.JsonParserMixin",
Expand Down