Merge remote-tracking branch 'origin/1.18' into 1.19.2
This commit is contained in:
commit
5d317b6d94
|
|
@ -88,6 +88,9 @@ dependencies {
|
||||||
|
|
||||||
// compile against the JEI API but do not include it at runtime
|
// compile against the JEI API but do not include it at runtime
|
||||||
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
||||||
|
modRuntimeOnly("curse.maven:jei-238222:4405346")
|
||||||
|
|
||||||
|
modCompileOnly("curse.maven:jeresources-240630:3951643")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
|
|
@ -153,7 +156,7 @@ curseforge {
|
||||||
id = "790626"
|
id = "790626"
|
||||||
changelog = '[Changelog is not currently available]'
|
changelog = '[Changelog is not currently available]'
|
||||||
changelogType = "markdown"
|
changelogType = "markdown"
|
||||||
releaseType = "release"
|
releaseType = "beta"
|
||||||
addGameVersion "Forge"
|
addGameVersion "Forge"
|
||||||
addGameVersion minecraft_version
|
addGameVersion minecraft_version
|
||||||
mainArtifact remapJar
|
mainArtifact remapJar
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,20 @@ import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
import net.minecraftforge.fml.*;
|
||||||
import net.minecraftforge.fml.IExtensionPoint;
|
|
||||||
import net.minecraftforge.fml.ModList;
|
|
||||||
import net.minecraftforge.fml.ModLoadingContext;
|
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.config.ModConfig;
|
import net.minecraftforge.fml.config.ModConfig;
|
||||||
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
import net.minecraftforge.fml.loading.FMLLoader;
|
import net.minecraftforge.fml.loading.FMLLoader;
|
||||||
import net.minecraftforge.network.NetworkConstants;
|
import net.minecraftforge.network.NetworkConstants;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
import org.embeddedt.modernfix.core.config.ModernFixConfig;
|
||||||
|
import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler;
|
||||||
|
import org.embeddedt.modernfix.packet.PacketHandler;
|
||||||
|
|
||||||
|
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
@ -62,9 +64,30 @@ public class ModernFix {
|
||||||
INSTANCE = this;
|
INSTANCE = this;
|
||||||
// Register ourselves for server and other game events we are interested in
|
// Register ourselves for server and other game events we are interested in
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::commonSetup);
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient()));
|
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> MinecraftForge.EVENT_BUS.register(new ModernFixClient()));
|
||||||
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
|
||||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
|
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.register(EntityDataIDSyncHandler.class);
|
||||||
|
PacketHandler.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean dfuModPresent() {
|
||||||
|
for(String modId : new String[] { "lazydfu", "datafixerslayer" }) {
|
||||||
|
if(ModList.get().isLoaded(modId))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void commonSetup(FMLCommonSetupEvent event) {
|
||||||
|
if(!dfuModPresent()) {
|
||||||
|
event.enqueueWork(() -> {
|
||||||
|
ModLoader.get().addWarning(new ModLoadingWarning(ModLoadingContext.get().getActiveContainer().getModInfo(), ModLoadingStage.COMMON_SETUP, "modernfix.no_lazydfu"));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,32 @@
|
||||||
package org.embeddedt.modernfix;
|
package org.embeddedt.modernfix;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screens.ConnectScreen;
|
import net.minecraft.client.gui.screens.ConnectScreen;
|
||||||
import net.minecraft.client.gui.screens.TitleScreen;
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
|
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
|
||||||
import net.minecraftforge.client.event.ScreenEvent;
|
import net.minecraftforge.client.event.ScreenEvent;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
import net.minecraftforge.eventbus.api.EventPriority;
|
import net.minecraftforge.eventbus.api.EventPriority;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.ModContainer;
|
import net.minecraftforge.fml.ModContainer;
|
||||||
import net.minecraftforge.fml.ModList;
|
import net.minecraftforge.fml.ModList;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||||
import org.embeddedt.modernfix.load.LoadEvents;
|
import org.embeddedt.modernfix.load.LoadEvents;
|
||||||
|
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
||||||
import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen;
|
import org.embeddedt.modernfix.screen.DeferredLevelLoadingScreen;
|
||||||
|
|
||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
import java.util.Optional;
|
import java.lang.reflect.Field;
|
||||||
|
import java.sql.Ref;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ModernFixClient {
|
public class ModernFixClient {
|
||||||
public static long worldLoadStartTime;
|
public static long worldLoadStartTime;
|
||||||
|
|
@ -71,4 +81,106 @@ public class ModernFixClient {
|
||||||
event.getLeft().add(brandingString);
|
event.getLeft().add(brandingString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the IDs match and remap them if not.
|
||||||
|
* @return true if ID remap was needed
|
||||||
|
*/
|
||||||
|
private static boolean compareAndSwitchIds(Class<? extends Entity> eClass, String fieldName, EntityDataAccessor<?> accessor, int newId) {
|
||||||
|
if(accessor.id != newId) {
|
||||||
|
ModernFix.LOGGER.warn("Corrected ID mismatch on {} field {}. Client had {} but server wants {}.",
|
||||||
|
eClass,
|
||||||
|
fieldName,
|
||||||
|
accessor.id,
|
||||||
|
newId);
|
||||||
|
accessor.id = newId;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
ModernFix.LOGGER.debug("{} {} ID fine: {}", eClass, fieldName, newId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Horrendous hack to allow tracking every synced entity data manager.
|
||||||
|
*
|
||||||
|
* This is to ensure we can perform ID fixup on already constructed managers.
|
||||||
|
*/
|
||||||
|
public static final Set<SynchedEntityData> allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
|
|
||||||
|
private static final Field entriesArrayField;
|
||||||
|
static {
|
||||||
|
Field field;
|
||||||
|
try {
|
||||||
|
field = SynchedEntityData.class.getDeclaredField("entriesArray");
|
||||||
|
field.setAccessible(true);
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
field = null;
|
||||||
|
}
|
||||||
|
entriesArrayField = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extremely hacky method to detect and correct mismatched entity data parameter IDs on the client and server.
|
||||||
|
*
|
||||||
|
* The technique is far from ideal, but it should detect reliably and also not break already constructed entities.
|
||||||
|
*/
|
||||||
|
public static void handleEntityIDSync(EntityIDSyncPacket packet, Supplier<NetworkEvent.Context> context) {
|
||||||
|
Map<Class<? extends Entity>, List<Pair<String, Integer>>> info = packet.getFieldInfo();
|
||||||
|
context.get().enqueueWork(() -> {
|
||||||
|
boolean fixNeeded = false;
|
||||||
|
for(Map.Entry<Class<? extends Entity>, List<Pair<String, Integer>>> entry : info.entrySet()) {
|
||||||
|
Class<? extends Entity> eClass = entry.getKey();
|
||||||
|
for(Pair<String, Integer> field : entry.getValue()) {
|
||||||
|
String fieldName = field.getFirst();
|
||||||
|
int newId = field.getSecond();
|
||||||
|
try {
|
||||||
|
Field f = eClass.getDeclaredField(fieldName);
|
||||||
|
f.setAccessible(true);
|
||||||
|
EntityDataAccessor<?> accessor = (EntityDataAccessor<?>)f.get(null);
|
||||||
|
if(compareAndSwitchIds(eClass, fieldName, accessor, newId))
|
||||||
|
fixNeeded = true;
|
||||||
|
} catch(NoSuchFieldException e) {
|
||||||
|
ModernFix.LOGGER.warn("Couldn't find field on {}: {}", eClass, fieldName);
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException("Unexpected exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Now the ID mappings on synced entity data instances are probably all wrong. Fix that. */
|
||||||
|
List<SynchedEntityData> dataEntries;
|
||||||
|
synchronized (allEntityDatas) {
|
||||||
|
if(fixNeeded) {
|
||||||
|
dataEntries = new ArrayList<>(allEntityDatas);
|
||||||
|
for(SynchedEntityData manager : dataEntries) {
|
||||||
|
Int2ObjectOpenHashMap<SynchedEntityData.DataItem<?>> fixedMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
List<SynchedEntityData.DataItem<?>> items = new ArrayList<>(manager.itemsById.values());
|
||||||
|
for(SynchedEntityData.DataItem<?> item : items) {
|
||||||
|
fixedMap.put(item.getAccessor().id, item);
|
||||||
|
}
|
||||||
|
manager.lock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
manager.itemsById.replaceAll((id, parameter) -> fixedMap.get((int)id));
|
||||||
|
if(entriesArrayField != null) {
|
||||||
|
try {
|
||||||
|
SynchedEntityData.DataItem<?>[] dataArray = new SynchedEntityData.DataItem[items.size()];
|
||||||
|
for(int i = 0; i < dataArray.length; i++) {
|
||||||
|
dataArray[i] = fixedMap.get(i);
|
||||||
|
}
|
||||||
|
entriesArrayField.set(manager, dataArray);
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
ModernFix.LOGGER.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
manager.lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allEntityDatas.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
context.get().setPacketHandled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ public class BlockStateCacheHandler {
|
||||||
currentRebuildThread = null;
|
currentRebuildThread = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ModernFix.LOGGER.warn("Deferred blockstate cache rebuild");
|
ModernFix.LOGGER.debug("Deferred blockstate cache rebuild");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.embeddedt.modernfix.core.config;
|
package org.embeddedt.modernfix.core.config;
|
||||||
|
|
||||||
import net.minecraftforge.fml.loading.FMLLoader;
|
import net.minecraftforge.fml.loading.FMLLoader;
|
||||||
|
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ public class ModernFixEarlyConfig {
|
||||||
this.addMixinRule("feature.measure_time", true);
|
this.addMixinRule("feature.measure_time", true);
|
||||||
this.addMixinRule("feature.reduce_loading_screen_freezes", false);
|
this.addMixinRule("feature.reduce_loading_screen_freezes", false);
|
||||||
this.addMixinRule("perf.fast_registry_validation", true);
|
this.addMixinRule("perf.fast_registry_validation", true);
|
||||||
|
this.addMixinRule("perf.use_integrated_resources", true);
|
||||||
this.addMixinRule("perf.remove_biome_temperature_cache", true);
|
this.addMixinRule("perf.remove_biome_temperature_cache", true);
|
||||||
this.addMixinRule("perf.reduce_blockstate_cache_rebuilds", true);
|
this.addMixinRule("perf.reduce_blockstate_cache_rebuilds", true);
|
||||||
this.addMixinRule("perf.parallelize_model_loading", true);
|
this.addMixinRule("perf.parallelize_model_loading", true);
|
||||||
|
|
@ -30,6 +32,7 @@ public class ModernFixEarlyConfig {
|
||||||
this.addMixinRule("perf.cache_upgraded_structures", true);
|
this.addMixinRule("perf.cache_upgraded_structures", true);
|
||||||
this.addMixinRule("bugfix.concurrency", true);
|
this.addMixinRule("bugfix.concurrency", true);
|
||||||
this.addMixinRule("bugfix.edge_chunk_not_saved", true);
|
this.addMixinRule("bugfix.edge_chunk_not_saved", true);
|
||||||
|
this.addMixinRule("perf.async_jei", true);
|
||||||
this.addMixinRule("perf.thread_priorities", true);
|
this.addMixinRule("perf.thread_priorities", true);
|
||||||
this.addMixinRule("perf.sync_executor_sleep", true);
|
this.addMixinRule("perf.sync_executor_sleep", true);
|
||||||
this.addMixinRule("perf.scan_cache", true);
|
this.addMixinRule("perf.scan_cache", true);
|
||||||
|
|
@ -43,7 +46,8 @@ public class ModernFixEarlyConfig {
|
||||||
/* off by default in 1.18 because it doesn't work as well */
|
/* off by default in 1.18 because it doesn't work as well */
|
||||||
this.addMixinRule("perf.faster_singleplayer_load", false);
|
this.addMixinRule("perf.faster_singleplayer_load", false);
|
||||||
/* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */
|
/* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */
|
||||||
this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null);
|
Optional<ModInfo> jeiMod = FMLLoader.getLoadingModList().getMods().stream().filter(mod -> mod.getModId().equals("jei")).findFirst();
|
||||||
|
this.addMixinRule("perf.blast_search_trees", jeiMod.isPresent() && jeiMod.get().getVersion().getMajorVersion() >= 10);
|
||||||
this.addMixinRule("safety", true);
|
this.addMixinRule("safety", true);
|
||||||
this.addMixinRule("launch.transformer_cache", false);
|
this.addMixinRule("launch.transformer_cache", false);
|
||||||
this.addMixinRule("launch.class_search_cache", true);
|
this.addMixinRule("launch.class_search_cache", true);
|
||||||
|
|
@ -52,6 +56,7 @@ public class ModernFixEarlyConfig {
|
||||||
disableIfModPresent("mixin.perf.thread_priorities", "smoothboot");
|
disableIfModPresent("mixin.perf.thread_priorities", "smoothboot");
|
||||||
disableIfModPresent("mixin.perf.async_jei", "modernui");
|
disableIfModPresent("mixin.perf.async_jei", "modernui");
|
||||||
disableIfModPresent("mixin.perf.compress_biome_container", "chocolate");
|
disableIfModPresent("mixin.perf.compress_biome_container", "chocolate");
|
||||||
|
disableIfModPresent("mixin.bugfix.mc218112", "performant");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disableIfModPresent(String configName, String... ids) {
|
private void disableIfModPresent(String configName, String... ids) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.embeddedt.modernfix.duck.reuse_datapacks;
|
||||||
|
|
||||||
|
import net.minecraft.server.ReloadableServerResources;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public interface ICachingResourceClient {
|
||||||
|
void setCachedResources(ReloadableServerResources r);
|
||||||
|
void setCachedDataPackConfig(Collection<String> c);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package org.embeddedt.modernfix.entity;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraftforge.event.OnDatapackSyncEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.EventPriority;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
|
||||||
|
import net.minecraftforge.network.PacketDistributor;
|
||||||
|
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||||
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
|
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
||||||
|
import org.embeddedt.modernfix.packet.PacketHandler;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class EntityDataIDSyncHandler {
|
||||||
|
private static Map<Class<? extends Entity>, List<Pair<String, Integer>>> fieldsToSyncMap;
|
||||||
|
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void onDatapackSyncEvent(OnDatapackSyncEvent event) {
|
||||||
|
if(event.getPlayer() != null) {
|
||||||
|
if(!ServerLifecycleHooks.getCurrentServer().isDedicatedServer() && event.getPlayerList().getPlayerCount() == 0) {
|
||||||
|
ModernFix.LOGGER.debug("Not syncing IDs on integrated server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Compute the current set of serializer IDs in use and send them */
|
||||||
|
try {
|
||||||
|
if(fieldsToSyncMap == null) {
|
||||||
|
fieldsToSyncMap = new HashMap<>();
|
||||||
|
Field entityPoolField = ObfuscationReflectionHelper.findField(SynchedEntityData.class, "f_135343_");
|
||||||
|
Map<Class<? extends Entity>, Integer> entityPoolMap = (Map<Class<? extends Entity>, Integer>)entityPoolField.get(null);
|
||||||
|
List<Field> fieldsToSync = new ArrayList<>();
|
||||||
|
for(Class<? extends Entity> eClass : entityPoolMap.keySet()) {
|
||||||
|
fieldsToSync.clear();
|
||||||
|
Field[] classFields = eClass.getDeclaredFields();
|
||||||
|
for(Field field : classFields) {
|
||||||
|
if(!Modifier.isStatic(field.getModifiers()))
|
||||||
|
continue;
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object o = field.get(null);
|
||||||
|
if(o != null && EntityDataAccessor.class.isAssignableFrom(o.getClass())) {
|
||||||
|
fieldsToSync.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(Field field : fieldsToSync) {
|
||||||
|
int id = ((EntityDataAccessor<?>)field.get(null)).id;
|
||||||
|
fieldsToSyncMap.computeIfAbsent(eClass, k -> new ArrayList<>()).add(Pair.of(field.getName(), id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntityIDSyncPacket packet = new EntityIDSyncPacket(fieldsToSyncMap);
|
||||||
|
ModernFix.LOGGER.debug("Sending ID correction packet to client with " + fieldsToSyncMap.size() + " classes");
|
||||||
|
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(event::getPlayer), packet);
|
||||||
|
} catch(ObfuscationReflectionHelper.UnableToFindFieldException | ReflectiveOperationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.core;
|
||||||
|
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.embeddedt.modernfix.ModernFixClient;
|
||||||
|
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(SynchedEntityData.class)
|
||||||
|
public class SynchedEntityDataMixin {
|
||||||
|
/**
|
||||||
|
* Store this in our set of all entity data objects.
|
||||||
|
*
|
||||||
|
* Not an ideal solution, but it should guarantee compatibility with mods.
|
||||||
|
*/
|
||||||
|
@Inject(method = "<init>", at = @At("RETURN"))
|
||||||
|
private void storeInSet(Entity arg, CallbackInfo ci) {
|
||||||
|
synchronized (ModernFixClient.allEntityDatas) {
|
||||||
|
ModernFixClient.allEntityDatas.add((SynchedEntityData)(Object)this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,9 +13,9 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Mixin(value = BrandingControl.class, remap = false)
|
@Mixin(value = BrandingControl.class, remap = false, priority = 1100)
|
||||||
public class BrandingControlMixin {
|
public class BrandingControlMixin {
|
||||||
@Inject(method = "computeBranding", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModList;get()Lnet/minecraftforge/fml/ModList;"), locals = LocalCapture.CAPTURE_FAILHARD)
|
@Inject(method = "computeBranding", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModList;get()Lnet/minecraftforge/fml/ModList;"), locals = LocalCapture.CAPTURE_FAILHARD, require = 0)
|
||||||
private static void addModernFixBranding(CallbackInfo ci, ImmutableList.Builder<String> builder) {
|
private static void addModernFixBranding(CallbackInfo ci, ImmutableList.Builder<String> builder) {
|
||||||
Optional<? extends ModContainer> mfContainer = ModList.get().getModContainerById("modernfix");
|
Optional<? extends ModContainer> mfContainer = ModList.get().getModContainerById("modernfix");
|
||||||
if(mfContainer.isPresent())
|
if(mfContainer.isPresent())
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ package org.embeddedt.modernfix.mixin.perf.blast_search_trees;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.searchtree.SearchRegistry;
|
import net.minecraft.client.searchtree.SearchRegistry;
|
||||||
|
import net.minecraftforge.fml.ModContainer;
|
||||||
import net.minecraftforge.fml.ModList;
|
import net.minecraftforge.fml.ModList;
|
||||||
|
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||||
import org.embeddedt.modernfix.searchtree.DummySearchTree;
|
import org.embeddedt.modernfix.searchtree.DummySearchTree;
|
||||||
import org.embeddedt.modernfix.searchtree.JEIBackedSearchTree;
|
import org.embeddedt.modernfix.searchtree.JEIBackedSearchTree;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
|
@ -12,6 +14,8 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
@Mixin(Minecraft.class)
|
||||||
public class MinecraftMixin {
|
public class MinecraftMixin {
|
||||||
@Shadow @Final private SearchRegistry searchRegistry;
|
@Shadow @Final private SearchRegistry searchRegistry;
|
||||||
|
|
@ -19,7 +23,8 @@ public class MinecraftMixin {
|
||||||
@Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "createSearchTrees", at = @At("HEAD"), cancellable = true)
|
||||||
private void replaceSearchTrees(CallbackInfo ci) {
|
private void replaceSearchTrees(CallbackInfo ci) {
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
if(ModList.get().getModFileById("jei") != null) {
|
Optional<? extends ModContainer> jeiContainer = ModList.get().getModContainerById("jei");
|
||||||
|
if(jeiContainer.isPresent() && jeiContainer.get().getModInfo().getVersion().getMajorVersion() >= 10) {
|
||||||
this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, list -> new JEIBackedSearchTree(false));
|
this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, list -> new JEIBackedSearchTree(false));
|
||||||
this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, list -> new JEIBackedSearchTree(true));
|
this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, list -> new JEIBackedSearchTree(true));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ public class IntegratedServerMixin {
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
@Inject(method = "<init>", at = @At("RETURN"))
|
||||||
private void adjustServerPriority(Thread thread, Minecraft arg, LevelStorageSource.LevelStorageAccess arg2, PackRepository arg3, WorldStem arg4, Services arg5, ChunkProgressListenerFactory arg6, CallbackInfo ci) {
|
private void adjustServerPriority(Thread thread, Minecraft arg, LevelStorageSource.LevelStorageAccess arg2, PackRepository arg3, WorldStem arg4, Services arg5, ChunkProgressListenerFactory arg6, CallbackInfo ci) {
|
||||||
int pri = ModernFixConfig.INTEGRATED_SERVER_PRIORITY.get();
|
int pri = ModernFixConfig.INTEGRATED_SERVER_PRIORITY.get();
|
||||||
ModernFix.LOGGER.info("Changing server thread priority to " + pri);
|
|
||||||
thread.setPriority(pri);
|
thread.setPriority(pri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.embeddedt.modernfix.mixin.perf.use_integrated_resources;
|
||||||
|
|
||||||
|
import jeresources.util.LootTableHelper;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
@Mixin(LootTableHelper.class)
|
||||||
|
public class LootTableHelperMixin {
|
||||||
|
@Redirect(method = "getLootTables", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getServer()Lnet/minecraft/server/MinecraftServer;"))
|
||||||
|
private static MinecraftServer useIntegrated(Level level) {
|
||||||
|
MinecraftServer server = level.getServer();
|
||||||
|
if(server != null)
|
||||||
|
return server;
|
||||||
|
return ServerLifecycleHooks.getCurrentServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package org.embeddedt.modernfix.packet;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class EntityIDSyncPacket {
|
||||||
|
private Map<Class<? extends Entity>, List<Pair<String, Integer>>> map;
|
||||||
|
|
||||||
|
public EntityIDSyncPacket(Map<Class<? extends Entity>, List<Pair<String, Integer>>> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Class<? extends Entity>, List<Pair<String, Integer>>> getFieldInfo() {
|
||||||
|
return this.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityIDSyncPacket() {
|
||||||
|
this.map = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serialize(FriendlyByteBuf buf) {
|
||||||
|
buf.writeVarInt(map.keySet().size());
|
||||||
|
for(Map.Entry<Class<? extends Entity>, List<Pair<String, Integer>>> entry : map.entrySet()) {
|
||||||
|
buf.writeUtf(entry.getKey().getName());
|
||||||
|
buf.writeVarInt(entry.getValue().size());
|
||||||
|
for(Pair<String, Integer> field : entry.getValue()) {
|
||||||
|
buf.writeUtf(field.getFirst());
|
||||||
|
buf.writeVarInt(field.getSecond());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static EntityIDSyncPacket deserialize(FriendlyByteBuf buf) {
|
||||||
|
EntityIDSyncPacket self = new EntityIDSyncPacket();
|
||||||
|
int numEntityClasses = buf.readVarInt();
|
||||||
|
for(int i = 0; i < numEntityClasses; i++) {
|
||||||
|
String clzName = buf.readUtf();
|
||||||
|
try {
|
||||||
|
Class<?> clz;
|
||||||
|
try {
|
||||||
|
clz = Class.forName(clzName);
|
||||||
|
} catch(ClassNotFoundException e) {
|
||||||
|
ModernFix.LOGGER.warn("Entity class not found: {}", clzName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!Entity.class.isAssignableFrom(clz)) {
|
||||||
|
ModernFix.LOGGER.error("Not an entity: " + clzName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int numFields = buf.readVarInt();
|
||||||
|
for(int j = 0; j < numFields; j++) {
|
||||||
|
String fieldName = buf.readUtf();
|
||||||
|
int id = buf.readVarInt();
|
||||||
|
Field f = clz.getDeclaredField(fieldName);
|
||||||
|
if(!Modifier.isStatic(f.getModifiers()))
|
||||||
|
continue;
|
||||||
|
f.setAccessible(true);
|
||||||
|
if(!EntityDataAccessor.class.isAssignableFrom(f.get(null).getClass())) {
|
||||||
|
ModernFix.LOGGER.error("Not a data accessor field: " + clz + "." + fieldName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.map.computeIfAbsent((Class<? extends Entity>)clz, k -> new ArrayList<>()).add(Pair.of(fieldName, id));
|
||||||
|
}
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
ModernFix.LOGGER.error("Error deserializing packet", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.embeddedt.modernfix.packet;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.network.NetworkRegistry;
|
||||||
|
import net.minecraftforge.network.simple.SimpleChannel;
|
||||||
|
import org.embeddedt.modernfix.ModernFix;
|
||||||
|
import org.embeddedt.modernfix.ModernFixClient;
|
||||||
|
|
||||||
|
public class PacketHandler {
|
||||||
|
private static final String PROTOCOL_VERSION = "1";
|
||||||
|
public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
|
||||||
|
new ResourceLocation(ModernFix.MODID, "main"),
|
||||||
|
() -> PROTOCOL_VERSION,
|
||||||
|
NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION),
|
||||||
|
NetworkRegistry.acceptMissingOr(PROTOCOL_VERSION)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
int id = 1;
|
||||||
|
INSTANCE.registerMessage(id++, EntityIDSyncPacket.class, EntityIDSyncPacket::serialize, EntityIDSyncPacket::deserialize, ModernFixClient::handleEntityIDSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,12 +11,119 @@ import org.lwjgl.stb.STBRPNode;
|
||||||
import org.lwjgl.stb.STBRPRect;
|
import org.lwjgl.stb.STBRPRect;
|
||||||
import org.lwjgl.stb.STBRectPack;
|
import org.lwjgl.stb.STBRectPack;
|
||||||
|
|
||||||
|
import static java.lang.invoke.MethodHandles.*;
|
||||||
|
import static java.lang.invoke.MethodType.*;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.sql.Ref;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/* Source: https://github.com/GTNewHorizons/lwjgl3ify/blob/f21364cd3d178aef863458a2faa1f5718a4e350d/src/main/java/me/eigenraven/lwjgl3ify/textures/StbStitcher.java */
|
/* Source: https://github.com/GTNewHorizons/lwjgl3ify/blob/f21364cd3d178aef863458a2faa1f5718a4e350d/src/main/java/me/eigenraven/lwjgl3ify/textures/StbStitcher.java */
|
||||||
public class StbStitcher {
|
public class StbStitcher {
|
||||||
|
/* Most of this logic is to allow use of LWJGL versions where coordinates are short and versions where they are int */
|
||||||
|
private static final MethodHandle MH_rect_shortSet, MH_rect_intSet, MH_rect_intX, MH_rect_intY, MH_rect_shortX,
|
||||||
|
MH_rect_shortY;
|
||||||
|
|
||||||
|
static {
|
||||||
|
MethodHandle shortM = null, intM = null;
|
||||||
|
List<ReflectiveOperationException> exceptions = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
intM = publicLookup().findVirtual(STBRPRect.class, "set", methodType(STBRPRect.class,
|
||||||
|
int.class, /* id */
|
||||||
|
int.class,
|
||||||
|
int.class,
|
||||||
|
int.class,
|
||||||
|
int.class,
|
||||||
|
boolean.class));
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
shortM = publicLookup().findVirtual(STBRPRect.class, "set", methodType(STBRPRect.class,
|
||||||
|
int.class, /* id */
|
||||||
|
short.class,
|
||||||
|
short.class,
|
||||||
|
short.class,
|
||||||
|
short.class,
|
||||||
|
boolean.class));
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
if(shortM == null && intM == null) {
|
||||||
|
IllegalStateException e = new IllegalStateException("An STBRPRect set method could not be located");
|
||||||
|
exceptions.forEach(e::addSuppressed);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
MH_rect_shortSet = shortM;
|
||||||
|
MH_rect_intSet = intM;
|
||||||
|
/* Now look for X methods */
|
||||||
|
exceptions.clear();
|
||||||
|
try {
|
||||||
|
intM = publicLookup().findVirtual(STBRPRect.class, "x", methodType(int.class));
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
shortM = publicLookup().findVirtual(STBRPRect.class, "x", methodType(short.class));
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
exceptions.add(e);
|
||||||
|
}
|
||||||
|
if(shortM == null && intM == null) {
|
||||||
|
IllegalStateException e = new IllegalStateException("An STBRPRect x() method could not be located");
|
||||||
|
exceptions.forEach(e::addSuppressed);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
MH_rect_shortX = shortM;
|
||||||
|
MH_rect_intX = intM;
|
||||||
|
/* Assume that Y is the same */
|
||||||
|
try {
|
||||||
|
if(MH_rect_shortX != null) {
|
||||||
|
MH_rect_shortY = publicLookup().findVirtual(STBRPRect.class, "y", methodType(short.class));
|
||||||
|
MH_rect_intY = null;
|
||||||
|
} else { /* it must be int */
|
||||||
|
MH_rect_intY = publicLookup().findVirtual(STBRPRect.class, "y", methodType(int.class));
|
||||||
|
MH_rect_shortY = null;
|
||||||
|
}
|
||||||
|
} catch(ReflectiveOperationException e) {
|
||||||
|
throw new IllegalStateException("An STBRPRect y() method could not be located", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static STBRPRect setWrapper(STBRPRect rect, int id, int width, int height, int x, int y, boolean was_packed) {
|
||||||
|
try {
|
||||||
|
if(MH_rect_shortSet != null)
|
||||||
|
return (STBRPRect)MH_rect_shortSet.invokeExact(rect, id, (short)width, (short)height, (short)0, (short)0, false);
|
||||||
|
else
|
||||||
|
return (STBRPRect)MH_rect_intSet.invokeExact(rect, id, width, height, 0, 0, false);
|
||||||
|
} catch(Throwable e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getX(STBRPRect rect) {
|
||||||
|
try {
|
||||||
|
if(MH_rect_shortX != null)
|
||||||
|
return (short)MH_rect_shortX.invokeExact(rect);
|
||||||
|
else
|
||||||
|
return (int)MH_rect_intX.invokeExact(rect);
|
||||||
|
} catch(Throwable e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getY(STBRPRect rect) {
|
||||||
|
try {
|
||||||
|
if(MH_rect_shortX != null)
|
||||||
|
return (short)MH_rect_shortY.invokeExact(rect);
|
||||||
|
else
|
||||||
|
return (int)MH_rect_intY.invokeExact(rect);
|
||||||
|
} catch(Throwable e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Pair<Pair<Integer, Integer>, List<LoadableSpriteInfo>> packRects(Stitcher.Holder[] holders) {
|
public static Pair<Pair<Integer, Integer>, List<LoadableSpriteInfo>> packRects(Stitcher.Holder[] holders) {
|
||||||
int holderSize = holders.length;
|
int holderSize = holders.length;
|
||||||
|
|
||||||
|
|
@ -36,7 +143,9 @@ public class StbStitcher {
|
||||||
int height = holder.height;
|
int height = holder.height;
|
||||||
|
|
||||||
// The ID here is just the array index, for easy lookup later
|
// The ID here is just the array index, for easy lookup later
|
||||||
rectBuf.get(j).set(j, (short)width, (short)height, (short)0, (short)0, false);
|
STBRPRect rect = rectBuf.get(j);
|
||||||
|
|
||||||
|
setWrapper(rect, j, width, height, 0, 0, false);
|
||||||
|
|
||||||
sqSize += (width * height);
|
sqSize += (width * height);
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +172,7 @@ public class StbStitcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the sprite now with the position and size that we've calculated so far
|
// Initialize the sprite now with the position and size that we've calculated so far
|
||||||
infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, rect.x(), rect.y()));
|
infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, getX(rect), getY(rect)));
|
||||||
//holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false);
|
//holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,22 @@
|
||||||
package org.embeddedt.modernfix.util;
|
package org.embeddedt.modernfix.util;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class FileUtil {
|
public class FileUtil {
|
||||||
public static File childFile(File file) {
|
public static File childFile(File file) {
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Pattern SLASH_PATTERN = Pattern.compile("(?:\\\\+|\\/+)");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a path by removing double slashes, etc.
|
||||||
|
* @param path input path
|
||||||
|
* @return a normalized version of the path
|
||||||
|
*/
|
||||||
|
public static String normalize(String path) {
|
||||||
|
return SLASH_PATTERN.matcher(path).replaceAll("/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,7 @@ public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedC
|
||||||
public net.minecraft.client.renderer.texture.Stitcher$Holder
|
public net.minecraft.client.renderer.texture.Stitcher$Holder
|
||||||
public net.minecraft.util.thread.BlockableEventLoop m_18699_()V # runAllTasks
|
public net.minecraft.util.thread.BlockableEventLoop m_18699_()V # runAllTasks
|
||||||
public net.minecraft.server.MinecraftServer f_129726_ # nextTickTime
|
public net.minecraft.server.MinecraftServer f_129726_ # nextTickTime
|
||||||
public net.minecraft.client.Minecraft f_90999_ # progressListener
|
public net.minecraft.client.Minecraft f_90999_ # progressListener
|
||||||
|
public-f net.minecraft.network.syncher.EntityDataAccessor f_135010_ # id
|
||||||
|
public-f net.minecraft.network.syncher.SynchedEntityData f_135345_ # itemsById
|
||||||
|
public-f net.minecraft.network.syncher.SynchedEntityData f_135346_ # lock
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,6 @@ side = "BOTH"
|
||||||
modId = "jei"
|
modId = "jei"
|
||||||
mandatory = false
|
mandatory = false
|
||||||
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
||||||
versionRange = "[9.9999,)"
|
versionRange = "[11,)"
|
||||||
ordering = "BEFORE"
|
ordering = "BEFORE"
|
||||||
side = "CLIENT"
|
side = "CLIENT"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"modernfix.jei_load": "Loading JEI, this may take a while",
|
"modernfix.jei_load": "Loading JEI, this may take a while",
|
||||||
|
"modernfix.no_lazydfu": "ModernFix detected that DFU rules were compiled on startup. This slows down game launching. Installing LazyDFU to resolve this is highly recommended.",
|
||||||
"asynclocator.map.locating": "Map (Locating...)",
|
"asynclocator.map.locating": "Map (Locating...)",
|
||||||
"asynclocator.map.none": "Map (No nearby feature found)"
|
"asynclocator.map.none": "Map (No nearby feature found)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"modernfix.jei_load": "正在加载JEI,这需要一点时间",
|
"modernfix.jei_load": "正在加载JEI,这需要一点时间。",
|
||||||
"asynclocator.map.locating": "地图(正在定位...)",
|
"modernfix.no_lazydfu": "现代化修复检测到DFU规则在游戏启动时已被编译。这会降低游戏启动速度。非常推荐安装DFU载入优化来解决这个问题。",
|
||||||
|
"asynclocator.map.locating": "地图(定位中……)",
|
||||||
"asynclocator.map.none": "地图(未能找到相关地物)"
|
"asynclocator.map.none": "地图(未能找到相关地物)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"core.MinecraftMixin",
|
"core.MinecraftMixin",
|
||||||
|
"core.SynchedEntityDataMixin",
|
||||||
"feature.measure_time.MinecraftMixin",
|
"feature.measure_time.MinecraftMixin",
|
||||||
"feature.reduce_loading_screen_freezes.ModelBakeryMixin",
|
"feature.reduce_loading_screen_freezes.ModelBakeryMixin",
|
||||||
"bugfix.concurrency.MinecraftMixin",
|
"bugfix.concurrency.MinecraftMixin",
|
||||||
|
|
@ -56,6 +57,7 @@
|
||||||
"perf.cache_model_materials.VanillaModelMixin",
|
"perf.cache_model_materials.VanillaModelMixin",
|
||||||
"perf.cache_model_materials.MultipartMixin",
|
"perf.cache_model_materials.MultipartMixin",
|
||||||
"perf.faster_texture_stitching.StitcherMixin",
|
"perf.faster_texture_stitching.StitcherMixin",
|
||||||
|
"perf.use_integrated_resources.LootTableHelperMixin",
|
||||||
"perf.faster_singleplayer_load.MinecraftServerMixin"
|
"perf.faster_singleplayer_load.MinecraftServerMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user