diff --git a/README.MD b/README.MD
index 81fd46c..79cc27f 100644
--- a/README.MD
+++ b/README.MD
@@ -9,6 +9,7 @@ A library for 1.7.10 with lots of useful stuff, licensed under the LGPLv3 licens
| [dependencies](src/main/java/com/falsepattern/lib/dependencies) | Runtime dependency loader which uses Maven (DEPRECATED, see [The new data-driven dependency format](src/main/resources/DEPENDENCIES.md) |
| [mapping](src/main/java/com/falsepattern/lib/mapping) | Notch-SRG-MCP name mapping helper code |
| [mixin](src/main/java/com/falsepattern/lib/mixin) | Mixin loader plugin boilerplate code |
+| [optifine](src/main/java/com/falsepattern/lib/optifine) | Tools for messing with OptiFine |
| [text](src/main/java/com/falsepattern/lib/text) | Better Chat and GUI text processing |
| [toasts](src/main/java/com/falsepattern/lib/toasts) | The toast system from newer versions, with some extras |
| [util](src/main/java/com/falsepattern/lib/util) | Additional utilities that do not fit the above categories, see below for more information |
diff --git a/gradle.properties b/gradle.properties
index cda3efa..aa5ce11 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -19,7 +19,7 @@ apiPackage =
# Packages separated by semicolons
# ExampleValue: apiPackages = foo;bar;baz
# ... foo;bar;baz -> com.myname.mymodid.foo;com.myname.mymodid.bar;com.myname.mymodid.baz
-apiPackages = asm;compat;config;dependencies;mapping;mixin;text;toasts;util
+apiPackages = asm;compat;config;dependencies;mapping;mixin;optifine;text;toasts;util
# Same as apiPackages, but does not pull in inner packages
apiPackagesNoRecurse = .
diff --git a/src/main/java/com/falsepattern/lib/internal/asm/FPTransformer.java b/src/main/java/com/falsepattern/lib/internal/asm/FPTransformer.java
index 7d737a8..6e6fd68 100644
--- a/src/main/java/com/falsepattern/lib/internal/asm/FPTransformer.java
+++ b/src/main/java/com/falsepattern/lib/internal/asm/FPTransformer.java
@@ -29,6 +29,7 @@ import com.falsepattern.lib.internal.asm.transformers.ConfigOrderTransformer;
import com.falsepattern.lib.internal.asm.transformers.GasStationValidatorTransformer;
import com.falsepattern.lib.internal.asm.transformers.IMixinPluginTransformer;
import com.falsepattern.lib.internal.asm.transformers.ITypeDiscovererTransformer;
+import com.falsepattern.lib.internal.impl.optifine.OptiFineTransformerHooksImpl;
import lombok.Getter;
import lombok.experimental.Accessors;
import org.apache.logging.log4j.LogManager;
@@ -48,6 +49,10 @@ public class FPTransformer implements SmartTransformer {
@Getter
private final Logger logger = LOG;
+ static {
+ OptiFineTransformerHooksImpl.init();
+ }
+
public FPTransformer() {
transformers = Arrays.asList(new IMixinPluginTransformer(),
new ITypeDiscovererTransformer(),
diff --git a/src/main/java/com/falsepattern/lib/internal/impl/optifine/OptiFineTransformerHooksImpl.java b/src/main/java/com/falsepattern/lib/internal/impl/optifine/OptiFineTransformerHooksImpl.java
new file mode 100644
index 0000000..5358a2d
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/internal/impl/optifine/OptiFineTransformerHooksImpl.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022-2023 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 .
+ */
+
+package com.falsepattern.lib.internal.impl.optifine;
+
+import com.falsepattern.lib.internal.Share;
+import lombok.val;
+
+import net.minecraft.launchwrapper.IClassTransformer;
+import net.minecraft.launchwrapper.Launch;
+import net.minecraft.launchwrapper.LaunchClassLoader;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class OptiFineTransformerHooksImpl {
+ private static final Set disabledPatches = new HashSet<>();
+ public static void init() {
+ Field tField;
+ try {
+ tField = LaunchClassLoader.class.getDeclaredField("transformers");
+ } catch (NoSuchFieldException e) {
+ Share.LOG.error("Could not retrieve transformers field", e);
+ return;
+ }
+ tField.setAccessible(true);
+ List transformers;
+ try {
+ transformers = (List)tField.get(Launch.classLoader);
+ } catch (IllegalAccessException e) {
+ Share.LOG.error("Could not retrieve transformers list", e);
+ return;
+ }
+ for (int i = 0; i < transformers.size(); i++) {
+ val transformer = transformers.get(i);
+ System.out.println(transformer.getClass().getName());
+ if (transformer.getClass().getName().equals("optifine.OptiFineClassTransformer")) {
+ Share.LOG.info("Attaching OptiFine ASM transformer hooks");
+ transformers.set(i, new WrappedOptiFineClassTransformer(transformer));
+ }
+ }
+ }
+
+ public static void disableOptiFinePatch(String patchName) {
+ disabledPatches.add(patchName);
+ }
+
+ public static boolean isDisabled(String className) {
+ return disabledPatches.contains(className);
+ }
+}
diff --git a/src/main/java/com/falsepattern/lib/internal/impl/optifine/WrappedOptiFineClassTransformer.java b/src/main/java/com/falsepattern/lib/internal/impl/optifine/WrappedOptiFineClassTransformer.java
new file mode 100644
index 0000000..272b5ca
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/internal/impl/optifine/WrappedOptiFineClassTransformer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022-2023 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 .
+ */
+
+package com.falsepattern.lib.internal.impl.optifine;
+
+import lombok.RequiredArgsConstructor;
+
+import net.minecraft.launchwrapper.IClassTransformer;
+
+@RequiredArgsConstructor
+public class WrappedOptiFineClassTransformer implements IClassTransformer {
+ private final IClassTransformer optiFineTransformer;
+ @Override
+ public byte[] transform(String name, String transformedName, byte[] basicClass) {
+ if (OptiFineTransformerHooksImpl.isDisabled(name)) {
+ return basicClass;
+ }
+ return optiFineTransformer.transform(name, transformedName, basicClass);
+ }
+}
diff --git a/src/main/java/com/falsepattern/lib/optifine/OptiFineTransformerHooks.java b/src/main/java/com/falsepattern/lib/optifine/OptiFineTransformerHooks.java
new file mode 100644
index 0000000..e370536
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/optifine/OptiFineTransformerHooks.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022-2023 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 .
+ */
+
+package com.falsepattern.lib.optifine;
+
+import com.falsepattern.lib.StableAPI;
+import com.falsepattern.lib.internal.impl.optifine.OptiFineTransformerHooksImpl;
+
+/**
+ * A utility for manipulating OptiFine's patches.
+ * If you have a mod that injects code that would otherwise conflict with OptiFine, and you have provably tested that
+ * removing certain OptiFine patches from the jar does NOT break anything, you may use this class to disable them
+ * without having to do jar file edits.
+ */
+@StableAPI(since = "1.0.0")
+public class OptiFineTransformerHooks {
+ @StableAPI.Expose
+ public static void disableOptiFinePatch(String patchName) {
+ OptiFineTransformerHooksImpl.disableOptiFinePatch(patchName);
+ }
+}