Merge pull request #199 from PolyhedralDev/dev/forge-tweaks

Forge Tweaks
This commit is contained in:
dfsek 2021-05-22 21:48:12 -07:00 committed by GitHub
commit fa164e5281
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 414 additions and 278 deletions

View File

@ -1,147 +0,0 @@
package com.dfsek.terra.config.builder;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.ExpressionSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class GeneratorBuilder {
private final Map<Long, WorldGenerator> gens = Collections.synchronizedMap(new HashMap<>());
private String noiseEquation;
private String elevationEquation;
private String carvingEquation;
private Scope varScope;
private Map<String, NoiseSeeded> noiseBuilderMap;
private Map<String, FunctionTemplate> functionTemplateMap;
private PaletteHolder palettes;
private PaletteHolder slantPalettes;
private boolean preventInterpolation;
private boolean interpolateElevation;
private NoiseSeeded biomeNoise;
private double elevationWeight;
private int blendDistance;
private int blendStep;
private double blendWeight;
public WorldGenerator build(long seed) {
synchronized(gens) {
return gens.computeIfAbsent(seed, k -> {
NoiseSampler noise;
NoiseSampler elevation;
NoiseSampler carving;
try {
noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
carving = new ExpressionSampler(carvingEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
} catch(ParseException e) {
throw new RuntimeException(e);
}
return new WorldGenerator(palettes, slantPalettes, noise, elevation, carving, biomeNoise.apply(seed), elevationWeight, blendDistance, blendStep, blendWeight);
});
}
}
public void setBlendWeight(double blendWeight) {
this.blendWeight = blendWeight;
}
public void setFunctionTemplateMap(Map<String, FunctionTemplate> functionTemplateMap) {
this.functionTemplateMap = functionTemplateMap;
}
public void setBlendStep(int blendStep) {
this.blendStep = blendStep;
}
public void setBlendDistance(int blendDistance) {
this.blendDistance = blendDistance;
}
public void setBiomeNoise(NoiseSeeded biomeNoise) {
this.biomeNoise = biomeNoise;
}
public void setElevationWeight(double elevationWeight) {
this.elevationWeight = elevationWeight;
}
public void setNoiseEquation(String noiseEquation) {
this.noiseEquation = noiseEquation;
}
public void setElevationEquation(String elevationEquation) {
this.elevationEquation = elevationEquation;
}
public void setCarvingEquation(String carvingEquation) {
this.carvingEquation = carvingEquation;
}
public Scope getVarScope() {
return varScope;
}
public void setVarScope(Scope varScope) {
this.varScope = varScope;
}
public void setNoiseBuilderMap(Map<String, NoiseSeeded> noiseBuilderMap) {
this.noiseBuilderMap = noiseBuilderMap;
}
public PaletteHolder getPalettes() {
return palettes;
}
public void setPalettes(PaletteHolder palettes) {
this.palettes = palettes;
}
public PaletteHolder getSlantPalettes() {
return slantPalettes;
}
public void setSlantPalettes(PaletteHolder slantPalettes) {
this.slantPalettes = slantPalettes;
}
public boolean isPreventInterpolation() {
return preventInterpolation;
}
public void setPreventInterpolation(boolean preventInterpolation) {
this.preventInterpolation = preventInterpolation;
}
public void setInterpolateElevation(boolean interpolateElevation) {
this.interpolateElevation = interpolateElevation;
}
public boolean interpolateElevation() {
return interpolateElevation;
}
}

View File

@ -3,12 +3,9 @@ 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")

View File

@ -1,36 +1,78 @@
package com.dfsek.terra.forge;
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 net.minecraft.block.Blocks;
import com.dfsek.terra.forge.config.PostLoadCompatibilityOptions;
import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.WorldGenRegistries;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeAmbience;
import net.minecraft.world.biome.BiomeGenerationSettings;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilderConfig;
import net.minecraft.world.gen.carver.ConfiguredCarver;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.StructureFeature;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
public final class ForgeUtil {
public static String createBiomeID(ConfigPack pack, String biomeID) {
return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT);
}
@SuppressWarnings("ConstantConditions")
public static Biome createBiome(BiomeBuilder biome) {
public static Biome createBiome(BiomeBuilder biome, ConfigPack pack, TerraForgePlugin.ForgeAddon forgeAddon) {
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
Biome vanilla = (Biome) ((Object) new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0));
Biome vanilla = (Biome) (new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle();
BiomeGenerationSettings.Builder generationSettings = new BiomeGenerationSettings.Builder();
generationSettings.surfaceBuilder(SurfaceBuilder.DEFAULT.configured(new SurfaceBuilderConfig(Blocks.GRASS_BLOCK.defaultBlockState(), Blocks.DIRT.defaultBlockState(), Blocks.GRAVEL.defaultBlockState()))); // It needs a surfacebuilder, even though we dont use it.
generationSettings.surfaceBuilder(vanilla.getGenerationSettings().getSurfaceBuilder()); // It needs a surfacebuilder, even though we dont use it.
generationSettings.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, TerraForgePlugin.POPULATOR_CONFIGURED_FEATURE);
if(pack.getTemplate().vanillaCaves()) {
for(GenerationStage.Carving carver : GenerationStage.Carving.values()) {
for(Supplier<ConfiguredCarver<?>> configuredCarverSupplier : vanilla.getGenerationSettings().getCarvers(carver)) {
generationSettings.addCarver(carver, configuredCarverSupplier.get());
}
}
}
Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions> pair = forgeAddon.getTemplates().get(pack);
PreLoadCompatibilityOptions compatibilityOptions = pair.getLeft();
PostLoadCompatibilityOptions postLoadCompatibilityOptions = pair.getRight();
TerraForgePlugin.getInstance().getDebugLogger().info("Injecting Vanilla structures and features into Terra biome " + biome.getTemplate().getID());
for(Supplier<StructureFeature<?, ?>> structureFeature : vanilla.getGenerationSettings().structures()) {
ResourceLocation key = WorldGenRegistries.CONFIGURED_STRUCTURE_FEATURE.getKey(structureFeature.get());
if(!compatibilityOptions.getExcludedBiomeStructures().contains(key) && !postLoadCompatibilityOptions.getExcludedPerBiomeStructures().getOrDefault(biome, Collections.emptySet()).contains(key)) {
generationSettings.addStructureStart(structureFeature.get());
TerraForgePlugin.getInstance().getDebugLogger().info("Injected structure " + key);
}
}
if(compatibilityOptions.doBiomeInjection()) {
for(int step = 0; step < vanilla.getGenerationSettings().features().size(); step++) {
for(Supplier<ConfiguredFeature<?, ?>> featureSupplier : vanilla.getGenerationSettings().features().get(step)) {
ResourceLocation key = WorldGenRegistries.CONFIGURED_FEATURE.getKey(featureSupplier.get());
if(!compatibilityOptions.getExcludedBiomeFeatures().contains(key) && !postLoadCompatibilityOptions.getExcludedPerBiomeFeatures().getOrDefault(biome, Collections.emptySet()).contains(key)) {
generationSettings.addFeature(step, featureSupplier);
TerraForgePlugin.getInstance().getDebugLogger().info("Injected feature " + key + " at stage " + step);
}
}
}
}
BiomeAmbience vanillaEffects = vanilla.getSpecialEffects();
BiomeAmbience.Builder effects = new BiomeAmbience.Builder()
.waterColor(colors.getOrDefault("water", vanillaEffects.getWaterColor()))
@ -44,7 +86,7 @@ public final class ForgeUtil {
} else {
vanillaEffects.getGrassColorOverride().ifPresent(effects::grassColorOverride);
}
vanillaEffects.getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
if(colors.containsKey("foliage")) {
effects.foliageColorOverride(colors.get("foliage"));
} else {
@ -61,6 +103,7 @@ public final class ForgeUtil {
.specialEffects(effects.build())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(generationSettings.build())
.build().setRegistryName("terra", createBiomeID(template.getPack(), template.getID()));
.build()
.setRegistryName("terra", createBiomeID(template.getPack(), template.getID()));
}
}

View File

@ -1,5 +1,7 @@
package com.dfsek.terra.forge;
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;
@ -25,6 +28,7 @@ import com.dfsek.terra.api.registry.LockedRegistry;
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.generic.pair.Pair;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.commands.CommandUtil;
import com.dfsek.terra.config.GenericLoaders;
@ -32,6 +36,8 @@ import com.dfsek.terra.config.PluginConfig;
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.forge.config.PostLoadCompatibilityOptions;
import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper;
import com.dfsek.terra.forge.generation.PopulatorFeature;
import com.dfsek.terra.forge.generation.TerraBiomeSource;
@ -45,6 +51,9 @@ import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.WorldGenRegistries;
import net.minecraft.world.DimensionType;
import net.minecraft.world.IWorld;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.Features;
@ -52,10 +61,12 @@ import net.minecraft.world.gen.feature.IFeatureConfig;
import net.minecraft.world.gen.feature.NoFeatureConfig;
import net.minecraft.world.gen.placement.DecoratedPlacement;
import net.minecraft.world.gen.placement.NoPlacementConfig;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.objectweb.asm.Type;
@ -78,7 +89,7 @@ public class TerraForgePlugin implements TerraPlugin {
public static final ConfiguredFeature<?, ?> POPULATOR_CONFIGURED_FEATURE = POPULATOR_FEATURE.configured(IFeatureConfig.NONE).decorated(DecoratedPlacement.NOPE.configured(NoPlacementConfig.INSTANCE));
private static TerraForgePlugin INSTANCE;
private final Map<Long, TerraWorld> worldMap = new HashMap<>();
private final Map<DimensionType, Pair<ServerWorld, TerraWorld>> worldMap = new HashMap<>();
private final EventManager eventManager = new TerraEventManager(this);
private final GenericLoaders genericLoaders = new GenericLoaders(this);
private final Profiler profiler = new ProfilerImpl();
@ -109,7 +120,10 @@ public class TerraForgePlugin implements TerraPlugin {
private final WorldHandle worldHandle = new ForgeWorldHandle();
private final ConfigRegistry registry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry);
private final AddonRegistry addonRegistry = new AddonRegistry(new ForgeAddon(this), this);
private final ForgeAddon addon = new ForgeAddon(this);
private final AddonRegistry addonRegistry = new AddonRegistry(addon, this);
private final LockedRegistry<TerraAddon> addonLockedRegistry = new LockedRegistry<>(addonRegistry);
private final PluginConfig config = new PluginConfig();
private final Transformer<String, Biome> biomeFixer = new Transformer.Builder<String, Biome>()
@ -123,6 +137,7 @@ public class TerraForgePlugin implements TerraPlugin {
this.dataFolder = Paths.get("config", "Terra").toFile();
saveDefaultConfig();
config.load(this);
debugLogger.setDebug(config.isDebug());
LangUtil.load(config.getLanguage(), this);
try {
CommandUtil.registerAll(manager);
@ -143,7 +158,7 @@ public class TerraForgePlugin implements TerraPlugin {
});
}
public void setup() {
public void init() {
logger.info("Initializing Terra...");
if(!addonRegistry.loadAll()) {
@ -153,6 +168,10 @@ public class TerraForgePlugin implements TerraPlugin {
registry.loadAll(this);
logger.info("Loaded packs.");
((ForgeRegistry<Biome>) ForgeRegistries.BIOMES).unfreeze(); // Evil
getConfigRegistry().forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> ForgeRegistries.BIOMES.register(ForgeUtil.createBiome(biome, pack, addon)))); // Register all Terra biomes.
((ForgeRegistry<Biome>) ForgeRegistries.BIOMES).freeze();
}
@Override
@ -162,10 +181,13 @@ public class TerraForgePlugin implements TerraPlugin {
@Override
public TerraWorld getWorld(World world) {
return worldMap.computeIfAbsent(world.getSeed(), w -> {
logger.info("Loading world " + w);
return new TerraWorld(world, ((ForgeChunkGeneratorWrapper) world.getGenerator()).getPack(), this);
});
return getWorld(((IWorld) world).dimensionType());
}
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;
}
/**
@ -191,12 +213,6 @@ public class TerraForgePlugin implements TerraPlugin {
return JarUtil.getJarFile();
}
public TerraWorld getWorld(long seed) {
TerraWorld world = worldMap.get(seed);
if(world == null) throw new IllegalArgumentException("No world exists with seed " + seed);
return world;
}
@Override
public com.dfsek.terra.api.util.logging.Logger logger() {
return logger;
@ -237,14 +253,11 @@ public class TerraForgePlugin implements TerraPlugin {
config.load(this);
LangUtil.load(config.getLanguage(), this); // Load language.
boolean succeed = registry.loadAll(this);
Map<Long, TerraWorld> 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;
}
@ -278,7 +291,12 @@ public class TerraForgePlugin implements TerraPlugin {
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));
.registerLoader(com.dfsek.terra.api.platform.world.Biome.class, (t, o, l) -> biomeFixer.translate((String) o))
.registerLoader(ResourceLocation.class, (t, o, l) -> {
ResourceLocation identifier = ResourceLocation.tryParse((String) o);
if(identifier == null) throw new LoadException("Invalid identifier: " + o);
return identifier;
});
}
@Override
@ -295,10 +313,16 @@ public class TerraForgePlugin implements TerraPlugin {
return manager;
}
public Map<DimensionType, Pair<ServerWorld, TerraWorld>> getWorldMap() {
return worldMap;
}
@Addon("Terra-Forge")
@Author("Terra")
@Version("1.0.0")
private static final class ForgeAddon extends TerraAddon implements EventListener {
public static final class ForgeAddon extends TerraAddon implements EventListener {
private final Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> templates = new HashMap<>();
private final TerraPlugin main;
@ -334,6 +358,39 @@ public class TerraForgePlugin implements TerraPlugin {
injectTree(treeRegistry, "MEGA_SPRUCE", Features.MEGA_SPRUCE);
injectTree(treeRegistry, "CRIMSON_FUNGUS", Features.CRIMSON_FUNGI);
injectTree(treeRegistry, "WARPED_FUNGUS", Features.WARPED_FUNGI);
PreLoadCompatibilityOptions template = new PreLoadCompatibilityOptions();
try {
event.loadTemplate(template);
} catch(ConfigException e) {
e.printStackTrace();
}
if(template.doRegistryInjection()) {
WorldGenRegistries.CONFIGURED_FEATURE.entrySet().forEach(entry -> {
if(!template.getExcludedRegistryFeatures().contains(entry.getKey().getRegistryName())) {
try {
event.getPack().getTreeRegistry().add(entry.getKey().getRegistryName().toString(), (Tree) entry.getValue());
main.getDebugLogger().info("Injected ConfiguredFeature " + entry.getKey().getRegistryName() + " as Tree: " + entry.getValue());
} 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);
}
@ -343,5 +400,9 @@ public class TerraForgePlugin implements TerraPlugin {
} catch(DuplicateEntryException ignore) {
}
}
public Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> getTemplates() {
return templates;
}
}
}

View File

@ -0,0 +1,30 @@
package com.dfsek.terra.forge.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.ResourceLocation;
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<BiomeBuilder, Set<ResourceLocation>> excludedPerBiomeStructures = new HashMap<>();
@Value("features.inject-biome.exclude-biomes")
@Default
private Map<BiomeBuilder, Set<ResourceLocation>> excludedPerBiomeFeatures = new HashMap<>();
public Map<BiomeBuilder, Set<ResourceLocation>> getExcludedPerBiomeFeatures() {
return excludedPerBiomeFeatures;
}
public Map<BiomeBuilder, Set<ResourceLocation>> getExcludedPerBiomeStructures() {
return excludedPerBiomeStructures;
}
}

View File

@ -0,0 +1,52 @@
package com.dfsek.terra.forge.config;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ConfigTemplate;
import net.minecraft.util.ResourceLocation;
import java.util.HashSet;
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<ResourceLocation> excludedRegistryFeatures = new HashSet<>();
@Value("features.inject-biome.excluded-features")
@Default
private Set<ResourceLocation> excludedBiomeFeatures = new HashSet<>();
@Value("structures.inject-biome.excluded-features")
@Default
private Set<ResourceLocation> excludedBiomeStructures = new HashSet<>();
public boolean doBiomeInjection() {
return doBiomeInjection;
}
public boolean doRegistryInjection() {
return doRegistryInjection;
}
public Set<ResourceLocation> getExcludedBiomeFeatures() {
return excludedBiomeFeatures;
}
public Set<ResourceLocation> getExcludedRegistryFeatures() {
return excludedRegistryFeatures;
}
public Set<ResourceLocation> getExcludedBiomeStructures() {
return excludedBiomeStructures;
}
}

View File

@ -4,32 +4,49 @@ 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;
import com.dfsek.terra.forge.ForgeAdapter;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.generators.DefaultChunkGenerator3D;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.population.items.TerraStructure;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.jafama.FastMath;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.SharedSeedRandom;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.Blockreader;
import net.minecraft.world.DimensionType;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeManager;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.Heightmap;
import net.minecraft.world.gen.WorldGenRegion;
import net.minecraft.world.gen.feature.structure.Structure;
import net.minecraft.world.gen.feature.structure.StructureManager;
import net.minecraft.world.gen.feature.template.TemplateManager;
import net.minecraft.world.gen.settings.DimensionStructuresSettings;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.spawner.WorldEntitySpawner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class ForgeChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
private final long seed;
@ -49,6 +66,8 @@ public class ForgeChunkGeneratorWrapper extends ChunkGenerator implements Genera
return pack;
}
private DimensionType dimensionType;
public ForgeChunkGeneratorWrapper(TerraBiomeSource biomeSource, long seed, ConfigPack configPack) {
super(biomeSource, new DimensionStructuresSettings(false));
this.pack = configPack;
@ -75,8 +94,32 @@ public class ForgeChunkGeneratorWrapper extends ChunkGenerator implements Genera
}
@Nullable
@Override
public BlockPos findNearestMapFeature(@NotNull ServerWorld world, @NotNull Structure<?> feature, @NotNull BlockPos center, int radius, boolean skipExistingChunks) {
if(!pack.getTemplate().disableStructures()) {
String name = Objects.requireNonNull(Registry.STRUCTURE_FEATURE.getKey(feature)).toString();
TerraWorld terraWorld = TerraForgePlugin.getInstance().getWorld((World) world);
TerraStructure located = pack.getStructure(pack.getTemplate().getLocatable().get(name));
if(located != null) {
CompletableFuture<BlockPos> result = new CompletableFuture<>();
AsyncStructureFinder finder = new AsyncStructureFinder(terraWorld.getBiomeProvider(), located, ForgeAdapter.adapt(center).toLocation((World) world), 0, 500, location -> {
result.complete(ForgeAdapter.adapt(location));
}, TerraForgePlugin.getInstance());
finder.run(); // Do this synchronously.
try {
return result.get();
} catch(InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}
return super.findNearestMapFeature(world, feature, center, radius, skipExistingChunks);
}
@Override
public boolean hasStronghold(@NotNull ChunkPos p_235952_1_) {
if(pack.getTemplate().vanillaStructures()) return super.hasStronghold(p_235952_1_);
return false;
}
@ -97,27 +140,26 @@ public class ForgeChunkGeneratorWrapper extends ChunkGenerator implements Genera
@Override
public int getBaseHeight(int x, int z, Heightmap.@NotNull Type p_222529_3_) {
TerraWorld world = TerraForgePlugin.getInstance().getWorld(seed);
TerraWorld world = TerraForgePlugin.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 @NotNull IBlockReader getBaseColumn(int p_230348_1_, int p_230348_2_) {
int height = 64; // TODO: implementation
public @NotNull IBlockReader getBaseColumn(int x, int z) {
TerraWorld world = TerraForgePlugin.getInstance().getWorld(dimensionType);
int height = getBaseHeight(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.defaultBlockState();
} else {
array[y] = Blocks.WATER.defaultBlockState();
@ -130,9 +172,24 @@ public class ForgeChunkGeneratorWrapper extends ChunkGenerator implements Genera
return new Blockreader(array);
}
@Override
public void spawnOriginalMobs(WorldGenRegion region) {
if(pack.getTemplate().vanillaMobs()) {
int cx = region.getCenterX();
int cy = region.getCenterZ();
Biome biome = region.getBiome((new ChunkPos(cx, cy)).getWorldPosition());
SharedSeedRandom chunkRandom = new SharedSeedRandom();
chunkRandom.setDecorationSeed(region.getSeed(), cx << 4, cy << 4);
WorldEntitySpawner.spawnMobsForChunkGeneration(region, biome, cx, cy, chunkRandom);
}
}
@Override
public TerraChunkGenerator getHandle() {
return delegate;
}
public void setDimensionType(DimensionType dimensionType) {
this.dimensionType = dimensionType;
}
}

View File

@ -0,0 +1,24 @@
package com.dfsek.terra.forge.generation;
import com.dfsek.terra.config.pack.ConfigPack;
import net.minecraft.client.gui.screen.BiomeGeneratorTypeScreens;
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 org.jetbrains.annotations.NotNull;
public class TerraGeneratorType extends BiomeGeneratorTypeScreens {
private final ConfigPack pack;
public TerraGeneratorType(ConfigPack pack) {
super(new StringTextComponent("Terra:" + pack.getTemplate().getID()));
this.pack = pack;
}
@Override
protected @NotNull ChunkGenerator generator(@NotNull Registry<Biome> biomeRegistry, @NotNull Registry<DimensionSettings> chunkGeneratorSettingsRegistry, long seed) {
return new ForgeChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack);
}
}

View File

@ -1,22 +0,0 @@
package com.dfsek.terra.forge.generation;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.forge.TerraForgePlugin;
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.minecraftforge.common.world.ForgeWorldType;
public class TerraLevelType implements ForgeWorldType.IChunkGeneratorFactory {
public static final TerraLevelType TERRA_LEVEL_TYPE = new TerraLevelType();
public static final ForgeWorldType FORGE_WORLD_TYPE = new ForgeWorldType(TERRA_LEVEL_TYPE).setRegistryName("terra", "world");
@Override
public ChunkGenerator createChunkGenerator(Registry<Biome> biomeRegistry, Registry<DimensionSettings> dimensionSettingsRegistry, long seed, String generatorSettings) {
System.out.println(generatorSettings);
dimensionSettingsRegistry.forEach(System.out::println);
ConfigPack pack = TerraForgePlugin.getInstance().getConfigRegistry().get("DEFAULT");
TerraForgePlugin.getInstance().logger().info("Creating generator for config pack " + pack.getTemplate().getID());
return new ForgeChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack);
}
}

View File

@ -1,50 +0,0 @@
package com.dfsek.terra.forge.listener;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.forge.generation.TerraLevelType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ForgeWorldTypeScreens;
import net.minecraftforge.common.world.ForgeWorldType;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ClientListener {
private static final TerraForgePlugin INSTANCE = TerraForgePlugin.getInstance();
@SubscribeEvent
public static void register(FMLClientSetupEvent event) {
INSTANCE.logger().info("Client setup...");
ForgeWorldType world = TerraLevelType.FORGE_WORLD_TYPE;
ForgeWorldTypeScreens.registerFactory(world, (returnTo, dimensionGeneratorSettings) -> new Screen(world.getDisplayName()) {
private final MutableInteger num = new MutableInteger(0);
private final List<ConfigPack> packs = new ArrayList<>();
private final Button toggle = new Button(0, 25, 120, 20, new StringTextComponent(""), button -> {
num.increment();
if(num.get() >= packs.size()) num.set(0);
button.setMessage(new StringTextComponent("Pack: " + packs.get(num.get()).getTemplate().getID()));
});
@Override
protected void init() {
packs.clear();
INSTANCE.getConfigRegistry().forEach((Consumer<ConfigPack>) packs::add);
addButton(new Button(0, 0, 120, 20, new StringTextComponent("Close"), btn -> Minecraft.getInstance().setScreen(returnTo)));
toggle.setMessage(new StringTextComponent("Pack: " + packs.get(num.get()).getTemplate().getID()));
addButton(toggle);
}
});
}
}

View File

@ -1,31 +1,13 @@
package com.dfsek.terra.forge.listener;
import com.dfsek.terra.forge.ForgeUtil;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.forge.generation.TerraLevelType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.Feature;
import net.minecraftforge.common.world.ForgeWorldType;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class RegistryListener {
private static final TerraForgePlugin INSTANCE = TerraForgePlugin.getInstance();
@SubscribeEvent
public static void registerLevels(RegistryEvent.Register<ForgeWorldType> event) {
INSTANCE.logger().info("Registering level types...");
event.getRegistry().register(TerraLevelType.FORGE_WORLD_TYPE);
}
@SubscribeEvent
public static void register(RegistryEvent.Register<Biome> event) {
INSTANCE.setup(); // Setup now because we need the biomes, and this event happens after blocks n stuff
INSTANCE.getConfigRegistry().forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> event.getRegistry().register(ForgeUtil.createBiome(biome)))); // Register all Terra biomes.
}
@SubscribeEvent
public static void registerPop(RegistryEvent.Register<Feature<?>> event) {
event.getRegistry().register(TerraForgePlugin.POPULATOR_FEATURE);

View File

@ -0,0 +1,37 @@
package com.dfsek.terra.forge.mixin;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper;
import com.dfsek.terra.world.TerraWorld;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ServerWorld.class)
public abstract class ServerWorldMixin {
@Shadow
@Final
private ServerChunkProvider chunkSource;
@Shadow
protected abstract void initCapabilities();
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/server/ServerWorld;initCapabilities()V"))
public void injectConstructor(ServerWorld serverWorld) {
if(chunkSource.getGenerator() instanceof ForgeChunkGeneratorWrapper) {
ForgeChunkGeneratorWrapper chunkGeneratorWrapper = (ForgeChunkGeneratorWrapper) chunkSource.getGenerator();
DimensionType dimensionType = ((World) (Object) this).dimensionType();
TerraForgePlugin.getInstance().getWorldMap().put(dimensionType, Pair.of((ServerWorld) (Object) this, new TerraWorld((com.dfsek.terra.api.platform.world.World) this, chunkGeneratorWrapper.getPack(), TerraForgePlugin.getInstance())));
chunkGeneratorWrapper.setDimensionType(dimensionType);
TerraForgePlugin.getInstance().logger().info("Registered world " + this + " to dimension type " + dimensionType);
}
initCapabilities();
}
}

View File

@ -0,0 +1,21 @@
package com.dfsek.terra.forge.mixin.access;
import net.minecraft.client.gui.screen.BiomeGeneratorTypeScreens;
import net.minecraft.util.text.ITextComponent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(BiomeGeneratorTypeScreens.class)
public interface BiomeGeneratorTypeScreensAccessor {
@Accessor("PRESETS")
static List<BiomeGeneratorTypeScreens> getPresets() {
throw new UnsupportedOperationException();
}
@Mutable
@Accessor
void setDescription(ITextComponent description);
}

View File

@ -0,0 +1,29 @@
package com.dfsek.terra.forge.mixin.init;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.forge.generation.TerraGeneratorType;
import com.dfsek.terra.forge.mixin.access.BiomeGeneratorTypeScreensAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.BiomeGeneratorTypeScreens;
import net.minecraft.resources.ResourcePackList;
import net.minecraft.util.text.StringTextComponent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Minecraft.class)
public abstract class MinecraftClientMixin {
@Redirect(method = "<init>", at = @At(value = "INVOKE",
target = "Lnet/minecraft/resources/ResourcePackList;reload()V" // sorta arbitrary position, after mod init, before window opens
))
public void injectConstructor(ResourcePackList resourcePackList) {
TerraForgePlugin.getInstance().init(); // Load during MinecraftClient construction, after other mods have registered blocks and stuff
TerraForgePlugin.getInstance().getConfigRegistry().forEach(pack -> {
final BiomeGeneratorTypeScreens generatorType = new TerraGeneratorType(pack);
//noinspection ConstantConditions
((BiomeGeneratorTypeScreensAccessor) generatorType).setDescription(new StringTextComponent("Terra:" + pack.getTemplate().getID()));
BiomeGeneratorTypeScreensAccessor.getPresets().add(1, generatorType);
});
resourcePackList.reload();
}
}

View File

@ -0,0 +1,16 @@
package com.dfsek.terra.forge.mixin.init;
import com.dfsek.terra.forge.TerraForgePlugin;
import net.minecraft.server.Main;
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;
@Mixin(Main.class)
public class MinecraftServerMixin {
@Inject(method = "main([Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/registry/DynamicRegistries;builtin()Lnet/minecraft/util/registry/DynamicRegistries$Impl;"))
private static void injectConstructor(String[] args, CallbackInfo ci) {
TerraForgePlugin.getInstance().init(); // Load during MinecraftServer construction, after other mods have registered blocks and stuff
}
}

View File

@ -5,7 +5,9 @@
"refmap": "terra-refmap.json",
"mixins": [
"DimensionGeneratorSettingsMixin",
"ServerWorldMixin",
"access.AbstractSpawnerAccessor",
"access.BiomeGeneratorTypeScreensAccessor",
"implementations.BiomeMixin",
"implementations.ChunkGeneratorMixin",
"implementations.ConfiguredFeatureMixin",
@ -31,6 +33,10 @@
"implementations.world.WorldGenRegionMixin"
],
"client": [
"init.MinecraftClientMixin"
],
"server": [
"init.MinecraftServerMixin"
],
"injectors": {
"defaultRequire": 1