Merge remote-tracking branch 'origin/1.19.2' into 1.19.4
This commit is contained in:
commit
9c421218b8
1
.github/workflows/gradle.yml
vendored
1
.github/workflows/gradle.yml
vendored
|
|
@ -16,6 +16,7 @@ jobs:
|
|||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
cache: 'gradle'
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
- name: Build the mod
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.embeddedt.modernfix.command.ModernFixCommands;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
import org.embeddedt.modernfix.resources.ReloadExecutor;
|
||||
import org.embeddedt.modernfix.util.ClassInfoManager;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
// The value here should match an entry in the META-INF/mods.toml file
|
||||
public class ModernFix {
|
||||
|
|
@ -31,12 +32,7 @@ public class ModernFix {
|
|||
|
||||
static {
|
||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.dedicated_reload_executor.ReloadExecutor")) {
|
||||
try {
|
||||
resourceReloadService = Util.makeExecutor("ResourceReload");
|
||||
} catch(Throwable e) {
|
||||
LOGGER.error("Error creating resource reload service, using fallback", e);
|
||||
resourceReloadService = Util.backgroundExecutor();
|
||||
}
|
||||
resourceReloadService = ReloadExecutor.createCustomResourceReloadExecutor();
|
||||
} else {
|
||||
resourceReloadService = Util.backgroundExecutor();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,6 +174,8 @@ public class ModernFixClient {
|
|||
}
|
||||
|
||||
public void onServerStarted(MinecraftServer server) {
|
||||
if(!ModernFixMixinPlugin.instance.isOptionEnabled("feature.integrated_server_watchdog.IntegratedWatchdog"))
|
||||
return;
|
||||
IntegratedWatchdog watchdog = new IntegratedWatchdog(server);
|
||||
watchdog.start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public abstract class ServerChunkCacheMixin {
|
|||
|
||||
@Inject(method = "getChunk", at = @At("HEAD"), cancellable = true)
|
||||
private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable<ChunkAccess> cir) {
|
||||
if(!this.mainThread.isAlive()) {
|
||||
if(!this.level.getServer().isRunning() && !this.mainThread.isAlive()) {
|
||||
ModernFix.LOGGER.fatal("A mod is accessing chunks from a stopped server (this will also cause memory leaks)");
|
||||
if(debugDeadServerAccess) {
|
||||
new Exception().printStackTrace();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering;
|
||||
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import org.embeddedt.modernfix.render.RenderState;
|
||||
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(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(FJLcom/mojang/blaze3d/vertex/PoseStack;)V", shift = At.Shift.BEFORE))
|
||||
private void markRenderingLevel(CallbackInfo ci) {
|
||||
RenderState.IS_RENDERING_LEVEL = true;
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(FJLcom/mojang/blaze3d/vertex/PoseStack;)V", shift = At.Shift.AFTER))
|
||||
private void markNotRenderingLevel(CallbackInfo ci) {
|
||||
RenderState.IS_RENDERING_LEVEL = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,10 @@ import net.minecraft.client.resources.model.SimpleBakedModel;
|
|||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.embeddedt.modernfix.render.FastItemRenderType;
|
||||
import org.embeddedt.modernfix.render.RenderState;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
|
@ -38,6 +41,17 @@ public abstract class ItemRendererMixin {
|
|||
this.transformType = transformType;
|
||||
}
|
||||
|
||||
private static final Direction[] ITEM_DIRECTIONS = new Direction[] { Direction.SOUTH };
|
||||
private static final Direction[] BLOCK_DIRECTIONS = new Direction[] { Direction.UP, Direction.EAST, Direction.NORTH };
|
||||
|
||||
private boolean isCorrectDirectionForType(FastItemRenderType type, Direction direction) {
|
||||
if(type == FastItemRenderType.SIMPLE_ITEM)
|
||||
return direction == Direction.SOUTH;
|
||||
else {
|
||||
return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a model
|
||||
* - is a vanilla item model (SimpleBakedModel),
|
||||
|
|
@ -48,25 +62,42 @@ public abstract class ItemRendererMixin {
|
|||
*/
|
||||
@Inject(method = "renderModelLists", at = @At("HEAD"), cancellable = true)
|
||||
private void fasterItemRender(BakedModel model, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer, CallbackInfo ci) {
|
||||
if(!stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemDisplayContext.GUI && model.getTransforms().gui == ItemTransform.NO_TRANSFORM) {
|
||||
if(!RenderState.IS_RENDERING_LEVEL && !stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemDisplayContext.GUI) {
|
||||
FastItemRenderType type;
|
||||
ItemTransform transform = model.getTransforms().gui;
|
||||
if(transform == ItemTransform.NO_TRANSFORM)
|
||||
type = FastItemRenderType.SIMPLE_ITEM;
|
||||
else if(stack.getItem() instanceof BlockItem && isBlockTransforms(transform))
|
||||
type = FastItemRenderType.SIMPLE_BLOCK;
|
||||
else
|
||||
return;
|
||||
ci.cancel();
|
||||
PoseStack.Pose pose = matrixStack.last();
|
||||
int[] combinedLights = new int[] {combinedLight, combinedLight, combinedLight, combinedLight};
|
||||
List<BakedQuad> culledFaces = model.getQuads(null, Direction.SOUTH, dummyRandom);
|
||||
List<BakedQuad> unculledFaces = model.getQuads(null, null, dummyRandom);
|
||||
/* check size to avoid instantiating iterator when the list is empty */
|
||||
if(culledFaces.size() > 0) {
|
||||
for(BakedQuad quad : culledFaces) {
|
||||
render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay);
|
||||
Direction[] directions = type == FastItemRenderType.SIMPLE_ITEM ? ITEM_DIRECTIONS : BLOCK_DIRECTIONS;
|
||||
for(Direction direction : directions) {
|
||||
List<BakedQuad> culledFaces = model.getQuads(null, direction, dummyRandom);
|
||||
/* check size to avoid instantiating iterator when the list is empty */
|
||||
if(culledFaces.size() > 0) {
|
||||
for(BakedQuad quad : culledFaces) {
|
||||
render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<BakedQuad> unculledFaces = model.getQuads(null, null, dummyRandom);
|
||||
for(BakedQuad quad : unculledFaces) {
|
||||
if(quad.getDirection() == Direction.SOUTH)
|
||||
if(isCorrectDirectionForType(type, quad.getDirection()))
|
||||
render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBlockTransforms(ItemTransform transform) {
|
||||
return transform.rotation.x() == 30f
|
||||
&& transform.rotation.y() == 225f
|
||||
&& transform.rotation.z() == 0f;
|
||||
}
|
||||
|
||||
private void render2dItemFace(BakedQuad quad, ItemStack stack, VertexConsumer buffer, PoseStack.Pose pose, int[] combinedLights, int combinedOverlay) {
|
||||
int i = -1;
|
||||
if (quad.isTinted()) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.resourcepacks;
|
||||
|
||||
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.resources.PackResourcesCacheEngine;
|
||||
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(ReloadableResourceManager.class)
|
||||
public class ReloadableResourceManagerMixin {
|
||||
@Inject(method = "createReload", at = @At("HEAD"))
|
||||
private void invalidateResourceCaches(CallbackInfoReturnable<?> cir) {
|
||||
ModernFix.LOGGER.info("Invalidating pack caches");
|
||||
PackResourcesCacheEngine.invalidate();
|
||||
}
|
||||
}
|
||||
|
|
@ -139,15 +139,15 @@ public class ModernFixEarlyConfig {
|
|||
|
||||
private static final ImmutableMap<String, Boolean> DEFAULT_SETTING_OVERRIDES = ImmutableMap.<String, Boolean>builder()
|
||||
.put("mixin.perf.dynamic_resources", false)
|
||||
.put("mixin.feature.reduce_loading_screen_freezes", false)
|
||||
.put("mixin.feature.direct_stack_trace", false)
|
||||
.put("mixin.perf.rewrite_registry", false)
|
||||
.put("mixin.perf.clear_mixin_classinfo", false)
|
||||
.put("mixin.perf.compress_blockstate", false)
|
||||
.put("mixin.bugfix.packet_leak", false)
|
||||
.put("mixin.perf.deduplicate_location", false)
|
||||
.put("mixin.perf.preload_block_classes", false)
|
||||
.put("mixin.perf.faster_singleplayer_load", false)
|
||||
.put("mixin.perf.dynamic_entity_renderers", false)
|
||||
.put("mixin.feature.integrated_server_watchdog", true)
|
||||
.put("mixin.perf.faster_item_rendering", false)
|
||||
.put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees)
|
||||
.put("mixin.devenv", isDevEnv)
|
||||
.put("mixin.perf.remove_spawn_chunks", isDevEnv)
|
||||
|
|
@ -185,8 +185,12 @@ public class ModernFixEarlyConfig {
|
|||
disableIfModPresent("mixin.perf.async_jei", "modernui");
|
||||
disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge");
|
||||
disableIfModPresent("mixin.bugfix.mc218112", "performant");
|
||||
disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant");
|
||||
disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me");
|
||||
disableIfModPresent("mixin.perf.reuse_datapacks", "tac");
|
||||
disableIfModPresent("mixin.launch.class_search_cache", "optifine");
|
||||
disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide");
|
||||
disableIfModPresent("mixin.perf.faster_texture_loading", "stitch");
|
||||
}
|
||||
|
||||
private void disableIfModPresent(String configName, String... ids) {
|
||||
|
|
@ -195,8 +199,6 @@ public class ModernFixEarlyConfig {
|
|||
Option option = this.options.get(configName);
|
||||
if(option != null)
|
||||
option.addModOverride(false, id);
|
||||
else
|
||||
LOGGER.warn("Can't disable missing option {}", configName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ public class ModelBakeryHelpers {
|
|||
}
|
||||
}
|
||||
}
|
||||
// check if there is only one possible state
|
||||
if(fixedProperties.size() == stateDefinition.getProperties().size()) {
|
||||
return ImmutableList.of(fixedState);
|
||||
}
|
||||
// generate all possible blockstates from the remaining properties
|
||||
ArrayList<Property<?>> anyProperties = new ArrayList<>(stateDefinition.getProperties());
|
||||
anyProperties.removeAll(fixedProperties);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package org.embeddedt.modernfix.render;
|
||||
|
||||
public enum FastItemRenderType {
|
||||
SIMPLE_ITEM,
|
||||
SIMPLE_BLOCK
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.embeddedt.modernfix.render;
|
||||
|
||||
public class RenderState {
|
||||
public static boolean IS_RENDERING_LEVEL = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.embeddedt.modernfix.resources;
|
||||
|
||||
public interface ICachingResourcePack {
|
||||
void invalidateCache();
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
package org.embeddedt.modernfix.resources;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.util.PackTypeHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -14,6 +17,7 @@ import java.util.*;
|
|||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
|
|
@ -26,6 +30,9 @@ public class PackResourcesCacheEngine {
|
|||
private final Map<PackType, Set<String>> namespacesByType;
|
||||
private final Set<CachedResourcePath> containedPaths;
|
||||
private final EnumMap<PackType, Map<String, List<CachedResourcePath>>> resourceListings;
|
||||
private volatile boolean cacheGenerationFlag = false;
|
||||
private List<Runnable> cacheGenerationTasks = new ArrayList<>();
|
||||
private Path debugPath;
|
||||
|
||||
public PackResourcesCacheEngine(Function<PackType, Set<String>> namespacesRetriever, BiFunction<PackType, String, Path> basePathRetriever) {
|
||||
this.namespacesByType = new EnumMap<>(PackType.class);
|
||||
|
|
@ -36,32 +43,44 @@ public class PackResourcesCacheEngine {
|
|||
}
|
||||
this.containedPaths = new ObjectOpenHashSet<>();
|
||||
this.resourceListings = new EnumMap<>(PackType.class);
|
||||
// used for log message
|
||||
this.debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath();
|
||||
for(PackType type : PackType.values()) {
|
||||
Collection<String> namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type);
|
||||
ImmutableMap.Builder<String, List<CachedResourcePath>> packTypedMap = ImmutableMap.builder();
|
||||
for(String namespace : namespaces) {
|
||||
try {
|
||||
ImmutableList.Builder<CachedResourcePath> namespacedList = ImmutableList.builder();
|
||||
Path root = basePathRetriever.apply(type, namespace).toAbsolutePath();
|
||||
String[] prefix = new String[] { type.getDirectory(), namespace };
|
||||
try (Stream<Path> stream = Files.walk(root)) {
|
||||
stream
|
||||
.map(path -> root.relativize(path.toAbsolutePath()))
|
||||
.filter(PackResourcesCacheEngine::isValidCachedResourcePath)
|
||||
.forEach(path -> {
|
||||
CachedResourcePath cachedPath = new CachedResourcePath(prefix, path);
|
||||
this.containedPaths.add(cachedPath);
|
||||
if(!cachedPath.getFileName().endsWith(".mcmeta"))
|
||||
namespacedList.add(cachedPath);
|
||||
});
|
||||
Collection<Pair<String, Path>> namespacedRoots = namespaces.stream().map(s -> Pair.of(s, basePathRetriever.apply(type, s).toAbsolutePath())).collect(Collectors.toList());
|
||||
cacheGenerationTasks.add(() -> {
|
||||
ImmutableMap.Builder<String, List<CachedResourcePath>> packTypedMap = ImmutableMap.builder();
|
||||
for(Pair<String, Path> pair : namespacedRoots) {
|
||||
try {
|
||||
ImmutableList.Builder<CachedResourcePath> namespacedList = ImmutableList.builder();
|
||||
String namespace = pair.getFirst();
|
||||
Path root = pair.getSecond();
|
||||
String[] prefix = new String[] { type.getDirectory(), namespace };
|
||||
try (Stream<Path> stream = Files.walk(root)) {
|
||||
stream
|
||||
.map(path -> root.relativize(path.toAbsolutePath()))
|
||||
.filter(PackResourcesCacheEngine::isValidCachedResourcePath)
|
||||
.forEach(path -> {
|
||||
CachedResourcePath cachedPath = new CachedResourcePath(prefix, path);
|
||||
synchronized (this.containedPaths) {
|
||||
this.containedPaths.add(cachedPath);
|
||||
}
|
||||
if(!cachedPath.getFileName().endsWith(".mcmeta"))
|
||||
namespacedList.add(cachedPath);
|
||||
});
|
||||
}
|
||||
packTypedMap.put(namespace, namespacedList.build());
|
||||
} catch(IOException ignored) {
|
||||
}
|
||||
packTypedMap.put(namespace, namespacedList.build());
|
||||
} catch(IOException ignored) {
|
||||
}
|
||||
}
|
||||
this.resourceListings.put(type, packTypedMap.build());
|
||||
synchronized (this.resourceListings) {
|
||||
this.resourceListings.put(type, packTypedMap.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
((ObjectOpenHashSet<CachedResourcePath>)this.containedPaths).trim();
|
||||
cacheGenerationTasks.add(() -> {
|
||||
((ObjectOpenHashSet<CachedResourcePath>)this.containedPaths).trim();
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isValidCachedResourcePath(Path path) {
|
||||
|
|
@ -86,13 +105,37 @@ public class PackResourcesCacheEngine {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void doGenerateCache() {
|
||||
Stopwatch watch = Stopwatch.createStarted();
|
||||
for(Runnable r : this.cacheGenerationTasks) {
|
||||
r.run();
|
||||
}
|
||||
watch.stop();
|
||||
ModernFix.LOGGER.debug("Generated cache for {} in {}", debugPath, watch);
|
||||
debugPath = null;
|
||||
cacheGenerationTasks = ImmutableList.of();
|
||||
}
|
||||
|
||||
private void awaitLoad() {
|
||||
if(!this.cacheGenerationFlag) {
|
||||
synchronized (this) {
|
||||
if(!this.cacheGenerationFlag) {
|
||||
this.doGenerateCache();
|
||||
this.cacheGenerationFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasResource(String path) {
|
||||
awaitLoad();
|
||||
return this.containedPaths.contains(new CachedResourcePath(path));
|
||||
}
|
||||
|
||||
public Collection<ResourceLocation> getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate<ResourceLocation> filter) {
|
||||
if(!PackTypeHelper.isVanillaPackType(type))
|
||||
throw new IllegalArgumentException("Only vanilla PackTypes are supported");
|
||||
awaitLoad();
|
||||
List<CachedResourcePath> paths = resourceListings.get(type).getOrDefault(resourceNamespace, Collections.emptyList());
|
||||
if(paths.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
|
@ -111,4 +154,20 @@ public class PackResourcesCacheEngine {
|
|||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
private static final WeakHashMap<ICachingResourcePack, Boolean> cachingPacks = new WeakHashMap<>();
|
||||
public static void track(ICachingResourcePack pack) {
|
||||
synchronized (cachingPacks) {
|
||||
cachingPacks.put(pack, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void invalidate() {
|
||||
synchronized (cachingPacks) {
|
||||
cachingPacks.keySet().forEach(pack -> {
|
||||
if(pack != null)
|
||||
pack.invalidateCache();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package org.embeddedt.modernfix.resources;
|
||||
|
||||
import net.minecraft.ReportedException;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinWorkerThread;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ReloadExecutor {
|
||||
public static ExecutorService createCustomResourceReloadExecutor() {
|
||||
ClassLoader loader = ReloadExecutor.class.getClassLoader();
|
||||
AtomicInteger workerCount = new AtomicInteger(0);
|
||||
return new ForkJoinPool(ForkJoinPool.getCommonPoolParallelism(), (forkJoinPool) -> {
|
||||
ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(forkJoinPool) {
|
||||
protected void onTermination(Throwable throwOnTermination) {
|
||||
if (throwOnTermination != null) {
|
||||
ModernFix.LOGGER.warn("{} died", this.getName(), throwOnTermination);
|
||||
} else {
|
||||
ModernFix.LOGGER.debug("{} shutdown", this.getName());
|
||||
}
|
||||
|
||||
super.onTermination(throwOnTermination);
|
||||
}
|
||||
};
|
||||
// needed to prevent weirdness on some systems
|
||||
forkJoinWorkerThread.setContextClassLoader(loader);
|
||||
forkJoinWorkerThread.setName("Worker-ResourceReload-" + workerCount.getAndIncrement());
|
||||
return forkJoinWorkerThread;
|
||||
}, ReloadExecutor::handleException, true);
|
||||
}
|
||||
|
||||
private static void handleException(Thread thread, Throwable throwable) {
|
||||
if (throwable instanceof CompletionException) {
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
|
||||
if (throwable instanceof ReportedException) {
|
||||
Bootstrap.realStdoutPrintln(((ReportedException)throwable).getReport().getFriendlyReport());
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
ModernFix.LOGGER.error(String.format("Caught exception in thread %s", thread), throwable);
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,12 @@ public class CachingStructureManager {
|
|||
|
||||
private static final Set<String> laggyStructureMods = new ObjectOpenHashSet<>();
|
||||
|
||||
private static final int MAX_HASH_LENGTH = 9;
|
||||
|
||||
private static String truncateHash(String hash) {
|
||||
return hash.substring(0, MAX_HASH_LENGTH + 1);
|
||||
}
|
||||
|
||||
public static CompoundTag readStructureTag(ResourceLocation location, DataFixer datafixer, InputStream stream) throws IOException {
|
||||
byte[] structureBytes = toBytes(stream);
|
||||
CompoundTag currentTag = NbtIo.readCompressed(new ByteArrayInputStream(structureBytes));
|
||||
|
|
@ -58,20 +64,22 @@ public class CachingStructureManager {
|
|||
}
|
||||
int currentDataVersion = currentTag.getInt("DataVersion");
|
||||
if(currentDataVersion < SharedConstants.getCurrentVersion().getDataVersion().getVersion()) {
|
||||
synchronized (laggyStructureMods) {
|
||||
if(laggyStructureMods.add(location.getNamespace())) {
|
||||
ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace());
|
||||
}
|
||||
}
|
||||
/* Needs upgrade, try looking up from cache */
|
||||
MessageDigest hasher = digestThreadLocal.get();
|
||||
hasher.reset();
|
||||
String hash = encodeHex(hasher.digest(structureBytes));
|
||||
CompoundTag cachedUpgraded = getCachedUpgraded(location, hash);
|
||||
CompoundTag cachedUpgraded = getCachedUpgraded(location, truncateHash(hash));
|
||||
if(cachedUpgraded == null)
|
||||
cachedUpgraded = getCachedUpgraded(location, hash); /* pick up old cache */
|
||||
if(cachedUpgraded != null && cachedUpgraded.getInt("DataVersion") == SharedConstants.getCurrentVersion().getDataVersion().getVersion()) {
|
||||
ModernFix.LOGGER.debug("Using cached upgraded version of {}", location);
|
||||
currentTag = cachedUpgraded;
|
||||
} else {
|
||||
synchronized (laggyStructureMods) {
|
||||
if(laggyStructureMods.add(location.getNamespace())) {
|
||||
ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace());
|
||||
}
|
||||
}
|
||||
ModernFix.LOGGER.debug("Structure {} is being run through DFU (hash {}), this will cause launch time delays", location, hash);
|
||||
currentTag = DataFixTypes.STRUCTURE.update(datafixer, currentTag, currentDataVersion,
|
||||
SharedConstants.getCurrentVersion().getDataVersion().getVersion());
|
||||
|
|
@ -100,7 +108,7 @@ public class CachingStructureManager {
|
|||
}
|
||||
|
||||
private static synchronized void saveCachedUpgraded(ResourceLocation location, String hash, CompoundTag tagToSave) {
|
||||
File theFile = getCachePath(location, hash);
|
||||
File theFile = getCachePath(location, truncateHash(hash));
|
||||
try {
|
||||
NbtIo.writeCompressed(tagToSave, theFile);
|
||||
} catch(IOException e) {
|
||||
|
|
|
|||
|
|
@ -43,4 +43,5 @@ accessible method net/minecraft/client/resources/model/ModelBakery$ModelBakerImp
|
|||
accessible method net/minecraft/client/resources/model/ModelBakery$BakedCacheKey <init> (Lnet/minecraft/resources/ResourceLocation;Lcom/mojang/math/Transformation;Z)V
|
||||
accessible class net/minecraft/world/level/chunk/PalettedContainer$Data
|
||||
accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/MinecraftServer$ReloadableResources;
|
||||
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
|
||||
accessible class net/minecraft/server/MinecraftServer$ReloadableResources
|
||||
accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ dependencies {
|
|||
modIncludeImplementation(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modIncludeImplementation(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modIncludeImplementation(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modIncludeImplementation(fabricApi.module("fabric-models-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
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;"))
|
||||
private void keepLoader(ModelLoadingRegistryImpl.LoaderInstance instance, ModelBakery value) {
|
||||
/* allow loading models to happen later */
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
"fabric-lifecycle-events-v1": "*",
|
||||
"fabric-screen-api-v1": "*",
|
||||
"fabric-command-api-v2": "*",
|
||||
"fabric-models-v0": "*",
|
||||
"minecraft": ">=1.16.5"
|
||||
},
|
||||
"breaks": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package org.embeddedt.modernfix.forge.datagen;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.screens.TitleScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.packs.PackResources;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.server.packs.resources.MultiPackResourceManager;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ScreenEvent;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import net.minecraftforge.data.event.GatherDataEvent;
|
||||
import net.minecraftforge.data.loading.DatagenModLoader;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mod.EventBusSubscriber(value = Dist.CLIENT)
|
||||
public class RuntimeDatagen {
|
||||
private static final String RESOURCES_OUT_DIR = getPropertyOrBlank("modernfix.datagen.output");
|
||||
private static final String RESOURCES_IN_DIR = getPropertyOrBlank("modernfix.datagen.existing");
|
||||
private static final String MODS_LIST = getPropertyOrBlank("modernfix.datagen.mods");
|
||||
private static final String EXISTING_MODS_LIST = getPropertyOrBlank("modernfix.datagen.existing_mods");
|
||||
private static final boolean IS_FLAT = Boolean.getBoolean("modernfix.datagen.flat");
|
||||
|
||||
private static String getPropertyOrBlank(String name) {
|
||||
String val = System.getProperty(name);
|
||||
if(val == null || val.length() == 0)
|
||||
return "";
|
||||
else
|
||||
return val;
|
||||
}
|
||||
|
||||
public static boolean isDatagenAvailable() {
|
||||
return RESOURCES_OUT_DIR.length() > 0;
|
||||
}
|
||||
|
||||
public static void runRuntimeDatagen() {
|
||||
ObfuscationReflectionHelper.setPrivateValue(DatagenModLoader.class, null, true, "runningDataGen");
|
||||
Set<String> mods = new HashSet<>(Arrays.stream(MODS_LIST.split(",")).collect(Collectors.toSet()));
|
||||
ModernFix.LOGGER.info("Beginning runtime datagen for " + mods.size() + " mods...");
|
||||
Set<String> existingMods = new HashSet<>(Arrays.stream(EXISTING_MODS_LIST.split(",")).collect(Collectors.toSet()));
|
||||
Set<Path> existingPacks = new HashSet<>(Arrays.stream(RESOURCES_IN_DIR.split(",")).map(Paths::get).collect(Collectors.toSet()));
|
||||
Path path = Paths.get(RESOURCES_OUT_DIR);
|
||||
GatherDataEvent.DataGeneratorConfig dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, Collections.emptyList(),
|
||||
true, true, true, true, true, mods.isEmpty() || IS_FLAT);
|
||||
if (!mods.contains("forge")) {
|
||||
//If we aren't generating data for forge, automatically add forge as an existing so mods can access forge's data
|
||||
existingMods.add("forge");
|
||||
}
|
||||
ExistingFileHelper existingFileHelper = new ExistingFileHelper(existingPacks, existingMods, true, null, null);
|
||||
/* Inject the client pack resources from us */
|
||||
MultiPackResourceManager manager = ObfuscationReflectionHelper.getPrivateValue(ExistingFileHelper.class, existingFileHelper, "clientResources");
|
||||
List<PackResources> oldPacks = new ArrayList<>(manager.listPacks().collect(Collectors.toList()));
|
||||
oldPacks.add(Minecraft.getInstance().getClientPackSource().getVanillaPack());
|
||||
ObfuscationReflectionHelper.setPrivateValue(ExistingFileHelper.class, existingFileHelper, new MultiPackResourceManager(PackType.CLIENT_RESOURCES, oldPacks), "clientResources");
|
||||
ModLoader.get().runEventGenerator(mc->new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p->dataGeneratorConfig.isFlat() ? p : p.resolve(mc.getModId()), dataGeneratorConfig.getMods().contains(mc.getModId())), dataGeneratorConfig, existingFileHelper));
|
||||
dataGeneratorConfig.runAll();
|
||||
ObfuscationReflectionHelper.setPrivateValue(DatagenModLoader.class, null, false, "runningDataGen");
|
||||
ModernFix.LOGGER.info("Finished runtime datagen.");
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onInitTitleScreen(ScreenEvent.Init.Post event) {
|
||||
if(isDatagenAvailable() && event.getScreen() instanceof TitleScreen) {
|
||||
TitleScreen screen = (TitleScreen)event.getScreen();
|
||||
screen.addRenderableWidget(Button.builder(Component.literal("DG"), (arg) -> {
|
||||
runRuntimeDatagen();
|
||||
}).pos(screen.width / 2 - 100 - 50, screen.height / 4 + 48).size(50, 20).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user