From 5f1a85e0654c83f58631230427d466e2e34e980b Mon Sep 17 00:00:00 2001
From: deirn <deirn@bai.lol>
Date: Fri, 22 Jul 2022 02:08:20 +0700
Subject: [PATCH] fix custom dimension not loaded on world preset other than
 default (#2387)

---
 .../loader/client/CreateWorldScreenMixin.java | 63 +++++++++++++++----
 .../client/MoreOptionsDialogAccessor.java     | 29 +++++++++
 ...bric-resource-loader-v0.client.mixins.json |  3 +-
 3 files changed, 81 insertions(+), 14 deletions(-)
 create mode 100644 fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/MoreOptionsDialogAccessor.java

diff --git a/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/CreateWorldScreenMixin.java b/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/CreateWorldScreenMixin.java
index e4595fcf0..a84d34d9f 100644
--- a/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/CreateWorldScreenMixin.java
+++ b/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/CreateWorldScreenMixin.java
@@ -17,10 +17,14 @@
 package net.fabricmc.fabric.mixin.resource.loader.client;
 
 import java.io.File;
+import java.util.concurrent.CompletableFuture;
 
 import com.google.gson.JsonElement;
 import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.DataResult;
+import com.mojang.serialization.DynamicOps;
 import com.mojang.serialization.JsonOps;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
@@ -31,25 +35,29 @@ import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.ModifyArg;
 import org.spongepowered.asm.mixin.injection.ModifyVariable;
 import org.spongepowered.asm.mixin.injection.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
+import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.screen.world.CreateWorldScreen;
+import net.minecraft.client.gui.screen.world.MoreOptionsDialog;
+import net.minecraft.client.world.GeneratorOptionsHolder;
 import net.minecraft.resource.DataPackSettings;
 import net.minecraft.resource.ResourceManager;
 import net.minecraft.resource.ResourcePackManager;
 import net.minecraft.resource.ResourceType;
+import net.minecraft.server.SaveLoading;
 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 abstract class CreateWorldScreenMixin {
+public abstract class CreateWorldScreenMixin extends Screen {
 	@Unique
 	private static DataPackSettings defaultDataPackSettings;
 
@@ -60,8 +68,25 @@ public abstract class CreateWorldScreenMixin {
 	@Final
 	private static Logger LOGGER;
 
-	@Unique
-	private static RegistryOps<JsonElement> loadedOps;
+	@Shadow
+	@Final
+	public MoreOptionsDialog moreOptionsDialog;
+
+	@Shadow
+	protected DataPackSettings dataPackSettings;
+
+	@Shadow
+	private static SaveLoading.ServerConfig createServerConfig(ResourcePackManager resourcePackManager, DataPackSettings dataPackSettings) {
+		return null;
+	}
+
+	@Shadow
+	@Nullable
+	protected abstract Pair<File, ResourcePackManager> getScannedPack();
+
+	private CreateWorldScreenMixin() {
+		super(null);
+	}
 
 	@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;"))
@@ -84,22 +109,34 @@ public abstract 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
-		loadedOps = RegistryOps.ofLoaded(JsonOps.INSTANCE, mutableRegistryManager, dataPackManager);
+		RegistryOps.ofLoaded(JsonOps.INSTANCE, mutableRegistryManager, dataPackManager);
 		return mutableRegistryManager.toImmutable();
 	}
 
 	/**
-	 * Fix GeneratorOptions not having custom dimensions.
+	 * Load the DynamicRegistryManager again to 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 = "startServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/world/CreateWorldScreen;clearDataPackTempDir()V"))
+	private void loadDatapackDimensions(CallbackInfo ci) {
+		CompletableFuture<Void> future = SaveLoading.load(createServerConfig(getScannedPack().getSecond(), dataPackSettings), (resourceManager, dataPackSettings1) -> {
+			GeneratorOptionsHolder holder = moreOptionsDialog.getGeneratorOptionsHolder();
+			DynamicRegistryManager.Mutable newDrm = DynamicRegistryManager.createAndLoad();
+			DynamicOps<JsonElement> heldOps = RegistryOps.of(JsonOps.INSTANCE, holder.dynamicRegistryManager());
+			DynamicOps<JsonElement> newOps = RegistryOps.ofLoaded(JsonOps.INSTANCE, newDrm, resourceManager);
+			DataResult<GeneratorOptions> result = GeneratorOptions.CODEC.encodeStart(heldOps, holder.generatorOptions())
+					.flatMap(json -> GeneratorOptions.CODEC.parse(newOps, json));
+			return Pair.of(result, newDrm.toImmutable());
+		}, (resourceManager, dataPackContents, drm, result) -> {
+			resourceManager.close();
+			GeneratorOptions options = result.getOrThrow(false, Util.addPrefix("Error parsing worldgen settings after loading data packs: ", LOGGER::error));
+			GeneratorOptionsHolder holder = new GeneratorOptionsHolder(options, result.lifecycle().add(drm.getRegistryLifecycle()), drm, dataPackContents);
+			((MoreOptionsDialogAccessor) moreOptionsDialog).callSetGeneratorOptionsHolder(holder);
+			return null;
+		}, Util.getMainWorkerExecutor(), client);
+
+		client.runTasks(future::isDone);
 	}
 
 	@Inject(method = "getScannedPack",
diff --git a/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/MoreOptionsDialogAccessor.java b/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/MoreOptionsDialogAccessor.java
new file mode 100644
index 000000000..9b056bda6
--- /dev/null
+++ b/fabric-resource-loader-v0/src/client/java/net/fabricmc/fabric/mixin/resource/loader/client/MoreOptionsDialogAccessor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.resource.loader.client;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+import net.minecraft.client.gui.screen.world.MoreOptionsDialog;
+import net.minecraft.client.world.GeneratorOptionsHolder;
+
+@Mixin(MoreOptionsDialog.class)
+public interface MoreOptionsDialogAccessor {
+	@Invoker
+	void callSetGeneratorOptionsHolder(GeneratorOptionsHolder generatorOptionsHolder);
+}
diff --git a/fabric-resource-loader-v0/src/client/resources/fabric-resource-loader-v0.client.mixins.json b/fabric-resource-loader-v0/src/client/resources/fabric-resource-loader-v0.client.mixins.json
index f2cc70818..5bed17030 100644
--- a/fabric-resource-loader-v0/src/client/resources/fabric-resource-loader-v0.client.mixins.json
+++ b/fabric-resource-loader-v0/src/client/resources/fabric-resource-loader-v0.client.mixins.json
@@ -7,7 +7,8 @@
     "CreateWorldScreenMixin",
     "FontManagerResourceReloadListenerMixin",
     "GameOptionsMixin",
-    "KeyedResourceReloadListenerClientMixin"
+    "KeyedResourceReloadListenerClientMixin",
+    "MoreOptionsDialogAccessor"
   ],
   "injectors": {
     "defaultRequire": 1