Generate mixin configs automatically using custom AP (#305)

This commit is contained in:
Fury_Phoenix 2023-12-28 06:36:49 -08:00 committed by GitHub
parent ae8cfbaa3d
commit 06bfd71d07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 555 additions and 108 deletions

View File

@ -0,0 +1,60 @@
plugins {
id 'com.github.johnrengelman.shadow'
id 'java-library'
id 'com.diffplug.spotless'
}
repositories {
mavenCentral()
maven { url uri("https://maven.fabricmc.net") }
maven { url "https://maven.neoforged.net/releases" }
}
dependencies {
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
compileOnly 'com.google.auto.service:auto-service:1.1.1'
implementation 'com.google.code.gson:gson:2.10.1'
shadow 'com.google.code.gson:gson:2.10.1'
implementation 'com.google.auto:auto-common:1.2.1'
shadow 'com.google.auto:auto-common:1.2.1'
implementation 'com.google.guava:guava:21.0'
shadow 'com.google.guava:guava:21.0'
implementation project(":annotations")
shadow project(":annotations")
// Shadow annotations
implementation 'net.fabricmc:sponge-mixin:0.12.5+'
implementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
implementation 'net.minecraftforge:mergetool:1.1.7'
implementation 'net.neoforged:mergetool:2.0.2'
}
tasks.withType(JavaCompile) {
options.compilerArgs += '--enable-preview'
options.release = 17
}
shadowJar {
dependencies {
include(dependency('net.fabricmc:sponge-mixin:'))
include(dependency('net.fabricmc:fabric-loader:'))
include(dependency(':mergetool:'))
}
// shadowJar bug
include '*.jar'
include 'META-INF/services/javax.annotation.processing.Processor'
include 'org/spongepowered/asm/mixin/Mixin.class'
include 'org/fury_phoenix/**/*'
include {it.getName() == 'OnlyIn.class'}
include {it.getName() == 'Dist.class'}
include {it.getName() == 'Environment.class'}
include {it.getName() == 'EnvType.class'}
}
spotless {
java {
removeUnusedImports()
}
}
version = '1.1.4'

View File

@ -0,0 +1,189 @@
package org.fury_phoenix.mixinAp.annotation;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import net.fabricmc.api.Environment;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.annotation.IgnoreMixin;
import org.fury_phoenix.mixinAp.util.TypedAccessorMap;
import org.spongepowered.asm.mixin.Mixin;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import static java.util.AbstractMap.SimpleImmutableEntry;
public class ClientMixinValidator {
private final Messager messager;
private final Elements elemUtils;
private final Types types;
private final boolean debug;
private static final TypedAccessorMap<Annotation> markers = new TypedAccessorMap<>();
private static final Map.Entry<Class<Environment>, Function<? super Environment, ?>>
FabricAccessor = new SimpleImmutableEntry<>(Environment.class, Environment::value);
private static final Map.Entry<
Class<net.minecraftforge.api.distmarker.OnlyIn>,
Function<? super net.minecraftforge.api.distmarker.OnlyIn, ?>>
ForgeAccessor = new SimpleImmutableEntry<>(
net.minecraftforge.api.distmarker.OnlyIn.class,
net.minecraftforge.api.distmarker.OnlyIn::value
);
private static final Map.Entry<
Class<net.neoforged.api.distmarker.OnlyIn>,
Function<? super net.neoforged.api.distmarker.OnlyIn, ?>>
NeoForgeAccessor = new SimpleImmutableEntry<>(
net.neoforged.api.distmarker.OnlyIn.class,
net.neoforged.api.distmarker.OnlyIn::value
);
static {
markers.put(FabricAccessor);
markers.put(ForgeAccessor);
markers.put(NeoForgeAccessor);
}
private static final Collection<String> unannotatedClasses = new HashSet<>();
public ClientMixinValidator(ProcessingEnvironment env) {
debug = Boolean.valueOf(env.getOptions().get("org.fury_phoenix.mixinAp.validator.debug"));
messager = env.getMessager();
elemUtils = env.getElementUtils();
types = env.getTypeUtils();
}
public boolean validateMixin(TypeElement annotatedMixinClass) {
return targetsClient(annotatedMixinClass) &&
(annotatedMixinClass.getAnnotation(ClientOnlyMixin.class) == null);
}
public boolean targetsClient(TypeElement annotatedMixinClass) {
return targetsClient(getTargets(annotatedMixinClass)) &&
!isIgnored(annotatedMixinClass);
}
private boolean targetsClient(Collection<?> classTargets) {
return classTargets.stream().anyMatch(this::targetsClient);
}
private boolean targetsClient(Object classTarget) {
return switch (classTarget) {
case TypeElement te ->
isClientMarked(te);
case TypeMirror tm -> {
var el = types.asElement(tm);
yield el != null ? targetsClient(el) : warn("TypeMirror of " + tm);
}
// If you're using a dollar sign in class names you are insane
case String s -> {
var te =
elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
yield te != null ? targetsClient(te) : warn(s);
}
default ->
throw new IllegalArgumentException("Unhandled type: "
+ classTarget.getClass() + "\n" + "Stringified contents: "
+ classTarget.toString());
};
}
private boolean isClientMarked(TypeElement te) {
for (var entry : markers.entrySet()) {
var marker = te.getAnnotation(entry.getKey());
if(marker == null) continue;
return entry.getValue().apply(marker).toString().equals("CLIENT");
}
if(debug && unannotatedClasses.add(te.toString())) {
messager.printMessage(Diagnostic.Kind.WARNING,
"No marker annotations present on " + te + "!");
}
return false;
}
private boolean isIgnored(TypeElement te) {
if(te.getAnnotation(IgnoreMixin.class) != null) {
messager.printMessage(Diagnostic.Kind.WARNING,
toSourceString(te.toString()) + " is ignored!");
return true;
}
return false;
}
private boolean warn(Object o) {
messager.printMessage(Diagnostic.Kind.WARNING,
toSourceString(o.toString()) + " can't be loaded, so it is skipped!");
return false;
}
public Map.Entry<? extends CharSequence, ? extends CharSequence>
getClientMixinEntry(TypeElement annotatedMixinClass) {
return new SimpleImmutableEntry<>(
annotatedMixinClass.getQualifiedName(),
getTargets(annotatedMixinClass)
.stream()
.filter(this::targetsClient)
.map(Object::toString)
.map(ClientMixinValidator::toSourceString)
.collect(Collectors.joining(", "))
);
}
private Collection<Object> getTargets(TypeElement annotatedMixinClass) {
Collection<? extends TypeMirror> clzsses = Set.of();
Collection<? extends String> imaginaries = Set.of();
TypeMirror MixinElement = elemUtils.getTypeElement(Mixin.class.getName()).asType();
for (var mirror : annotatedMixinClass.getAnnotationMirrors()) {
if(!types.isSameType(mirror.getAnnotationType(), MixinElement))
continue;
@SuppressWarnings("unchecked")
var wrappedClzss = (List<? extends AnnotationValue>)
getAnnotationValue(mirror, "value").getValue();
clzsses = wrappedClzss.stream()
.map(AnnotationValue::getValue)
.map(TypeMirror.class::cast)
.collect(Collectors.toSet());
@SuppressWarnings("unchecked")
var wrappedStrings = (List<? extends AnnotationValue>)
getAnnotationValue(mirror, "targets").getValue();
imaginaries = wrappedStrings.stream()
.map(AnnotationValue::getValue)
.map(String.class::cast)
.collect(Collectors.toSet());
}
return Stream.of(clzsses, imaginaries)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
}
public static String toSourceString(String bytecodeName) {
return bytecodeName.replaceAll("\\/", ".");
}
}

View File

@ -0,0 +1,115 @@
package org.fury_phoenix.mixinAp.annotation;
import com.google.auto.service.AutoService;
import com.google.common.base.Throwables;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import org.fury_phoenix.mixinAp.config.MixinConfig;
@SupportedAnnotationTypes({"org.spongepowered.asm.mixin.Mixin", "org.embeddedt.modernfix.annotation.ClientOnlyMixin"})
@SupportedOptions({"rootProject.name", "project.name", "org.fury_phoenix.mixinAp.validator.debug"})
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@AutoService(Processor.class)
public class MixinProcessor extends AbstractProcessor {
// Remember to call toString when using aliases
private static final Map<String, String> aliases = Map.of(
"Mixin", "mixins",
"ClientOnlyMixin", "client"
);
private final Map<String, List<String>> mixinConfigList = new HashMap<>();
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
try {
if(roundEnv.processingOver()){
filterMixinSets();
// create record for serialization, compute package name
String packageName = Optional.ofNullable(mixinConfigList.get("mixins"))
.orElse(mixinConfigList.get("client"))
.get(0).split("(?<=mixin)")[0];
finalizeMixinConfig();
new MixinConfig(packageName,
mixinConfigList.get("mixins"),
mixinConfigList.get("client")
).generateMixinConfig(processingEnv);
} else {
processMixins(annotations, roundEnv);
}
} catch (Exception e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Fatal error:" +
Throwables.getStackTraceAsString(e));
throw new RuntimeException(e);
// Halt the AP to prevent nonsense errors
}
return false;
}
private void processMixins(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
Set<? extends Element> annotatedMixins = roundEnv.getElementsAnnotatedWith(annotation);
Stream<TypeElement> mixinStream =
annotatedMixins.stream()
.map(TypeElement.class::cast);
validateCommonMixins(annotation, mixinStream);
List<String> mixins =
annotatedMixins.stream()
.map(TypeElement.class::cast)
.map(TypeElement::toString)
.collect(Collectors.toList());
mixinConfigList.putIfAbsent(aliases.get(annotation.getSimpleName().toString()), mixins);
}
}
private void filterMixinSets() {
List<String> commonSet = mixinConfigList.get("mixins");
if(commonSet == null) return;
commonSet.removeAll(mixinConfigList.get("client"));
}
private void validateCommonMixins(TypeElement annotation, Stream<TypeElement> mixins) {
if(!annotation.getSimpleName().toString().equals("Mixin"))
return;
ClientMixinValidator validator = new ClientMixinValidator(processingEnv);
// The implementation may throw a CME
mixins.sequential()
.filter(validator::validateMixin)
.map(validator::getClientMixinEntry)
.forEach(this::logClientClassTarget);
}
private void logClientClassTarget(Map.Entry<? extends CharSequence, ? extends CharSequence> mixin) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
"Mixin " + mixin.getKey() + " targets client-side classes: " + mixin.getValue());
}
private void finalizeMixinConfig() {
// relativize class names
for(var list : mixinConfigList.values()) {
list.replaceAll(className -> className.split("(?<=mixin.)")[1]);
}
}
}

View File

@ -0,0 +1,65 @@
package org.fury_phoenix.mixinAp.config;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import java.util.Optional;
import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.StandardLocation;
public record MixinConfig(
boolean required,
String minVersion,
@SerializedName("package")
String packageName,
String plugin,
String compatabilityLevel,
@SerializedName("mixins")
List<String> commonMixins,
@SerializedName("client")
List<String> clientMixins,
InjectorOptions injectors, OverwriteOptions overwrites
) {
public MixinConfig(String packageName, List<String> commonMixins, List<String> clientMixins) {
this(true, "0.8", packageName, "org.embeddedt.modernfix.core.ModernFixMixinPlugin", "JAVA_8",
commonMixins, clientMixins, InjectorOptions.DEFAULT, OverwriteOptions.DEFAULT);
}
public record InjectorOptions(int defaultRequire) {
public static final InjectorOptions DEFAULT = new InjectorOptions(1);
}
public record OverwriteOptions(boolean conformVisibility) {
public static final OverwriteOptions DEFAULT = new OverwriteOptions(true);
}
public void generateMixinConfig(ProcessingEnvironment env) throws IOException {
try (
Writer mixinConfigWriter = env.getFiler()
.createResource(StandardLocation.SOURCE_OUTPUT, "",
MixinConfig.computeMixinConfigPath(
Optional.of(env.getOptions().get("rootProject.name")),
Optional.ofNullable(env.getOptions().get("project.name"))
)
).openWriter()
) {
String mixinConfig = new GsonBuilder()
.setPrettyPrinting()
.create()
.toJson(this);
mixinConfigWriter.write(mixinConfig);
mixinConfigWriter.write("\n");
} catch (IOException e) { throw e; }
}
private static String computeMixinConfigPath(Optional<String> rootProjectName, Optional<String> projectName) {
return "resources/" +
rootProjectName.get() +
(projectName.isPresent() ? "-" : "") +
projectName.orElse("") +
".mixins.json";
}
}

View File

@ -0,0 +1,37 @@
package org.fury_phoenix.mixinAp.util;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import static java.util.Map.Entry;
/**
* Type-safe heterogenous map of accessors
* @author Fury_Phoenix
* @reason Type-safety since K, V of Map are non-identical
* @param <SuperType> The supertype of desired types.
* This is useful in cases such as <A extends Annotation>.
*/
public class TypedAccessorMap<SuperType> {
private final Map<Class<? extends SuperType>, Function<Object, ?>> typedAccessors = new HashMap<>();
public <T extends SuperType> void put(Class<T> key, Function<? super T, ?> func) {
Objects.requireNonNull(func);
typedAccessors.put(Objects.requireNonNull(key), o -> func.apply(key.cast(o)));
}
public <T extends SuperType> void put(Entry<Class<T>, Function<? super T, ?>> entry) {
put(entry.getKey(), entry.getValue());
}
public <T extends SuperType> Function<Object, ?> get(Class<T> key) {
return typedAccessors.get(key);
}
public Set<Entry<Class<? extends SuperType>, Function<Object, ?>>> entrySet() {
return typedAccessors.entrySet();
}
}

6
annotations/build.gradle Normal file
View File

@ -0,0 +1,6 @@
plugins {
id 'modernfix.common-conventions'
id 'java-library'
}
version = '1.1.0'

View File

@ -0,0 +1,11 @@
package org.embeddedt.modernfix.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface IgnoreMixin {
}

View File

@ -7,7 +7,7 @@ plugins {
id 'org.ajoberstar.grgit' version '5.2.0'
id 'se.bjurr.gitchangelog.git-changelog-gradle-plugin' version '1.79.0'
id "com.modrinth.minotaur" version "2.+" apply false
id("com.diffplug.spotless") version "6.18.0" apply false
id("com.diffplug.spotless") version "6.18.0" apply false
id 'modernfix.common-conventions' apply false
}

View File

@ -1,3 +1,3 @@
plugins {
id 'groovy-gradle-plugin'
}
}

View File

@ -78,4 +78,4 @@ repositories {
url 'https://maven.terraformersmc.com/releases'
}
maven { url = "https://jitpack.io" }
}
}

View File

@ -16,37 +16,26 @@ dependencies {
parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
}
}
implementation project(":annotations")
annotationProcessor project(path: ":annotation-processor", configuration: 'shadow')
}
project.sourceSets {
main.resources.srcDirs += [layout.buildDirectory.dir("generated/sources/annotationProcessor/java/main/resources")]
}
// hack to shut up gradle about the hack to include generated resources
tasks {
processResources {
def mixinFileList = []
def mixinDirectory = file("src/main/java/org/embeddedt/modernfix/" + project.name + "/mixin")
fileTree(mixinDirectory).visit { FileVisitDetails details ->
if(details.file.isFile()) {
def fileName = mixinDirectory.relativePath(details.file).toString().replaceFirst(/\.java$/, "").replace('/', '.')
mixinFileList << fileName
}
}
dependsOn compileJava
}
}
def mixinClassesStringB = new StringBuilder()
for(int i = 0; i < mixinFileList.size(); i++) {
mixinClassesStringB.append(" \"")
mixinClassesStringB.append(mixinFileList.get(i))
mixinClassesStringB.append('"')
if(i < (mixinFileList.size() - 1))
mixinClassesStringB.append(',')
mixinClassesStringB.append('\n')
}
def replacements = [
mixin_classes: mixinClassesStringB.toString()
]
inputs.properties replacements
def filePattern = "modernfix-" + project.name + ".mixins.json"
filesMatching(filePattern) {
expand replacements
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.jvmArgs << '--enable-preview'
configure(options) {
if (!name.toLowerCase().contains('test')) {
options.compilerArgs << "-ArootProject.name=${rootProject.name}" << "-Aproject.name=${project.name}"
}
}
}
}

View File

@ -6,6 +6,7 @@ import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.world.item.Item;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.dynamicresources.DynamicModelCache;
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
import org.embeddedt.modernfix.util.DynamicInt2ObjectMap;
@ -18,6 +19,7 @@ import java.util.HashMap;
import java.util.Map;
@Mixin(ItemModelShaper.class)
@ClientOnlyMixin
public abstract class ItemModelShaperMixin {
@Shadow public abstract ModelManager getModelManager();

View File

@ -1,6 +1,7 @@
package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering;
import net.minecraft.client.renderer.GameRenderer;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.render.RenderState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -8,6 +9,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
@ClientOnlyMixin
public class GameRendererMixin {
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(FJLcom/mojang/blaze3d/vertex/PoseStack;)V", shift = At.Shift.BEFORE))
private void markRenderingLevel(CallbackInfo ci) {

View File

@ -11,6 +11,7 @@ import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.render.FastItemRenderType;
import org.embeddedt.modernfix.render.RenderState;
import org.embeddedt.modernfix.render.SimpleItemModelView;
@ -21,6 +22,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = ItemRenderer.class, priority = 600)
@ClientOnlyMixin
public abstract class ItemRendererMixin {
private ItemTransforms.TransformType transformType;
private final SimpleItemModelView modelView = new SimpleItemModelView();

View File

@ -1,16 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "org.embeddedt.modernfix.common.mixin",
"plugin": "org.embeddedt.modernfix.core.ModernFixMixinPlugin",
"compatibilityLevel": "JAVA_8",
"mixins": [
${mixin_classes}
],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"conformVisibility": true
}
}

View File

@ -1,5 +1,5 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
id "com.github.johnrengelman.shadow"
id 'com.adarshr.test-logger' version '3.2.0'
id "modernfix.mod-common-conventions"
id "modernfix.platform-conventions"
@ -122,4 +122,4 @@ publishing {
repositories {
// Add repositories to publish to here.
}
}
}

View File

@ -1,16 +0,0 @@
{
"required": true,
"package": "org.embeddedt.modernfix.fabric.mixin",
"plugin": "org.embeddedt.modernfix.core.ModernFixMixinPlugin",
"compatibilityLevel": "JAVA_8",
"minVersion": "0.8",
"mixins": [
${mixin_classes}
],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"conformVisibility": true
}
}

View File

@ -1,5 +1,5 @@
plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
id "com.github.johnrengelman.shadow"
id "modernfix.mod-common-conventions"
id "modernfix.platform-conventions"
}
@ -141,4 +141,4 @@ publishing {
repositories {
// Add repositories to publish to here.
}
}
}

View File

@ -2,6 +2,7 @@ package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.systems.RenderSystem;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
@ -9,6 +10,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(InputConstants.class)
@ClientOnlyMixin
@RequiresMod("jei")
public class InputConstantsMixin {
@Redirect(method = "isKeyDown", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwGetKey(JI)I", remap = false))

View File

@ -1,11 +1,13 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.world.entity.projectile.EyeOfEnder;
import org.embeddedt.modernfix.annotation.IgnoreMixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(EyeOfEnder.class)
@IgnoreMixin
public interface EyeOfEnderAccess {
@Accessor
void setLife(int life);
@Accessor
void setLife(int life);
}

View File

@ -1,6 +1,7 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.world.entity.projectile.EyeOfEnder;
import org.embeddedt.modernfix.annotation.IgnoreMixin;
import org.embeddedt.modernfix.forge.structure.logic.EyeOfEnderData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -8,30 +9,31 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EyeOfEnder.class)
@IgnoreMixin
public class EyeOfEnderMixin implements EyeOfEnderData {
private boolean locateTaskOngoing = false;
private boolean locateTaskOngoing = false;
@Override
public void setLocateTaskOngoing(boolean locateTaskOngoing) {
this.locateTaskOngoing = locateTaskOngoing;
}
@Override
public void setLocateTaskOngoing(boolean locateTaskOngoing) {
this.locateTaskOngoing = locateTaskOngoing;
}
/*
Intercept EyeOfEnder#tick call and return after the super call if there's an ongoing locate task. This is to
prevent the entity from moving or dying until we have a location result.
*/
@Inject(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Entity;tick()V",
shift = At.Shift.AFTER
),
cancellable = true
)
public void skipTick(CallbackInfo ci) {
if (locateTaskOngoing) {
ci.cancel();
}
}
/*
Intercept EyeOfEnder#tick call and return after the super call if there's an ongoing locate task. This is to
prevent the entity from moving or dying until we have a location result.
*/
@Inject(
method = "tick",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Entity;tick()V",
shift = At.Shift.AFTER
),
cancellable = true
)
public void skipTick(CallbackInfo ci) {
if (locateTaskOngoing) {
ci.cancel();
}
}
}

View File

@ -1,16 +0,0 @@
{
"required": true,
"package": "org.embeddedt.modernfix.forge.mixin",
"plugin": "org.embeddedt.modernfix.core.ModernFixMixinPlugin",
"compatibilityLevel": "JAVA_8",
"minVersion": "0.8",
"mixins": [
${mixin_classes}
],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"conformVisibility": true
}
}

View File

@ -16,6 +16,8 @@ refined_storage_version=3807951
kubejs_version=1605.3.19-build.299
ctm_version=MC1.16.1-1.1.2.6
supported_minecraft_versions=1.16.4,1.16.5
// Look up maven coordinates when changing shadow_version
shadow_version=7.1.2
fabric_loader_version=0.14.21
fabric_api_version=0.42.0+1.16
@ -25,4 +27,4 @@ modmenu_version=1.16.23
spark_forge_version=3767277
spark_fabric_version=3337642
use_fabric_api_at_runtime=true
use_fabric_api_at_runtime=true

View File

@ -5,8 +5,17 @@ pluginManagement {
maven { url "https://maven.architectury.dev/" }
maven { url "https://maven.minecraftforge.net/" }
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.github.johnrengelman.shadow") {
useModule("gradle.plugin.com.github.johnrengelman:shadow:${shadow_version}")
}
}
}
}
include("annotation-processor")
include("annotations")
include("test_agent")
include("common")