Skip to content

Commit

Permalink
Add overlap handling to GamePatch.process. Helps with #376
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexIIL committed Oct 18, 2023
1 parent 0658992 commit adae65a
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,31 @@
* limitations under the License.
*/

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.quiltmc.loader.impl.entrypoint.GamePatch;
import org.quiltmc.loader.impl.entrypoint.GamePatchContext;
import org.quiltmc.loader.impl.launch.common.QuiltLauncher;
import org.quiltmc.loader.impl.util.log.Log;
import org.quiltmc.loader.impl.util.log.LogCategory;

import java.util.ListIterator;
import java.util.function.Consumer;
import java.util.function.Function;

public final class BrandingPatch extends GamePatch {
@Override
public void process(QuiltLauncher launcher, Function<String, ClassReader> classSource, Consumer<ClassNode> classEmitter) {
public void process(QuiltLauncher launcher, GamePatchContext context) {
for (String brandClassName : new String[] {
"net.minecraft.client.ClientBrandRetriever",
"net.minecraft.server.MinecraftServer"
}) {
ClassNode brandClass = readClass(classSource.apply(brandClassName));
ClassNode brandClass = context.getClassNode(brandClassName);

if (brandClass != null) {
if (applyBrandingPatch(brandClass)) {
classEmitter.accept(brandClass);
context.addPatchedClass(brandClass);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.quiltmc.loader.impl.entrypoint.GamePatch;

import org.quiltmc.loader.impl.entrypoint.GamePatchContext;
import org.quiltmc.loader.impl.fabric.util.version.VersionPredicateParser;
import org.quiltmc.loader.impl.game.minecraft.MinecraftGameProvider;
import org.quiltmc.loader.impl.launch.common.QuiltLauncher;
Expand All @@ -65,7 +65,7 @@ private void finishEntrypoint(EnvType type, ListIterator<AbstractInsnNode> it) {
}

@Override
public void process(QuiltLauncher launcher, Function<String, ClassReader> classSource, Consumer<ClassNode> classEmitter) {
public void process(QuiltLauncher launcher, GamePatchContext context) {
EnvType type = launcher.getEnvironmentType();
String entrypoint = launcher.getEntrypoint();
Version gameVersion = getGameVersion();
Expand All @@ -77,7 +77,8 @@ public void process(QuiltLauncher launcher, Function<String, ClassReader> classS
String gameEntrypoint = null;
boolean serverHasFile = true;
boolean isApplet = entrypoint.contains("Applet");
ClassNode mainClass = readClass(classSource.apply(entrypoint));
ClassNode mainClass = context.getClassNode(entrypoint);
Function<String, ClassReader> classSource = context::getClassSourceReader;

if (mainClass == null) {
throw new RuntimeException("Could not load main class " + entrypoint + "!");
Expand Down Expand Up @@ -192,7 +193,7 @@ public void process(QuiltLauncher launcher, Function<String, ClassReader> classS
if (gameEntrypoint.equals(entrypoint) || is20w22aServerOrHigher) {
gameClass = mainClass;
} else {
gameClass = readClass(classSource.apply(gameEntrypoint));
gameClass = context.getClassNode(gameEntrypoint);
if (gameClass == null) throw new RuntimeException("Could not load game class " + gameEntrypoint + "!");
}

Expand Down Expand Up @@ -520,9 +521,9 @@ public void process(QuiltLauncher launcher, Function<String, ClassReader> classS
}

if (gameClass != mainClass) {
classEmitter.accept(gameClass);
context.addPatchedClass(gameClass);
} else {
classEmitter.accept(mainClass);
context.addPatchedClass(mainClass);
}

if (isApplet) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ protected boolean isPublicInstance(int access) {
return ((access & 0x0F) == (Opcodes.ACC_PUBLIC | 0 /* non-static */));
}

public abstract void process(QuiltLauncher launcher, Function<String, ClassReader> classSource, Consumer<ClassNode> classEmitter);
public void process(QuiltLauncher launcher, Function<String, ClassReader> classSource, Consumer<ClassNode> classEmitter) {
throw new AbstractMethodError(getClass() + " must override one of the 'process' methods!");
}

public void process(QuiltLauncher launcher, GamePatchContext context) {
process(launcher, context::getClassSourceReader, context::addPatchedClass);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.quiltmc.loader.impl.entrypoint;

import org.jetbrains.annotations.ApiStatus;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.quiltmc.loader.impl.util.QuiltLoaderInternal;
import org.quiltmc.loader.impl.util.QuiltLoaderInternalType;

@ApiStatus.NonExtendable
@QuiltLoaderInternal(QuiltLoaderInternalType.LEGACY_EXPOSED)
public interface GamePatchContext {

/** @return A {@link ClassReader} which reads the original class file. */
ClassReader getClassSourceReader(String className);

/** @return A {@link ClassNode}, which may have already been modified by another {@link GamePatch}. */
ClassNode getClassNode(String className);

void addPatchedClass(ClassNode patchedClass);
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,45 @@ public void locateEntrypoints(QuiltLauncher launcher, List<Path> gameJars) {
}
};

Map<String, ClassNode> tempClassNodes = new HashMap<>();
Map<String, ClassNode> addedClassNodes = new HashMap<>();

GamePatchContext context = new GamePatchContext() {

@Override
public ClassReader getClassSourceReader(String className) {
return classSource.apply(className);
}

@Override
public ClassNode getClassNode(String className) {
ClassNode node = tempClassNodes.get(className);
if (node == null) {
node = GamePatch.readClass(getClassSourceReader(className));
tempClassNodes.put(className, node);
}
return node;
}

@Override
public void addPatchedClass(ClassNode node) {
String key = node.name.replace('/', '.');
if (tempClassNodes.get(key) == node) {
addedClassNodes.put(key, node);
} else if (addedClassNodes.containsKey(key)) {
throw new RuntimeException("Duplicate addPatchedClasses call: " + key);
} else {
GameTransformer.this.addPatchedClass(node);
}
}
};

for (GamePatch patch : patches) {
patch.process(launcher, classSource, this::addPatchedClass);
patch.process(launcher, context);
}

for (ClassNode node : addedClassNodes.values()) {
addPatchedClass(node);
}
} catch (IOException e) {
throw ExceptionUtil.wrap(e);
Expand Down

0 comments on commit adae65a

Please sign in to comment.