Remove Fabric subproject
This commit is contained in:
parent
d64a1c760b
commit
9c4da7fa68
|
|
@ -1,128 +0,0 @@
|
||||||
plugins {
|
|
||||||
id "com.github.johnrengelman.shadow"
|
|
||||||
id 'com.adarshr.test-logger' version '3.2.0'
|
|
||||||
id "modernfix.mod-common-conventions"
|
|
||||||
id "modernfix.platform-conventions"
|
|
||||||
}
|
|
||||||
|
|
||||||
architectury {
|
|
||||||
platformSetupLoomIde()
|
|
||||||
fabric()
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
common
|
|
||||||
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
|
|
||||||
compileClasspath.extendsFrom common
|
|
||||||
runtimeClasspath.extendsFrom common
|
|
||||||
|
|
||||||
modIncludeImplementation
|
|
||||||
|
|
||||||
include.extendsFrom modIncludeImplementation
|
|
||||||
modImplementation.extendsFrom modIncludeImplementation
|
|
||||||
|
|
||||||
testAgent {
|
|
||||||
canBeConsumed = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
|
||||||
testImplementation "net.fabricmc:fabric-loader-junit:${rootProject.fabric_loader_version}"
|
|
||||||
annotationProcessor("io.github.llamalad7:mixinextras-fabric:${rootProject.mixinextras_version}")
|
|
||||||
|
|
||||||
modCompileOnly(fabricApi.module("fabric-api-base", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modCompileOnly(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modCompileOnly(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modCompileOnly(fabricApi.module("fabric-model-loading-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modCompileOnly(fabricApi.module("fabric-models-v0", "0.84.0+1.20.1")) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modCompileOnly(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modCompileOnly(fabricApi.module("fabric-data-generation-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
if(project.use_fabric_api_at_runtime.toBoolean()) {
|
|
||||||
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
|
||||||
modImplementation "curse.maven:spark-361579:${rootProject.spark_version}"
|
|
||||||
modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}") { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
} else {
|
|
||||||
modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
|
||||||
modCompileOnly "curse.maven:spark-361579:${rootProject.spark_version}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the next line if you don't want to depend on the API
|
|
||||||
// modApi "me.shedaniel:architectury-fabric:${rootProject.architectury_version}"
|
|
||||||
|
|
||||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
|
||||||
testImplementation(shadowCommon(project(path: ":common", configuration: "transformProductionFabric"))) { transitive false }
|
|
||||||
shadowCommon(project(path: ":annotations"))
|
|
||||||
|
|
||||||
testImplementation(platform("org.junit:junit-bom:${project.junit_version}"))
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api")
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-params")
|
|
||||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
|
|
||||||
testImplementation("org.junit.platform:junit-platform-launcher")
|
|
||||||
testImplementation("org.assertj:assertj-core:3.19.0")
|
|
||||||
testImplementation("com.google.guava:guava-testlib:21.0")
|
|
||||||
testImplementation("org.mockito:mockito-junit-jupiter:5.3.1")
|
|
||||||
|
|
||||||
testAgent(project("path": ":test_agent", "configuration": "agentJar"))
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named("test") {
|
|
||||||
useJUnitPlatform()
|
|
||||||
def runDir = file('test_run')
|
|
||||||
doFirst() {
|
|
||||||
runDir.mkdir()
|
|
||||||
}
|
|
||||||
workingDir = runDir
|
|
||||||
systemProperty 'modernfix.ignoreConfigForTesting', 'true'
|
|
||||||
|
|
||||||
// inject our custom agent to fix #817
|
|
||||||
FileCollection agentFile = configurations.getByName("testAgent")
|
|
||||||
jvmArgs "-javaagent:${agentFile.singleFile.absolutePath}"
|
|
||||||
dependsOn(agentFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
inputs.property "version", project.version
|
|
||||||
|
|
||||||
filesMatching("fabric.mod.json") {
|
|
||||||
expand "version": project.version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shadowJar {
|
|
||||||
exclude "architectury.common.json"
|
|
||||||
|
|
||||||
configurations = [project.configurations.shadowCommon]
|
|
||||||
archiveClassifier.set("dev-shadow")
|
|
||||||
}
|
|
||||||
|
|
||||||
remapJar {
|
|
||||||
injectAccessWidener = true
|
|
||||||
input.set shadowJar.archiveFile
|
|
||||||
dependsOn shadowJar
|
|
||||||
archiveClassifier.set(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
|
||||||
archiveClassifier.set("dev")
|
|
||||||
}
|
|
||||||
|
|
||||||
components.java {
|
|
||||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
|
||||||
skip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
mavenFabric(MavenPublication) {
|
|
||||||
artifactId = rootProject.archives_base_name + "-" + project.name
|
|
||||||
from components.java
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
|
||||||
repositories {
|
|
||||||
// Add repositories to publish to here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix;
|
|
||||||
|
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import org.embeddedt.modernfix.fabric.datagen.RuntimeDatagen;
|
|
||||||
|
|
||||||
public class ModernFixClientFabric implements ClientModInitializer {
|
|
||||||
public static ModernFixClient commonMod;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInitializeClient() {
|
|
||||||
commonMod = new ModernFixClient();
|
|
||||||
|
|
||||||
if(FabricLoader.getInstance().isModLoaded("fabric-data-generation-api-v1")) {
|
|
||||||
RuntimeDatagen.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package org.embeddedt.modernfix;
|
|
||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
public class ModernFixFabric implements ModInitializer {
|
|
||||||
public static ModernFix commonMod;
|
|
||||||
public static WeakReference<MinecraftServer> theServer = new WeakReference<>(null);
|
|
||||||
@Override
|
|
||||||
public void onInitialize() {
|
|
||||||
commonMod = new ModernFix();
|
|
||||||
|
|
||||||
// TODO: implement entity ID desync
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package org.embeddedt.modernfix;
|
|
||||||
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
|
|
||||||
import net.fabricmc.loader.impl.gui.FabricGuiEntry;
|
|
||||||
import net.fabricmc.loader.impl.gui.FabricStatusTree;
|
|
||||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
|
||||||
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
|
|
||||||
import org.embeddedt.modernfix.util.CommonModUtil;
|
|
||||||
|
|
||||||
public class ModernFixPreLaunchFabric implements PreLaunchEntrypoint {
|
|
||||||
@Override
|
|
||||||
public void onPreLaunch() {
|
|
||||||
if(ModernFixMixinPlugin.instance == null) {
|
|
||||||
System.err.println("Mixin plugin not loaded yet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_launch.OnFabric")) {
|
|
||||||
CommonModUtil.runWithoutCrash(() -> SparkLaunchProfiler.start("launch"), "Failed to start profiler");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent launching with Continuity when dynamic resources is on
|
|
||||||
if(false && ModernFixMixinPlugin.instance.isOptionEnabled("perf.dynamic_resources.ContinuityCheck")
|
|
||||||
&& FabricLoader.getInstance().isModLoaded("continuity")) {
|
|
||||||
CommonModUtil.runWithoutCrash(() -> {
|
|
||||||
FabricGuiEntry.displayError("Compatibility warning", null, tree -> {
|
|
||||||
FabricStatusTree.FabricStatusTab crashTab = tree.addTab("Warning");
|
|
||||||
crashTab.node.addMessage("Continuity and ModernFix's dynamic resources option are not compatible before Minecraft 1.19.4.", FabricStatusTree.FabricTreeWarningLevel.ERROR);
|
|
||||||
crashTab.node.addMessage("Remove Continuity or disable dynamic resources in the ModernFix config.", FabricStatusTree.FabricTreeWarningLevel.ERROR);
|
|
||||||
tree.tabs.removeIf(tab -> tab != crashTab);
|
|
||||||
}, true);
|
|
||||||
}, "display Continuity warning");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.api.dynresources;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
public class ModelScanController {
|
|
||||||
public static final List<Predicate<ResourceLocation>> SCAN_PREDICATES = new ArrayList<>();
|
|
||||||
public static boolean shouldScanAndTestWrapping(ResourceLocation location) {
|
|
||||||
if(SCAN_PREDICATES.size() > 0) {
|
|
||||||
for(Predicate<ResourceLocation> predicate : SCAN_PREDICATES) {
|
|
||||||
if(!predicate.test(location))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.datagen;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
|
||||||
import net.fabricmc.fabric.impl.datagen.FabricDataGenHelper;
|
|
||||||
import net.minecraft.client.gui.components.Button;
|
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
public class RuntimeDatagen {
|
|
||||||
private static final boolean SHOULD_RUNTIME_DATAGEN = System.getProperty("fabric-api.datagen.output-dir") != null;
|
|
||||||
|
|
||||||
private static void runRuntimeDatagen() {
|
|
||||||
// call runInternal directly to avoid exiting immediately
|
|
||||||
try {
|
|
||||||
System.setProperty("fabric-api.datagen", "true");
|
|
||||||
Method method = FabricDataGenHelper.class.getDeclaredMethod("runInternal");
|
|
||||||
method.setAccessible(true);
|
|
||||||
method.invoke(null);
|
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.error("Error running datagen", e);
|
|
||||||
} finally {
|
|
||||||
System.clearProperty("fabric-api.datagen");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init() {
|
|
||||||
if(!SHOULD_RUNTIME_DATAGEN)
|
|
||||||
return;
|
|
||||||
ScreenEvents.AFTER_INIT.register(((client, s, scaledWidth, scaledHeight) -> {
|
|
||||||
if(s instanceof TitleScreen screen) {
|
|
||||||
screen.addRenderableWidget(Button.builder(Component.literal("DG"), (arg) -> {
|
|
||||||
runRuntimeDatagen();
|
|
||||||
}).pos(screen.width / 2 - 100 - 50, screen.height / 4 + 48).size(50, 20).build());
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.core;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(MinecraftServer.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class ClientMinecraftServerMixin {
|
|
||||||
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getMillis()J", ordinal = 0))
|
|
||||||
private void markServerStarted(CallbackInfo ci) {
|
|
||||||
ModernFixClient.INSTANCE.onServerStarted((MinecraftServer)(Object)this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.core;
|
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClientFabric;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(value = ClientPacketListener.class, priority = 1500)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class ClientPlayNetHandlerMixin {
|
|
||||||
@Inject(method = "handleUpdateRecipes", at = @At("RETURN"))
|
|
||||||
private void signalRecipes(CallbackInfo ci) {
|
|
||||||
ModernFixClientFabric.commonMod.onRecipesUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "handleUpdateTags", at = @At("RETURN"))
|
|
||||||
private void signalTags(CallbackInfo ci) {
|
|
||||||
ModernFixClientFabric.commonMod.onTagsUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.core;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class MCMixin_Fabric {
|
|
||||||
@Inject(method = "tick", at = @At("RETURN"))
|
|
||||||
private void onRenderTickEnd(CallbackInfo ci) {
|
|
||||||
ModernFixClient.INSTANCE.onRenderTickEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.core;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.ModernFixFabric;
|
|
||||||
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;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
@Mixin(MinecraftServer.class)
|
|
||||||
public class MinecraftServerMixin {
|
|
||||||
@Inject(method = "runServer", at = @At("HEAD"))
|
|
||||||
private void changeServerReference(CallbackInfo ci) {
|
|
||||||
ModernFixFabric.theServer = new WeakReference<>((MinecraftServer)(Object)this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getMillis()J", ordinal = 0))
|
|
||||||
private void hookServerStarted(CallbackInfo ci) {
|
|
||||||
ModernFix.INSTANCE.onServerStarted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "stopServer", at = @At("RETURN"))
|
|
||||||
private void hookServerShutdown(CallbackInfo ci) {
|
|
||||||
ModernFix.INSTANCE.onServerDead((MinecraftServer)(Object)this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.feature.branding;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.components.DebugScreenOverlay;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClientFabric;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(DebugScreenOverlay.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class GuiMixin {
|
|
||||||
@ModifyVariable(method = "getSystemInformation", at = @At("STORE"), ordinal = 0, require = 0)
|
|
||||||
private List<String> addModernFix(List<String> list) {
|
|
||||||
list.add("");
|
|
||||||
list.add(ModernFixClientFabric.commonMod.brandingString);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.feature.measure_time;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class MinecraftMixin_Fabric {
|
|
||||||
@Inject(method = "doWorldLoad", at = @At("HEAD"))
|
|
||||||
private void recordWorldLoadStart(CallbackInfo ci) {
|
|
||||||
ModernFixClient.worldLoadStartTime = System.nanoTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl;
|
|
||||||
import net.minecraft.client.resources.model.ModelBakery;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
@Mixin(ModelLoadingRegistryImpl.LoaderInstance.class)
|
|
||||||
@RequiresMod("fabric-models-v0")
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class LoaderInstanceMixin {
|
|
||||||
@Redirect(method = "finish", at = @At(value = "FIELD", target = "Lnet/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl$LoaderInstance;loader:Lnet/minecraft/client/resources/model/ModelBakery;"), require = 0)
|
|
||||||
private void keepLoader(ModelLoadingRegistryImpl.LoaderInstance instance, ModelBakery value) {
|
|
||||||
/* allow loading models to happen later */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
||||||
import net.minecraft.client.resources.model.*;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.ModelMissingException;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
|
|
||||||
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
|
||||||
@Shadow @Final private ModelBakery field_40571;
|
|
||||||
|
|
||||||
@Shadow public abstract UnbakedModel getModel(ResourceLocation arg);
|
|
||||||
|
|
||||||
@Shadow @Final private Function<Material, TextureAtlasSprite> modelTextureGetter;
|
|
||||||
|
|
||||||
private static final MethodHandle blockStateLoaderHandle;
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
blockStateLoaderHandle = MethodHandles.lookup().unreflect(ModelBakery.class.getDeclaredMethod(
|
|
||||||
FabricLoader.getInstance().getMappingResolver().mapMethodName(
|
|
||||||
"intermediary",
|
|
||||||
"net.minecraft.client.resources.model.ModelBakery",
|
|
||||||
"method_4716",
|
|
||||||
"(Lnet/minecraft/world/level/block/state/BlockState;)V"
|
|
||||||
),
|
|
||||||
BlockState.class
|
|
||||||
));
|
|
||||||
} catch(ReflectiveOperationException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean throwIfMissing;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean throwOnMissingModel(boolean flag) {
|
|
||||||
boolean old = throwIfMissing;
|
|
||||||
throwIfMissing = flag;
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void obtainModel(ResourceLocation arg, CallbackInfoReturnable<UnbakedModel> cir) {
|
|
||||||
if(debugDynamicModelLoading)
|
|
||||||
ModernFix.LOGGER.info("Baking {}", arg);
|
|
||||||
IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571;
|
|
||||||
if(arg instanceof ModelResourceLocation && arg != ModelBakery.MISSING_MODEL_LOCATION) {
|
|
||||||
// synchronized because we use topLevelModels
|
|
||||||
synchronized (this.field_40571) {
|
|
||||||
/* to emulate vanilla model loading, treat as top-level */
|
|
||||||
Optional<Block> blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath()));
|
|
||||||
boolean invalidMRL = false;
|
|
||||||
if(blockOpt.isPresent()) {
|
|
||||||
/* load via lambda for mods that expect blockstate to get loaded */
|
|
||||||
ImmutableList<BlockState> states;
|
|
||||||
try {
|
|
||||||
states = extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
states = ImmutableList.of();
|
|
||||||
invalidMRL = true;
|
|
||||||
// Fall back to getModel
|
|
||||||
cir.setReturnValue(this.field_40571.getModel(arg));
|
|
||||||
}
|
|
||||||
for(BlockState state : states) {
|
|
||||||
try {
|
|
||||||
blockStateLoaderHandle.invokeExact(this.field_40571, state);
|
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.error("Error loading model", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.field_40571.loadTopLevel((ModelResourceLocation)arg);
|
|
||||||
}
|
|
||||||
if(!invalidMRL) {
|
|
||||||
cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel()));
|
|
||||||
// avoid leaks
|
|
||||||
this.field_40571.topLevelModels.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
cir.setReturnValue(this.field_40571.getModel(arg));
|
|
||||||
UnbakedModel toReplace = cir.getReturnValue();
|
|
||||||
if(true) {
|
|
||||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
|
||||||
try {
|
|
||||||
toReplace = integration.onUnbakedModelPreBake(arg, toReplace, this.field_40571);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
ModernFix.LOGGER.error("Exception firing model pre-bake event for {}", arg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cir.setReturnValue(toReplace);
|
|
||||||
cir.getReturnValue().resolveParents(this.field_40571::getModel);
|
|
||||||
if(cir.getReturnValue() == extendedBakery.mfix$getUnbakedMissingModel()) {
|
|
||||||
if(arg != ModelBakery.MISSING_MODEL_LOCATION) {
|
|
||||||
if(debugDynamicModelLoading)
|
|
||||||
ModernFix.LOGGER.warn("Model {} not present", arg);
|
|
||||||
if(throwIfMissing)
|
|
||||||
throw new ModelMissingException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@WrapOperation(method = "bake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/UnbakedModel;bake(Lnet/minecraft/client/resources/model/ModelBaker;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/BakedModel;"))
|
|
||||||
private BakedModel callBakedModelIntegration(UnbakedModel unbakedModel, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState state, ResourceLocation location, Operation<BakedModel> operation) {
|
|
||||||
BakedModel model = operation.call(unbakedModel, baker, spriteGetter, state, location);
|
|
||||||
|
|
||||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
|
||||||
model = integration.onBakedModelLoad(location, unbakedModel, model, state, this.field_40571, spriteGetter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason emulate old function, to allow injectors to work
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
@Overwrite
|
|
||||||
public BakedModel bake(ResourceLocation arg, ModelState arg2) {
|
|
||||||
ModelBakery.BakedCacheKey key = new ModelBakery.BakedCacheKey(arg, arg2.getRotation(), arg2.isUvLocked());
|
|
||||||
BakedModel existing = this.field_40571.bakedCache.get(key);
|
|
||||||
if (existing != null) {
|
|
||||||
return existing;
|
|
||||||
} else {
|
|
||||||
synchronized (this.field_40571) {
|
|
||||||
if(debugDynamicModelLoading)
|
|
||||||
ModernFix.LOGGER.info("Baking {}", arg);
|
|
||||||
UnbakedModel iunbakedmodel = this.getModel(arg);
|
|
||||||
// TODO: make sure parent resolution doesn't re-run many times
|
|
||||||
iunbakedmodel.resolveParents(this::getModel);
|
|
||||||
BakedModel ibakedmodel = null;
|
|
||||||
if (iunbakedmodel instanceof BlockModel) {
|
|
||||||
BlockModel blockmodel = (BlockModel)iunbakedmodel;
|
|
||||||
if (blockmodel.getRootModel() == ModelBakery.GENERATION_MARKER) {
|
|
||||||
ibakedmodel = ModelBakery.ITEM_MODEL_GENERATOR.generateBlockModel(this.modelTextureGetter, blockmodel).bake((ModelBaker)this, blockmodel, this.modelTextureGetter, arg2, arg, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ibakedmodel == null) {
|
|
||||||
// leave the original assignment in the same spot so wrapping injectors work
|
|
||||||
// this means two bakes might happen for missing models, but not much we can do
|
|
||||||
ibakedmodel = iunbakedmodel.bake((ModelBaker)this, this.modelTextureGetter, arg2, arg);
|
|
||||||
IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571;
|
|
||||||
if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel()) {
|
|
||||||
// use a shared baked missing model
|
|
||||||
createBakedMissingModelIfNeeded(extendedBakery, iunbakedmodel, arg2, arg);
|
|
||||||
ibakedmodel = extendedBakery.getBakedMissingModel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.field_40571.bakedCache.put(key, ibakedmodel);
|
|
||||||
return ibakedmodel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
@ -1,334 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
|
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.RemovalNotification;
|
|
||||||
import com.google.common.collect.ForwardingMap;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.color.block.BlockColors;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
||||||
import net.minecraft.client.resources.model.*;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBaker;
|
|
||||||
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.*;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
|
|
||||||
/* low priority so that our injectors are added after other mods' */
|
|
||||||
@Mixin(value = ModelBakery.class, priority = 1100)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|
||||||
|
|
||||||
private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading");
|
|
||||||
|
|
||||||
@Shadow @Final @Mutable public Map<ResourceLocation, UnbakedModel> unbakedCache;
|
|
||||||
|
|
||||||
@Shadow @Final public static ModelResourceLocation MISSING_MODEL_LOCATION;
|
|
||||||
|
|
||||||
@Shadow @Final private Set<ResourceLocation> loadingStack;
|
|
||||||
|
|
||||||
@Shadow protected abstract void loadModel(ResourceLocation blockstateLocation) throws Exception;
|
|
||||||
|
|
||||||
@Shadow @Final @Mutable
|
|
||||||
private Map<ResourceLocation, BakedModel> bakedTopLevelModels;
|
|
||||||
|
|
||||||
@Shadow @Final @Mutable private Map<ModelBakery.BakedCacheKey, BakedModel> bakedCache;
|
|
||||||
|
|
||||||
@Shadow @Final @Mutable private BlockColors blockColors;
|
|
||||||
@Shadow @Final private static Logger LOGGER;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract void loadTopLevel(ModelResourceLocation modelResourceLocation);
|
|
||||||
|
|
||||||
@Shadow public abstract UnbakedModel getModel(ResourceLocation resourceLocation);
|
|
||||||
|
|
||||||
private Cache<ModelBakery.BakedCacheKey, BakedModel> loadedBakedModels;
|
|
||||||
|
|
||||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
|
||||||
|
|
||||||
private HashMap<ResourceLocation, UnbakedModel> smallLoadingCache = new HashMap<>();
|
|
||||||
|
|
||||||
private boolean ignoreModelLoad;
|
|
||||||
|
|
||||||
// disable fabric recursion
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private boolean fabric_enableGetOrLoadModelGuard;
|
|
||||||
|
|
||||||
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/resources/model/ModelBakery;blockColors:Lnet/minecraft/client/color/block/BlockColors;"))
|
|
||||||
private void replaceTopLevelBakedModels(ModelBakery bakery, BlockColors val) {
|
|
||||||
// we can handle recursion in getModel without issues
|
|
||||||
fabric_enableGetOrLoadModelGuard = false;
|
|
||||||
this.blockColors = val;
|
|
||||||
this.loadedBakedModels = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterAccess(ModelBakeryHelpers.MAX_MODEL_LIFETIME_SECS, TimeUnit.SECONDS)
|
|
||||||
.maximumSize(ModelBakeryHelpers.MAX_BAKED_MODEL_COUNT)
|
|
||||||
.concurrencyLevel(8)
|
|
||||||
.removalListener(this::onModelRemoved)
|
|
||||||
.softValues()
|
|
||||||
.build();
|
|
||||||
this.loadedModels = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterAccess(ModelBakeryHelpers.MAX_MODEL_LIFETIME_SECS, TimeUnit.SECONDS)
|
|
||||||
.maximumSize(ModelBakeryHelpers.MAX_UNBAKED_MODEL_COUNT)
|
|
||||||
.concurrencyLevel(8)
|
|
||||||
.removalListener(this::onModelRemoved)
|
|
||||||
//.softValues()
|
|
||||||
.build();
|
|
||||||
this.bakedCache = loadedBakedModels.asMap();
|
|
||||||
ConcurrentMap<ResourceLocation, UnbakedModel> unbakedCacheBackingMap = loadedModels.asMap();
|
|
||||||
this.unbakedCache = new ForwardingMap<ResourceLocation, UnbakedModel>() {
|
|
||||||
@Override
|
|
||||||
protected Map<ResourceLocation, UnbakedModel> delegate() {
|
|
||||||
return unbakedCacheBackingMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UnbakedModel put(ResourceLocation key, UnbakedModel value) {
|
|
||||||
smallLoadingCache.put(key, value);
|
|
||||||
return super.put(key, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", ordinal = 0))
|
|
||||||
private void ignoreFutureModelLoads(CallbackInfo ci) {
|
|
||||||
this.ignoreModelLoad = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <K, V> void onModelRemoved(RemovalNotification<K, V> notification) {
|
|
||||||
if(!debugDynamicModelLoading)
|
|
||||||
return;
|
|
||||||
Object k = notification.getKey();
|
|
||||||
if(k == null)
|
|
||||||
return;
|
|
||||||
ResourceLocation rl;
|
|
||||||
boolean baked = false;
|
|
||||||
if(k instanceof ResourceLocation) {
|
|
||||||
rl = (ResourceLocation)k;
|
|
||||||
} else {
|
|
||||||
rl = ((ModelBakery.BakedCacheKey)k).id();
|
|
||||||
baked = true;
|
|
||||||
}
|
|
||||||
/* can fire when a model is replaced */
|
|
||||||
if(!baked && this.loadedModels.getIfPresent(rl) != null)
|
|
||||||
return;
|
|
||||||
ModernFix.LOGGER.warn("Evicted {} model {}", baked ? "baked" : "unbaked", rl);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnbakedModel missingModel;
|
|
||||||
|
|
||||||
private Set<ResourceLocation> blockStateFiles;
|
|
||||||
private Set<ResourceLocation> modelFiles;
|
|
||||||
|
|
||||||
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0), index = 1)
|
|
||||||
private Object captureMissingModel(Object model) {
|
|
||||||
this.missingModel = (UnbakedModel)model;
|
|
||||||
this.blockStateFiles = new HashSet<>();
|
|
||||||
this.modelFiles = new HashSet<>();
|
|
||||||
return this.missingModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason don't actually load most models
|
|
||||||
*/
|
|
||||||
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ModelBakery;loadTopLevel(Lnet/minecraft/client/resources/model/ModelResourceLocation;)V"))
|
|
||||||
private void addTopLevelFile(ModelBakery bakery, ModelResourceLocation location) {
|
|
||||||
if(location == MISSING_MODEL_LOCATION || !this.ignoreModelLoad) {
|
|
||||||
loadTopLevel(location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/Map;forEach(Ljava/util/function/BiConsumer;)V", ordinal = 0))
|
|
||||||
private void fetchStaticDefinitions(Map<ResourceLocation, StateDefinition<Block, BlockState>> map, BiConsumer<ResourceLocation, StateDefinition<Block, BlockState>> func) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/StateDefinition;getPossibleStates()Lcom/google/common/collect/ImmutableList;", ordinal = 0))
|
|
||||||
private ImmutableList<BlockState> fetchBlocks(StateDefinition<Block, BlockState> def) {
|
|
||||||
/* no-op */
|
|
||||||
return ImmutableList.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a copy of the top-level model list to avoid CME if more models get loaded here.
|
|
||||||
*/
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/Map;values()Ljava/util/Collection;", ordinal = 0))
|
|
||||||
private Collection<?> copyTopLevelModelList(Map<?, ?> map) {
|
|
||||||
return new ArrayList<>(map.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
private BiFunction<ResourceLocation, Material, TextureAtlasSprite> textureGetter;
|
|
||||||
|
|
||||||
@Inject(method = "bakeModels", at = @At("HEAD"))
|
|
||||||
private void captureGetter(BiFunction<ResourceLocation, Material, TextureAtlasSprite> getter, CallbackInfo ci) {
|
|
||||||
this.ignoreModelLoad = false;
|
|
||||||
textureGetter = getter;
|
|
||||||
DynamicBakedModelProvider.currentInstance = (DynamicBakedModelProvider)this.bakedTopLevelModels;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "bakeModels", at = @At(value = "INVOKE", target = "Ljava/util/Map;keySet()Ljava/util/Set;"))
|
|
||||||
private Set<ResourceLocation> skipBake(Map<ResourceLocation, UnbakedModel> instance) {
|
|
||||||
Set<ResourceLocation> modelSet = new HashSet<>(instance.keySet());
|
|
||||||
if(modelSet.size() > 0)
|
|
||||||
ModernFix.LOGGER.info("Early baking {} models", modelSet.size());
|
|
||||||
return modelSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the already loaded missing model instead of the cache entry (which will probably get evicted).
|
|
||||||
*/
|
|
||||||
@Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 1))
|
|
||||||
private Object getMissingModel(Map map, Object rl) {
|
|
||||||
if(rl == MISSING_MODEL_LOCATION && map == unbakedCache)
|
|
||||||
return missingModel;
|
|
||||||
return unbakedCache.get(rl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ModifyVariable(method = "cacheAndQueueDependencies", at = @At("HEAD"), argsOnly = true)
|
|
||||||
private UnbakedModel fireUnbakedEvent(UnbakedModel model, ResourceLocation location) {
|
|
||||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
|
||||||
try {
|
|
||||||
model = integration.onUnbakedModelLoad(location, model, (ModelBakery)(Object)this);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
ModernFix.LOGGER.error("Exception firing model load event for {}", location, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int mfix$nestedLoads = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason synchronize
|
|
||||||
*/
|
|
||||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
|
||||||
public void getOrLoadModelDynamic(ResourceLocation modelLocation, CallbackInfoReturnable<UnbakedModel> cir) {
|
|
||||||
if(modelLocation.equals(MISSING_MODEL_LOCATION)) {
|
|
||||||
cir.setReturnValue(missingModel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UnbakedModel existing = this.unbakedCache.get(modelLocation);
|
|
||||||
if (existing != null) {
|
|
||||||
cir.setReturnValue(existing);
|
|
||||||
} else {
|
|
||||||
synchronized(this) {
|
|
||||||
if (this.loadingStack.contains(modelLocation)) {
|
|
||||||
throw new IllegalStateException("Circular reference while loading " + modelLocation);
|
|
||||||
} else {
|
|
||||||
this.loadingStack.add(modelLocation);
|
|
||||||
UnbakedModel iunbakedmodel = missingModel;
|
|
||||||
|
|
||||||
while(!this.loadingStack.isEmpty()) {
|
|
||||||
ResourceLocation resourcelocation = this.loadingStack.iterator().next();
|
|
||||||
|
|
||||||
mfix$nestedLoads++;
|
|
||||||
try {
|
|
||||||
existing = this.unbakedCache.get(resourcelocation);
|
|
||||||
if (existing == null) {
|
|
||||||
if(debugDynamicModelLoading)
|
|
||||||
LOGGER.info("Loading {}", resourcelocation);
|
|
||||||
this.loadModel(resourcelocation);
|
|
||||||
} else
|
|
||||||
smallLoadingCache.put(resourcelocation, existing);
|
|
||||||
} catch (ModelBakery.BlockStateDefinitionException var9) {
|
|
||||||
LOGGER.warn(var9.getMessage());
|
|
||||||
this.unbakedCache.put(resourcelocation, iunbakedmodel);
|
|
||||||
smallLoadingCache.put(resourcelocation, iunbakedmodel);
|
|
||||||
} catch (Exception var10) {
|
|
||||||
LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10);
|
|
||||||
this.unbakedCache.put(resourcelocation, iunbakedmodel);
|
|
||||||
smallLoadingCache.put(resourcelocation, iunbakedmodel);
|
|
||||||
} finally {
|
|
||||||
mfix$nestedLoads--;
|
|
||||||
this.loadingStack.remove(resourcelocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have to get the result from the temporary cache used for a model load
|
|
||||||
// As in pathological cases (e.g. Pedestals on 1.19) unbakedCache can lose
|
|
||||||
// the model immediately
|
|
||||||
UnbakedModel result = smallLoadingCache.getOrDefault(modelLocation, iunbakedmodel);
|
|
||||||
try {
|
|
||||||
// required as some mods (e.g. EBE) call bake directly on the returned model, without resolving parents themselves
|
|
||||||
result.resolveParents(this::getModel);
|
|
||||||
} catch(RuntimeException ignored) {}
|
|
||||||
// We are done with loading, so clear this cache to allow GC of any unneeded models
|
|
||||||
if(mfix$nestedLoads == 0)
|
|
||||||
smallLoadingCache.clear();
|
|
||||||
cir.setReturnValue(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends Comparable<T>, V extends T> BlockState setPropertyGeneric(BlockState state, Property<T> prop, Object o) {
|
|
||||||
return state.setValue(prop, (V)o);
|
|
||||||
}
|
|
||||||
@Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/StateDefinition;getPossibleStates()Lcom/google/common/collect/ImmutableList;"))
|
|
||||||
private ImmutableList<BlockState> loadOnlyRelevantBlockState(StateDefinition<Block, BlockState> stateDefinition, ResourceLocation location) {
|
|
||||||
if(!(location instanceof ModelResourceLocation) || Minecraft.getInstance().getOverlay() != null || Minecraft.getInstance().level == null)
|
|
||||||
return stateDefinition.getPossibleStates();
|
|
||||||
return ModelBakeryHelpers.getBlockStatesForMRL(stateDefinition, (ModelResourceLocation)location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state) {
|
|
||||||
ModelBakery.BakedCacheKey key = new ModelBakery.BakedCacheKey(modelLocation, BlockModelRotation.X0_Y0.getRotation(), BlockModelRotation.X0_Y0.isUvLocked());
|
|
||||||
BakedModel m = loadedBakedModels.getIfPresent(key);
|
|
||||||
if(m != null)
|
|
||||||
return m;
|
|
||||||
ModelBakery self = (ModelBakery) (Object) this;
|
|
||||||
ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation);
|
|
||||||
((IExtendedModelBaker)theBaker).throwOnMissingModel(true);
|
|
||||||
synchronized(this) { m = theBaker.bake(modelLocation, state); }
|
|
||||||
if(m != null)
|
|
||||||
loadedBakedModels.put(key, m);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImmutableList<BlockState> getBlockStatesForMRL(StateDefinition<Block, BlockState> stateDefinition, ModelResourceLocation location) {
|
|
||||||
return loadOnlyRelevantBlockState(stateDefinition, location);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnbakedModel mfix$getUnbakedMissingModel() {
|
|
||||||
return missingModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mfix$clearModels() {
|
|
||||||
loadedModels.invalidateAll();
|
|
||||||
loadedBakedModels.invalidateAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.perf.faster_command_suggestions;
|
|
||||||
|
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
|
||||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
|
||||||
import org.spongepowered.asm.mixin.*;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple hack-fix to limit the number of suggestions being processed. Not a perfect fix but mitigates lag decently
|
|
||||||
* on an i3-4150.
|
|
||||||
*/
|
|
||||||
@Mixin(SuggestionsBuilder.class)
|
|
||||||
public class SuggestionsBuilderMixin {
|
|
||||||
@Unique
|
|
||||||
private static final int MAX_SUGGESTIONS = 10000;
|
|
||||||
|
|
||||||
@Shadow(remap = false) @Final @Mutable
|
|
||||||
private List<Suggestion> result;
|
|
||||||
|
|
||||||
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z"), require = 0)
|
|
||||||
private <T> boolean addIfFits(List<T> list, T entry) {
|
|
||||||
if(list != result || list.size() < MAX_SUGGESTIONS) {
|
|
||||||
return list.add(entry);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.safety;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(DynamicTexture.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class DynamicTextureMixin {
|
|
||||||
@Shadow @Nullable private NativeImage pixels;
|
|
||||||
|
|
||||||
private Exception closeTrace;
|
|
||||||
|
|
||||||
@Inject(method = "method_22793", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/texture/DynamicTexture;pixels:Lcom/mojang/blaze3d/platform/NativeImage;", ordinal = 0))
|
|
||||||
private void checkNullPixels(CallbackInfo ci) {
|
|
||||||
if(pixels == null) {
|
|
||||||
ModernFix.LOGGER.error("Attempted to upload null texture! This is not allowed, closed here", closeTrace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "close", at = @At("HEAD"))
|
|
||||||
private void storeCloseTrace(CallbackInfo ci) {
|
|
||||||
closeTrace = new Exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package org.embeddedt.modernfix.fabric.modmenu;
|
|
||||||
|
|
||||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
|
||||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
|
||||||
import org.embeddedt.modernfix.screen.ModernFixConfigScreen;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class ModernFixModMenuApiImpl implements ModMenuApi {
|
|
||||||
@Override
|
|
||||||
public ConfigScreenFactory<ModernFixConfigScreen> getModConfigScreenFactory() {
|
|
||||||
return ModernFixConfigScreen::new;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
package org.embeddedt.modernfix.platform.fabric;
|
|
||||||
|
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
|
||||||
import net.fabricmc.api.EnvType;
|
|
||||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.fabricmc.loader.api.ModContainer;
|
|
||||||
import net.fabricmc.loader.api.metadata.CustomValue;
|
|
||||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
|
||||||
import net.minecraft.client.searchtree.SearchRegistry;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.item.CreativeModeTabs;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import org.embeddedt.modernfix.ModernFixFabric;
|
|
||||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
|
||||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
|
|
||||||
import org.embeddedt.modernfix.util.CommonModUtil;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks {
|
|
||||||
public boolean isClient() {
|
|
||||||
return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDedicatedServer() {
|
|
||||||
return FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String verString = FabricLoader.getInstance().getModContainer("modernfix")
|
|
||||||
.map(mfModContainer -> mfModContainer.getMetadata().getVersion().getFriendlyString())
|
|
||||||
.orElse("[unknown]");
|
|
||||||
|
|
||||||
public String getVersionString() {
|
|
||||||
return verString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean modPresent(String modId) {
|
|
||||||
return FabricLoader.getInstance().getModContainer(modId).isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDevEnv() {
|
|
||||||
return FabricLoader.getInstance().isDevelopmentEnvironment();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MinecraftServer getCurrentServer() {
|
|
||||||
return ModernFixFabric.theServer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEarlyLoadingNormally() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLoadingNormally() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getGameDirectory() {
|
|
||||||
return FabricLoader.getInstance().getGameDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendPacket(ServerPlayer player, Object packet) {
|
|
||||||
//PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void injectPlatformSpecificHacks() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyASMTransformers(String mixinClassName, ClassNode targetClass) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onServerCommandRegister(Consumer<CommandDispatcher<CommandSourceStack>> handler) {
|
|
||||||
if(FabricLoader.getInstance().isModLoaded("fabric-command-api-v2"))
|
|
||||||
CommandRegistrationCallback.EVENT.register((dispatcher, arg, env) -> handler.accept(dispatcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Multimap<String, String> modOptions;
|
|
||||||
public Multimap<String, String> getCustomModOptions() {
|
|
||||||
if(modOptions == null) {
|
|
||||||
modOptions = ArrayListMultimap.create();
|
|
||||||
for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
|
|
||||||
ModMetadata meta = container.getMetadata();
|
|
||||||
if (meta.containsCustomValue(IntegrationConstants.INTEGRATIONS_KEY)) {
|
|
||||||
CustomValue integrations = meta.getCustomValue(IntegrationConstants.INTEGRATIONS_KEY);
|
|
||||||
if (integrations.getType() != CustomValue.CvType.OBJECT) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (Map.Entry<String, CustomValue> entry : integrations.getAsObject()) {
|
|
||||||
if(entry.getValue().getType() != CustomValue.CvType.STRING)
|
|
||||||
continue;
|
|
||||||
modOptions.put(entry.getKey(), entry.getValue().getAsString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier<ItemStack> nameSupplier, SearchRegistry.TreeBuilderSupplier<ItemStack> tagSupplier, BiConsumer<SearchRegistry.Key<ItemStack>, List<ItemStack>> populator) {
|
|
||||||
CreativeModeTabs.searchTab().setSearchTreeBuilder((list) -> {
|
|
||||||
populator.accept(SearchRegistry.CREATIVE_NAMES, list);
|
|
||||||
populator.accept(SearchRegistry.CREATIVE_TAGS, list);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onLaunchComplete() {
|
|
||||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spark_profile_launch.OnFabric")) {
|
|
||||||
CommonModUtil.runWithoutCrash(() -> SparkLaunchProfiler.stop("launch"), "Failed to stop profiler");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPlatformName() {
|
|
||||||
return "Fabric";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
{
|
|
||||||
"schemaVersion": 1,
|
|
||||||
"id": "modernfix",
|
|
||||||
"version": "${version}",
|
|
||||||
"name": "ModernFix",
|
|
||||||
"description": "Egregious, yet effective performance improvements for modern Minecraft",
|
|
||||||
"authors": [
|
|
||||||
"embeddedt"
|
|
||||||
],
|
|
||||||
"contact": {
|
|
||||||
"sources": "https://github.com/embeddedt/ModernFix",
|
|
||||||
"homepage": "https://modrinth.com/mod/modernfix",
|
|
||||||
"issues": "https://github.com/embeddedt/ModernFix/issues"
|
|
||||||
},
|
|
||||||
"license": "LGPL-3.0",
|
|
||||||
"icon": "icon.png",
|
|
||||||
"custom": {
|
|
||||||
"modmenu": {
|
|
||||||
"links": {
|
|
||||||
"modmenu.kofi": "https://ko-fi.com/embeddedt",
|
|
||||||
"modmenu.github_releases": "https://github.com/embeddedt/ModernFix/releases",
|
|
||||||
"modmenu.curseforge": "https://www.curseforge.com/minecraft/mc-mods/modernfix"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": "*",
|
|
||||||
"entrypoints": {
|
|
||||||
"main": [
|
|
||||||
"org.embeddedt.modernfix.ModernFixFabric"
|
|
||||||
],
|
|
||||||
"client": [
|
|
||||||
"org.embeddedt.modernfix.ModernFixClientFabric"
|
|
||||||
],
|
|
||||||
"modmenu": [ "org.embeddedt.modernfix.fabric.modmenu.ModernFixModMenuApiImpl" ],
|
|
||||||
"preLaunch": [
|
|
||||||
"org.embeddedt.modernfix.ModernFixPreLaunchFabric"
|
|
||||||
],
|
|
||||||
"jei_mod_plugin": [ "org.embeddedt.modernfix.searchtree.JEIRuntimeCapturer"]
|
|
||||||
},
|
|
||||||
"mixins": [
|
|
||||||
"modernfix-fabric.mixins.json",
|
|
||||||
"modernfix-common.mixins.json"
|
|
||||||
],
|
|
||||||
"depends": {
|
|
||||||
"minecraft": ">=1.16.2",
|
|
||||||
"fabricloader": ">=0.16.10"
|
|
||||||
},
|
|
||||||
"breaks": {
|
|
||||||
"dashloader": "<5.0.0-beta.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
package net.minecraft.world.level.block.state;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.material.FluidState;
|
|
||||||
import org.embeddedt.modernfix.duck.IBlockState;
|
|
||||||
import org.embeddedt.modernfix.testing.util.BootstrapMinecraft;
|
|
||||||
import org.junit.jupiter.api.*;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@BootstrapMinecraft
|
|
||||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
|
||||||
public class BlockStateCacheTest {
|
|
||||||
@BeforeEach
|
|
||||||
public void rebuildCache() {
|
|
||||||
Blocks.rebuildCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initially, the cache should be invalid, and null.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@Order(1)
|
|
||||||
public void testCacheNullInitially() {
|
|
||||||
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
|
|
||||||
assertTrue(((IBlockState)stoneBlock).isCacheInvalid());
|
|
||||||
assertNull(stoneBlock.cache);
|
|
||||||
|
|
||||||
// make sure lazy cache correctly handles solid
|
|
||||||
assertTrue(stoneBlock.isSolid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an API that needs the cache is called, it should be built and the invalid flag
|
|
||||||
* becomes false.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@Order(2)
|
|
||||||
public void testCacheBuiltByRequest() {
|
|
||||||
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
|
|
||||||
stoneBlock.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
|
||||||
assertFalse(((IBlockState)stoneBlock).isCacheInvalid());
|
|
||||||
assertNotNull(stoneBlock.cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a second rebuild occurs, the invalid flag should be set to true, but the old cache
|
|
||||||
* is not set to null, in order to prevent NPEs if a second thread is accessing the cache
|
|
||||||
* when this takes place.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@Order(3)
|
|
||||||
public void testCacheInvalidatedByLateRebuild() {
|
|
||||||
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
|
|
||||||
stoneBlock.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
|
||||||
Blocks.rebuildCache();
|
|
||||||
assertTrue(((IBlockState)stoneBlock).isCacheInvalid());
|
|
||||||
assertNotNull(stoneBlock.cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the fluidState and isRandomlyTicking caching fields added by Mojang to blockstates are correctly
|
|
||||||
* handled by the dynamic cache system.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@Order(4)
|
|
||||||
public void testExtraFieldCachingCorrect() {
|
|
||||||
Block[] blocksToCheck = new Block[] { Blocks.WATER, Blocks.FARMLAND };
|
|
||||||
for(Block block : blocksToCheck) {
|
|
||||||
for(BlockState state : block.getStateDefinition().getPossibleStates()) {
|
|
||||||
// check that the fluid states match
|
|
||||||
assertEquals(block.getFluidState(state), state.getFluidState(), "mismatched fluid state on " + state);
|
|
||||||
// check that random ticking flag matches
|
|
||||||
assertEquals(block.isRandomlyTicking(state), state.isRandomlyTicking(), "mismatched random tick state on " + state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Order(5)
|
|
||||||
public void checkRecursiveFluidState() {
|
|
||||||
Block b = new Block(BlockBehaviour.Properties.copy(Blocks.STONE)) {
|
|
||||||
@Override
|
|
||||||
public FluidState getFluidState(BlockState state) {
|
|
||||||
return state.getFluidState();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
BlockState state = b.getStateDefinition().any();
|
|
||||||
((IBlockState)state).clearCache();
|
|
||||||
// this should not throw
|
|
||||||
state.getFluidState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dynamicresources;
|
|
||||||
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.client.resources.model.BuiltInModel;
|
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.Items;
|
|
||||||
import org.embeddedt.modernfix.testing.util.BootstrapMinecraft;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@BootstrapMinecraft
|
|
||||||
public class DynamicModelCacheTest {
|
|
||||||
@Test
|
|
||||||
public void testCacheReturnsNullForNullGetter() {
|
|
||||||
DynamicModelCache<Item> cache = new DynamicModelCache(k -> null, true);
|
|
||||||
assertNull(cache.get(Items.STONE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCacheFunctions() {
|
|
||||||
BakedModel model = new BuiltInModel(null, null, null, false);
|
|
||||||
DynamicModelCache<Item> cache = new DynamicModelCache(k -> model, true);
|
|
||||||
assertEquals(model, cache.get(Items.STONE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testing.util;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@ExtendWith({ BootstrapMinecraftExtension.class })
|
|
||||||
public @interface BootstrapMinecraft {
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testing.util;
|
|
||||||
|
|
||||||
import net.minecraft.DetectedVersion;
|
|
||||||
import net.minecraft.core.MappedRegistry;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.server.Bootstrap;
|
|
||||||
import org.junit.jupiter.api.extension.AfterAllCallback;
|
|
||||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
|
||||||
import org.junit.jupiter.api.extension.Extension;
|
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.IdentityHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple extension to run vanilla bootstrap, inspired by AE2.
|
|
||||||
*/
|
|
||||||
public class BootstrapMinecraftExtension implements Extension, BeforeAllCallback, AfterAllCallback {
|
|
||||||
@Override
|
|
||||||
public void beforeAll(ExtensionContext context) throws Exception {
|
|
||||||
DetectedVersion.tryDetectVersion();
|
|
||||||
Bootstrap.bootStrap();
|
|
||||||
// Allow blocks to be created in tests
|
|
||||||
Field field = MappedRegistry.class.getDeclaredField("unregisteredIntrusiveHolders");
|
|
||||||
field.setAccessible(true);
|
|
||||||
if(field.get(BuiltInRegistries.BLOCK) == null) {
|
|
||||||
field.set(BuiltInRegistries.BLOCK, new IdentityHashMap<>());
|
|
||||||
field = MappedRegistry.class.getDeclaredField("frozen");
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.setBoolean(BuiltInRegistries.BLOCK, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterAll(ExtensionContext context) throws Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'dev.architectury.loom'
|
|
||||||
}
|
|
||||||
|
|
||||||
loom {
|
|
||||||
accessWidenerPath = project(":common").loom.accessWidenerPath
|
|
||||||
runs {
|
|
||||||
client {
|
|
||||||
vmArgs "-Xmx8G"
|
|
||||||
property("modernfix.config.mixin.perf.blast_search_trees", "true")
|
|
||||||
property("modernfix.config.mixin.perf.dynamic_resources", "true")
|
|
||||||
property("modernfix.config.mixin.perf.dynamic_block_codecs", "true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
|
||||||
mappings loom.layered() {
|
|
||||||
officialMojangMappings()
|
|
||||||
}
|
|
||||||
|
|
||||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
|
||||||
modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modImplementation(fabricApi.module("fabric-models-v0", "0.84.0+1.20.1")) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modImplementation(fabricApi.module("fabric-registry-sync-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modImplementation(fabricApi.module("fabric-renderer-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
modRuntimeOnly(fabricApi.module("fabric-renderer-indigo", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
|
||||||
|
|
||||||
implementation project(path: ":common", configuration: "namedElements")
|
|
||||||
implementation project(path: ":fabric", configuration: "namedElements")
|
|
||||||
}
|
|
||||||
|
|
||||||
processResources {
|
|
||||||
inputs.property "version", project.version
|
|
||||||
|
|
||||||
filesMatching("fabric.mod.json") {
|
|
||||||
expand "version": project.version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make genSources do nothing in this project
|
|
||||||
project.gradle.startParameter.excludedTaskNames.add("genSources")
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
||||||
|
|
||||||
public class TestBlock extends Block {
|
|
||||||
private static final BlockBehaviour.Properties PROPERTIES = BlockBehaviour.Properties.copy(Blocks.STONE);
|
|
||||||
|
|
||||||
public TestBlock() {
|
|
||||||
super(PROPERTIES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod;
|
|
||||||
|
|
||||||
import net.minecraft.world.item.BlockItem;
|
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
|
|
||||||
public class TestBlockItem extends BlockItem {
|
|
||||||
private static final Item.Properties PROPERTIES = new Item.Properties();
|
|
||||||
|
|
||||||
public TestBlockItem(TestBlock block) {
|
|
||||||
super(block, PROPERTIES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod;
|
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class TestMod implements ModInitializer {
|
|
||||||
public static final String ID = "mfix_testmod";
|
|
||||||
public static final Logger LOGGER = LogManager.getLogger("ModernFix TestMod");
|
|
||||||
|
|
||||||
public static final int NUM_COLORS = 32;
|
|
||||||
public static final int MAX_COLOR = NUM_COLORS - 1;
|
|
||||||
|
|
||||||
public static final List<BlockState> WOOL_STATES = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInitialize() {
|
|
||||||
// Register 1 million blocks & items
|
|
||||||
Stopwatch watch = Stopwatch.createStarted();
|
|
||||||
int totalToRegister = NUM_COLORS * NUM_COLORS * NUM_COLORS;
|
|
||||||
int progressReport = totalToRegister / 20;
|
|
||||||
int numRegistered = 0;
|
|
||||||
for(int r = 0; r < NUM_COLORS; r++) {
|
|
||||||
for(int g = 0; g < NUM_COLORS; g++) {
|
|
||||||
for(int b = 0; b < NUM_COLORS; b++) {
|
|
||||||
ResourceLocation name = new ResourceLocation(ID, "wool_" + r + "_" + g + "_" + b);
|
|
||||||
TestBlock block = Registry.register(BuiltInRegistries.BLOCK, name, new TestBlock());
|
|
||||||
WOOL_STATES.add(block.defaultBlockState());
|
|
||||||
//Registry.register(BuiltInRegistries.ITEM, name, new TestBlockItem(block));
|
|
||||||
numRegistered++;
|
|
||||||
if((numRegistered % progressReport) == 0) {
|
|
||||||
LOGGER.info(String.format("Registering... %.02f%%", ((float)numRegistered)/totalToRegister * 100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
watch.stop();
|
|
||||||
LOGGER.info("Registered {} registry entries in {}", totalToRegister, watch);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final BlockState AIR = Blocks.AIR.defaultBlockState();
|
|
||||||
|
|
||||||
public static BlockState getColorCubeStateFor(int chunkX, int chunkY, int chunkZ) {
|
|
||||||
BlockState blockState = null;
|
|
||||||
if (chunkX >= 0 && chunkY >= 0 && chunkZ >= 0) { // && chunkX % 2 == 0 && chunkY % 2 == 0 && chunkZ % 2 == 0) {
|
|
||||||
/*
|
|
||||||
chunkX /= 2;
|
|
||||||
chunkY /= 2;
|
|
||||||
chunkZ /= 2;
|
|
||||||
|
|
||||||
*/
|
|
||||||
if(chunkX <= TestMod.MAX_COLOR && chunkY <= TestMod.MAX_COLOR && chunkZ <= TestMod.MAX_COLOR) {
|
|
||||||
blockState = TestMod.WOOL_STATES.get((chunkX * TestMod.NUM_COLORS * TestMod.NUM_COLORS) + (chunkY * TestMod.NUM_COLORS) + chunkZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return blockState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod.client;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemOverrides;
|
|
||||||
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
||||||
import net.minecraft.client.resources.model.*;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.util.RandomSource;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import org.embeddedt.modernfix.testmod.TestMod;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class TestModBlockModel implements UnbakedModel, BakedModel, FabricBakedModel {
|
|
||||||
private static final Material BASE_WOOL = new Material(TextureAtlas.LOCATION_BLOCKS, new ResourceLocation(TestMod.ID, "block/base_wool"));
|
|
||||||
|
|
||||||
private Mesh mesh;
|
|
||||||
private TextureAtlasSprite texture;
|
|
||||||
|
|
||||||
private final int r, g, b;
|
|
||||||
|
|
||||||
public TestModBlockModel(int r, int g, int b) {
|
|
||||||
this.r = r;
|
|
||||||
this.g = g;
|
|
||||||
this.b = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isVanillaAdapter() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
|
|
||||||
context.meshConsumer().accept(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void emitItemQuads(ItemStack stack, Supplier<RandomSource> randomSupplier, RenderContext context) {
|
|
||||||
context.meshConsumer().accept(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean useAmbientOcclusion() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGui3d() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean usesBlockLight() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCustomRenderer() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TextureAtlasSprite getParticleIcon() {
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemTransforms getTransforms() {
|
|
||||||
return ModelHelper.MODEL_TRANSFORM_BLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemOverrides getOverrides() {
|
|
||||||
return ItemOverrides.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<ResourceLocation> getDependencies() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resolveParents(Function<ResourceLocation, UnbakedModel> function) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int scaleColor(int c) {
|
|
||||||
return c * 255 / TestMod.MAX_COLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BakedModel bake(ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState state, ResourceLocation location) {
|
|
||||||
// Build the mesh using the Renderer API
|
|
||||||
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
|
|
||||||
MeshBuilder builder = renderer.meshBuilder();
|
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
|
||||||
|
|
||||||
texture = spriteGetter.apply(BASE_WOOL);
|
|
||||||
|
|
||||||
for(Direction direction : Direction.values()) {
|
|
||||||
// Add a new face to the mesh
|
|
||||||
emitter.square(direction, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
|
|
||||||
// Set the sprite of the face, must be called after .square()
|
|
||||||
// We haven't specified any UV coordinates, so we want to use the whole texture. BAKE_LOCK_UV does exactly that.
|
|
||||||
emitter.spriteBake(0, texture, MutableQuadView.BAKE_LOCK_UV);
|
|
||||||
int color = (255 << 24) | (scaleColor(r) << 16) | (scaleColor(g) << 8) | scaleColor(b);
|
|
||||||
// Enable texture usage
|
|
||||||
emitter.spriteColor(0, color, color, color, color);
|
|
||||||
// Add the quad to the mesh
|
|
||||||
emitter.emit();
|
|
||||||
}
|
|
||||||
mesh = builder.build();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod.client;
|
|
||||||
|
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
|
||||||
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
|
|
||||||
import org.embeddedt.modernfix.fabric.api.dynresources.ModelScanController;
|
|
||||||
import org.embeddedt.modernfix.testmod.TestMod;
|
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class TestModClient implements ClientModInitializer {
|
|
||||||
private static final Pattern RGB_PATTERN = Pattern.compile("^wool_([0-9]+)_([0-9]+)_([0-9]+)$");
|
|
||||||
@Override
|
|
||||||
public void onInitializeClient() {
|
|
||||||
ModelScanController.SCAN_PREDICATES.add(rl -> !rl.getNamespace().equals(TestMod.ID));
|
|
||||||
ModelLoadingRegistry.INSTANCE.registerVariantProvider(resourceManager -> (modelId, context) -> {
|
|
||||||
if(modelId.getNamespace().equals(TestMod.ID)) {
|
|
||||||
Matcher matcher = RGB_PATTERN.matcher(modelId.getPath());
|
|
||||||
if(matcher.matches()) {
|
|
||||||
int r = Integer.parseInt(matcher.group(1));
|
|
||||||
int g = Integer.parseInt(matcher.group(2));
|
|
||||||
int b = Integer.parseInt(matcher.group(3));
|
|
||||||
return new TestModBlockModel(r, g, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
|
||||||
import org.embeddedt.modernfix.testmod.TestMod;
|
|
||||||
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.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(LevelChunk.class)
|
|
||||||
public class ChunkMixin {
|
|
||||||
@Inject(method = "getBlockState", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void redirectDebugWorld(BlockPos pos, CallbackInfoReturnable<BlockState> cir) {
|
|
||||||
BlockState overrideState = TestMod.getColorCubeStateFor(pos.getX(), pos.getY(), pos.getZ());
|
|
||||||
if(overrideState != null) {
|
|
||||||
cir.setReturnValue(overrideState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.SectionPos;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
|
||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
|
||||||
import org.embeddedt.modernfix.testmod.TestMod;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
|
|
||||||
@Mixin(FlatLevelSource.class)
|
|
||||||
public abstract class DebugLevelSourceMixin extends ChunkGenerator {
|
|
||||||
public DebugLevelSourceMixin(BiomeSource biomeSource) {
|
|
||||||
super(biomeSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyBiomeDecoration(WorldGenLevel level, ChunkAccess chunk, StructureManager structureFeatureManager) {
|
|
||||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
||||||
ChunkPos chunkPos = chunk.getPos();
|
|
||||||
int i = chunkPos.x;
|
|
||||||
int j = chunkPos.z;
|
|
||||||
|
|
||||||
for(int k = 0; k < 16; ++k) {
|
|
||||||
for(int l = 0; l < 16; ++l) {
|
|
||||||
int m = SectionPos.sectionToBlockCoord(i, k);
|
|
||||||
int n = SectionPos.sectionToBlockCoord(j, l);
|
|
||||||
for(int y = 0; y < 255; y++) {
|
|
||||||
BlockState blockState = TestMod.getColorCubeStateFor(m, y, n);
|
|
||||||
if (blockState != null) {
|
|
||||||
level.setBlock(mutableBlockPos.set(m, y, n), blockState, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testmod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import org.embeddedt.modernfix.testmod.TestMod;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(targets = { "net/minecraft/client/renderer/chunk/RenderChunk" })
|
|
||||||
public class RenderChunkMixin {
|
|
||||||
@Shadow @Final private boolean debug;
|
|
||||||
|
|
||||||
@Inject(method = "getBlockState", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void redirectDebugWorld(BlockPos pos, CallbackInfoReturnable<BlockState> cir) {
|
|
||||||
if(this.debug) {
|
|
||||||
cir.setReturnValue(TestMod.getColorCubeStateFor(pos.getX(), pos.getY(), pos.getZ()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 560 B |
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"schemaVersion": 1,
|
|
||||||
"id": "mfix_testmod",
|
|
||||||
"version": "${version}",
|
|
||||||
"name": "ModernFix test mod",
|
|
||||||
"description": "Test mod used to validate features and behaviors of ModernFix, the essential Minecraft performance mod",
|
|
||||||
"authors": [
|
|
||||||
"embeddedt"
|
|
||||||
],
|
|
||||||
"contact": {
|
|
||||||
"sources": "https://github.com/embeddedt/ModernFix",
|
|
||||||
"homepage": "https://modrinth.com/mod/modernfix",
|
|
||||||
"issues": "https://github.com/embeddedt/ModernFix/issues"
|
|
||||||
},
|
|
||||||
"license": "LGPL-3.0",
|
|
||||||
"environment": "*",
|
|
||||||
"mixins": [ "testmod.mixins.json" ],
|
|
||||||
"entrypoints": {
|
|
||||||
"main": [
|
|
||||||
"org.embeddedt.modernfix.testmod.TestMod"
|
|
||||||
],
|
|
||||||
"client": [
|
|
||||||
"org.embeddedt.modernfix.testmod.client.TestModClient"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"pack": {
|
|
||||||
"description": "testmod resources",
|
|
||||||
"pack_format": 6,
|
|
||||||
"_comment": "A pack_format of 6 requires json lang files and some texture changes from 1.16.2. Note: we require v6 pack meta for all mods."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"required": true,
|
|
||||||
"package": "org.embeddedt.modernfix.testmod.mixin",
|
|
||||||
"compatibilityLevel": "JAVA_8",
|
|
||||||
"minVersion": "0.8",
|
|
||||||
"mixins": [
|
|
||||||
"ChunkMixin",
|
|
||||||
"DebugLevelSourceMixin"
|
|
||||||
],
|
|
||||||
"client": [
|
|
||||||
"RenderChunkMixin"
|
|
||||||
],
|
|
||||||
"injectors": {
|
|
||||||
"defaultRequire": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,7 +6,7 @@ mixinextras_version=0.4.1
|
||||||
|
|
||||||
mod_id=modernfix
|
mod_id=modernfix
|
||||||
minecraft_version=1.20.1
|
minecraft_version=1.20.1
|
||||||
enabled_platforms=fabric,forge
|
enabled_platforms=forge
|
||||||
forge_version=1.20.1-47.4.0
|
forge_version=1.20.1-47.4.0
|
||||||
parchment_version=2023.07.09
|
parchment_version=2023.07.09
|
||||||
refined_storage_version=4392788
|
refined_storage_version=4392788
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import re
|
||||||
def get_valid_mixin_options():
|
def get_valid_mixin_options():
|
||||||
all_mixin_options = set()
|
all_mixin_options = set()
|
||||||
# gather all mixins in mixin folders
|
# gather all mixins in mixin folders
|
||||||
for platform in [ "common", "fabric", "forge" ]:
|
for platform in [ "common", "forge" ]:
|
||||||
base_path = f"{platform}/src/main/java/org/embeddedt/modernfix/{platform}/mixin"
|
base_path = f"{platform}/src/main/java/org/embeddedt/modernfix/{platform}/mixin"
|
||||||
for root, dirs, files in os.walk(base_path):
|
for root, dirs, files in os.walk(base_path):
|
||||||
for file in files:
|
for file in files:
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
plugins {
|
|
||||||
//id 'com.github.johnrengelman.shadow' version '7.1.2'
|
|
||||||
id 'java'
|
|
||||||
id 'modernfix.common-conventions'
|
|
||||||
}
|
|
||||||
|
|
||||||
group 'org.embeddedt'
|
|
||||||
archivesBaseName = 'modernfix-test-agent'
|
|
||||||
version '1.0'
|
|
||||||
|
|
||||||
sourceCompatibility = '1.8'
|
|
||||||
targetCompatibility = '1.8'
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
mavenLocal()
|
|
||||||
maven {
|
|
||||||
name = 'forge'
|
|
||||||
url = 'https://maven.minecraftforge.net/'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
shadowJar {
|
|
||||||
relocate 'net.bytebuddy.agent', 'org.embeddedt.modernfix.testing.shadow.bytebuddyagent'
|
|
||||||
relocate 'org.objectweb.asm', 'org.embeddedt.modernfix.testing.shadow.asm'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
shadowJar {
|
|
||||||
project.configurations.implementation.canBeResolved = true
|
|
||||||
configurations = [project.configurations.implementation]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
dependencies {
|
|
||||||
compileOnly "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
|
||||||
implementation "org.ow2.asm:asm-tree:9.1"
|
|
||||||
implementation "org.ow2.asm:asm-commons:9.1"
|
|
||||||
implementation "org.ow2.asm:asm-util:9.1"
|
|
||||||
|
|
||||||
//implementation('net.bytebuddy:byte-buddy-agent:1.12.22')
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
|
||||||
// this fixes some edge cases with special characters not displaying correctly
|
|
||||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
|
||||||
// If Javadoc is generated, this must be specified in that task too.
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
|
||||||
manifest {
|
|
||||||
attributes(
|
|
||||||
"Premain-Class": "org.embeddedt.modernfix.testing.Agent",
|
|
||||||
"Can-Redefine-Classes": false,
|
|
||||||
"Can-Set-Native-Method-Prefix": false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
|
|
||||||
shadowJar {
|
|
||||||
archiveBaseName.set('modernfix-test-agent')
|
|
||||||
archiveClassifier.set('')
|
|
||||||
archiveVersion.set('v1')
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
agentJar {
|
|
||||||
canBeConsumed = true
|
|
||||||
canBeResolved = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
agentJar(jar)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
project.tasks.shadowJar.dependsOn build
|
|
||||||
defaultTasks 'shadowJar'
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testing;
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassReader;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
|
||||||
import java.lang.instrument.IllegalClassFormatException;
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
import java.security.ProtectionDomain;
|
|
||||||
import java.util.ListIterator;
|
|
||||||
|
|
||||||
public class Agent {
|
|
||||||
/**
|
|
||||||
* Simple agent that transforms Fabric Loader to never mark game JARs as system libraries.
|
|
||||||
*
|
|
||||||
* Ugly, but usable workaround for <a href="https://github.com/FabricMC/fabric-loader/issues/817">issue #817</a>
|
|
||||||
* on the Loader bug tracker.
|
|
||||||
*/
|
|
||||||
public static void premain(String args, Instrumentation instrumentation) {
|
|
||||||
instrumentation.addTransformer(new ClassFileTransformer() {
|
|
||||||
@Override
|
|
||||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
|
|
||||||
if(className.equals("net/fabricmc/loader/impl/game/LibClassifier")) {
|
|
||||||
ClassNode node = new ClassNode();
|
|
||||||
ClassReader reader = new ClassReader(classfileBuffer);
|
|
||||||
reader.accept(node, 0);
|
|
||||||
for(MethodNode m : node.methods) {
|
|
||||||
if(m.name.equals("<init>")) {
|
|
||||||
ListIterator<AbstractInsnNode> iter = m.instructions.iterator();
|
|
||||||
int addMatches = 0;
|
|
||||||
while(iter.hasNext()) {
|
|
||||||
AbstractInsnNode n = iter.next();
|
|
||||||
if(n instanceof MethodInsnNode) {
|
|
||||||
MethodInsnNode invokeNode = (MethodInsnNode)n;
|
|
||||||
if(invokeNode.name.equals("add") && invokeNode.owner.equals("java/util/Set") && invokeNode.desc.equals("(Ljava/lang/Object;)Z")) {
|
|
||||||
addMatches++;
|
|
||||||
if(addMatches == 2) {
|
|
||||||
iter.set(new MethodInsnNode(Opcodes.INVOKESTATIC, "org/embeddedt/modernfix/testing/AgentHooks", "addLibraryWithCheck", "(Ljava/util/Set;Ljava/lang/Object;)Z", false));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
|
||||||
node.accept(writer);
|
|
||||||
byte[] finalArray = writer.toByteArray();
|
|
||||||
//dumpDebugClass(className, finalArray);
|
|
||||||
return finalArray;
|
|
||||||
}
|
|
||||||
return classfileBuffer;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package org.embeddedt.modernfix.testing;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class AgentHooks {
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes" })
|
|
||||||
public static boolean addLibraryWithCheck(Set pathSet, Object path) {
|
|
||||||
boolean shouldAdd;
|
|
||||||
if(path instanceof Path) {
|
|
||||||
shouldAdd = !((Path)path).toString().contains("minecraft-merged");
|
|
||||||
} else
|
|
||||||
shouldAdd = true;
|
|
||||||
return shouldAdd && pathSet.add(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user