From 059ddb01b8d00c99babacf0287bfa74eb9d5848e Mon Sep 17 00:00:00 2001 From: Naz Date: Tue, 31 Oct 2023 23:38:15 +0800 Subject: [PATCH] Working towards fixing Immersive Engineering --- .../world/item/ItemStackInject.java | 15 +++- .../AbstractFurnaceBlockEntityInject.java | 64 ++++++++++++++++ .../ItemStackCapabilityProviderImpl.java | 4 + .../modlauncher/api/ILaunchHandlerService.kt | 17 +++++ .../api/ITransformingClassLoaderBuilder.kt | 15 ++++ .../cpw/mods/modlauncher/api/NamedPath.kt | 8 ++ .../cpw/mods/modlauncher/api/ServiceRunner.kt | 11 +++ .../minecraftforge/fml/loading/FMLLoader.kt | 9 +++ .../loading/targets/CommonLaunchHandler.kt | 73 +++++++++++++++++++ .../fml/loading/targets/KnotLaunchHandler.kt | 39 ++++++++++ .../kilt/loader/remap/KiltRemapper.kt | 8 +- .../CompatibleCapabilityWorkaroundFixer.kt | 40 ++++++++++ .../resources/kilt_forge_injects.mixins.json | 1 + 13 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 src/main/java/xyz/bluspring/kilt/forgeinjects/world/level/block/entity/AbstractFurnaceBlockEntityInject.java create mode 100644 src/main/kotlin/cpw/mods/modlauncher/api/ILaunchHandlerService.kt create mode 100644 src/main/kotlin/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.kt create mode 100644 src/main/kotlin/cpw/mods/modlauncher/api/NamedPath.kt create mode 100644 src/main/kotlin/cpw/mods/modlauncher/api/ServiceRunner.kt create mode 100644 src/main/kotlin/net/minecraftforge/fml/loading/targets/CommonLaunchHandler.kt create mode 100644 src/main/kotlin/net/minecraftforge/fml/loading/targets/KnotLaunchHandler.kt create mode 100644 src/main/kotlin/xyz/bluspring/kilt/loader/remap/fixers/CompatibleCapabilityWorkaroundFixer.kt diff --git a/src/main/java/xyz/bluspring/kilt/forgeinjects/world/item/ItemStackInject.java b/src/main/java/xyz/bluspring/kilt/forgeinjects/world/item/ItemStackInject.java index cb9a666e..60c2ad23 100644 --- a/src/main/java/xyz/bluspring/kilt/forgeinjects/world/item/ItemStackInject.java +++ b/src/main/java/xyz/bluspring/kilt/forgeinjects/world/item/ItemStackInject.java @@ -5,10 +5,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityDispatcher; -import net.minecraftforge.common.capabilities.CapabilityProvider; -import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.capabilities.*; import net.minecraftforge.common.extensions.IForgeItemStack; import net.minecraftforge.common.util.LazyOptional; import org.jetbrains.annotations.NotNull; @@ -125,6 +122,16 @@ public boolean areCapsCompatible(CapabilityProvider other) { return workaround.areCapsCompatible(other); } + @Override + public boolean areCapsCompatible(ICapabilityProviderImpl stack) { + if (stack instanceof ItemStackCapabilityProviderImpl stackWorkaround) + return workaround.areCapsCompatible(stackWorkaround.getWorkaround()); + else if (stack instanceof CapabilityProvider provider) + return workaround.areCapsCompatible(provider); + else + return false; + } + @Override public boolean areCapsCompatible(@Nullable CapabilityDispatcher other) { return workaround.areCapsCompatible(other); diff --git a/src/main/java/xyz/bluspring/kilt/forgeinjects/world/level/block/entity/AbstractFurnaceBlockEntityInject.java b/src/main/java/xyz/bluspring/kilt/forgeinjects/world/level/block/entity/AbstractFurnaceBlockEntityInject.java new file mode 100644 index 00000000..2ba11462 --- /dev/null +++ b/src/main/java/xyz/bluspring/kilt/forgeinjects/world/level/block/entity/AbstractFurnaceBlockEntityInject.java @@ -0,0 +1,64 @@ +package xyz.bluspring.kilt.forgeinjects.world.level.block.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.crafting.AbstractCookingRecipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.wrapper.SidedInvWrapper; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(AbstractFurnaceBlockEntity.class) +public abstract class AbstractFurnaceBlockEntityInject extends BaseContainerBlockEntity { + private RecipeType recipeType; + + protected AbstractFurnaceBlockEntityInject(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { + super(blockEntityType, blockPos, blockState); + } + + @Inject(method = "", at = @At("TAIL")) + private void kilt$initRecipeType(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState, RecipeType recipeType, CallbackInfo ci) { + this.recipeType = recipeType; + } + + LazyOptional[] handlers = SidedInvWrapper.create((AbstractFurnaceBlockEntity) (Object) this, Direction.UP, Direction.DOWN, Direction.NORTH); + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (!this.remove && side != null && cap == ForgeCapabilities.ITEM_HANDLER) { + if (side == Direction.UP) + return handlers[0].cast(); + else if (side == Direction.DOWN) + return handlers[1].cast(); + else + return handlers[2].cast(); + } + return super.getCapability(cap, side); + } + + @Override + public void invalidateCaps() { + super.invalidateCaps(); + for (LazyOptional handler : handlers) { + handler.invalidate(); + } + } + + @Override + public void reviveCaps() { + super.reviveCaps(); + this.handlers = SidedInvWrapper.create((AbstractFurnaceBlockEntity) (Object) this, Direction.UP, Direction.DOWN, Direction.NORTH); + } +} diff --git a/src/main/java/xyz/bluspring/kilt/injections/capabilities/ItemStackCapabilityProviderImpl.java b/src/main/java/xyz/bluspring/kilt/injections/capabilities/ItemStackCapabilityProviderImpl.java index 13c33b83..c5966eb5 100644 --- a/src/main/java/xyz/bluspring/kilt/injections/capabilities/ItemStackCapabilityProviderImpl.java +++ b/src/main/java/xyz/bluspring/kilt/injections/capabilities/ItemStackCapabilityProviderImpl.java @@ -8,4 +8,8 @@ public interface ItemStackCapabilityProviderImpl extends ICapabilityProviderImpl default CapabilityProviderWorkaround getWorkaround() { throw new IllegalStateException(); } + + default boolean areCapsCompatible(ICapabilityProviderImpl stack) { + throw new IllegalStateException(); + } } diff --git a/src/main/kotlin/cpw/mods/modlauncher/api/ILaunchHandlerService.kt b/src/main/kotlin/cpw/mods/modlauncher/api/ILaunchHandlerService.kt new file mode 100644 index 00000000..9352e294 --- /dev/null +++ b/src/main/kotlin/cpw/mods/modlauncher/api/ILaunchHandlerService.kt @@ -0,0 +1,17 @@ +package cpw.mods.modlauncher.api + +/** + * A singleton instance of this is loaded by the system to designate the launch target + */ +interface ILaunchHandlerService { + fun name(): String + + @Deprecated("") + fun configureTransformationClassLoader(builder: ITransformingClassLoaderBuilder) + + fun launchService(arguments: Array, gameLayer: ModuleLayer): ServiceRunner + + fun getPaths(): Array { + return arrayOf() + } +} \ No newline at end of file diff --git a/src/main/kotlin/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.kt b/src/main/kotlin/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.kt new file mode 100644 index 00000000..4a5fb8dd --- /dev/null +++ b/src/main/kotlin/cpw/mods/modlauncher/api/ITransformingClassLoaderBuilder.kt @@ -0,0 +1,15 @@ +package cpw.mods.modlauncher.api + +import java.net.URL +import java.nio.file.Path +import java.util.* +import java.util.function.Function + + +interface ITransformingClassLoaderBuilder { + fun addTransformationPath(path: Path) + + fun setClassBytesLocator(additionalClassBytesLocator: Function>) + + fun setResourceEnumeratorLocator(resourceEnumeratorLocator: Function>) +} \ No newline at end of file diff --git a/src/main/kotlin/cpw/mods/modlauncher/api/NamedPath.kt b/src/main/kotlin/cpw/mods/modlauncher/api/NamedPath.kt new file mode 100644 index 00000000..e18d9654 --- /dev/null +++ b/src/main/kotlin/cpw/mods/modlauncher/api/NamedPath.kt @@ -0,0 +1,8 @@ +package cpw.mods.modlauncher.api + +import java.nio.file.Path + +class NamedPath( + val name: String, + vararg paths: Path +) diff --git a/src/main/kotlin/cpw/mods/modlauncher/api/ServiceRunner.kt b/src/main/kotlin/cpw/mods/modlauncher/api/ServiceRunner.kt new file mode 100644 index 00000000..b07942ee --- /dev/null +++ b/src/main/kotlin/cpw/mods/modlauncher/api/ServiceRunner.kt @@ -0,0 +1,11 @@ +package cpw.mods.modlauncher.api + +fun interface ServiceRunner { + @Throws(Throwable::class) + fun run() + + companion object { + @JvmField + val NOOP = ServiceRunner {} + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/minecraftforge/fml/loading/FMLLoader.kt b/src/main/kotlin/net/minecraftforge/fml/loading/FMLLoader.kt index 9ba1aaae..09b81fb0 100644 --- a/src/main/kotlin/net/minecraftforge/fml/loading/FMLLoader.kt +++ b/src/main/kotlin/net/minecraftforge/fml/loading/FMLLoader.kt @@ -1,6 +1,8 @@ package net.minecraftforge.fml.loading import net.fabricmc.loader.api.FabricLoader +import net.minecraftforge.fml.loading.targets.CommonLaunchHandler +import net.minecraftforge.fml.loading.targets.KnotLaunchHandler import java.nio.file.Path object FMLLoader { @@ -9,6 +11,13 @@ object FMLLoader { return !FabricLoader.getInstance().isDevelopmentEnvironment } + private val handler = KnotLaunchHandler() + + @JvmStatic + fun getLaunchHandler(): CommonLaunchHandler { + return this.handler + } + @JvmStatic fun launcherHandlerName(): String { return "kilt" diff --git a/src/main/kotlin/net/minecraftforge/fml/loading/targets/CommonLaunchHandler.kt b/src/main/kotlin/net/minecraftforge/fml/loading/targets/CommonLaunchHandler.kt new file mode 100644 index 00000000..d39ba273 --- /dev/null +++ b/src/main/kotlin/net/minecraftforge/fml/loading/targets/CommonLaunchHandler.kt @@ -0,0 +1,73 @@ +package net.minecraftforge.fml.loading.targets + +import com.mojang.logging.LogUtils +import cpw.mods.modlauncher.api.ILaunchHandlerService +import cpw.mods.modlauncher.api.ITransformingClassLoaderBuilder +import net.minecraftforge.api.distmarker.Dist +import net.minecraftforge.fml.loading.LogMarkers +import org.slf4j.Logger +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths +import java.util.* +import java.util.function.BiPredicate +import java.util.stream.Collectors + + +abstract class CommonLaunchHandler : ILaunchHandlerService { + data class LocatedPaths( + val minecraftPaths: List, + val minecraftFilter: BiPredicate, + val otherModPaths: List>, + val otherArtifacts: List + ) + + abstract fun getDist(): Dist + + abstract fun getNaming(): String + + open fun isProduction(): Boolean { + return false + } + + open fun isData(): Boolean { + return false + } + + abstract fun getMinecraftPaths(): LocatedPaths + + override fun configureTransformationClassLoader(builder: ITransformingClassLoaderBuilder) {} + + protected fun getModClasses(): Map> { + val modClasses: String = Optional.ofNullable(System.getenv("MOD_CLASSES")).orElse("") + LOGGER.debug(LogMarkers.CORE, "Got mod coordinates {} from env", modClasses) + data class ExplodedModPath(val modid: String, val path: Path) + + // "a/b/;c/d/;" -> "modid%%c:\fish\pepper;modid%%c:\fish2\pepper2\;modid2%%c:\fishy\bums;modid2%%c:\hmm" + val modClassPaths = + Arrays.stream(modClasses.split(File.pathSeparator.toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) + .map { inp -> inp.split("%%", limit = 2) } + .map { splitString -> + ExplodedModPath( + if (splitString.size == 1) "defaultmodid" else splitString[0], + Paths.get(splitString[splitString.size - 1]) + ) + } + .collect( + Collectors.groupingBy( + ExplodedModPath::modid, + Collectors.mapping(ExplodedModPath::path, Collectors.toList()) + ) + ) + LOGGER.debug(LogMarkers.CORE, "Found supplied mod coordinates [{}]", modClassPaths) + + //final var explodedTargets = ((Map>)arguments).computeIfAbsent("explodedTargets", a -> new ArrayList<>()); + //modClassPaths.forEach((modlabel,paths) -> explodedTargets.add(new ExplodedDirectoryLocator.ExplodedMod(modlabel, paths))); + return modClassPaths + } + + companion object { + protected val LOGGER: Logger = LogUtils.getLogger() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/minecraftforge/fml/loading/targets/KnotLaunchHandler.kt b/src/main/kotlin/net/minecraftforge/fml/loading/targets/KnotLaunchHandler.kt new file mode 100644 index 00000000..34d406e3 --- /dev/null +++ b/src/main/kotlin/net/minecraftforge/fml/loading/targets/KnotLaunchHandler.kt @@ -0,0 +1,39 @@ +package net.minecraftforge.fml.loading.targets + +import cpw.mods.modlauncher.api.ServiceRunner +import net.fabricmc.api.EnvType +import net.fabricmc.loader.api.FabricLoader +import net.minecraftforge.api.distmarker.Dist +import xyz.bluspring.kilt.loader.remap.KiltRemapper + +class KnotLaunchHandler : CommonLaunchHandler() { + override fun getDist(): Dist { + return if (FabricLoader.getInstance().environmentType == EnvType.CLIENT) + Dist.CLIENT + else + Dist.DEDICATED_SERVER + } + + override fun getNaming(): String { + return FabricLoader.getInstance().mappingResolver.currentRuntimeNamespace + } + + private val paths = LocatedPaths( + KiltRemapper.getGameClassPath().toList(), { _, _ -> + true + }, + listOf(), listOf() + ) + + override fun getMinecraftPaths(): LocatedPaths { + return paths + } + + override fun name(): String { + return "knot" + } + + override fun launchService(arguments: Array, gameLayer: ModuleLayer): ServiceRunner { + return ServiceRunner.NOOP + } +} \ No newline at end of file diff --git a/src/main/kotlin/xyz/bluspring/kilt/loader/remap/KiltRemapper.kt b/src/main/kotlin/xyz/bluspring/kilt/loader/remap/KiltRemapper.kt index 7892034b..f30bdbde 100644 --- a/src/main/kotlin/xyz/bluspring/kilt/loader/remap/KiltRemapper.kt +++ b/src/main/kotlin/xyz/bluspring/kilt/loader/remap/KiltRemapper.kt @@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory import xyz.bluspring.kilt.Kilt import xyz.bluspring.kilt.loader.KiltLoader import xyz.bluspring.kilt.loader.mod.ForgeMod +import xyz.bluspring.kilt.loader.remap.fixers.CompatibleCapabilityWorkaroundFixer import xyz.bluspring.kilt.loader.remap.fixers.ConflictingStaticMethodFixer import xyz.bluspring.kilt.loader.remap.fixers.EventClassVisibilityFixer import xyz.bluspring.kilt.loader.remap.fixers.EventEmptyInitializerFixer @@ -50,7 +51,7 @@ object KiltRemapper { // Keeps track of the remapper changes, so every time I update the remapper, // it remaps all the mods following the remapper changes. // this can update by like 12 versions in 1 update, so don't worry too much about it. - const val REMAPPER_VERSION = 107 + const val REMAPPER_VERSION = 110 val logConsumer = Consumer { logger.debug(it) @@ -401,6 +402,9 @@ object KiltRemapper { val visitor = EnhancedClassRemapper(classWriter, remapper, RenamingTransformer(remapper, false)) classNode.accept(visitor) + ConflictingStaticMethodFixer.fixClass(classNode) + CompatibleCapabilityWorkaroundFixer.fixClass(classNode) + jarOutput.putNextEntry(entry) jarOutput.write(classWriter.toByteArray()) jarOutput.closeEntry() @@ -468,7 +472,7 @@ object KiltRemapper { return null } - private fun getGameClassPath(): Array { + fun getGameClassPath(): Array { return if (!FabricLoader.getInstance().isDevelopmentEnvironment) arrayOf( FabricLoader.getInstance().objectShare.get("fabric-loader:inputGameJar") as Path, diff --git a/src/main/kotlin/xyz/bluspring/kilt/loader/remap/fixers/CompatibleCapabilityWorkaroundFixer.kt b/src/main/kotlin/xyz/bluspring/kilt/loader/remap/fixers/CompatibleCapabilityWorkaroundFixer.kt new file mode 100644 index 00000000..d80c8625 --- /dev/null +++ b/src/main/kotlin/xyz/bluspring/kilt/loader/remap/fixers/CompatibleCapabilityWorkaroundFixer.kt @@ -0,0 +1,40 @@ +package xyz.bluspring.kilt.loader.remap.fixers + +import net.fabricmc.loader.api.FabricLoader +import org.objectweb.asm.Opcodes +import org.objectweb.asm.tree.AbstractInsnNode +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.MethodInsnNode + +object CompatibleCapabilityWorkaroundFixer { + private val mappingResolver = FabricLoader.getInstance().mappingResolver + private val workaroundClasses = listOf( + mappingResolver.mapClassName("intermediary", "net.minecraft.class_1799").replace(".", "/") + ) + + fun fixClass(classNode: ClassNode) { + for (method in classNode.methods) { + val newNodeMap = mutableMapOf() + + for (insnNode in method.instructions) { + // Target virtual invokes specifically + if (insnNode is MethodInsnNode && insnNode.opcode == Opcodes.INVOKEVIRTUAL) { + if (!workaroundClasses.contains(insnNode.owner)) + continue + + if (insnNode.name != "areCapsCompatible") + continue + + val node = MethodInsnNode(insnNode.opcode, insnNode.owner, insnNode.name, "(Lnet/minecraftforge/common/capabilities/ICapabilityProviderImpl;)Z") + newNodeMap[insnNode] = node + } + } + + if (newNodeMap.isNotEmpty()) { + for ((oldNode, newNode) in newNodeMap) { + method.instructions.set(oldNode, newNode) + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/kilt_forge_injects.mixins.json b/src/main/resources/kilt_forge_injects.mixins.json index 17a09c68..660040c9 100644 --- a/src/main/resources/kilt_forge_injects.mixins.json +++ b/src/main/resources/kilt_forge_injects.mixins.json @@ -134,6 +134,7 @@ "world.level.block.LiquidBlockInject", "world.level.block.PoweredRailBlockInject", "world.level.block.StairBlockInject", + "world.level.block.entity.AbstractFurnaceBlockEntityInject", "world.level.block.entity.BlockEntityInject", "world.level.block.entity.HopperBlockEntityInject", "world.level.block.state.BlockBehaviourInject",