Merge 1.20.4 into 1.20.5
This commit is contained in:
commit
b55ed00748
60
annotation-processor/build.gradle
Normal file
60
annotation-processor/build.gradle
Normal 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'
|
||||||
|
|
@ -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<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)
|
||||||
|
.filter(o -> o instanceof TypeMirror)
|
||||||
|
.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("\\/", ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
6
annotations/build.gradle
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
plugins {
|
||||||
|
id 'modernfix.common-conventions'
|
||||||
|
id 'java-library'
|
||||||
|
}
|
||||||
|
|
||||||
|
version = '1.1.0'
|
||||||
|
|
@ -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 {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@ plugins {
|
||||||
id 'org.ajoberstar.grgit' version '5.2.0'
|
id 'org.ajoberstar.grgit' version '5.2.0'
|
||||||
id 'se.bjurr.gitchangelog.git-changelog-gradle-plugin' version '1.79.0'
|
id 'se.bjurr.gitchangelog.git-changelog-gradle-plugin' version '1.79.0'
|
||||||
id "com.modrinth.minotaur" version "2.+" apply false
|
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
|
id 'modernfix.common-conventions' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
plugins {
|
plugins {
|
||||||
id 'groovy-gradle-plugin'
|
id 'groovy-gradle-plugin'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,5 +77,4 @@ repositories {
|
||||||
maven {
|
maven {
|
||||||
url 'https://maven.terraformersmc.com/releases'
|
url 'https://maven.terraformersmc.com/releases'
|
||||||
}
|
}
|
||||||
maven { url = "https://jitpack.io" }
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -16,37 +16,26 @@ dependencies {
|
||||||
parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
|
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 {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
def mixinFileList = []
|
dependsOn compileJava
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def mixinClassesStringB = new StringBuilder()
|
tasks.withType(JavaCompile) {
|
||||||
for(int i = 0; i < mixinFileList.size(); i++) {
|
options.fork = true
|
||||||
mixinClassesStringB.append(" \"")
|
options.forkOptions.jvmArgs << '--enable-preview'
|
||||||
mixinClassesStringB.append(mixinFileList.get(i))
|
configure(options) {
|
||||||
mixinClassesStringB.append('"')
|
if (!name.toLowerCase().contains('test')) {
|
||||||
if(i < (mixinFileList.size() - 1))
|
options.compilerArgs << "-ArootProject.name=${rootProject.name}" << "-Aproject.name=${project.name}"
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import net.minecraft.client.gui.font.providers.GlyphProviderDefinition;
|
||||||
import net.minecraft.client.gui.font.providers.UnihexProvider;
|
import net.minecraft.client.gui.font.providers.UnihexProvider;
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
import net.minecraft.server.packs.resources.ResourceManager;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
|
@ -16,6 +17,7 @@ import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
@Mixin(UnihexProvider.Definition.class)
|
@Mixin(UnihexProvider.Definition.class)
|
||||||
|
@ClientOnlyMixin
|
||||||
public class UnihexProviderDefinitionMixin {
|
public class UnihexProviderDefinitionMixin {
|
||||||
@Inject(method = "unpack", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "unpack", at = @At("HEAD"), cancellable = true)
|
||||||
private void disableProvider(CallbackInfoReturnable<Either<GlyphProviderDefinition.Loader, GlyphProviderDefinition.Reference>> cir) {
|
private void disableProvider(CallbackInfoReturnable<Either<GlyphProviderDefinition.Loader, GlyphProviderDefinition.Reference>> cir) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import net.minecraft.client.resources.model.ModelManager;
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelCache;
|
import org.embeddedt.modernfix.dynamicresources.DynamicModelCache;
|
||||||
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
||||||
import org.embeddedt.modernfix.util.DynamicInt2ObjectMap;
|
import org.embeddedt.modernfix.util.DynamicInt2ObjectMap;
|
||||||
|
|
@ -19,6 +20,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Mixin(ItemModelShaper.class)
|
@Mixin(ItemModelShaper.class)
|
||||||
|
@ClientOnlyMixin
|
||||||
public abstract class ItemModelShaperMixin {
|
public abstract class ItemModelShaperMixin {
|
||||||
|
|
||||||
@Shadow public abstract ModelManager getModelManager();
|
@Shadow public abstract ModelManager getModelManager();
|
||||||
|
|
|
||||||
|
|
@ -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<UnbakedModel> original) {
|
||||||
|
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
|
||||||
|
try {
|
||||||
|
return original.call(instance, resourceLocation);
|
||||||
|
} finally {
|
||||||
|
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.util.LambdaMap;
|
import org.embeddedt.modernfix.util.LambdaMap;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
@ -26,6 +27,7 @@ import java.util.concurrent.Executor;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Mixin(ModelManager.class)
|
@Mixin(ModelManager.class)
|
||||||
|
@ClientOnlyMixin
|
||||||
public class ModelManagerMixin {
|
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;"))
|
@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<Map<ResourceLocation, BlockModel>> deferBlockModelLoad(ResourceManager manager, Executor executor) {
|
private CompletableFuture<Map<ResourceLocation, BlockModel>> deferBlockModelLoad(ResourceManager manager, Executor executor) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering;
|
package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.GameRenderer;
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.render.RenderState;
|
import org.embeddedt.modernfix.render.RenderState;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
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;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(GameRenderer.class)
|
@Mixin(GameRenderer.class)
|
||||||
|
@ClientOnlyMixin
|
||||||
public class GameRendererMixin {
|
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))
|
@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) {
|
private void markRenderingLevel(CallbackInfo ci) {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import net.minecraft.client.resources.model.SimpleBakedModel;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.BlockItem;
|
import net.minecraft.world.item.BlockItem;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.render.FastItemRenderType;
|
import org.embeddedt.modernfix.render.FastItemRenderType;
|
||||||
import org.embeddedt.modernfix.render.RenderState;
|
import org.embeddedt.modernfix.render.RenderState;
|
||||||
import org.embeddedt.modernfix.render.SimpleItemModelView;
|
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;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(value = ItemRenderer.class, priority = 600)
|
@Mixin(value = ItemRenderer.class, priority = 600)
|
||||||
|
@ClientOnlyMixin
|
||||||
public abstract class ItemRendererMixin {
|
public abstract class ItemRendererMixin {
|
||||||
private ItemDisplayContext transformType;
|
private ItemDisplayContext transformType;
|
||||||
private final SimpleItemModelView modelView = new SimpleItemModelView();
|
private final SimpleItemModelView modelView = new SimpleItemModelView();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ import java.util.*;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
public class ModernFixEarlyConfig {
|
public class ModernFixEarlyConfig {
|
||||||
private static final Logger LOGGER = LogManager.getLogger("ModernFixConfig");
|
private static final Logger LOGGER = LogManager.getLogger("ModernFixConfig");
|
||||||
|
|
@ -85,7 +87,10 @@ public class ModernFixEarlyConfig {
|
||||||
continue;
|
continue;
|
||||||
try(Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
|
try(Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
|
||||||
JsonObject configObject = (JsonObject)new JsonParser().parse(reader);
|
JsonObject configObject = (JsonObject)new JsonParser().parse(reader);
|
||||||
JsonArray mixinList = configObject.getAsJsonArray("mixins");
|
List<JsonElement> 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('.', '/');
|
String packageName = configObject.get("package").getAsString().replace('.', '/');
|
||||||
for(JsonElement mixin : mixinList) {
|
for(JsonElement mixin : mixinList) {
|
||||||
mixinPaths.add(packageName + "/" + mixin.getAsString().replace('.', '/') + ".class");
|
mixinPaths.add(packageName + "/" + mixin.getAsString().replace('.', '/') + ".class");
|
||||||
|
|
@ -212,6 +217,7 @@ public class ModernFixEarlyConfig {
|
||||||
disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant");
|
disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant");
|
||||||
disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me");
|
disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me");
|
||||||
disableIfModPresent("mixin.bugfix.preserve_early_window_pos", "better_loading_screen");
|
disableIfModPresent("mixin.bugfix.preserve_early_window_pos", "better_loading_screen");
|
||||||
|
disableIfModPresent("mixin.perf.dynamic_dfu", "litematica");
|
||||||
disableIfModPresent("mixin.perf.cache_strongholds", "littletiles", "c2me");
|
disableIfModPresent("mixin.perf.cache_strongholds", "littletiles", "c2me");
|
||||||
// content overlap
|
// content overlap
|
||||||
disableIfModPresent("mixin.perf.deduplicate_wall_shapes", "dashloader");
|
disableIfModPresent("mixin.perf.deduplicate_wall_shapes", "dashloader");
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.embeddedt.modernfix.duck;
|
||||||
public interface IExtendedModelBaker {
|
public interface IExtendedModelBaker {
|
||||||
/**
|
/**
|
||||||
* Causes the ModelBaker to throw when it finds a missing model instead of proceeding with the bake.
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ public class ModelBakeryHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<T>> T getValueHelper(Property<T> property, String value) {
|
private static <T extends Comparable<T>> T getValueHelper(Property<T> property, String value) {
|
||||||
return property.getValue(value).orElse((T) null);
|
return property.getValue(value).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Splitter COMMA_SPLITTER = Splitter.on(',');
|
private static final Splitter COMMA_SPLITTER = Splitter.on(',');
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ package org.embeddedt.modernfix.packet;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
|
|
||||||
|
|
@ -10,7 +12,8 @@ import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
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<Class<? extends Entity>, List<Pair<String, Integer>>> map;
|
private Map<Class<? extends Entity>, List<Pair<String, Integer>>> map;
|
||||||
|
|
||||||
public EntityIDSyncPacket(Map<Class<? extends Entity>, List<Pair<String, Integer>>> map) {
|
public EntityIDSyncPacket(Map<Class<? extends Entity>, List<Pair<String, Integer>>> map) {
|
||||||
|
|
@ -21,11 +24,8 @@ public class EntityIDSyncPacket {
|
||||||
return this.map;
|
return this.map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityIDSyncPacket() {
|
@Override
|
||||||
this.map = new HashMap<>();
|
public void write(FriendlyByteBuf buf) {
|
||||||
}
|
|
||||||
|
|
||||||
public void serialize(FriendlyByteBuf buf) {
|
|
||||||
buf.writeVarInt(map.keySet().size());
|
buf.writeVarInt(map.keySet().size());
|
||||||
for(Map.Entry<Class<? extends Entity>, List<Pair<String, Integer>>> entry : map.entrySet()) {
|
for(Map.Entry<Class<? extends Entity>, List<Pair<String, Integer>>> entry : map.entrySet()) {
|
||||||
buf.writeUtf(entry.getKey().getName());
|
buf.writeUtf(entry.getKey().getName());
|
||||||
|
|
@ -38,8 +38,8 @@ public class EntityIDSyncPacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static EntityIDSyncPacket deserialize(FriendlyByteBuf buf) {
|
public EntityIDSyncPacket(FriendlyByteBuf buf) {
|
||||||
EntityIDSyncPacket self = new EntityIDSyncPacket();
|
EntityIDSyncPacket self = this;
|
||||||
int numEntityClasses = buf.readVarInt();
|
int numEntityClasses = buf.readVarInt();
|
||||||
for(int i = 0; i < numEntityClasses; i++) {
|
for(int i = 0; i < numEntityClasses; i++) {
|
||||||
String clzName = buf.readUtf();
|
String clzName = buf.readUtf();
|
||||||
|
|
@ -73,6 +73,10 @@ public class EntityIDSyncPacket {
|
||||||
ModernFix.LOGGER.error("Error deserializing packet", e);
|
ModernFix.LOGGER.error("Error deserializing packet", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation id() {
|
||||||
|
return ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.google.common.collect.Multimap;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import net.minecraft.client.searchtree.SearchRegistry;
|
import net.minecraft.client.searchtree.SearchRegistry;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
@ -39,7 +40,7 @@ public interface ModernFixPlatformHooks {
|
||||||
|
|
||||||
Path getGameDirectory();
|
Path getGameDirectory();
|
||||||
|
|
||||||
void sendPacket(ServerPlayer player, Object packet);
|
void sendPacket(ServerPlayer player, CustomPacketPayload packet);
|
||||||
|
|
||||||
Multimap<String, String> getCustomModOptions();
|
Multimap<String, String> getCustomModOptions();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,8 @@ public class RegistryStorage {
|
||||||
|
|
||||||
public static <T> BiMap<ResourceKey<T>, DirectStorageRegistryObject> createKeyStorage(ResourceKey<? extends Registry<T>> registryKey, BiMap<ResourceLocation, DirectStorageRegistryObject> storage) {
|
public static <T> BiMap<ResourceKey<T>, DirectStorageRegistryObject> createKeyStorage(ResourceKey<? extends Registry<T>> registryKey, BiMap<ResourceLocation, DirectStorageRegistryObject> storage) {
|
||||||
if(storage instanceof DirectStorageBiMap) {
|
if(storage instanceof DirectStorageBiMap) {
|
||||||
DirectStorageBiMap<ResourceLocation, DirectStorageRegistryObject> directStorageBiMap = (DirectStorageBiMap<ResourceLocation, DirectStorageRegistryObject>)storage;
|
|
||||||
// silently ignore put/putAll calls on this map
|
// silently ignore put/putAll calls on this map
|
||||||
return new TransformingBiMap<ResourceLocation, DirectStorageRegistryObject, ResourceKey<T>, DirectStorageRegistryObject>(directStorageBiMap, loc -> ResourceKey.create(registryKey, loc), ResourceKey::location, Function.identity(), Function.identity()) {
|
return new TransformingBiMap<ResourceLocation, DirectStorageRegistryObject, ResourceKey<T>, DirectStorageRegistryObject>(storage, loc -> ResourceKey.create(registryKey, loc), ResourceKey::location, Function.identity(), Function.identity()) {
|
||||||
@Override
|
@Override
|
||||||
public DirectStorageRegistryObject put(ResourceKey<T> key, DirectStorageRegistryObject value) {
|
public DirectStorageRegistryObject put(ResourceKey<T> key, DirectStorageRegistryObject value) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,22 @@ package org.embeddedt.modernfix.util;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
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.MixinEnvironment;
|
||||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||||
import org.spongepowered.asm.mixin.transformer.ClassInfo;
|
import org.spongepowered.asm.mixin.transformer.ClassInfo;
|
||||||
|
import org.spongepowered.asm.service.MixinServiceAbstract;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ClassInfoManager {
|
public class ClassInfoManager {
|
||||||
private static boolean hasRun = false;
|
private static boolean hasRun = false;
|
||||||
|
private static final List<Runnable> loggersToRestore = new ArrayList<>();
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
if (!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager") || hasRun)
|
if (!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager") || hasRun)
|
||||||
return;
|
return;
|
||||||
|
|
@ -25,11 +31,33 @@ public class ClassInfoManager {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void changeLoggerAndRestoreLater(Map<String, ILogger> 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<String, ILogger>)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<String, ILogger>)loggersField.get(null), new LoggerAdapterDefault("mixin.audit"));
|
||||||
|
}
|
||||||
|
|
||||||
private static void doClear() {
|
private static void doClear() {
|
||||||
Map<String, ClassInfo> classInfoCache;
|
Map<String, ClassInfo> classInfoCache;
|
||||||
Field mixinField, stateField, classNodeField, methodsField, fieldsField;
|
Field mixinField, stateField, classNodeField, methodsField, fieldsField;
|
||||||
Class<?> stateClz;
|
Class<?> stateClz;
|
||||||
try {
|
try {
|
||||||
|
disableLoggers();
|
||||||
Field field = accessible(ClassInfo.class.getDeclaredField("cache"));
|
Field field = accessible(ClassInfo.class.getDeclaredField("cache"));
|
||||||
classInfoCache = (Map<String, ClassInfo>) field.get(null);
|
classInfoCache = (Map<String, ClassInfo>) field.get(null);
|
||||||
mixinField = accessible(ClassInfo.class.getDeclaredField("mixin"));
|
mixinField = accessible(ClassInfo.class.getDeclaredField("mixin"));
|
||||||
|
|
@ -70,6 +98,9 @@ public class ClassInfoManager {
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
// Put back the old logger
|
||||||
|
loggersToRestore.forEach(Runnable::run);
|
||||||
|
loggersToRestore.clear();
|
||||||
ModernFix.LOGGER.warn("Cleared mixin data structures");
|
ModernFix.LOGGER.warn("Cleared mixin data structures");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
plugins {
|
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 'com.adarshr.test-logger' version '3.2.0'
|
||||||
id "modernfix.mod-common-conventions"
|
id "modernfix.mod-common-conventions"
|
||||||
id "modernfix.platform-conventions"
|
id "modernfix.platform-conventions"
|
||||||
|
|
@ -63,6 +63,7 @@ dependencies {
|
||||||
|
|
||||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||||
testImplementation(shadowCommon(project(path: ":common", configuration: "transformProductionFabric"))) { 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(platform("org.junit:junit-bom:${project.junit_version}"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api")
|
testImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ package org.embeddedt.modernfix.fabric.mixin.core;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
|
import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
|
||||||
import org.embeddedt.modernfix.ModernFixClientFabric;
|
import org.embeddedt.modernfix.ModernFixClientFabric;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(ClientCommonPacketListenerImpl.class)
|
@Mixin(ClientCommonPacketListenerImpl.class)
|
||||||
|
@ClientOnlyMixin
|
||||||
public class ClientCommonPacketListenerImplMixin {
|
public class ClientCommonPacketListenerImplMixin {
|
||||||
@Inject(method = "handleUpdateTags", at = @At("RETURN"))
|
@Inject(method = "handleUpdateTags", at = @At("RETURN"))
|
||||||
private void signalTags(CallbackInfo ci) {
|
private void signalTags(CallbackInfo ci) {
|
||||||
|
|
|
||||||
|
|
@ -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<BakedModel> original) {
|
||||||
|
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
|
||||||
|
try {
|
||||||
|
return original.call(instance, resourceLocation, modelState);
|
||||||
|
} finally {
|
||||||
|
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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.BlockState;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
import org.embeddedt.modernfix.ModernFixClient;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||||
|
|
@ -29,6 +30,7 @@ import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600)
|
@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600)
|
||||||
|
@ClientOnlyMixin
|
||||||
public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
|
public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
|
||||||
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
||||||
@Shadow @Final private ModelBakery field_40571;
|
@Shadow @Final private ModelBakery field_40571;
|
||||||
|
|
@ -57,8 +59,10 @@ public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
|
||||||
private boolean throwIfMissing;
|
private boolean throwIfMissing;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void throwOnMissingModel() {
|
public boolean throwOnMissingModel(boolean flag) {
|
||||||
throwIfMissing = true;
|
boolean old = throwIfMissing;
|
||||||
|
throwIfMissing = flag;
|
||||||
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
return m;
|
return m;
|
||||||
ModelBakery self = (ModelBakery) (Object) this;
|
ModelBakery self = (ModelBakery) (Object) this;
|
||||||
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
||||||
((IExtendedModelBaker)theBaker).throwOnMissingModel();
|
((IExtendedModelBaker)theBaker).throwOnMissingModel(true);
|
||||||
synchronized(this) { m = theBaker.bake(modelLocation, state); }
|
synchronized(this) { m = theBaker.bake(modelLocation, state); }
|
||||||
if(m != null)
|
if(m != null)
|
||||||
loadedBakedModels.put(key, m);
|
loadedBakedModels.put(key, m);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import net.fabricmc.loader.api.metadata.CustomValue;
|
||||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||||
import net.minecraft.client.searchtree.SearchRegistry;
|
import net.minecraft.client.searchtree.SearchRegistry;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.item.CreativeModeTabs;
|
import net.minecraft.world.item.CreativeModeTabs;
|
||||||
|
|
@ -72,7 +73,7 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks {
|
||||||
return FabricLoader.getInstance().getGameDir();
|
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);
|
//PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -41,3 +41,5 @@ processResources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make genSources do nothing in this project
|
||||||
|
project.gradle.startParameter.excludedTaskNames.add("genSources")
|
||||||
|
|
@ -5,6 +5,7 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraftforge.client.model.data.ModelDataManager;
|
import net.minecraftforge.client.model.data.ModelDataManager;
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
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 org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
@ -24,12 +26,14 @@ import java.util.function.Function;
|
||||||
public abstract class ModelDataManagerMixin {
|
public abstract class ModelDataManagerMixin {
|
||||||
@Shadow protected abstract void refreshAt(ChunkPos chunk);
|
@Shadow protected abstract void refreshAt(ChunkPos chunk);
|
||||||
|
|
||||||
|
@Shadow @Final private Map<ChunkPos, Set<BlockPos>> needModelDataRefresh;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the set of positions to refresh a real concurrent hash set rather than relying on synchronizedSet,
|
* 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
|
* 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)
|
@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<ChunkPos, Set<BlockPos>> changeTypeOfSetUsed(Function<ChunkPos, Set<BlockPos>> mappingFunction) {
|
private Function<ChunkPos, Set<BlockPos>> changeTypeOfSetUsed(Function<ChunkPos, Set<BlockPos>> mappingFunction) {
|
||||||
return pos -> Collections.newSetFromMap(new ConcurrentHashMap<>());
|
return pos -> Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +41,8 @@ public abstract class ModelDataManagerMixin {
|
||||||
private void onlyRefreshOnMainThread(ModelDataManager instance, ChunkPos pos) {
|
private void onlyRefreshOnMainThread(ModelDataManager instance, ChunkPos pos) {
|
||||||
// Only refresh model data on the main thread. This prevents calling getBlockEntity from worker threads
|
// Only refresh model data on the main thread. This prevents calling getBlockEntity from worker threads
|
||||||
// which could cause weird CMEs or other behavior.
|
// 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
|
// 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
|
// 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.
|
// try to access model data in neighboring chunks.
|
||||||
|
|
|
||||||
|
|
@ -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 <T> boolean checkAliveAfterCap(LivingEntity entity, Capability<T> capability, @Nullable Direction facing) {
|
||||||
|
return capability == ForgeCapabilities.ITEM_HANDLER && entity.isAlive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
org.gradle.jvmargs=-Xmx2G
|
org.gradle.jvmargs=-Xmx2G
|
||||||
|
|
||||||
junit_version=5.10.0-M1
|
junit_version=5.10.0-M1
|
||||||
mixinextras_version=0.3.1
|
mixinextras_version=0.3.2
|
||||||
|
|
||||||
mod_id=modernfix
|
mod_id=modernfix
|
||||||
minecraft_version=23w51a
|
minecraft_version=23w51a
|
||||||
enabled_platforms=fabric
|
enabled_platforms=fabric
|
||||||
forge_version=20.4.22-beta
|
forge_version=20.4.70-beta
|
||||||
# parchment_version=2023.07.09
|
# parchment_version=2023.07.09
|
||||||
refined_storage_version=4392788
|
refined_storage_version=4392788
|
||||||
jei_version=16.0.0.28
|
jei_version=16.0.0.28
|
||||||
|
|
@ -28,3 +28,6 @@ diagonal_fences_version=4558828
|
||||||
spark_version=4587310
|
spark_version=4587310
|
||||||
|
|
||||||
use_fabric_api_at_runtime=false
|
use_fabric_api_at_runtime=false
|
||||||
|
|
||||||
|
# Look up maven coordinates when changing shadow_version
|
||||||
|
shadow_version=7.1.2
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
id "com.github.johnrengelman.shadow"
|
||||||
id "modernfix.mod-common-conventions"
|
id "modernfix.mod-common-conventions"
|
||||||
id "modernfix.platform-conventions"
|
id "modernfix.platform-conventions"
|
||||||
}
|
}
|
||||||
|
|
@ -35,8 +35,7 @@ repositories {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
neoForge "net.neoforged:neoforge:${rootProject.forge_version}"
|
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
|
// Remove the next line if you don't want to depend on the API
|
||||||
// modApi "me.shedaniel:architectury-forge:${rootProject.architectury_version}"
|
// modApi "me.shedaniel:architectury-forge:${rootProject.architectury_version}"
|
||||||
|
|
||||||
|
|
@ -65,6 +64,8 @@ dependencies {
|
||||||
|
|
||||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||||
shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive = false }
|
shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive = false }
|
||||||
|
shadowCommon(project(path: ":annotations"))
|
||||||
|
forgeRuntimeLibrary(project(path: ":annotations"))
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import org.embeddedt.modernfix.util.ForwardingInclDefaultsMap;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
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
|
* 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 {
|
public class ModelBakeEventHelper {
|
||||||
// TODO: make into config option
|
// TODO: make into config option
|
||||||
private static final Set<String> INCOMPATIBLE_MODS = ImmutableSet.of("industrialforegoing", "vampirism", "elevatorid", "embers");
|
private static final Set<String> INCOMPATIBLE_MODS = ImmutableSet.of(
|
||||||
|
"industrialforegoing",
|
||||||
|
"mekanism",
|
||||||
|
"vampirism",
|
||||||
|
"elevatorid",
|
||||||
|
"embers");
|
||||||
private final Map<ResourceLocation, BakedModel> modelRegistry;
|
private final Map<ResourceLocation, BakedModel> modelRegistry;
|
||||||
private final Set<ResourceLocation> topLevelModelLocations;
|
private final Set<ResourceLocation> topLevelModelLocations;
|
||||||
private final MutableGraph<String> dependencyGraph;
|
private final MutableGraph<String> dependencyGraph;
|
||||||
|
|
@ -79,7 +85,7 @@ public class ModelBakeEventHelper {
|
||||||
private void logWarning() {
|
private void logWarning() {
|
||||||
if(!WARNED_MOD_IDS.add(modId))
|
if(!WARNED_MOD_IDS.add(modId))
|
||||||
return;
|
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);
|
" 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();
|
logWarning();
|
||||||
return super.values();
|
return super.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel, ? extends BakedModel> function) {
|
||||||
|
logWarning();
|
||||||
|
super.replaceAll(function);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,6 +151,32 @@ public class ModelBakeEventHelper {
|
||||||
public boolean containsKey(@Nullable Object key) {
|
public boolean containsKey(@Nullable Object key) {
|
||||||
return ourModelLocations.contains(key) || super.containsKey(key);
|
return ourModelLocations.contains(key) || super.containsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel, ? extends BakedModel> 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<ResourceLocation> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,9 @@
|
||||||
package org.embeddedt.modernfix.neoforge.mixin.bugfix.recipe_book_type_desync;
|
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.stats.RecipeBookSettings;
|
||||||
import net.minecraft.world.inventory.RecipeBookType;
|
import net.minecraft.world.inventory.RecipeBookType;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.neoforge.packet.NetworkUtils;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
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.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
|
@ -36,12 +30,14 @@ public class RecipeBookSettingsMixin {
|
||||||
}
|
}
|
||||||
mfix$maxVanillaOrdinal = ord;
|
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"))
|
@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) {
|
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());
|
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 false; // skip actually reading buffer
|
||||||
}
|
}
|
||||||
return buf.readBoolean();
|
return buf.readBoolean();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package org.embeddedt.modernfix.neoforge.mixin.core;
|
package org.embeddedt.modernfix.neoforge.mixin.core;
|
||||||
|
|
||||||
import net.minecraft.server.Bootstrap;
|
import net.minecraft.server.Bootstrap;
|
||||||
import net.neoforged.neoforge.network.NetworkConstants;
|
|
||||||
import org.embeddedt.modernfix.util.TimeFormatter;
|
import org.embeddedt.modernfix.util.TimeFormatter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
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));
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
|
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.client.resources.model.BakedModel;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.neoforged.bus.api.Event;
|
import net.neoforged.bus.api.Event;
|
||||||
|
|
@ -9,6 +10,7 @@ import net.neoforged.fml.ModLoader;
|
||||||
import net.neoforged.fml.util.ObfuscationReflectionHelper;
|
import net.neoforged.fml.util.ObfuscationReflectionHelper;
|
||||||
import net.neoforged.neoforge.client.ClientHooks;
|
import net.neoforged.neoforge.client.ClientHooks;
|
||||||
import net.neoforged.neoforge.client.event.ModelEvent;
|
import net.neoforged.neoforge.client.event.ModelEvent;
|
||||||
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.neoforge.dynresources.ModelBakeEventHelper;
|
import org.embeddedt.modernfix.neoforge.dynresources.ModelBakeEventHelper;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
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.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Mixin(ClientHooks.class)
|
@Mixin(ClientHooks.class)
|
||||||
public class ForgeHooksClientMixin {
|
public class ForgeHooksClientMixin {
|
||||||
|
|
@ -32,11 +35,16 @@ public class ForgeHooksClientMixin {
|
||||||
ModList.get().forEachModContainer((id, mc) -> {
|
ModList.get().forEachModContainer((id, mc) -> {
|
||||||
Map<ResourceLocation, BakedModel> newRegistry = helper.wrapRegistry(id);
|
Map<ResourceLocation, BakedModel> newRegistry = helper.wrapRegistry(id);
|
||||||
ModelEvent.ModifyBakingResult postedEvent = new ModelEvent.ModifyBakingResult(newRegistry, bakeEvent.getModelBakery());
|
ModelEvent.ModifyBakingResult postedEvent = new ModelEvent.ModifyBakingResult(newRegistry, bakeEvent.getModelBakery());
|
||||||
|
Stopwatch timer = Stopwatch.createStarted();
|
||||||
try {
|
try {
|
||||||
acceptEv.invoke(mc, postedEvent);
|
acceptEv.invoke(mc, postedEvent);
|
||||||
} catch(ReflectiveOperationException e) {
|
} catch(ReflectiveOperationException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
timer.stop();
|
||||||
|
if(timer.elapsed(TimeUnit.SECONDS) >= 1) {
|
||||||
|
ModernFix.LOGGER.warn("Mod '{}' took {} in the model bake event", id, timer);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<ResourceLocation, TextureAtlasSprite> spriteGetter, Operation<BakedModel> original) {
|
||||||
|
boolean prevState = ((IExtendedModelBaker)instance).throwOnMissingModel(false);
|
||||||
|
try {
|
||||||
|
return original.call(instance, resourceLocation, modelState, spriteGetter);
|
||||||
|
} finally {
|
||||||
|
((IExtendedModelBaker)instance).throwOnMissingModel(prevState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import net.minecraft.client.resources.model.*;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
import org.embeddedt.modernfix.ModernFixClient;
|
||||||
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
||||||
|
|
@ -23,6 +24,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600)
|
@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600)
|
||||||
|
@ClientOnlyMixin
|
||||||
public abstract class ModelBakerImplMixin implements IModelBakerImpl, IExtendedModelBaker {
|
public abstract class ModelBakerImplMixin implements IModelBakerImpl, IExtendedModelBaker {
|
||||||
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
||||||
@Shadow @Final private ModelBakery field_40571;
|
@Shadow @Final private ModelBakery field_40571;
|
||||||
|
|
@ -39,8 +41,10 @@ public abstract class ModelBakerImplMixin implements IModelBakerImpl, IExtendedM
|
||||||
private boolean throwIfMissing;
|
private boolean throwIfMissing;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void throwOnMissingModel() {
|
public boolean throwOnMissingModel(boolean flag) {
|
||||||
throwIfMissing = true;
|
boolean old = throwIfMissing;
|
||||||
|
throwIfMissing = flag;
|
||||||
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
return m;
|
return m;
|
||||||
ModelBakery self = (ModelBakery) (Object) this;
|
ModelBakery self = (ModelBakery) (Object) this;
|
||||||
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
||||||
((IExtendedModelBaker)theBaker).throwOnMissingModel();
|
((IExtendedModelBaker)theBaker).throwOnMissingModel(true);
|
||||||
synchronized(this) { m = theBaker.bake(modelLocation, state, theBaker.getModelTextureGetter()); }
|
synchronized(this) { m = theBaker.bake(modelLocation, state, theBaker.getModelTextureGetter()); }
|
||||||
if(m != null)
|
if(m != null)
|
||||||
loadedBakedModels.put(key, m);
|
loadedBakedModels.put(key, m);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package org.embeddedt.modernfix.neoforge.packet;
|
|
||||||
|
|
||||||
public class NetworkUtils {
|
|
||||||
public static boolean isCurrentlyVanilla;
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +1,24 @@
|
||||||
package org.embeddedt.modernfix.neoforge.packet;
|
package org.embeddedt.modernfix.neoforge.packet;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
import net.neoforged.api.distmarker.Dist;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
|
||||||
import net.neoforged.fml.DistExecutor;
|
import net.neoforged.neoforge.network.handling.PlayPayloadContext;
|
||||||
import net.neoforged.neoforge.network.NetworkEvent;
|
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
|
||||||
import net.neoforged.neoforge.network.NetworkRegistry;
|
|
||||||
import net.neoforged.neoforge.network.simple.SimpleChannel;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
import org.embeddedt.modernfix.ModernFixClient;
|
||||||
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
||||||
|
|
||||||
public class PacketHandler {
|
public class PacketHandler {
|
||||||
private static final String PROTOCOL_VERSION = "1";
|
private static void registerPackets(final RegisterPayloadHandlerEvent event) {
|
||||||
public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
|
final IPayloadRegistrar registrar = event.registrar(ModernFix.MODID).optional();
|
||||||
new ResourceLocation(ModernFix.MODID, "main"),
|
registrar.play(EntityIDSyncPacket.ID, EntityIDSyncPacket::new, PacketHandler::handleSyncPacket);
|
||||||
() -> PROTOCOL_VERSION,
|
}
|
||||||
NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION),
|
|
||||||
NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION)
|
|
||||||
);
|
|
||||||
|
|
||||||
public static void register() {
|
public static void register() {
|
||||||
int id = 1;
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(PacketHandler::registerPackets);
|
||||||
INSTANCE.registerMessage(id++, EntityIDSyncPacket.class, EntityIDSyncPacket::serialize, EntityIDSyncPacket::deserialize, PacketHandler::handleSyncPacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleSyncPacket(EntityIDSyncPacket packet, NetworkEvent.Context contextSupplier) {
|
private static void handleSyncPacket(EntityIDSyncPacket packet, PlayPayloadContext context) {
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
context.workHandler().execute(() -> ModernFixClient.handleEntityIDSync(packet));
|
||||||
contextSupplier.enqueueWork(() -> ModernFixClient.handleEntityIDSync(packet));
|
|
||||||
contextSupplier.setPacketHandled(true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.google.common.collect.Multimap;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import net.minecraft.client.searchtree.SearchRegistry;
|
import net.minecraft.client.searchtree.SearchRegistry;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
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.core.ModernFixMixinPlugin;
|
||||||
import org.embeddedt.modernfix.neoforge.config.NightConfigFixer;
|
import org.embeddedt.modernfix.neoforge.config.NightConfigFixer;
|
||||||
import org.embeddedt.modernfix.neoforge.init.ModernFixForge;
|
import org.embeddedt.modernfix.neoforge.init.ModernFixForge;
|
||||||
import org.embeddedt.modernfix.neoforge.packet.PacketHandler;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||||
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
|
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
|
||||||
import org.embeddedt.modernfix.util.CommonModUtil;
|
import org.embeddedt.modernfix.util.CommonModUtil;
|
||||||
|
|
@ -87,8 +87,8 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks {
|
||||||
return FMLPaths.GAMEDIR.get();
|
return FMLPaths.GAMEDIR.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPacket(ServerPlayer player, Object packet) {
|
public void sendPacket(ServerPlayer player, CustomPacketPayload packet) {
|
||||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
PacketDistributor.PLAYER.with(player).send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void injectPlatformSpecificHacks() {
|
public void injectPlatformSpecificHacks() {
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,9 @@ Egregious, yet effective performance improvements for modern Minecraft
|
||||||
# the modid of the dependency
|
# the modid of the dependency
|
||||||
modId = "neoforge" #mandatory
|
modId = "neoforge" #mandatory
|
||||||
# Does this dependency have to exist - if not, ordering below must be specified
|
# 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
|
# 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
|
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
|
||||||
ordering = "NONE"
|
ordering = "NONE"
|
||||||
# Side this dependency is applied on - BOTH, CLIENT or SERVER
|
# Side this dependency is applied on - BOTH, CLIENT or SERVER
|
||||||
|
|
@ -55,14 +55,14 @@ side = "BOTH"
|
||||||
# Here's another dependency
|
# Here's another dependency
|
||||||
[[dependencies.modernfix]]
|
[[dependencies.modernfix]]
|
||||||
modId = "minecraft"
|
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
|
# 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)"
|
versionRange = "[1.20, 1.21)"
|
||||||
ordering = "NONE"
|
ordering = "NONE"
|
||||||
side = "BOTH"
|
side = "BOTH"
|
||||||
[[dependencies.modernfix]]
|
[[dependencies.modernfix]]
|
||||||
modId = "jei"
|
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
|
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
||||||
versionRange = "[13,)"
|
versionRange = "[13,)"
|
||||||
ordering = "BEFORE"
|
ordering = "BEFORE"
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,13 +5,20 @@ pluginManagement {
|
||||||
maven { url "https://maven.architectury.dev/" }
|
maven { url "https://maven.architectury.dev/" }
|
||||||
maven { url "https://maven.minecraftforge.net/" }
|
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("test_agent")
|
||||||
include("common")
|
include("common")
|
||||||
|
|
||||||
startParameter.excludedTaskNames.add(':fabric:testmod:genSources')
|
|
||||||
|
|
||||||
def current_platforms = getProperty("enabled_platforms").tokenize(',')
|
def current_platforms = getProperty("enabled_platforms").tokenize(',')
|
||||||
current_platforms.each { it ->
|
current_platforms.each { it ->
|
||||||
def platform_name = it.trim()
|
def platform_name = it.trim()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user