diff --git a/annotation-processor/build.gradle b/annotation-processor/build.gradle new file mode 100644 index 00000000..223d94bc --- /dev/null +++ b/annotation-processor/build.gradle @@ -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' diff --git a/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/annotation/ClientMixinValidator.java b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/annotation/ClientMixinValidator.java new file mode 100644 index 00000000..2d76bcef --- /dev/null +++ b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/annotation/ClientMixinValidator.java @@ -0,0 +1,190 @@ +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 markers = new TypedAccessorMap<>(); + + private static final Map.Entry, Function> + FabricAccessor = new SimpleImmutableEntry<>(Environment.class, Environment::value); + + private static final Map.Entry< + Class, + Function> + ForgeAccessor = new SimpleImmutableEntry<>( + net.minecraftforge.api.distmarker.OnlyIn.class, + net.minecraftforge.api.distmarker.OnlyIn::value + ); + + private static final Map.Entry< + Class, + Function> + 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 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 + 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 getTargets(TypeElement annotatedMixinClass) { + Collection clzsses = Set.of(); + Collection 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) + getAnnotationValue(mirror, "value").getValue(); + + clzsses = wrappedClzss.stream() + .map(AnnotationValue::getValue) + .filter(o -> o instanceof TypeMirror) + .map(TypeMirror.class::cast) + .collect(Collectors.toSet()); + + @SuppressWarnings("unchecked") + var wrappedStrings = (List) + 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("\\/", "."); + } +} diff --git a/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/annotation/MixinProcessor.java b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/annotation/MixinProcessor.java new file mode 100644 index 00000000..747f8865 --- /dev/null +++ b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/annotation/MixinProcessor.java @@ -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 aliases = Map.of( + "Mixin", "mixins", + "ClientOnlyMixin", "client" + ); + + private final Map> mixinConfigList = new HashMap<>(); + + @Override + public boolean process(Set 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 annotations, RoundEnvironment roundEnv) { + for (TypeElement annotation : annotations) { + Set annotatedMixins = roundEnv.getElementsAnnotatedWith(annotation); + + Stream mixinStream = + annotatedMixins.stream() + .map(TypeElement.class::cast); + + validateCommonMixins(annotation, mixinStream); + + List 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 commonSet = mixinConfigList.get("mixins"); + if(commonSet == null) return; + commonSet.removeAll(mixinConfigList.get("client")); + } + + private void validateCommonMixins(TypeElement annotation, Stream 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 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]); + } + } +} diff --git a/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/config/MixinConfig.java b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/config/MixinConfig.java new file mode 100644 index 00000000..9d1e6c91 --- /dev/null +++ b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/config/MixinConfig.java @@ -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 commonMixins, + @SerializedName("client") + List clientMixins, + InjectorOptions injectors, OverwriteOptions overwrites + ) { + public MixinConfig(String packageName, List commonMixins, List 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 rootProjectName, Optional projectName) { + return "resources/" + + rootProjectName.get() + + (projectName.isPresent() ? "-" : "") + + projectName.orElse("") + + ".mixins.json"; + } +} diff --git a/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/util/TypedAccessorMap.java b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/util/TypedAccessorMap.java new file mode 100644 index 00000000..5632a917 --- /dev/null +++ b/annotation-processor/src/main/java/org/fury_phoenix/mixinAp/util/TypedAccessorMap.java @@ -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 The supertype of desired types. + * This is useful in cases such as . + */ +public class TypedAccessorMap { + private final Map, Function> typedAccessors = new HashMap<>(); + + public void put(Class key, Function func) { + Objects.requireNonNull(func); + typedAccessors.put(Objects.requireNonNull(key), o -> func.apply(key.cast(o))); + } + + public void put(Entry, Function> entry) { + put(entry.getKey(), entry.getValue()); + } + + public Function get(Class key) { + return typedAccessors.get(key); + } + + public Set, Function>> entrySet() { + return typedAccessors.entrySet(); + } +} diff --git a/annotations/build.gradle b/annotations/build.gradle new file mode 100644 index 00000000..5271e5b3 --- /dev/null +++ b/annotations/build.gradle @@ -0,0 +1,6 @@ +plugins { + id 'modernfix.common-conventions' + id 'java-library' +} + +version = '1.1.0' diff --git a/common/src/main/java/org/embeddedt/modernfix/annotation/ClientOnlyMixin.java b/annotations/src/main/java/org/embeddedt/modernfix/annotation/ClientOnlyMixin.java similarity index 100% rename from common/src/main/java/org/embeddedt/modernfix/annotation/ClientOnlyMixin.java rename to annotations/src/main/java/org/embeddedt/modernfix/annotation/ClientOnlyMixin.java diff --git a/annotations/src/main/java/org/embeddedt/modernfix/annotation/IgnoreMixin.java b/annotations/src/main/java/org/embeddedt/modernfix/annotation/IgnoreMixin.java new file mode 100644 index 00000000..00ae1fb7 --- /dev/null +++ b/annotations/src/main/java/org/embeddedt/modernfix/annotation/IgnoreMixin.java @@ -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 { +} + diff --git a/common/src/main/java/org/embeddedt/modernfix/annotation/IgnoreOutsideDev.java b/annotations/src/main/java/org/embeddedt/modernfix/annotation/IgnoreOutsideDev.java similarity index 100% rename from common/src/main/java/org/embeddedt/modernfix/annotation/IgnoreOutsideDev.java rename to annotations/src/main/java/org/embeddedt/modernfix/annotation/IgnoreOutsideDev.java diff --git a/common/src/main/java/org/embeddedt/modernfix/annotation/RequiresMod.java b/annotations/src/main/java/org/embeddedt/modernfix/annotation/RequiresMod.java similarity index 100% rename from common/src/main/java/org/embeddedt/modernfix/annotation/RequiresMod.java rename to annotations/src/main/java/org/embeddedt/modernfix/annotation/RequiresMod.java diff --git a/build.gradle b/build.gradle index 78e5255d..504cc599 100644 --- a/build.gradle +++ b/build.gradle @@ -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 } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 1957c339..67840524 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,3 +1,3 @@ plugins { id 'groovy-gradle-plugin' -} \ No newline at end of file +} diff --git a/buildSrc/src/main/groovy/modernfix.common-conventions.gradle b/buildSrc/src/main/groovy/modernfix.common-conventions.gradle index 3c3d5e07..cde96eab 100644 --- a/buildSrc/src/main/groovy/modernfix.common-conventions.gradle +++ b/buildSrc/src/main/groovy/modernfix.common-conventions.gradle @@ -77,5 +77,4 @@ repositories { maven { url 'https://maven.terraformersmc.com/releases' } - maven { url = "https://jitpack.io" } -} \ No newline at end of file +} diff --git a/buildSrc/src/main/groovy/modernfix.mod-common-conventions.gradle b/buildSrc/src/main/groovy/modernfix.mod-common-conventions.gradle index 3362ce37..2997c5cd 100644 --- a/buildSrc/src/main/groovy/modernfix.mod-common-conventions.gradle +++ b/buildSrc/src/main/groovy/modernfix.mod-common-conventions.gradle @@ -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}" } } -} \ No newline at end of file +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java index bb5aebb7..114577c1 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/feature/disable_unihex_font/UnihexProviderDefinitionMixin.java @@ -7,6 +7,7 @@ import net.minecraft.client.gui.font.providers.GlyphProviderDefinition; import net.minecraft.client.gui.font.providers.UnihexProvider; import net.minecraft.server.packs.resources.ResourceManager; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -16,6 +17,7 @@ import java.io.IOException; import java.lang.reflect.Constructor; @Mixin(UnihexProvider.Definition.class) +@ClientOnlyMixin public class UnihexProviderDefinitionMixin { @Inject(method = "unpack", at = @At("HEAD"), cancellable = true) private void disableProvider(CallbackInfoReturnable> cir) { diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java index 6725a87a..424fa2d0 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemModelShaperMixin.java @@ -7,6 +7,7 @@ import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.resources.ResourceLocation; 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; @@ -19,6 +20,7 @@ import java.util.HashMap; import java.util.Map; @Mixin(ItemModelShaper.class) +@ClientOnlyMixin public abstract class ItemModelShaperMixin { @Shadow public abstract ModelManager getModelManager(); diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemOverridesMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemOverridesMixin.java new file mode 100644 index 00000000..5de98b42 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ItemOverridesMixin.java @@ -0,0 +1,26 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.duck.IExtendedModelBaker; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ItemOverrides.class) +@ClientOnlyMixin +public class ItemOverridesMixin { + @WrapOperation(method = "bakeModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBaker;getModel(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/UnbakedModel;")) + private UnbakedModel preventThrowForMissing(ModelBaker instance, ResourceLocation resourceLocation, Operation original) { + boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false); + try { + return original.call(instance, resourceLocation); + } finally { + ((IExtendedModelBaker)instance).throwOnMissingModel(prevState); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelManagerMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelManagerMixin.java index 683f4169..04351172 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelManagerMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelManagerMixin.java @@ -11,6 +11,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.util.LambdaMap; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -26,6 +27,7 @@ import java.util.concurrent.Executor; import java.util.stream.Collectors; @Mixin(ModelManager.class) +@ClientOnlyMixin public class ModelManagerMixin { @Redirect(method = "reload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelManager;loadBlockModels(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) private CompletableFuture> deferBlockModelLoad(ResourceManager manager, Executor executor) { diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java index ee3a0f9d..d457b5d4 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/GameRendererMixin.java @@ -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) { diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java index d18e369a..d138f29d 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java @@ -11,6 +11,7 @@ import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.world.item.ItemDisplayContext; 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 ItemDisplayContext transformType; private final SimpleItemModelView modelView = new SimpleItemModelView(); diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 4da9e34b..a21f2542 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -26,6 +26,8 @@ import java.util.*; import java.util.function.BooleanSupplier; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; public class ModernFixEarlyConfig { private static final Logger LOGGER = LogManager.getLogger("ModernFixConfig"); @@ -85,7 +87,10 @@ public class ModernFixEarlyConfig { continue; try(Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { JsonObject configObject = (JsonObject)new JsonParser().parse(reader); - JsonArray mixinList = configObject.getAsJsonArray("mixins"); + List mixinList = Stream.of("mixins", "client") + .map(key -> Optional.ofNullable(configObject.getAsJsonArray(key))) + .flatMap(arr -> arr.map(jsonElements -> StreamSupport.stream(jsonElements.spliterator(), false)).orElseGet(Stream::of)) + .collect(Collectors.toList()); String packageName = configObject.get("package").getAsString().replace('.', '/'); for(JsonElement mixin : mixinList) { mixinPaths.add(packageName + "/" + mixin.getAsString().replace('.', '/') + ".class"); @@ -212,6 +217,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant"); disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me"); disableIfModPresent("mixin.bugfix.preserve_early_window_pos", "better_loading_screen"); + disableIfModPresent("mixin.perf.dynamic_dfu", "litematica"); disableIfModPresent("mixin.perf.cache_strongholds", "littletiles", "c2me"); // content overlap disableIfModPresent("mixin.perf.deduplicate_wall_shapes", "dashloader"); diff --git a/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBaker.java b/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBaker.java index 5a26ed55..b50f65d4 100644 --- a/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBaker.java +++ b/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBaker.java @@ -3,6 +3,7 @@ package org.embeddedt.modernfix.duck; public interface IExtendedModelBaker { /** * Causes the ModelBaker to throw when it finds a missing model instead of proceeding with the bake. + * @return the previous value of this flag */ - void throwOnMissingModel(); + boolean throwOnMissingModel(boolean flag); } diff --git a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java index 61a081a0..c7d3717f 100644 --- a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java +++ b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelBakeryHelpers.java @@ -59,7 +59,7 @@ public class ModelBakeryHelpers { } private static > T getValueHelper(Property property, String value) { - return property.getValue(value).orElse((T) null); + return property.getValue(value).orElse(null); } private static final Splitter COMMA_SPLITTER = Splitter.on(','); diff --git a/common/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java b/common/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java index 6fe2c6b1..9db7642b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java +++ b/common/src/main/java/org/embeddedt/modernfix/packet/EntityIDSyncPacket.java @@ -2,7 +2,9 @@ package org.embeddedt.modernfix.packet; import com.mojang.datafixers.util.Pair; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import org.embeddedt.modernfix.ModernFix; @@ -10,7 +12,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; -public class EntityIDSyncPacket { +public class EntityIDSyncPacket implements CustomPacketPayload { + public static final ResourceLocation ID = new ResourceLocation(ModernFix.MODID, "entity_id_sync"); private Map, List>> map; public EntityIDSyncPacket(Map, List>> map) { @@ -21,11 +24,8 @@ public class EntityIDSyncPacket { return this.map; } - public EntityIDSyncPacket() { - this.map = new HashMap<>(); - } - - public void serialize(FriendlyByteBuf buf) { + @Override + public void write(FriendlyByteBuf buf) { buf.writeVarInt(map.keySet().size()); for(Map.Entry, List>> entry : map.entrySet()) { buf.writeUtf(entry.getKey().getName()); @@ -38,8 +38,8 @@ public class EntityIDSyncPacket { } @SuppressWarnings("unchecked") - public static EntityIDSyncPacket deserialize(FriendlyByteBuf buf) { - EntityIDSyncPacket self = new EntityIDSyncPacket(); + public EntityIDSyncPacket(FriendlyByteBuf buf) { + EntityIDSyncPacket self = this; int numEntityClasses = buf.readVarInt(); for(int i = 0; i < numEntityClasses; i++) { String clzName = buf.readUtf(); @@ -73,6 +73,10 @@ public class EntityIDSyncPacket { ModernFix.LOGGER.error("Error deserializing packet", e); } } - return self; + } + + @Override + public ResourceLocation id() { + return ID; } } diff --git a/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java b/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java index 0a805814..1f38dff9 100644 --- a/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java +++ b/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java @@ -4,6 +4,7 @@ import com.google.common.collect.Multimap; import com.mojang.brigadier.CommandDispatcher; import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; @@ -39,7 +40,7 @@ public interface ModernFixPlatformHooks { Path getGameDirectory(); - void sendPacket(ServerPlayer player, Object packet); + void sendPacket(ServerPlayer player, CustomPacketPayload packet); Multimap getCustomModOptions(); diff --git a/common/src/main/java/org/embeddedt/modernfix/registry/RegistryStorage.java b/common/src/main/java/org/embeddedt/modernfix/registry/RegistryStorage.java index 252676d2..5d2fb207 100644 --- a/common/src/main/java/org/embeddedt/modernfix/registry/RegistryStorage.java +++ b/common/src/main/java/org/embeddedt/modernfix/registry/RegistryStorage.java @@ -15,9 +15,8 @@ public class RegistryStorage { public static BiMap, DirectStorageRegistryObject> createKeyStorage(ResourceKey> registryKey, BiMap storage) { if(storage instanceof DirectStorageBiMap) { - DirectStorageBiMap directStorageBiMap = (DirectStorageBiMap)storage; // silently ignore put/putAll calls on this map - return new TransformingBiMap, DirectStorageRegistryObject>(directStorageBiMap, loc -> ResourceKey.create(registryKey, loc), ResourceKey::location, Function.identity(), Function.identity()) { + return new TransformingBiMap, DirectStorageRegistryObject>(storage, loc -> ResourceKey.create(registryKey, loc), ResourceKey::location, Function.identity(), Function.identity()) { @Override public DirectStorageRegistryObject put(ResourceKey key, DirectStorageRegistryObject value) { return null; diff --git a/common/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java b/common/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java index 8efaa4f1..1daa97a8 100644 --- a/common/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java +++ b/common/src/main/java/org/embeddedt/modernfix/util/ClassInfoManager.java @@ -3,16 +3,22 @@ package org.embeddedt.modernfix.util; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.logging.ILogger; +import org.spongepowered.asm.logging.LoggerAdapterDefault; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; import org.spongepowered.asm.mixin.transformer.ClassInfo; +import org.spongepowered.asm.service.MixinServiceAbstract; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; public class ClassInfoManager { private static boolean hasRun = false; + private static final List loggersToRestore = new ArrayList<>(); public static void clear() { if (!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager") || hasRun) return; @@ -25,11 +31,33 @@ public class ClassInfoManager { return f; } + private static void changeLoggerAndRestoreLater(Map map, ILogger newLogger) { + ILogger oldLogger = map.put("mixin.audit", newLogger); + loggersToRestore.add(() -> map.put("mixin.audit", oldLogger)); + } + + private static void disableLoggers() throws ReflectiveOperationException { + // Disable default audit logger + Field loggersField = accessible(MixinServiceAbstract.class.getDeclaredField("loggers")); + changeLoggerAndRestoreLater((Map)loggersField.get(null), new LoggerAdapterDefault("mixin.audit")); + Class fabricLogger = null; + try { + fabricLogger = Class.forName("net.fabricmc.loader.impl.knot.MixinLogger"); + } catch(Throwable e) { + // Probably not Fabric + return; + } + // Disable Fabric audit logger + loggersField = accessible(fabricLogger.getDeclaredField("LOGGER_MAP")); + changeLoggerAndRestoreLater((Map)loggersField.get(null), new LoggerAdapterDefault("mixin.audit")); + } + private static void doClear() { Map classInfoCache; Field mixinField, stateField, classNodeField, methodsField, fieldsField; Class stateClz; try { + disableLoggers(); Field field = accessible(ClassInfo.class.getDeclaredField("cache")); classInfoCache = (Map) field.get(null); mixinField = accessible(ClassInfo.class.getDeclaredField("mixin")); @@ -70,6 +98,9 @@ public class ClassInfoManager { } catch (RuntimeException e) { e.printStackTrace(); } + // Put back the old logger + loggersToRestore.forEach(Runnable::run); + loggersToRestore.clear(); ModernFix.LOGGER.warn("Cleared mixin data structures"); } } diff --git a/common/src/main/resources/modernfix-common.mixins.json b/common/src/main/resources/modernfix-common.mixins.json deleted file mode 100644 index 437491fb..00000000 --- a/common/src/main/resources/modernfix-common.mixins.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "org.embeddedt.modernfix.common.mixin", - "plugin": "org.embeddedt.modernfix.core.ModernFixMixinPlugin", - "compatibilityLevel": "JAVA_17", - "mixins": [ -${mixin_classes} - ], - "injectors": { - "defaultRequire": 1 - }, - "overwrites": { - "conformVisibility": true - } -} diff --git a/fabric/build.gradle b/fabric/build.gradle index cbff9707..5de446b8 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -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" @@ -63,6 +63,7 @@ dependencies { common(project(path: ":common", configuration: "namedElements")) { transitive false } testImplementation(shadowCommon(project(path: ":common", configuration: "transformProductionFabric"))) { transitive false } + shadowCommon(project(path: ":annotations")) testImplementation(platform("org.junit:junit-bom:${project.junit_version}")) testImplementation("org.junit.jupiter:junit-jupiter-api") diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/core/ClientCommonPacketListenerImplMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/core/ClientCommonPacketListenerImplMixin.java index 7dacc520..f0130601 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/core/ClientCommonPacketListenerImplMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/core/ClientCommonPacketListenerImplMixin.java @@ -2,12 +2,14 @@ package org.embeddedt.modernfix.fabric.mixin.core; import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl; import org.embeddedt.modernfix.ModernFixClientFabric; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientCommonPacketListenerImpl.class) +@ClientOnlyMixin public class ClientCommonPacketListenerImplMixin { @Inject(method = "handleUpdateTags", at = @At("RETURN")) private void signalTags(CallbackInfo ci) { diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ItemOverridesFabricMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ItemOverridesFabricMixin.java new file mode 100644 index 00000000..140f0737 --- /dev/null +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ItemOverridesFabricMixin.java @@ -0,0 +1,31 @@ +package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.duck.IExtendedModelBaker; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ItemOverrides.class) +@ClientOnlyMixin +public class ItemOverridesFabricMixin { + /** + * @author embeddedt + * @reason servers insist on generating invalid item overrides that have missing models + */ + @WrapOperation(method = "bakeModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBaker;bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;)Lnet/minecraft/client/resources/model/BakedModel;")) + private BakedModel bake(ModelBaker instance, ResourceLocation resourceLocation, ModelState modelState, Operation original) { + boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false); + try { + return original.call(instance, resourceLocation, modelState); + } finally { + ((IExtendedModelBaker)instance).throwOnMissingModel(prevState); + } + } +} diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java index 4db81275..2324eda4 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java @@ -11,6 +11,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.ModernFixClient; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.duck.IExtendedModelBaker; import org.embeddedt.modernfix.duck.IExtendedModelBakery; @@ -29,6 +30,7 @@ import java.util.Optional; import java.util.function.Function; @Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600) +@ClientOnlyMixin public abstract class ModelBakerImplMixin implements IExtendedModelBaker { private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); @Shadow @Final private ModelBakery field_40571; @@ -57,8 +59,10 @@ public abstract class ModelBakerImplMixin implements IExtendedModelBaker { private boolean throwIfMissing; @Override - public void throwOnMissingModel() { - throwIfMissing = true; + public boolean throwOnMissingModel(boolean flag) { + boolean old = throwIfMissing; + throwIfMissing = flag; + return old; } @Inject(method = "getModel", at = @At("HEAD"), cancellable = true) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index fd51fc97..39ac1fb3 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -310,7 +310,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return m; ModelBakery self = (ModelBakery) (Object) this; ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation); - ((IExtendedModelBaker)theBaker).throwOnMissingModel(); + ((IExtendedModelBaker)theBaker).throwOnMissingModel(true); synchronized(this) { m = theBaker.bake(modelLocation, state); } if(m != null) loadedBakedModels.put(key, m); diff --git a/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java b/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java index c87b50cd..e9e6ebcb 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java @@ -11,6 +11,7 @@ import net.fabricmc.loader.api.metadata.CustomValue; import net.fabricmc.loader.api.metadata.ModMetadata; import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.CreativeModeTabs; @@ -72,7 +73,7 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks { return FabricLoader.getInstance().getGameDir(); } - public void sendPacket(ServerPlayer player, Object packet) { + public void sendPacket(ServerPlayer player, CustomPacketPayload packet) { //PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), packet); } diff --git a/fabric/src/main/resources/modernfix-fabric.mixins.json b/fabric/src/main/resources/modernfix-fabric.mixins.json deleted file mode 100644 index 3d94ea0d..00000000 --- a/fabric/src/main/resources/modernfix-fabric.mixins.json +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/fabric/testmod/build.gradle b/fabric/testmod/build.gradle index a8dab8eb..ef69d092 100644 --- a/fabric/testmod/build.gradle +++ b/fabric/testmod/build.gradle @@ -41,3 +41,5 @@ processResources { } } +// Make genSources do nothing in this project +project.gradle.startParameter.excludedTaskNames.add("genSources") \ No newline at end of file diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/model_data_manager_cme/ModelDataManagerMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/model_data_manager_cme/ModelDataManagerMixin.java index b0b5843e..5fba1b2e 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/model_data_manager_cme/ModelDataManagerMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/model_data_manager_cme/ModelDataManagerMixin.java @@ -5,6 +5,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.ChunkPos; import net.minecraftforge.client.model.data.ModelDataManager; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -12,6 +13,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.Redirect; import java.util.Collections; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -24,12 +26,14 @@ import java.util.function.Function; public abstract class ModelDataManagerMixin { @Shadow protected abstract void refreshAt(ChunkPos chunk); + @Shadow @Final private Map> needModelDataRefresh; + /** * Make the set of positions to refresh a real concurrent hash set rather than relying on synchronizedSet, * because the returned iterator won't be thread-safe otherwise. See https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/7511 */ @ModifyArg(method = "requestRefresh", at = @At(value = "INVOKE", target = "Ljava/util/Map;computeIfAbsent(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;", ordinal = 0), index = 1, remap = false) - private static Function> changeTypeOfSetUsed(Function> mappingFunction) { + private Function> changeTypeOfSetUsed(Function> mappingFunction) { return pos -> Collections.newSetFromMap(new ConcurrentHashMap<>()); } @@ -37,7 +41,8 @@ public abstract class ModelDataManagerMixin { private void onlyRefreshOnMainThread(ModelDataManager instance, ChunkPos pos) { // Only refresh model data on the main thread. This prevents calling getBlockEntity from worker threads // which could cause weird CMEs or other behavior. - if(Minecraft.getInstance().isSameThread()) { + // Avoid the loop if no model data needs to be refreshed, to prevent unnecessary allocation. + if(Minecraft.getInstance().isSameThread() && !needModelDataRefresh.isEmpty()) { // Refresh the given chunk, and all its neighbors. This is less efficient than the default code // but we have no choice since we need to not do refreshing on workers, and blocks might // try to access model data in neighboring chunks. diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/forge_cap_retrieval/LivingEntityMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/forge_cap_retrieval/LivingEntityMixin.java new file mode 100644 index 00000000..68e86aab --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/forge_cap_retrieval/LivingEntityMixin.java @@ -0,0 +1,24 @@ +package org.embeddedt.modernfix.forge.mixin.perf.forge_cap_retrieval; + +import net.minecraft.core.Direction; +import net.minecraft.world.entity.LivingEntity; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import javax.annotation.Nullable; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin { + /** + * @author embeddedt (issue noted by XFactHD) + * @reason check capability equality before checking that entity is alive, the latter requires a lot more + * indirection + */ + @Redirect(method = "getCapability", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isAlive()Z")) + private boolean checkAliveAfterCap(LivingEntity entity, Capability capability, @Nullable Direction facing) { + return capability == ForgeCapabilities.ITEM_HANDLER && entity.isAlive(); + } +} diff --git a/gradle.properties b/gradle.properties index 53ac7000..bac75e44 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,12 +2,12 @@ org.gradle.jvmargs=-Xmx2G junit_version=5.10.0-M1 -mixinextras_version=0.3.1 +mixinextras_version=0.3.2 mod_id=modernfix minecraft_version=23w51a enabled_platforms=fabric -forge_version=20.4.22-beta +forge_version=20.4.70-beta # parchment_version=2023.07.09 refined_storage_version=4392788 jei_version=16.0.0.28 @@ -28,3 +28,6 @@ diagonal_fences_version=4558828 spark_version=4587310 use_fabric_api_at_runtime=false + +# Look up maven coordinates when changing shadow_version +shadow_version=7.1.2 diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 1b790a61..e46564d0 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -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" } @@ -35,8 +35,7 @@ repositories { dependencies { neoForge "net.neoforged:neoforge:${rootProject.forge_version}" - //implementation(annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-common:${rootProject.mixinextras_version}")) - //implementation(include("com.github.llamalad7.mixinextras:mixinextras-forge:${rootProject.mixinextras_version}")) + // Remove the next line if you don't want to depend on the API // modApi "me.shedaniel:architectury-forge:${rootProject.architectury_version}" @@ -65,6 +64,8 @@ dependencies { common(project(path: ":common", configuration: "namedElements")) { transitive false } shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive = false } + shadowCommon(project(path: ":annotations")) + forgeRuntimeLibrary(project(path: ":annotations")) } processResources { diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/dynresources/ModelBakeEventHelper.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/dynresources/ModelBakeEventHelper.java index 85b876a2..0581cb16 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/dynresources/ModelBakeEventHelper.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/dynresources/ModelBakeEventHelper.java @@ -21,6 +21,7 @@ import org.embeddedt.modernfix.util.ForwardingInclDefaultsMap; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.BiFunction; /** * Stores a list of all known default block/item models in the game, and provides a namespaced version @@ -28,7 +29,12 @@ import java.util.*; */ public class ModelBakeEventHelper { // TODO: make into config option - private static final Set INCOMPATIBLE_MODS = ImmutableSet.of("industrialforegoing", "vampirism", "elevatorid", "embers"); + private static final Set INCOMPATIBLE_MODS = ImmutableSet.of( + "industrialforegoing", + "mekanism", + "vampirism", + "elevatorid", + "embers"); private final Map modelRegistry; private final Set topLevelModelLocations; private final MutableGraph dependencyGraph; @@ -79,7 +85,7 @@ public class ModelBakeEventHelper { private void logWarning() { if(!WARNED_MOD_IDS.add(modId)) return; - ModernFix.LOGGER.warn("Mod '{}' is accessing Map#keySet/entrySet/values on the model registry map inside its event handler." + + ModernFix.LOGGER.warn("Mod '{}' is accessing Map#keySet/entrySet/values/replaceAll on the model registry map inside its event handler." + " This probably won't work as expected with dynamic resources on. Prefer using Map#get/put and constructing ModelResourceLocations another way.", modId); } @@ -100,6 +106,12 @@ public class ModelBakeEventHelper { logWarning(); return super.values(); } + + @Override + public void replaceAll(BiFunction function) { + logWarning(); + super.replaceAll(function); + } }; } @@ -139,6 +151,32 @@ public class ModelBakeEventHelper { public boolean containsKey(@Nullable Object key) { return ourModelLocations.contains(key) || super.containsKey(key); } + + @Override + public void replaceAll(BiFunction function) { + ModernFix.LOGGER.warn("Mod '{}' is calling replaceAll on the model registry. Some hacks will be used to keep this fast, but they may not be 100% compatible.", modId); + List locations = new ArrayList<>(keySet()); + for(ResourceLocation location : locations) { + /* + * Fetching every model is insanely slow. So we call the function with a null object first, since it + * probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know + * it actually cares about the given model. + */ + boolean needsReplacement; + try { + needsReplacement = function.apply(location, null) != null; + } catch(Throwable e) { + needsReplacement = true; + } + if(needsReplacement) { + BakedModel existing = get(location); + BakedModel replacement = function.apply(location, existing); + if(replacement != existing) { + put(location, replacement); + } + } + } + } }; } } diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/bugfix/recipe_book_type_desync/RecipeBookSettingsMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/bugfix/recipe_book_type_desync/RecipeBookSettingsMixin.java index f18ad746..774c05e0 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/bugfix/recipe_book_type_desync/RecipeBookSettingsMixin.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/bugfix/recipe_book_type_desync/RecipeBookSettingsMixin.java @@ -1,15 +1,9 @@ package org.embeddedt.modernfix.neoforge.mixin.bugfix.recipe_book_type_desync; -import com.llamalad7.mixinextras.sugar.Local; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.stats.RecipeBookSettings; import net.minecraft.world.inventory.RecipeBookType; -import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; -import org.embeddedt.modernfix.neoforge.packet.NetworkUtils; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -36,12 +30,14 @@ public class RecipeBookSettingsMixin { } mfix$maxVanillaOrdinal = ord; } + /* @Redirect(method = "read(Lnet/minecraft/network/FriendlyByteBuf;)Lnet/minecraft/stats/RecipeBookSettings;", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/FriendlyByteBuf;readBoolean()Z")) private static boolean useDefaultBooleanIfVanilla(FriendlyByteBuf buf, @Local(ordinal = 0) RecipeBookType type) { - if(type.ordinal() >= (mfix$maxVanillaOrdinal + 1) && NetworkUtils.isCurrentlyVanilla) { + if(type.ordinal() >= (mfix$maxVanillaOrdinal + 1)) { ModernFix.LOGGER.warn("Not reading recipe book data for type '{}' as we are using vanilla connection", type.name()); return false; // skip actually reading buffer } return buf.readBoolean(); } + */ } diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/BootstrapMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/BootstrapMixin.java index 369fc6f3..ec7e849e 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/BootstrapMixin.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/BootstrapMixin.java @@ -1,7 +1,6 @@ package org.embeddedt.modernfix.neoforge.mixin.core; import net.minecraft.server.Bootstrap; -import net.neoforged.neoforge.network.NetworkConstants; import org.embeddedt.modernfix.util.TimeFormatter; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; @@ -25,10 +24,4 @@ public class BootstrapMixin { LOGGER.info("ModernFix reached bootstrap stage ({} after launch)", TimeFormatter.formatNanos(ManagementFactory.getRuntimeMXBean().getUptime() * 1000L * 1000L)); } } - - /* for https://github.com/MinecraftForge/MinecraftForge/issues/9505 */ - @Inject(method = "bootStrap", at = @At("RETURN")) - private static void doClassloadHack(CallbackInfo ci) { - NetworkConstants.init(); - } } diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/NetworkHooksMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/NetworkHooksMixin.java deleted file mode 100644 index aaee04e9..00000000 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/core/NetworkHooksMixin.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.embeddedt.modernfix.neoforge.mixin.core; - -import net.minecraft.network.Connection; -import net.neoforged.neoforge.network.NetworkHooks; -import org.embeddedt.modernfix.neoforge.packet.NetworkUtils; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(NetworkHooks.class) -public abstract class NetworkHooksMixin { - @Inject(method = "handleClientLoginSuccess", at = @At("RETURN"), remap = false) - private static void setVanillaGlobalFlag(Connection manager, CallbackInfo ci) { - NetworkUtils.isCurrentlyVanilla = NetworkHooks.isVanillaConnection(manager); - } -} diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ForgeHooksClientMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ForgeHooksClientMixin.java index bb8146dd..0eb15bc4 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ForgeHooksClientMixin.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ForgeHooksClientMixin.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources; +import com.google.common.base.Stopwatch; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.resources.ResourceLocation; import net.neoforged.bus.api.Event; @@ -9,6 +10,7 @@ import net.neoforged.fml.ModLoader; import net.neoforged.fml.util.ObfuscationReflectionHelper; import net.neoforged.neoforge.client.ClientHooks; import net.neoforged.neoforge.client.event.ModelEvent; +import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.neoforge.dynresources.ModelBakeEventHelper; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -16,6 +18,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; import java.lang.reflect.Method; import java.util.Map; +import java.util.concurrent.TimeUnit; @Mixin(ClientHooks.class) public class ForgeHooksClientMixin { @@ -32,11 +35,16 @@ public class ForgeHooksClientMixin { ModList.get().forEachModContainer((id, mc) -> { Map newRegistry = helper.wrapRegistry(id); ModelEvent.ModifyBakingResult postedEvent = new ModelEvent.ModifyBakingResult(newRegistry, bakeEvent.getModelBakery()); + Stopwatch timer = Stopwatch.createStarted(); try { acceptEv.invoke(mc, postedEvent); } catch(ReflectiveOperationException e) { e.printStackTrace(); } + timer.stop(); + if(timer.elapsed(TimeUnit.SECONDS) >= 1) { + ModernFix.LOGGER.warn("Mod '{}' took {} in the model bake event", id, timer); + } }); } } diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ItemOverridesForgeMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ItemOverridesForgeMixin.java new file mode 100644 index 00000000..f59e02ec --- /dev/null +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ItemOverridesForgeMixin.java @@ -0,0 +1,34 @@ +package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.resources.ResourceLocation; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.duck.IExtendedModelBaker; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.function.Function; + +@Mixin(ItemOverrides.class) +@ClientOnlyMixin +public class ItemOverridesForgeMixin { + /** + * @author embeddedt + * @reason servers insist on generating invalid item overrides that have missing models + */ + @WrapOperation(method = "bakeModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBaker;bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;"), remap = false) + private BakedModel bake(ModelBaker instance, ResourceLocation resourceLocation, ModelState modelState, Function spriteGetter, Operation original) { + boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false); + try { + return original.call(instance, resourceLocation, modelState, spriteGetter); + } finally { + ((IExtendedModelBaker)instance).throwOnMissingModel(prevState); + } + } +} diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java index 634a84fe..afbef46d 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java @@ -8,6 +8,7 @@ import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.ModernFixClient; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.duck.IExtendedModelBaker; import org.embeddedt.modernfix.duck.IExtendedModelBakery; @@ -23,6 +24,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.function.Function; @Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600) +@ClientOnlyMixin public abstract class ModelBakerImplMixin implements IModelBakerImpl, IExtendedModelBaker { private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); @Shadow @Final private ModelBakery field_40571; @@ -39,8 +41,10 @@ public abstract class ModelBakerImplMixin implements IModelBakerImpl, IExtendedM private boolean throwIfMissing; @Override - public void throwOnMissingModel() { - throwIfMissing = true; + public boolean throwOnMissingModel(boolean flag) { + boolean old = throwIfMissing; + throwIfMissing = flag; + return old; } @Inject(method = "getModel", at = @At("HEAD"), cancellable = true) diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 94b81f46..fe0e53f7 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -316,7 +316,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return m; ModelBakery self = (ModelBakery) (Object) this; ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation); - ((IExtendedModelBaker)theBaker).throwOnMissingModel(); + ((IExtendedModelBaker)theBaker).throwOnMissingModel(true); synchronized(this) { m = theBaker.bake(modelLocation, state, theBaker.getModelTextureGetter()); } if(m != null) loadedBakedModels.put(key, m); diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/NetworkUtils.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/NetworkUtils.java deleted file mode 100644 index 4f1d88dd..00000000 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/NetworkUtils.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.embeddedt.modernfix.neoforge.packet; - -public class NetworkUtils { - public static boolean isCurrentlyVanilla; -} diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/PacketHandler.java b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/PacketHandler.java index 4c9bba7a..9f6caaf2 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/PacketHandler.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/neoforge/packet/PacketHandler.java @@ -1,33 +1,24 @@ package org.embeddedt.modernfix.neoforge.packet; -import net.minecraft.resources.ResourceLocation; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.fml.DistExecutor; -import net.neoforged.neoforge.network.NetworkEvent; -import net.neoforged.neoforge.network.NetworkRegistry; -import net.neoforged.neoforge.network.simple.SimpleChannel; +import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent; +import net.neoforged.neoforge.network.handling.PlayPayloadContext; +import net.neoforged.neoforge.network.registration.IPayloadRegistrar; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.packet.EntityIDSyncPacket; public class PacketHandler { - private static final String PROTOCOL_VERSION = "1"; - public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( - new ResourceLocation(ModernFix.MODID, "main"), - () -> PROTOCOL_VERSION, - NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION), - NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION) - ); + private static void registerPackets(final RegisterPayloadHandlerEvent event) { + final IPayloadRegistrar registrar = event.registrar(ModernFix.MODID).optional(); + registrar.play(EntityIDSyncPacket.ID, EntityIDSyncPacket::new, PacketHandler::handleSyncPacket); + } public static void register() { - int id = 1; - INSTANCE.registerMessage(id++, EntityIDSyncPacket.class, EntityIDSyncPacket::serialize, EntityIDSyncPacket::deserialize, PacketHandler::handleSyncPacket); + FMLJavaModLoadingContext.get().getModEventBus().addListener(PacketHandler::registerPackets); } - private static void handleSyncPacket(EntityIDSyncPacket packet, NetworkEvent.Context contextSupplier) { - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - contextSupplier.enqueueWork(() -> ModernFixClient.handleEntityIDSync(packet)); - contextSupplier.setPacketHandled(true); - }); + private static void handleSyncPacket(EntityIDSyncPacket packet, PlayPayloadContext context) { + context.workHandler().execute(() -> ModernFixClient.handleEntityIDSync(packet)); } } diff --git a/neoforge/src/main/java/org/embeddedt/modernfix/platform/neoforge/ModernFixPlatformHooksImpl.java b/neoforge/src/main/java/org/embeddedt/modernfix/platform/neoforge/ModernFixPlatformHooksImpl.java index 58f45578..5e455b81 100644 --- a/neoforge/src/main/java/org/embeddedt/modernfix/platform/neoforge/ModernFixPlatformHooksImpl.java +++ b/neoforge/src/main/java/org/embeddedt/modernfix/platform/neoforge/ModernFixPlatformHooksImpl.java @@ -5,6 +5,7 @@ import com.google.common.collect.Multimap; import com.mojang.brigadier.CommandDispatcher; import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.CreativeModeTab; @@ -24,7 +25,6 @@ import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.neoforge.config.NightConfigFixer; import org.embeddedt.modernfix.neoforge.init.ModernFixForge; -import org.embeddedt.modernfix.neoforge.packet.PacketHandler; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; import org.embeddedt.modernfix.spark.SparkLaunchProfiler; import org.embeddedt.modernfix.util.CommonModUtil; @@ -87,8 +87,8 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks { return FMLPaths.GAMEDIR.get(); } - public void sendPacket(ServerPlayer player, Object packet) { - PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), packet); + public void sendPacket(ServerPlayer player, CustomPacketPayload packet) { + PacketDistributor.PLAYER.with(player).send(packet); } public void injectPlatformSpecificHacks() { diff --git a/neoforge/src/main/resources/META-INF/mods.toml b/neoforge/src/main/resources/META-INF/mods.toml index 37477b8e..17114291 100644 --- a/neoforge/src/main/resources/META-INF/mods.toml +++ b/neoforge/src/main/resources/META-INF/mods.toml @@ -45,9 +45,9 @@ Egregious, yet effective performance improvements for modern Minecraft # the modid of the dependency modId = "neoforge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified -mandatory = true #mandatory +type = "required" #mandatory # The version range of the dependency -versionRange = "[20.4.22-beta,)" #mandatory +versionRange = "[20.4.70-beta,)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory ordering = "NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER @@ -55,14 +55,14 @@ side = "BOTH" # Here's another dependency [[dependencies.modernfix]] modId = "minecraft" -mandatory = true +type = "required" # This version range declares a minimum of the current minecraft version up to but not including the next major version versionRange = "[1.20, 1.21)" ordering = "NONE" side = "BOTH" [[dependencies.modernfix]] modId = "jei" -mandatory = false +type = "optional" # This version range declares a minimum of the current minecraft version up to but not including the next major version versionRange = "[13,)" ordering = "BEFORE" diff --git a/neoforge/src/main/resources/modernfix-neoforge.mixins.json b/neoforge/src/main/resources/modernfix-neoforge.mixins.json deleted file mode 100644 index 6555f46f..00000000 --- a/neoforge/src/main/resources/modernfix-neoforge.mixins.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "required": true, - "package": "org.embeddedt.modernfix.neoforge.mixin", - "plugin": "org.embeddedt.modernfix.core.ModernFixMixinPlugin", - "compatibilityLevel": "JAVA_8", - "minVersion": "0.8", - "mixins": [ -${mixin_classes} - ], - "injectors": { - "defaultRequire": 1 - }, - "overwrites": { - "conformVisibility": true - } -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 514910c1..37fd1368 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,13 +5,20 @@ 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") -startParameter.excludedTaskNames.add(':fabric:testmod:genSources') - def current_platforms = getProperty("enabled_platforms").tokenize(',') current_platforms.each { it -> def platform_name = it.trim()