diff --git a/src/main/java/dev/redstudio/optinotfine/asm/OptiNotFineTransformer.java b/src/main/java/dev/redstudio/optinotfine/asm/OptiNotFineTransformer.java index 52d89cd..1d021b7 100644 --- a/src/main/java/dev/redstudio/optinotfine/asm/OptiNotFineTransformer.java +++ b/src/main/java/dev/redstudio/optinotfine/asm/OptiNotFineTransformer.java @@ -40,29 +40,30 @@ public final class OptiNotFineTransformer implements IClassTransformer { return transformNativeMemory(basicClass); } - switch (transformedName) { - case "net.optifine.shaders.config.ShaderOptionSwitch": - return transformShaderOptionSwitch(basicClass); + if (OptiNotFineConfig.replaceRegexes) { + switch (transformedName) { + case "net.optifine.shaders.config.ShaderOptionSwitch": + return transformShaderOptionSwitch(basicClass); + } } - if (!OptiNotFineConfig.stopLogSpam) - return basicClass; - - switch (transformedName) { - case "net.optifine.shaders.SMCLog": - return transformSMCLog(basicClass); - case "net.optifine.config.ConnectedParser": - return transformConnectedParser(basicClass); - case "net.optifine.shaders.ItemAliases": - return transformAliases(basicClass, "loadItemAliases", "item"); - case "net.optifine.shaders.BlockAliases": - return transformAliases(basicClass, "loadBlockAliases", "block"); - case "net.optifine.shaders.EntityAliases": - return transformAliases(basicClass, "loadEntityAliases", "entity"); - case "net.optifine.shaders.config.MacroExpressionResolver": - return stripConfigWarn(basicClass, "getExpression", "(Ljava/lang/String;)Lnet/optifine/expr/IExpression;"); - case "net.optifine.shaders.config.ShaderPackParser": - return stripConfigWarn(basicClass, "collectShaderOptions", "(Lnet/optifine/shaders/IShaderPack;Ljava/lang/String;Ljava/util/Map;)V"); + if (OptiNotFineConfig.stopLogSpam) { + switch (transformedName) { + case "net.optifine.shaders.SMCLog": + return transformSMCLog(basicClass); + case "net.optifine.config.ConnectedParser": + return transformConnectedParser(basicClass); + case "net.optifine.shaders.ItemAliases": + return transformAliases(basicClass, "loadItemAliases", "item"); + case "net.optifine.shaders.BlockAliases": + return transformAliases(basicClass, "loadBlockAliases", "block"); + case "net.optifine.shaders.EntityAliases": + return transformAliases(basicClass, "loadEntityAliases", "entity"); + case "net.optifine.shaders.config.MacroExpressionResolver": + return stripConfigWarn(basicClass, "getExpression", "(Ljava/lang/String;)Lnet/optifine/expr/IExpression;"); + case "net.optifine.shaders.config.ShaderPackParser": + return stripConfigWarn(basicClass, "collectShaderOptions", "(Lnet/optifine/shaders/IShaderPack;Ljava/lang/String;Ljava/util/Map;)V"); + } } return basicClass; @@ -175,54 +176,66 @@ public final class OptiNotFineTransformer implements IClassTransformer { public static boolean matchesDefineLine(final String line, final String name) { final int len = line.length(); - if (len < 9) + final int nameLen = name.length(); + + // Tighter minimum: "#define " (8) + at least 1 char identifier + if (len < 8 + nameLen) return false; int i = 0; + // Skip leading whitespace while (i < len && line.charAt(i) <= ' ') i++; + // Optional "//" prefix if (i + 1 < len && line.charAt(i) == '/' && line.charAt(i + 1) == '/') i += 2; + // Skip whitespace while (i < len && line.charAt(i) <= ' ') i++; - if (i + 7 > len) + // Match "#define" — check remaining length first + if (len - i < 8 + nameLen) return false; - if (line.charAt(i) != '#' || line.charAt(i + 1) != 'd' || line.charAt(i + 2) != 'e' || line.charAt(i + 3) != 'f' || line.charAt(i + 4) != 'i' || line.charAt(i + 5) != 'n' || line.charAt(i + 6) != 'e') + if (line.charAt(i) != '#' || line.charAt(i + 1) != 'd' || + line.charAt(i + 2) != 'e' || line.charAt(i + 3) != 'f' || + line.charAt(i + 4) != 'i' || line.charAt(i + 5) != 'n' || + line.charAt(i + 6) != 'e') return false; i += 7; - if (i >= len || line.charAt(i) > ' ') + // Must have whitespace after #define + if (line.charAt(i) > ' ') return false; - while (i < len && line.charAt(i) <= ' ') + do { i++; + } while (i < len && line.charAt(i) <= ' '); - final int start = i; - while (i < len) { - final char c = line.charAt(i); - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_') - i++; - else - break; + // Inline comparison with name — early exit on mismatch + for (int j = 0; j < nameLen; j++, i++) { + if (i >= len || line.charAt(i) != name.charAt(j)) + return false; } - if (i == start) - return false; - - final int idLen = i - start; - if (idLen != name.length()) - return false; + // Ensure identifier ends here (next char must NOT be identifier char) + if (i < len) { + final char c = line.charAt(i); + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '_') + return false; - while (i < len && line.charAt(i) <= ' ') - i++; + // Skip trailing whitespace + while (i < len && line.charAt(i) <= ' ') + i++; - if (i < len && !(line.charAt(i) == '/' && i + 1 < len && line.charAt(i + 1) == '/')) - return false; + // Must be EOL or comment + if (i < len && !(line.charAt(i) == '/' && i + 1 < len && line.charAt(i + 1) == '/')) + return false; + } - return line.regionMatches(start, name, 0, idLen); + return true; } private static String findFieldName(final Object fieldValue) { diff --git a/src/main/java/dev/redstudio/optinotfine/config/OptiNotFineConfig.java b/src/main/java/dev/redstudio/optinotfine/config/OptiNotFineConfig.java index 7ef3b15..c4e13c1 100644 --- a/src/main/java/dev/redstudio/optinotfine/config/OptiNotFineConfig.java +++ b/src/main/java/dev/redstudio/optinotfine/config/OptiNotFineConfig.java @@ -20,6 +20,11 @@ public final class OptiNotFineConfig { @Config.Comment("Stop what is considered log spam but may still be useful when working with OptiFine features (Shaders, Resourcepacks, etc...), see README.md for a list.") public static boolean stopLogSpam = true; + @Config.RequiresMcRestart + @Config.Name("Replace Regexes") + @Config.Comment("Replaces heavy, greedy, regexes in the parsing of shaders, may have edge cases with shaders.") + public static boolean replaceRegexes = true; + @SubscribeEvent public static void onConfigChanged(final ConfigChangedEvent.OnConfigChangedEvent onConfigChangedEvent) { if (!onConfigChangedEvent.getModID().equals(ID))