package net.lerariemann.infinity.dimensions; import net.lerariemann.infinity.InfinityMod; import net.lerariemann.infinity.options.RandomInfinityOptions; import net.lerariemann.infinity.util.VersionMethods; import net.lerariemann.infinity.util.core.CommonIO; import net.lerariemann.infinity.util.InfinityMethods; import net.lerariemann.infinity.util.core.ConfigType; import net.lerariemann.infinity.util.core.NbtUtils; import net.lerariemann.infinity.util.core.RandomProvider; import net.lerariemann.infinity.util.platform.InfinityPlatform; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.*; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.tags.BiomeTags; import net.minecraft.tags.TagKey; import net.minecraft.util.Mth; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.storage.LevelResource; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; public class RandomDimension { public final long numericId; public final RandomProvider PROVIDER; public ResourceLocation identifier; public final Random random; public int height; public int min_y; public int sea_level; public boolean randomiseblocks; public CompoundTag default_block; public CompoundTag deepslate; public CompoundTag default_fluid; public List additional_blocks; public List vanilla_biomes; public List random_biome_ids; public List random_biomes; public Map top_blocks; public Map> structure_ids; public Map underwater; public String type_alike; public MinecraftServer server; public CompoundTag data; public RandomDimensionType type; public RandomDimension(ResourceLocation id, MinecraftServer server) { this.server = server; PROVIDER = InfinityMod.provider; identifier = id; numericId = InfinityMethods.getNumericFromId(identifier); random = new Random(numericId); initializeStorage(); /* Code for easter dimensions */ if (PROVIDER.easterizer.easterize(this)) { wrap_up(true); return; } /* Code for procedurally generated dimensions */ genBasics(); type = new RandomDimensionType(this); data.putString("type", type.fullname); data.put("generator", randomDimensionGenerator()); for (Long l: random_biome_ids) if (doesNotContain(Registries.BIOME, "biome_"+l)) { RandomBiome b = new RandomBiome(l, this); random_biomes.add(b); addStructures(b); } writeTags(getRootPath()); wrap_up(false); } public String getName() { return identifier.getPath(); } public String getRootPath() { return server.getWorldPath(LevelResource.DATAPACK_DIR).resolve(getName()).toString(); } public String getStoragePath() { return server.getWorldPath(LevelResource.DATAPACK_DIR).resolve(getName()).resolve("data").resolve(InfinityMod.MOD_ID).toString(); } public void initializeStorage() { data = new CompoundTag(); vanilla_biomes = new ArrayList<>(); random_biome_ids = new ArrayList<>(); random_biomes = new ArrayList<>(); top_blocks = new HashMap<>(); underwater = new HashMap<>(); structure_ids = new HashMap<>(); additional_blocks = new ArrayList<>(); } public void genBasics() { type_alike = PROVIDER.randomName(random, ConfigType.NOISE_PRESETS); min_y = 16*Mth.clamp((int)Math.floor(random.nextExponential() * 2), isOverworldLike() ? -125 : -3, 0); int avgHeight = Mth.clamp(RandomProvider.ruleInt("avgDimensionHeight"), 64, 1024); int max_y = 16*Mth.clamp((int)Math.floor(random.nextGaussian(avgHeight/16.0, avgHeight/64.0)), isOverworldLike() ? 1 : 5, 125); randomiseblocks = PROVIDER.roll(random, "randomise_blocks"); int sea_level_default = 63; if (!isOverworldLike()) sea_level_default = switch(type_alike) { case "minecraft:floating_islands" -> -64; case "minecraft:end" -> 0; case "minecraft:nether", "minecraft:caves" -> 32; default -> 63; }; sea_level = randomiseblocks ? (int)Math.floor(random.nextGaussian(sea_level_default, 8)) : sea_level_default; max_y = Math.max(max_y, 16 * (int) (1 + Math.floor(sea_level / 16.0))); height = max_y - min_y; default_block = randomiseblocks ? PROVIDER.randomElement(random, ConfigType.FULL_BLOCKS_WG) : NbtUtils.nameToElement(getDefaultBlock("minecraft:stone")); default_fluid = randomiseblocks ? PROVIDER.randomElement(random, ConfigType.FLUIDS) : NbtUtils.nameToFluid(getDefaultFluid()); deepslate = Arrays.stream((new String[]{"minecraft:overworld", "minecraft:amplified", "infinity:whack"})).toList().contains(type_alike) ? NbtUtils.nameToElement("minecraft:deepslate") : default_block; } void wrap_up(boolean isEasterDim) { if (!isEasterDim) (new DimensionData(this)).save(); (new RandomInfinityOptions(this, isEasterDim)).save(); CommonIO.write(data, getStoragePath() + "/dimension", getName() + ".json"); if (!(Paths.get(getRootPath() + "/pack.mcmeta")).toFile().exists()) CommonIO.write(InfinityPlatform.dataPackMcmeta("Dimension #" + numericId), getRootPath(), "pack.mcmeta"); } String getDefaultBlock(String fallback) { switch(type_alike) { case "minecraft:end" -> { return "minecraft:end_stone"; } case "minecraft:nether" -> { return "minecraft:netherrack"; } default -> { return fallback; } } } String getDefaultFluid() { switch(type_alike) { case "minecraft:end" -> { return "minecraft:air"; } case "minecraft:nether" -> { return "minecraft:lava"; } default -> { return "minecraft:water"; } } } public boolean doesNotContain(ResourceKey> key, String name) { //? if >1.21.4 { return !(server.registryAccess().lookupOrThrow(key) //?} else { /*return !(server.registryAccess().registryOrThrow(key) *///?} .containsKey(ResourceKey.create(key, InfinityMethods.getId(name)))); } boolean isOverworldLike() { return (type_alike.equals("minecraft:overworld")) || (type_alike.equals("minecraft:large_biomes")) || (type_alike.equals("minecraft:amplified")) || (type_alike.equals("infinity:whack")); } boolean hasCeiling() { return ((type_alike.equals("minecraft:nether")) || (type_alike.equals("minecraft:caves")) || (type_alike.equals("infinity:tangled"))); } CompoundTag randomDimensionGenerator() { CompoundTag res = new CompoundTag(); String type = PROVIDER.randomName(random, ConfigType.GENERATOR_TYPES); res.putString("type", type); switch (type) { case "minecraft:flat" -> { res.put("settings", randomSuperflatSettings()); return res; } case "minecraft:noise" -> { res.put("biome_source", randomBiomeSource()); res.putString("settings", randomNoiseSettings()); res.putLong("seed", numericId ^ server.overworld().getSeed()); return res; } default -> { return res; } } } CompoundTag superflatLayer(int h, String block) { CompoundTag res = new CompoundTag(); res.putInt("height", h); res.putString("block", block); return res; } CompoundTag randomSuperflatSettings() { CompoundTag res = new CompoundTag(); ListTag layers = new ListTag(); String biome = randomBiome(); String block = "minecraft:air"; int layer_count = Math.min(64, 1 + (int) Math.floor(random.nextExponential() * 2)); int heightLeft = height; for (int i = 0; i < layer_count; i++) { int layerHeight = Math.min(heightLeft, 1 + (int) Math.floor(random.nextExponential() * 4)); heightLeft -= layerHeight; block = PROVIDER.randomName(random, ConfigType.FULL_BLOCKS_WG); layers.add(superflatLayer(layerHeight, block)); if (heightLeft <= 1) { break; } } if (random.nextBoolean()) { block = PROVIDER.randomName(random, ConfigType.TOP_BLOCKS); layers.add(superflatLayer(1, block)); } res.putString("biome", biome); res.put("layers", layers); res.putBoolean("lakes", random.nextBoolean()); res.putBoolean("features", random.nextBoolean()); top_blocks.put(biome, NbtUtils.nameToElement(block)); underwater.put(biome, NbtUtils.nameToElement(block)); return res; } CompoundTag randomBiomeSource() { CompoundTag res = new CompoundTag(); String type = PROVIDER.randomName(random, ConfigType.BIOME_SOURCE_TYPES); res.putString("type",type); switch (type) { case "minecraft:the_end" -> { return res; } case "minecraft:checkerboard" -> { res.put("biomes", randomBiomesCheckerboard()); res.putInt("scale", Math.min(62, (int) Math.floor(random.nextExponential() * 2))); return res; } case "minecraft:multi_noise" -> { String preset = PROVIDER.randomName(random, ConfigType.MULTINOISE_PRESETS); if (preset.equals("none") || hasCeiling()) res.put("biomes", randomBiomes()); else { res.putString("preset", preset.replace("_", ":")); addPresetBiomes(preset); } return res; } case "minecraft:fixed" -> res.putString("biome", randomBiome()); } return res; } void addPresetBiomes(String preset) { TagKey tag = preset.equals("overworld") ? BiomeTags.IS_OVERWORLD : BiomeTags.IS_NETHER; Registry r = VersionMethods.getRegistry(server.registryAccess(), Registries.BIOME); r.registryKeySet().forEach(key -> { if (!Objects.equals(key.location().getNamespace(), "infinity")) { if (r.get(key) != null && r.wrapAsHolder(VersionMethods.getFromRegistry(r, key)).is(tag)) vanilla_biomes.add(key.location().toString()); } }); } int getBiomeCount() { return random.nextInt(2, Mth.clamp(RandomProvider.ruleInt("maxBiomeCount"), 2, 10)); } ListTag randomBiomesCheckerboard() { ListTag res = new ListTag(); int biome_count = getBiomeCount(); for (int i = 0; i < biome_count; i++) { res.add(StringTag.valueOf(randomBiome())); } return res; } ListTag randomBiomes() { ListTag res = new ListTag(); int biome_count = getBiomeCount(); for (int i = 0; i < biome_count; i++) { CompoundTag element = new CompoundTag(); element.putString("biome", randomBiome()); element.put("parameters", randomMultiNoiseParameters()); res.add(element); } return res; } CompoundTag randomMultiNoiseParameters() { CompoundTag res = new CompoundTag(); res.put("temperature", randomMultiNoiseParameter()); res.put("humidity", randomMultiNoiseParameter()); res.put("continentalness", randomMultiNoiseParameter()); res.put("erosion", randomMultiNoiseParameter()); res.put("weirdness", DoubleTag.valueOf(0)); res.put("depth", DoubleTag.valueOf(0)); res.put("offset", DoubleTag.valueOf(0)); return res; } Tag randomMultiNoiseParameter() { return DoubleTag.valueOf((random.nextDouble()-0.5)*2); } String randomBiome() { String biome; if (!hasCeiling() && !PROVIDER.roll(random, "use_random_biome")) { biome = PROVIDER.randomName(random, ConfigType.BIOMES); vanilla_biomes.add(biome); } else { long id = InfinityMethods.getRandomSeed(random); random_biome_ids.add(id); biome = "infinity:biome_" + id; } return biome; } String randomNoiseSettings() { RandomNoisePreset preset = new RandomNoisePreset(this); return preset.fullname; } void addStructures(RandomBiome b) { int maxCount = RandomProvider.ruleInt("maxStructureCount"); Set temp = new HashSet<>(); if (maxCount > 0) { maxCount = Math.min(maxCount, 8); int numstructures = random.nextInt(1, maxCount + 1); for (int i = 0; i < numstructures; i++) { addStructure(new RandomStructure(random.nextInt(), b), temp); } } if (PROVIDER.roll( random, "text")) { addStructure(new RandomText(random.nextInt(), b), temp); } } void addStructure(RandomStructure s, Set temp) { if (!temp.contains(s.name)) { temp.add(s.name); s.save(); if (!structure_ids.containsKey(s.type)) structure_ids.put(s.type, new ArrayList<>()); structure_ids.get(s.type).add(s.fullname); } } void writeTags(String rootPath) { String path = rootPath + "/data/minecraft/tags/worldgen/structure"; try { Files.createDirectories(Paths.get(path)); } catch (IOException e) { throw new RuntimeException(e); } CompoundTag dictionary = CommonIO.read(InfinityMod.utilPath + "/structure_tags.json"); Map tags = new HashMap<>(); for (String s : structure_ids.keySet()) for (String ss : NbtUtils.keys(dictionary)) if (s.contains(ss)) { for (Tag e : (ListTag) Objects.requireNonNull(dictionary.get(ss))) { String t = NbtUtils.getAsString(e); if (!tags.containsKey(t)) tags.put(t, new ListTag()); structure_ids.get(s).forEach(fullname -> tags.get(t).add(StringTag.valueOf(fullname))); } } for (String t : tags.keySet()) { CompoundTag compound = new CompoundTag(); compound.putBoolean("replace", false); compound.put("values", tags.get(t)); CommonIO.write(compound, path, t + ".json"); } } }