feat: custom dimensions

This commit is contained in:
Timo Ley 2024-10-26 15:01:40 +02:00
parent 24af45798e
commit 58164c7554
9 changed files with 304 additions and 6 deletions

View file

@ -11,8 +11,12 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import dev.tilera.cwg.api.CwgGlobals;
import dev.tilera.cwg.api.hooks.IHookProvider;
import dev.tilera.cwg.api.utils.BooleanOption;
import dev.tilera.cwg.api.utils.IntOption;
import dev.tilera.cwg.api.utils.StringOption;
import dev.tilera.cwg.classic.ClassicChunkManagerFactory;
import dev.tilera.cwg.command.CommandChangeWorld;
import dev.tilera.cwg.dimensions.CustomDimensions;
import dev.tilera.cwg.dimensions.DimProvider;
import dev.tilera.cwg.hooks.DefaultCavegenHook;
import dev.tilera.cwg.hooks.DefaultTemperatureHook;
import dev.tilera.cwg.hooks.HookOption;
@ -23,10 +27,12 @@ import dev.tilera.cwg.noisegen.NoiseGeneratorOctavesFarlands;
import dev.tilera.cwg.options.ChunkManagerOption;
import dev.tilera.cwg.options.ConfigProvider;
import dev.tilera.cwg.proxy.CommonProxy;
import dev.tilera.cwg.vanilla.SingleBiomeChunkManagerFactory;
import dev.tilera.cwg.vanilla.VanillaChunkManagerFactory;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.gen.NoiseGenerator;
import net.minecraft.world.gen.NoiseGeneratorOctaves;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.terraingen.InitMapGenEvent;
import net.minecraftforge.event.terraingen.InitNoiseGensEvent;
@ -47,6 +53,7 @@ public class ClassicWorldgen {
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
Config.initConfig();
CustomDimensions.INSTANCE = new CustomDimensions(CUSTOM);
CwgGlobals.setOptionRegistry(CUSTOM);
CwgGlobals.setDefaultProvider(CONFIG);
CwgGlobals.setGeneratorRegistry(CUSTOM);
@ -62,6 +69,9 @@ public class ClassicWorldgen {
registerGenerators();
registerOptions();
registerHooks();
DimensionManager.registerProviderType(Config.dimensionProviderID, DimProvider.class, false);
CustomDimensions.INSTANCE.readConfig(Config.dimensionsDefinition);
CustomDimensions.INSTANCE.registerDimensions();
}
public void registerOptions() {
@ -75,6 +85,9 @@ public class ClassicWorldgen {
CwgGlobals.getOptionRegistry().registerOption(new BooleanOption("cwg:disable_jungle_melons", "Disable Jungle Melons", false));
CwgGlobals.getOptionRegistry().registerOption(new BooleanOption("cwg:disable_new_flowers", "Disable new Flowers", false));
CwgGlobals.getOptionRegistry().registerOption(new BooleanOption("cwg:disable_tall_flowers", "Disable Tall Flowers", false));
CwgGlobals.getOptionRegistry().registerOption(new StringOption("cwg:dimensions:name", "Dimension Name", "Custom Dimension", true));
CwgGlobals.getOptionRegistry().registerOption(new IntOption("cwg:dimensions:provider", "Provider ID", Config.dimensionProviderID, true, false));
CwgGlobals.getOptionRegistry().registerOption(new IntOption("cwg:generator.singleBiome:biomeID", "Biome ID", 0, false, true));
}
public void registerHooks() {
@ -91,6 +104,7 @@ public class ClassicWorldgen {
VanillaChunkManagerFactory def = new VanillaChunkManagerFactory();
CwgGlobals.getGeneratorRegistry().registerChunkManager(def);
CwgGlobals.getGeneratorRegistry().registerChunkManager(new ClassicChunkManagerFactory());
CwgGlobals.getGeneratorRegistry().registerChunkManager(new SingleBiomeChunkManagerFactory());
CwgGlobals.getOptionRegistry().registerOption(new ChunkManagerOption(
"cwg:generator",
"Generator",

View file

@ -7,6 +7,7 @@ import net.minecraftforge.common.config.Configuration;
public class Config {
public static File dimensionsDefinition;
static Configuration conf;
public static boolean enableSwissCheeseCaves = false;
public static boolean addNewVanillaBiomes = false;
@ -17,9 +18,13 @@ public class Config {
public static boolean disableModdedBiomes = false;
public static boolean enableDesertLakes = true;
public static boolean enableModdedWorldgen = true;
public static int dimensionProviderID = 88;
public static void initConfig() {
conf = new Configuration(new File(Loader.instance().getConfigDir(), "ClassicWorldgen.cfg"));
File cwgDir = new File(Loader.instance().getConfigDir(), "cwg");
cwgDir.mkdirs();
dimensionsDefinition = new File(cwgDir, "dimensions.json");
conf.load();
enableSwissCheeseCaves = conf.getBoolean("enableSwissCheeseCaves", "caves", enableSwissCheeseCaves, "enable classic (1.6) cavegen");
addNewVanillaBiomes = conf.getBoolean("addNewVanillaBiomes", "worldgen", addNewVanillaBiomes, "generate new 1.7 vanilla biomes with classic/1.6 WorldType");
@ -30,6 +35,7 @@ public class Config {
disableModdedBiomes = conf.getBoolean("disableModdedBiomes", "worldgen", disableModdedBiomes, "prevent modded biomes from generating in classic worldgen");
enableDesertLakes = conf.getBoolean("enableDesertLakes", "worldgen", enableDesertLakes, "enable lakes in desert in classic worldgen");
enableModdedWorldgen = conf.getBoolean("enableModdedWorldgen", "worldgen", enableModdedWorldgen, "enable worldgen features from other mods");
dimensionProviderID = conf.getInt("providerID", "dimensions", dimensionProviderID, Integer.MIN_VALUE, Integer.MAX_VALUE, null);
conf.save();
}

View file

@ -41,13 +41,17 @@ public class WorldTypeCustom extends WorldType implements IGeneratorOptionRegist
public WorldChunkManager getChunkManager(World world) {
String opts = world.getWorldInfo().getGeneratorOptions();
IGeneratorOptionProvider options;
try {
options = decodeOptions(opts);
} catch (Exception e) {
e.printStackTrace();
if (opts.isEmpty()) {
options = this;
} else {
try {
options = decodeOptions(opts);
} catch (Exception e) {
e.printStackTrace();
options = this;
}
}
AbstractChunkManager manager = options.getValue("cwg:generator", IChunkManagerFactory.class).createChunkManager(ClassicWorldgen.CONFIG, world);
AbstractChunkManager manager = options.getValue("cwg:generator", IChunkManagerFactory.class).createChunkManager(options, world);
CwgGlobals.setCurrentState(world);
return manager;
}
@ -181,4 +185,25 @@ public class WorldTypeCustom extends WorldType implements IGeneratorOptionRegist
return chunkManagerRegistry.values().stream().collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
@Override
public <T> IOption<T> getOption(String id, Class<T> type) {
IOption<?> opt = optionRegistry.get(id);
if (opt != null && opt.getType() == type) {
return (IOption<T>) optionRegistry.get(id);
} else {
return null;
}
}
@Override
public Class<?> getOptionType(String id) {
IOption<?> opt = optionRegistry.get(id);
if (opt != null) {
return opt.getType();
} else {
return null;
}
}
}

View file

@ -14,4 +14,8 @@ public interface IGeneratorOptionRegistry extends IGeneratorOptionProvider {
<T> boolean isRegistered(String id, Class<T> type);
<T> IOption<T> getOption(String id, Class<T> type);
Class<?> getOptionType(String id);
}

View file

@ -0,0 +1,79 @@
package dev.tilera.cwg.api.utils;
import java.util.Map;
import dev.tilera.cwg.api.options.IOption;
public class IntOption implements IOption<Integer> {
private String id;
private String displayName;
private int defaultValue;
private boolean isInternal = false;
private boolean isGeneratorSpecific = false;
public IntOption(String id, String displayName, int defaultValue) {
this.id = id;
this.displayName = displayName;
this.defaultValue = defaultValue;
}
public IntOption(String id, String displayName, int defaultValue, boolean isInternal, boolean isGeneratorSpecific) {
this.id = id;
this.displayName = displayName;
this.defaultValue = defaultValue;
this.isInternal = isInternal;
this.isGeneratorSpecific = isGeneratorSpecific;
}
@Override
public Integer getDefault() {
return defaultValue;
}
@Override
public String getID() {
return id;
}
@Override
public String getVisableName() {
return displayName;
}
@Override
public Class<Integer> getType() {
return Integer.class;
}
@Override
public Type getOptionType() {
return isInternal ? Type.INTERNAL : Type.STRING;
}
@Override
public Map<Integer, String> getPossibleValues() {
return null;
}
@Override
public Integer decodeString(String input) {
return Integer.parseInt(input);
}
@Override
public Integer fromRepresentation(String repr) {
return null;
}
@Override
public String toRepresentation(Integer obj) {
return null;
}
@Override
public boolean isGeneratorSpecific() {
return isGeneratorSpecific;
}
}

View file

@ -9,6 +9,7 @@ public class StringOption implements IOption<String> {
private String id;
private String displayName;
private String defaultValue;
private boolean isInternal = false;
public StringOption(String id, String displayName, String defaultValue) {
this.id = id;
@ -16,6 +17,11 @@ public class StringOption implements IOption<String> {
this.defaultValue = defaultValue;
}
public StringOption(String id, String displayName, String defaultValue, boolean isInternal) {
this(id, displayName, defaultValue);
this.isInternal = isInternal;
}
@Override
public String getDefault() {
return defaultValue;
@ -58,7 +64,7 @@ public class StringOption implements IOption<String> {
@Override
public Type getOptionType() {
return Type.STRING;
return isInternal ? Type.INTERNAL : Type.STRING;
}

View file

@ -0,0 +1,88 @@
package dev.tilera.cwg.dimensions;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import dev.tilera.cwg.api.options.IGeneratorOptionProvider;
import dev.tilera.cwg.api.options.IGeneratorOptionRegistry;
import net.minecraftforge.common.DimensionManager;
public class CustomDimensions {
public static CustomDimensions INSTANCE;
private Gson gson = new GsonBuilder().create();
private IGeneratorOptionRegistry registry;
private Map<Integer, IGeneratorOptionProvider> dimensions = new HashMap<>();
public CustomDimensions(IGeneratorOptionRegistry registry) {
this.registry = registry;
}
public IGeneratorOptionProvider getDimensionOptions(int id) {
return dimensions.get(id);
}
public Integer[] getCustomDimensions() {
return dimensions.keySet().toArray(new Integer[0]);
}
public void registerDimensions() {
for (int id : getCustomDimensions()) {
IGeneratorOptionProvider options = getDimensionOptions(id);
int providerId = options.getInt("cwg:dimensions:provider");
DimensionManager.registerDimension(id, providerId);
}
}
public void readConfig(File file) {
JsonObject[] dims = decodeConfig(file);
for (JsonObject dim : dims) {
Integer id = getDimID(dim);
IGeneratorOptionProvider options = decodeOptions(dim);
dimensions.put(id, options);
}
}
private JsonObject[] decodeConfig(File file) {
try {
return gson.fromJson(new FileReader(file), JsonObject[].class);
} catch (FileNotFoundException e) {
return new JsonObject[0];
} catch (JsonSyntaxException | JsonIOException e) {
throw new RuntimeException(e);
}
}
private int getDimID(JsonObject def) throws IllegalStateException {
JsonElement id = def.get("id");
if (id == null || !id.isJsonPrimitive()) throw new IllegalStateException("Dimension definition does not contain a valid dimension ID: " + def);
return id.getAsInt();
}
private IGeneratorOptionProvider decodeOptions(JsonObject def) throws IllegalStateException {
JsonElement options = def.get("options");
String encodedJson = null;
if (options == null) {
throw new IllegalStateException("Dimension definition does not contain valid options: " + def);
} else if (options.isJsonObject()) {
encodedJson = Base64.getEncoder().encodeToString(gson.toJson(options).getBytes());
} else if (options.isJsonPrimitive() && options.getAsJsonPrimitive().isString()) {
encodedJson = options.getAsJsonPrimitive().getAsString();
} else {
throw new IllegalStateException("Dimension definition does not contain valid options: " + def);
}
return registry.decodeOptions(encodedJson);
}
}

View file

@ -0,0 +1,36 @@
package dev.tilera.cwg.dimensions;
import dev.tilera.cwg.api.generator.AbstractChunkManager;
import dev.tilera.cwg.api.generator.IChunkManagerFactory;
import dev.tilera.cwg.api.options.IGeneratorOptionProvider;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.chunk.IChunkProvider;
public class DimProvider extends WorldProvider {
@Override
public String getDimensionName() {
return getOptions().getString("cwg:dimensions:name");
}
@Override
public String getSaveFolder() {
return "cwg/DIM" + dimensionId;
}
@Override
public IChunkProvider createChunkGenerator() {
return ((AbstractChunkManager)this.worldChunkMgr).getGenerator(this.worldObj);
}
@Override
protected void registerWorldChunkManager() {
IGeneratorOptionProvider options = CustomDimensions.INSTANCE.getDimensionOptions(dimensionId);
this.worldChunkMgr = options.getValue("cwg:generator", IChunkManagerFactory.class).createChunkManager(options, worldObj);
}
protected IGeneratorOptionProvider getOptions() {
return ((AbstractChunkManager)this.worldChunkMgr).getOptionProvider();
}
}

View file

@ -0,0 +1,40 @@
package dev.tilera.cwg.vanilla;
import dev.tilera.cwg.DelegateChunkManager;
import dev.tilera.cwg.api.generator.AbstractChunkManager;
import dev.tilera.cwg.api.generator.IChunkManagerFactory;
import dev.tilera.cwg.api.options.IGeneratorOptionProvider;
import dev.tilera.cwg.api.options.IOption;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.biome.WorldChunkManagerHell;
import net.minecraft.world.gen.ChunkProviderGenerate;
public class SingleBiomeChunkManagerFactory implements IChunkManagerFactory {
@Override
public AbstractChunkManager createChunkManager(IGeneratorOptionProvider options, World world) {
int biomeID = options.getInt("cwg:generator.singleBiome:biomeID");
return new DelegateChunkManager(
options,
new ChunkProviderGenerate(world, world.getSeed(), world.getWorldInfo().isMapFeaturesEnabled()),
new WorldChunkManagerHell(BiomeGenBase.getBiome(biomeID), 1.0f)
);
}
@Override
public String getID() {
return "cwg:singleBiome";
}
@Override
public String getDisplayName() {
return "Single Biome";
}
@Override
public boolean hasSpecificOption(IOption<?> option) {
return option.getID().startsWith("cwg:generator.singleBiome");
}
}