Skip to content

Commit

Permalink
Update to be compatible with 1.17+, Quilt Loader and Loader 0.12+
Browse files Browse the repository at this point in the history
 - Updated Gradle to 7.3.1
 - Updated Loom to 0.7
 - Removed dependency on Fabric API for as there is no API-dependent code.
 - Removed dependency on Minecraft for as there is no Minecraft-dependent code.
 - Added dynamic transformer bootstrapping for various implementations
  • Loading branch information
Ampflower committed Dec 11, 2021
1 parent 7e277a6 commit 77b3080
Show file tree
Hide file tree
Showing 9 changed files with 416 additions and 250 deletions.
19 changes: 6 additions & 13 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '0.4-SNAPSHOT'
id 'fabric-loom' version '0.7-SNAPSHOT'
id 'maven-publish'
}

Expand All @@ -11,30 +11,23 @@ version = project.mod_version
group = project.maven_group

dependencies {
//to change the versions see the gradle.properties file
// Required for bootstrapping Fabric & Loom.
// Doesn't necessarily mean that it's version-bound.
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"

// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"

// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.
compile "org.jetbrains:annotations:${project.annotations_version}"
implementation "org.jetbrains:annotations:${project.annotations_version}"
}

processResources {
inputs.property "version", project.version

from(sourceSets.main.resources.srcDirs) {
include "fabric.mod.json"
filesMatching("fabric.mod.json") {
expand "version": project.version
}

from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
}

// ensure that the encoding is set to UTF-8, no matter what the system default is
Expand All @@ -48,7 +41,7 @@ tasks.withType(JavaCompile) {
// if it is present.
// If you remove this task, sources will not be generated.
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = "sources"
archiveClassifier.set("sources")
from sourceSets.main.allSource
}

Expand Down
11 changes: 3 additions & 8 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G

# Fabric Properties
# check these on https://fabricmc.net/use
minecraft_version=1.16.2
yarn_mappings=1.16.2+build.46:v2
loader_version=0.9.2+build.206

# Mod Properties
mod_version = 0.2.10
maven_group = net.gudenau.minecraft
archives_base_name = gud_asm

mod_version=0.3.0
maven_group=net.gudenau.minecraft
archives_base_name=gud_asm
# Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.20.0+build.399-1.16
annotations_version=16.0.2
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
290 changes: 240 additions & 50 deletions src/main/java/net/gudenau/minecraft/asm/impl/Bootstrap.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.gudenau.minecraft.asm.impl;

import java.util.List;
import net.gudenau.minecraft.asm.api.v1.AsmUtils;
import net.gudenau.minecraft.asm.api.v1.Identifier;
import net.gudenau.minecraft.asm.api.v1.Transformer;
Expand All @@ -9,36 +8,38 @@
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;

import java.util.List;

/**
* A simple transformer to enable some JVM abuse.
* */
public class BootstrapTransformer implements Transformer{
*/
public class BootstrapTransformer implements Transformer {
// On the off chance that ForceInline is not around, we should not use it.
private static final boolean ENABLED;
static{

static {
boolean enable;
try{
try {
ReflectionHelper.loadClass("jdk.internal.vm.annotation.ForceInline");
enable = true;
}catch(Throwable ignored){
} catch (Throwable ignored) {
enable = false;
}
ENABLED = enable;
}
private static final Type FORCEBOOTLOADER = Type.getObjectType("net/gudenau/minecraft/asm/api/v0/annotation/ForceBootloader");
private static final Type ASM_FORCEINLINE = Type.getObjectType("net/gudenau/minecraft/asm/api/v0/annotation/ForceInline");

private static final Type FORCEBOOTLOADER = Type.getObjectType("net/gudenau/minecraft/asm/api/v1/annotation/ForceBootloader");
private static final Type ASM_FORCEINLINE = Type.getObjectType("net/gudenau/minecraft/asm/api/v1/annotation/ForceInline");
private static final Type JVM_FORCEINLINE = Type.getObjectType("jdk/internal/vm/annotation/ForceInline");

@Override
public Identifier getName(){
public Identifier getName() {
return new Identifier("gud_asm", "bootstrap");
}

// Special case, this is always true when called.
@Override
public boolean handlesClass(String name, String transformedName){
public boolean handlesClass(String name, String transformedName) {
return ENABLED;
}

Expand Down
163 changes: 67 additions & 96 deletions src/main/java/net/gudenau/minecraft/asm/impl/MixinTransformer.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
package net.gudenau.minecraft.asm.impl;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.invoke.MethodHandle;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import net.fabricmc.loader.api.FabricLoader;
import net.gudenau.minecraft.asm.api.v1.AsmUtils;
import net.gudenau.minecraft.asm.api.v1.ClassCache;
Expand All @@ -30,77 +12,62 @@
import org.spongepowered.asm.mixin.transformer.FabricMixinTransformerProxy;
import org.spongepowered.asm.mixin.transformer.IMixinTransformer;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.ProtectionDomain;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

/**
* Our custom "mixin" transformer.
* */
public class MixinTransformer extends FabricMixinTransformerProxy{
private static final Type ANNOTATION_FORCE_BOOTLOADER = Type.getObjectType("net/gudenau/minecraft/asm/api/v0/annotation/ForceBootloader");
*/
public class MixinTransformer extends FabricMixinTransformerProxy {
private static final Type ANNOTATION_FORCE_BOOTLOADER = Type.getObjectType("net/gudenau/minecraft/asm/api/v1/annotation/ForceBootloader");

private static final Set<String> BLACKLIST = new HashSet<>(Arrays.asList(
"net.gudenau.minecraft.asm.",
"org.objectweb.asm.",
"com.google.gson.",
"org.lwjgl.",
"it.unimi.dsi.fastutil."
"net.gudenau.minecraft.asm.",
"org.objectweb.asm.",
"com.google.gson.",
"org.lwjgl.",
"it.unimi.dsi.fastutil."
));

private static final Transformer BOOTSTRAP_TRANSFORMER = new BootstrapTransformer();

private static final MethodHandle ClassLoader$defineClass;
static{
try{
ClassLoader$defineClass = ReflectionHelper.findStatic(
ClassLoader.class,
"defineClass1",
Class.class,
ClassLoader.class, String.class, byte[].class, int.class, int.class, ProtectionDomain.class, String.class
);
}catch(ReflectiveOperationException e){
new RuntimeException("Failed to get ClassLoader.defineClass1", e).printStackTrace();
System.exit(0);
// Unreachable, makes javac happy
throw new RuntimeException("Failed to get ClassLoader.defineClass1", e);
}
}

private static ClassLoader classLoader;

public static void setClassLoader(ClassLoader classLoader){
MixinTransformer.classLoader = classLoader;
}


private final ClassLoader classLoader;

private final Set<String> seenClasses = new HashSet<>();
private final Locker seenClassesLocker = new Locker();

private final IMixinTransformer parent;
private final List<Transformer> transformers;
private final List<Transformer> earlyTransformers;

private final boolean forceDump = Configuration.DUMP.get() == Configuration.DumpMode.FORCE;
private final boolean dump = Configuration.DUMP.get() == Configuration.DumpMode.ON || forceDump;
MixinTransformer(IMixinTransformer parent){

MixinTransformer(IMixinTransformer parent, ClassLoader classLoader) {
this.parent = parent;
this.classLoader = classLoader;
transformers = RegistryImpl.INSTANCE.getTransformers();
earlyTransformers = RegistryImpl.INSTANCE.getEarlyTransformers();
}

@Override
public byte[] transformClassBytes(String name, String transformedName, byte[] basicClass){
if(seenClassesLocker.readLock(()->seenClasses.contains(name))){

public byte[] transformClassBytes(String name, String transformedName, byte[] basicClass) {
if (seenClassesLocker.readLock(() -> seenClasses.contains(name))) {
return basicClass;
}
if(seenClassesLocker.writeLock(()->{
if(seenClasses.contains(name)){
return true;
}else{
seenClasses.add(name);
return false;
}
})){
if (seenClassesLocker.writeLock(() -> !seenClasses.add(name))) {
return parent.transformClassBytes(name, transformedName, basicClass);
}

for(String prefix : BLACKLIST){
if(name.startsWith(prefix)){
byte[] transformedClass = parent.transformClassBytes(name, transformedName, basicClass);
Expand Down Expand Up @@ -231,52 +198,56 @@ private byte[] bootstrap(byte[] bytecode, boolean shouldBootstrap){
return null;
}

if(shouldBootstrap){
try{
ClassLoader$defineClass.invoke(
(ClassLoader)null, // AKA bootstrap ClassLoader
(String)null, // Let the JVM figure it out
bytecode,
0,
bytecode.length,
(ProtectionDomain)null,
(String)null
if(shouldBootstrap) {
try {
Bootstrap.ClassLoader$defineClass.invoke(
(ClassLoader) null, // AKA bootstrap ClassLoader
(String) null, // Let the JVM figure it out
bytecode,
0,
bytecode.length,
(ProtectionDomain) null,
(String) null
);
}catch(Throwable throwable){
} catch (Throwable throwable) {
new RuntimeException("Failed to force a class into the bootstrap ClassLoader", throwable).printStackTrace();
System.exit(0);
}

return null;
}else{
} else {
return bytecode;
}
}

public void blacklistPackage(String name){

public void blacklistPackages(Collection<String> packages) {
BLACKLIST.addAll(packages);
}

public void blacklistPackage(String name) {
BLACKLIST.add(name);
}
static class Cache extends MixinTransformer{

static class Cache extends MixinTransformer {
private final ClassCache cache;
Cache(IMixinTransformer parent, ClassCache cache){
super(parent);

Cache(IMixinTransformer parent, ClassLoader classLoader, ClassCache cache) {
super(parent, classLoader);
this.cache = cache;
}

@Override
byte[] cache(byte[] original, Supplier<byte[]> transformer){
if(original == null){
byte[] cache(byte[] original, Supplier<byte[]> transformer) {
if (original == null) {
return transformer.get();
}

Optional<byte[]> result = cache.getEntry(original);
if(result.isPresent()){
if (result.isPresent()) {
return result.get();
}else{
} else {
byte[] transformed = transformer.get();
if(transformed != null){
if (transformed != null) {
cache.putEntry(original, transformed);
}
return transformed;
Expand Down
Loading

0 comments on commit 77b3080

Please sign in to comment.