diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java index 213b23a..1653e15 100644 --- a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/Mixin.java @@ -22,16 +22,16 @@ package com.falsepattern.chunk.internal.mixin.plugin; -import com.falsepattern.lib.mixin.IMixin; -import com.falsepattern.lib.mixin.ITargetedMod; +import com.falsepattern.chunk.internal.mixin.plugin.fplib.IMixin; +import com.falsepattern.chunk.internal.mixin.plugin.fplib.ITargetedMod; import lombok.Getter; import lombok.RequiredArgsConstructor; import java.util.List; import java.util.function.Predicate; -import static com.falsepattern.lib.mixin.IMixin.PredicateHelpers.always; -import static com.falsepattern.lib.mixin.IMixin.PredicateHelpers.require; +import static com.falsepattern.chunk.internal.mixin.plugin.fplib.IMixin.PredicateHelpers.always; +import static com.falsepattern.chunk.internal.mixin.plugin.fplib.IMixin.PredicateHelpers.require; @RequiredArgsConstructor public enum Mixin implements IMixin { diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/MixinPlugin.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/MixinPlugin.java index 7bd8467..72a1086 100644 --- a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/MixinPlugin.java +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/MixinPlugin.java @@ -23,9 +23,9 @@ package com.falsepattern.chunk.internal.mixin.plugin; import com.falsepattern.chunk.internal.Tags; -import com.falsepattern.lib.mixin.IMixin; -import com.falsepattern.lib.mixin.IMixinPlugin; -import com.falsepattern.lib.mixin.ITargetedMod; +import com.falsepattern.chunk.internal.mixin.plugin.fplib.IMixin; +import com.falsepattern.chunk.internal.mixin.plugin.fplib.IMixinPlugin; +import com.falsepattern.chunk.internal.mixin.plugin.fplib.ITargetedMod; import lombok.Getter; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/TargetedMod.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/TargetedMod.java index 49b0f1b..7fc9fc1 100644 --- a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/TargetedMod.java +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/TargetedMod.java @@ -22,13 +22,13 @@ package com.falsepattern.chunk.internal.mixin.plugin; -import com.falsepattern.lib.mixin.ITargetedMod; +import com.falsepattern.chunk.internal.mixin.plugin.fplib.ITargetedMod; import lombok.Getter; import lombok.RequiredArgsConstructor; import java.util.function.Predicate; -import static com.falsepattern.lib.mixin.ITargetedMod.PredicateHelpers.contains; +import static com.falsepattern.chunk.internal.mixin.plugin.fplib.ITargetedMod.PredicateHelpers.contains; @RequiredArgsConstructor public enum TargetedMod implements ITargetedMod { diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/FileUtil.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/FileUtil.java new file mode 100644 index 0000000..eafaa77 --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/FileUtil.java @@ -0,0 +1,47 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ +package com.falsepattern.chunk.internal.mixin.plugin.fplib; + +import lombok.experimental.UtilityClass; + +import net.minecraft.launchwrapper.Launch; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @since 0.8.2 + */ +@UtilityClass +public final class FileUtil { + public static File getMinecraftHome() { + return getMinecraftHomePath().toFile(); + } + + /** + * @since 1.0.0 + */ + public static Path getMinecraftHomePath() { + return Launch.minecraftHome == null ? Paths.get("").toAbsolutePath() : Launch.minecraftHome.toPath(); + } +} diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/IMixin.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/IMixin.java new file mode 100644 index 0000000..203ca54 --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/IMixin.java @@ -0,0 +1,77 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ +package com.falsepattern.chunk.internal.mixin.plugin.fplib; + +import lombok.val; + +import cpw.mods.fml.relauncher.FMLLaunchHandler; + +import java.util.List; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public interface IMixin { + String getMixin(); + Side getSide(); + Predicate> getFilter(); + + default boolean shouldLoad(List loadedMods) { + val side = getSide(); + return (side == Side.COMMON + || side == Side.SERVER && FMLLaunchHandler.side().isServer() + || side == Side.CLIENT && FMLLaunchHandler.side().isClient()) && getFilter().test(loadedMods); + } + + /** + * @since 0.10.0 + */ + enum Side { + COMMON, + CLIENT, + SERVER + } + + /** + * @since 0.10.0 + */ + final class PredicateHelpers { + public static Predicate> never() { + return (list) -> false; + } + + public static Predicate> condition(Supplier condition) { + return (list) -> condition.get(); + } + + public static Predicate> always() { + return (list) -> true; + } + + public static Predicate> require(ITargetedMod mod) { + return (list) -> list.contains(mod); + } + + public static Predicate> avoid(ITargetedMod mod) { + return (list) -> !list.contains(mod); + } + } +} diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/IMixinPlugin.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/IMixinPlugin.java new file mode 100644 index 0000000..93c7b8d --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/IMixinPlugin.java @@ -0,0 +1,218 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ +package com.falsepattern.chunk.internal.mixin.plugin.fplib; + +import lombok.val; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.ApiStatus; +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import net.minecraft.launchwrapper.Launch; + +import java.io.File; +import java.net.URL; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.nio.file.Files.walk; + +public interface IMixinPlugin extends IMixinConfigPlugin { + Path MODS_DIRECTORY_PATH = FileUtil.getMinecraftHome().toPath().resolve("mods"); + + static Logger createLogger(String modName) { + return LogManager.getLogger(modName + " Mixin Loader"); + } + + /** + * @deprecated since 1.4.0 + */ + @Deprecated + static File findJarOf(final ITargetedMod mod) { + File result = null; + try (val stream = walk(MODS_DIRECTORY_PATH)) { + result = stream.filter(mod::isMatchingJar).map(Path::toFile).findFirst().orElse(null); + } catch (Exception e) { + e.printStackTrace(); + } + if (result == null) { + File found = null; + for (URL url : Launch.classLoader.getURLs()) { + try { + val file = new File(url.toURI()); + Path path = file.toPath(); + if (mod.isMatchingJar(path)) { + found = file; + break; + } + } catch (Exception ignored) { + } + } + result = found; + } + return result; + } + + /** + * @since 1.4.0 + */ + static Set findJarsOf(IMixinPlugin self, final ITargetedMod mod) { + if (!self.useNewFindJar()) { + val jar = findJarOf(mod); + return jar == null ? Collections.emptySet() : Collections.singleton(jar); + } + val results = new HashSet(); + try (val stream = walk(MODS_DIRECTORY_PATH)) { + results.addAll(stream.filter(mod::isMatchingJar).map(Path::toFile).collect(Collectors.toSet())); + } catch (Exception e) { + e.printStackTrace(); + } + for (URL url : Launch.classLoader.getURLs()) { + try { + val file = new File(url.toURI()); + Path path = file.toPath(); + if (mod.isMatchingJar(path)) { + results.add(file); + break; + } + } catch (Exception ignored) { + } + } + return results; + } + + Logger getLogger(); + + IMixin[] getMixinEnumValues(); + + ITargetedMod[] getTargetedModEnumValues(); + + /** + * @since 1.4.0 + */ + default boolean useNewFindJar() { + return false; + } + + @Override + @ApiStatus.Internal + default void onLoad(String mixinPackage) { + + } + + @Override + @ApiStatus.Internal + default String getRefMapperConfig() { + return null; + } + + @Override + @ApiStatus.Internal + default boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return true; + } + + @Override + @ApiStatus.Internal + default void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + @ApiStatus.Internal + default List getMixins() { + val isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment"); + val targetedMods = getTargetedModEnumValues(); + val loadedMods = Arrays.stream(targetedMods) + //Java 21 compat + .filter(new Predicate() { + @Override + public boolean test(ITargetedMod mod) { + boolean loadJar = IMixinPlugin.this.loadJarOf(mod); + return (mod.isLoadInDevelopment() && isDevelopmentEnvironment) + || loadJar; + } + }) + .collect(Collectors.toList()); + + for (val mod : targetedMods) { + if (loadedMods.contains(mod)) { + getLogger().info("Found " + mod.getModName() + "! Integrating now..."); + } else { + getLogger().info("Could not find " + mod.getModName() + "! Skipping integration...."); + } + } + + List mixins = new ArrayList<>(); + for (val mixin : getMixinEnumValues()) { + if (mixin.shouldLoad(loadedMods)) { + String mixinClass = mixin.getSide().name().toLowerCase() + "." + mixin.getMixin(); + mixins.add(mixinClass); + getLogger().info("Loading mixin: " + mixinClass); + } + } + return mixins; + } + + @ApiStatus.Internal + default boolean loadJarOf(final ITargetedMod mod) { + try { + val jars = findJarsOf(this, mod); + if (jars.isEmpty()) { + getLogger().info("Jar not found for {}", mod); + return false; + } + for (val jar: jars) { + getLogger().info("Attempting to add {} to the URL Class Path", jar); + try { + MinecraftURLClassPath.addJar(jar); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + return true; + } + + @Override + @ApiStatus.Internal + default void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + @ApiStatus.Internal + default void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/ITargetedMod.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/ITargetedMod.java new file mode 100644 index 0000000..1d651f4 --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/ITargetedMod.java @@ -0,0 +1,59 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ + +package com.falsepattern.chunk.internal.mixin.plugin.fplib; + +import com.google.common.io.Files; + +import java.nio.file.Path; +import java.util.function.Predicate; + +public interface ITargetedMod { + String getModName(); + + boolean isLoadInDevelopment(); + + @SuppressWarnings("UnstableApiUsage") + default boolean isMatchingJar(Path path) { + String pathString = path.toString(); + String nameLowerCase = Files.getNameWithoutExtension(pathString).toLowerCase(); + String fileExtension = Files.getFileExtension(pathString); + + return "jar".equals(fileExtension) && getCondition().test(nameLowerCase); + } + + Predicate getCondition(); + + final class PredicateHelpers { + public static Predicate startsWith(String subString) { + return (name) -> name.startsWith(subString.toLowerCase()); + } + + public static Predicate contains(String subString) { + return (name) -> name.contains(subString.toLowerCase()); + } + + public static Predicate matches(String regex) { + return (name) -> name.matches(regex); + } + } +} diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/LICENSE b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/LICENSE new file mode 100644 index 0000000..f9a78b9 --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/LICENSE @@ -0,0 +1,19 @@ +FalsePatternLib + +Copyright (C) 2022-2025 FalsePattern +All Rights Reserved + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, only version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see . \ No newline at end of file diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/MinecraftURLClassPath.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/MinecraftURLClassPath.java new file mode 100644 index 0000000..a249f72 --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/MinecraftURLClassPath.java @@ -0,0 +1,41 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ +package com.falsepattern.chunk.internal.mixin.plugin.fplib; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.File; + +/** + * Backport from spongemixins 1.3 for compat with the curseforge 1.2.0 version. + *

+ * Also added Grimoire protection. + * + * @since 0.10.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class MinecraftURLClassPath { + public static void addJar(File pathToJar) throws Exception { + UCPImpl.addJar(pathToJar); + } +} diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/README b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/README new file mode 100644 index 0000000..d1745be --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/README @@ -0,0 +1 @@ +Shadowed from FalsePatternLib 1.7.0 \ No newline at end of file diff --git a/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/UCPImpl.java b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/UCPImpl.java new file mode 100644 index 0000000..8dc9b2d --- /dev/null +++ b/src/main/java/com/falsepattern/chunk/internal/mixin/plugin/fplib/UCPImpl.java @@ -0,0 +1,61 @@ +/* + * This file is part of FalsePatternLib. + * + * Copyright (C) 2022-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * FalsePatternLib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * FalsePatternLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FalsePatternLib. If not, see . + */ + +package com.falsepattern.chunk.internal.mixin.plugin.fplib; + +import lombok.val; + +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; + +import java.io.File; +import java.io.IOException; + +public final class UCPImpl { + private static final boolean GRIMOIRE; + + static { + boolean grimoire = false; + String[] knownGrimoireClassNames = + new String[]{"io.github.crucible.grimoire.Grimoire", "io.github.crucible.grimoire.common.GrimoireCore"}; + for (val className : knownGrimoireClassNames) { + try { + if (Launch.classLoader.getClassBytes(className) != null) { + grimoire = true; + break; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + GRIMOIRE = grimoire; + } + + public static void addJar(File pathToJar) throws Exception { + if (!GRIMOIRE) { + final LaunchClassLoader loader = Launch.classLoader; + loader.addURL(pathToJar.toURI().toURL()); + // Act as-if we only added the mod to ucp + loader.getSources().remove(loader.getSources().size() - 1); + } + } +}