Fix custom dimension not getting loaded on first world load ()

* re-enable custom dimension test

* port ServerBugfixMixin to 1.19

* fix custom dimension not loading on first load on client
This commit is contained in:
deirn 2022-06-29 01:25:50 +07:00 committed by GitHub
parent 07df213ec3
commit a6d2f785a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 9 deletions
fabric-dimensions-v1/src
main/java/net/fabricmc/fabric/mixin/dimension
testmod/java/net/fabricmc/fabric/test/dimension
fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client

View file

@ -16,9 +16,22 @@
package net.fabricmc.fabric.mixin.dimension;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Lifecycle;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;
import net.minecraft.nbt.NbtElement;
import net.minecraft.resource.DataPackSettings;
import net.minecraft.server.Main;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.level.LevelInfo;
import net.minecraft.world.level.LevelProperties;
import net.minecraft.world.level.storage.LevelStorage;
/**
* This Mixin aims to solve a Minecraft Vanilla bug where datapacks are ignored during creation of the
@ -33,11 +46,48 @@ import net.minecraft.server.Main;
*
* <p>See https://bugs.mojang.com/browse/MC-195468 for a related bug report.
*
* <p>In 1.18: Retest if this bug still occurs without this Mixin by launching a dedicated server with the
* <p>TODO: Retest if this bug still occurs without this Mixin by launching a dedicated server with the
* dimension testmod, and no world directory. If the dimension is available (i.e. in /execute in, or via
* the testmod's commands), then the bug is fixed and this Mixin can be removed.
*/
@Mixin(value = Main.class)
public class ServerBugfixMixin {
// TODO fix me 22w06a
@Unique
private static LevelStorage.Session session;
@Unique
private static DynamicRegistryManager.Mutable drm;
@Unique
private static DynamicOps<NbtElement> ops;
@ModifyVariable(method = "main", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/level/storage/LevelStorage;createSession(Ljava/lang/String;)Lnet/minecraft/world/level/storage/LevelStorage$Session;"))
private static LevelStorage.Session captureSession(LevelStorage.Session value) {
session = value;
return value;
}
@ModifyVariable(method = "method_43613", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/util/registry/DynamicRegistryManager;createAndLoad()Lnet/minecraft/util/registry/DynamicRegistryManager$Mutable;"))
private static DynamicRegistryManager.Mutable captureDrm(DynamicRegistryManager.Mutable value) {
drm = value;
return value;
}
// The value is stored as DynamicOps instead of RegistryOps in the bytecode
@ModifyVariable(method = "method_43613", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/util/dynamic/RegistryOps;ofLoaded(Lcom/mojang/serialization/DynamicOps;Lnet/minecraft/util/registry/DynamicRegistryManager$Mutable;Lnet/minecraft/resource/ResourceManager;)Lnet/minecraft/util/dynamic/RegistryOps;"))
private static DynamicOps<NbtElement> captureOps(DynamicOps<NbtElement> value) {
ops = value;
return value;
}
@Redirect(method = "method_43613", at = @At(value = "NEW", target = "net/minecraft/world/level/LevelProperties"))
private static LevelProperties onCreateNewLevelProperties(LevelInfo levelInfo, GeneratorOptions generatorOptions, Lifecycle lifecycle) {
DataPackSettings dataPackSettings = levelInfo.getDataPackSettings();
// Save the level.dat file
session.backupLevelDataFile(drm, new LevelProperties(levelInfo, generatorOptions, lifecycle));
// And reload it again, and replace the actual level properties with it
return (LevelProperties) session.readLevelProperties(ops, dataPackSettings, drm.getRegistryLifecycle());
}
}

View file

@ -65,11 +65,6 @@ public class FabricDimensionTest implements ModInitializer {
}
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
if (true) {
// TODO 22w06a ServerBugfixMixin
return;
}
ServerWorld overworld = server.getWorld(World.OVERWORLD);
ServerWorld world = server.getWorld(WORLD_KEY);

View file

@ -18,8 +18,11 @@ package net.fabricmc.fabric.mixin.resource.loader.client;
import java.io.File;
import com.google.gson.JsonElement;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.JsonOps;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@ -35,21 +38,31 @@ import net.minecraft.resource.DataPackSettings;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourcePackManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Util;
import net.minecraft.util.dynamic.RegistryOps;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.gen.WorldPresets;
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackUtil;
import net.fabricmc.fabric.mixin.resource.loader.ResourcePackManagerAccessor;
@Mixin(CreateWorldScreen.class)
public class CreateWorldScreenMixin {
public abstract class CreateWorldScreenMixin {
@Unique
private static DataPackSettings defaultDataPackSettings;
@Shadow
private ResourcePackManager packManager;
@Shadow
@Final
private static Logger LOGGER;
@Unique
private static RegistryOps<JsonElement> loadedOps;
@ModifyVariable(method = "create(Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/client/gui/screen/Screen;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/world/CreateWorldScreen;createServerConfig(Lnet/minecraft/resource/ResourcePackManager;Lnet/minecraft/resource/DataPackSettings;)Lnet/minecraft/server/SaveLoading$ServerConfig;"))
private static ResourcePackManager onCreateResManagerInit(ResourcePackManager manager) {
@ -71,10 +84,24 @@ public class CreateWorldScreenMixin {
@Redirect(method = "method_41854", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/registry/DynamicRegistryManager$Mutable;toImmutable()Lnet/minecraft/util/registry/DynamicRegistryManager$Immutable;"))
private static DynamicRegistryManager.Immutable loadDynamicRegistry(DynamicRegistryManager.Mutable mutableRegistryManager, ResourceManager dataPackManager) {
// This loads the dynamic registry from the data pack
RegistryOps.ofLoaded(JsonOps.INSTANCE, mutableRegistryManager, dataPackManager);
loadedOps = RegistryOps.ofLoaded(JsonOps.INSTANCE, mutableRegistryManager, dataPackManager);
return mutableRegistryManager.toImmutable();
}
/**
* Fix GeneratorOptions not having custom dimensions.
* Taken from {@link CreateWorldScreen#applyDataPacks(ResourcePackManager)}.
*/
@SuppressWarnings("JavadocReference")
@Redirect(method = "method_41854", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/gen/WorldPresets;createDefaultOptions(Lnet/minecraft/util/registry/DynamicRegistryManager;)Lnet/minecraft/world/gen/GeneratorOptions;"))
private static GeneratorOptions loadDatapackDimensions(DynamicRegistryManager dynamicRegistryManager) {
GeneratorOptions defaultGen = WorldPresets.createDefaultOptions(dynamicRegistryManager);
RegistryOps<JsonElement> registryOps = RegistryOps.of(JsonOps.INSTANCE, dynamicRegistryManager);
return GeneratorOptions.CODEC.encodeStart(registryOps, defaultGen)
.flatMap(json -> GeneratorOptions.CODEC.parse(loadedOps, json))
.getOrThrow(false, Util.addPrefix("Error parsing worldgen settings after loading data packs: ", LOGGER::error));
}
@Inject(method = "getScannedPack",
at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourcePackManager;scanPacks()V", shift = At.Shift.BEFORE))
private void onScanPacks(CallbackInfoReturnable<Pair<File, ResourcePackManager>> cir) {