Merge remote-tracking branch 'origin/master' into ver/6.0.0

# Conflicts:
#	build.gradle.kts
#	common/src/main/java/com/dfsek/terra/api/world/palette/holder/PaletteHolder.java
#	common/src/main/java/com/dfsek/terra/api/world/palette/holder/PaletteHolderBuilder.java
#	common/src/main/java/com/dfsek/terra/config/builder/GeneratorBuilder.java
#	common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java
#	common/src/main/java/com/dfsek/terra/config/templates/BiomeTemplate.java
#	common/src/main/java/com/dfsek/terra/config/templates/OreTemplate.java
#	gradle.properties
#	platforms/fabric/src/main/java/com/dfsek/terra/fabric/TerraFabricPlugin.java
#	platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java
#	platforms/forge/src/main/java/com/dfsek/terra/forge/TerraForgePlugin.java
This commit is contained in:
dfsek
2021-06-22 21:59:27 -07:00
181 changed files with 4163 additions and 2247 deletions
+2 -2
View File
@@ -15,7 +15,7 @@ configureCommon()
group = "com.dfsek.terra.bukkit"
val mcVersion = "1.16.5"
val mcVersion = "1.17"
val testDir = "target/server"
val testMem = "3G"
@@ -25,7 +25,7 @@ val purpurURL = "https://ci.pl3x.net/job/Purpur/lastSuccessfulBuild/artifact/fin
dependencies {
"shadedApi"(project(":common"))
"compileOnly"("com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT")
"compileOnly"("io.papermc.paper:paper-api:1.17-R0.1-SNAPSHOT")
"shadedImplementation"("io.papermc:paperlib:1.0.5")
"shadedImplementation"("org.bstats:bstats-bukkit:1.7")
@@ -84,7 +84,8 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
static {
String ver = Bukkit.getServer().getClass().getPackage().getName();
if(ver.contains("1_16")) BUKKIT_VERSION = BukkitVersion.V1_16;
if(ver.contains("1_17")) BUKKIT_VERSION = BukkitVersion.V1_17;
else if(ver.contains("1_16")) BUKKIT_VERSION = BukkitVersion.V1_16;
else if(ver.contains("1_15")) BUKKIT_VERSION = BukkitVersion.V1_15;
else if(ver.contains("1_14")) BUKKIT_VERSION = BukkitVersion.V1_14;
else if(ver.contains("1_13")) BUKKIT_VERSION = BukkitVersion.V1_13;
@@ -316,6 +317,8 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin {
V1_16(16),
V1_17(17),
UNKNOWN(Integer.MAX_VALUE); // Assume unknown version is latest.
private final int index;
@@ -19,7 +19,6 @@ public class PaperListener implements Listener {
@EventHandler
public void onStructureLocate(StructureLocateEvent e) {
if(!BukkitAdapter.adapt(e.getWorld()).isTerraWorld()) return;
e.setResult(null); // Assume no result.
String name = "minecraft:" + e.getType().getName();
main.getDebugLogger().info("Overriding structure location for \"" + name + "\"");
TerraWorld tw = main.getWorld(BukkitAdapter.adapt(e.getWorld()));
@@ -32,10 +31,8 @@ public class PaperListener implements Listener {
}, main);
finder.run(); // Do this synchronously.
} else {
main.logger().warning("No overrides are defined for \"" + name + "\"");
e.setResult(e.getOrigin());
main.logger().warning("No overrides are defined for \"" + name + "\". Locating this structure will NOT work properly!");
}
}
}
@@ -70,7 +70,7 @@ public class BukkitWorld implements World {
@Override
public int getMinHeight() {
return 0;
return delegate.getMinHeight();
}
@Override
@@ -3,16 +3,13 @@ main: "com.dfsek.terra.bukkit.TerraBukkitPlugin"
version: "@VERSION@"
load: "STARTUP"
author: dfsek
website: "@WIKI@"
api-version: "1.13"
description: "An insanely powerful free & open-source data-driven world generator."
description: "@DESCRIPTION@"
softdepend: [ "WorldEdit" ]
commands:
terra:
description: "Terra base command"
usage: "/terra "
aliases: [ "te" ]
permission: "terra.command"
locate:
description: "Locate a Terra Structure"
usage: "/locate <STRUCTURE_ID> <radius>"
permission: "terra.locate"
permission: "terra.command"
+16 -5
View File
@@ -7,7 +7,7 @@ import net.fabricmc.loom.task.RemapJarTask
plugins {
`java-library`
`maven-publish`
id("fabric-loom").version("0.6-SNAPSHOT")
id("fabric-loom").version("0.8-SNAPSHOT")
id("com.modrinth.minotaur").version("1.1.0")
}
@@ -23,11 +23,22 @@ group = "com.dfsek.terra.fabric"
dependencies {
"shadedApi"(project(":common"))
"minecraft"("com.mojang:minecraft:1.16.5")
"mappings"("net.fabricmc:yarn:1.16.5+build.5:v2")
"modImplementation"("net.fabricmc:fabric-loader:0.11.2")
"minecraft"("com.mojang:minecraft:1.17")
"mappings"("net.fabricmc:yarn:1.17+build.1:v2")
"modImplementation"("net.fabricmc:fabric-loader:0.11.3")
"modImplementation"("net.fabricmc.fabric-api:fabric-api:0.31.0+1.16")
"modCompileOnly"("com.sk89q.worldedit:worldedit-fabric-mc1.16:7.2.0-SNAPSHOT") {
exclude(group = "com.google.guava", module = "guava")
exclude(group = "com.google.code.gson", module = "gson")
exclude(group = "it.unimi.dsi", module = "fastutil")
exclude(group = "org.apache.logging.log4j", module = "log4j-api")
exclude(group = "org.apache.logging.log4j", module = "log4j-core")
}
}
tasks.named<ShadowJar>("shadowJar") {
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
}
@@ -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;
@@ -8,31 +10,29 @@ import com.dfsek.terra.api.addons.annotations.Author;
import com.dfsek.terra.api.addons.annotations.Version;
import com.dfsek.terra.api.command.CommandManager;
import com.dfsek.terra.api.command.TerraCommandManager;
import com.dfsek.terra.api.command.exception.CommandException;
import com.dfsek.terra.api.command.exception.MalformedCommandException;
import com.dfsek.terra.api.event.EventListener;
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.CommandSender;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
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;
@@ -40,112 +40,117 @@ import com.dfsek.terra.config.templates.BiomeTemplate;
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.config.PostLoadCompatibilityOptions;
import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.fabric.event.BiomeRegistrationEvent;
import com.dfsek.terra.fabric.event.GameInitializationEvent;
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.fabric.util.ProtoBiome;
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 com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.Blocks;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.server.command.ServerCommandSource;
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.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
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<Long, TerraWorld> worldMap = new HashMap<>();
private final Map<DimensionType, Pair<ServerWorld, TerraWorld>> worldMap = new HashMap<>();
public Map<DimensionType, Pair<ServerWorld, TerraWorld>> 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);
}
};
private final DebugLogger debugLogger = new DebugLogger(logger);
private final ItemHandle itemHandle = new FabricItemHandle();
private final WorldHandle worldHandle = new FabricWorldHandle();
private final ConfigRegistry registry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(registry);
private final AddonRegistry addonRegistry = new AddonRegistry(new FabricAddon(this), this);
private final ConfigRegistry configRegistry = new ConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedRegistry = new CheckedRegistry<>(configRegistry);
private final FabricAddon fabricAddon = new FabricAddon();
private final AddonRegistry addonRegistry = new AddonRegistry(fabricAddon, 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>()
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse(id)), new NotNullValidator<>())
.addTransform(id -> BuiltinRegistries.BIOME.get(Identifier.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build();
private final Transformer<String, ProtoBiome> biomeFixer = new Transformer.Builder<String, ProtoBiome>()
.addTransform(this::parseBiome, Validator.notNull())
.addTransform(id -> parseBiome("minecraft:" + id.toLowerCase()), Validator.notNull()).build();
private ProtoBiome parseBiome(String id) {
Identifier identifier = Identifier.tryParse(id);
if(BuiltinRegistries.BIOME.get(identifier) == null) return null; // failure.
return new ProtoBiome(identifier);
}
private File dataFolder;
private final CommandManager manager = new TerraCommandManager(this);
public CommandManager getManager() {
return manager;
}
public static TerraFabricPlugin getInstance() {
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;
@@ -153,15 +158,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;
}
@@ -180,11 +182,20 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
return dataFolder;
}
@Override
public boolean isDebug() {
return config.isDebug();
}
@Override
public Language getLanguage() {
return LangUtil.getLanguage();
}
public FabricAddon getFabricAddon() {
return fabricAddon;
}
@Override
public CheckedRegistry<ConfigPack> getConfigRegistry() {
return checkedRegistry;
@@ -199,15 +210,12 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
public boolean reload() {
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));
boolean succeed = configRegistry.loadAll(this);
worldMap.forEach((seed, pair) -> {
pair.getRight().getConfig().getSamplerCache().clear();
String packID = pair.getRight().getConfig().getTemplate().getID();
pair.setRight(new TerraWorld(pair.getRight().getWorld(), configRegistry.get(packID), this));
});
worldMap.clear();
worldMap.putAll(newMap);
return succeed;
}
@@ -241,50 +249,12 @@ 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<String, Integer> 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;
});
}
@Override
@@ -305,93 +275,21 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
}
logger.info("Loaded addons.");
registry.loadAll(this);
logger.info("Loaded packs.");
Registry.register(Registry.FEATURE, new Identifier("terra", "flora_populator"), POPULATOR_FEATURE);
RegistryKey<ConfiguredFeature<?, ?>> floraKey = RegistryKey.of(Registry.CONFIGURED_FEATURE_WORLDGEN, new Identifier("terra", "flora_populator"));
Registry.register(Registry.FEATURE, new Identifier("terra", "populator"), POPULATOR_FEATURE);
RegistryKey<ConfiguredFeature<?, ?>> floraKey = RegistryKey.of(Registry.CONFIGURED_FEATURE_KEY, new Identifier("terra", "populator"));
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, floraKey.getValue(), POPULATOR_CONFIGURED_FEATURE);
registry.forEach(pack -> pack.getRegistry(BiomeBuilder.class).forEach((id, biome) -> Registry.register(BuiltinRegistries.BIOME, new Identifier("terra", createBiomeID(pack, id)), createBiome(biome)))); // Register all Terra biomes.
Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), FabricChunkGeneratorWrapper.CODEC);
Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), TerraBiomeSource.CODEC);
if(FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
registry.forEach(pack -> {
final GeneratorType generatorType = new GeneratorType("terra." + pack.getTemplate().getID()) {
@Override
protected ChunkGenerator getChunkGenerator(Registry<Biome> biomeRegistry, Registry<ChunkGeneratorSettings> 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);
});
}
CommandManager manager = new TerraCommandManager(this);
try {
CommandUtil.registerAll(manager);
} catch(MalformedCommandException e) {
e.printStackTrace(); // TODO do something here even though this should literally never happen
}
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
int max = manager.getMaxArgumentDepth();
RequiredArgumentBuilder<ServerCommandSource, String> arg = argument("arg" + (max - 1), StringArgumentType.word());
for(int i = 0; i < max; i++) {
RequiredArgumentBuilder<ServerCommandSource, String> next = argument("arg" + (max - i - 1), StringArgumentType.word());
arg = next.then(assemble(arg, manager));
}
dispatcher.register(literal("terra").executes(context -> 1).then(assemble(arg, manager)));
dispatcher.register(literal("te").executes(context -> 1).then(assemble(arg, manager)));
//dispatcher.register(literal("te").redirect(root));
}
);
}
private RequiredArgumentBuilder<ServerCommandSource, String> assemble(RequiredArgumentBuilder<ServerCommandSource, String> in, CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrThrow();
} catch(CommandSyntaxException ignore) {
}
try {
manager.tabComplete(args.remove(0), sender, args).forEach(builder::suggest);
} catch(CommandException e) {
sender.sendMessage(e.getMessage());
}
return builder.buildFuture();
}).executes(context -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrThrow();
} catch(CommandSyntaxException ignore) {
}
try {
manager.execute(args.remove(0), sender, args);
} catch(CommandException e) {
context.getSource().sendError(new LiteralText(e.getMessage()));
}
return 1;
});
}
private List<String> parseCommand(String command) {
if(command.startsWith("/terra ")) command = command.substring("/terra ".length());
else if(command.startsWith("/te ")) command = command.substring("/te ".length());
List<String> c = new ArrayList<>(Arrays.asList(command.split(" ")));
if(command.endsWith(" ")) c.add("");
return c;
logger.info("Finished initialization.");
}
@@ -408,17 +306,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 {
private final TerraPlugin main;
private FabricAddon(TerraPlugin main) {
this.main = main;
}
public final class FabricAddon extends TerraAddon implements EventListener {
private final Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> templates = new HashMap<>();
@Override
public void initialize() {
main.getEventManager().registerListener(this, this);
eventManager.registerListener(this, this);
}
@Priority(Priority.LOWEST)
@@ -432,7 +325,7 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
injectTree(treeRegistry, "LARGE_OAK", ConfiguredFeatures.FANCY_OAK);
injectTree(treeRegistry, "LARGE_SPRUCE", ConfiguredFeatures.PINE);
injectTree(treeRegistry, "SMALL_JUNGLE", ConfiguredFeatures.JUNGLE_TREE);
injectTree(treeRegistry, "SWAMP_OAK", ConfiguredFeatures.SWAMP_TREE);
injectTree(treeRegistry, "SWAMP_OAK", ConfiguredFeatures.SWAMP_OAK);
injectTree(treeRegistry, "TALL_BIRCH", ConfiguredFeatures.BIRCH_TALL);
injectTree(treeRegistry, "ACACIA", ConfiguredFeatures.ACACIA);
injectTree(treeRegistry, "BIRCH", ConfiguredFeatures.BIRCH);
@@ -444,8 +337,57 @@ 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());
debugLogger.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);
}
@Global
public void injectBiomes(BiomeRegistrationEvent event) {
logger.info("Registering biomes...");
Registry<Biome> biomeRegistry = event.getRegistryManager().get(Registry.BIOME_KEY);
configRegistry.forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> FabricUtil.registerOrOverwrite(biomeRegistry, Registry.BIOME_KEY, new Identifier("terra", FabricUtil.createBiomeID(pack, id)), FabricUtil.createBiome(biome, pack, event.getRegistryManager())))); // Register all Terra biomes.
logger.info("Biomes registered.");
}
@Global
public void initializePacks(GameInitializationEvent event) {
TerraFabricPlugin main = TerraFabricPlugin.getInstance();
main.logger().info("Loading config packs...");
configRegistry.loadAll(TerraFabricPlugin.this);
logger.info("Loaded packs.");
}
private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) {
try {
@@ -453,5 +395,9 @@ public class TerraFabricPlugin implements TerraPlugin, ModInitializer {
} catch(DuplicateEntryException ignore) {
}
}
public Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> getTemplates() {
return templates;
}
}
}
@@ -7,7 +7,7 @@ import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.FluidBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
@@ -2,8 +2,8 @@ package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Directional;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.DirectionProperty;
@@ -2,8 +2,8 @@ package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.data.Orientable;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.util.math.Direction;
@@ -1,7 +1,7 @@
package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.data.Slab;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;
@@ -2,7 +2,7 @@ package com.dfsek.terra.fabric.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Stairs;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.Properties;
@@ -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<BiomeBuilder, Set<Identifier>> excludedPerBiomeStructures = new HashMap<>();
@Value("features.inject-biome.exclude-biomes")
@Default
private Map<BiomeBuilder, Set<Identifier>> excludedPerBiomeFeatures = new HashMap<>();
public Map<BiomeBuilder, Set<Identifier>> getExcludedPerBiomeFeatures() {
return excludedPerBiomeFeatures;
}
public Map<BiomeBuilder, Set<Identifier>> getExcludedPerBiomeStructures() {
return excludedPerBiomeStructures;
}
}
@@ -0,0 +1,52 @@
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 net.minecraft.util.Identifier;
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<Identifier> excludedRegistryFeatures = new HashSet<>();
@Value("features.inject-biome.excluded-features")
@Default
private Set<Identifier> excludedBiomeFeatures = new HashSet<>();
@Value("structures.inject-biome.excluded-features")
@Default
private Set<Identifier> excludedBiomeStructures = new HashSet<>();
public boolean doBiomeInjection() {
return doBiomeInjection;
}
public boolean doRegistryInjection() {
return doRegistryInjection;
}
public Set<Identifier> getExcludedBiomeFeatures() {
return excludedBiomeFeatures;
}
public Set<Identifier> getExcludedRegistryFeatures() {
return excludedRegistryFeatures;
}
public Set<Identifier> getExcludedBiomeStructures() {
return excludedBiomeStructures;
}
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.fabric.event;
import com.dfsek.terra.api.event.events.Event;
import net.minecraft.util.registry.DynamicRegistryManager;
/**
* Fired when biomes should be registered.
*/
public class BiomeRegistrationEvent implements Event {
private final DynamicRegistryManager registryManager;
public BiomeRegistrationEvent(DynamicRegistryManager registryManager) {
this.registryManager = registryManager;
}
public DynamicRegistryManager getRegistryManager() {
return registryManager;
}
}
@@ -0,0 +1,9 @@
package com.dfsek.terra.fabric.event;
import com.dfsek.terra.api.event.events.Event;
/**
* Called when the game is initialized and packs should be registered.
*/
public class GameInitializationEvent implements Event {
}
@@ -4,32 +4,38 @@ 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.generation.Chunkified;
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.fabric.FabricAdapter;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.mixin.StructureAccessorAccessor;
import com.dfsek.terra.fabric.util.FabricAdapter;
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.entity.SpawnGroup;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.structure.StructureManager;
import net.minecraft.util.collection.Pool;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.BlockView;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.HeightLimitView;
import net.minecraft.world.Heightmap;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.SpawnHelper;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.SpawnSettings;
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;
@@ -41,24 +47,32 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
public class FabricChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
public static final Codec<ConfigPack> PACK_CODEC = RecordCodecBuilder.create(
config -> config.group(
Codec.STRING.fieldOf("pack")
.forGetter(pack -> pack.getTemplate().getID())
).apply(config, config.stable(TerraFabricPlugin.getInstance().getConfigRegistry()::get)));
public static final Codec<FabricChunkGeneratorWrapper> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
TerraBiomeSource.CODEC.fieldOf("biome_source")
.forGetter(generator -> generator.biomeSource),
Codec.LONG.fieldOf("seed").stable()
.forGetter(generator -> generator.seed),
PACK_CODEC.fieldOf("pack").stable()
.forGetter(generator -> generator.pack)
).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new))
);
private final long seed;
private final DefaultChunkGenerator3D delegate;
private final TerraBiomeSource biomeSource;
public static final Codec<ConfigPack> PACK_CODEC = (RecordCodecBuilder.create(config -> config.group(
Codec.STRING.fieldOf("pack").forGetter(pack -> pack.getTemplate().getID())
).apply(config, config.stable(TerraFabricPlugin.getInstance().getConfigRegistry()::get))));
public static final Codec<FabricChunkGeneratorWrapper> CODEC = RecordCodecBuilder.create(instance -> instance.group(
TerraBiomeSource.CODEC.fieldOf("biome_source").forGetter(generator -> generator.biomeSource),
Codec.LONG.fieldOf("seed").stable().forGetter(generator -> generator.seed),
PACK_CODEC.fieldOf("pack").stable().forGetter(generator -> generator.pack))
.apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)));
private final ConfigPack pack;
public ConfigPack getPack() {
return pack;
}
private final ConfigPack pack;
private DimensionType dimensionType;
public FabricChunkGeneratorWrapper(TerraBiomeSource biomeSource, long seed, ConfigPack configPack) {
super(biomeSource, new StructuresConfig(false));
@@ -82,93 +96,141 @@ public class FabricChunkGeneratorWrapper extends ChunkGenerator implements Gener
return new FabricChunkGeneratorWrapper((TerraBiomeSource) this.biomeSource.withSeed(seed), seed, pack);
}
public ConfigPack getPack() {
return pack;
}
@Override
public void buildSurface(ChunkRegion region, Chunk chunk) {
// No-op
}
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.getRegistry(TerraStructure.class).get(pack.getTemplate().getLocatable().get(name));
if(located != null) {
CompletableFuture<BlockPos> 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<BlockPos> 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;
}
@Override
public void generateFeatures(ChunkRegion region, StructureAccessor accessor) {
super.generateFeatures(region, accessor);
}
@Override
public void populateNoise(WorldAccess world, StructureAccessor accessor, Chunk chunk) {
delegate.generateChunkData((World) world, new FastRandom(), chunk.getPos().x, chunk.getPos().z, (ChunkData) chunk);
return super.locateStructure(world, feature, center, radius, skipExistingChunks);
}
@Override
public void carve(long seed, BiomeAccess access, Chunk chunk, GenerationStep.Carver carver) {
// No caves
if(pack.getTemplate().vanillaCaves()) {
super.carve(seed, access, chunk, carver);
}
}
@Override
public void setStructureStarts(DynamicRegistryManager dynamicRegistryManager, StructureAccessor structureAccessor, Chunk chunk, StructureManager structureManager, long worldSeed) {
if(pack.getTemplate().vanillaStructures()) {
super.setStructureStarts(dynamicRegistryManager, structureAccessor, chunk, structureManager, worldSeed);
}
}
@Override
public CompletableFuture<Chunk> populateNoise(Executor executor, StructureAccessor accessor, Chunk chunk) {
return CompletableFuture.supplyAsync(() -> {
World world = (World) ((StructureAccessorAccessor) accessor).getWorld();
delegate.generateChunkData(world, new FastRandom(), chunk.getPos().x, chunk.getPos().z, (ChunkData) chunk);
delegate.getPopulators().forEach(populator -> {
if(populator instanceof Chunkified) {
populator.populate(world, (com.dfsek.terra.api.platform.world.Chunk) world);
}
});
return chunk;
}, executor);
}
@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);
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);
public int getHeightOnGround(int x, int z, Heightmap.Type heightmap, HeightLimitView world) {
return super.getHeightOnGround(x, z, heightmap, world);
}
@Override
public int getHeight(int x, int z, Heightmap.Type heightmap, HeightLimitView heightmapType) {
TerraWorld world = TerraFabricPlugin.getInstance().getWorld(dimensionType);
int height = world.getWorld().getMaxHeight();
while (height >= 0 && sampler.sample(cx, height - 1, cz) < 0) {
while(height >= world.getWorld().getMinHeight() && !heightmap.getBlockPredicate().test(((FabricBlockData) world.getUngeneratedBlock(x, height - 1, z)).getHandle())) {
height--;
}
return height;
}
@Override
public BlockView getColumnSample(int x, int z) {
int height = 64; // TODO: implementation
BlockState[] array = new BlockState[256];
for(int y = 255; y >= 0; y--) {
if(y > height) {
if(y > getSeaLevel()) {
array[y] = Blocks.AIR.getDefaultState();
} else {
array[y] = Blocks.WATER.getDefaultState();
}
} else {
array[y] = Blocks.STONE.getDefaultState();
public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView view) {
TerraWorld world = TerraFabricPlugin.getInstance().getWorld(dimensionType);
BlockState[] array = new BlockState[view.getHeight()];
for(int y = view.getBottomY() + view.getHeight() - 1; y >= view.getBottomY(); y--) {
array[y] = ((FabricBlockData) world.getUngeneratedBlock(x, y, z)).getHandle();
}
return new VerticalBlockSample(view.getBottomY(), array);
}
@Override
public void populateEntities(ChunkRegion region) {
if(pack.getTemplate().vanillaMobs()) {
int cx = region.getCenterPos().x;
int cy = region.getCenterPos().z;
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, region.getCenterPos(), chunkRandom);
}
}
public Pool<SpawnSettings.SpawnEntry> getEntitySpawnList(Biome biome, StructureAccessor accessor, SpawnGroup group, BlockPos pos) {
if(accessor.getStructureAt(pos, true, StructureFeature.SWAMP_HUT).hasChildren()) {
if(group == SpawnGroup.MONSTER) {
return StructureFeature.SWAMP_HUT.getMonsterSpawns();
}
if(group == SpawnGroup.CREATURE) {
return StructureFeature.SWAMP_HUT.getCreatureSpawns();
}
}
return new VerticalBlockSample(array);
if(group == SpawnGroup.MONSTER) {
if(accessor.getStructureAt(pos, false, StructureFeature.PILLAGER_OUTPOST).hasChildren()) {
return StructureFeature.PILLAGER_OUTPOST.getMonsterSpawns();
}
if(accessor.getStructureAt(pos, false, StructureFeature.MONUMENT).hasChildren()) {
return StructureFeature.MONUMENT.getMonsterSpawns();
}
if(accessor.getStructureAt(pos, true, StructureFeature.FORTRESS).hasChildren()) {
return StructureFeature.FORTRESS.getMonsterSpawns();
}
}
return group == SpawnGroup.UNDERGROUND_WATER_CREATURE && accessor.getStructureAt(pos, false, StructureFeature.MONUMENT).hasChildren() ? StructureFeature.MONUMENT.getUndergroundWaterCreatureSpawns() : super.getEntitySpawnList(biome, accessor, group, pos);
}
@Override
@@ -2,15 +2,13 @@ package com.dfsek.terra.fabric.generation;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.mojang.serialization.Codec;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.Feature;
import java.util.Random;
import net.minecraft.world.gen.feature.util.FeatureContext;
/**
* Feature wrapper for Terra populator
@@ -21,9 +19,16 @@ public class PopulatorFeature extends Feature<DefaultFeatureConfig> {
}
@Override
public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) {
public boolean generate(FeatureContext<DefaultFeatureConfig> context) {
ChunkGenerator chunkGenerator = context.getGenerator();
if(!(chunkGenerator instanceof FabricChunkGeneratorWrapper)) return true;
StructureWorldAccess world = context.getWorld();
FabricChunkGeneratorWrapper gen = (FabricChunkGeneratorWrapper) chunkGenerator;
gen.getHandle().getPopulators().forEach(populator -> populator.populate((World) world, (Chunk) world));
gen.getHandle().getPopulators().forEach(populator -> {
if(!(populator instanceof Chunkified)) {
populator.populate((World) world, (Chunk) world);
}
});
return true;
}
}
@@ -4,15 +4,16 @@ 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;
import net.minecraft.util.dynamic.RegistryLookupCodec;
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<Biome> 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;
}
}
@@ -0,0 +1,38 @@
package com.dfsek.terra.fabric.generation;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.event.BiomeRegistrationEvent;
import com.dfsek.terra.fabric.util.FabricUtil;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.world.GeneratorType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
@Environment(EnvType.CLIENT)
public class TerraGeneratorType extends GeneratorType {
private final ConfigPack pack;
public TerraGeneratorType(ConfigPack pack) {
super("terra." + pack.getTemplate().getID());
this.pack = pack;
}
@Override
public GeneratorOptions createDefaultOptions(DynamicRegistryManager.Impl registryManager, long seed, boolean generateStructures, boolean bonusChest) {
GeneratorOptions options = super.createDefaultOptions(registryManager, seed, generateStructures, bonusChest);
TerraFabricPlugin.getInstance().getEventManager().callEvent(new BiomeRegistrationEvent(registryManager)); // register biomes
return options;
}
@Override
protected ChunkGenerator getChunkGenerator(Registry<Biome> biomeRegistry, Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry, long seed) {
return new FabricChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack);
}
}
@@ -1,9 +1,13 @@
package com.dfsek.terra.fabric.handle;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.fabric.block.FabricBlockData;
import com.dfsek.terra.fabric.util.FabricAdapter;
import com.dfsek.terra.fabric.util.WorldEditUtil;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.BlockState;
@@ -33,4 +37,14 @@ public class FabricWorldHandle implements WorldHandle {
if(identifier == null) identifier = Identifier.tryParse("minecraft:" + id.toLowerCase(Locale.ROOT));
return (EntityType) Registry.ENTITY_TYPE.get(identifier);
}
@Override
public Pair<Location, Location> getSelectedLocation(Player player) {
try {
Class.forName("com.sk89q.worldedit.WorldEdit");
} catch(ClassNotFoundException e) {
throw new IllegalStateException("WorldEdit is not installed.");
}
return WorldEditUtil.getSelection(player);
}
}
@@ -0,0 +1,86 @@
package com.dfsek.terra.fabric.mixin;
import com.dfsek.terra.api.command.exception.CommandException;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
@Mixin(CommandManager.class)
public abstract class CommandManagerMixin {
@Shadow
@Final
private CommandDispatcher<ServerCommandSource> dispatcher;
@Inject(method = "<init>", 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();
RequiredArgumentBuilder<ServerCommandSource, String> arg = argument("arg" + (max - 1), StringArgumentType.word());
for(int i = 0; i < max; i++) {
RequiredArgumentBuilder<ServerCommandSource, String> next = argument("arg" + (max - i - 1), StringArgumentType.word());
arg = next.then(assemble(arg, manager));
}
dispatcher.register(literal("terra").executes(context -> 1).then(assemble(arg, manager)));
dispatcher.register(literal("te").executes(context -> 1).then(assemble(arg, manager)));
}
private RequiredArgumentBuilder<ServerCommandSource, String> assemble(RequiredArgumentBuilder<ServerCommandSource, String> in, com.dfsek.terra.api.command.CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrThrow();
} catch(CommandSyntaxException ignore) {
}
try {
manager.tabComplete(args.remove(0), sender, args).forEach(builder::suggest);
} catch(CommandException e) {
sender.sendMessage(e.getMessage());
}
return builder.buildFuture();
}).executes(context -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrThrow();
} catch(CommandSyntaxException ignore) {
}
try {
manager.execute(args.remove(0), sender, args);
} catch(CommandException e) {
context.getSource().sendError(new LiteralText(e.getMessage()));
}
return 1;
});
}
private List<String> parseCommand(String command) {
if(command.startsWith("/terra ")) command = command.substring("/terra ".length());
else if(command.startsWith("/te ")) command = command.substring("/te ".length());
List<String> c = new ArrayList<>(Arrays.asList(command.split(" ")));
if(command.endsWith(" ")) c.add("");
return c;
}
}
@@ -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 = "<init>", at = @At(value = "RETURN"))
public void injectConstructor(MinecraftServer server, Executor workerExecutor, LevelStorage.Session session, ServerWorldProperties properties, RegistryKey<World> registryKey, DimensionType dimensionType, WorldGenerationProgressListener worldGenerationProgressListener, ChunkGenerator chunkGenerator, boolean debugWorld, long l, List<Spawner> 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);
}
}
}
@@ -0,0 +1,12 @@
package com.dfsek.terra.fabric.mixin;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.gen.StructureAccessor;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(StructureAccessor.class)
public interface StructureAccessorAccessor {
@Accessor
WorldAccess getWorld();
}
@@ -1,12 +1,14 @@
package com.dfsek.terra.fabric.mixin.access;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.MobSpawnerLogic;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(MobSpawnerLogic.class)
public interface MobSpawnerLogicAccessor {
@Invoker("getEntityId")
Identifier callGetEntityId();
Identifier callGetEntityId(World world, BlockPos blockPos);
}
@@ -3,11 +3,13 @@ package com.dfsek.terra.fabric.mixin.implementations;
import net.minecraft.world.biome.Biome;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Biome.class)
@Implements(@Interface(iface = com.dfsek.terra.api.platform.world.Biome.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class BiomeMixin {
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -3,11 +3,13 @@ package com.dfsek.terra.fabric.mixin.implementations;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(ChunkGenerator.class)
@Implements(@Interface(iface = com.dfsek.terra.api.platform.world.generator.ChunkGenerator.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class ChunkGeneratorMixin {
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -3,20 +3,23 @@ package com.dfsek.terra.fabric.mixin.implementations.block;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.block.FabricBlock;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(BlockEntity.class)
@Implements(@Interface(iface = BlockState.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class BlockEntityMixin {
@Final
@Shadow
protected BlockPos pos;
@Shadow
@@ -29,6 +32,7 @@ public abstract class BlockEntityMixin {
@Shadow
public abstract boolean hasWorld();
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -54,7 +58,7 @@ public abstract class BlockEntityMixin {
}
public boolean terra$update(boolean applyPhysics) {
if(hasWorld()) world.getChunk(pos).setBlockEntity(pos, (BlockEntity) (Object) this);
if(hasWorld()) world.getChunk(pos).setBlockEntity((BlockEntity) (Object) this);
return true;
}
}
@@ -2,12 +2,13 @@ package com.dfsek.terra.fabric.mixin.implementations.block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -17,6 +18,7 @@ public abstract class BlockMixin {
@Shadow
private BlockState defaultState;
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -6,6 +6,7 @@ import com.dfsek.terra.fabric.mixin.implementations.block.BlockEntityMixin;
import net.minecraft.block.entity.LootableContainerBlockEntity;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(LootableContainerBlockEntity.class)
@@ -15,6 +16,7 @@ public abstract class LootableContainerBlockEntityMixin extends BlockEntityMixin
return (Inventory) this;
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -5,9 +5,14 @@ import com.dfsek.terra.api.platform.block.state.SerialState;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.mixin.access.MobSpawnerLogicAccessor;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.MobSpawnerLogic;
import net.minecraft.world.World;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
@@ -16,12 +21,16 @@ import org.spongepowered.asm.mixin.Shadow;
@Mixin(MobSpawnerBlockEntity.class)
@Implements(@Interface(iface = MobSpawner.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class MobSpawnerBlockEntityMixin {
public abstract class MobSpawnerBlockEntityMixin extends BlockEntity {
private MobSpawnerBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
@Shadow
public abstract MobSpawnerLogic getLogic();
public EntityType terra$getSpawnedType() {
return (EntityType) Registry.ENTITY_TYPE.get(((MobSpawnerLogicAccessor) getLogic()).callGetEntityId());
return (EntityType) Registry.ENTITY_TYPE.get(((MobSpawnerLogicAccessor) getLogic()).callGetEntityId(world, pos));
}
public void terra$setSpawnedType(@NotNull EntityType creatureType) {
@@ -20,18 +20,18 @@ public abstract class SignBlockEntityMixin {
@Shadow
@Final
private Text[] text;
private Text[] texts;
public @NotNull String[] terra$getLines() {
String[] lines = new String[text.length];
for(int i = 0; i < text.length; i++) {
lines[i] = text[i].asString();
String[] lines = new String[texts.length];
for(int i = 0; i < texts.length; i++) {
lines[i] = texts[i].asString();
}
return lines;
}
public @NotNull String terra$getLine(int index) throws IndexOutOfBoundsException {
return text[index].asString();
return texts[index].asString();
}
public void terra$setLine(int index, @NotNull String line) throws IndexOutOfBoundsException {
@@ -7,6 +7,7 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.block.FabricBlock;
import com.dfsek.terra.fabric.block.FabricBlockData;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.ChunkRegion;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
@@ -20,18 +21,14 @@ import org.spongepowered.asm.mixin.Shadow;
public abstract class ChunkRegionMixin {
@Final
@Shadow
private int centerChunkX;
@Final
@Shadow
private int centerChunkZ;
private ChunkPos centerPos;
public int terra$getX() {
return centerChunkX;
return centerPos.x;
}
public int terra$getZ() {
return centerChunkZ;
return centerPos.z;
}
public World terra$getWorld() {
@@ -39,7 +36,7 @@ public abstract class ChunkRegionMixin {
}
public Block terra$getBlock(int x, int y, int z) {
BlockPos pos = new BlockPos(x + (centerChunkX << 4), y, z + (centerChunkZ << 4));
BlockPos pos = new BlockPos(x + (centerPos.x << 4), y, z + (centerPos.z << 4));
return new FabricBlock(pos, (ChunkRegion) (Object) this);
}
@@ -48,10 +45,8 @@ public abstract class ChunkRegionMixin {
}
public void terra$setBlock(int x, int y, int z, @NotNull BlockData blockData) {
((ChunkRegion) (Object) this).setBlockState(new BlockPos(x + (centerChunkX << 4), y, z + (centerChunkZ << 4)), ((FabricBlockData) blockData).getHandle(), 0);
((ChunkRegion) (Object) this).setBlockState(new BlockPos(x + (centerPos.x << 4), y, z + (centerPos.z << 4)), ((FabricBlockData) blockData).getHandle(), 0);
}
public Object terra$getHandle() {
return this;
}
// getHandle already added in world/ChunkRegionMixin.
}
@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -47,6 +48,7 @@ public abstract class WorldChunkMixin {
((net.minecraft.world.chunk.Chunk) this).setBlockState(new BlockPos(x, y, z), ((FabricBlockData) blockData).getHandle(), false);
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -9,6 +9,7 @@ import net.minecraft.world.chunk.ProtoChunk;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -26,6 +27,7 @@ public abstract class ProtoChunkMixin {
((net.minecraft.world.chunk.Chunk) this).setBlockState(new BlockPos(x, y, z), ((FabricBlockData) blockData).getHandle(), false);
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -2,13 +2,14 @@ package com.dfsek.terra.fabric.mixin.implementations.entity;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.fabric.FabricAdapter;
import com.dfsek.terra.fabric.util.FabricAdapter;
import net.minecraft.entity.Entity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -29,6 +30,7 @@ public abstract class EntityMixin {
@Shadow
public abstract void sendSystemMessage(Text message, UUID senderUuid);
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -3,11 +3,13 @@ package com.dfsek.terra.fabric.mixin.implementations.entity;
import net.minecraft.entity.EntityType;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(EntityType.class)
@Implements(@Interface(iface = com.dfsek.terra.api.platform.entity.EntityType.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class EntityTypeMixin {
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -6,6 +6,7 @@ import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -19,6 +20,7 @@ public abstract class ServerCommandSourceMixin {
sendFeedback(new LiteralText(message), true);
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -6,11 +6,13 @@ import net.minecraft.block.entity.LockableContainerBlockEntity;
import net.minecraft.item.Items;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(LockableContainerBlockEntity.class)
@Implements(@Interface(iface = Inventory.class, prefix = "terra$", remap = Interface.Remap.NONE))
public class LockableContainerBlockEntityMixin {
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -4,6 +4,7 @@ import com.dfsek.terra.api.platform.inventory.ItemStack;
import net.minecraft.item.Item;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -13,6 +14,7 @@ public abstract class ItemMixin {
@Shadow
public abstract int getMaxDamage();
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -3,7 +3,7 @@ package com.dfsek.terra.fabric.mixin.implementations.inventory.item;
import com.dfsek.terra.api.platform.inventory.Item;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtCompound;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
@@ -27,7 +27,7 @@ public abstract class ItemStackMixin {
public abstract boolean isDamageable();
@Shadow
public abstract void setTag(@Nullable CompoundTag tag);
public abstract void setTag(@Nullable NbtCompound tag);
public int terra$getAmount() {
return getCount();
@@ -50,6 +50,7 @@ public abstract class ItemStackMixin {
setTag(((ItemStack) (Object) meta).getTag());
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -5,6 +5,7 @@ import net.minecraft.enchantment.Enchantment;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -19,6 +20,7 @@ public abstract class EnchantmentMixin {
@Shadow
public abstract boolean canCombine(Enchantment other);
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -3,8 +3,8 @@ package com.dfsek.terra.fabric.mixin.implementations.inventory.meta;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtList;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
@@ -23,11 +23,12 @@ public abstract class ItemStackMetaMixin {
public abstract boolean hasEnchantments();
@Shadow
public abstract ListTag getEnchantments();
public abstract NbtList getEnchantments();
@Shadow
public abstract void addEnchantment(net.minecraft.enchantment.Enchantment enchantment, int level);
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -38,7 +39,7 @@ public abstract class ItemStackMetaMixin {
Map<Enchantment, Integer> map = new HashMap<>();
getEnchantments().forEach(enchantment -> {
CompoundTag eTag = (CompoundTag) enchantment;
NbtCompound eTag = (NbtCompound) enchantment;
map.put((Enchantment) Registry.ENCHANTMENT.get(eTag.getInt("id")), eTag.getInt("lvl"));
});
return map;
@@ -34,7 +34,7 @@ public abstract class ChunkRegionMixin {
private long seed;
public int terra$getMaxHeight() {
return ((ChunkRegion) (Object) this).getDimensionHeight();
return (((ChunkRegion) (Object) this).getBottomY()) + ((ChunkRegion) (Object) this).getHeight();
}
@SuppressWarnings("deprecation")
@@ -64,9 +64,10 @@ public abstract class ChunkRegionMixin {
}
public int terra$getMinHeight() {
return 0;
return ((ChunkRegion) (Object) this).getBottomY();
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -13,6 +13,7 @@ import com.dfsek.terra.fabric.block.FabricBlock;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.ServerWorldAccess;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
@@ -27,7 +28,7 @@ public abstract class ServerWorldMixin {
public abstract long getSeed();
public int terra$getMaxHeight() {
return ((ServerWorld) (Object) this).getDimensionHeight();
return (((ServerWorld) (Object) this).getBottomY()) + ((ServerWorld) (Object) this).getHeight();
}
public ChunkGenerator terra$getGenerator() {
@@ -55,9 +56,10 @@ public abstract class ServerWorldMixin {
}
public int terra$getMinHeight() {
return 0;
return ((ServerWorld) (Object) this).getBottomY();
}
@Intrinsic
public Object terra$getHandle() {
return this;
}
@@ -0,0 +1,30 @@
package com.dfsek.terra.fabric.mixin.lifecycle.client;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.event.GameInitializationEvent;
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;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MinecraftClient.class)
public class MinecraftClientMixin {
@Inject(method = "<init>", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/util/WindowProvider;createWindow(Lnet/minecraft/client/WindowSettings;Ljava/lang/String;Ljava/lang/String;)Lnet/minecraft/client/util/Window;", // sorta arbitrary position, after mod init, before window opens
shift = At.Shift.BEFORE))
public void injectConstructor(RunArgs args, CallbackInfo callbackInfo) {
TerraFabricPlugin.getInstance().getEventManager().callEvent(new GameInitializationEvent());
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);
});
}
}
@@ -0,0 +1,4 @@
/**
* Mixins that inject behavior into the client/server lifecycle.
*/
package com.dfsek.terra.fabric.mixin.lifecycle;
@@ -1,10 +1,13 @@
package com.dfsek.terra.fabric.mixin;
package com.dfsek.terra.fabric.mixin.lifecycle.server;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.event.BiomeRegistrationEvent;
import com.dfsek.terra.fabric.generation.TerraBiomeSource;
import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper;
import com.dfsek.terra.fabric.util.FabricUtil;
import com.google.common.base.MoreObjects;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
@@ -24,11 +27,13 @@ import java.util.Random;
@Mixin(GeneratorOptions.class)
public abstract class GeneratorOptionsMixin {
@Inject(method = "fromProperties(Lnet/minecraft/util/registry/DynamicRegistryManager;Ljava/util/Properties;)Lnet/minecraft/world/gen/GeneratorOptions;", at = @At("HEAD"), cancellable = true)
private static void fromProperties(DynamicRegistryManager dynamicRegistryManager, Properties properties, CallbackInfoReturnable<GeneratorOptions> cir) {
private static void fromProperties(DynamicRegistryManager registryManager, Properties properties, CallbackInfoReturnable<GeneratorOptions> cir) {
if(properties.get("level-type") == null) {
return;
}
TerraFabricPlugin main = TerraFabricPlugin.getInstance();
String prop = properties.get("level-type").toString().trim();
if(prop.startsWith("Terra")) {
String seed = (String) MoreObjects.firstNonNull(properties.get("level-seed"), "");
@@ -46,18 +51,20 @@ public abstract class GeneratorOptionsMixin {
String generate_structures = (String) properties.get("generate-structures");
boolean generateStructures = generate_structures == null || Boolean.parseBoolean(generate_structures);
Registry<DimensionType> dimensionTypes = dynamicRegistryManager.get(Registry.DIMENSION_TYPE_KEY);
Registry<Biome> biomes = dynamicRegistryManager.get(Registry.BIOME_KEY);
Registry<ChunkGeneratorSettings> chunkGeneratorSettings = dynamicRegistryManager.get(Registry.NOISE_SETTINGS_WORLDGEN);
SimpleRegistry<DimensionOptions> dimensionOptions = DimensionType.createDefaultDimensionOptions(dimensionTypes, biomes, chunkGeneratorSettings, l);
Registry<DimensionType> dimensionTypes = registryManager.get(Registry.DIMENSION_TYPE_KEY);
Registry<Biome> biomeRegistry = registryManager.get(Registry.BIOME_KEY);
Registry<ChunkGeneratorSettings> chunkGeneratorSettings = registryManager.get(Registry.CHUNK_GENERATOR_SETTINGS_KEY);
SimpleRegistry<DimensionOptions> dimensionOptions = DimensionType.createDefaultDimensionOptions(dimensionTypes, biomeRegistry, chunkGeneratorSettings, l);
prop = prop.substring(prop.indexOf(":") + 1);
ConfigPack pack = TerraFabricPlugin.getInstance().getConfigRegistry().get(prop);
ConfigPack config = main.getConfigRegistry().get(prop);
if(pack == null) throw new IllegalArgumentException("No such pack " + prop);
if(config == null) throw new IllegalArgumentException("No such pack " + prop);
cir.setReturnValue(new GeneratorOptions(l, generateStructures, false, GeneratorOptions.method_28608(dimensionTypes, dimensionOptions, new FabricChunkGeneratorWrapper(new TerraBiomeSource(biomes, l, pack), l, pack))));
main.getEventManager().callEvent(new BiomeRegistrationEvent(registryManager)); // register biomes
cir.setReturnValue(new GeneratorOptions(l, generateStructures, false, GeneratorOptions.getRegistryWithReplacedOverworldGenerator(dimensionTypes, dimensionOptions, new FabricChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, l, config), l, config))));
}
}
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.fabric.mixin.lifecycle.server;
import com.dfsek.terra.fabric.TerraFabricPlugin;
import com.dfsek.terra.fabric.event.GameInitializationEvent;
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 ServerMainMixin {
@Inject(method = "main([Ljava/lang/String;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/registry/DynamicRegistryManager;create()Lnet/minecraft/util/registry/DynamicRegistryManager$Impl;"))
private static void injectConstructor(String[] args, CallbackInfo ci) {
TerraFabricPlugin.getInstance().getEventManager().callEvent(new GameInitializationEvent()); // Load during MinecraftServer construction, after other mods have registered blocks and stuff
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.fabric;
package com.dfsek.terra.fabric.util;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.Axis;
@@ -0,0 +1,133 @@
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 com.mojang.serialization.Lifecycle;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.util.registry.MutableRegistry;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
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 biome The Terra BiomeBuilder.
* @param pack The ConfigPack this biome belongs to.
* @return The Minecraft delegate biome.
*/
public static Biome createBiome(BiomeBuilder biome, ConfigPack pack, DynamicRegistryManager registryManager) {
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
TerraFabricPlugin.FabricAddon fabricAddon = TerraFabricPlugin.getInstance().getFabricAddon();
Registry<Biome> biomeRegistry = registryManager.get(Registry.BIOME_KEY);
Biome vanilla = ((ProtoBiome) (new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0))).get(biomeRegistry);
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<ConfiguredCarver<?>> configuredCarverSupplier : vanilla.getGenerationSettings().getCarversForStep(carver)) {
generationSettings.carver(carver, configuredCarverSupplier.get());
}
}
}
Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions> 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());
Registry<ConfiguredStructureFeature<?, ?>> configuredStructureFeatureRegistry = registryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_KEY);
for(Supplier<ConfiguredStructureFeature<?, ?>> structureFeature : vanilla.getGenerationSettings().getStructureFeatures()) {
Identifier key = configuredStructureFeatureRegistry.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()) {
Registry<ConfiguredFeature<?, ?>> configuredFeatureRegistry = registryManager.get(Registry.CONFIGURED_FEATURE_KEY);
for(int step = 0; step < vanilla.getGenerationSettings().getFeatures().size(); step++) {
for(Supplier<ConfiguredFeature<?, ?>> featureSupplier : vanilla.getGenerationSettings().getFeatures().get(step)) {
Identifier key = configuredFeatureRegistry.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();
}
public static <T> void registerOrOverwrite(Registry<T> registry, RegistryKey<Registry<T>> key, Identifier identifier, T item) {
if(registry.containsId(identifier)) {
((MutableRegistry<T>) registry).set(registry.getRawId(registry.get(identifier)), RegistryKey.of(key, identifier), item, Lifecycle.stable());
} else {
Registry.register(registry, identifier, item);
}
}
}
@@ -0,0 +1,22 @@
package com.dfsek.terra.fabric.util;
import com.dfsek.terra.api.platform.world.Biome;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public class ProtoBiome implements Biome {
private final Identifier identifier;
public ProtoBiome(Identifier identifier) {
this.identifier = identifier;
}
public net.minecraft.world.biome.Biome get(Registry<net.minecraft.world.biome.Biome> registry) {
return registry.get(identifier);
}
@Override
public Object getHandle() {
return identifier;
}
}
@@ -0,0 +1,29 @@
package com.dfsek.terra.fabric.util;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.world.World;
public final class WorldEditUtil {
public static Pair<Location, Location> getSelection(Player player) {
WorldEdit worldEdit = WorldEdit.getInstance();
try {
Region selection = worldEdit.getSessionManager()
.get(com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer((ServerPlayerEntity) player))
.getSelection(com.sk89q.worldedit.fabric.FabricAdapter.adapt((World) player.getWorld()));
BlockVector3 min = selection.getMinimumPoint();
BlockVector3 max = selection.getMaximumPoint();
Location l1 = new Location(player.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
Location l2 = new Location(player.getWorld(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
return Pair.of(l1, l2);
} catch(IncompleteRegionException e) {
throw new IllegalStateException("No selection has been made", e);
}
}
}
@@ -3,15 +3,16 @@
"id": "terra",
"version": "@VERSION@",
"name": "Terra",
"description": "An insanely powerful free & open-source data-driven world generator.",
"description": "@DESCRIPTION@",
"authors": [
"dfsek"
],
"contact": {
"homepage": "https://github.com/PolyhedralDev/Terra/wiki",
"sources": "https://github.com/PolyhedralDev/Terra"
"homepage": "@WIKI@",
"sources": "@SOURCE@",
"issues": "@ISSUES@"
},
"license": "GPL-3.0",
"license": "@LICENSE@",
"icon": "assets/terra/icon.png",
"environment": "*",
"entrypoints": {
@@ -24,8 +25,7 @@
],
"depends": {
"fabricloader": ">=0.7.4",
"fabric": "*",
"minecraft": "1.16.x"
"minecraft": "1.17.x"
},
"accessWidener": "terra.accesswidener"
}
@@ -1,3 +1,3 @@
accessWidener v1 named
extendable method net/minecraft/client/world/GeneratorType <init> (Ljava/lang/String;)V
extendable method net/minecraft/client/world/GeneratorType <init> (Ljava/lang/String;)V
@@ -2,9 +2,11 @@
"required": true,
"minVersion": "0.8",
"package": "com.dfsek.terra.fabric.mixin",
"compatibilityLevel": "JAVA_8",
"compatibilityLevel": "JAVA_16",
"mixins": [
"GeneratorOptionsMixin",
"StructureAccessorAccessor",
"CommandManagerMixin",
"ServerWorldMixin",
"access.BiomeEffectsAccessor",
"access.MobSpawnerLogicAccessor",
"access.StateAccessor",
@@ -33,9 +35,13 @@
"implementations.world.ServerWorldMixin"
],
"client": [
"access.GeneratorTypeAccessor"
"access.GeneratorTypeAccessor",
"lifecycle.client.MinecraftClientMixin"
],
"server": [
"lifecycle.server.GeneratorOptionsMixin",
"lifecycle.server.ServerMainMixin"
],
"server": [],
"injectors": {
"defaultRequire": 1
},
@@ -1,6 +1,6 @@
import com.dfsek.terra.configureCommon
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.minecraftforge.gradle.common.util.RunConfig
import net.minecraftforge.gradle.mcp.task.GenerateSRG
import net.minecraftforge.gradle.userdev.UserDevExtension
import net.minecraftforge.gradle.userdev.tasks.RenameJarInPlace
@@ -55,11 +55,17 @@ if ("true" == System.getProperty("idea.sync.active")) {
}
}
tasks.named<ShadowJar>("shadowJar") {
archiveBaseName.set(tasks.getByName<Jar>("jar").archiveBaseName.orNull) // Pain. Agony, even.
archiveClassifier.set("") // Suffering, if you will.
}
afterEvaluate {
val reobf = extensions.getByName<NamedDomainObjectContainer<RenameJarInPlace>>("reobf")
reobf.maybeCreate("shadowJar").run {
group = "forge"
mappings = tasks.getByName<GenerateSRG>("createMcpToSrg").output
tasks.named<RenameJarInPlace>("reobfJar") {
val shadow = tasks.getByName<ShadowJar>("shadowJar");
dependsOn(shadow)
input = shadow.archiveFile.orNull?.asFile
}
}
@@ -71,7 +77,7 @@ configure<UserDevExtension> {
runs {
val runConfig = Action<RunConfig> {
properties(mapOf(
"forge.logging.markers" to "SCAN,REGISTRIES,REGISTRYDUMP",
//"forge.logging.markers" to "SCAN,REGISTRIES,REGISTRYDUMP",
"forge.logging.console.level" to "debug"
))
arg("-mixin.config=terra.mixins.json")
@@ -124,12 +130,12 @@ tasks.jar {
}
tasks.register<com.modrinth.minotaur.TaskModrinthUpload>("publishModrinthForge") {
dependsOn("reobfShadowJar")
dependsOn("reobfJar")
group = "forge"
token = System.getenv("MODRINTH_SECRET")
projectId = "FIlZB9L0"
versionNumber = "${project.version}-forge"
uploadFile = tasks.named<RenameJarInPlace>("reobfShadowJar").get().input.absoluteFile
uploadFile = tasks.named<RenameJarInPlace>("reobfJar").get().input.absoluteFile
releaseType = "alpha"
addGameVersion("1.16.5")
addLoader("forge")
@@ -0,0 +1,90 @@
package com.dfsek.terra.forge;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.platform.block.state.MobSpawner;
import com.dfsek.terra.api.platform.block.state.Sign;
import com.dfsek.terra.forge.block.ForgeBlockData;
import com.dfsek.terra.forge.block.data.ForgeDirectional;
import com.dfsek.terra.forge.block.data.ForgeMultipleFacing;
import com.dfsek.terra.forge.block.data.ForgeOrientable;
import com.dfsek.terra.forge.block.data.ForgeRotatable;
import com.dfsek.terra.forge.block.data.ForgeSlab;
import com.dfsek.terra.forge.block.data.ForgeStairs;
import com.dfsek.terra.forge.block.data.ForgeWaterlogged;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.LockableLootTileEntity;
import net.minecraft.tileentity.MobSpawnerTileEntity;
import net.minecraft.tileentity.SignTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import java.util.Arrays;
public final class ForgeAdapter {
public static BlockPos adapt(Vector3 v) {
return new BlockPos(v.getBlockX(), v.getBlockY(), v.getBlockZ());
}
public static Vector3 adapt(BlockPos pos) {
return new Vector3(pos.getX(), pos.getY(), pos.getZ());
}
public static ForgeBlockData adapt(BlockState state) {
if(state.hasProperty(BlockStateProperties.STAIRS_SHAPE)) return new ForgeStairs(state);
if(state.hasProperty(BlockStateProperties.SLAB_TYPE)) return new ForgeSlab(state);
if(state.hasProperty(BlockStateProperties.AXIS)) return new ForgeOrientable(state, BlockStateProperties.AXIS);
if(state.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) return new ForgeOrientable(state, BlockStateProperties.HORIZONTAL_AXIS);
if(state.hasProperty(BlockStateProperties.ROTATION_16)) return new ForgeRotatable(state);
if(state.hasProperty(BlockStateProperties.FACING)) return new ForgeDirectional(state, BlockStateProperties.FACING);
if(state.hasProperty(BlockStateProperties.FACING_HOPPER)) return new ForgeDirectional(state, BlockStateProperties.FACING_HOPPER);
if(state.hasProperty(BlockStateProperties.HORIZONTAL_FACING))
return new ForgeDirectional(state, BlockStateProperties.HORIZONTAL_FACING);
if(state.getProperties().containsAll(Arrays.asList(BlockStateProperties.NORTH, BlockStateProperties.SOUTH, BlockStateProperties.EAST, BlockStateProperties.WEST)))
return new ForgeMultipleFacing(state);
if(state.hasProperty(BlockStateProperties.WATERLOGGED)) return new ForgeWaterlogged(state);
return new ForgeBlockData(state);
}
public static com.dfsek.terra.api.platform.block.state.BlockState adapt(com.dfsek.terra.api.platform.block.Block block) {
IWorld worldAccess = (IWorld) block.getLocation().getWorld();
TileEntity entity = worldAccess.getBlockEntity(adapt(block.getLocation().toVector()));
if(entity instanceof SignTileEntity) {
return (Sign) entity;
} else if(entity instanceof MobSpawnerTileEntity) {
return (MobSpawner) entity;
} else if(entity instanceof LockableLootTileEntity) {
return (Container) entity;
}
return null;
}
public static Direction adapt(BlockFace face) {
switch(face) {
case NORTH:
return Direction.NORTH;
case WEST:
return Direction.WEST;
case SOUTH:
return Direction.SOUTH;
case EAST:
return Direction.EAST;
case UP:
return Direction.UP;
case DOWN:
return Direction.DOWN;
default:
throw new IllegalArgumentException("Illegal direction: " + face);
}
}
}
@@ -0,0 +1,109 @@
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 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.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);
}
public static Biome createBiome(BiomeBuilder biome, ConfigPack pack, TerraForgePlugin.ForgeAddon forgeAddon) {
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
Biome vanilla = (Biome) (new ArrayList<>(biome.getVanillaBiomes().getContents()).get(0)).getHandle();
BiomeGenerationSettings.Builder generationSettings = new BiomeGenerationSettings.Builder();
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()))
.waterFogColor(colors.getOrDefault("water-fog", vanillaEffects.getWaterFogColor()))
.fogColor(colors.getOrDefault("fog", vanillaEffects.getFogColor()))
.skyColor(colors.getOrDefault("sky", vanillaEffects.getSkyColor()))
.grassColorModifier(vanillaEffects.getGrassColorModifier());
if(colors.containsKey("grass")) {
effects.grassColorOverride(colors.get("grass"));
} else {
vanillaEffects.getGrassColorOverride().ifPresent(effects::grassColorOverride);
}
if(colors.containsKey("foliage")) {
effects.foliageColorOverride(colors.get("foliage"));
} else {
vanillaEffects.getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
}
return new Biome.Builder()
.precipitation(vanilla.getPrecipitation())
.biomeCategory(vanilla.getBiomeCategory())
.depth(vanilla.getDepth())
.scale(vanilla.getScale())
.temperature(vanilla.getBaseTemperature())
.downfall(vanilla.getDownfall())
.specialEffects(effects.build())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(generationSettings.build())
.build()
.setRegistryName("terra", createBiomeID(template.getPack(), template.getID()));
}
}
@@ -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;
@@ -8,15 +10,14 @@ import com.dfsek.terra.api.addons.annotations.Author;
import com.dfsek.terra.api.addons.annotations.Version;
import com.dfsek.terra.api.command.CommandManager;
import com.dfsek.terra.api.command.TerraCommandManager;
import com.dfsek.terra.api.command.exception.CommandException;
import com.dfsek.terra.api.command.exception.MalformedCommandException;
import com.dfsek.terra.api.event.EventListener;
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.CommandSender;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
@@ -24,67 +25,48 @@ 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.generic.pair.Pair;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.api.util.mutable.MutableInteger;
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.forge.inventory.ForgeItemHandle;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.ForgeBiome;
import com.dfsek.terra.forge.world.ForgeTree;
import com.dfsek.terra.forge.world.ForgeWorldHandle;
import com.dfsek.terra.forge.world.features.PopulatorFeature;
import com.dfsek.terra.forge.world.generator.ForgeChunkGenerator;
import com.dfsek.terra.forge.world.generator.ForgeChunkGeneratorWrapper;
import com.dfsek.terra.forge.world.generator.config.TerraLevelType;
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;
import com.dfsek.terra.forge.handle.ForgeItemHandle;
import com.dfsek.terra.forge.handle.ForgeWorldHandle;
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 com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import net.minecraft.block.Blocks;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.command.CommandSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.StringTextComponent;
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.biome.BiomeAmbience;
import net.minecraft.world.biome.BiomeGenerationSettings;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.Features;
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.gen.surfacebuilders.SurfaceBuilder;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilderConfig;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ForgeWorldTypeScreens;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.world.ForgeWorldType;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
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;
@@ -94,20 +76,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.jar.JarFile;
import java.util.zip.ZipFile;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;
@Mod("terra")
@Mod.EventBusSubscriber(modid = "terra", bus = Mod.EventBusSubscriber.Bus.MOD)
public class TerraForgePlugin implements TerraPlugin {
@@ -115,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();
@@ -140,129 +114,51 @@ public class TerraForgePlugin implements TerraPlugin {
logger.error(message);
}
};
private final DebugLogger debugLogger = new DebugLogger(logger);
private final ItemHandle itemHandle = new ForgeItemHandle();
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>()
.addTransform(id -> ForgeRegistries.BIOMES.getValue(ResourceLocation.tryParse(id)), new NotNullValidator<>())
.addTransform(id -> ForgeRegistries.BIOMES.getValue(ResourceLocation.tryParse("minecraft:" + id.toLowerCase())), new NotNullValidator<>()).build();
private File dataFolder;
.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() {
if(INSTANCE != null) throw new IllegalStateException("Only one TerraPlugin instance may exist.");
INSTANCE = this;
MinecraftForge.EVENT_BUS.register(ClientEvents.class);
MinecraftForge.EVENT_BUS.register(getClass());
MinecraftForge.EVENT_BUS.register(ForgeEvents.class);
this.dataFolder = Paths.get("config", "Terra").toFile();
saveDefaultConfig();
config.load(this);
debugLogger.setDebug(config.isDebug());
LangUtil.load(config.getLanguage(), this);
try {
CommandUtil.registerAll(manager);
} catch(MalformedCommandException e) {
e.printStackTrace(); // TODO do something here even though this should literally never happen
}
}
public static TerraForgePlugin getInstance() {
return INSTANCE;
}
public static String createBiomeID(ConfigPack pack, String biomeID) {
return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT);
}
private static RequiredArgumentBuilder<CommandSource, String> assemble(RequiredArgumentBuilder<CommandSource, String> in, CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = ForgeAdapter.adapt(context.getSource());
try {
manager.tabComplete(args.remove(0), sender, args).forEach(builder::suggest);
} catch(CommandException e) {
sender.sendMessage(e.getMessage());
}
return builder.buildFuture();
}).executes(context -> {
List<String> args = parseCommand(context.getInput());
try {
manager.execute(args.remove(0), ForgeAdapter.adapt(context.getSource()), args);
} catch(CommandException e) {
context.getSource().sendFailure(new StringTextComponent(e.getMessage()));
}
return 1;
@SubscribeEvent
public static void setupListener(FMLCommonSetupEvent event) {
event.enqueueWork(() -> {
Registry.register(Registry.BIOME_SOURCE, "terra:biome", TerraBiomeSource.CODEC);
Registry.register(Registry.CHUNK_GENERATOR, "terra:generator", ForgeChunkGeneratorWrapper.CODEC);
});
}
private static List<String> parseCommand(String command) {
if(command.startsWith("/terra ")) command = command.substring("/terra ".length());
else if(command.startsWith("/te ")) command = command.substring("/te ".length());
List<String> c = new ArrayList<>(Arrays.asList(command.split(" ")));
if(command.endsWith(" ")) c.add("");
return c;
}
@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.getRegistry(BiomeBuilder.class).forEach((id, biome) -> event.getRegistry().register(INSTANCE.createBiome(biome)))); // Register all Terra biomes.
}
@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 registerPop(RegistryEvent.Register<Feature<?>> event) {
event.getRegistry().register(POPULATOR_FEATURE);
}
public Biome createBiome(BiomeBuilder biome) {
BiomeTemplate template = biome.getTemplate();
Map<String, Integer> colors = template.getColors();
Biome vanilla = ((ForgeBiome) 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.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, POPULATOR_CONFIGURED_FEATURE);
BiomeAmbience vanillaEffects = vanilla.getSpecialEffects();
BiomeAmbience.Builder effects = new BiomeAmbience.Builder()
.waterColor(colors.getOrDefault("water", vanillaEffects.getWaterColor()))
.waterFogColor(colors.getOrDefault("water-fog", vanillaEffects.getWaterFogColor()))
.fogColor(colors.getOrDefault("fog", vanillaEffects.getFogColor()))
.skyColor(colors.getOrDefault("sky", vanillaEffects.getSkyColor()))
.grassColorModifier(vanillaEffects.getGrassColorModifier());
if(colors.containsKey("grass")) {
effects.grassColorOverride(colors.get("grass"));
} else {
vanillaEffects.getGrassColorOverride().ifPresent(effects::grassColorOverride);
}
vanillaEffects.getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
if(colors.containsKey("foliage")) {
effects.foliageColorOverride(colors.get("foliage"));
} else {
vanillaEffects.getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
}
return new Biome.Builder()
.precipitation(vanilla.getPrecipitation())
.biomeCategory(vanilla.getBiomeCategory())
.depth(vanilla.getDepth())
.scale(vanilla.getScale())
.temperature(vanilla.getBaseTemperature())
.downfall(vanilla.getDownfall())
.specialEffects(effects.build())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(generationSettings.build())
.build().setRegistryName("terra", createBiomeID(template.getPack(), template.getID()));
}
public void setup() {
this.dataFolder = Paths.get("config", "Terra").toFile();
saveDefaultConfig();
config.load(this);
LangUtil.load(config.getLanguage(), this);
public void init() {
logger.info("Initializing Terra...");
if(!addonRegistry.loadAll()) {
@@ -271,15 +167,11 @@ public class TerraForgePlugin implements TerraPlugin {
logger.info("Loaded addons.");
registry.loadAll(this);
logger.info("Loaded packs.");
try {
CommandUtil.registerAll(manager);
} catch(MalformedCommandException e) {
e.printStackTrace(); // TODO do something here even though this should literally never happen
}
((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
@@ -289,12 +181,22 @@ 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) ((ForgeChunkGenerator) world.getGenerator()).getHandle()).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;
}
/**
* evil code brought to you by Forge Mod Loader
* <p>
* Forge changes the JAR URI to something that cannot
* be resolved back to the original JAR, so we have to
* do this to get our JAR.
*/
@Override
public JarFile getModJar() throws URISyntaxException, IOException {
File modsDir = new File("./mods");
@@ -311,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;
@@ -332,6 +228,11 @@ public class TerraForgePlugin implements TerraPlugin {
return dataFolder;
}
@Override
public boolean isDebug() {
return config.isDebug();
}
@Override
public Language getLanguage() {
return LangUtil.getLanguage();
@@ -352,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;
}
@@ -393,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) -> new ForgeBiome(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
@@ -406,28 +309,20 @@ public class TerraForgePlugin implements TerraPlugin {
return profiler;
}
@Mod.EventBusSubscriber(modid = "terra", bus = Mod.EventBusSubscriber.Bus.FORGE)
public static final class ForgeEvents {
@SuppressWarnings({"unchecked", "rawtypes"})
@SubscribeEvent
public static void registerCommands(RegisterCommandsEvent event) {
int max = INSTANCE.manager.getMaxArgumentDepth();
RequiredArgumentBuilder<CommandSource, String> arg = argument("arg" + (max - 1), StringArgumentType.word());
for(int i = 0; i < max; i++) {
RequiredArgumentBuilder<CommandSource, String> next = argument("arg" + (max - i - 1), StringArgumentType.word());
public CommandManager getManager() {
return manager;
}
arg = next.then(assemble(arg, INSTANCE.manager));
}
event.getDispatcher().register(literal("terra").executes(context -> 1).then((ArgumentBuilder) assemble(arg, INSTANCE.manager)));
event.getDispatcher().register(literal("te").executes(context -> 1).then((ArgumentBuilder) assemble(arg, INSTANCE.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;
@@ -463,43 +358,51 @@ 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);
}
private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) {
try {
registry.add(id, new ForgeTree(tree, id, TerraForgePlugin.getInstance()));
registry.add(id, (Tree) tree);
} catch(DuplicateEntryException ignore) {
}
}
}
@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
public static final class ClientEvents {
@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.registry.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);
}
});
public Map<ConfigPack, Pair<PreLoadCompatibilityOptions, PostLoadCompatibilityOptions>> getTemplates() {
return templates;
}
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.forge.world.block;
package com.dfsek.terra.forge.block;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
@@ -6,9 +6,8 @@ import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.block.state.ForgeBlockState;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldAccess;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.forge.ForgeAdapter;
import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
@@ -35,7 +34,7 @@ public class ForgeBlock implements Block {
@Override
public BlockState getState() {
return ForgeBlockState.newInstance(this);
return ForgeAdapter.adapt(this);
}
@Override
@@ -51,7 +50,7 @@ public class ForgeBlock implements Block {
@Override
public Location getLocation() {
return ForgeAdapter.adapt(delegate.position).toLocation(new ForgeWorldAccess(delegate.worldAccess));
return ForgeAdapter.adapt(delegate.position).toLocation((World) delegate.worldAccess);
}
@Override
@@ -1,8 +1,7 @@
package com.dfsek.terra.forge.world.block;
package com.dfsek.terra.forge.block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.forge.world.ForgeAdapter;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.state.Property;
@@ -39,7 +38,7 @@ public class ForgeBlockData implements BlockData {
@Override
public BlockType getBlockType() {
return ForgeAdapter.adapt(delegate.getBlock());
return (BlockType) delegate.getBlock();
}
@Override
@@ -1,7 +1,7 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.data.AnaloguePowerable;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.block.BlockState;
/**
@@ -1,9 +1,9 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Directional;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.ForgeAdapter;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.DirectionProperty;
@@ -1,4 +1,4 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.BlockFace;
@@ -1,12 +1,11 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.MultipleFacing;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
import java.util.HashSet;
import java.util.Set;
@@ -1,13 +1,12 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.data.Orientable;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.EnumProperty;
import net.minecraft.util.Direction;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
@@ -1,8 +1,8 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Rotatable;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
@@ -1,4 +1,4 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.data.Slab;
import net.minecraft.block.BlockState;
@@ -1,4 +1,4 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Stairs;
@@ -1,7 +1,7 @@
package com.dfsek.terra.forge.world.block.data;
package com.dfsek.terra.forge.block.data;
import com.dfsek.terra.api.platform.block.data.Waterlogged;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
@@ -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;
}
}
@@ -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;
}
}
@@ -1,37 +1,52 @@
package com.dfsek.terra.forge.world.generator;
package com.dfsek.terra.forge.generation;
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.forge.world.TerraBiomeSource;
import com.dfsek.terra.forge.world.handles.world.ForgeSeededWorldAccess;
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.Chunk;
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.gen.settings.StructureSpreadSettings;
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;
@@ -51,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;
@@ -77,50 +94,72 @@ 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;
}
@Override
public void createStructures(@NotNull DynamicRegistries p_242707_1_, @NotNull StructureManager p_242707_2_, @NotNull IChunk p_242707_3_, @NotNull TemplateManager p_242707_4_, long p_242707_5_) {
public void createStructures(@NotNull DynamicRegistries dynamicRegistries, @NotNull StructureManager manager, @NotNull IChunk chunk, @NotNull TemplateManager templateManager, long p_242707_5_) {
if(pack.getTemplate().vanillaStructures()) super.createStructures(dynamicRegistries, manager, chunk, templateManager, p_242707_5_);
}
@Override
public void applyCarvers(long p_230350_1_, @NotNull BiomeManager p_230350_3_, @NotNull IChunk p_230350_4_, GenerationStage.@NotNull Carving p_230350_5_) {
// No caves
public void applyCarvers(long p_230350_1_, @NotNull BiomeManager biomeManager, @NotNull IChunk chunk, GenerationStage.@NotNull Carving carving) {
if(pack.getTemplate().vanillaCaves()) super.applyCarvers(p_230350_1_, biomeManager, chunk, carving);
}
@Override
public void fillFromNoise(@NotNull IWorld world, @NotNull StructureManager p_230352_2_, @NotNull IChunk chunk) {
ForgeSeededWorldAccess worldAccess = new ForgeSeededWorldAccess(world, seed, this);
delegate.generateChunkData(worldAccess, new FastRandom(), chunk.getPos().x, chunk.getPos().z, new ForgeChunkData(chunk));
delegate.generateChunkData((World) world, new FastRandom(), chunk.getPos().x, chunk.getPos().z, (ChunkData) chunk);
}
@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();
@@ -133,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;
}
}
@@ -1,9 +1,7 @@
package com.dfsek.terra.forge.world.features;
package com.dfsek.terra.forge.generation;
import com.dfsek.terra.forge.world.generator.ForgeChunkGenerator;
import com.dfsek.terra.forge.world.generator.ForgeChunkGeneratorWrapper;
import com.dfsek.terra.forge.world.handles.ForgeWorld;
import com.dfsek.terra.forge.world.handles.chunk.ForgeChunkWorldAccess;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.mojang.serialization.Codec;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ISeedReader;
@@ -23,11 +21,9 @@ public class PopulatorFeature extends Feature<NoFeatureConfig> {
}
@Override
public boolean place(@NotNull ISeedReader world, @NotNull ChunkGenerator generator, @NotNull Random random, BlockPos pos, @NotNull NoFeatureConfig config) {
public boolean place(@NotNull ISeedReader world, @NotNull ChunkGenerator generator, @NotNull Random random, @NotNull BlockPos pos, @NotNull NoFeatureConfig config) {
ForgeChunkGeneratorWrapper gen = (ForgeChunkGeneratorWrapper) generator;
ForgeChunkWorldAccess chunk = new ForgeChunkWorldAccess(world, pos.getX() >> 4, pos.getZ() >> 4);
ForgeWorld world1 = new ForgeWorld(world.getLevel(), new ForgeChunkGenerator(generator));
gen.getHandle().getPopulators().forEach(populator -> populator.populate(world1, chunk));
gen.getHandle().getPopulators().forEach(populator -> populator.populate((World) world, (Chunk) world));
return true;
}
@@ -1,8 +1,9 @@
package com.dfsek.terra.forge.world;
package com.dfsek.terra.forge.generation;
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.forge.ForgeUtil;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@@ -51,6 +52,6 @@ public class TerraBiomeSource extends net.minecraft.world.biome.provider.BiomePr
@Override
public @NotNull Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) {
UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome(biomeX << 2, biomeZ << 2);
return Objects.requireNonNull(biomeRegistry.get(new ResourceLocation("terra", TerraForgePlugin.createBiomeID(pack, biome.getID()))));
return Objects.requireNonNull(biomeRegistry.get(new ResourceLocation("terra", ForgeUtil.createBiomeID(pack, biome.getID()))));
}
}
@@ -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);
}
}
@@ -1,14 +1,12 @@
package com.dfsek.terra.forge.inventory;
package com.dfsek.terra.forge.handle;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.inventory.Item;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.arguments.ItemArgument;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Set;
@@ -19,7 +17,7 @@ public class ForgeItemHandle implements ItemHandle {
@Override
public Item createItem(String data) {
try {
return ForgeAdapter.adapt(new ItemArgument().parse(new StringReader(data)).getItem());
return (Item) new ItemArgument().parse(new StringReader(data)).getItem();
} catch(CommandSyntaxException e) {
throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e);
}
@@ -27,11 +25,11 @@ public class ForgeItemHandle implements ItemHandle {
@Override
public Enchantment getEnchantment(String id) {
return ForgeAdapter.adapt(ForgeRegistries.ENCHANTMENTS.getValue(ResourceLocation.tryParse(id)));
return (Enchantment) ForgeRegistries.ENCHANTMENTS.getValue(ResourceLocation.tryParse(id));
}
@Override
public Set<Enchantment> getEnchantments() {
return ForgeRegistries.ENCHANTMENTS.getEntries().stream().map(entry -> ForgeAdapter.adapt(entry.getValue())).collect(Collectors.toSet());
return ForgeRegistries.ENCHANTMENTS.getEntries().stream().map(entry -> (Enchantment) entry.getValue()).collect(Collectors.toSet());
}
}
@@ -1,14 +1,14 @@
package com.dfsek.terra.forge.world;
package com.dfsek.terra.forge.handle;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.ForgeAdapter;
import com.dfsek.terra.forge.block.ForgeBlockData;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.BlockState;
import net.minecraft.command.arguments.BlockStateParser;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Locale;
@@ -31,6 +31,6 @@ public class ForgeWorldHandle implements WorldHandle {
public EntityType getEntity(String id) {
ResourceLocation identifier = ResourceLocation.tryParse(id);
if(identifier == null) identifier = ResourceLocation.tryParse("minecraft:" + id.toLowerCase(Locale.ROOT));
return ForgeAdapter.adapt(ForgeRegistries.ENTITIES.getValue(identifier));
return (EntityType) ForgeRegistries.ENTITIES.getValue(identifier);
}
}
@@ -1,42 +0,0 @@
package com.dfsek.terra.forge.inventory;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.forge.world.ForgeAdapter;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Objects;
public class ForgeEnchantment implements Enchantment {
private final net.minecraft.enchantment.Enchantment enchantment;
public ForgeEnchantment(net.minecraft.enchantment.Enchantment enchantment) {
this.enchantment = enchantment;
}
@Override
public net.minecraft.enchantment.Enchantment getHandle() {
return enchantment;
}
@Override
public boolean canEnchantItem(ItemStack itemStack) {
return enchantment.canEnchant(ForgeAdapter.adapt(itemStack));
}
@Override
public String getID() {
return Objects.requireNonNull(ForgeRegistries.ENCHANTMENTS.getKey(enchantment)).toString();
}
@Override
public boolean conflictsWith(Enchantment other) {
return !enchantment.isCompatibleWith(ForgeAdapter.adapt(other));
}
@Override
public int getMaxLevel() {
return enchantment.getMaxLevel();
}
}
@@ -1,36 +0,0 @@
package com.dfsek.terra.forge.inventory;
import com.dfsek.terra.api.platform.inventory.Inventory;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.forge.world.ForgeAdapter;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Items;
public class ForgeInventory implements Inventory {
private final net.minecraft.inventory.IInventory delegate;
public ForgeInventory(IInventory delegate) {
this.delegate = delegate;
}
@Override
public net.minecraft.inventory.IInventory getHandle() {
return delegate;
}
@Override
public int getSize() {
return delegate.getContainerSize();
}
@Override
public ItemStack getItem(int slot) {
net.minecraft.item.ItemStack itemStack = delegate.getItem(slot);
return itemStack.getItem() == Items.AIR ? null : ForgeAdapter.adapt(itemStack);
}
@Override
public void setItem(int slot, ItemStack newStack) {
delegate.setItem(slot, ForgeAdapter.adapt(newStack));
}
}
@@ -1,27 +0,0 @@
package com.dfsek.terra.forge.inventory;
import com.dfsek.terra.api.platform.inventory.Item;
import com.dfsek.terra.api.platform.inventory.ItemStack;
public class ForgeItem implements Item {
private final net.minecraft.item.Item delegate;
public ForgeItem(net.minecraft.item.Item delegate) {
this.delegate = delegate;
}
@Override
public net.minecraft.item.Item getHandle() {
return delegate;
}
@Override
public ItemStack newItemStack(int amount) {
return new ForgeItemStack(new net.minecraft.item.ItemStack(delegate, amount));
}
@Override
public double getMaxDurability() {
return delegate.getMaxDamage();
}
}
@@ -1,46 +0,0 @@
package com.dfsek.terra.forge.inventory;
import com.dfsek.terra.api.platform.inventory.Item;
import com.dfsek.terra.api.platform.inventory.ItemStack;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import com.dfsek.terra.forge.inventory.meta.ForgeDamageable;
import com.dfsek.terra.forge.inventory.meta.ForgeItemMeta;
public class ForgeItemStack implements ItemStack {
private net.minecraft.item.ItemStack delegate;
public ForgeItemStack(net.minecraft.item.ItemStack delegate) {
this.delegate = delegate;
}
@Override
public int getAmount() {
return delegate.getCount();
}
@Override
public void setAmount(int i) {
delegate.setCount(i);
}
@Override
public Item getType() {
return new ForgeItem(delegate.getItem());
}
@Override
public ItemMeta getItemMeta() {
if(delegate.isDamageableItem()) return new ForgeDamageable(delegate.copy());
return new ForgeItemMeta(delegate.copy());
}
@Override
public void setItemMeta(ItemMeta meta) {
this.delegate = ((ForgeItemMeta) meta).getHandle();
}
@Override
public net.minecraft.item.ItemStack getHandle() {
return delegate;
}
}
@@ -1,25 +0,0 @@
package com.dfsek.terra.forge.inventory.meta;
import com.dfsek.terra.api.platform.inventory.item.Damageable;
import net.minecraft.item.ItemStack;
public class ForgeDamageable extends ForgeItemMeta implements Damageable {
public ForgeDamageable(ItemStack delegate) {
super(delegate);
}
@Override
public int getDamage() {
return delegate.getDamageValue();
}
@Override
public void setDamage(int damage) {
delegate.setDamageValue(damage);
}
@Override
public boolean hasDamage() {
return delegate.isDamaged();
}
}
@@ -1,43 +0,0 @@
package com.dfsek.terra.forge.inventory.meta;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
import com.dfsek.terra.forge.world.ForgeAdapter;
import net.minecraft.command.arguments.NBTCompoundTagArgument;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.registry.Registry;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ForgeItemMeta implements ItemMeta {
protected final ItemStack delegate;
public ForgeItemMeta(ItemStack delegate) {
this.delegate = delegate;
}
@Override
public ItemStack getHandle() {
return delegate;
}
@Override
public Map<Enchantment, Integer> getEnchantments() {
if(!delegate.isEnchanted()) return Collections.emptyMap();
Map<Enchantment, Integer> map = new HashMap<>();
delegate.getEnchantmentTags().forEach(enchantment -> {
CompoundNBT eTag = (CompoundNBT) enchantment;
map.put(ForgeAdapter.adapt(Registry.ENCHANTMENT.byId(eTag.getInt("id"))), eTag.getInt("lvl"));
});
return map;
}
@Override
public void addEnchantment(Enchantment enchantment, int level) {
delegate.enchant(ForgeAdapter.adapt(enchantment), level);
}
}
@@ -0,0 +1,81 @@
package com.dfsek.terra.forge.listener;
import com.dfsek.terra.api.command.CommandManager;
import com.dfsek.terra.api.command.exception.CommandException;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;
@Mod.EventBusSubscriber(modid = "terra", bus = Mod.EventBusSubscriber.Bus.FORGE)
public class ForgeListener {
private static final TerraForgePlugin INSTANCE = TerraForgePlugin.getInstance();
@SuppressWarnings({"unchecked", "rawtypes"})
@SubscribeEvent
public static void registerCommands(RegisterCommandsEvent event) {
int max = INSTANCE.getManager().getMaxArgumentDepth();
RequiredArgumentBuilder<CommandSource, String> arg = argument("arg" + (max - 1), StringArgumentType.word());
for(int i = 0; i < max; i++) {
RequiredArgumentBuilder<CommandSource, String> next = argument("arg" + (max - i - 1), StringArgumentType.word());
arg = next.then(assemble(arg, INSTANCE.getManager()));
}
event.getDispatcher().register(literal("terra").executes(context -> 1).then((ArgumentBuilder) assemble(arg, INSTANCE.getManager())));
event.getDispatcher().register(literal("te").executes(context -> 1).then((ArgumentBuilder) assemble(arg, INSTANCE.getManager())));
}
public static RequiredArgumentBuilder<CommandSource, String> assemble(RequiredArgumentBuilder<CommandSource, String> in, CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrException();
} catch(CommandSyntaxException ignore) {
}
try {
manager.tabComplete(args.remove(0), sender, args).forEach(builder::suggest);
} catch(CommandException e) {
sender.sendMessage(e.getMessage());
}
return builder.buildFuture();
}).executes(context -> {
List<String> args = parseCommand(context.getInput());
try {
CommandSender sender = (CommandSender) context.getSource();
try {
sender = (Entity) context.getSource().getEntityOrException();
} catch(CommandSyntaxException ignore) {
}
manager.execute(args.remove(0), sender, args);
} catch(CommandException e) {
context.getSource().sendFailure(new StringTextComponent(e.getMessage()));
}
return 1;
});
}
private static List<String> parseCommand(String command) {
if(command.startsWith("/terra ")) command = command.substring("/terra ".length());
else if(command.startsWith("/te ")) command = command.substring("/te ".length());
List<String> c = new ArrayList<>(Arrays.asList(command.split(" ")));
if(command.endsWith(" ")) c.add("");
return c;
}
}
@@ -0,0 +1,15 @@
package com.dfsek.terra.forge.listener;
import com.dfsek.terra.forge.TerraForgePlugin;
import net.minecraft.world.gen.feature.Feature;
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 {
@SubscribeEvent
public static void registerPop(RegistryEvent.Register<Feature<?>> event) {
event.getRegistry().register(TerraForgePlugin.POPULATOR_FEATURE);
}
}
@@ -0,0 +1,64 @@
package com.dfsek.terra.forge.mixin;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper;
import com.dfsek.terra.forge.generation.TerraBiomeSource;
import com.google.common.base.MoreObjects;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.SimpleRegistry;
import net.minecraft.world.Dimension;
import net.minecraft.world.DimensionType;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.DimensionSettings;
import net.minecraft.world.gen.settings.DimensionGeneratorSettings;
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.CallbackInfoReturnable;
import java.util.Properties;
import java.util.Random;
@Mixin(DimensionGeneratorSettings.class)
public abstract class DimensionGeneratorSettingsMixin {
@Inject(method = "create(Lnet/minecraft/util/registry/DynamicRegistries;Ljava/util/Properties;)Lnet/minecraft/world/gen/settings/DimensionGeneratorSettings;", at = @At("HEAD"), cancellable = true)
private static void fromProperties(DynamicRegistries dynamicRegistries, Properties properties, CallbackInfoReturnable<DimensionGeneratorSettings> cir) {
if(properties.get("level-type") == null) {
return;
}
String prop = properties.get("level-type").toString().trim();
if(prop.startsWith("Terra")) {
String seed = (String) MoreObjects.firstNonNull(properties.get("level-seed"), "");
long l = new Random().nextLong();
if(!seed.isEmpty()) {
try {
long m = Long.parseLong(seed);
if(m != 0L) {
l = m;
}
} catch(NumberFormatException exception) {
l = seed.hashCode();
}
}
String generate_structures = (String) properties.get("generate-structures");
boolean generateStructures = generate_structures == null || Boolean.parseBoolean(generate_structures);
Registry<DimensionType> dimensionTypes = dynamicRegistries.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY);
Registry<Biome> biomes = dynamicRegistries.registryOrThrow(Registry.BIOME_REGISTRY);
Registry<DimensionSettings> chunkGeneratorSettings = dynamicRegistries.registryOrThrow(Registry.NOISE_GENERATOR_SETTINGS_REGISTRY);
SimpleRegistry<Dimension> dimensionOptions = DimensionType.defaultDimensions(dimensionTypes, biomes, chunkGeneratorSettings, l);
prop = prop.substring(prop.indexOf(":") + 1);
ConfigPack pack = TerraForgePlugin.getInstance().getConfigRegistry().get(prop);
if(pack == null) throw new IllegalArgumentException("No such pack " + prop);
TerraForgePlugin.getInstance().logger().info("Using config pack " + pack.getTemplate().getID());
cir.setReturnValue(new DimensionGeneratorSettings(l, generateStructures, false, DimensionGeneratorSettings.withOverworld(dimensionTypes, dimensionOptions, new ForgeChunkGeneratorWrapper(new TerraBiomeSource(biomes, l, pack), l, pack))));
}
}
}
@@ -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();
}
}
@@ -0,0 +1,12 @@
package com.dfsek.terra.forge.mixin.access;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.spawner.AbstractSpawner;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(AbstractSpawner.class)
public interface AbstractSpawnerAccessor {
@Invoker("getEntityId")
ResourceLocation callGetEntityId();
}
@@ -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);
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.forge.mixin.implementations;
import net.minecraft.world.biome.Biome;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Biome.class)
@Implements(@Interface(iface = com.dfsek.terra.api.platform.world.Biome.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class BiomeMixin {
public Object terra$getHandle() {
return this;
}
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.forge.mixin.implementations;
import net.minecraft.world.gen.ChunkGenerator;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(ChunkGenerator.class)
@Implements(@Interface(iface = com.dfsek.terra.api.platform.world.generator.ChunkGenerator.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class ChunkGeneratorMixin {
public Object terra$getHandle() {
return this;
}
}
@@ -0,0 +1,40 @@
package com.dfsek.terra.forge.mixin.implementations;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.profiler.ProfileFrame;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ISeedReader;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Random;
@Mixin(ConfiguredFeature.class)
@Implements(@Interface(iface = Tree.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class ConfiguredFeatureMixin {
@Shadow
public abstract boolean place(ISeedReader p_242765_1_, ChunkGenerator p_242765_2_, Random p_242765_3_, BlockPos p_242765_4_);
@SuppressWarnings({"try"})
public boolean terra$plant(Location l, Random r) {
try(ProfileFrame ignore = TerraForgePlugin.getInstance().getProfiler().profile("forge_tree")) {
ISeedReader world = ((ISeedReader) l.getWorld());
ChunkGenerator generatorWrapper = (ChunkGenerator) l.getWorld().getGenerator();
return place(world, generatorWrapper, r, new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()));
}
}
public MaterialSet terra$getSpawnable() {
return MaterialSet.get(TerraForgePlugin.getInstance().getWorldHandle().createBlockData("minecraft:grass_block"),
TerraForgePlugin.getInstance().getWorldHandle().createBlockData("minecraft:podzol"),
TerraForgePlugin.getInstance().getWorldHandle().createBlockData("minecraft:mycelium"));
}
}
@@ -0,0 +1,36 @@
package com.dfsek.terra.forge.mixin.implementations.block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.forge.ForgeAdapter;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(Block.class)
@Implements(@Interface(iface = BlockType.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class BlockMixin {
@Shadow
private BlockState defaultBlockState;
public Object terra$getHandle() {
return this;
}
public BlockData terra$getDefaultData() {
return ForgeAdapter.adapt(defaultBlockState);
}
public boolean terra$isSolid() {
return defaultBlockState.canOcclude();
}
@SuppressWarnings("ConstantConditions")
public boolean terra$isWater() {
return ((Object) this) == Blocks.WATER;
}
}
@@ -0,0 +1,63 @@
package com.dfsek.terra.forge.mixin.implementations.block;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.forge.ForgeAdapter;
import com.dfsek.terra.forge.block.ForgeBlock;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import javax.annotation.Nullable;
@Mixin(TileEntity.class)
@Implements(@Interface(iface = BlockState.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class TileEntityMixin {
@Shadow
protected BlockPos worldPosition;
@Shadow
@Nullable
protected World level;
@Shadow
@Nullable
private net.minecraft.block.BlockState blockState;
@Shadow
public abstract boolean hasLevel();
public Object terra$getHandle() {
return this;
}
public Block terra$getBlock() {
return new ForgeBlock(worldPosition, level);
}
public int terra$getX() {
return worldPosition.getX();
}
public int terra$getY() {
return worldPosition.getY();
}
public int terra$getZ() {
return worldPosition.getZ();
}
public BlockData terra$getBlockData() {
return ForgeAdapter.adapt(blockState);
}
public boolean terra$update(boolean applyPhysics) {
if(hasLevel()) level.getChunk(worldPosition).setBlockEntity(worldPosition, (TileEntity) (Object) this);
return true;
}
}
@@ -0,0 +1,21 @@
package com.dfsek.terra.forge.mixin.implementations.block.state;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.platform.inventory.Inventory;
import com.dfsek.terra.forge.mixin.implementations.block.TileEntityMixin;
import net.minecraft.tileentity.LockableLootTileEntity;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(LockableLootTileEntity.class)
@Implements(@Interface(iface = Container.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class LockableLootTileEntityMixin extends TileEntityMixin {
public Inventory terra$getInventory() {
return (Inventory) this;
}
public Object terra$getHandle() {
return this;
}
}
@@ -0,0 +1,120 @@
package com.dfsek.terra.forge.mixin.implementations.block.state;
import com.dfsek.terra.api.platform.block.state.MobSpawner;
import com.dfsek.terra.api.platform.block.state.SerialState;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.forge.TerraForgePlugin;
import com.dfsek.terra.forge.mixin.access.AbstractSpawnerAccessor;
import com.dfsek.terra.forge.mixin.implementations.block.TileEntityMixin;
import net.minecraft.tileentity.MobSpawnerTileEntity;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.spawner.AbstractSpawner;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(MobSpawnerTileEntity.class)
@Implements(@Interface(iface = MobSpawner.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class MobSpawnerTileEntityMixin extends TileEntityMixin {
@Shadow
public abstract AbstractSpawner getSpawner();
public EntityType terra$getSpawnedType() {
return (EntityType) Registry.ENTITY_TYPE.get(((AbstractSpawnerAccessor) getSpawner()).callGetEntityId());
}
public void terra$setSpawnedType(@NotNull EntityType creatureType) {
getSpawner().setEntityId((net.minecraft.entity.EntityType<?>) creatureType);
}
public int terra$getDelay() {
return 0;
}
public void terra$setDelay(int delay) {
}
public int terra$getMinSpawnDelay() {
return 0;
}
public void terra$setMinSpawnDelay(int delay) {
}
public int terra$getMaxSpawnDelay() {
return 0;
}
public void terra$setMaxSpawnDelay(int delay) {
}
public int terra$getSpawnCount() {
return 0;
}
public void terra$setSpawnCount(int spawnCount) {
}
public int terra$getMaxNearbyEntities() {
return 0;
}
public void terra$setMaxNearbyEntities(int maxNearbyEntities) {
}
public int terra$getRequiredPlayerRange() {
return 0;
}
public void terra$setRequiredPlayerRange(int requiredPlayerRange) {
}
public int terra$getSpawnRange() {
return 0;
}
public void terra$setSpawnRange(int spawnRange) {
}
public void terra$applyState(String state) {
SerialState.parse(state).forEach((k, v) -> {
switch(k) {
case "type":
terra$setSpawnedType(TerraForgePlugin.getInstance().getWorldHandle().getEntity(v));
return;
case "delay":
terra$setDelay(Integer.parseInt(v));
return;
case "min_delay":
terra$setMinSpawnDelay(Integer.parseInt(v));
return;
case "max_delay":
terra$setMaxSpawnDelay(Integer.parseInt(v));
return;
case "spawn_count":
terra$setSpawnCount(Integer.parseInt(v));
return;
case "spawn_range":
terra$setSpawnRange(Integer.parseInt(v));
return;
case "max_nearby":
terra$setMaxNearbyEntities(Integer.parseInt(v));
return;
case "required_player_range":
terra$setRequiredPlayerRange(Integer.parseInt(v));
return;
default:
throw new IllegalArgumentException("Invalid property: " + k);
}
});
}
}
@@ -0,0 +1,48 @@
package com.dfsek.terra.forge.mixin.implementations.block.state;
import com.dfsek.terra.api.platform.block.state.SerialState;
import com.dfsek.terra.api.platform.block.state.Sign;
import net.minecraft.tileentity.SignTileEntity;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(SignTileEntity.class)
@Implements(@Interface(iface = Sign.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class SignTileEntityMixin {
@Shadow
@Final
private ITextComponent[] messages;
@Shadow
public abstract void setMessage(int p_212365_1_, ITextComponent p_212365_2_);
public @NotNull String[] terra$getLines() {
String[] lines = new String[messages.length];
for(int i = 0; i < messages.length; i++) {
lines[i] = messages[i].getString();
}
return lines;
}
public @NotNull String terra$getLine(int index) throws IndexOutOfBoundsException {
return messages[index].getString();
}
public void terra$setLine(int index, @NotNull String line) throws IndexOutOfBoundsException {
setMessage(index, new StringTextComponent(line));
}
public void terra$applyState(String state) {
SerialState.parse(state).forEach((k, v) -> {
if(!k.startsWith("text")) throw new IllegalArgumentException("Invalid property: " + k);
terra$setLine(Integer.parseInt(k.substring(4)), v);
});
}
}
@@ -0,0 +1,54 @@
package com.dfsek.terra.forge.mixin.implementations.chunk;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.forge.block.ForgeBlock;
import com.dfsek.terra.forge.block.ForgeBlockData;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.IChunk;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(net.minecraft.world.chunk.Chunk.class)
@Implements(@Interface(iface = Chunk.class, prefix = "terra$", remap = Interface.Remap.NONE))
public abstract class ChunkMixin {
@Shadow
@Final
private net.minecraft.world.World level;
public int terra$getX() {
return ((IChunk) this).getPos().x;
}
public int terra$getZ() {
return ((IChunk) this).getPos().z;
}
public World terra$getWorld() {
return (World) level;
}
public Block terra$getBlock(int x, int y, int z) {
BlockPos pos = new BlockPos(x + (terra$getX() << 4), y, z + (terra$getZ() << 4));
return new ForgeBlock(pos, level);
}
public @NotNull BlockData terra$getBlockData(int x, int y, int z) {
return terra$getBlock(x, y, z).getBlockData();
}
public void terra$setBlock(int x, int y, int z, @NotNull BlockData blockData) {
((IChunk) this).setBlockState(new BlockPos(x, y, z), ((ForgeBlockData) blockData).getHandle(), false);
}
public Object terra$getHandle() {
return this;
}
}

Some files were not shown because too many files have changed in this diff Show More