Compare commits

...

1 Commits

Author SHA1 Message Date
embeddedt
f9c1f3e9aa
WIP backporting 2024-11-18 14:58:33 -05:00
121 changed files with 265 additions and 3111 deletions

View File

@ -1,43 +0,0 @@
name: Build ModernFix using Gradle
on:
push:
branches:
- '**'
tags-ignore:
- '**'
pull_request:
jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') }}
gradle-home-cache-cleanup: true
- name: Setup project Loom cache
uses: actions/cache@v4
with:
path: |
.gradle/loom-cache
key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle.properties', '**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-
- name: Build ModernFix using Gradle
run: ./gradlew build
- name: Upload Artifacts to GitHub
uses: actions/upload-artifact@v4
with:
name: Package
path: bin

View File

@ -1,41 +0,0 @@
name: Release ModernFix Artifacts
on:
release:
types:
- published
jobs:
release:
if: github.repository_owner == 'embeddedt'
runs-on: ubuntu-22.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Remove tags for release on other versions
run: ./scripts/tagcleaner.sh
- name: Build and publish mod to CurseForge & Modrinth
run: ./gradlew publishToModSites copyJarToBin
env:
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
- name: Upload assets to GitHub
uses: AButler/upload-release-assets@v3.0
with:
files: 'bin/*'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Add changelog to release
uses: irongut/EditRelease@v1.2.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
id: ${{ github.event.release.id }}
replacebody: true
files: "CHANGELOG.md"

View File

@ -1,27 +0,0 @@
name: Update wiki using WikiGen
on:
push:
branches:
- '1.**'
jobs:
wikigen:
if: github.repository_owner == 'embeddedt'
runs-on: ubuntu-22.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate Markdown Patch-List
run: python3 scripts/gen-markdown-patchlist.py
- name: Very legitimate hack for wiki push race condition
run: sleep $((1 + (RANDOM % 30)))
shell: bash
- name: Upload generated file to wiki
uses: SwiftDocOrg/github-wiki-publish-action@v1
with:
path: "doc/generated"
env:
GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.WIKI_TOKEN }}

View File

@ -12,9 +12,7 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixinextras_version}"))
modCompileOnly("dev.latvian.mods:kubejs:${kubejs_version}") {
transitive = false
}
modCompileOnly("curse.maven:kubejs-238086:3103858")
// Remove the next line if you don't want to depend on the API
// modApi "me.shedaniel:architectury:${rootProject.architectury_version}"
}

View File

@ -1,13 +1,12 @@
package org.embeddedt.modernfix.blockstate;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.embeddedt.modernfix.duck.IBlockState;
public class BlockStateCacheHandler {
public static void rebuildParallel(boolean force) {
synchronized (BlockBehaviour.BlockStateBase.class) {
synchronized (BlockState.class) {
for (BlockState blockState : Block.BLOCK_STATE_REGISTRY) {
((IBlockState)blockState).clearCache();
}

View File

@ -28,7 +28,7 @@ public class ModernFixCommands {
return 0;
}
ResourceManager manager = level.getServer().resources.getResourceManager();
ResourceManager manager = level.getServer().getResources();
Collection<ResourceLocation> structures = manager.listResources("structures", p -> p.endsWith(".nbt"));
int upgradedNum = 0;
Pattern pathPattern = Pattern.compile("^structures/(.*)\\.nbt$");

View File

@ -1,14 +1,14 @@
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 100)
@Mixin(value = BlockState.class, priority = 100)
public class BlockStateBaseMixin {
@ModifyVariable(method = "getOffset", at = @At("HEAD"), argsOnly = true, index = 1)
private BlockGetter useSafeGetter(BlockGetter g) {

View File

@ -1,28 +0,0 @@
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
import net.minecraft.tags.StaticTagHelper;
import net.minecraft.tags.TagCollection;
import net.minecraft.tags.TagContainer;
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.callback.CallbackInfo;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
@Mixin(StaticTagHelper.class)
public class StaticTagHelperMixin<T> {
@SuppressWarnings("rawtypes")
@Shadow @Mutable
@Final private List wrappers;
@Inject(method = "<init>", at = @At("RETURN"))
private void useCOWArrayList(Function<TagContainer, TagCollection<T>> function, CallbackInfo ci) {
this.wrappers = new CopyOnWriteArrayList<>();
}
}

View File

@ -1,6 +1,5 @@
package org.embeddedt.modernfix.common.mixin.bugfix.paper_chunk_patches;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
@ -29,9 +28,8 @@ public class ChunkMapMixin {
@Inject(method = "<init>", at = @At("RETURN"))
private void setup(CallbackInfo ci) {
MinecraftServer server = this.level.getServer();
this.mainInvokingExecutor = (runnable) -> {
if(server.isSameThread())
if(this.level.getServer().isSameThread())
runnable.run();
else
this.mainThreadExecutor.execute(runnable);

View File

@ -17,7 +17,7 @@ public class MinecraftServerMixin implements ITimeTrackingServer {
return mfix$lastTickStartTime;
}
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickServer(Ljava/util/function/BooleanSupplier;)V"))
@Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickServer(Ljava/util/function/BooleanSupplier;)V"))
private void trackTickTime(CallbackInfo ci) {
mfix$lastTickStartTime = Util.getMillis();
}

View File

@ -1,19 +0,0 @@
package org.embeddedt.modernfix.common.mixin.devenv;
import com.mojang.authlib.minecraft.OfflineSocialInteractions;
import com.mojang.authlib.minecraft.SocialInteractionsService;
import net.minecraft.client.Minecraft;
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.CallbackInfoReturnable;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public class MinecraftMixin {
@Inject(method = "createSocialInteractions", at = @At("HEAD"), cancellable = true)
private void noSocialInteraction(CallbackInfoReturnable<SocialInteractionsService> cir) {
cir.setReturnValue(new OfflineSocialInteractions());
}
}

View File

@ -1,47 +0,0 @@
package org.embeddedt.modernfix.common.mixin.feature.measure_time;
import com.mojang.datafixers.util.Function4;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Overlay;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.level.DataPackConfig;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.level.storage.WorldData;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.ModernFixClient;
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;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.Function;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public class MinecraftMixin {
@Shadow @Nullable public Overlay overlay;
private long datapackReloadStartTime;
@Inject(method = "makeServerStem", at = @At(value = "HEAD"))
private void recordReloadStart(RegistryAccess.RegistryHolder p_238189_1_, Function<LevelStorageSource.LevelStorageAccess, DataPackConfig> p_238189_2_, Function4<LevelStorageSource.LevelStorageAccess, RegistryAccess.RegistryHolder, ResourceManager, DataPackConfig, WorldData> p_238189_3_, boolean p_238189_4_, LevelStorageSource.LevelStorageAccess p_238189_5_, CallbackInfoReturnable<Minecraft.ServerStem> cir) {
datapackReloadStartTime = System.nanoTime();
}
@Inject(method = "makeServerStem", at = @At(value = "RETURN"))
private void recordReloadEnd(RegistryAccess.RegistryHolder p_238189_1_, Function<LevelStorageSource.LevelStorageAccess, DataPackConfig> p_238189_2_, Function4<LevelStorageSource.LevelStorageAccess, RegistryAccess.RegistryHolder, ResourceManager, DataPackConfig, WorldData> p_238189_3_, boolean p_238189_4_, LevelStorageSource.LevelStorageAccess p_238189_5_, CallbackInfoReturnable<Minecraft.ServerStem> cir) {
float timeSpentReloading = ((float)(System.nanoTime() - datapackReloadStartTime) / 1000000000f);
ModernFix.LOGGER.warn("Datapack reload took " + timeSpentReloading + " seconds.");
}
@Inject(method = "tick", at = @At("HEAD"))
private void onClientTick(CallbackInfo ci) {
if(this.overlay == null && ModernFixClient.INSTANCE != null) {
ModernFixClient.INSTANCE.onGameLaunchFinish();
}
}
}

View File

@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(Util.class)
public class UtilMixin {
@ModifyConstant(method = "makeExecutor", constant = @Constant(intValue = 7))
@ModifyConstant(method = "makeBackgroundExecutor", constant = @Constant(intValue = 7))
private static int useHigherThreadCount(int old) {
String requestedMax = System.getProperty("max.bg.threads");
if(requestedMax != null) {

View File

@ -1,22 +1,15 @@
package org.embeddedt.modernfix.common.mixin.perf.cache_blockstate_cache_arrays;
import net.minecraft.world.level.block.SupportType;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(BlockBehaviour.BlockStateBase.Cache.class)
@Mixin(BlockState.Cache.class)
public class AbstractBlockStateCacheMixin {
private static final SupportType[] MF_BLOCK_VOXEL_SHAPES = SupportType.values();
private static final Direction.Axis[] DIRECTION_AXIS_VALUES = Direction.Axis.values();
@Redirect(method = "<init>(Lnet/minecraft/world/level/block/state/BlockState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/SupportType;values()[Lnet/minecraft/world/level/block/SupportType;"))
private SupportType[] getVoxelShapeValues() {
return MF_BLOCK_VOXEL_SHAPES;
}
@Redirect(method = "<init>(Lnet/minecraft/world/level/block/state/BlockState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/Direction$Axis;values()[Lnet/minecraft/core/Direction$Axis;"))
private Direction.Axis[] getDirectionAxisValues() {
return DIRECTION_AXIS_VALUES;

View File

@ -4,26 +4,29 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.feature.StrongholdFeature;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.duck.IServerLevel;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import org.embeddedt.modernfix.world.StrongholdLocationCache;
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.callback.CallbackInfo;
import java.util.Arrays;
import java.util.List;
@Mixin(ChunkGenerator.class)
@Mixin(StrongholdFeature.class)
public class ChunkGeneratorMixin {
@Shadow @Final private List<ChunkPos> strongholdPositions;
@Shadow @Final @Mutable private ChunkPos[] strongholdPos;
@Inject(method = "generateStrongholds", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList()Ljava/util/ArrayList;", ordinal = 0, remap = false), cancellable = true)
private void useCachedDataIfAvailable(CallbackInfo ci) {
ServerLevel level = searchLevel();
@Inject(method = "generatePositions", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList()Ljava/util/ArrayList;", ordinal = 0, remap = false), cancellable = true)
private void useCachedDataIfAvailable(ChunkGenerator<?> generator, CallbackInfo ci) {
ServerLevel level = searchLevel(generator);
if(level == null) {
ModernFix.LOGGER.error("Can't find server level for " + this);
return;
@ -32,17 +35,17 @@ public class ChunkGeneratorMixin {
List<ChunkPos> positions = cache.getChunkPosList();
if(positions.isEmpty())
return;
ModernFix.LOGGER.debug("Loaded stronghold cache for dimension {} with {} positions", level.dimension().location(), positions.size());
this.strongholdPositions.addAll(positions);
ModernFix.LOGGER.debug("Loaded stronghold cache for dimension {} with {} positions", level.dimension.getType().toString(), positions.size());
this.strongholdPos = positions.toArray(new ChunkPos[0]);
ci.cancel();
}
private ServerLevel searchLevel() {
private ServerLevel searchLevel(ChunkGenerator<?> generator) {
MinecraftServer server = ModernFixPlatformHooks.INSTANCE.getCurrentServer();
if(server != null) {
ServerLevel ourLevel = null;
for (ServerLevel level : server.getAllLevels()) {
if (level.getChunkSource().getGenerator() == ((ChunkGenerator) (Object) this)) {
if (level.getChunkSource().getGenerator() == generator) {
ourLevel = level;
break;
}
@ -52,14 +55,14 @@ public class ChunkGeneratorMixin {
return null;
}
@Inject(method = "generateStrongholds", at = @At("TAIL"))
private void saveCachedData(CallbackInfo ci) {
if(this.strongholdPositions.size() > 0) {
ServerLevel level = searchLevel();
@Inject(method = "generatePositions", at = @At("TAIL"))
private void saveCachedData(ChunkGenerator<?> generator, CallbackInfo ci) {
if(this.strongholdPos.length > 0) {
ServerLevel level = searchLevel(generator);
if(level != null) {
StrongholdLocationCache cache = ((IServerLevel)level).mfix$getStrongholdCache();
cache.setChunkPosList(this.strongholdPositions);
ModernFix.LOGGER.debug("Saved stronghold cache for dimension {}", level.dimension().location());
cache.setChunkPosList(Arrays.asList(this.strongholdPos));
ModernFix.LOGGER.debug("Saved stronghold cache for dimension {}", level.dimension.getType().toString());
}
}
}

View File

@ -1,18 +1,13 @@
package org.embeddedt.modernfix.common.mixin.perf.cache_strongholds;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.CustomSpawner;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.dimension.Dimension;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.storage.DimensionDataStorage;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.ServerLevelData;
import net.minecraft.world.level.storage.WritableLevelData;
import net.minecraft.world.level.storage.LevelData;
import org.embeddedt.modernfix.duck.IServerLevel;
import org.embeddedt.modernfix.world.StrongholdLocationCache;
import org.spongepowered.asm.mixin.Mixin;
@ -21,14 +16,13 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
import java.util.function.BiFunction;
@Mixin(ServerLevel.class)
public abstract class ServerLevelMixin extends Level implements IServerLevel {
protected ServerLevelMixin(WritableLevelData arg, ResourceKey<Level> arg2, DimensionType arg3, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l) {
super(arg, arg2, arg3, supplier, bl, bl2, l);
protected ServerLevelMixin(LevelData levelData, DimensionType dimensionType, BiFunction<Level, Dimension, ChunkSource> biFunction, ProfilerFiller profilerFiller, boolean bl) {
super(levelData, dimensionType, biFunction, profilerFiller, bl);
}
@Shadow public abstract DimensionDataStorage getDataStorage();
@ -36,10 +30,8 @@ public abstract class ServerLevelMixin extends Level implements IServerLevel {
private StrongholdLocationCache mfix$strongholdCache;
@Inject(method = "<init>", at = @At("RETURN"))
private void addStrongholdCache(MinecraftServer minecraftServer, Executor executor, LevelStorageSource.LevelStorageAccess arg,
ServerLevelData arg2, ResourceKey<Level> arg3, DimensionType arg4, ChunkProgressListener arg5,
ChunkGenerator arg6, boolean bl, long l, List<CustomSpawner> list, boolean bl2, CallbackInfo ci) {
mfix$strongholdCache = this.getDataStorage().computeIfAbsent(() -> new StrongholdLocationCache((ServerLevel)(Object)this), StrongholdLocationCache.getFileId(this.dimensionType()));
private void addStrongholdCache(CallbackInfo ci) {
mfix$strongholdCache = this.getDataStorage().computeIfAbsent(() -> new StrongholdLocationCache((ServerLevel)(Object)this), StrongholdLocationCache.getFileId(this.dimension.getType()));
}
@Override

View File

@ -1,35 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
import org.embeddedt.modernfix.registry.LifecycleMap;
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.callback.CallbackInfo;
import java.util.Map;
@Mixin(MappedRegistry.class)
@IgnoreOutsideDev
public abstract class MappedRegistryMixin<T> extends Registry<T> {
@Shadow
@Final
@Mutable
private Map<T, Lifecycle> lifecycles;
protected MappedRegistryMixin(ResourceKey<? extends Registry<T>> resourceKey, Lifecycle lifecycle) {
super(resourceKey, lifecycle);
}
@Inject(method = "<init>", at = @At("RETURN"))
private void replaceStorage(CallbackInfo ci) {
this.lifecycles = new LifecycleMap<>();
}
}

View File

@ -2,8 +2,8 @@ package org.embeddedt.modernfix.common.mixin.perf.compress_biome_container;
import it.unimi.dsi.fastutil.objects.Reference2ShortMap;
import it.unimi.dsi.fastutil.objects.Reference2ShortOpenHashMap;
import net.minecraft.core.Registry;
import net.minecraft.util.BitStorage;
import net.minecraft.core.IdMap;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.util.Mth;
import net.minecraft.world.level.biome.Biome;
@ -21,10 +21,6 @@ public class MixinBiomeContainer {
@Final
private Biome[] biomes;
@Shadow
@Final
private IdMap<Biome> biomeRegistry;
@Shadow
@Final
private static int WIDTH_BITS;
@ -32,23 +28,23 @@ public class MixinBiomeContainer {
private Biome[] palette;
private BitStorage intArray;
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;[I)V", at = @At("RETURN"), require = 0)
private void reinit1(IdMap p_i241970_1_, int[] p_i241970_2_, CallbackInfo ci) {
@Inject(method = "<init>(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At("RETURN"))
private void reinit1(CallbackInfo ci) {
this.createCompact();
}
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;[Lnet/minecraft/world/level/biome/Biome;)V", at = @At("RETURN"))
private void reinit2(IdMap p_i241971_1_, Biome[] p_i241971_2_, CallbackInfo ci) {
@Inject(method = "<init>([Lnet/minecraft/world/level/biome/Biome;)V", at = @At("RETURN"))
private void reinit2(Biome[] p_i241971_2_, CallbackInfo ci) {
this.createCompact();
}
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/biome/BiomeSource;)V", at = @At("RETURN"))
private void reinit3(IdMap p_i241968_1_, ChunkPos p_i241968_2_, BiomeSource p_i241968_3_, CallbackInfo ci) {
@Inject(method = "<init>(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/biome/BiomeSource;)V", at = @At("RETURN"))
private void reinit3(ChunkPos p_i241968_2_, BiomeSource p_i241968_3_, CallbackInfo ci) {
this.createCompact();
}
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/biome/BiomeSource;[I)V", at = @At("RETURN"))
private void reinit4(IdMap p_i241969_1_, ChunkPos p_i241969_2_, BiomeSource p_i241969_3_, int[] p_i241969_4_, CallbackInfo ci) {
@Inject(method = "<init>(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/biome/BiomeSource;[I)V", at = @At("RETURN"))
private void reinit4(ChunkPos p_i241969_2_, BiomeSource p_i241969_3_, int[] p_i241969_4_, CallbackInfo ci) {
this.createCompact();
}
@ -127,7 +123,7 @@ public class MixinBiomeContainer {
int[] array = new int[size];
for(int i = 0; i < size; ++i) {
array[i] = this.biomeRegistry.getId(this.palette[this.intArray.get(i)]);
array[i] = Registry.BIOME.getId(this.palette[this.intArray.get(i)]);
}
return array;
@ -145,4 +141,18 @@ public class MixinBiomeContainer {
return this.palette[this.intArray.get(y << WIDTH_BITS + WIDTH_BITS | z << WIDTH_BITS | x)];
}
/**
* @author embeddedt
* @reason Reimplement
*/
@Overwrite
public ChunkBiomeContainer copy() {
int size = this.intArray.getSize();
Biome[] biomes = new Biome[size];
for(int i = 0; i < size; ++i) {
biomes[i] = this.palette[this.intArray.get(i)];
}
return new ChunkBiomeContainer(biomes);
}
}

View File

@ -12,7 +12,7 @@ import java.util.concurrent.Executor;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public class MinecraftMixin {
@Redirect(method = { "<init>", "makeServerStem", "reloadResourcePacks" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;backgroundExecutor()Ljava/util/concurrent/Executor;", ordinal = 0))
@Redirect(method = { "<init>", "reloadResourcePacks" }, at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;backgroundExecutor()Ljava/util/concurrent/Executor;", ordinal = 0))
private Executor getResourceReloadExecutor() {
return ModernFix.resourceReloadExecutor();
}

View File

@ -10,7 +10,7 @@ import java.util.concurrent.Executor;
@Mixin(MinecraftServer.class)
public class MinecraftServerMixin {
@ModifyArg(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;loadResources(Ljava/util/List;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 3)
@ModifyArg(method = "updateSelectedPacks", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;reload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/List;Ljava/util/concurrent/CompletableFuture;)Ljava/util/concurrent/CompletableFuture;"), index = 1)
private Executor getReloadExecutor(Executor asyncExecutor) {
return ModernFix.resourceReloadExecutor();
}

View File

@ -1,13 +1,11 @@
package org.embeddedt.modernfix.common.mixin.perf.deduplicate_wall_shapes;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.mojang.datafixers.util.Pair;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.WallBlock;
import net.minecraft.world.level.block.CrossCollisionBlock;
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 net.minecraft.world.phys.shapes.VoxelShape;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -23,44 +21,33 @@ import java.util.Map;
* same shape instances. To do this we can cache a mapping between a state (represented only as its prop->value map)
* and the desired shape, and generate the BlockState->VoxelShape map from this for each block.
*/
@Mixin(WallBlock.class)
@Mixin(CrossCollisionBlock.class)
public abstract class WallBlockMixin extends Block {
private static Map<ImmutableList<Float>, Pair<Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape>, StateDefinition<Block, BlockState>>> CACHE_BY_SHAPE_VALS = new HashMap<>();
private static Map<ImmutableList<Float>, Pair<VoxelShape[], StateDefinition<Block, BlockState>>> CACHE_BY_SHAPE_VALS = new HashMap<>();
public WallBlockMixin(Properties properties) {
super(properties);
}
@Inject(method = "makeShapes", at = @At("HEAD"), cancellable = true)
private synchronized void useCachedShapeMap(float f1, float f2, float f3, float f4, float f5, float f6, CallbackInfoReturnable<Map<BlockState, VoxelShape>> cir) {
ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5, f6);
Pair<Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape>, StateDefinition<Block, BlockState>> cache = CACHE_BY_SHAPE_VALS.get(key);
private synchronized void useCachedShapeMap(float f1, float f2, float f3, float f4, float f5, CallbackInfoReturnable<VoxelShape[]> cir) {
ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5);
Pair<VoxelShape[], StateDefinition<Block, BlockState>> cache = CACHE_BY_SHAPE_VALS.get(key);
// require the properties to be identical
if(cache == null || !cache.getSecond().getProperties().equals(this.stateDefinition.getProperties()))
return;
ImmutableMap.Builder<BlockState, VoxelShape> builder = ImmutableMap.builder();
for(BlockState state : this.stateDefinition.getPossibleStates()) {
VoxelShape shape = cache.getFirst().get(state.getValues());
if(shape == null)
return; // fallback to vanilla logic
builder.put(state, shape);
}
cir.setReturnValue(builder.build());
cir.setReturnValue(cache.getFirst());
}
@Inject(method = "makeShapes", at = @At("RETURN"))
private synchronized void storeCachedShapesByProperty(float f1, float f2, float f3, float f4, float f5, float f6, CallbackInfoReturnable<Map<BlockState, VoxelShape>> cir) {
private synchronized void storeCachedShapesByProperty(float f1, float f2, float f3, float f4, float f5, CallbackInfoReturnable<VoxelShape[]> cir) {
// never populate cache as a non-vanilla block
if((Class<?>)this.getClass() != WallBlock.class)
return;
ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5, f6);
//if((Class<?>)this.getClass() != WallBlock.class)
// return;
ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5);
if(!CACHE_BY_SHAPE_VALS.containsKey(key)) {
Map<ImmutableMap<Property<?>, Comparable<?>>, VoxelShape> cacheByProperties = new HashMap<>();
Map<BlockState, VoxelShape> shapeMap = cir.getReturnValue();
for(Map.Entry<BlockState, VoxelShape> entry : shapeMap.entrySet()) {
cacheByProperties.put(entry.getKey().getValues(), entry.getValue());
}
CACHE_BY_SHAPE_VALS.put(key, Pair.of(cacheByProperties, this.stateDefinition));
VoxelShape[] shapes = cir.getReturnValue();
CACHE_BY_SHAPE_VALS.put(key, Pair.of(shapes, this.stateDefinition));
}
}
}

View File

@ -1,19 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.dynamic_dfu;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.types.Type;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* Prevent fetchChoiceType calls from loading DFU early. Vanilla doesn't need the return values here.
*/
@Mixin(BlockEntityType.class)
public class BlockEntityTypeMixin {
@Redirect(method = "register", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;fetchChoiceType(Lcom/mojang/datafixers/DSL$TypeReference;Ljava/lang/String;)Lcom/mojang/datafixers/types/Type;"))
private static Type<?> skipSchemaCheck(DSL.TypeReference ref, String s) {
return null;
}
}

View File

@ -1,30 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.dynamic_dfu;
import com.mojang.datafixers.DataFixer;
import net.minecraft.util.datafix.DataFixers;
import org.embeddedt.modernfix.dfu.LazyDataFixer;
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(DataFixers.class)
public abstract class DataFixersMixin {
@Shadow protected static DataFixer createFixerUpper() {
throw new AssertionError();
}
private static LazyDataFixer lazyDataFixer;
/**
* Avoid classloading the DFU logic until we actually need it.
*/
@Inject(method = "createFixerUpper", at = @At("HEAD"), cancellable = true)
private static void createLazyFixerUpper(CallbackInfoReturnable<DataFixer> cir) {
if(lazyDataFixer == null) {
lazyDataFixer = new LazyDataFixer(DataFixersMixin::createFixerUpper);
cir.setReturnValue(lazyDataFixer);
}
}
}

View File

@ -1,19 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.dynamic_dfu;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.types.Type;
import net.minecraft.world.entity.EntityType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* Prevent fetchChoiceType calls from loading DFU early. Vanilla doesn't need the return values here.
*/
@Mixin(EntityType.Builder.class)
public class EntityTypeBuilderMixin {
@Redirect(method = "build", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;fetchChoiceType(Lcom/mojang/datafixers/DSL$TypeReference;Ljava/lang/String;)Lcom/mojang/datafixers/types/Type;"))
private Type<?> skipSchemaCheck(DSL.TypeReference ref, String s) {
return null;
}
}

View File

@ -2,12 +2,9 @@ package org.embeddedt.modernfix.common.mixin.perf.dynamic_structure_manager;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.mojang.datafixers.DataFixer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
@ -24,7 +21,7 @@ public class StructureManagerMixin {
private Map<ResourceLocation, StructureTemplate> structureRepository;
@Inject(method = "<init>", at = @At("RETURN"))
private void makeStructuresSafe(ResourceManager arg, LevelStorageSource.LevelStorageAccess arg2, DataFixer dataFixer, CallbackInfo ci) {
private void makeStructuresSafe(CallbackInfo ci) {
/* Structures needing to be reloaded is not a huge issue since we optimize loading them already */
Cache<ResourceLocation, StructureTemplate> structureCache = CacheBuilder.newBuilder()
.softValues()

View File

@ -24,15 +24,15 @@ import java.util.Map;
@Mixin(LegacyUnicodeBitmapsProvider.class)
@ClientOnlyMixin
public abstract class LegacyUnicodeBitmapsProviderMixin {
@Shadow protected abstract ResourceLocation getSheetLocation(int i);
@Shadow protected abstract ResourceLocation getSheetLocation(char i);
@Shadow @Final private Map<ResourceLocation, NativeImage> textures;
private final ResourceLocation[] glyphLocations = new ResourceLocation[256];
private ResourceLocation currentCharIdx;
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/font/providers/LegacyUnicodeBitmapsProvider;getSheetLocation(I)Lnet/minecraft/resources/ResourceLocation;"))
private ResourceLocation storeCurrentCharIdx(LegacyUnicodeBitmapsProvider provider, int i) {
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/font/providers/LegacyUnicodeBitmapsProvider;getSheetLocation(C)Lnet/minecraft/resources/ResourceLocation;"))
private ResourceLocation storeCurrentCharIdx(LegacyUnicodeBitmapsProvider provider, char i) {
ResourceLocation location = getSheetLocation(i);
currentCharIdx = location;
return location;
@ -56,15 +56,15 @@ public abstract class LegacyUnicodeBitmapsProviderMixin {
}
@Inject(method = "getSheetLocation", at = @At("HEAD"), cancellable = true)
private void useCachedLocation(int idx, CallbackInfoReturnable<ResourceLocation> cir) {
int cachedIdx = idx / 256;
private void useCachedLocation(char idx, CallbackInfoReturnable<ResourceLocation> cir) {
char cachedIdx = (char)(idx / 256);
if(cachedIdx >= 0 && cachedIdx < glyphLocations.length && glyphLocations[cachedIdx] != null)
cir.setReturnValue(glyphLocations[cachedIdx]);
}
@Inject(method = "getSheetLocation", at = @At("RETURN"))
private void saveCachedLocation(int idx, CallbackInfoReturnable<ResourceLocation> cir) {
int cachedIdx = idx / 256;
private void saveCachedLocation(char idx, CallbackInfoReturnable<ResourceLocation> cir) {
char cachedIdx = (char)(idx / 256);
if(cachedIdx >= 0 && cachedIdx < glyphLocations.length)
glyphLocations[cachedIdx] = cir.getReturnValue();
}

View File

@ -1,12 +1,12 @@
package org.embeddedt.modernfix.common.mixin.perf.model_optimizations;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.AbstractProperty;
import org.embeddedt.modernfix.dedup.IdentifierCaches;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Property.class)
@Mixin(AbstractProperty.class)
public class PropertyMixin {
@Shadow @Mutable
@ -16,8 +16,8 @@ public class PropertyMixin {
@Shadow @Final private Class clazz;
@Redirect(method = "<init>", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/state/properties/Property;name:Ljava/lang/String;"))
private void internName(Property instance, String name) {
@Redirect(method = "<init>", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/state/properties/AbstractProperty;name:Ljava/lang/String;"))
private void internName(AbstractProperty<?> instance, String name) {
this.name = IdentifierCaches.PROPERTY.deduplicate(name);
}
/**
@ -28,10 +28,10 @@ public class PropertyMixin {
public boolean equals(Object p_equals_1_) {
if (this == p_equals_1_) {
return true;
} else if (!(p_equals_1_ instanceof Property)) {
} else if (!(p_equals_1_ instanceof AbstractProperty<?>)) {
return false;
} else {
Property<?> property = (Property)p_equals_1_;
AbstractProperty<?> property = (AbstractProperty<?>)p_equals_1_;
/* reference equality is safe here because of deduplication */
return this.clazz == property.getValueClass() && this.name == property.getName();
}

View File

@ -1,36 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.mojang_registry_size;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.core.MappedRegistry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(MappedRegistry.class)
public class MappedRegistryMixin {
/**
* Avoid copying the ID list to a slightly larger one every time an entry is added to the registry.
* The original behavior causes O(n) time complexity for registration.
*/
@Redirect(
method = "registerMapping(ILnet/minecraft/resources/ResourceKey;Ljava/lang/Object;Lcom/mojang/serialization/Lifecycle;Z)Ljava/lang/Object;",
at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/ObjectList;size(I)V", remap = false)
)
private void setSizeSmart(ObjectList<?> list, int size) {
if(list instanceof ObjectArrayList && size > list.size()) {
int requestedSize = size;
/* choose next power of two, or this value if it is a power of two */
int p2Size = Integer.highestOneBit(size);
if(p2Size != size)
size = p2Size << 1;
// grow backing array to power-of-two size, this will return instantly in most cases
((ObjectArrayList<?>)list).ensureCapacity(size);
// write null entries to fill size, to match the behavior of list.size(int)
while(list.size() < requestedSize)
list.add(null);
} else {
list.size(size);
}
}
}

View File

@ -1,28 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.mojang_registry_size;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
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;
import java.util.Map;
@Mixin(ResourceKey.class)
public class ResourceKeyMixin<T> {
private static final Map<ResourceLocation, Map<ResourceLocation, ResourceKey<?>>> INTERNING_MAP = new Object2ObjectOpenHashMap<>();
@Inject(method = "create(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceKey;", at = @At("HEAD"), cancellable = true)
private static <T> void createEfficient(ResourceLocation parent, ResourceLocation location, CallbackInfoReturnable<ResourceKey<T>> cir) {
synchronized (ResourceKey.class) {
Map<ResourceLocation, ResourceKey<?>> keys = INTERNING_MAP.computeIfAbsent(parent, k -> new Object2ObjectOpenHashMap<>());
ResourceKey<?> key = keys.get(location);
if(key == null) {
key = new ResourceKey<>(parent, location);
keys.put(location, key);
}
cir.setReturnValue((ResourceKey<T>)key);
}
}
}

View File

@ -4,7 +4,7 @@ import com.google.common.collect.ArrayTable;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.block.state.AbstractStateHolder;
import net.minecraft.world.level.block.state.properties.Property;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.spongepowered.asm.mixin.Mixin;
@ -17,7 +17,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* Minor mixin to avoid duplicate empty neighbor tables, used when FerriteCore is not present. Won't be enabled in 99% of
* modded environments but is useful for testing in dev without dragging in Fabric API.
*/
@Mixin(StateHolder.class)
@Mixin(AbstractStateHolder.class)
@RequiresMod("!ferritecore")
public class StateHolderMixin {
@Shadow private Table<Property<?>, Comparable<?>, ?> neighbours;

View File

@ -1,6 +1,6 @@
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.embeddedt.modernfix.duck.IBlockState;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
@ -9,11 +9,11 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(BlockBehaviour.BlockStateBase.class)
@Mixin(BlockState.class)
public abstract class BlockStateBaseMixin implements IBlockState {
@Shadow public abstract void initCache();
@Shadow private BlockBehaviour.BlockStateBase.Cache cache;
@Shadow private BlockState.Cache cache;
private volatile boolean cacheInvalid = false;
private static boolean buildingCache = false;
@ -30,7 +30,7 @@ public abstract class BlockStateBaseMixin implements IBlockState {
private void mfix$generateCache() {
if(cacheInvalid) {
// Ensure that only one block's cache is built at a time
synchronized (BlockBehaviour.BlockStateBase.class) {
synchronized (BlockState.class) {
if(cacheInvalid) {
// Ensure that if we end up in here recursively, we just use the original cache
if(!buildingCache) {
@ -51,10 +51,10 @@ public abstract class BlockStateBaseMixin implements IBlockState {
@Redirect(method = "*", at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;cache:Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase$Cache;",
target = "Lnet/minecraft/world/level/block/state/BlockState;cache:Lnet/minecraft/world/level/block/state/BlockState$Cache;",
ordinal = 0
))
private BlockBehaviour.BlockStateBase.Cache dynamicCacheGen(BlockBehaviour.BlockStateBase base) {
private BlockState.Cache dynamicCacheGen(BlockState base) {
mfix$generateCache();
return this.cache;
}

View File

@ -1,6 +1,6 @@
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.server.MinecraftServer;
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -8,10 +8,10 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.function.Consumer;
@Mixin(value = Blocks.class, priority = 1100)
@Mixin(value = MinecraftServer.class, priority = 1100)
public class BlocksMixin {
@ModifyArg(method = "rebuildCache", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/IdMapper;forEach(Ljava/util/function/Consumer;)V"), index = 0)
private static Consumer getEmptyConsumer(Consumer original) {
@ModifyArg(method = "refreshRegistries", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/IdMapper;forEach(Ljava/util/function/Consumer;)V"), index = 0)
private Consumer getEmptyConsumer(Consumer original) {
BlockStateCacheHandler.rebuildParallel(true);
return o -> {};
}

View File

@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.Shadow;
/* Idea from Lithium for 1.19.3 */
@Mixin(Biome.class)
public abstract class BiomeMixin {
@Shadow protected abstract float getHeightAdjustedTemperature(BlockPos pos);
@Shadow protected abstract float getTemperatureNoCache(BlockPos pos);
/**
* @author 2No2Name
@ -19,6 +19,6 @@ public abstract class BiomeMixin {
*/
@Overwrite
public final float getTemperature(BlockPos pos) {
return this.getHeightAdjustedTemperature(pos);
return this.getTemperatureNoCache(pos);
}
}

View File

@ -1,37 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(Entity.class)
public class EntityMixin {
/**
* @author embeddedt
* @reason If the spawn chunks are not loaded, end portals linking to the overworld will teleport entities into
* the void at the spawn position, which is not ideal. To solve this, we create a PORTAL ticket if the expected
* overworld chunk is missing.
*/
@ModifyExpressionValue(method = "findDimensionEntryPoint", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;getSharedSpawnPos()Lnet/minecraft/core/BlockPos;"), require = 0)
private BlockPos mfix$triggerChunkloadAtSpawnPos(BlockPos spawnPos, ServerLevel destination) {
// Only apply this change if the overworld is the destination
if (destination.dimension() == ServerLevel.OVERWORLD) {
// No ticket is required if the chunk happens to already be loaded
if(!destination.hasChunk(spawnPos.getX() >> 4, spawnPos.getZ() >> 4)) {
// Create a portal ticket. While we could just load the chunk once, it would immediately unload on the
// next tick, causing churn. The ticket will keep it loaded for a few seconds which should give high
// performance for farms pumping things through portals frequently.
BlockPos key = spawnPos.immutable();
destination.getChunkSource().addRegionTicket(TicketType.PORTAL, new ChunkPos(key), 3, key);
// Wait for the chunk to be loaded, as adding the ticket is asynchronous
destination.getChunk(key);
}
}
return spawnPos;
}
}

View File

@ -1,24 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkStatus;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = MinecraftServer.class, priority = 1100)
public class MinecraftServerMixin {
@Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"))
private void addSpawnChunkTicket(ServerChunkCache cache, TicketType<?> type, ChunkPos pos, int distance, Object o) {
// load first chunk
cache.getChunk(pos.x, pos.z, ChunkStatus.FULL, true);
}
@Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I"), require = 0)
private int getGenerated(ServerChunkCache cache) {
return 441;
}
}

View File

@ -1,12 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
import net.minecraft.server.level.DistanceManager;
import net.minecraft.server.level.ServerChunkCache;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerChunkCache.class)
public interface ServerChunkCacheAccessor {
@Accessor("distanceManager")
DistanceManager getDistanceManager();
}

View File

@ -1,20 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.level.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ServerLevel.class)
public class ServerLevelMixin {
@Redirect(method = "setDefaultSpawnPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;removeRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"))
private void removeTicket(ServerChunkCache cache, TicketType<?> type, ChunkPos pos, int distance, Object o) {
}
@Redirect(method = "setDefaultSpawnPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"))
private void addTicket(ServerChunkCache cache, TicketType<?> type, ChunkPos pos, int distance, Object o) {
}
}

View File

@ -1,25 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.util.SortedArraySet;
import org.embeddedt.modernfix.ModernFix;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(SortedArraySet.class)
public class SortedArraySetMixin<T> {
/**
* @author embeddedt
* @reason Make add() not crash with a null key, since some mods (Carpet) assume there will always be a spawn ticket,
* and then assume the reference they have is non-null (it can be null with this option enabled).
*/
@WrapOperation(method = "add", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SortedArraySet;findIndex(Ljava/lang/Object;)I"), require = 0)
private int checkStatus(SortedArraySet<T> instance, T object, Operation<Integer> original) {
if(object == null) {
ModernFix.LOGGER.error("Attempted to insert a null key into SortedArraySet, ignoring");
return 0;
}
return original.call(instance, object);
}
}

View File

@ -1,83 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.reuse_datapacks;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.Minecraft;
import net.minecraft.commands.Commands;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerResources;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.world.level.DataPackConfig;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public abstract class MinecraftMixin implements ICachingResourceClient {
@Shadow public abstract boolean isLocalServer();
private ServerResources cachedResources;
private List<String> cachedDataPackConfig;
private List<String> loadingDataPackConfig;
@Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;configurePackRepository(Lnet/minecraft/server/packs/repository/PackRepository;Lnet/minecraft/world/level/DataPackConfig;Z)Lnet/minecraft/world/level/DataPackConfig;"))
private DataPackConfig saveLoadingConfig(PackRepository repo, DataPackConfig inCodec, boolean vanillaOnly) {
DataPackConfig config = MinecraftServer.configurePackRepository(repo, inCodec, vanillaOnly);
loadingDataPackConfig = repo.getSelectedPacks().stream().map(Pack::getId).collect(ImmutableList.toImmutableList());
return config;
}
@Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;loadResources(Ljava/util/List;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
private CompletableFuture<ServerResources> useCachedResources(List<PackResources> list, Commands.CommandSelection arg, int i, Executor executor, Executor executor2) {
if(cachedResources != null) {
if(cachedResources.getResourceManager().getNamespaces().size() > 0) {
if (cachedDataPackConfig.equals(loadingDataPackConfig)) {
ModernFix.LOGGER.warn("Reusing loaded server resources from previous world");
return CompletableFuture.completedFuture(cachedResources);
} else {
ModernFix.LOGGER.warn("Discarding cached server resources, datapack configs have changed");
ModernFix.LOGGER.warn("Old: {}", "[" + String.join(", ", cachedDataPackConfig) + "]");
ModernFix.LOGGER.warn("New: {}", "[" + String.join(", ", loadingDataPackConfig) + "]");
cachedResources.close();
cachedResources = null;
cachedDataPackConfig = null;
}
} else {
ModernFix.LOGGER.error("Cached server resources were closed somehow, that shouldn't happen");
cachedResources = null;
}
}
return ServerResources.loadResources(list, arg, i, executor, executor2);
}
@Override
public void setCachedResources(ServerResources r) {
cachedResources = r;
}
@Override
public void setCachedDataPackConfig(Collection<String> c) {
cachedDataPackConfig = ImmutableList.copyOf(c);
}
@Inject(method = "setLevel", at = @At("HEAD"))
private void clearResourcesIfNotLocal(CallbackInfo ci) {
if(!this.isLocalServer())
cachedResources = null;
}
}

View File

@ -1,29 +0,0 @@
package org.embeddedt.modernfix.common.mixin.perf.reuse_datapacks;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerResources;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackRepository;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient;
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.Redirect;
@Mixin(MinecraftServer.class)
@ClientOnlyMixin
public class MinecraftServerMixin {
@Shadow @Final private PackRepository packRepository;
@Redirect(method = "stopServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;close()V"))
private void saveResources(ServerResources resources) {
ICachingResourceClient client = ((ICachingResourceClient) Minecraft.getInstance());
client.setCachedDataPackConfig(this.packRepository.getSelectedPacks().stream().map(Pack::getId).collect(ImmutableList.toImmutableList()));
client.setCachedResources(resources);
}
}

View File

@ -16,7 +16,7 @@ import java.util.Map;
@Mixin(StateDefinition.class)
@RequiresMod("ferritecore")
public class StateDefinitionMixin<O, S extends StateHolder<O, S>> {
public class StateDefinitionMixin<O, S extends StateHolder<S>> {
@Shadow @Final private ImmutableSortedMap<String, Property<?>> propertiesByName;
@ModifyVariable(method = "<init>", at = @At(value = "STORE", ordinal = 0), ordinal = 1, index = 8)

View File

@ -2,27 +2,32 @@ package org.embeddedt.modernfix.common.mixin.perf.thread_priorities;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import net.minecraft.client.Minecraft;
import net.minecraft.server.ServerResources;
import net.minecraft.server.packs.repository.PackRepository;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import com.mojang.datafixers.DataFixer;
import net.minecraft.client.server.IntegratedServer;
import net.minecraft.server.players.GameProfileCache;
import net.minecraft.core.RegistryAccess;
import net.minecraft.commands.Commands;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.world.level.storage.WorldData;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.server.players.GameProfileCache;
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;
import java.io.File;
import java.net.Proxy;
@Mixin(IntegratedServer.class)
@ClientOnlyMixin
public class IntegratedServerMixin {
public abstract class IntegratedServerMixin extends MinecraftServer {
public IntegratedServerMixin(File file, Proxy proxy, DataFixer dataFixer, Commands commands, YggdrasilAuthenticationService yggdrasilAuthenticationService, MinecraftSessionService minecraftSessionService, GameProfileRepository gameProfileRepository, GameProfileCache gameProfileCache, ChunkProgressListenerFactory chunkProgressListenerFactory, String string) {
super(file, proxy, dataFixer, commands, yggdrasilAuthenticationService, minecraftSessionService, gameProfileRepository, gameProfileCache, chunkProgressListenerFactory, string);
}
@Inject(method = "<init>", at = @At("RETURN"))
private void adjustServerPriority(Thread pServerThread, Minecraft pMinecraft, RegistryAccess.RegistryHolder pRegistryHolder, LevelStorageSource.LevelStorageAccess pStorageSource, PackRepository pPackRepository, ServerResources pResources, WorldData pWorldData, MinecraftSessionService pSessionService, GameProfileRepository pProfileRepository, GameProfileCache pProfileCache, ChunkProgressListenerFactory pProgressListenerfactory, CallbackInfo ci) {
private void adjustServerPriority(CallbackInfo ci) {
int pri = 4; //ModernFixConfig.INTEGRATED_SERVER_PRIORITY.get();
pServerThread.setPriority(pri);
this.serverThread.setPriority(pri);
}
}

View File

@ -10,7 +10,7 @@ import java.util.concurrent.ForkJoinWorkerThread;
@Mixin(Util.class)
public class UtilMixin {
@ModifyArg(method = "makeExecutor", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/ForkJoinPool;<init>(ILjava/util/concurrent/ForkJoinPool$ForkJoinWorkerThreadFactory;Ljava/lang/Thread$UncaughtExceptionHandler;Z)V"), index = 1)
@ModifyArg(method = "makeBackgroundExecutor", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/ForkJoinPool;<init>(ILjava/util/concurrent/ForkJoinPool$ForkJoinWorkerThreadFactory;Ljava/lang/Thread$UncaughtExceptionHandler;Z)V"), index = 1)
private static ForkJoinPool.ForkJoinWorkerThreadFactory adjustPriorityOfThreadFactory(ForkJoinPool.ForkJoinWorkerThreadFactory factory) {
return pool -> {
ForkJoinWorkerThread thread = factory.newThread(pool);

View File

@ -1,30 +0,0 @@
package org.embeddedt.modernfix.common.mixin.safety;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.client.renderer.item.ItemPropertyFunction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
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.callback.CallbackInfo;
import java.util.Collections;
import java.util.Map;
@Mixin(value = ItemProperties.class, priority = 700)
@ClientOnlyMixin
public class ItemPropertiesMixin {
@Shadow @Final @Mutable private static Map<ResourceLocation, ItemPropertyFunction> GENERIC_PROPERTIES;
@Shadow @Final @Mutable private static Map<Item, Map<ResourceLocation, ItemPropertyFunction>> PROPERTIES;
@Inject(method = "<clinit>", at = @At("RETURN"))
private static void useConcurrentMaps(CallbackInfo ci) {
GENERIC_PROPERTIES = Collections.synchronizedMap(GENERIC_PROPERTIES);
PROPERTIES = Collections.synchronizedMap(PROPERTIES);
}
}

View File

@ -182,7 +182,7 @@ public class ModernFixEarlyConfig {
.put("mixin.feature.spark_profile_launch", false)
.put("mixin.perf.blast_search_trees", shouldReplaceSearchTrees)
.put("mixin.devenv", isDevEnv)
.put("mixin.perf.remove_spawn_chunks", isDevEnv)
.put("mixin.perf.remove_spawn_chunks", false)
.putConditionally(() -> !isFabric, "mixin.bugfix.fix_config_crashes", true)
.putConditionally(() -> isFabric, "mixin.perf.clear_fabric_mapping_tables", false)
.build();

View File

@ -2,8 +2,8 @@ package org.embeddedt.modernfix.dfu;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.Dynamic;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.serialization.Dynamic;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@ -1,10 +0,0 @@
package org.embeddedt.modernfix.duck.reuse_datapacks;
import net.minecraft.server.ServerResources;
import java.util.Collection;
public interface ICachingResourceClient {
void setCachedResources(ServerResources r);
void setCachedDataPackConfig(Collection<String> c);
}

View File

@ -14,7 +14,7 @@ import it.unimi.dsi.fastutil.objects.ReferenceSet;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.resources.model.*;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.Pack;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.FallbackResourceManager;
import net.minecraft.server.packs.resources.Resource;
@ -90,8 +90,8 @@ public class ModelBakeryHelpers {
return parser.parse(jsonReader);
}
private static void gatherAdditionalViaManualScan(List<PackResources> untrustedPacks, Set<ResourceLocation> knownLocations,
Collection<ResourceLocation> uncertainLocations, String filePrefix) {
private static void gatherAdditionalViaManualScan(List<Pack> untrustedPacks, Set<ResourceLocation> knownLocations,
Collection<ResourceLocation> uncertainLocations, String filePrefix) {
if(untrustedPacks.size() > 0) {
/* Now make a fallback resource manager and use it on the remaining packs to see if they actually contain these files */
FallbackResourceManager frm = new FallbackResourceManager(PackType.CLIENT_RESOURCES, "dummy");
@ -126,10 +126,10 @@ public class ModelBakeryHelpers {
* main list contained inside the parent resource manager, so we need to scan each of the namespaced managers as
* well.
*/
private static void checkFallbacks(SimpleReloadableResourceManager manager, List<PackResources> resourcePackList) {
ReferenceSet<PackResources> knownPacks = new ReferenceOpenHashSet<>(resourcePackList);
private static void checkFallbacks(SimpleReloadableResourceManager manager, List<Pack> resourcePackList) {
ReferenceSet<Pack> knownPacks = new ReferenceOpenHashSet<>(resourcePackList);
Map<String, FallbackResourceManager> namespacedMap = manager.namespacedPacks;
namespacedMap.values().stream().flatMap(FallbackResourceManager::listPacks).forEach(pack -> {
namespacedMap.values().stream().flatMap(m -> getAllPacks(m).stream()).forEach(pack -> {
if(knownPacks.add(pack)) {
/* the pack was not previously known, add to our list */
ModernFix.LOGGER.debug("Injecting unlisted pack '{}': {}", pack.getName(), pack.getClass().getName());
@ -138,7 +138,17 @@ public class ModelBakeryHelpers {
});
}
public static void gatherModelMaterials(ResourceManager manager, Predicate<PackResources> isTrustedPack,
private static List<Pack> getAllPacks(ResourceManager manager) {
if (manager instanceof FallbackResourceManager) {
return ((FallbackResourceManager)manager).fallbacks;
} else if (manager instanceof SimpleReloadableResourceManager) {
return ((SimpleReloadableResourceManager)manager).namespacedPacks.values().stream().flatMap(m -> m.fallbacks.stream()).distinct().collect(Collectors.toList());
} else {
return ImmutableList.of();
}
}
public static void gatherModelMaterials(ResourceManager manager, Predicate<Pack> isTrustedPack,
Set<Material> materialSet, Set<ResourceLocation> blockStateFiles,
Set<ResourceLocation> modelFiles, UnbakedModel missingModel,
Function<JsonElement, BlockModel> modelDeserializer,
@ -151,19 +161,19 @@ public class ModelBakeryHelpers {
* First, gather all vanilla packs, and use listResources on them. This will allow us to (hopefully) avoid
* scanning most packs a lot.
*/
List<PackResources> allPackResources = new ArrayList<>(manager.listPacks().collect(Collectors.toList()));
List<Pack> allPack = new ArrayList<>(getAllPacks(manager));
if(manager instanceof SimpleReloadableResourceManager) {
checkFallbacks((SimpleReloadableResourceManager)manager, allPackResources);
checkFallbacks((SimpleReloadableResourceManager)manager, allPack);
}
Collections.reverse(allPackResources);
Collections.reverse(allPack);
ObjectOpenHashSet<ResourceLocation> allAvailableModels = new ObjectOpenHashSet<>(), allAvailableStates = new ObjectOpenHashSet<>();
/* try to fix CME in some runtime packs by forcing generation */
for(PackResources pack : allPackResources) {
for(Pack pack : allPack) {
try(InputStream stream = pack.getResource(PackType.CLIENT_RESOURCES, new ResourceLocation("modernfix", "dummy.json"))) {
} catch(Exception ignored) {
}
}
allPackResources.removeIf(pack -> {
allPack.removeIf(pack -> {
for(String namespace : pack.getNamespaces(PackType.CLIENT_RESOURCES)) {
Collection<ResourceLocation> allBlockstates = pack.getResources(PackType.CLIENT_RESOURCES, namespace, "blockstates", Integer.MAX_VALUE, p -> p.endsWith(".json"));
for(ResourceLocation blockstate : allBlockstates) {
@ -181,7 +191,7 @@ public class ModelBakeryHelpers {
return true;
});
gatherAdditionalViaManualScan(allPackResources, allAvailableStates, blockStateFiles, "blockstates/");
gatherAdditionalViaManualScan(allPack, allAvailableStates, blockStateFiles, "blockstates/");
// We now have a list of all blockstates known to exist. Delete anything that we don't have
blockStateFiles.retainAll(allAvailableStates);
allAvailableStates.clear();
@ -275,7 +285,7 @@ public class ModelBakeryHelpers {
modelFiles.addAll(allAvailableModels);
/* figure out which models we should actually load */
gatherAdditionalViaManualScan(allPackResources, allAvailableModels, modelFiles, "models/");
gatherAdditionalViaManualScan(allPack, allAvailableModels, modelFiles, "models/");
modelFiles.retainAll(allAvailableModels);
allAvailableModels.clear();
allAvailableModels.trim();

View File

@ -1,20 +0,0 @@
package org.embeddedt.modernfix.registry;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
public class LifecycleMap<T> extends Reference2ReferenceOpenHashMap<T, Lifecycle> {
public LifecycleMap() {
this.defaultReturnValue(Lifecycle.stable());
}
@Override
public Lifecycle put(T t, Lifecycle lifecycle) {
if(lifecycle != defRetValue)
return super.put(t, lifecycle);
else {
// need the duplicate containsKey/get logic here to override the default return value
return super.containsKey(t) ? super.get(t) : null;
}
}
}

View File

@ -95,7 +95,7 @@ public class PackResourcesCacheEngine {
if(str.length() == 0)
return false;
for(int i = 0; i < str.length(); i++) {
if(!ResourceLocation.validPathChar(str.charAt(i))) {
if(!ResourceLocation.isAllowedInResourceLocation(str.charAt(i))) {
return false;
}
}

View File

@ -1,11 +1,9 @@
package org.embeddedt.modernfix.screen;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.Util;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.*;
import org.jetbrains.annotations.Nullable;
public class ModernFixConfigScreen extends Screen {
private OptionList optionList;
@ -25,10 +23,10 @@ public class ModernFixConfigScreen extends Screen {
this.optionList = new OptionList(this, this.minecraft);
this.optionList.setScrollAmount(lastScrollAmount);
this.children.add(this.optionList);
this.wikiButton = new Button(this.width / 2 - 155, this.height - 29, 150, 20, new TranslatableComponent("modernfix.config.wiki"), (arg) -> {
this.wikiButton = new Button(this.width / 2 - 155, this.height - 29, 150, 20, new TranslatableComponent("modernfix.config.wiki").getString(), (arg) -> {
Util.getPlatform().openUri("https://github.com/embeddedt/ModernFix/wiki/Summary-of-Patches");
});
this.doneButton = new Button(this.width / 2 - 155 + 160, this.height - 29, 150, 20, CommonComponents.GUI_DONE, (arg) -> {
this.doneButton = new Button(this.width / 2 - 155 + 160, this.height - 29, 150, 20, "Done", (arg) -> {
this.onClose();
});
this.addButton(this.wikiButton);
@ -41,17 +39,12 @@ public class ModernFixConfigScreen extends Screen {
}
@Override
public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTicks) {
this.renderBackground(poseStack);
this.optionList.render(poseStack, mouseX, mouseY, partialTicks);
drawCenteredString(poseStack, this.font, this.title, this.width / 2, 8, 16777215);
this.doneButton.setMessage(madeChanges ? new TranslatableComponent("modernfix.config.done_restart") : CommonComponents.GUI_DONE);
super.render(poseStack, mouseX, mouseY, partialTicks);
}
@Override
public void renderComponentHoverEffect(PoseStack matrixStack, @Nullable Style style, int mouseX, int mouseY) {
super.renderComponentHoverEffect(matrixStack, style, mouseX, mouseY);
public void render(int mouseX, int mouseY, float partialTicks) {
this.renderBackground();
this.optionList.render(mouseX, mouseY, partialTicks);
drawCenteredString(this.font, this.title.getString(), this.width / 2, 8, 16777215);
this.doneButton.setMessage(madeChanges ? new TranslatableComponent("modernfix.config.done_restart").getString() : "Done");
super.render(mouseX, mouseY, partialTicks);
}
public void setLastScrollAmount(double d) {

View File

@ -1,14 +1,11 @@
package org.embeddedt.modernfix.screen;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.util.FormattedCharSequence;
public class ModernFixOptionInfoScreen extends Screen {
private final Screen lastScreen;
@ -24,7 +21,7 @@ public class ModernFixOptionInfoScreen extends Screen {
@Override
protected void init() {
super.init();
this.addButton(new Button(this.width / 2 - 100, this.height - 29, 200, 20, CommonComponents.GUI_DONE, (button) -> {
this.addButton(new Button(this.width / 2 - 100, this.height - 29, 200, 20, "Done", (button) -> {
this.onClose();
}));
}
@ -34,18 +31,18 @@ public class ModernFixOptionInfoScreen extends Screen {
this.minecraft.setScreen(lastScreen);
}
private void drawMultilineString(PoseStack mStack, Font fr, Component str, int x, int y) {
for(FormattedCharSequence s : fr.split(str, this.width - 50)) {
fr.drawShadow(mStack, s, (float)x, (float)y, 16777215);
private void drawMultilineString(Font fr, Component str, int x, int y) {
for(String s : fr.split(str.getString(), this.width - 50)) {
fr.drawShadow(s, (float)x, (float)y, 16777215);
y += fr.lineHeight;
}
}
@Override
public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTicks) {
this.renderBackground(poseStack);
drawCenteredString(poseStack, this.font, this.title, this.width / 2, 8, 16777215);
this.drawMultilineString(poseStack, this.minecraft.font, description, 10, 50);
super.render(poseStack, mouseX, mouseY, partialTicks);
public void render(int mouseX, int mouseY, float partialTicks) {
this.renderBackground();
drawCenteredString(this.font, this.title.getString(), this.width / 2, 8, 16777215);
this.drawMultilineString(this.minecraft.font, description, 10, 50);
super.render(mouseX, mouseY, partialTicks);
}
}

View File

@ -2,7 +2,6 @@ package org.embeddedt.modernfix.screen;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
@ -25,18 +24,18 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
private static final int DEPTH_OFFSET = 20;
private static final Component OPTION_ON = new TranslatableComponent("modernfix.option.on").withStyle(style -> style.withColor(ChatFormatting.GREEN));
private static final Component OPTION_OFF = new TranslatableComponent("modernfix.option.off").withStyle(style -> style.withColor(ChatFormatting.RED));
private static final Component OPTION_ON = new TranslatableComponent("modernfix.option.on").withStyle(style -> style.setColor(ChatFormatting.GREEN));
private static final Component OPTION_OFF = new TranslatableComponent("modernfix.option.off").withStyle(style -> style.setColor(ChatFormatting.RED));
private static final Set<String> OPTIONS_MISSING_HELP = new HashSet<>();
private ModernFixConfigScreen mainScreen;
private static MutableComponent getOptionComponent(Option option) {
private static BaseComponent getOptionComponent(Option option) {
String friendlyKey = "modernfix.option.name." + option.getName();
TextComponent baseComponent = new TextComponent(option.getSelfName());
if(I18n.exists(friendlyKey))
return new TranslatableComponent(friendlyKey).withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, baseComponent)));
return new TranslatableComponent(friendlyKey);
else
return baseComponent;
}
@ -53,7 +52,7 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
private void addOption(Option option) {
if(addedOptions.add(option)) {
int w = this.minecraft.font.width(getOptionComponent(option)) + DEPTH_OFFSET * option.getDepth();
int w = this.minecraft.font.width(getOptionComponent(option).getString()) + DEPTH_OFFSET * option.getDepth();
this.maxNameWidth = Math.max(w, this.maxNameWidth);
this.addEntry(new OptionEntry(option.getName(), option));
ModernFixMixinPlugin.instance.config.getOptionMap().values().stream()
@ -73,7 +72,6 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
for(String category : theCategories) {
String categoryTranslationKey = "modernfix.option.category." + category;
this.addEntry(new CategoryEntry(new TranslatableComponent(categoryTranslationKey)
.withStyle(Style.EMPTY.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TranslatableComponent(categoryTranslationKey + ".description"))))
));
optionsByCategory.get(category).stream().filter(key -> {
int dotCount = 0;
@ -100,16 +98,14 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
public CategoryEntry(Component component) {
this.name = component;
this.width = OptionList.this.minecraft.font.width(this.name);
this.width = OptionList.this.minecraft.font.width(this.name.getString());
}
public void render(PoseStack matrixStack, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTicks) {
public void render(int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTicks) {
Font var10000 = OptionList.this.minecraft.font;
float x = (float)(OptionList.this.minecraft.screen.width / 2 - this.width / 2);
int y = top + height - 10;
var10000.draw(matrixStack, this.name, x, y, 16777215);
if(mouseX >= x && mouseY >= y && mouseX <= (x + this.width) && mouseY <= (y + OptionList.this.minecraft.font.lineHeight))
OptionList.this.mainScreen.renderComponentHoverEffect(matrixStack, this.name.getStyle(), mouseX, mouseY);
var10000.draw(this.name.getString(), x, y, 16777215);
}
public boolean changeFocus(boolean focus) {
@ -131,7 +127,7 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
public OptionEntry(String optionName, Option option) {
this.name = optionName;
this.option = option;
this.toggleButton = new Button(0, 0, 55, 20, new TextComponent(""), (arg) -> {
this.toggleButton = new Button(0, 0, 55, 20, new TextComponent("").toString(), (arg) -> {
this.option.setEnabled(!this.option.isEnabled(), !this.option.isUserDefined());
try {
ModernFixMixinPlugin.instance.config.save();
@ -144,20 +140,9 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
ModernFix.LOGGER.error("Unable to save config", e);
}
OptionList.this.updateOptionEntryStatuses();
}, (btn, gfx, x, y) -> {
if(this.option.isModDefined()) {
String disablingMods = String.join(", ", this.option.getDefiningMods());
OptionList.this.mainScreen.renderTooltip(
gfx,
new TranslatableComponent("modernfix.option." + (this.option.isEnabled() ? "enabled" : "disabled"))
.append(new TranslatableComponent("modernfix.option.mod_override", disablingMods)),
x,
y
);
}
});
updateStatus();
this.helpButton = new Button(75, 0, 20, 20, new TextComponent("?"), (arg) -> {
this.helpButton = new Button(75, 0, 20, 20, new TextComponent("?").getString(), (arg) -> {
mainScreen.setLastScrollAmount(getScrollAmount());
Minecraft.getInstance().setScreen(new ModernFixOptionInfoScreen(mainScreen, optionName));
});
@ -173,22 +158,20 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
}
@Override
public void render(PoseStack matrixStack, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTicks) {
MutableComponent nameComponent = getOptionComponent(option);
public void render(int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTicks) {
BaseComponent nameComponent = getOptionComponent(option);
if(this.option.isUserDefined())
nameComponent = nameComponent.withStyle(style -> style.withItalic(true)).append(new TranslatableComponent("modernfix.config.not_default"));
nameComponent = (BaseComponent) nameComponent.withStyle(style -> style.setItalic(true)).append(new TranslatableComponent("modernfix.config.not_default"));
float textX = (float)(left + DEPTH_OFFSET * option.getDepth() + 160 - OptionList.this.maxNameWidth);
float textY = (float)(top + height / 2 - 4);
OptionList.this.minecraft.font.draw(matrixStack, nameComponent, textX, textY, 16777215);
OptionList.this.minecraft.font.draw(nameComponent.getString(), textX, textY, 16777215);
this.toggleButton.x = left + 175;
this.toggleButton.y = top;
this.toggleButton.setMessage(getOptionMessage(this.option));
this.toggleButton.render(matrixStack, mouseX, mouseY, partialTicks);
this.toggleButton.setMessage(getOptionMessage(this.option).getString());
this.toggleButton.render(mouseX, mouseY, partialTicks);
this.helpButton.x = left + 175 + 55;
this.helpButton.y = top;
this.helpButton.render(matrixStack, mouseX, mouseY, partialTicks);
if(mouseX >= textX && mouseY >= textY && mouseX <= (textX + OptionList.this.maxNameWidth) && mouseY <= (textY + OptionList.this.minecraft.font.lineHeight))
OptionList.this.mainScreen.renderComponentHoverEffect(matrixStack, nameComponent.getStyle(), mouseX, mouseY);
this.helpButton.render(mouseX, mouseY, partialTicks);
}
private Component getOptionMessage(Option option) {

View File

@ -98,7 +98,7 @@ public class CachingStructureManager {
private static synchronized CompoundTag getCachedUpgraded(ResourceLocation location, String hash) {
File theFile = getCachePath(location, hash);
try {
return NbtIo.readCompressed(theFile);
return NbtIo.readCompressed(new FileInputStream(theFile));
} catch(FileNotFoundException e) {
return null;
} catch(IOException e) {
@ -110,7 +110,7 @@ public class CachingStructureManager {
private static synchronized void saveCachedUpgraded(ResourceLocation location, String hash, CompoundTag tagToSave) {
File theFile = getCachePath(location, truncateHash(hash));
try {
NbtIo.writeCompressed(tagToSave, theFile);
NbtIo.writeCompressed(tagToSave, new FileOutputStream(theFile));
} catch(IOException e) {
e.printStackTrace();
}

View File

@ -1,148 +1,6 @@
package org.embeddedt.modernfix.util;
import com.google.common.collect.ImmutableSet;
import com.mojang.serialization.Lifecycle;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.DataPackConfig;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.Difficulty;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.storage.WorldData;
import net.minecraft.world.level.storage.ServerLevelData;
import java.util.Set;
public class DummyServerConfiguration {
public class DummyServerConfiguration implements WorldData {
@Override
public DataPackConfig getDataPackConfig() {
return DataPackConfig.DEFAULT;
}
@Override
public void setDataPackConfig(DataPackConfig codec) {
}
@Override
public boolean wasModded() {
return true;
}
@Override
public Set<String> getKnownServerBrands() {
return ImmutableSet.of("forge");
}
@Override
public void setModdedInfo(String name, boolean isModded) {
}
@Override
public CompoundTag getCustomBossEvents() {
return null;
}
@Override
public void setCustomBossEvents(CompoundTag nbt) {
}
@Override
public ServerLevelData overworldData() {
return null;
}
@Override
public LevelSettings getLevelSettings() {
return null;
}
@Override
public CompoundTag createTag(RegistryAccess registries, CompoundTag hostPlayerNBT) {
return null;
}
@Override
public boolean isHardcore() {
return false;
}
@Override
public int getVersion() {
return 0;
}
@Override
public String getLevelName() {
return null;
}
@Override
public GameType getGameType() {
return null;
}
@Override
public void setGameType(GameType type) {
}
@Override
public boolean getAllowCommands() {
return false;
}
@Override
public Difficulty getDifficulty() {
return null;
}
@Override
public void setDifficulty(Difficulty difficulty) {
}
@Override
public boolean isDifficultyLocked() {
return false;
}
@Override
public void setDifficultyLocked(boolean locked) {
}
@Override
public GameRules getGameRules() {
return null;
}
@Override
public CompoundTag getLoadedPlayerTag() {
return null;
}
@Override
public CompoundTag endDragonFightData() {
return null;
}
@Override
public void setEndDragonFightData(CompoundTag nbt) {
}
@Override
public WorldGenSettings worldGenSettings() {
return null;
}
@Override
public Lifecycle worldGenSettingsLifecycle() {
return Lifecycle.stable();
}
}

View File

@ -12,7 +12,7 @@ import java.util.List;
public class StrongholdLocationCache extends SavedData {
private List<ChunkPos> chunkPosList;
public StrongholdLocationCache(ServerLevel level) {
super(getFileId(level.dimensionType()));
super(getFileId(level.dimension.getType()));
chunkPosList = new ArrayList<>();
}

View File

@ -10,10 +10,8 @@ accessible class net/minecraft/client/renderer/RenderType$CompositeRenderType
accessible method net/minecraft/client/renderer/RenderType$CompositeRenderType <init> (Ljava/lang/String;Lcom/mojang/blaze3d/vertex/VertexFormat;IIZZLnet/minecraft/client/renderer/RenderType$CompositeState;)V
accessible method net/minecraft/nbt/CompoundTag <init> (Ljava/util/Map;)V
accessible class net/minecraft/client/Minecraft$ExperimentalDialogType
accessible class net/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase$Cache
accessible class net/minecraft/world/level/block/state/BlockState$Cache
accessible class net/minecraft/server/level/ServerChunkCache$MainThreadExecutor
accessible field net/minecraft/world/level/block/state/BlockBehaviour properties Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;
accessible class net/minecraft/client/renderer/block/model/BlockElementFace$Deserializer
accessible class net/minecraft/client/renderer/texture/Stitcher$Holder
accessible field net/minecraft/client/renderer/texture/Stitcher$Holder width I
@ -24,17 +22,15 @@ accessible class net/minecraft/client/resources/model/ModelBakery$BlockStateDefi
accessible field net/minecraft/network/syncher/SynchedEntityData itemsById Ljava/util/Map;
accessible field net/minecraft/network/syncher/SynchedEntityData ENTITY_ID_POOL Ljava/util/Map;
accessible field net/minecraft/network/syncher/SynchedEntityData lock Ljava/util/concurrent/locks/ReadWriteLock;
accessible method net/minecraft/Util makeExecutor (Ljava/lang/String;)Ljava/util/concurrent/ExecutorService;
accessible field net/minecraft/server/level/ChunkMap updatingChunkMap Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/server/level/ChunkMap visibleChunkMap Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/server/level/ChunkMap pendingUnloads Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
accessible field net/minecraft/client/Minecraft reserve [B
accessible method net/minecraft/resources/ResourceKey <init> (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)V
accessible method net/minecraft/client/renderer/texture/TextureAtlasSprite <init> (Lnet/minecraft/client/renderer/texture/TextureAtlas;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIIILcom/mojang/blaze3d/platform/NativeImage;)V
accessible field net/minecraft/client/renderer/block/model/BlockModel GSON Lcom/google/gson/Gson;
accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/ServerResources;
accessible field net/minecraft/client/renderer/RenderStateShard name Ljava/lang/String;
accessible method net/minecraft/client/gui/screens/Screen addButton (Lnet/minecraft/client/gui/components/AbstractWidget;)Lnet/minecraft/client/gui/components/AbstractWidget;
accessible field net/minecraft/server/packs/resources/SimpleReloadableResourceManager namespacedPacks Ljava/util/Map;
accessible field net/minecraft/client/renderer/entity/EnderDragonRenderer$DragonModel entity Lnet/minecraft/world/entity/boss/enderdragon/EnderDragon;
accessible method net/minecraft/world/level/block/state/StateDefinition appendPropertyCodec (Lcom/mojang/serialization/MapCodec;Ljava/util/function/Supplier;Ljava/lang/String;Lnet/minecraft/world/level/block/state/properties/Property;)Lcom/mojang/serialization/MapCodec;
accessible field net/minecraft/server/packs/resources/FallbackResourceManager fallbacks Ljava/util/List;

View File

@ -32,7 +32,7 @@ dependencies {
include(implementation(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-screen-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
modCompileOnly(fabricApi.module("fabric-command-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
modCompileOnly(fabricApi.module("fabric-models-v0", rootProject.fabric_api_version)) { 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' }

View File

@ -2,13 +2,13 @@ package org.embeddedt.modernfix.fabric.bridge;
import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import java.util.function.Consumer;
public class ModelV0Bridge {
public static void populate(Consumer<ResourceLocation> modelConsumer, ModelBakery bakery, ResourceManager manager) {
public static void populate(Consumer<ModelResourceLocation> modelConsumer, ModelBakery bakery, ResourceManager manager) {
ModelLoadingRegistryImpl.LoaderInstance instance = ModelLoadingRegistryImpl.begin(bakery, manager);
instance.onModelPopulation(modelConsumer);
instance.finish();

View File

@ -11,7 +11,7 @@ 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))
@Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getMillis()J", ordinal = 0))
private void markServerStarted(CallbackInfo ci) {
ModernFixClient.INSTANCE.onServerStarted((MinecraftServer)(Object)this);
}

View File

@ -12,12 +12,12 @@ import java.lang.ref.WeakReference;
@Mixin(MinecraftServer.class)
public class MinecraftServerMixin {
@Inject(method = "runServer", at = @At("HEAD"))
@Inject(method = "run", 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))
@Inject(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getMillis()J", ordinal = 0))
private void hookServerStarted(CallbackInfo ci) {
ModernFix.INSTANCE.onServerStarted();
}

View File

@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public class MinecraftMixin_Fabric {
@Inject(method = "doLoadLevel", at = @At("HEAD"))
@Inject(method = "selectLevel", at = @At("HEAD"))
private void recordWorldLoadStart(CallbackInfo ci) {
ModernFixClient.worldLoadStartTime = System.nanoTime();
}

View File

@ -20,10 +20,10 @@ import net.minecraft.client.resources.ClientPackSource;
import net.minecraft.client.resources.model.*;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.FilePackResources;
import net.minecraft.server.packs.FolderPackResources;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.VanillaPackResources;
import net.minecraft.server.packs.FileResourcePack;
import net.minecraft.server.packs.FolderResourcePack;
import net.minecraft.server.packs.Pack;
import net.minecraft.server.packs.VanillaPack;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.block.Block;
@ -231,11 +231,11 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
}
}
private boolean trustedResourcePack(PackResources pack) {
return pack instanceof VanillaPackResources ||
private boolean trustedResourcePack(Pack pack) {
return pack instanceof VanillaPack ||
pack instanceof ClientPackSource ||
pack instanceof FolderPackResources ||
pack instanceof FilePackResources;
pack instanceof FolderResourcePack ||
pack instanceof FileResourcePack;
}
/**

View File

@ -1,7 +1,7 @@
package org.embeddedt.modernfix.fabric.modmenu;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import io.github.prospector.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi;
import org.embeddedt.modernfix.screen.ModernFixConfigScreen;
@SuppressWarnings("unused")

View File

@ -41,7 +41,7 @@
"modernfix-common.mixins.json"
],
"depends": {
"minecraft": ">=1.16.2"
"minecraft": "1.15.2"
},
"breaks": {
"dashloader": "*"

View File

@ -55,7 +55,7 @@ dependencies {
modCompileOnly("curse.maven:refinedstorage-243076:${refined_storage_version}")
modCompileOnly("dev.latvian.mods:kubejs-forge:${kubejs_version}")
modCompileOnly("curse.maven:kubejs-238086:3103858")
modCompileOnly("curse.maven:jeresources-240630:3545538")
modCompileOnly("curse.maven:jepb-437558:3172880")
modCompileOnly("curse.maven:babel-436964:3196072")

View File

@ -1,7 +1,6 @@
package org.embeddedt.modernfix.forge.classloading;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Multimap;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.LoadingModList;
@ -19,8 +18,6 @@ import org.embeddedt.modernfix.util.FileUtil;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
@ -90,26 +87,4 @@ public class ModernFixResourceFinder {
} else
throw new UnsupportedOperationException("Unknown ModLocator type: " + locator.getClass().getName());
}
public static Enumeration<URL> findAllURLsForResource(String input) {
// fallback to Forge impl for any paths ending in a slash
char endChar = input.length() > 0 ? input.charAt(input.length() - 1) : '/';
if(endChar == '/' || endChar == '\\') {
return LoadingModList.get().findAllURLsForResource(input);
}
// CachedResourcePath normalizes already
Collection<String> urlList = urlsForClass.get(new CachedResourcePath(input));
if(!urlList.isEmpty()) {
String pathInput = FileUtil.normalize(input);
return Iterators.asEnumeration(urlList.stream().map(modId -> {
try {
return new URL("modjar://" + modId + "/" + pathInput);
} catch(MalformedURLException e) {
throw new RuntimeException(e);
}
}).iterator());
} else {
return Collections.emptyEnumeration();
}
}
}

View File

@ -1,78 +0,0 @@
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.TextComponent;
import net.minecraft.server.packs.resources.SimpleReloadableResourceManager;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DatagenModLoader;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import org.embeddedt.modernfix.ModernFix;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
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 */
((SimpleReloadableResourceManager)ObfuscationReflectionHelper.getPrivateValue(ExistingFileHelper.class, existingFileHelper, "clientResources")).add(Minecraft.getInstance().getClientPackSource().getVanillaPack());
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(GuiScreenEvent.InitGuiEvent.Post event) {
if(isDatagenAvailable() && event.getGui() instanceof TitleScreen) {
TitleScreen screen = (TitleScreen)event.getGui();
screen.addButton(new Button(screen.width / 2 - 100 - 50, screen.height / 4 + 48, 50, 20, new TextComponent("DG"), (arg) -> {
runRuntimeDatagen();
}));
}
}
}

View File

@ -47,7 +47,7 @@ public class ModernFixClientForge {
ClientRegistry.registerKeyBinding(configKey);
if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.dynamic_resources.ConnectednessCheck")
&& ModList.get().isLoaded("connectedness")) {
event.enqueueWork(() -> {
DeferredWorkQueue.runLater(() -> {
ModLoader.get().addWarning(new ModLoadingWarning(ModLoadingContext.get().getActiveContainer().getModInfo(), ModLoadingStage.SIDED_SETUP, "modernfix.connectedness_dynresoruces"));
});
}

View File

@ -6,8 +6,6 @@ import net.minecraft.commands.CommandSourceStack;
import net.minecraft.world.item.Item;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.OnDatapackSyncEvent;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@ -16,16 +14,15 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.network.FMLNetworkConstants;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.tuple.Pair;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler;
import org.embeddedt.modernfix.forge.ModernFixConfig;
import org.embeddedt.modernfix.forge.classloading.ClassLoadHack;
import org.embeddedt.modernfix.forge.classloading.ModFileScanDataDeduplicator;
@ -46,24 +43,24 @@ public class ModernFixForge {
commonMod = new ModernFix();
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onCommandRegister);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup);
FMLJavaModLoadingContext.get().getModEventBus().addGenericListener(Item.class, this::registerItems);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClientForge()));
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
if(ModList.get().isLoaded("kubejs"))
MinecraftForge.EVENT_BUS.register(KubeUtil.class);
FMLJavaModLoadingContext.get().getModEventBus().register(KubeUtil.class);
PacketHandler.register();
ModFileScanDataDeduplicator.deduplicate();
ClassLoadHack.loadModClasses();
ConfigFixer.replaceConfigHandlers();
}
@SubscribeEvent
public void onCommandRegister(RegisterCommandsEvent event) {
public void onCommandRegister(FMLServerStartingEvent event) {
// Register separate commands since redirecting doesn't work without arguments
for(String name : new String[] { "mfrc", "mfsrc"}) {
event.getDispatcher().register(LiteralArgumentBuilder.<CommandSourceStack>literal(name)
event.getCommandDispatcher().register(LiteralArgumentBuilder.<CommandSourceStack>literal(name)
.requires(source -> source.hasPermission(3))
.executes(context -> {
NightConfigFixer.runReloads();
@ -72,15 +69,6 @@ public class ModernFixForge {
}
}
@SubscribeEvent
public void onDatapackSync(OnDatapackSyncEvent event) {
if(event.getPlayer() != null) {
if(!ServerLifecycleHooks.getCurrentServer().isDedicatedServer() && event.getPlayerList().getPlayerCount() == 0)
return;
EntityDataIDSyncHandler.onDatapackSyncEvent(event.getPlayer());
}
}
private void registerItems(RegistryEvent<Item> event) {
if(Boolean.getBoolean("modernfix.largeRegistryTest")) {
Item.Properties props = new Item.Properties();
@ -98,7 +86,7 @@ public class ModernFixForge {
@SubscribeEvent
public void commonSetup(FMLCommonSetupEvent event) {
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.warn_missing_perf_mods.Warnings")) {
event.enqueueWork(() -> {
DeferredWorkQueue.runLater(() -> {
boolean atLeastOneWarning = false;
for(Pair<List<String>, String> warning : MOD_WARNINGS) {
boolean isPresent = !FMLLoader.isProduction() || warning.getLeft().stream().anyMatch(name -> ModList.get().isLoaded(name));

View File

@ -1,7 +1,5 @@
package org.embeddedt.modernfix.forge.load;
import net.minecraftforge.fml.ModWorkManager;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.TimeUnit;
@ -40,6 +38,7 @@ public class ModWorkManagerQueue extends ConcurrentLinkedDeque<Runnable> {
@SuppressWarnings({"unchecked", "rawtypes"})
public static void replace() {
/*
try {
Class<?> syncExecutorClass = Class.forName("net.minecraftforge.fml.ModWorkManager$SyncExecutor");
ConcurrentLinkedDeque<Runnable> taskQueue = (ConcurrentLinkedDeque<Runnable>)ObfuscationReflectionHelper.getPrivateValue((Class)syncExecutorClass, (Object)ModWorkManager.syncExecutor(), "tasks");
@ -54,5 +53,7 @@ public class ModWorkManagerQueue extends ConcurrentLinkedDeque<Runnable> {
} catch(ReflectiveOperationException e) {
e.printStackTrace();
}
*/
}
}

View File

@ -4,7 +4,7 @@ import com.stal111.valhelsia_structures.init.ModBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.spongepowered.asm.mixin.Mixin;
@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 900)
@Mixin(value = BlockState.class, priority = 900)
@RequiresMod("valhelsia_structures")
public abstract class BlockStateBaseMixin {
@Shadow public abstract Block getBlock();

View File

@ -45,7 +45,7 @@ public class ChunkMapMixin {
for (ClassInstanceMultiMap<Entity> entitySection : entitySections) {
if(entitySection == null)
continue;
for (Entity entity : entitySection.getAllInstances()) {
for (Entity entity : entitySection) {
if (!(entity instanceof Player) && !this.level.loadFromChunk(entity)) {
if (list == null) {
list = Lists.newArrayList(entity);

View File

@ -1,20 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.bugfix.file_dialog_title;
import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent;
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.ModifyArg;
@Mixin(WorldGenSettingsComponent.class)
@ClientOnlyMixin
public class WorldGenSettingsComponentMixin {
/**
* @author embeddedt
* @reason Do not provide resource pack-controlled string to TinyFD
*/
@ModifyArg(method = "*", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/tinyfd/TinyFileDialogs;tinyfd_openFileDialog(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Lorg/lwjgl/PointerBuffer;Ljava/lang/CharSequence;Z)Ljava/lang/String;", remap = false), index = 0)
private CharSequence sanitizeTitleString(CharSequence original) {
return "Select settings file (.json)";
}
}

View File

@ -1,47 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.bugfix.recipe_book_type_desync;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.stats.RecipeBookSettings;
import net.minecraft.world.inventory.RecipeBookType;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.forge.packet.NetworkUtils;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@Mixin(RecipeBookSettings.class)
@ClientOnlyMixin
public class RecipeBookSettingsMixin {
private static int mfix$maxVanillaOrdinal;
static {
int ord = 0;
for(Field f : RecipeBookType.class.getDeclaredFields()) {
if(RecipeBookType.class.isAssignableFrom(f.getType()) && Modifier.isStatic(f.getModifiers()) && Modifier.isPublic(f.getModifiers())) {
try {
f.setAccessible(true);
RecipeBookType type = (RecipeBookType)f.get(null);
ord = Math.max(type.ordinal(), ord);
} catch(Exception e) {
e.printStackTrace();
ord = Integer.MAX_VALUE - 1;
break;
}
}
}
mfix$maxVanillaOrdinal = ord;
}
@Redirect(method = "read(Lnet/minecraft/network/FriendlyByteBuf;)Lnet/minecraft/stats/RecipeBookSettings;", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/FriendlyByteBuf;readBoolean()Z"))
private static boolean useDefaultBooleanIfVanilla(FriendlyByteBuf buf, @Local(ordinal = 0) RecipeBookType type) {
if(type.ordinal() >= (mfix$maxVanillaOrdinal + 1) && NetworkUtils.isCurrentlyVanilla) {
ModernFix.LOGGER.warn("Not reading recipe book data for type '{}' as we are using vanilla connection", type.name());
return false; // skip actually reading buffer
}
return buf.readBoolean();
}
}

View File

@ -1,33 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.bugfix.remove_block_chunkloading;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.RemoveBlockGoal;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.event.ForgeEventFactory;
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.Redirect;
@Mixin(RemoveBlockGoal.class)
public class RemoveBlockGoalMixin {
@Shadow @Final private Mob removerMob;
@Redirect(method = "canUse", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/common/ForgeHooks;canEntityDestroy(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/LivingEntity;)Z"))
private boolean fireGriefingEvent(Level level, BlockPos pos, LivingEntity entity) {
return ForgeEventFactory.getMobGriefingEvent(level, entity);
}
@Redirect(method = "isValidTarget", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z"))
private boolean checkBlockValidDestroyTarget(BlockState state, Block desiredBlock, LevelReader level, BlockPos pos) {
if(!(state.canEntityDestroy(level, pos, this.removerMob) && ForgeEventFactory.onEntityDestroyBlock(this.removerMob, pos, state)))
return false;
return state.is(desiredBlock);
}
}

View File

@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
@ClientOnlyMixin
public class MinecraftMixin_Forge {
@Inject(method = "loadWorld", at = @At("HEAD"), remap = false)
@Inject(method = "selectLevel", at = @At("HEAD"))
private void recordWorldLoadStart(CallbackInfo ci) {
ModernFixClient.worldLoadStartTime = System.nanoTime();
}

View File

@ -1,115 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.helpers.IModIdHelper;
import mezz.jei.config.*;
import mezz.jei.config.sorting.RecipeCategorySortingConfig;
import mezz.jei.events.EventBusHelper;
import mezz.jei.events.PlayerJoinedWorldEvent;
import mezz.jei.gui.textures.Textures;
import mezz.jei.ingredients.IIngredientSorter;
import mezz.jei.startup.ClientLifecycleHandler;
import mezz.jei.startup.JeiStarter;
import mezz.jei.startup.NetworkHandler;
import net.minecraft.client.Minecraft;
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.jei.async.JEILoadingInterruptedException;
import org.embeddedt.modernfix.jei.async.JEIReloadThread;
import org.embeddedt.modernfix.forge.util.JEIUtil;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
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;
import java.util.List;
@Mixin(ClientLifecycleHandler.class)
@RequiresMod("jei")
@ClientOnlyMixin
public class ClientLifecycleHandlerMixin {
@Shadow(remap = false) @Final private JeiStarter starter;
@Shadow(remap = false) @Final private List<IModPlugin> plugins;
@Shadow(remap = false) @Final private Textures textures;
@Shadow(remap = false) @Final private IClientConfig clientConfig;
@Shadow(remap = false) @Final private IEditModeConfig editModeConfig;
@Shadow(remap = false) @Final private IngredientFilterConfig ingredientFilterConfig;
@Shadow(remap = false) @Final private WorldConfig worldConfig;
@Shadow(remap = false) @Final private BookmarkConfig bookmarkConfig;
@Shadow(remap = false) @Final private IModIdHelper modIdHelper;
@Shadow(remap = false) @Final private RecipeCategorySortingConfig recipeCategorySortingConfig;
@Shadow(remap = false) @Final private IIngredientSorter ingredientSorter;
private volatile JEIReloadThread reloadThread = null;
@Inject(method = "setupJEI", at = @At(value = "INVOKE", target = "Lmezz/jei/startup/ClientLifecycleHandler;startJEI()V"), cancellable = true, remap = false)
private void startAsync(CallbackInfo ci) {
ci.cancel();
startJEIAsync(() -> Minecraft.getInstance().execute(() -> EventBusHelper.post(new PlayerJoinedWorldEvent())));
}
/**
* @author embeddedt
* @reason force JEI starts to be asynchronous
*/
@Overwrite(remap = false)
public void startJEI() {
startJEIAsync(() -> {});
}
@Inject(method = "<init>", at = @At("TAIL"))
private void setupCancellationHandler(NetworkHandler networkHandler, Textures textures, CallbackInfo ci) {
EventBusHelper.addListener(this, ClientPlayerNetworkEvent.LoggedOutEvent.class, event -> cancelPreviousStart());
JEIUtil.registerLoadingRenderer(() -> reloadThread != null);
}
private void cancelPreviousStart() {
JEIReloadThread currentReloadThread = reloadThread;
if(currentReloadThread != null) {
currentReloadThread.requestStop();
if(currentReloadThread.isAlive()) {
ModernFix.LOGGER.warn("Blocking until JEI thread terminates");
Minecraft.getInstance().managedBlock(() -> !currentReloadThread.isAlive());
}
reloadThread = null;
}
}
private static int numReloads = 1;
private void startJEIAsync(Runnable whenFinishedCb) {
cancelPreviousStart();
if(Minecraft.getInstance().level == null)
return;
ModernFix.LOGGER.info("Starting new JEI thread.");
JEIReloadThread newThread = new JEIReloadThread(() -> {
if(((JEIReloadThread)Thread.currentThread()).isStopRequested())
return;
try {
starter.start(
plugins,
textures,
clientConfig,
editModeConfig,
ingredientFilterConfig,
worldConfig,
bookmarkConfig,
modIdHelper,
recipeCategorySortingConfig,
ingredientSorter);
} catch(JEILoadingInterruptedException e) {
ModernFix.LOGGER.warn("JEI loading interrupted prematurely (this is normal)");
}
whenFinishedCb.run();
reloadThread = null;
}, "ModernFix JEI Reload Thread " + numReloads++);
newThread.setPriority(Thread.MIN_PRIORITY);
reloadThread = newThread;
newThread.start();
}
}

View File

@ -1,24 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import mezz.jei.api.ingredients.IIngredientType;
import mezz.jei.api.runtime.IIngredientManager;
import mezz.jei.gui.ingredients.IIngredientListElement;
import mezz.jei.ingredients.IngredientListElementFactory;
import net.minecraft.core.NonNullList;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.jei.async.IAsyncJeiStarter;
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(IngredientListElementFactory.class)
@RequiresMod("jei")
public class IngredientListElementFactoryMixin {
private static int ingredientNum = 0;
@Inject(method = "addToBaseList", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/NonNullList;add(Ljava/lang/Object;)Z"))
private static void checkForInterrupt(NonNullList<IIngredientListElement<?>> baseList, IIngredientManager ingredientManager, IIngredientType ingredientType, CallbackInfo ci) {
if((ingredientNum++ % 100) == 0)
IAsyncJeiStarter.checkForLoadInterruption();
}
}

View File

@ -1,23 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.systems.RenderSystem;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(InputConstants.class)
@ClientOnlyMixin
@RequiresMod("jei")
public class InputConstantsMixin {
@Redirect(method = "isKeyDown", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwGetKey(JI)I", remap = false))
private static int offThreadKeyFetch(long win, int k) {
if(RenderSystem.isOnRenderThreadOrInit())
return GLFW.glfwGetKey(win, k);
else
return 0;
}
}

View File

@ -1,46 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.helpers.IModIdHelper;
import mezz.jei.config.*;
import mezz.jei.config.sorting.RecipeCategorySortingConfig;
import mezz.jei.gui.textures.Textures;
import mezz.jei.ingredients.IIngredientSorter;
import mezz.jei.load.PluginCaller;
import mezz.jei.startup.JeiStarter;
import net.minecraft.client.Minecraft;
import org.embeddedt.modernfix.annotation.RequiresMod;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CancellationException;
import java.util.List;
import java.util.concurrent.CompletionException;
import java.util.function.Consumer;
@Mixin(JeiStarter.class)
@RequiresMod("jei")
public class JeiStarterMixin {
@Shadow(remap = false) private boolean started;
@Inject(method = "start", at = @At(value = "INVOKE", target = "Lmezz/jei/util/ErrorUtil;checkNotEmpty(Ljava/util/Collection;Ljava/lang/String;)V", ordinal = 0, shift = At.Shift.AFTER), remap = false)
private void setStartedFlag(List<IModPlugin> plugins, Textures textures, IClientConfig clientConfig, IEditModeConfig editModeConfig, IIngredientFilterConfig ingredientFilterConfig, IWorldConfig worldConfig, BookmarkConfig bookmarkConfig, IModIdHelper modIdHelper, RecipeCategorySortingConfig recipeCategorySortingConfig, IIngredientSorter ingredientSorter, CallbackInfo ci) {
/* We need to set this ASAP so the reload system will restart the async load if needed */
started = true;
}
@Redirect(method = "start", at = @At(value = "INVOKE", target = "Lmezz/jei/load/PluginCaller;callOnPlugins(Ljava/lang/String;Ljava/util/List;Ljava/util/function/Consumer;)V"), remap = false)
private void callOnPluginsViaMainThread(String title, List<IModPlugin> plugins, Consumer<IModPlugin> func) {
PluginCaller.callOnPlugins(title, plugins, plugin -> {
try {
Minecraft.getInstance().executeBlocking(() -> func.accept(plugin));
} catch(CancellationException | CompletionException e) {
throw new RuntimeException(e);
}
});
}
}

View File

@ -1,38 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import mezz.jei.api.IModPlugin;
import mezz.jei.load.PluginCaller;
import net.minecraft.client.Minecraft;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.forge.ModernFixConfig;
import org.embeddedt.modernfix.jei.async.IAsyncJeiStarter;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.function.Consumer;
@Mixin(PluginCaller.class)
@RequiresMod("jei")
public class PluginCallerMixin {
@Inject(method = "callOnPlugins", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;hasNext()Z"), remap = false)
private static void checkForInterrupt(String title, List<IModPlugin> plugins, Consumer<IModPlugin> func, CallbackInfo ci) {
IAsyncJeiStarter.checkForLoadInterruption();
}
@SuppressWarnings({"unchecked","rawtypes"})
@Redirect(method = "callOnPlugins", at = @At(value = "INVOKE", target = "Ljava/util/function/Consumer;accept(Ljava/lang/Object;)V"), remap = false)
private static void runOnMainThreadIfNeeded(Consumer instance, Object pluginObj) {
IModPlugin plugin = (IModPlugin)pluginObj;
if(ModernFixConfig.getJeiPluginBlacklist().contains(plugin.getPluginUid())) {
ModernFix.LOGGER.warn("Going to main thread for " + plugin.getPluginUid());
Minecraft.getInstance().executeBlocking(() -> instance.accept(plugin));
} else {
instance.accept(plugin);
}
}
}

View File

@ -1,20 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_jei;
import com.google.common.collect.ImmutableListMultimap;
import mezz.jei.recipes.RecipeManagerInternal;
import net.minecraft.resources.ResourceLocation;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.jei.async.IAsyncJeiStarter;
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(RecipeManagerInternal.class)
@RequiresMod("jei")
public class RecipeManagerInternalMixin {
@Inject(method = "addRecipes", at = @At(value = "INVOKE", target = "Lmezz/jei/recipes/RecipeManagerInternal;addRecipeTyped(Ljava/lang/Object;Lnet/minecraft/resources/ResourceLocation;)V"))
private void checkForInterrupt(ImmutableListMultimap<ResourceLocation, Object> recipes, CallbackInfo ci) {
IAsyncJeiStarter.checkForLoadInterruption();
}
}

View File

@ -1,12 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(CommandSourceStack.class)
public interface CommandSourceStackAccess {
@Accessor
CommandSource getSource();
}

View File

@ -1,109 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import com.google.common.collect.ImmutableSet;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.animal.Dolphin;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.forge.structure.AsyncLocator;
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.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(targets = "net.minecraft.world.entity.animal.Dolphin$DolphinSwimToTreasureGoal")
public class DolphinSwimToTreasureGoalMixin {
@Final
@Shadow
private Dolphin dolphin;
@Shadow
private boolean stuck;
private AsyncLocator.LocateTask<BlockPos> locateTask = null;
/*
Intercept DolphinSwimToTreasureGoal#start call right before it calls ServerLevel#findNearestMapFeature to pass
the logic over to an async task.
*/
@Inject(
method = "start",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;findNearestMapFeature(Lnet/minecraft/world/level/levelgen/feature/StructureFeature;Lnet/minecraft/core/BlockPos;IZ)Lnet/minecraft/core/BlockPos;"
),
cancellable = true,
locals = LocalCapture.CAPTURE_FAILSOFT
)
public void findTreasureAsync(CallbackInfo ci, ServerLevel level, BlockPos blockpos) {
ModernFix.LOGGER.debug("Intercepted DolphinSwimToTreasureGoal#start call");
handleFindTreasureAsync(level, blockpos);
ci.cancel();
}
/*
Intercept DolphinSwimToTreasureGoal#canContinueToUse to return true if an async locating task is ongoing so that
the goal isn't ended early due to no treasure pos being set yet.
*/
@Inject(
method = "canContinueToUse",
at = @At(value = "HEAD"),
cancellable = true
)
public void continueToUseIfLocatingTreasure(CallbackInfoReturnable<Boolean> cir) {
if (locateTask != null) {
ModernFix.LOGGER.debug("Locating task ongoing - returning true for continueToUse()");
cir.setReturnValue(true);
}
}
@Inject(
method = "stop",
at = @At(value = "HEAD")
)
public void stopLocatingTreasure(CallbackInfo ci) {
if (locateTask != null) {
ModernFix.LOGGER.debug("Locating task ongoing - cancelling during stop()");
locateTask.cancel();
locateTask = null;
}
}
/*
Intercept DolphinSwimToTreasureGoal#tick to return early if an async locating task is ongoing so that the
dolphin doesn't try to go towards an old treasure position.
*/
@Inject(
method = "tick",
at = @At(value = "HEAD"),
cancellable = true
)
public void skipTickingIfLocatingTreasure(CallbackInfo ci) {
if (locateTask != null) {
ModernFix.LOGGER.debug("Locating task ongoing - skipping tick()");
ci.cancel();
}
}
private void handleFindTreasureAsync(ServerLevel level, BlockPos blockPos) {
locateTask = AsyncLocator.locateLevel(level, ImmutableSet.of(StructureFeature.OCEAN_RUIN, StructureFeature.SHIPWRECK), blockPos, 50, false)
.thenOnServerThread(pos -> handleLocationFound(level, pos));
}
private void handleLocationFound(ServerLevel level, BlockPos pos) {
locateTask = null;
if (pos != null) {
ModernFix.LOGGER.debug("Location found - updating dolphin treasure pos");
dolphin.setTreasurePos(pos);
level.broadcastEntityEvent(dolphin, (byte) 38);
} else {
ModernFix.LOGGER.debug("No location found - marking dolphin as stuck");
stuck = true;
}
}
}

View File

@ -1,104 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.advancements.critereon.UsedEnderEyeTrigger;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.EyeOfEnder;
import net.minecraft.world.item.EnderEyeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.phys.HitResult;
import org.embeddedt.modernfix.forge.structure.logic.EnderEyeItemLogic;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(EnderEyeItem.class)
public class EnderEyeItemMixin {
/*
Intercept EnderEyeItem#use call and return BlockPos.ZERO instead. It won't be used in the EyeOfEnder entity
created later either, as we need to set the actual location ourselves.
*/
@Redirect(
method = "use",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/chunk/ChunkGenerator;findNearestMapFeature(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/levelgen/feature/StructureFeature;Lnet/minecraft/core/BlockPos;IZ)Lnet/minecraft/core/BlockPos;"
)
)
public BlockPos levelFindNearestMapFeature(
ChunkGenerator generator,
ServerLevel level,
StructureFeature<?> structureFeature,
BlockPos pPos,
int pRadius,
boolean pSkipExistingChunks
) {
return BlockPos.ZERO;
}
// Start the async locate task here so we have the eye of ender entity for context
@Inject(
method = "use",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/projectile/EyeOfEnder;setItem(Lnet/minecraft/world/item/ItemStack;)V"
),
locals = LocalCapture.CAPTURE_FAILEXCEPTION
)
public void startAsyncLocateTask(
Level pLevel,
Player pPlayer,
InteractionHand pHand,
CallbackInfoReturnable<InteractionResultHolder<ItemStack>> cir,
ItemStack itemstack,
HitResult hitresult,
BlockPos blockpos,
EyeOfEnder eyeofender
) {
EnderEyeItemLogic.locateAsync((ServerLevel)pLevel, pPlayer, eyeofender, (EnderEyeItem) (Object) this);
}
@Redirect(
method = "use",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/projectile/EyeOfEnder;signalTo(Lnet/minecraft/core/BlockPos;)V"
)
)
public void eyeOfEnderSignalTo(EyeOfEnder eyeOfEnder, BlockPos blockpos) {
// Do nothing - we'll do this later if a location is found
}
@Redirect(
method = "use",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/advancements/critereon/UsedEnderEyeTrigger;trigger(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/core/BlockPos;)V"
)
)
public void triggerUsedEnderEyeCriteria(UsedEnderEyeTrigger trigger, ServerPlayer player, BlockPos pos) {
// Do nothing - we'll do this later if a location is found
}
@Redirect(
method = "use",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;awardStat(Lnet/minecraft/stats/Stat;)V"
)
)
public void playerAwardStat(Player instance, Stat<?> pStat) {
// Do nothing - we'll do this later if a location is found
}
}

View File

@ -1,63 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.saveddata.maps.MapDecoration;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.functions.ExplorationMapFunction;
import net.minecraft.world.phys.Vec3;
import org.embeddedt.modernfix.forge.structure.logic.ExplorationMapFunctionLogic;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ExplorationMapFunction.class)
public class ExplorationMapFunctionMixin {
@Shadow
@Final
StructureFeature<?> destination;
@Shadow
@Final
MapDecoration.Type mapDecoration;
@Shadow
@Final
byte zoom;
@Shadow
@Final
int searchRadius;
@Shadow
@Final
boolean skipKnownStructures;
@Inject(
method = "run",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;findNearestMapFeature(Lnet/minecraft/world/level/levelgen/feature/StructureFeature;Lnet/minecraft/core/BlockPos;IZ)Lnet/minecraft/core/BlockPos;"
),
locals = LocalCapture.CAPTURE_FAILSOFT,
cancellable = true
)
public void updateMapAsync(
ItemStack pStack,
LootContext pContext,
CallbackInfoReturnable<ItemStack> cir,
Vec3 vec3,
ServerLevel serverlevel
) {
ItemStack mapStack = ExplorationMapFunctionLogic.updateMapAsync(
serverlevel, new BlockPos(vec3), zoom, searchRadius, skipKnownStructures, mapDecoration, destination
);
cir.setReturnValue(mapStack);
}
}

View File

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

View File

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

View File

@ -1,14 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.server.commands.LocateCommand;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(LocateCommand.class)
public interface LocateCommandAccess {
@Accessor("ERROR_FAILED")
static SimpleCommandExceptionType getErrorFailed() {
throw new UnsupportedOperationException();
}
}

View File

@ -1,34 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.commands.LocateCommand;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import org.embeddedt.modernfix.forge.structure.logic.LocateCommandLogic;
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;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(LocateCommand.class)
public class LocateCommandMixin {
@Inject(
method = "locate",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;findNearestMapFeature(Lnet/minecraft/world/level/levelgen/feature/StructureFeature;Lnet/minecraft/core/BlockPos;IZ)Lnet/minecraft/core/BlockPos;"
),
cancellable = true,
locals = LocalCapture.CAPTURE_FAILSOFT
)
private static void findLocationAsync(CommandSourceStack sourceStack, StructureFeature<?> feature, CallbackInfoReturnable<Integer> cir) {
CommandSource source = ((CommandSourceStackAccess) sourceStack).getSource();
if (source instanceof ServerPlayer || source instanceof MinecraftServer) {
LocateCommandLogic.locateAsync(sourceStack, feature);
cir.setReturnValue(0);
}
}
}

View File

@ -1,17 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.MapItem;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(MapItem.class)
public interface MapItemAccess {
@Invoker
static MapItemSavedData callCreateAndStoreSavedData(ItemStack pStack, Level pLevel, int pX, int pZ, int pScale, boolean pTrackingPosition, boolean pUnlimitedTracking, ResourceKey<Level> pDimension) {
throw new UnsupportedOperationException();
}
}

View File

@ -1,13 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.world.item.trading.MerchantOffer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(MerchantOffer.class)
public interface MerchantOfferAccess {
@Mutable
@Accessor
void setMaxUses(int maxUses);
}

View File

@ -1,28 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.storage.loot.functions.SetNameFunction;
import org.embeddedt.modernfix.forge.structure.logic.CommonLogic;
import org.embeddedt.modernfix.forge.structure.logic.ExplorationMapFunctionLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(SetNameFunction.class)
public class SetNameFunctionMixin {
@Redirect(
method = "run",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/item/ItemStack;setHoverName(Lnet/minecraft/network/chat/Component;)Lnet/minecraft/world/item/ItemStack;"
)
)
public ItemStack deferSetName(ItemStack stack, Component name) {
if (CommonLogic.isEmptyPendingMap(stack))
ExplorationMapFunctionLogic.cacheName(stack, name);
else
stack.setHoverName(name);
return stack;
}
}

View File

@ -1,28 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.embeddedt.modernfix.forge.structure.logic.CommonLogic;
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(Slot.class)
public abstract class SlotMixin {
@Shadow
public abstract ItemStack getItem();
@Inject(
method = "mayPickup",
at = @At(value = "HEAD"),
cancellable = true
)
public void preventPickupOfPendingExplorationMap(Player player, CallbackInfoReturnable<Boolean> cir) {
if (CommonLogic.isEmptyPendingMap(getItem())) {
cir.setReturnValue(false);
}
}
}

View File

@ -1,62 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.async_locator;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.saveddata.maps.MapDecoration;
import org.embeddedt.modernfix.forge.structure.logic.MerchantLogic;
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.util.Locale;
import java.util.Random;
@Mixin(targets = "net.minecraft.world.entity.npc.VillagerTrades$TreasureMapForEmeralds")
public class TreasureMapForEmeraldsMixin {
@Shadow
@Final
private int emeraldCost;
@Shadow
@Final
private MapDecoration.Type destinationType;
@Shadow
@Final
private int maxUses;
@Shadow
@Final
private int villagerXp;
@Shadow
@Final
private StructureFeature<?> destination;
/*
Intercept TreasureMapForEmeralds#getOffer call right before it calls ServerLevel#findNearestMapFeature to pass
the logic over to an async task. Instead of returning the complete map or null, we'll have to always return an
incomplete filled map and later update it with the details when we have them.
*/
@Inject(
method = "getOffer",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;findNearestMapFeature(Lnet/minecraft/world/level/levelgen/feature/StructureFeature;Lnet/minecraft/core/BlockPos;IZ)Lnet/minecraft/core/BlockPos;"
),
cancellable = true
)
public void updateMapAsync(Entity pTrader, Random pRand, CallbackInfoReturnable<MerchantOffer> callbackInfo) {
String displayName = "filled_map." + this.destination.getFeatureName().toLowerCase(Locale.ROOT);
MerchantOffer offer = MerchantLogic.updateMapAsync(
pTrader, emeraldCost, displayName, destinationType, maxUses, villagerXp, destination
);
if (offer != null) {
callbackInfo.setReturnValue(offer);
}
}
}

View File

@ -1,6 +1,6 @@
package org.embeddedt.modernfix.forge.mixin.perf.blast_search_trees;
import mezz.jei.ingredients.IIngredientListElementInfo;
import mezz.jei.gui.ingredients.IIngredientListElement;
import mezz.jei.ingredients.IngredientFilter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@ -10,5 +10,5 @@ import java.util.List;
@Mixin(IngredientFilter.class)
public interface IngredientFilterInvoker {
@Invoker(remap = false)
List<IIngredientListElementInfo<?>> invokeGetIngredientListUncached(String filterText);
List<IIngredientListElement<?>> invokeGetIngredientListUncached(String filterText);
}

View File

@ -27,8 +27,6 @@ public class ForgeHooksClientMixin {
*/
@Redirect(method = "onModelBake", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModLoader;postEvent(Lnet/minecraftforge/eventbus/api/Event;)V"), remap = false)
private static void postNamespacedKeySetEvent(ModLoader loader, Event event) {
if(!ModLoader.isLoadingStateValid())
return;
ModelBakeEvent bakeEvent = ((ModelBakeEvent)event);
ModelBakeEventHelper helper = new ModelBakeEventHelper(bakeEvent.getModelRegistry());
Method acceptEv = ObfuscationReflectionHelper.findMethod(ModContainer.class, "acceptEvent", Event.class);

View File

@ -16,10 +16,10 @@ import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.ClientPackSource;
import net.minecraft.client.resources.model.*;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.FilePackResources;
import net.minecraft.server.packs.FolderPackResources;
import net.minecraft.server.packs.PackResources;
import net.minecraft.server.packs.VanillaPackResources;
import net.minecraft.server.packs.FileResourcePack;
import net.minecraft.server.packs.FolderResourcePack;
import net.minecraft.server.packs.Pack;
import net.minecraft.server.packs.VanillaPack;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.block.Block;
@ -190,13 +190,13 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
return ImmutableList.of();
}
private boolean trustedResourcePack(PackResources pack) {
return pack instanceof VanillaPackResources ||
private boolean trustedResourcePack(Pack pack) {
return pack instanceof VanillaPack ||
pack instanceof ModFileResourcePack ||
pack instanceof ClientPackSource ||
pack instanceof DelegatingResourcePack ||
pack instanceof FolderPackResources ||
pack instanceof FilePackResources;
pack instanceof FolderResourcePack ||
pack instanceof FileResourcePack;
}
/**

View File

@ -1,35 +0,0 @@
package org.embeddedt.modernfix.forge.mixin.perf.kubejs;
import dev.latvian.kubejs.recipe.RecipeJS;
import dev.latvian.kubejs.recipe.filter.IDFilter;
import net.minecraft.resources.ResourceLocation;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.forge.util.KubeUtil;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(IDFilter.class)
@RequiresMod("kubejs")
public class IDFilterMixin {
@Shadow @Final private ResourceLocation id;
private RecipeJS _target;
private boolean _targetSearched = false;
/**
* @author embeddedt
* @reason avoid scanning every recipe
*/
@Overwrite(remap = false)
public boolean test(RecipeJS recipe) {
if(!_targetSearched) {
if(KubeUtil.originalRecipesByHash.size() > 0) {
_target = KubeUtil.originalRecipesByHash.get(this.id);
_targetSearched = true;
} else
return recipe.getOrCreateId().equals(this.id); // fallback
}
return recipe == _target;
}
}

Some files were not shown because too many files have changed in this diff Show More