diff --git a/build.gradle.kts b/build.gradle.kts index db0ed685b..60ac2571e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ import com.dfsek.terra.getGitHash -val versionObj = Version("5", "3", "2", true) +val versionObj = Version("5", "3", "3", true) allprojects { version = versionObj diff --git a/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackLoadEvent.java b/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackLoadEvent.java index 7aa7ab8a4..e995c8897 100644 --- a/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackLoadEvent.java +++ b/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackLoadEvent.java @@ -1,5 +1,7 @@ package com.dfsek.terra.api.event.events.config; +import com.dfsek.tectonic.config.ConfigTemplate; +import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.terra.api.event.events.PackEvent; import com.dfsek.terra.config.pack.ConfigPack; @@ -8,13 +10,28 @@ import com.dfsek.terra.config.pack.ConfigPack; */ public abstract class ConfigPackLoadEvent implements PackEvent { private final ConfigPack pack; + private final ExceptionalConsumer configLoader; - public ConfigPackLoadEvent(ConfigPack pack) { + public ConfigPackLoadEvent(ConfigPack pack, ExceptionalConsumer configLoader) { this.pack = pack; + this.configLoader = configLoader; } @Override public ConfigPack getPack() { return pack; } + + /** + * Load a custom {@link ConfigTemplate} using the pack manifest. + * + * @param template Template to register. + */ + public void loadTemplate(ConfigTemplate template) throws ConfigException { + configLoader.accept(template); + } + + public interface ExceptionalConsumer { + void accept(T value) throws ConfigException; + } } diff --git a/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPostLoadEvent.java b/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPostLoadEvent.java index 138de647c..1398ec219 100644 --- a/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPostLoadEvent.java +++ b/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPostLoadEvent.java @@ -1,12 +1,13 @@ package com.dfsek.terra.api.event.events.config; +import com.dfsek.tectonic.config.ConfigTemplate; import com.dfsek.terra.config.pack.ConfigPack; /** * Called when a config pack has finished loading. */ public class ConfigPackPostLoadEvent extends ConfigPackLoadEvent { - public ConfigPackPostLoadEvent(ConfigPack pack) { - super(pack); + public ConfigPackPostLoadEvent(ConfigPack pack, ExceptionalConsumer loader) { + super(pack, loader); } } diff --git a/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPreLoadEvent.java b/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPreLoadEvent.java index 317603c9e..1ac2de54d 100644 --- a/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPreLoadEvent.java +++ b/common/src/main/java/com/dfsek/terra/api/event/events/config/ConfigPackPreLoadEvent.java @@ -1,12 +1,14 @@ package com.dfsek.terra.api.event.events.config; +import com.dfsek.tectonic.config.ConfigTemplate; +import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.terra.config.pack.ConfigPack; /** * Called before a config pack's registries are filled. At this point, the pack manifest has been loaded, and all registries are empty. */ public class ConfigPackPreLoadEvent extends ConfigPackLoadEvent { - public ConfigPackPreLoadEvent(ConfigPack pack) { - super(pack); + public ConfigPackPreLoadEvent(ConfigPack pack, ExceptionalConsumer configLoader) { + super(pack, configLoader); } } diff --git a/common/src/main/java/com/dfsek/terra/api/transform/NotNullValidator.java b/common/src/main/java/com/dfsek/terra/api/transform/NotNullValidator.java deleted file mode 100644 index b94b7be39..000000000 --- a/common/src/main/java/com/dfsek/terra/api/transform/NotNullValidator.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.dfsek.terra.api.transform; - -public class NotNullValidator implements Validator { - @Override - public boolean validate(T value) { - return !(value == null); - } -} diff --git a/common/src/main/java/com/dfsek/terra/api/transform/Validator.java b/common/src/main/java/com/dfsek/terra/api/transform/Validator.java index c9ba5db9e..b22b7c08b 100644 --- a/common/src/main/java/com/dfsek/terra/api/transform/Validator.java +++ b/common/src/main/java/com/dfsek/terra/api/transform/Validator.java @@ -1,6 +1,12 @@ package com.dfsek.terra.api.transform; +import java.util.Objects; + public interface Validator { boolean validate(T value) throws TransformException; + + static Validator notNull() { + return Objects::nonNull; + } } diff --git a/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java b/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java index 02772f633..871b4ebe3 100644 --- a/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java +++ b/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java @@ -2,6 +2,7 @@ package com.dfsek.terra.config.pack; import com.dfsek.paralithic.eval.parser.Scope; import com.dfsek.tectonic.abstraction.AbstractConfigLoader; +import com.dfsek.tectonic.config.Configuration; import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.loading.ConfigLoader; @@ -110,6 +111,8 @@ public class ConfigPack implements LoaderRegistrar { private final TerraPlugin main; private final Loader loader; + private final Configuration configuration; + private final BiomeProvider.BiomeProviderBuilder biomeProviderBuilder; @@ -130,11 +133,15 @@ public class ConfigPack implements LoaderRegistrar { File pack = new File(folder, "pack.yml"); try { - selfLoader.load(template, new FileInputStream(pack)); + configuration = new Configuration(new FileInputStream(pack)); + selfLoader.load(template, configuration); main.logger().info("Loading config pack \"" + template.getID() + "\""); + main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, configuration))); + load(l, main); + ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate(); selfLoader.load(packPostTemplate, new FileInputStream(pack)); biomeProviderBuilder = packPostTemplate.getProviderBuilder(); @@ -174,9 +181,12 @@ public class ConfigPack implements LoaderRegistrar { if(pack == null) throw new LoadException("No pack.yml file found in " + file.getName()); - selfLoader.load(template, file.getInputStream(pack)); + configuration = new Configuration(file.getInputStream(pack)); + selfLoader.load(template, configuration); main.logger().info("Loading config pack \"" + template.getID() + "\""); + main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, configuration))); + load(l, main); ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate(); @@ -211,8 +221,6 @@ public class ConfigPack implements LoaderRegistrar { private void load(long start, TerraPlugin main) throws ConfigException { - main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this)); - for(Map.Entry var : template.getVariables().entrySet()) { varScope.create(var.getKey(), var.getValue()); } @@ -245,7 +253,7 @@ public class ConfigPack implements LoaderRegistrar { .open("flora", ".yml").then(configs -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.loadConfigs(configs, FloraTemplate::new), main)).close() .open("biomes", ".yml").then(configs -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.loadConfigs(configs, () -> new BiomeTemplate(this, main)), main)).close(); - main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this)); + main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this, template -> selfLoader.load(template, configuration))); main.logger().info("Loaded config pack \"" + template.getID() + "\" v" + template.getVersion() + " by " + template.getAuthor() + " in " + (System.nanoTime() - start) / 1000000D + "ms."); } diff --git a/common/src/main/resources/lang/cs_cz.yml b/common/src/main/resources/lang/cs_cz.yml new file mode 100644 index 000000000..c01c6fcf9 --- /dev/null +++ b/common/src/main/resources/lang/cs_cz.yml @@ -0,0 +1,122 @@ +enable: + - "Pokud se vám líbí Terra, můžete nás podpořit na Patreon!" + - "Získáte přístup k experimentálním funkcím, než budou vydány!" + - "Podpořit projekt můžete zde: https://www.patreon.com/dfsek" +disable: + - "Děkujeme, že používáte Terra!" +command: + debug-only: "Tento příkaz musí být použit se zapnutým debug modem!" + player-only: "Tento příkaz je pouze pro hráče!" + invalid: "Neznámý příkaz. (Očekáváno %1$s argumentů, nalezeno %2$s)." + players-only: "Příkaz je pouze pro použití hráčem." + world: "Tento příkaz musí být použit v Terra světě!" + reload: "Obnoven Terra konfig." + reload-error: "Nastaly chyby při obnově Terra konfigurace. Podívejte se do logů pro více informací." + version: "Na tomto serveru běží Terra verze \"%1$s\", na platformě \"%2$s\"" + main-menu: + - "--------------------Terra--------------------" + - "reload - Obnoví konfigurační data" + - "biome - Ukáže aktuální biom" + - "ore - Generuje žílu rud v lokaci, ve směru kam se koukáte (Pro debugging)" + - "save-data - Uložit populační data" + - "structure - Nahrát a exportovat struktury" + - "profile - Profiler možnosti" + - "image - Obrázek/GUI možnosti" + biome: + biome-found: "Lokalizován biom na (%1$s, %2$s)" + unable-to-locate: "Nelze lokalizovat biom." + invalid-radius: "Nesprávný radius: \"%s\"" + invalid: "Nesprávné ID bomu: \"%s\"" + in: "Jste v \"%s\"" + packs: + main: "Aktuální instalované konfigurační balíčky:" + pack: " - %1$s v%3$s od %2$s" + none: "Žádné konfigurační balíčky nejsou nainstalovány." + ore: + main-menu: + - "---------------Terra/ore---------------" + - "Generuje žílu rud na bloku, na který koukáte." + out-of-range: "Blok mimo dosah" + invalid-ore: "Nelze nalézt Rudu \"%s\"" + geometry: + main-menu: + - "---------------Terra/geometry----------------" + - "Různé voxel geometrické debugging příkazy" + - "sphere - Generuje kouli" + - "deformsphere - Generuje deformovanou kouli" + - "tube - Generuje válec" + deform: + invalid-radius: "Nesprávný radius: \"%s\"" + invalid-deform: "Nesprávná deformace: \"%s\"" + invalid-frequency: "Nesprávná frekvence: \"%s\"" + sphere: + invalid-radius: "Nesprávný radius: \"%s\"" + tube: + invalid-radius: "Nesprávný radius: \"%s\"" + image: + main-menu: + - "---------------Terra/image---------------" + - "render - Vykreslí obrázek s danou šířkou a výškou, který může být později importován jako svět." + - "gui - Otevřít debug GUI (Musí být zapnuto v konfigu)" + gui: + main-menu: + - "-------------Terra/image/gui-------------" + - "raw - Otevře GUI s raw Biom daty" + - "step - Znovu vykreslí data k lepšímu zobrazení borderu" + debug: "Debug mod musí být zapnutý pro použití této možnosti! Debug GUI NENÍ PRODUKČNĚ BEZPEČNÉ!" + render: + save: "Uložen obrázek jako \"%s\"" + error: "Nastala chyba při generování obrázku!" + profile: + main-menu: + - "---------------Terra/profile---------------" + - "start - Zapne profiler" + - "stop - Vypne profiler" + - "query - Ukáže profiler data" + - "reset - Resetuje profiler data" + reset: "Profiler byl resetován." + start: "Profiler byl zapnut." + stop: "Profiler byl vypnut." + structure: + main-menu: + - "---------------Terra/structure---------------" + - "export - Export vašeho výběru WorldEdit jako Terra struktura." + - "load - Načíst Terra strukturu" + invalid-radius: "Nesprávný radius: \"%s\"" + invalid-rotation: "Nesprávná rotace: \"%s\"" + invalid: "Nesprávné ID struktury: \"%s\"" + export: "Uložena struktura do \"%s\"" +world-config: + load: "Načteny konfigurační hodnoty světa pro svět \"%s\"..." + not-found: "Konfigurace pro svět \"%s\" nenalezena. Kopíruji defaultní konfig." + using-image: "Načítám svět z obrázku." + error: "Nelze načíst konfigurace pro svět %s" + done: "Načítání světa \"%1$s\" dokončeno. Uplynulý čas: %2$sms" +config-pack: + loaded: "Konfigurační balíček %1$s v%4$s od %3$s byl načten za %2$sms." +config: + loaded: "Načten %1$s ze souboru %2$s" + loaded-all: "Načteno %1$s %2$s(s) za %3$sms." + error: + invalid-failover: "Nesprávný typ failover: \"%s\"" + duplicate: "Duplikační ID nalezeno v souboru: %s" + file: + - "Konfigurační chyba pro Terra objekt. Soubor: %1$s" + - "%2$s" + - "Opravte jej před pokračováním!" + generic: + - "Nastala chyba při načítání konfigurace." + - "Prosíme nahlašte to na Terra." +warning: + no-population: "Žádné populační chunky nebyly načteny. Pokud je to poprvé, co zapínáte server s Terra, či vytváříte nový svět, je tohle normální." +error: + severe-config: "Vážná konfigurační chyba zabránila Terra ze správné generace terénu na koordinátech: %1$s, %2$s. Prosíme zkontrolujte konfiguraci pro chyby. Jakékoli konfigurační chyby jsou vypsány výše." +debug: + data-save : "Uložena populační data." +use-paper: + - "Vypadá to, že používáte Spigot/CraftBukkit." + - "Ačkoli Terra &ofunguje&r na Spigot, některé funkce budou ztraceny. (Terra je netestována na CraftBukkit; žádná podpora nebude dána pro CraftBukkit)." + - "Pro nejvíce funkcí s Terra, použijte Paper." + - "Navíc, Paper přináší obrovské výkonnostní zlepešení než Spigot, a všechny Spigot pluginy by měli fungovat s Paper!" + - "Pro nejlepší zážitek s Terra a všemi pluginy, použijte prosím Paper." + - "Více info najdete na stránce Paperu: https://papermc.io/" diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java index a51328b45..3778da03a 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java @@ -1,5 +1,7 @@ package com.dfsek.terra.fabric; +import com.dfsek.tectonic.exception.ConfigException; +import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.loading.TypeRegistry; import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.addons.TerraAddon; @@ -14,6 +16,7 @@ import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.TerraEventManager; import com.dfsek.terra.api.event.annotations.Global; import com.dfsek.terra.api.event.annotations.Priority; +import com.dfsek.terra.api.event.events.config.ConfigPackPostLoadEvent; import com.dfsek.terra.api.event.events.config.ConfigPackPreLoadEvent; import com.dfsek.terra.api.platform.block.BlockData; import com.dfsek.terra.api.platform.handle.ItemHandle; @@ -22,94 +25,87 @@ import com.dfsek.terra.api.platform.world.Tree; import com.dfsek.terra.api.platform.world.World; import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.LockedRegistry; -import com.dfsek.terra.api.transform.NotNullValidator; import com.dfsek.terra.api.transform.Transformer; +import com.dfsek.terra.api.transform.Validator; +import com.dfsek.terra.api.util.generic.pair.Pair; import com.dfsek.terra.api.util.logging.DebugLogger; import com.dfsek.terra.api.util.logging.Logger; import com.dfsek.terra.commands.CommandUtil; import com.dfsek.terra.config.GenericLoaders; import com.dfsek.terra.config.PluginConfig; -import com.dfsek.terra.config.builder.BiomeBuilder; import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.lang.Language; import com.dfsek.terra.config.pack.ConfigPack; -import com.dfsek.terra.config.templates.BiomeTemplate; +import com.dfsek.terra.fabric.config.PostLoadCompatibilityOptions; +import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; import com.dfsek.terra.fabric.generation.PopulatorFeature; import com.dfsek.terra.fabric.generation.TerraBiomeSource; import com.dfsek.terra.fabric.handle.FabricItemHandle; import com.dfsek.terra.fabric.handle.FabricWorldHandle; -import com.dfsek.terra.fabric.mixin.access.BiomeEffectsAccessor; -import com.dfsek.terra.fabric.mixin.access.GeneratorTypeAccessor; +import com.dfsek.terra.fabric.util.FabricUtil; import com.dfsek.terra.profiler.Profiler; import com.dfsek.terra.profiler.ProfilerImpl; import com.dfsek.terra.registry.exception.DuplicateEntryException; import com.dfsek.terra.registry.master.AddonRegistry; import com.dfsek.terra.registry.master.ConfigRegistry; import com.dfsek.terra.world.TerraWorld; -import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.block.Blocks; -import net.minecraft.client.world.GeneratorType; -import net.minecraft.text.LiteralText; +import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.WorldAccess; import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeEffects; -import net.minecraft.world.biome.GenerationSettings; -import net.minecraft.world.gen.GenerationStep; -import net.minecraft.world.gen.chunk.ChunkGenerator; -import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.gen.decorator.Decorator; import net.minecraft.world.gen.decorator.NopeDecoratorConfig; import net.minecraft.world.gen.feature.ConfiguredFeature; import net.minecraft.world.gen.feature.ConfiguredFeatures; import net.minecraft.world.gen.feature.DefaultFeatureConfig; import net.minecraft.world.gen.feature.FeatureConfig; -import net.minecraft.world.gen.surfacebuilder.SurfaceBuilder; -import net.minecraft.world.gen.surfacebuilder.TernarySurfaceConfig; import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.LogManager; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.HashMap; -import java.util.Locale; import java.util.Map; public class TerraFabricPlugin implements TerraPlugin, ModInitializer { - + private final org.apache.logging.log4j.Logger log4jLogger = LogManager.getLogger(); public static final PopulatorFeature POPULATOR_FEATURE = new PopulatorFeature(DefaultFeatureConfig.CODEC); public static final ConfiguredFeature POPULATOR_CONFIGURED_FEATURE = POPULATOR_FEATURE.configure(FeatureConfig.DEFAULT).decorate(Decorator.NOPE.configure(NopeDecoratorConfig.INSTANCE)); private static TerraFabricPlugin instance; - private final Map worldMap = new HashMap<>(); + private final Map> worldMap = new HashMap<>(); + + public Map> getWorldMap() { + return worldMap; + } + private final EventManager eventManager = new TerraEventManager(this); private final GenericLoaders genericLoaders = new GenericLoaders(this); private final Profiler profiler = new ProfilerImpl(); private final Logger logger = new Logger() { - private final org.apache.logging.log4j.Logger logger = LogManager.getLogger(); - @Override public void info(String message) { - logger.info(message); + log4jLogger.info(message); } @Override public void warning(String message) { - logger.warn(message); + log4jLogger.warn(message); } @Override public void severe(String message) { - logger.error(message); + log4jLogger.error(message); } }; @@ -118,12 +114,16 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { private final WorldHandle worldHandle = new FabricWorldHandle(); private final ConfigRegistry registry = new ConfigRegistry(); private final CheckedRegistry checkedRegistry = new CheckedRegistry<>(registry); - private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this); + + private final FabricAddon fabricAddon = new FabricAddon(this); + private final AddonRegistry addonRegistry = new AddonRegistry(fabricAddon, this); private final LockedRegistry addonLockedRegistry = new LockedRegistry<>(addonRegistry); + private final PluginConfig config = new PluginConfig(); + private final Transformer biomeFixer = new Transformer.Builder() - .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), new NotNullValidator<>()) - .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build(); + .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), Validator.notNull()) + .addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), Validator.notNull()).build(); private File dataFolder; private final CommandManager manager = new TerraCommandManager(this); @@ -135,10 +135,6 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { return instance; } - public static String createBiomeID(ConfigPack pack, String biomeID) { - return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT); - } - @Override public WorldHandle getWorldHandle() { return worldHandle; @@ -146,15 +142,12 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { @Override public TerraWorld getWorld(World world) { - return worldMap.computeIfAbsent(world.getSeed(), w -> { - logger.info("Loading world " + w); - return new TerraWorld(world, ((FabricChunkGeneratorWrapper) world.getGenerator()).getPack(), this); - }); + return getWorld(((WorldAccess) world).getDimension()); } - public TerraWorld getWorld(long seed) { - TerraWorld world = worldMap.get(seed); - if(world == null) throw new IllegalArgumentException("No world exists with seed " + seed); + public TerraWorld getWorld(DimensionType type) { + TerraWorld world = worldMap.get(type).getRight(); + if(world == null) throw new IllegalArgumentException("No world exists with dimension type " + type); return world; } @@ -175,7 +168,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { @Override public boolean isDebug() { - return true; + return config.isDebug(); } @Override @@ -198,14 +191,11 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { config.load(this); LangUtil.load(config.getLanguage(), this); // Load language. boolean succeed = registry.loadAll(this); - Map newMap = new HashMap<>(); - worldMap.forEach((seed, tw) -> { - tw.getConfig().getSamplerCache().clear(); - String packID = tw.getConfig().getTemplate().getID(); - newMap.put(seed, new TerraWorld(tw.getWorld(), registry.get(packID), this)); + worldMap.forEach((seed, pair) -> { + pair.getRight().getConfig().getSamplerCache().clear(); + String packID = pair.getRight().getConfig().getTemplate().getID(); + pair.setRight(new TerraWorld(pair.getRight().getWorld(), registry.get(packID), this)); }); - worldMap.clear(); - worldMap.putAll(newMap); return succeed; } @@ -239,71 +229,19 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { genericLoaders.register(registry); registry .registerLoader(BlockData.class, (t, o, l) -> worldHandle.createBlockData((String) o)) - .registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> biomeFixer.translate((String) o)); - } - - private Biome createBiome(BiomeBuilder biome) { - BiomeTemplate template = biome.getTemplate(); - Map colors = template.getColors(); - - Biome vanilla = (Biome) (new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle(); - - GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); - generationSettings.surfaceBuilder(SurfaceBuilder.DEFAULT.withConfig(new TernarySurfaceConfig(Blocks.GRASS_BLOCK.getDefaultState(), Blocks.DIRT.getDefaultState(), Blocks.GRAVEL.getDefaultState()))); // It needs a surfacebuilder, even though we dont use it. - generationSettings.feature(GenerationStep.Feature.VEGETAL_DECORATION, POPULATOR_CONFIGURED_FEATURE); - - - BiomeEffectsAccessor accessor = (BiomeEffectsAccessor) vanilla.getEffects(); - BiomeEffects.Builder effects = new BiomeEffects.Builder() - .waterColor(colors.getOrDefault("water", accessor.getWaterColor())) - .waterFogColor(colors.getOrDefault("water-fog", accessor.getWaterFogColor())) - .fogColor(colors.getOrDefault("fog", accessor.getFogColor())) - .skyColor(colors.getOrDefault("sky", accessor.getSkyColor())) - .grassColorModifier(accessor.getGrassColorModifier()); - - if(colors.containsKey("grass")) { - effects.grassColor(colors.get("grass")); - } else { - accessor.getGrassColor().ifPresent(effects::grassColor); - } - if(colors.containsKey("foliage")) { - effects.foliageColor(colors.get("foliage")); - } else { - accessor.getFoliageColor().ifPresent(effects::foliageColor); - } - - return new Biome.Builder() - .precipitation(vanilla.getPrecipitation()) - .category(vanilla.getCategory()) - .depth(vanilla.getDepth()) - .scale(vanilla.getScale()) - .temperature(vanilla.getTemperature()) - .downfall(vanilla.getDownfall()) - .effects(effects.build()) - .spawnSettings(vanilla.getSpawnSettings()) - .generationSettings(generationSettings.build()) - .build(); + .registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> biomeFixer.translate((String) o)) + .registerLoader(Identifier.class, (t, o, l) -> { + Identifier identifier = Identifier.tryParse((String) o); + if(identifier == null) throw new LoadException("Invalid identifier: " + o); + return identifier; + }); } public void packInit() { logger.info("Loading config packs..."); registry.loadAll(this); - registry.forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> Registry.register(BuiltinRegistries.BIOME, new Identifier("terra", createBiomeID(pack, id)), createBiome(biome)))); // Register all Terra biomes. - - if(FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - registry.forEach(pack -> { - final GeneratorType generatorType = new GeneratorType("terra." + pack.getTemplate().getID()) { - @Override - protected ChunkGenerator getChunkGenerator(Registry biomeRegistry, Registry chunkGeneratorSettingsRegistry, long seed) { - return new FabricChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack); - } - }; - //noinspection ConstantConditions - ((GeneratorTypeAccessor) generatorType).setTranslationKey(new LiteralText("Terra:" + pack.getTemplate().getID())); - GeneratorTypeAccessor.getValues().add(generatorType); - }); - } + registry.forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> Registry.register(BuiltinRegistries.BIOME, new Identifier("terra", FabricUtil.createBiomeID(pack, id)), FabricUtil.createBiome(fabricAddon, biome, pack)))); // Register all Terra biomes. logger.info("Loaded packs."); } @@ -315,6 +253,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { this.dataFolder = new File(FabricLoader.getInstance().getConfigDir().toFile(), "Terra"); saveDefaultConfig(); config.load(this); + debugLogger.setDebug(config.isDebug()); LangUtil.load(config.getLanguage(), this); logger.info("Initializing Terra..."); @@ -324,9 +263,8 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { logger.info("Loaded addons."); - - Registry.register(Registry.FEATURE, new Identifier("terra", "flora_populator"), POPULATOR_FEATURE); - RegistryKey> floraKey = RegistryKey.of(Registry.CONFIGURED_FEATURE_WORLDGEN, new Identifier("terra", "flora_populator")); + Registry.register(Registry.FEATURE, new Identifier("terra", "populator"), POPULATOR_FEATURE); + RegistryKey> floraKey = RegistryKey.of(Registry.CONFIGURED_FEATURE_WORLDGEN, new Identifier("terra", "populator")); Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, floraKey.getValue(), POPULATOR_CONFIGURED_FEATURE); Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), FabricChunkGeneratorWrapper.CODEC); @@ -355,10 +293,12 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { @Addon("Terra-Fabric") @Author("Terra") @Version("1.0.0") - private static final class FabricAddon extends TerraAddon implements EventListener { + public static final class FabricAddon extends TerraAddon implements EventListener { private final TerraPlugin main; + private final Map> templates = new HashMap<>(); + private FabricAddon(TerraPlugin main) { this.main = main; } @@ -391,6 +331,40 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { injectTree(treeRegistry, "MEGA_SPRUCE", ConfiguredFeatures.MEGA_SPRUCE); injectTree(treeRegistry, "CRIMSON_FUNGUS", ConfiguredFeatures.CRIMSON_FUNGI); injectTree(treeRegistry, "WARPED_FUNGUS", ConfiguredFeatures.WARPED_FUNGI); + + PreLoadCompatibilityOptions template = new PreLoadCompatibilityOptions(); + try { + event.loadTemplate(template); + } catch(ConfigException e) { + e.printStackTrace(); + } + + if(template.doRegistryInjection()) { + BuiltinRegistries.CONFIGURED_FEATURE.getEntries().forEach(entry -> { + if(!template.getExcludedRegistryFeatures().contains(entry.getKey().getValue())) { + try { + event.getPack().getTreeRegistry().add(entry.getKey().getValue().toString(), (Tree) entry.getValue()); + main.getDebugLogger().info("Injected ConfiguredFeature " + entry.getKey().getValue() + " as Tree."); + } catch(DuplicateEntryException ignored) { + } + } + }); + } + templates.put(event.getPack(), Pair.of(template, null)); + } + + @Priority(Priority.HIGHEST) + @Global + public void createInjectionOptions(ConfigPackPostLoadEvent event) { + PostLoadCompatibilityOptions template = new PostLoadCompatibilityOptions(); + + try { + event.loadTemplate(template); + } catch(ConfigException e) { + e.printStackTrace(); + } + + templates.get(event.getPack()).setRight(template); } @@ -400,5 +374,9 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer { } catch(DuplicateEntryException ignore) { } } + + public Map> getTemplates() { + return templates; + } } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java new file mode 100644 index 000000000..ae812bed5 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java @@ -0,0 +1,30 @@ +package com.dfsek.terra.fabric.config; + +import com.dfsek.tectonic.annotations.Default; +import com.dfsek.tectonic.annotations.Value; +import com.dfsek.tectonic.config.ConfigTemplate; +import com.dfsek.terra.config.builder.BiomeBuilder; +import net.minecraft.util.Identifier; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@SuppressWarnings("FieldMayBeFinal") +public class PostLoadCompatibilityOptions implements ConfigTemplate { + @Value("structures.inject-biome.exclude-biomes") + @Default + private Map> excludedPerBiomeStructures = new HashMap<>(); + + @Value("features.inject-biome.exclude-biomes") + @Default + private Map> excludedPerBiomeFeatures = new HashMap<>(); + + public Map> getExcludedPerBiomeFeatures() { + return excludedPerBiomeFeatures; + } + + public Map> getExcludedPerBiomeStructures() { + return excludedPerBiomeStructures; + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java new file mode 100644 index 000000000..bcaef6237 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java @@ -0,0 +1,55 @@ +package com.dfsek.terra.fabric.config; + +import com.dfsek.tectonic.annotations.Default; +import com.dfsek.tectonic.annotations.Value; +import com.dfsek.tectonic.config.ConfigTemplate; +import com.dfsek.terra.config.builder.BiomeBuilder; +import net.minecraft.util.Identifier; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +@SuppressWarnings("FieldMayBeFinal") +public class PreLoadCompatibilityOptions implements ConfigTemplate { + @Value("features.inject-registry.enable") + @Default + private boolean doRegistryInjection = false; + + @Value("features.inject-biome.enable") + @Default + private boolean doBiomeInjection = false; + + @Value("features.inject-registry.excluded-features") + @Default + private Set excludedRegistryFeatures = new HashSet<>(); + + @Value("features.inject-biome.excluded-features") + @Default + private Set excludedBiomeFeatures = new HashSet<>(); + + @Value("structures.inject-biome.excluded-features") + @Default + private Set excludedBiomeStructures = new HashSet<>(); + + public boolean doBiomeInjection() { + return doBiomeInjection; + } + + public boolean doRegistryInjection() { + return doRegistryInjection; + } + + public Set getExcludedBiomeFeatures() { + return excludedBiomeFeatures; + } + + public Set getExcludedRegistryFeatures() { + return excludedRegistryFeatures; + } + + public Set getExcludedBiomeStructures() { + return excludedBiomeStructures; + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java index b4efa496e..1c9d587ed 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java @@ -4,6 +4,7 @@ import com.dfsek.terra.api.platform.world.World; import com.dfsek.terra.api.platform.world.generator.ChunkData; import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper; import com.dfsek.terra.api.util.FastRandom; +import com.dfsek.terra.api.world.biome.UserDefinedBiome; import com.dfsek.terra.api.world.generation.TerraChunkGenerator; import com.dfsek.terra.api.world.locate.AsyncStructureFinder; import com.dfsek.terra.config.pack.ConfigPack; @@ -27,9 +28,13 @@ import net.minecraft.util.registry.Registry; import net.minecraft.world.BlockView; import net.minecraft.world.ChunkRegion; import net.minecraft.world.Heightmap; +import net.minecraft.world.SpawnHelper; import net.minecraft.world.WorldAccess; +import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.source.BiomeAccess; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.ChunkRandom; import net.minecraft.world.gen.GenerationStep; import net.minecraft.world.gen.StructureAccessor; import net.minecraft.world.gen.chunk.ChunkGenerator; @@ -55,6 +60,7 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener PACK_CODEC.fieldOf("pack").stable().forGetter(generator -> generator.pack)) .apply(instance, instance.stable(FabricChunkGeneratorWrapper::new))); private final ConfigPack pack; + private DimensionType dimensionType; public ConfigPack getPack() { return pack; @@ -87,26 +93,31 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener } + public void setDimensionType(DimensionType dimensionType) { + this.dimensionType = dimensionType; + } + @Nullable @Override public BlockPos locateStructure(ServerWorld world, StructureFeature feature, BlockPos center, int radius, boolean skipExistingChunks) { - String name = Objects.requireNonNull(Registry.STRUCTURE_FEATURE.getId(feature)).toString(); - TerraWorld terraWorld = TerraFabricPlugin.getInstance().getWorld((World) world); - TerraStructure located = pack.getStructure(pack.getTemplate().getLocatable().get(name)); - if(located != null) { - CompletableFuture result = new CompletableFuture<>(); - AsyncStructureFinder finder = new AsyncStructureFinder(terraWorld.getBiomeProvider(), located, FabricAdapter.adapt(center).toLocation((World) world), 0, 500, location -> { - result.complete(FabricAdapter.adapt(location)); - }, TerraFabricPlugin.getInstance()); - finder.run(); // Do this synchronously. - try { - return result.get(); - } catch(InterruptedException | ExecutionException e) { - throw new RuntimeException(e); + if(!pack.getTemplate().disableStructures()) { + String name = Objects.requireNonNull(Registry.STRUCTURE_FEATURE.getId(feature)).toString(); + TerraWorld terraWorld = TerraFabricPlugin.getInstance().getWorld((World) world); + TerraStructure located = pack.getStructure(pack.getTemplate().getLocatable().get(name)); + if(located != null) { + CompletableFuture result = new CompletableFuture<>(); + AsyncStructureFinder finder = new AsyncStructureFinder(terraWorld.getBiomeProvider(), located, FabricAdapter.adapt(center).toLocation((World) world), 0, 500, location -> { + result.complete(FabricAdapter.adapt(location)); + }, TerraFabricPlugin.getInstance()); + finder.run(); // Do this synchronously. + try { + return result.get(); + } catch(InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } } } - TerraFabricPlugin.getInstance().logger().warning("No overrides are defined for \"" + name + "\""); - return null; + return super.locateStructure(world, feature, center, radius, skipExistingChunks); } @Override @@ -127,32 +138,32 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener @Override public boolean isStrongholdStartingChunk(ChunkPos chunkPos) { + if(pack.getTemplate().vanillaStructures()) return super.isStrongholdStartingChunk(chunkPos); return false; } @Override public int getHeight(int x, int z, Heightmap.Type heightmapType) { - TerraWorld world = TerraFabricPlugin.getInstance().getWorld(seed); + TerraWorld world = TerraFabricPlugin.getInstance().getWorld(dimensionType); Sampler sampler = world.getConfig().getSamplerCache().getChunk(FastMath.floorDiv(x, 16), FastMath.floorDiv(z, 16)); int cx = FastMath.floorMod(x, 16); int cz = FastMath.floorMod(z, 16); int height = world.getWorld().getMaxHeight(); - while (height >= 0 && sampler.sample(cx, height - 1, cz) < 0) { - height--; - } + while(height >= 0 && sampler.sample(cx, height-1, cz) < 0) height--; return height; } @Override public BlockView getColumnSample(int x, int z) { - int height = 64; // TODO: implementation + TerraWorld world = TerraFabricPlugin.getInstance().getWorld(dimensionType); + int height = getHeight(x, z, Heightmap.Type.WORLD_SURFACE); BlockState[] array = new BlockState[256]; for(int y = 255; y >= 0; y--) { if(y > height) { - if(y > getSeaLevel()) { + if(y > ((UserDefinedBiome) world.getBiomeProvider().getBiome(x, z)).getConfig().getSeaLevel()) { array[y] = Blocks.AIR.getDefaultState(); } else { array[y] = Blocks.WATER.getDefaultState(); @@ -165,6 +176,18 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener return new VerticalBlockSample(array); } + @Override + public void populateEntities(ChunkRegion region) { + if(pack.getTemplate().vanillaMobs()) { + int cx = region.getCenterChunkX(); + int cy = region.getCenterChunkZ(); + Biome biome = region.getBiome((new ChunkPos(cx, cy)).getStartPos()); + ChunkRandom chunkRandom = new ChunkRandom(); + chunkRandom.setPopulationSeed(region.getSeed(), cx << 4, cy << 4); + SpawnHelper.populateEntities(region, biome, cx, cy, chunkRandom); + } + } + @Override public TerraChunkGenerator getHandle() { return delegate; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java index e2d821192..d83ae46ad 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java @@ -4,6 +4,7 @@ import com.dfsek.terra.api.world.biome.UserDefinedBiome; import com.dfsek.terra.api.world.biome.provider.BiomeProvider; import com.dfsek.terra.config.pack.ConfigPack; import com.dfsek.terra.fabric.TerraFabricPlugin; +import com.dfsek.terra.fabric.util.FabricUtil; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.util.Identifier; @@ -11,8 +12,8 @@ import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryLookupCodec; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.source.BiomeSource; -import net.minecraft.world.gen.feature.StructureFeature; +import java.util.Objects; import java.util.stream.Collectors; public class TerraBiomeSource extends BiomeSource { @@ -31,7 +32,9 @@ public class TerraBiomeSource extends BiomeSource { private final ConfigPack pack; public TerraBiomeSource(Registry biomes, long seed, ConfigPack pack) { - super(biomes.stream().collect(Collectors.toList())); + super(biomes.stream() + .filter(biome -> Objects.requireNonNull(biomes.getId(biome)).getNamespace().equals("terra")) // Filter out non-Terra biomes. + .collect(Collectors.toList())); this.biomeRegistry = biomes; this.seed = seed; this.grid = pack.getBiomeProviderBuilder().build(seed); @@ -51,14 +54,6 @@ public class TerraBiomeSource extends BiomeSource { @Override public Biome getBiomeForNoiseGen(int biomeX, int biomeY, int biomeZ) { UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome(biomeX << 2, biomeZ << 2); - return biomeRegistry.get(new Identifier("terra", TerraFabricPlugin.createBiomeID(pack, biome.getID()))); + return biomeRegistry.get(new Identifier("terra", FabricUtil.createBiomeID(pack, biome.getID()))); } - - - @Override - public boolean hasStructureFeature(StructureFeature feature) { - return false; - } - - } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraGeneratorType.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraGeneratorType.java new file mode 100644 index 000000000..6ae8dac89 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraGeneratorType.java @@ -0,0 +1,22 @@ +package com.dfsek.terra.fabric.generation; + +import com.dfsek.terra.config.pack.ConfigPack; +import net.minecraft.client.world.GeneratorType; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; + +public class TerraGeneratorType extends GeneratorType { + private final ConfigPack pack; + + public TerraGeneratorType(ConfigPack pack) { + super("terra." + pack.getTemplate().getID()); + this.pack = pack; + } + + @Override + protected ChunkGenerator getChunkGenerator(Registry biomeRegistry, Registry chunkGeneratorSettingsRegistry, long seed) { + return new FabricChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/CommandManagerMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/CommandManagerMixin.java index 13b15d7ce..2e98614df 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/CommandManagerMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/CommandManagerMixin.java @@ -31,7 +31,7 @@ public abstract class CommandManagerMixin { @Final private CommandDispatcher dispatcher; - @Inject(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/CommandDispatcher;findAmbiguities(Lcom/mojang/brigadier/AmbiguityConsumer;)V")) + @Inject(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/CommandDispatcher;findAmbiguities(Lcom/mojang/brigadier/AmbiguityConsumer;)V", remap = false)) private void injectTerraCommands(CommandManager.RegistrationEnvironment environment, CallbackInfo ci) { com.dfsek.terra.api.command.CommandManager manager = TerraFabricPlugin.getInstance().getManager(); int max = manager.getMaxArgumentDepth(); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/ServerWorldMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/ServerWorldMixin.java new file mode 100644 index 000000000..b3d5d7c97 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/ServerWorldMixin.java @@ -0,0 +1,35 @@ +package com.dfsek.terra.fabric.mixin; + +import com.dfsek.terra.api.util.generic.pair.Pair; +import com.dfsek.terra.fabric.TerraFabricPlugin; +import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.world.TerraWorld; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.WorldGenerationProgressListener; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.Spawner; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.level.ServerWorldProperties; +import net.minecraft.world.level.storage.LevelStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; +import java.util.concurrent.Executor; + +@Mixin(ServerWorld.class) +public abstract class ServerWorldMixin { + @Inject(method = "", at = @At(value = "RETURN")) + public void injectConstructor(MinecraftServer server, Executor workerExecutor, LevelStorage.Session session, ServerWorldProperties properties, RegistryKey registryKey, DimensionType dimensionType, WorldGenerationProgressListener worldGenerationProgressListener, ChunkGenerator chunkGenerator, boolean debugWorld, long l, List list, boolean bl, CallbackInfo ci) { + if(chunkGenerator instanceof FabricChunkGeneratorWrapper) { + TerraFabricPlugin.getInstance().getWorldMap().put(dimensionType, Pair.of((ServerWorld) (Object) this, new TerraWorld((com.dfsek.terra.api.platform.world.World) this, ((FabricChunkGeneratorWrapper) chunkGenerator).getPack(), TerraFabricPlugin.getInstance()))); + ((FabricChunkGeneratorWrapper) chunkGenerator).setDimensionType(dimensionType); + TerraFabricPlugin.getInstance().logger().info("Registered world " + this + " to dimension type " + dimensionType); + } + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/init/MinecraftClientMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/init/MinecraftClientMixin.java index 4da836a97..59dba3484 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/init/MinecraftClientMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/init/MinecraftClientMixin.java @@ -1,8 +1,12 @@ package com.dfsek.terra.fabric.mixin.init; import com.dfsek.terra.fabric.TerraFabricPlugin; +import com.dfsek.terra.fabric.generation.TerraGeneratorType; +import com.dfsek.terra.fabric.mixin.access.GeneratorTypeAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.client.RunArgs; +import net.minecraft.client.world.GeneratorType; +import net.minecraft.text.LiteralText; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -15,5 +19,11 @@ public class MinecraftClientMixin { shift = At.Shift.BEFORE)) public void injectConstructor(RunArgs args, CallbackInfo callbackInfo) { TerraFabricPlugin.getInstance().packInit(); // Load during MinecraftClient construction, after other mods have registered blocks and stuff + TerraFabricPlugin.getInstance().getConfigRegistry().forEach(pack -> { + final GeneratorType generatorType = new TerraGeneratorType(pack); + //noinspection ConstantConditions + ((GeneratorTypeAccessor) generatorType).setTranslationKey(new LiteralText("Terra:" + pack.getTemplate().getID())); + GeneratorTypeAccessor.getValues().add(1, generatorType); + }); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java new file mode 100644 index 000000000..c761cade4 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java @@ -0,0 +1,117 @@ +package com.dfsek.terra.fabric.util; + +import com.dfsek.terra.api.util.generic.pair.Pair; +import com.dfsek.terra.config.builder.BiomeBuilder; +import com.dfsek.terra.config.pack.ConfigPack; +import com.dfsek.terra.config.templates.BiomeTemplate; +import com.dfsek.terra.fabric.TerraFabricPlugin; +import com.dfsek.terra.fabric.config.PostLoadCompatibilityOptions; +import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.fabric.mixin.access.BiomeEffectsAccessor; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeEffects; +import net.minecraft.world.biome.GenerationSettings; +import net.minecraft.world.gen.GenerationStep; +import net.minecraft.world.gen.carver.ConfiguredCarver; +import net.minecraft.world.gen.feature.ConfiguredFeature; +import net.minecraft.world.gen.feature.ConfiguredStructureFeature; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Locale; +import java.util.Map; +import java.util.function.Supplier; + +public final class FabricUtil { + public static String createBiomeID(ConfigPack pack, String biomeID) { + return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT); + } + + /** + * Clones a Vanilla biome and injects Terra data to create a Terra-vanilla biome delegate. + * + * @param fabricAddon The Fabric addon instance. + * @param biome The Terra BiomeBuilder. + * @param pack The ConfigPack this biome belongs to. + * @return The Minecraft delegate biome. + */ + public static Biome createBiome(TerraFabricPlugin.FabricAddon fabricAddon, BiomeBuilder biome, ConfigPack pack) { + BiomeTemplate template = biome.getTemplate(); + Map colors = template.getColors(); + + Biome vanilla = (Biome) (new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle(); + + GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); + + generationSettings.surfaceBuilder(vanilla.getGenerationSettings().getSurfaceBuilder()); // It needs a surfacebuilder, even though we dont use it. + + generationSettings.feature(GenerationStep.Feature.VEGETAL_DECORATION, TerraFabricPlugin.POPULATOR_CONFIGURED_FEATURE); + + if(pack.getTemplate().vanillaCaves()) { + for(GenerationStep.Carver carver : GenerationStep.Carver.values()) { + for(Supplier> configuredCarverSupplier : vanilla.getGenerationSettings().getCarversForStep(carver)) { + generationSettings.carver(carver, configuredCarverSupplier.get()); + } + } + } + + Pair pair = fabricAddon.getTemplates().get(pack); + PreLoadCompatibilityOptions compatibilityOptions = pair.getLeft(); + PostLoadCompatibilityOptions postLoadCompatibilityOptions = pair.getRight(); + + TerraFabricPlugin.getInstance().getDebugLogger().info("Injecting Vanilla structures and features into Terra biome " + biome.getTemplate().getID()); + + for(Supplier> structureFeature : vanilla.getGenerationSettings().getStructureFeatures()) { + Identifier key = BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE.getId(structureFeature.get()); + if(!compatibilityOptions.getExcludedBiomeStructures().contains(key) && !postLoadCompatibilityOptions.getExcludedPerBiomeStructures().getOrDefault(biome, Collections.emptySet()).contains(key)) { + generationSettings.structureFeature(structureFeature.get()); + TerraFabricPlugin.getInstance().getDebugLogger().info("Injected structure " + key); + } + } + + if(compatibilityOptions.doBiomeInjection()) { + for(int step = 0; step < vanilla.getGenerationSettings().getFeatures().size(); step++) { + for(Supplier> featureSupplier : vanilla.getGenerationSettings().getFeatures().get(step)) { + Identifier key = BuiltinRegistries.CONFIGURED_FEATURE.getId(featureSupplier.get()); + if(!compatibilityOptions.getExcludedBiomeFeatures().contains(key) && !postLoadCompatibilityOptions.getExcludedPerBiomeFeatures().getOrDefault(biome, Collections.emptySet()).contains(key)) { + generationSettings.feature(step, featureSupplier); + TerraFabricPlugin.getInstance().getDebugLogger().info("Injected feature " + key + " at stage " + step); + } + } + } + } + + BiomeEffectsAccessor accessor = (BiomeEffectsAccessor) vanilla.getEffects(); + BiomeEffects.Builder effects = new BiomeEffects.Builder() + .waterColor(colors.getOrDefault("water", accessor.getWaterColor())) + .waterFogColor(colors.getOrDefault("water-fog", accessor.getWaterFogColor())) + .fogColor(colors.getOrDefault("fog", accessor.getFogColor())) + .skyColor(colors.getOrDefault("sky", accessor.getSkyColor())) + .grassColorModifier(accessor.getGrassColorModifier()); + + if(colors.containsKey("grass")) { + effects.grassColor(colors.get("grass")); + } else { + accessor.getGrassColor().ifPresent(effects::grassColor); + } + if(colors.containsKey("foliage")) { + effects.foliageColor(colors.get("foliage")); + } else { + accessor.getFoliageColor().ifPresent(effects::foliageColor); + } + + return new Biome.Builder() + .precipitation(vanilla.getPrecipitation()) + .category(vanilla.getCategory()) + .depth(vanilla.getDepth()) + .scale(vanilla.getScale()) + .temperature(vanilla.getTemperature()) + .downfall(vanilla.getDownfall()) + .effects(effects.build()) + .spawnSettings(vanilla.getSpawnSettings()) + .generationSettings(generationSettings.build()) + .build(); + } +} diff --git a/platforms/fabric/src/main/resources/terra.mixins.json b/platforms/fabric/src/main/resources/terra.mixins.json index 506962111..c8cdbaa33 100644 --- a/platforms/fabric/src/main/resources/terra.mixins.json +++ b/platforms/fabric/src/main/resources/terra.mixins.json @@ -6,6 +6,7 @@ "mixins": [ "CommandManagerMixin", "GeneratorOptionsMixin", + "ServerWorldMixin", "access.BiomeEffectsAccessor", "access.MobSpawnerLogicAccessor", "access.StateAccessor", diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/TerraForgePlugin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/TerraForgePlugin.java index 993766056..dc8308c4e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/TerraForgePlugin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/TerraForgePlugin.java @@ -22,8 +22,8 @@ import com.dfsek.terra.api.platform.world.Tree; import com.dfsek.terra.api.platform.world.World; import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.LockedRegistry; -import com.dfsek.terra.api.transform.NotNullValidator; import com.dfsek.terra.api.transform.Transformer; +import com.dfsek.terra.api.transform.Validator; import com.dfsek.terra.api.util.JarUtil; import com.dfsek.terra.api.util.logging.DebugLogger; import com.dfsek.terra.commands.CommandUtil; @@ -113,8 +113,8 @@ public class TerraForgePlugin implements TerraPlugin { private final LockedRegistry addonLockedRegistry = new LockedRegistry<>(addonRegistry); private final PluginConfig config = new PluginConfig(); private final Transformer biomeFixer = new Transformer.Builder() - .addTransform(id -> ForgeRegistries.BIOMES.getValue(ResourceLocation.tryParse(id)), new NotNullValidator<>()) - .addTransform(id -> ForgeRegistries.BIOMES.getValue(ResourceLocation.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build(); + .addTransform(id -> ForgeRegistries.BIOMES.getValue(ResourceLocation.tryParse(id)), Validator.notNull()) + .addTransform(id -> ForgeRegistries.BIOMES.getValue(ResourceLocation.tryParse("minecraft:" + id.toLowerCase())), Validator.notNull()).build(); private final File dataFolder; public TerraForgePlugin() {