diff --git a/patches/minecraft/net/minecraft/client/gui/screen/BiomeGeneratorTypeScreens.java.patch b/patches/minecraft/net/minecraft/client/gui/screen/BiomeGeneratorTypeScreens.java.patch new file mode 100644 index 000000000..16299d898 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/gui/screen/BiomeGeneratorTypeScreens.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/client/gui/screen/BiomeGeneratorTypeScreens.java ++++ b/net/minecraft/client/gui/screen/BiomeGeneratorTypeScreens.java +@@ -113,6 +113,9 @@ + private BiomeGeneratorTypeScreens(String p_i232324_1_) { + this.field_239076_k_ = new TranslationTextComponent("generator." + p_i232324_1_); + } ++ public BiomeGeneratorTypeScreens(ITextComponent displayName) { ++ this.field_239076_k_ = displayName; ++ } + + private static DimensionGeneratorSettings func_243452_a(DynamicRegistries p_243452_0_, DimensionGeneratorSettings p_243452_1_, BiomeGeneratorTypeScreens p_243452_2_, Biome p_243452_3_) { + BiomeProvider biomeprovider = new SingleBiomeProvider(p_243452_3_); +@@ -166,4 +169,8 @@ + public interface IFactory { + Screen createEditScreen(CreateWorldScreen p_createEditScreen_1_, DimensionGeneratorSettings p_createEditScreen_2_); + } ++ ++ // Forge start ++ // For internal use only, automatically called for all ForgeWorldTypes. Register your ForgeWorldType in the forge registry! ++ public static void registerGenerator(BiomeGeneratorTypeScreens gen) { field_239068_c_.add(gen); } + } diff --git a/patches/minecraft/net/minecraft/client/gui/screen/CreateWorldScreen.java.patch b/patches/minecraft/net/minecraft/client/gui/screen/CreateWorldScreen.java.patch index 612270849..d51678da0 100644 --- a/patches/minecraft/net/minecraft/client/gui/screen/CreateWorldScreen.java.patch +++ b/patches/minecraft/net/minecraft/client/gui/screen/CreateWorldScreen.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/client/gui/screen/CreateWorldScreen.java +++ b/net/minecraft/client/gui/screen/CreateWorldScreen.java +@@ -110,7 +110,7 @@ + + public static CreateWorldScreen func_243425_a(@Nullable Screen p_243425_0_) { + DynamicRegistries.Impl dynamicregistries$impl = DynamicRegistries.func_239770_b_(); +- return new CreateWorldScreen(p_243425_0_, DatapackCodec.field_234880_a_, new WorldOptionsScreen(dynamicregistries$impl, DimensionGeneratorSettings.func_242751_a(dynamicregistries$impl.func_243612_b(Registry.field_239698_ad_), dynamicregistries$impl.func_243612_b(Registry.field_239720_u_), dynamicregistries$impl.func_243612_b(Registry.field_243549_ar)), Optional.of(BiomeGeneratorTypeScreens.field_239066_a_), OptionalLong.empty())); ++ return new CreateWorldScreen(p_243425_0_, DatapackCodec.field_234880_a_, new WorldOptionsScreen(dynamicregistries$impl, DimensionGeneratorSettings.func_242751_a(dynamicregistries$impl.func_243612_b(Registry.field_239698_ad_), dynamicregistries$impl.func_243612_b(Registry.field_239720_u_), dynamicregistries$impl.func_243612_b(Registry.field_243549_ar)), net.minecraftforge.client.ForgeHooksClient.getDefaultWorldType(), OptionalLong.empty())); + } + + private CreateWorldScreen(@Nullable Screen p_i242063_1_, DatapackCodec p_i242063_2_, WorldOptionsScreen p_i242063_3_) { @@ -542,6 +542,7 @@ File file1 = path.toFile(); if (this.field_243416_G == null) { diff --git a/patches/minecraft/net/minecraft/client/gui/screen/WorldOptionsScreen.java.patch b/patches/minecraft/net/minecraft/client/gui/screen/WorldOptionsScreen.java.patch new file mode 100644 index 000000000..20c6bf80c --- /dev/null +++ b/patches/minecraft/net/minecraft/client/gui/screen/WorldOptionsScreen.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/client/gui/screen/WorldOptionsScreen.java ++++ b/net/minecraft/client/gui/screen/WorldOptionsScreen.java +@@ -134,6 +134,7 @@ + this.field_239035_i_.field_230693_o_ = this.field_239040_n_.isPresent(); + this.field_239036_j_ = p_239048_1_.func_230480_a_(new Button(j, 120, 150, 20, new TranslationTextComponent("selectWorld.customizeType"), (p_239044_3_) -> { + BiomeGeneratorTypeScreens.IFactory biomegeneratortypescreens$ifactory = BiomeGeneratorTypeScreens.field_239069_d_.get(this.field_239040_n_); ++ biomegeneratortypescreens$ifactory = net.minecraftforge.client.ForgeHooksClient.getBiomeGeneratorTypeScreenFactory(this.field_239040_n_, biomegeneratortypescreens$ifactory); + if (biomegeneratortypescreens$ifactory != null) { + p_239048_2_.func_147108_a(biomegeneratortypescreens$ifactory.createEditScreen(p_239048_1_, this.field_239039_m_)); + } +@@ -292,7 +293,7 @@ + } else { + this.field_239034_h_.field_230694_p_ = p_239059_1_; + this.field_239027_a_.field_230694_p_ = p_239059_1_; +- this.field_239036_j_.field_230694_p_ = p_239059_1_ && BiomeGeneratorTypeScreens.field_239069_d_.containsKey(this.field_239040_n_); ++ this.field_239036_j_.field_230694_p_ = p_239059_1_ && (BiomeGeneratorTypeScreens.field_239069_d_.containsKey(this.field_239040_n_) || net.minecraftforge.client.ForgeHooksClient.hasBiomeGeneratorSettingsOptionsScreen(this.field_239040_n_)); + this.field_239037_k_.field_230694_p_ = p_239059_1_; + } + diff --git a/patches/minecraft/net/minecraft/world/gen/settings/DimensionGeneratorSettings.java.patch b/patches/minecraft/net/minecraft/world/gen/settings/DimensionGeneratorSettings.java.patch new file mode 100644 index 000000000..5309a61bf --- /dev/null +++ b/patches/minecraft/net/minecraft/world/gen/settings/DimensionGeneratorSettings.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/gen/settings/DimensionGeneratorSettings.java ++++ b/net/minecraft/world/gen/settings/DimensionGeneratorSettings.java +@@ -192,7 +192,7 @@ + String s3 = (String)p_242753_1_.get("level-type"); + String s4 = Optional.ofNullable(s3).map((p_236217_0_) -> { + return p_236217_0_.toLowerCase(Locale.ROOT); +- }).orElse("default"); ++ }).orElseGet(net.minecraftforge.common.ForgeHooks::getDefaultWorldType); + p_242753_1_.put("level-type", s4); + long i = (new Random()).nextLong(); + if (!s1.isEmpty()) { +@@ -210,6 +210,8 @@ + Registry registry = p_242753_0_.func_243612_b(Registry.field_239720_u_); + Registry registry1 = p_242753_0_.func_243612_b(Registry.field_243549_ar); + SimpleRegistry simpleregistry = DimensionType.func_242718_a(registry2, registry, registry1, i); ++ net.minecraftforge.common.world.ForgeWorldType type = net.minecraftforge.registries.ForgeRegistries.WORLD_TYPES.getValue(new net.minecraft.util.ResourceLocation(s4)); ++ if (type != null) return type.createSettings(p_242753_0_, i, flag, false, s); + switch(s4) { + case "flat": + JsonObject jsonobject = !s.isEmpty() ? JSONUtils.func_212745_a(s) : new JsonObject(); diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java index 737cb6b5c..d048df74b 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/VersionSupportMatrix.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.fml.loading; import net.minecraftforge.forgespi.language.MavenVersionAdapter; diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index d775be7ae..8690740d2 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -31,6 +31,7 @@ import net.minecraft.client.audio.SoundEngine; import net.minecraft.client.gui.AbstractGui; import net.minecraft.client.gui.ClientBossInfo; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.screen.BiomeGeneratorTypeScreens; import net.minecraft.client.gui.screen.MainMenuScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.play.NetworkPlayerInfo; @@ -78,6 +79,7 @@ import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.GameType; import net.minecraft.world.IBlockDisplayReader; import net.minecraft.world.World; +import net.minecraft.world.gen.settings.DimensionGeneratorSettings; import net.minecraftforge.client.event.*; import net.minecraftforge.client.event.sound.PlaySoundEvent; import net.minecraftforge.client.model.ModelLoader; @@ -102,12 +104,14 @@ import org.apache.logging.log4j.core.impl.ReusableLogEventFactory; import org.lwjgl.opengl.GL13; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.lang.reflect.Field; import java.nio.Buffer; import java.nio.ByteBuffer; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.stream.Stream; @@ -785,4 +789,29 @@ public class ForgeHooksClient }); setRenderLayer(null); } + + public static void registerForgeWorldTypeScreens() + { + ForgeWorldTypeScreens.registerTypes(); + } + + public static BiomeGeneratorTypeScreens.IFactory getBiomeGeneratorTypeScreenFactory(Optional generator, @Nullable BiomeGeneratorTypeScreens.IFactory biomegeneratortypescreens$ifactory) + { + return ForgeWorldTypeScreens.getGeneratorScreenFactory(generator, biomegeneratortypescreens$ifactory); + } + + public static boolean hasBiomeGeneratorSettingsOptionsScreen(Optional generator) + { + return getBiomeGeneratorTypeScreenFactory(generator, null) != null; + } + + public static Optional getWorldTypeFromGenerator(DimensionGeneratorSettings dimensionGeneratorSettings) + { + return BiomeGeneratorTypeScreens.func_239079_a_(dimensionGeneratorSettings); + } + + public static Optional getDefaultWorldType() + { + return Optional.of(ForgeWorldTypeScreens.getDefaultGenerator()); + } } diff --git a/src/main/java/net/minecraftforge/client/ForgeWorldTypeScreens.java b/src/main/java/net/minecraftforge/client/ForgeWorldTypeScreens.java new file mode 100644 index 000000000..1a542154d --- /dev/null +++ b/src/main/java/net/minecraftforge/client/ForgeWorldTypeScreens.java @@ -0,0 +1,118 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.client; + +import com.google.common.collect.Maps; +import net.minecraft.client.gui.screen.BiomeGeneratorTypeScreens; +import net.minecraft.util.registry.DynamicRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.DimensionSettings; +import net.minecraft.world.gen.settings.DimensionGeneratorSettings; +import net.minecraftforge.common.world.ForgeWorldType; +import net.minecraftforge.registries.ForgeRegistries; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Optional; + +public class ForgeWorldTypeScreens +{ + private static final Logger LOGGER = LogManager.getLogger(); + + private static final Map GENERATORS = Maps.newHashMap(); + private static final Map GENERATOR_SCREEN_FACTORIES = Maps.newHashMap(); + + public static synchronized void registerFactory(ForgeWorldType type, BiomeGeneratorTypeScreens.IFactory factory) + { + if (GENERATOR_SCREEN_FACTORIES.containsKey(type)) + throw new IllegalStateException("Factory has already been registered for: " + type); + + GENERATOR_SCREEN_FACTORIES.put(type, factory); + } + + static BiomeGeneratorTypeScreens getDefaultGenerator() + { + ForgeWorldType def = ForgeWorldType.getDefaultWorldType(); + if (def == null) + { + return BiomeGeneratorTypeScreens.field_239066_a_; + } + + BiomeGeneratorTypeScreens gen = GENERATORS.get(def); + if (gen == null) + { + LOGGER.error("The default world type '{}' has not been added to the GUI. Was it registered too late?", def.getRegistryName()); + return BiomeGeneratorTypeScreens.field_239066_a_; + } + + return gen; + } + + static BiomeGeneratorTypeScreens.IFactory getGeneratorScreenFactory(Optional generator, @Nullable BiomeGeneratorTypeScreens.IFactory biomegeneratortypescreens$ifactory) + { + return generator.filter(gen -> gen instanceof GeneratorType) + .map(type -> GENERATOR_SCREEN_FACTORIES.get(((GeneratorType)type).getWorldType())) + .orElse(biomegeneratortypescreens$ifactory); + } + + static void registerTypes() + { + ForgeRegistries.WORLD_TYPES.forEach(wt -> { + GeneratorType gen = new GeneratorType(wt); + GENERATORS.put(wt, gen); + BiomeGeneratorTypeScreens.registerGenerator(gen); + }); + } + + private static class GeneratorType extends BiomeGeneratorTypeScreens + { + private final ForgeWorldType worldType; + + public GeneratorType(ForgeWorldType wt) + { + super(wt.getDisplayName()); + worldType = wt; + } + + public ForgeWorldType getWorldType() + { + return worldType; + } + + @Nonnull + @Override + public DimensionGeneratorSettings func_241220_a_(@Nonnull DynamicRegistries.Impl dynamicRegistries, long seed, boolean generateStructures, boolean bonusChest) + { + return worldType.createSettings(dynamicRegistries, seed, generateStructures, bonusChest, ""); + } + + @Nonnull + @Override + protected ChunkGenerator func_241869_a(@Nonnull Registry p_241869_1_, @Nonnull Registry p_241869_2_, long p_241869_3_) + { + return worldType.createChunkGenerator(p_241869_1_, p_241869_2_, p_241869_3_, ""); + } + } +} diff --git a/src/main/java/net/minecraftforge/common/ForgeConfig.java b/src/main/java/net/minecraftforge/common/ForgeConfig.java index 0bead7c58..c3ecc2595 100644 --- a/src/main/java/net/minecraftforge/common/ForgeConfig.java +++ b/src/main/java/net/minecraftforge/common/ForgeConfig.java @@ -108,10 +108,33 @@ public class ForgeConfig .comment("Fix advancement loading to use a proper topological sort. This may have visibility side-effects and can thus be turned off if needed for data-pack compatibility.") .translation("forge.configgui.fixAdvancementLoading") .define("fixAdvancementLoading", true); + builder.pop(); } } + /** + * General configuration that doesn't need to be synchronized but needs to be available before server startup + */ + public static class Common { + public final ForgeConfigSpec.ConfigValue defaultWorldType; + + Common(ForgeConfigSpec.Builder builder) + { + builder.comment("General configuration settings") + .push("general"); + + defaultWorldType = builder + .comment("Defines a default world type to use. The vanilla default world type is represented by 'default'.", + "The modded world types are registry names which should include the registry namespace, such as 'examplemod:example_world_type'.") + .translation("forge.configgui.defaultWorldType") + .define("defaultWorldType", "default"); + + builder.pop(); + } + + } + /** * Client specific configuration - only loaded clientside from forge-client.toml */ @@ -196,6 +219,15 @@ public class ForgeConfig } + static final ForgeConfigSpec commonSpec; + public static final Common COMMON; + static { + final Pair specPair = new ForgeConfigSpec.Builder().configure(Common::new); + commonSpec = specPair.getRight(); + COMMON = specPair.getLeft(); + } + + static final ForgeConfigSpec serverSpec; public static final Server SERVER; static { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 3eadf2a94..15064d191 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -120,6 +120,7 @@ import net.minecraftforge.common.loot.IGlobalLootModifier; import net.minecraftforge.common.loot.LootModifierManager; import net.minecraftforge.common.util.BlockSnapshot; import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder; +import net.minecraftforge.common.world.ForgeWorldType; import net.minecraftforge.common.world.MobSpawnInfoBuilder; import net.minecraftforge.event.AnvilUpdateEvent; import net.minecraftforge.event.DifficultyChangeEvent; @@ -879,6 +880,14 @@ public class ForgeHooks throw new RuntimeException("Mod fluids must override createAttributes."); } + public static String getDefaultWorldType() + { + ForgeWorldType def = ForgeWorldType.getDefaultWorldType(); + if (def != null) + return def.getRegistryName().toString(); + return "default"; + } + @FunctionalInterface public interface BiomeCallbackFunction { diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 4d8c03114..143021e37 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -27,14 +27,16 @@ import net.minecraft.entity.ai.attributes.RangedAttribute; import net.minecraft.util.SoundEvent; import net.minecraft.world.storage.IServerConfiguration; import net.minecraft.world.storage.SaveFormat; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.*; import net.minecraftforge.fml.config.ModConfig; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLModIdMappingEvent; +import net.minecraftforge.fml.event.lifecycle.*; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLEnvironment; import net.minecraftforge.fml.loading.progress.StartupMessageManager; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.server.command.EnumArgument; @@ -71,7 +73,6 @@ import net.minecraftforge.common.data.ForgeRecipeProvider; import net.minecraftforge.common.model.animation.CapabilityAnimation; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.fml.common.Mod; @@ -118,12 +119,14 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.addListener(this::preInit); modEventBus.addListener(this::gatherData); + modEventBus.addListener(this::loadComplete); modEventBus.register(this); ATTRIBUTES.register(modEventBus); MinecraftForge.EVENT_BUS.addListener(this::serverStopping); MinecraftForge.EVENT_BUS.addGenericListener(SoundEvent.class, this::missingSoundMapping); ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ForgeConfig.clientSpec); ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ForgeConfig.serverSpec); + ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ForgeConfig.commonSpec); modEventBus.register(ForgeConfig.class); // Forge does not display problems when the remote is not matching. ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, ()-> Pair.of(()->"ANY", (remote, isServer)-> true)); @@ -154,6 +157,12 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook ArgumentTypes.register("forge:modid", ModIdArgument.class, new ArgumentSerializer<>(ModIdArgument::modIdArgument)); } + public void loadComplete(FMLLoadCompleteEvent event) + { + if (FMLEnvironment.dist == Dist.CLIENT) + ForgeHooksClient.registerForgeWorldTypeScreens(); + } + public void serverStopping(FMLServerStoppingEvent evt) { WorldWorkerManager.clear(); diff --git a/src/main/java/net/minecraftforge/common/world/ForgeWorldType.java b/src/main/java/net/minecraftforge/common/world/ForgeWorldType.java new file mode 100644 index 000000000..907c4f22f --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/ForgeWorldType.java @@ -0,0 +1,121 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.world; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StringUtils; +import net.minecraft.util.Util; +import net.minecraft.util.registry.DynamicRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.DimensionType; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.DimensionSettings; +import net.minecraft.world.gen.settings.DimensionGeneratorSettings; +import net.minecraftforge.common.ForgeConfig; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.ForgeRegistryEntry; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ForgeWorldType extends ForgeRegistryEntry +{ + private static final Logger LOGGER = LogManager.getLogger(); + + public static ForgeWorldType getDefaultWorldType() + { + String defaultWorldType = ForgeConfig.COMMON.defaultWorldType.get(); + + if (StringUtils.isNullOrEmpty(defaultWorldType) || "default".equals(defaultWorldType)) + return null; // use vanilla + + ForgeWorldType def = ForgeRegistries.WORLD_TYPES.getValue(new ResourceLocation(defaultWorldType)); + if (def == null) + { + LOGGER.error("The defaultWorldType '{}' specified in the forge config has not been registered. The vanilla default generator will be used.", defaultWorldType); + } + + return def; + } + + private final IChunkGeneratorFactory factory; + + public ForgeWorldType(IChunkGeneratorFactory factory) + { + this.factory = factory; + } + + public ForgeWorldType(IBasicChunkGeneratorFactory factory) + { + this.factory = factory; + } + + public String getTranslationKey() + { + return Util.makeTranslationKey("generator", getRegistryName()); + } + + public ITextComponent getDisplayName() + { + return new TranslationTextComponent(getTranslationKey()); + } + + /** + * Called from both the dedicated server and the world creation screen in the client. + * to construct the DimensionGEneratorSettings: + * @return The constructed chunk generator. + */ + public ChunkGenerator createChunkGenerator(Registry biomeRegistry, Registry dimensionSettingsRegistry, long seed, String generatorSettings) + { + return this.factory.createChunkGenerator(biomeRegistry, dimensionSettingsRegistry, seed, generatorSettings); + } + + public DimensionGeneratorSettings createSettings(DynamicRegistries dynamicRegistries, long seed, boolean generateStructures, boolean generateLoot, String generatorSettings) + { + return this.factory.createSettings(dynamicRegistries, seed, generateStructures, generateLoot, generatorSettings); + } + + public interface IChunkGeneratorFactory + { + ChunkGenerator createChunkGenerator(Registry biomeRegistry, Registry dimensionSettingsRegistry, long seed, String generatorSettings); + + default DimensionGeneratorSettings createSettings(DynamicRegistries dynamicRegistries, long seed, boolean generateStructures, boolean bonusChest, String generatorSettings) { + Registry biomeRegistry = dynamicRegistries.getRegistry(Registry.BIOME_KEY); + Registry dimensionTypeRegistry = dynamicRegistries.getRegistry(Registry.DIMENSION_TYPE_KEY); + Registry dimensionSettingsRegistry = dynamicRegistries.getRegistry(Registry.NOISE_SETTINGS_KEY); + return new DimensionGeneratorSettings(seed, generateStructures, bonusChest, + DimensionGeneratorSettings.func_242749_a(dimensionTypeRegistry, + DimensionType.getDefaultSimpleRegistry(dimensionTypeRegistry, biomeRegistry, dimensionSettingsRegistry, seed), + createChunkGenerator(biomeRegistry, dimensionSettingsRegistry, seed, generatorSettings))); + } + } + + public interface IBasicChunkGeneratorFactory extends IChunkGeneratorFactory + { + ChunkGenerator createChunkGenerator(Registry biomeRegistry, Registry dimensionSettingsRegistry, long seed); + + default ChunkGenerator createChunkGenerator(Registry biomeRegistry, Registry dimensionSettingsRegistry, long seed, String generatorSettings) + { + return createChunkGenerator(biomeRegistry, dimensionSettingsRegistry, seed); + } + } +} diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistries.java b/src/main/java/net/minecraftforge/registries/ForgeRegistries.java index 7898a57d1..b25d143da 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistries.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistries.java @@ -57,6 +57,7 @@ import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder; import net.minecraft.world.gen.treedecorator.TreeDecoratorType; import net.minecraftforge.common.Tags; import net.minecraftforge.common.loot.GlobalLootModifierSerializer; +import net.minecraftforge.common.world.ForgeWorldType; import net.minecraftforge.fml.common.registry.GameRegistry; /** @@ -111,6 +112,7 @@ public class ForgeRegistries // Custom forge registries public static final IForgeRegistry DATA_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(DataSerializerEntry.class); public static final IForgeRegistry> LOOT_MODIFIER_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(GlobalLootModifierSerializer.class); + public static final IForgeRegistry WORLD_TYPES = RegistryManager.ACTIVE.getRegistry(ForgeWorldType.class); public static final class Keys { //Vanilla @@ -152,6 +154,7 @@ public class ForgeRegistries //Forge public static final RegistryKey> DATA_SERIALIZERS = key("data_serializers"); public static final RegistryKey>> LOOT_MODIFIER_SERIALIZERS = key("forge:loot_modifier_serializers"); + public static final RegistryKey> WORLD_TYPES = key("forge:world_types"); private static RegistryKey> key(String name) { diff --git a/src/main/java/net/minecraftforge/registries/GameData.java b/src/main/java/net/minecraftforge/registries/GameData.java index 4e2147ec0..67e92e606 100644 --- a/src/main/java/net/minecraftforge/registries/GameData.java +++ b/src/main/java/net/minecraftforge/registries/GameData.java @@ -74,6 +74,7 @@ import net.minecraft.world.gen.treedecorator.TreeDecoratorType; import net.minecraftforge.common.ForgeTagHandler; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.loot.GlobalLootModifierSerializer; +import net.minecraftforge.common.world.ForgeWorldType; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent.MissingMappings; import net.minecraftforge.fml.ModContainer; @@ -180,6 +181,7 @@ public class GameData // Custom forge registries makeRegistry(DATA_SERIALIZERS, DataSerializerEntry.class, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides().addCallback(SerializerCallbacks.INSTANCE).create(); makeRegistry(LOOT_MODIFIER_SERIALIZERS, c(GlobalLootModifierSerializer.class)).disableSaving().disableSync().create(); + makeRegistry(WORLD_TYPES, ForgeWorldType.class).disableSaving().disableSync().create(); } @SuppressWarnings("unchecked") //Ugly hack to let us pass in a typed Class object. Remove when we remove type specific references. private static Class c(Class cls) { return (Class)cls; } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index a4c0d575a..00c903980 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -144,6 +144,7 @@ public net.minecraft.client.gui.ScreenManager func_216911_a(Lnet/minecraft/inven public net.minecraft.client.gui.ScreenManager$IScreenFactory protected net.minecraft.client.gui.overlay.DebugOverlayGui field_211537_g # rayTraceBlock protected net.minecraft.client.gui.overlay.DebugOverlayGui field_211538_h # rayTraceFluid +public net.minecraft.client.gui.screen.WorldOptionsScreen func_239043_a_(Lnet/minecraft/world/gen/settings/DimensionGeneratorSettings;)V # func_239043_a_ protected net.minecraft.client.gui.widget.list.AbstractList$AbstractListEntry field_230666_a_ # list public net.minecraft.client.particle.ParticleManager func_199283_a(Lnet/minecraft/particles/ParticleType;Lnet/minecraft/client/particle/IParticleFactory;)V # registerFactory public net.minecraft.client.particle.ParticleManager func_215234_a(Lnet/minecraft/particles/ParticleType;Lnet/minecraft/client/particle/ParticleManager$IParticleMetaFactory;)V # registerFactory diff --git a/src/test/java/net/minecraftforge/debug/client/rendering/RenderLocalPlayerTest.java b/src/test/java/net/minecraftforge/debug/client/rendering/RenderLocalPlayerTest.java index e7408f23e..9f6b8b7cc 100644 --- a/src/test/java/net/minecraftforge/debug/client/rendering/RenderLocalPlayerTest.java +++ b/src/test/java/net/minecraftforge/debug/client/rendering/RenderLocalPlayerTest.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.debug.client.rendering; import net.minecraft.client.Minecraft; diff --git a/src/test/java/net/minecraftforge/debug/world/ForgeWorldTypeTest.java b/src/test/java/net/minecraftforge/debug/world/ForgeWorldTypeTest.java new file mode 100644 index 000000000..baaa118df --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/world/ForgeWorldTypeTest.java @@ -0,0 +1,82 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2020. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.debug.world; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.DimensionSettings; +import net.minecraft.world.gen.settings.DimensionGeneratorSettings; +import net.minecraftforge.client.ForgeWorldTypeScreens; +import net.minecraftforge.common.world.ForgeWorldType; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.ObjectHolder; + +@Mod("forge_world_type_test") +public class ForgeWorldTypeTest +{ + @ObjectHolder("forge_world_type_test:test_world_type") + public static ForgeWorldType testWorldType; + + public ForgeWorldTypeTest() + { + FMLJavaModLoadingContext.get().getModEventBus().addGenericListener(ForgeWorldType.class, this::registerWorldTypes); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::registerWorldTypeScreenFactories); + } + + private void registerWorldTypes(RegistryEvent.Register event) + { + event.getRegistry().registerAll( + new ForgeWorldType(DimensionGeneratorSettings::func_242750_a).setRegistryName("test_world_type") + ); + event.getRegistry().registerAll( + new ForgeWorldType(this::createChunkGenerator).setRegistryName("test_world_type2") + ); + } + + private ChunkGenerator createChunkGenerator(Registry biomes, Registry dimensionSettings, long seed, String settings) + { + return DimensionGeneratorSettings.func_242750_a(biomes, dimensionSettings, seed); + } + + private void registerWorldTypeScreenFactories(FMLClientSetupEvent event) + { + ForgeWorldTypeScreens.registerFactory(testWorldType, (returnTo, dimensionGeneratorSettings) -> new Screen(testWorldType.getDisplayName()) + { + @Override + protected void init() + { + super.init(); + + addButton(new Button(0, 0, 120, 20, new StringTextComponent("close"), btn -> { + Minecraft.getInstance().displayGuiScreen(returnTo); + })); + } + }); + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index a9143df4b..2131c2b57 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -95,4 +95,6 @@ license="LGPL v2.1" [[mods]] modId="forge_codecs_test" [[mods]] - modId="render_local_player_test" \ No newline at end of file + modId="render_local_player_test" +[[mods]] + modId="forge_world_type_test" \ No newline at end of file