Pack loading on Forge

This commit is contained in:
dfsek 2021-04-29 20:30:48 -07:00
parent 93a2f103f7
commit 9f3dcf07b6
44 changed files with 2744 additions and 36 deletions

View File

@ -3,93 +3,243 @@ package com.dfsek.terra.forge;
import com.dfsek.tectonic.loading.TypeRegistry;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.addons.annotations.Addon;
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.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.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.platform.block.BlockData;
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.util.logging.DebugLogger;
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.ForgeBiome;
import com.dfsek.terra.forge.world.ForgeTree;
import com.dfsek.terra.forge.world.ForgeWorldHandle;
import com.dfsek.terra.forge.world.TerraBiomeSource;
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.profiler.Profiler;
import com.dfsek.terra.profiler.ProfilerImpl;
import com.dfsek.terra.registry.exception.DuplicateEntryException;
import com.dfsek.terra.registry.master.AddonRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.world.TerraWorld;
import net.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.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.biome.Biome;
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.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.client.ForgeWorldTypeScreens;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.world.ForgeWorldType;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@Mod("terra")
@Mod.EventBusSubscriber(modid = "terra", bus = Mod.EventBusSubscriber.Bus.MOD)
public class TerraForgePlugin implements TerraPlugin {
private final GenericLoaders genericLoaders = new GenericLoaders(this);
private static final Logger LOGGER = LogManager.getLogger();
public static final PopulatorFeature POPULATOR_FEATURE = new PopulatorFeature(NoFeatureConfig.CODEC);
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 EventManager eventManager = new TerraEventManager(this);
private final GenericLoaders genericLoaders = new GenericLoaders(this);
private final Profiler profiler = new ProfilerImpl();
private final com.dfsek.terra.api.util.logging.Logger logger = new com.dfsek.terra.api.util.logging.Logger() {
private final org.apache.logging.log4j.Logger logger = LogManager.getLogger();
@Override
public void info(String message) {
logger.info(message);
}
@Override
public void warning(String message) {
logger.warn(message);
}
@Override
public void severe(String message) {
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 FabricAddon(this), 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;
public TerraForgePlugin() {
if(INSTANCE != null) throw new IllegalStateException("Only one TerraPlugin instance may exist.");
INSTANCE = this;
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(this::setup);
MinecraftForge.EVENT_BUS.register(this);
}
public void setup(final FMLCommonSetupEvent event) {
logger().info("Initializing...");
public static TerraForgePlugin getInstance() {
return INSTANCE;
}
@Override
public void register(TypeRegistry registry) {
genericLoaders.register(registry);
public static String createBiomeID(ConfigPack pack, String biomeID) {
return pack.getTemplate().getID().toLowerCase() + "/" + biomeID.toLowerCase(Locale.ROOT);
}
@SubscribeEvent
public static void register(RegistryEvent.Register<Biome> event) {
INSTANCE.registry.forEach(pack -> pack.getBiomeRegistry().forEach((id, biome) -> event.getRegistry().register(createBiome(biome)))); // Register all Terra biomes.
}
public void setup(final FMLCommonSetupEvent event) {
this.dataFolder = Paths.get("config", "Terra").toFile();
saveDefaultConfig();
config.load(this);
LangUtil.load(config.getLanguage(), this);
logger.info("Initializing Terra...");
if(!addonRegistry.loadAll()) {
throw new IllegalStateException("Failed to load addons. Please correct addon installations to continue.");
}
logger.info("Loaded addons.");
registry.loadAll(this);
logger.info("Loaded packs.");
Registry.register(Registry.CHUNK_GENERATOR, new ResourceLocation("terra:terra"), ForgeChunkGeneratorWrapper.CODEC);
Registry.register(Registry.BIOME_SOURCE, new ResourceLocation("terra:terra"), TerraBiomeSource.CODEC);
registry.forEach(configPack -> {
ForgeWorldType world = new ForgeWorldType(new TerraLevelType(configPack)).setRegistryName("terra", configPack.getTemplate().getID().toLowerCase(Locale.ROOT));
ForgeWorldTypeScreens.registerFactory(world, (returnTo, dimensionGeneratorSettings) -> new Screen(world.getDisplayName()) {
@Override
protected void init() {
addButton(new Button(0, 0, 120, 20, new StringTextComponent("close"), btn -> Minecraft.getInstance().setScreen(returnTo)));
}
});
});
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));
}
);
*/
}
@Override
public WorldHandle getWorldHandle() {
return null;
return worldHandle;
}
@Override
public TerraWorld getWorld(World world) {
return null;
return worldMap.computeIfAbsent(world.getSeed(), w -> {
logger.info("Loading world " + w);
return new TerraWorld(world, ((ForgeChunkGeneratorWrapper) ((ForgeChunkGenerator) world.getGenerator()).getHandle()).getPack(), this);
});
}
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 new com.dfsek.terra.api.util.logging.Logger() {
@Override
public void info(String message) {
LOGGER.info(message);
}
@Override
public void warning(String message) {
LOGGER.warn(message);
}
@Override
public void severe(String message) {
LOGGER.error(message);
}
};
return logger;
}
@Override
public PluginConfig getTerraConfig() {
return null;
return config;
}
@Override
public File getDataFolder() {
return null;
return dataFolder;
}
@Override
@ -99,44 +249,148 @@ public class TerraForgePlugin implements TerraPlugin {
@Override
public Language getLanguage() {
return null;
return LangUtil.getLanguage();
}
@Override
public CheckedRegistry<ConfigPack> getConfigRegistry() {
return null;
return checkedRegistry;
}
@Override
public LockedRegistry<TerraAddon> getAddons() {
return null;
return addonLockedRegistry;
}
@Override
public boolean reload() {
return false;
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.clear();
worldMap.putAll(newMap);
return succeed;
}
@Override
public ItemHandle getItemHandle() {
return null;
return itemHandle;
}
@Override
public void saveDefaultConfig() {
try(InputStream stream = getClass().getResourceAsStream("/config.yml")) {
File configFile = new File(getDataFolder(), "config.yml");
if(!configFile.exists()) FileUtils.copyInputStreamToFile(stream, configFile);
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public String platformName() {
return null;
return "Fabric";
}
@Override
public DebugLogger getDebugLogger() {
return new DebugLogger(logger());
return debugLogger;
}
@Override
public void register(TypeRegistry registry) {
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)));
}
private static 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.Builder effects = new BiomeAmbience.Builder()
.waterColor(colors.getOrDefault("water", vanilla.getSpecialEffects().waterColor))
.waterFogColor(colors.getOrDefault("water-fog", vanilla.getSpecialEffects().waterFogColor))
.fogColor(colors.getOrDefault("fog", vanilla.getSpecialEffects().fogColor))
.skyColor(colors.getOrDefault("sky", vanilla.getSpecialEffects().skyColor))
.grassColorModifier(vanilla.getSpecialEffects().grassColorModifier);
if(colors.containsKey("grass")) {
effects.grassColorOverride(colors.get("grass"));
} else {
vanilla.getSpecialEffects().grassColor.ifPresent(effects::grassColor);
}
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
if(colors.containsKey("foliage")) {
effects.foliageColor(colors.get("foliage"));
} else {
vanilla.getEffects().foliageColor.ifPresent(effects::foliageColor);
}
*/
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())
.specialEffects(vanilla.getSpecialEffects())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(generationSettings.build())
.build();
}
/*
private RequiredArgumentBuilder<ServerCommandSource, String> assemble(RequiredArgumentBuilder<ServerCommandSource, String> in, CommandManager manager) {
return in.suggests((context, builder) -> {
List<String> args = parseCommand(context.getInput());
CommandSender sender = FabricAdapter.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), FabricAdapter.adapt(context.getSource()), 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;
}
*/
@Override
public EventManager getEventManager() {
return eventManager;
@ -146,4 +400,54 @@ public class TerraForgePlugin implements TerraPlugin {
public Profiler getProfiler() {
return profiler;
}
@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;
}
@Override
public void initialize() {
main.getEventManager().registerListener(this, this);
}
@Priority(Priority.LOWEST)
@Global
public void injectTrees(ConfigPackPreLoadEvent event) {
CheckedRegistry<Tree> treeRegistry = event.getPack().getTreeRegistry();
injectTree(treeRegistry, "BROWN_MUSHROOM", Features.HUGE_BROWN_MUSHROOM);
injectTree(treeRegistry, "RED_MUSHROOM", Features.HUGE_RED_MUSHROOM);
injectTree(treeRegistry, "JUNGLE", Features.MEGA_JUNGLE_TREE);
injectTree(treeRegistry, "JUNGLE_COCOA", Features.JUNGLE_TREE);
injectTree(treeRegistry, "LARGE_OAK", Features.FANCY_OAK);
injectTree(treeRegistry, "LARGE_SPRUCE", Features.PINE);
injectTree(treeRegistry, "SMALL_JUNGLE", Features.JUNGLE_TREE);
injectTree(treeRegistry, "SWAMP_OAK", Features.SWAMP_TREE);
injectTree(treeRegistry, "TALL_BIRCH", Features.BIRCH_TALL);
injectTree(treeRegistry, "ACACIA", Features.ACACIA);
injectTree(treeRegistry, "BIRCH", Features.BIRCH);
injectTree(treeRegistry, "DARK_OAK", Features.DARK_OAK);
injectTree(treeRegistry, "OAK", Features.OAK);
injectTree(treeRegistry, "CHORUS_PLANT", Features.CHORUS_PLANT);
injectTree(treeRegistry, "SPRUCE", Features.SPRUCE);
injectTree(treeRegistry, "JUNGLE_BUSH", Features.JUNGLE_BUSH);
injectTree(treeRegistry, "MEGA_SPRUCE", Features.MEGA_SPRUCE);
injectTree(treeRegistry, "CRIMSON_FUNGUS", Features.CRIMSON_FUNGI);
injectTree(treeRegistry, "WARPED_FUNGUS", Features.WARPED_FUNGI);
}
private void injectTree(CheckedRegistry<Tree> registry, String id, ConfiguredFeature<?, ?> tree) {
try {
registry.add(id, new ForgeTree(tree, id, TerraForgePlugin.getInstance()));
} catch(DuplicateEntryException ignore) {
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.dfsek.terra.forge;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.forge.world.TerraBiomeSource;
import com.dfsek.terra.forge.world.generator.ForgeChunkGeneratorWrapper;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.DimensionSettings;
import net.minecraftforge.common.world.ForgeWorldType;
public class TerraLevelType implements ForgeWorldType.IChunkGeneratorFactory {
private final ConfigPack pack;
public TerraLevelType(ConfigPack pack) {
this.pack = pack;
}
@Override
public ChunkGenerator createChunkGenerator(Registry<Biome> biomeRegistry, Registry<DimensionSettings> dimensionSettingsRegistry, long seed, String generatorSettings) {
return new ForgeChunkGeneratorWrapper(new TerraBiomeSource(biomeRegistry, seed, pack), seed, pack);
}
}

View File

@ -0,0 +1,41 @@
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 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(Registry.ENCHANTMENT.getKey(enchantment)).toString();
}
@Override
public boolean conflictsWith(Enchantment other) {
return !enchantment.isCompatibleWith(ForgeAdapter.adapt(other));
}
@Override
public int getMaxLevel() {
return enchantment.getMaxLevel();
}
}

View File

@ -0,0 +1,36 @@
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));
}
}

View File

@ -0,0 +1,27 @@
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();
}
}

View File

@ -0,0 +1,36 @@
package com.dfsek.terra.forge.inventory;
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 java.util.Set;
import java.util.stream.Collectors;
public class ForgeItemHandle implements ItemHandle {
@Override
public Item createItem(String data) {
try {
return ForgeAdapter.adapt(new ItemArgument().parse(new StringReader(data)).getItem());
} catch(CommandSyntaxException e) {
throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e);
}
}
@Override
public Enchantment getEnchantment(String id) {
return ForgeAdapter.adapt(Registry.ENCHANTMENT.get(ResourceLocation.tryParse(id)));
}
@Override
public Set<Enchantment> getEnchantments() {
return Registry.ENCHANTMENT.stream().map(ForgeAdapter::adapt).collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,46 @@
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;
}
}

View File

@ -0,0 +1,25 @@
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();
}
}

View File

@ -0,0 +1,43 @@
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);
}
}

View File

@ -0,0 +1,128 @@
package com.dfsek.terra.forge.world;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
import com.dfsek.terra.forge.inventory.ForgeEnchantment;
import com.dfsek.terra.forge.inventory.ForgeItem;
import com.dfsek.terra.forge.inventory.ForgeItemStack;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.world.block.ForgeBlockType;
import com.dfsek.terra.forge.world.block.data.ForgeDirectional;
import com.dfsek.terra.forge.world.block.data.ForgeMultipleFacing;
import com.dfsek.terra.forge.world.block.data.ForgeOrientable;
import com.dfsek.terra.forge.world.block.data.ForgeRotatable;
import com.dfsek.terra.forge.world.block.data.ForgeSlab;
import com.dfsek.terra.forge.world.block.data.ForgeStairs;
import com.dfsek.terra.forge.world.block.data.ForgeWaterlogged;
import com.dfsek.terra.forge.world.entity.ForgeCommandSender;
import com.dfsek.terra.forge.world.entity.ForgeEntityType;
import com.dfsek.terra.forge.world.entity.ForgePlayer;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldHandle;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.command.CommandSource;
import net.minecraft.command.ICommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.state.properties.BlockStateProperties;
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 CommandSender adapt(CommandSource serverCommandSource) {
if(serverCommandSource.getEntity() instanceof PlayerEntity) return new ForgePlayer((PlayerEntity) serverCommandSource.getEntity());
return new ForgeCommandSender(serverCommandSource);
}
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);
}
}
public static BlockType adapt(Block block) {
return new ForgeBlockType(block);
}
public static EntityType adapt(net.minecraft.entity.EntityType<?> entityType) {
return new ForgeEntityType(entityType);
}
public static net.minecraft.entity.EntityType<? extends Entity> adapt(EntityType entityType) {
return ((ForgeEntityType) entityType).getHandle();
}
public static ItemStack adapt(com.dfsek.terra.api.platform.inventory.ItemStack itemStack) {
return ((ForgeItemStack) itemStack).getHandle();
}
public static com.dfsek.terra.api.platform.inventory.ItemStack adapt(ItemStack itemStack) {
return new ForgeItemStack(itemStack);
}
public static com.dfsek.terra.api.platform.inventory.Item adapt(Item item) {
return new ForgeItem(item);
}
public static Enchantment adapt(net.minecraft.enchantment.Enchantment enchantment) {
return new ForgeEnchantment(enchantment);
}
public static net.minecraft.enchantment.Enchantment adapt(Enchantment enchantment) {
return ((ForgeEnchantment) enchantment).getHandle();
}
public IWorld adapt(ForgeWorldHandle worldHandle) {
return worldHandle.getWorld();
}
}

View File

@ -0,0 +1,17 @@
package com.dfsek.terra.forge.world;
import com.dfsek.terra.api.platform.world.Biome;
public class ForgeBiome implements Biome {
private final net.minecraft.world.biome.Biome delegate;
public ForgeBiome(net.minecraft.world.biome.Biome delegate) {
this.delegate = delegate;
}
@Override
public net.minecraft.world.biome.Biome getHandle() {
return delegate;
}
}

View File

@ -0,0 +1,44 @@
package com.dfsek.terra.forge.world;
import com.dfsek.terra.api.TerraPlugin;
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.world.generator.ForgeChunkGenerator;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldAccess;
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 java.util.Locale;
import java.util.Random;
public class ForgeTree implements Tree {
private final ConfiguredFeature<?, ?> delegate;
private final String id;
private final TerraPlugin main;
public ForgeTree(ConfiguredFeature<?, ?> delegate, String id, TerraPlugin main) {
this.delegate = delegate;
this.id = id;
this.main = main;
}
@Override
public boolean plant(Location l, Random r) {
try(ProfileFrame ignore = main.getProfiler().profile("fabric_tree:" + id.toLowerCase(Locale.ROOT))) {
ForgeWorldAccess fabricWorldAccess = ((ForgeWorldAccess) l.getWorld());
ChunkGenerator generatorWrapper = ((ForgeChunkGenerator) fabricWorldAccess.getGenerator()).getHandle();
return delegate.place((ISeedReader) fabricWorldAccess.getHandle(), generatorWrapper, r, new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()));
}
}
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:grass_block"),
main.getWorldHandle().createBlockData("minecraft:podzol"),
main.getWorldHandle().createBlockData("minecraft:mycelium"));
}
}

View File

@ -0,0 +1,35 @@
package com.dfsek.terra.forge.world;
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.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 java.util.Locale;
public class ForgeWorldHandle implements WorldHandle {
@Override
public ForgeBlockData createBlockData(String data) {
BlockStateParser parser = new BlockStateParser(new StringReader(data), true);
try {
BlockState state = parser.parse(true).getState();
if(state == null) throw new IllegalArgumentException("Invalid data: " + data);
return ForgeAdapter.adapt(state);
} catch(CommandSyntaxException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public EntityType getEntity(String id) {
ResourceLocation identifier = ResourceLocation.tryParse(id);
if(identifier == null) identifier = ResourceLocation.tryParse("minecraft:" + id.toLowerCase(Locale.ROOT));
return ForgeAdapter.adapt(Registry.ENTITY_TYPE.get(identifier));
}
}

View File

@ -0,0 +1,57 @@
package com.dfsek.terra.forge.world;
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.TerraForgePlugin;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryLookupCodec;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.StructureFeature;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.stream.Collectors;
public class TerraBiomeSource extends net.minecraft.world.biome.provider.BiomeProvider {
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(TerraForgePlugin.getInstance().getConfigRegistry()::get))));
public static final Codec<TerraBiomeSource> CODEC = RecordCodecBuilder.create(instance -> instance.group(
RegistryLookupCodec.create(Registry.BIOME_REGISTRY).forGetter(source -> source.biomeRegistry),
Codec.LONG.fieldOf("seed").stable().forGetter(source -> source.seed),
PACK_CODEC.fieldOf("pack").stable().forGetter(source -> source.pack))
.apply(instance, instance.stable(TerraBiomeSource::new)));
private final Registry<Biome> biomeRegistry;
private final long seed;
private final BiomeProvider grid;
private final ConfigPack pack;
public TerraBiomeSource(Registry<Biome> biomes, long seed, ConfigPack pack) {
super(biomes.stream().collect(Collectors.toList()));
this.biomeRegistry = biomes;
this.seed = seed;
this.grid = pack.getBiomeProviderBuilder().build(seed);
this.pack = pack;
}
@Override
protected @NotNull Codec<? extends net.minecraft.world.biome.provider.BiomeProvider> codec() {
return CODEC;
}
@Override
public net.minecraft.world.biome.provider.@NotNull BiomeProvider withSeed(long seed) {
return new TerraBiomeSource(this.biomeRegistry, seed, pack);
}
@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()))));
}
}

View File

@ -0,0 +1,96 @@
package com.dfsek.terra.forge.world.block;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
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 net.minecraft.block.FlowingFluidBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
public class ForgeBlock implements Block {
private final Handle delegate;
public ForgeBlock(BlockPos position, IWorld worldAccess) {
this.delegate = new Handle(position, worldAccess);
}
@Override
public void setBlockData(BlockData data, boolean physics) {
delegate.worldAccess.setBlock(delegate.position, ((ForgeBlockData) data).getHandle(), physics ? 3 : 1042);
if(physics && ((ForgeBlockData) data).getHandle().getBlock() instanceof FlowingFluidBlock) {
delegate.worldAccess.getLiquidTicks().scheduleTick(delegate.position, ((FlowingFluidBlock) ((ForgeBlockData) data).getHandle().getBlock()).getFluidState(((ForgeBlockData) data).getHandle()).getFluidState().getType(), 0);
}
}
@Override
public BlockData getBlockData() {
return new ForgeBlockData(delegate.worldAccess.getBlockState(delegate.position));
}
@Override
public BlockState getState() {
return ForgeBlockState.newInstance(this);
}
@Override
public Block getRelative(BlockFace face, int len) {
BlockPos newPos = delegate.position.offset(face.getModX() * len, face.getModY() * len, face.getModZ() * len);
return new ForgeBlock(newPos, delegate.worldAccess);
}
@Override
public boolean isEmpty() {
return getBlockData().isAir();
}
@Override
public Location getLocation() {
return ForgeAdapter.adapt(delegate.position).toLocation(new ForgeWorldAccess(delegate.worldAccess));
}
@Override
public BlockType getType() {
return getBlockData().getBlockType();
}
@Override
public int getX() {
return delegate.position.getX();
}
@Override
public int getZ() {
return delegate.position.getZ();
}
@Override
public int getY() {
return delegate.position.getY();
}
@Override
public boolean isPassable() {
return isEmpty();
}
@Override
public Handle getHandle() {
return delegate;
}
public static final class Handle {
private final BlockPos position;
private final IWorld worldAccess;
public Handle(BlockPos position, IWorld worldAccess) {
this.position = position;
this.worldAccess = worldAccess;
}
}
}

View File

@ -0,0 +1,64 @@
package com.dfsek.terra.forge.world.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;
public class ForgeBlockData implements BlockData {
protected BlockState delegate;
public ForgeBlockData(BlockState delegate) {
this.delegate = delegate;
}
@Override
public BlockType getBlockType() {
return ForgeAdapter.adapt(delegate.getBlock());
}
@Override
public boolean matches(BlockData other) {
return delegate.getBlock() == ((ForgeBlockData) other).delegate.getBlock();
}
@Override
public BlockData clone() {
try {
return (ForgeBlockData) super.clone();
} catch(CloneNotSupportedException e) {
throw new Error(e);
}
}
@Override
public String getAsString() {
/*
StringBuilder data = new StringBuilder(Registry.BLOCK.getId(delegate.getBlock()).toString());
if(!delegate.getProperties().isEmpty()) {
data.append('[');
data.append(delegate.getProperties().stream().map(State.PROPERTY_MAP_PRINTER).collect(Collectors.joining(",")));
data.append(']');
}
return data.toString();
*/
throw new UnsupportedOperationException("TODO: implement this"); // TODO
}
@Override
public boolean isAir() {
return delegate.isAir();
}
@Override
public boolean isStructureVoid() {
return delegate.getBlock() == Blocks.STRUCTURE_VOID;
}
@Override
public BlockState getHandle() {
return delegate;
}
}

View File

@ -0,0 +1,46 @@
package com.dfsek.terra.forge.world.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.Block;
import net.minecraft.block.Blocks;
public class ForgeBlockType implements BlockType {
private final Block delegate;
public ForgeBlockType(Block delegate) {
this.delegate = delegate;
}
@Override
public Block getHandle() {
return delegate;
}
@Override
public BlockData getDefaultData() {
return ForgeAdapter.adapt(delegate.defaultBlockState());
}
@Override
public boolean isSolid() {
return delegate.defaultBlockState().canOcclude();
}
@Override
public boolean isWater() {
return delegate == Blocks.WATER;
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof ForgeBlockType)) return false;
return ((ForgeBlockType) obj).delegate == delegate;
}
}

View File

@ -0,0 +1,29 @@
package com.dfsek.terra.forge.world.block.data;
import com.dfsek.terra.api.platform.block.data.AnaloguePowerable;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import net.minecraft.block.BlockState;
/**
* None of this actually has implementation, TODO: implement this if we ever end up needing it.
*/
public class ForgeAnaloguePowerable extends ForgeBlockData implements AnaloguePowerable {
public ForgeAnaloguePowerable(BlockState delegate) {
super(delegate);
}
@Override
public int getMaximumPower() {
return 0;
}
@Override
public int getPower() {
return 0;
}
@Override
public void setPower(int power) {
}
}

View File

@ -0,0 +1,42 @@
package com.dfsek.terra.forge.world.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 net.minecraft.block.BlockState;
import net.minecraft.state.DirectionProperty;
public class ForgeDirectional extends ForgeBlockData implements Directional {
private final DirectionProperty property;
public ForgeDirectional(BlockState delegate, DirectionProperty property) {
super(delegate);
this.property = property;
}
@Override
public BlockFace getFacing() {
switch(delegate.getValue(property)) {
case SOUTH:
return BlockFace.SOUTH;
case DOWN:
return BlockFace.DOWN;
case UP:
return BlockFace.UP;
case EAST:
return BlockFace.EAST;
case WEST:
return BlockFace.WEST;
case NORTH:
return BlockFace.NORTH;
default:
throw new IllegalStateException();
}
}
@Override
public void setFacing(BlockFace facing) {
delegate = delegate.setValue(property, ForgeAdapter.adapt(facing));
}
}

View File

@ -0,0 +1,159 @@
package com.dfsek.terra.forge.world.block.data;
import com.dfsek.terra.api.platform.block.Axis;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Bisected;
import com.dfsek.terra.api.platform.block.data.Slab;
import com.dfsek.terra.api.platform.block.data.Stairs;
import net.minecraft.state.properties.Half;
import net.minecraft.state.properties.SlabType;
import net.minecraft.state.properties.StairsShape;
import net.minecraft.util.Direction;
public final class ForgeEnumAdapter {
public static Stairs.Shape adapt(StairsShape shape) {
switch(shape) {
case OUTER_RIGHT:
return Stairs.Shape.OUTER_RIGHT;
case INNER_RIGHT:
return Stairs.Shape.INNER_RIGHT;
case OUTER_LEFT:
return Stairs.Shape.OUTER_LEFT;
case INNER_LEFT:
return Stairs.Shape.INNER_LEFT;
case STRAIGHT:
return Stairs.Shape.STRAIGHT;
default:
throw new IllegalStateException();
}
}
public static Bisected.Half adapt(Half half) {
switch(half) {
case BOTTOM:
return Bisected.Half.BOTTOM;
case TOP:
return Bisected.Half.TOP;
default:
throw new IllegalStateException();
}
}
public static BlockFace adapt(Direction direction) {
switch(direction) {
case DOWN:
return BlockFace.DOWN;
case UP:
return BlockFace.UP;
case WEST:
return BlockFace.WEST;
case EAST:
return BlockFace.EAST;
case NORTH:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.SOUTH;
default:
throw new IllegalStateException();
}
}
public static Slab.Type adapt(SlabType type) {
switch(type) {
case BOTTOM:
return Slab.Type.BOTTOM;
case TOP:
return Slab.Type.TOP;
case DOUBLE:
return Slab.Type.DOUBLE;
default:
throw new IllegalStateException();
}
}
public static StairsShape adapt(Stairs.Shape shape) {
switch(shape) {
case STRAIGHT:
return StairsShape.STRAIGHT;
case INNER_LEFT:
return StairsShape.INNER_LEFT;
case OUTER_LEFT:
return StairsShape.OUTER_LEFT;
case INNER_RIGHT:
return StairsShape.INNER_RIGHT;
case OUTER_RIGHT:
return StairsShape.OUTER_RIGHT;
default:
throw new IllegalStateException();
}
}
public static Half adapt(Bisected.Half half) {
switch(half) {
case TOP:
return Half.TOP;
case BOTTOM:
return Half.BOTTOM;
default:
throw new IllegalStateException();
}
}
public static Direction adapt(BlockFace face) {
switch(face) {
case SOUTH:
return Direction.SOUTH;
case NORTH:
return Direction.NORTH;
case EAST:
return Direction.EAST;
case WEST:
return Direction.WEST;
case UP:
return Direction.UP;
case DOWN:
return Direction.DOWN;
default:
throw new IllegalArgumentException();
}
}
public static SlabType adapt(Slab.Type type) {
switch(type) {
case DOUBLE:
return SlabType.DOUBLE;
case TOP:
return SlabType.TOP;
case BOTTOM:
return SlabType.BOTTOM;
default:
throw new IllegalStateException();
}
}
public static Axis adapt(Direction.Axis axis) {
switch(axis) {
case X:
return Axis.X;
case Y:
return Axis.Y;
case Z:
return Axis.Z;
default:
throw new IllegalStateException();
}
}
public static Direction.Axis adapt(Axis axis) {
switch(axis) {
case Z:
return Direction.Axis.Z;
case Y:
return Direction.Axis.Y;
case X:
return Direction.Axis.X;
default:
throw new IllegalStateException();
}
}
}

View File

@ -0,0 +1,70 @@
package com.dfsek.terra.forge.world.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 net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
import java.util.HashSet;
import java.util.Set;
public class ForgeMultipleFacing extends ForgeBlockData implements MultipleFacing {
public ForgeMultipleFacing(BlockState delegate) {
super(delegate);
}
@Override
public Set<BlockFace> getFaces() {
Set<BlockFace> set = new HashSet<>();
if(delegate.getValue(BlockStateProperties.NORTH)) set.add(BlockFace.NORTH);
if(delegate.getValue(BlockStateProperties.SOUTH)) set.add(BlockFace.SOUTH);
if(delegate.getValue(BlockStateProperties.EAST)) set.add(BlockFace.EAST);
if(delegate.getValue(BlockStateProperties.WEST)) set.add(BlockFace.WEST);
if(delegate.hasProperty(BlockStateProperties.UP) && delegate.getValue(BlockStateProperties.UP)) set.add(BlockFace.UP);
if(delegate.hasProperty(BlockStateProperties.DOWN) && delegate.getValue(BlockStateProperties.DOWN)) set.add(BlockFace.DOWN);
return set;
}
@Override
public void setFace(BlockFace face, boolean facing) {
switch(face) {
case NORTH:
delegate = delegate.setValue(BlockStateProperties.NORTH, facing);
break;
case SOUTH:
delegate = delegate.setValue(BlockStateProperties.SOUTH, facing);
break;
case EAST:
delegate = delegate.setValue(BlockStateProperties.EAST, facing);
break;
case WEST:
delegate = delegate.setValue(BlockStateProperties.WEST, facing);
break;
case UP:
delegate = delegate.setValue(BlockStateProperties.UP, facing);
break;
case DOWN:
delegate = delegate.setValue(BlockStateProperties.DOWN, facing);
break;
}
}
@Override
public Set<BlockFace> getAllowedFaces() {
Set<BlockFace> set = new HashSet<>();
if(delegate.hasProperty(BlockStateProperties.NORTH)) set.add(BlockFace.NORTH);
if(delegate.hasProperty(BlockStateProperties.SOUTH)) set.add(BlockFace.SOUTH);
if(delegate.hasProperty(BlockStateProperties.EAST)) set.add(BlockFace.EAST);
if(delegate.hasProperty(BlockStateProperties.WEST)) set.add(BlockFace.WEST);
if(delegate.hasProperty(BlockStateProperties.UP)) set.add(BlockFace.UP);
if(delegate.hasProperty(BlockStateProperties.DOWN)) set.add(BlockFace.DOWN);
return set;
}
@Override
public boolean hasFace(BlockFace f) {
return getFaces().contains(f);
}
}

View File

@ -0,0 +1,37 @@
package com.dfsek.terra.forge.world.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 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;
public class ForgeOrientable extends ForgeBlockData implements Orientable {
private final EnumProperty<Direction.Axis> property;
public ForgeOrientable(BlockState delegate, EnumProperty<Direction.Axis> property) {
super(delegate);
this.property = property;
}
@Override
public Set<Axis> getAxes() {
return Arrays.stream(Axis.values()).collect(Collectors.toSet());
}
@Override
public Axis getAxis() {
return ForgeEnumAdapter.adapt(getHandle().getValue(property));
}
@Override
public void setAxis(Axis axis) {
delegate = delegate.setValue(property, ForgeEnumAdapter.adapt(axis));
}
}

View File

@ -0,0 +1,111 @@
package com.dfsek.terra.forge.world.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 net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
public class ForgeRotatable extends ForgeBlockData implements Rotatable {
public ForgeRotatable(BlockState delegate) {
super(delegate);
}
@Override
public BlockFace getRotation() {
int r = delegate.getValue(BlockStateProperties.ROTATION_16);
switch(r) {
case 0:
return BlockFace.SOUTH;
case 1:
return BlockFace.SOUTH_SOUTH_WEST;
case 2:
return BlockFace.SOUTH_WEST;
case 3:
return BlockFace.WEST_SOUTH_WEST;
case 4:
return BlockFace.WEST;
case 5:
return BlockFace.WEST_NORTH_WEST;
case 6:
return BlockFace.NORTH_WEST;
case 7:
return BlockFace.NORTH_NORTH_WEST;
case 8:
return BlockFace.NORTH;
case 9:
return BlockFace.NORTH_NORTH_EAST;
case 10:
return BlockFace.NORTH_EAST;
case 11:
return BlockFace.EAST_NORTH_EAST;
case 12:
return BlockFace.EAST;
case 13:
return BlockFace.EAST_SOUTH_EAST;
case 14:
return BlockFace.SOUTH_EAST;
case 15:
return BlockFace.SOUTH_SOUTH_EAST;
default:
throw new IllegalArgumentException("Unknown rotation " + r);
}
}
@Override
public void setRotation(BlockFace face) {
switch(face) {
case UP:
case DOWN:
throw new IllegalArgumentException("Illegal rotation " + face);
case SOUTH:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 0);
return;
case SOUTH_SOUTH_WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 1);
return;
case SOUTH_WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 2);
return;
case WEST_SOUTH_WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 3);
return;
case WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 4);
return;
case WEST_NORTH_WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 5);
return;
case NORTH_WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 6);
return;
case NORTH_NORTH_WEST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 7);
return;
case NORTH:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 8);
return;
case NORTH_NORTH_EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 9);
return;
case NORTH_EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 10);
return;
case EAST_NORTH_EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 11);
return;
case EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 12);
return;
case EAST_SOUTH_EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 13);
return;
case SOUTH_EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 14);
return;
case SOUTH_SOUTH_EAST:
delegate = delegate.setValue(BlockStateProperties.ROTATION_16, 15);
return;
}
}
}

View File

@ -0,0 +1,21 @@
package com.dfsek.terra.forge.world.block.data;
import com.dfsek.terra.api.platform.block.data.Slab;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
public class ForgeSlab extends ForgeWaterlogged implements Slab {
public ForgeSlab(BlockState delegate) {
super(delegate);
}
@Override
public Type getType() {
return ForgeEnumAdapter.adapt(delegate.getValue(BlockStateProperties.SLAB_TYPE));
}
@Override
public void setType(Type type) {
delegate = delegate.setValue(BlockStateProperties.SLAB_TYPE, ForgeEnumAdapter.adapt(type));
}
}

View File

@ -0,0 +1,42 @@
package com.dfsek.terra.forge.world.block.data;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.platform.block.data.Stairs;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
public class ForgeStairs extends ForgeWaterlogged implements Stairs {
public ForgeStairs(BlockState delegate) {
super(delegate);
}
@Override
public Shape getShape() {
return ForgeEnumAdapter.adapt(getHandle().getValue(BlockStateProperties.STAIRS_SHAPE));
}
@Override
public void setShape(Shape shape) {
super.delegate = getHandle().setValue(BlockStateProperties.STAIRS_SHAPE, ForgeEnumAdapter.adapt(shape));
}
@Override
public Half getHalf() {
return ForgeEnumAdapter.adapt(getHandle().getValue(BlockStateProperties.HALF));
}
@Override
public void setHalf(Half half) {
super.delegate = getHandle().setValue(BlockStateProperties.HALF, ForgeEnumAdapter.adapt(half));
}
@Override
public BlockFace getFacing() {
return ForgeEnumAdapter.adapt(getHandle().getValue(BlockStateProperties.HORIZONTAL_FACING));
}
@Override
public void setFacing(BlockFace facing) {
super.delegate = getHandle().setValue(BlockStateProperties.HORIZONTAL_FACING, ForgeEnumAdapter.adapt(facing));
}
}

View File

@ -0,0 +1,22 @@
package com.dfsek.terra.forge.world.block.data;
import com.dfsek.terra.api.platform.block.data.Waterlogged;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import net.minecraft.block.BlockState;
import net.minecraft.state.properties.BlockStateProperties;
public class ForgeWaterlogged extends ForgeBlockData implements Waterlogged {
public ForgeWaterlogged(BlockState delegate) {
super(delegate);
}
@Override
public boolean isWaterlogged() {
return delegate.getValue(BlockStateProperties.WATERLOGGED);
}
@Override
public void setWaterlogged(boolean waterlogged) {
super.delegate = delegate.setValue(BlockStateProperties.WATERLOGGED, waterlogged);
}
}

View File

@ -0,0 +1,73 @@
package com.dfsek.terra.forge.world.block.state;
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.world.ForgeAdapter;
import com.dfsek.terra.forge.world.block.ForgeBlock;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldHandle;
import net.minecraft.tileentity.LockableLootTileEntity;
import net.minecraft.tileentity.MobSpawnerTileEntity;
import net.minecraft.tileentity.SignTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IWorld;
public class ForgeBlockState implements BlockState {
protected final TileEntity blockEntity;
private final IWorld worldAccess;
public ForgeBlockState(TileEntity blockEntity, IWorld worldAccess) {
this.blockEntity = blockEntity;
this.worldAccess = worldAccess;
}
public static ForgeBlockState newInstance(Block block) {
IWorld worldAccess = ((ForgeWorldHandle) block.getLocation().getWorld()).getWorld();
TileEntity entity = worldAccess.getBlockEntity(ForgeAdapter.adapt(block.getLocation().toVector()));
if(entity instanceof SignTileEntity) {
return new ForgeSign((SignTileEntity) entity, worldAccess);
} else if(entity instanceof MobSpawnerTileEntity) {
return new ForgeMobSpawner((MobSpawnerTileEntity) entity, worldAccess);
} else if(entity instanceof LockableLootTileEntity) {
return new ForgeContainer((LockableLootTileEntity) entity, worldAccess);
}
return null;
}
@Override
public TileEntity getHandle() {
return blockEntity;
}
@Override
public Block getBlock() {
return new ForgeBlock(blockEntity.getBlockPos(), blockEntity.getLevel());
}
@Override
public int getX() {
return blockEntity.getBlockPos().getX();
}
@Override
public int getY() {
return blockEntity.getBlockPos().getY();
}
@Override
public int getZ() {
return blockEntity.getBlockPos().getZ();
}
@Override
public BlockData getBlockData() {
return ForgeAdapter.adapt(blockEntity.getBlockState());
}
@Override
public boolean update(boolean applyPhysics) {
worldAccess.getChunk(blockEntity.getBlockPos()).setBlockEntity(blockEntity.getBlockPos(), blockEntity);
return true;
}
}

View File

@ -0,0 +1,18 @@
package com.dfsek.terra.forge.world.block.state;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.platform.inventory.Inventory;
import com.dfsek.terra.forge.inventory.ForgeInventory;
import net.minecraft.tileentity.LockableLootTileEntity;
import net.minecraft.world.IWorld;
public class ForgeContainer extends ForgeBlockState implements Container {
public ForgeContainer(LockableLootTileEntity blockEntity, IWorld worldAccess) {
super(blockEntity, worldAccess);
}
@Override
public Inventory getInventory() {
return new ForgeInventory(((LockableLootTileEntity) blockEntity));
}
}

View File

@ -0,0 +1,133 @@
package com.dfsek.terra.forge.world.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.world.ForgeAdapter;
import net.minecraft.tileentity.MobSpawnerTileEntity;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.IWorld;
import org.jetbrains.annotations.NotNull;
public class ForgeMobSpawner extends ForgeBlockState implements MobSpawner { // TODO: finish implementation / refactor API because bukkit doesnt expose most of the stuff spawners can do
public ForgeMobSpawner(MobSpawnerTileEntity blockEntity, IWorld worldAccess) {
super(blockEntity, worldAccess);
}
@Override
public EntityType getSpawnedType() {
return ForgeAdapter.adapt(Registry.ENTITY_TYPE.get(((MobSpawnerTileEntity) blockEntity).getSpawner().getSpawnerEntity().getType().getRegistryName()));
}
@Override
public void setSpawnedType(@NotNull EntityType creatureType) {
((MobSpawnerTileEntity) blockEntity).getSpawner().setEntityId(ForgeAdapter.adapt(creatureType));
}
@Override
public int getDelay() {
return 0;
}
@Override
public void setDelay(int delay) {
}
@Override
public int getMinSpawnDelay() {
return 0;
}
@Override
public void setMinSpawnDelay(int delay) {
}
@Override
public int getMaxSpawnDelay() {
return 0;
}
@Override
public void setMaxSpawnDelay(int delay) {
}
@Override
public int getSpawnCount() {
return 0;
}
@Override
public void setSpawnCount(int spawnCount) {
}
@Override
public int getMaxNearbyEntities() {
return 0;
}
@Override
public void setMaxNearbyEntities(int maxNearbyEntities) {
}
@Override
public int getRequiredPlayerRange() {
return 0;
}
@Override
public void setRequiredPlayerRange(int requiredPlayerRange) {
}
@Override
public int getSpawnRange() {
return 0;
}
@Override
public void setSpawnRange(int spawnRange) {
}
@Override
public void applyState(String state) {
SerialState.parse(state).forEach((k, v) -> {
switch(k) {
case "type":
setSpawnedType(TerraForgePlugin.getInstance().getWorldHandle().getEntity(v));
return;
case "delay":
setDelay(Integer.parseInt(v));
return;
case "min_delay":
setMinSpawnDelay(Integer.parseInt(v));
return;
case "max_delay":
setMaxSpawnDelay(Integer.parseInt(v));
return;
case "spawn_count":
setSpawnCount(Integer.parseInt(v));
return;
case "spawn_range":
setSpawnRange(Integer.parseInt(v));
return;
case "max_nearby":
setMaxNearbyEntities(Integer.parseInt(v));
return;
case "required_player_range":
setRequiredPlayerRange(Integer.parseInt(v));
return;
default:
throw new IllegalArgumentException("Invalid property: " + k);
}
});
}
}

View File

@ -0,0 +1,44 @@
package com.dfsek.terra.forge.world.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.StringTextComponent;
import net.minecraft.world.IWorld;
import org.jetbrains.annotations.NotNull;
public class ForgeSign extends ForgeBlockState implements Sign {
public ForgeSign(SignTileEntity blockEntity, IWorld worldAccess) {
super(blockEntity, worldAccess);
}
@Override
public @NotNull String[] getLines() {
SignTileEntity sign = (SignTileEntity) blockEntity;
return new String[] {
sign.getMessage(0).getString(),
sign.getMessage(1).getString(),
sign.getMessage(2).getString(),
sign.getMessage(3).getString()
};
}
@Override
public @NotNull String getLine(int index) throws IndexOutOfBoundsException {
return ((SignTileEntity) blockEntity).getMessage(index).getString();
}
@Override
public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException {
((SignTileEntity) blockEntity).setMessage(index, new StringTextComponent(line));
}
@Override
public void applyState(String state) {
SerialState.parse(state).forEach((k, v) -> {
if(!k.startsWith("text")) throw new IllegalArgumentException("Invalid property: " + k);
setLine(Integer.parseInt(k.substring(4)), v);
});
}
}

View File

@ -0,0 +1,23 @@
package com.dfsek.terra.forge.world.entity;
import com.dfsek.terra.api.platform.CommandSender;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.StringTextComponent;
public class ForgeCommandSender implements CommandSender {
private final CommandSource delegate;
public ForgeCommandSender(CommandSource delegate) {
this.delegate = delegate;
}
@Override
public void sendMessage(String message) {
delegate.sendSuccess(new StringTextComponent(message), true);
}
@Override
public Object getHandle() {
return delegate;
}
}

View File

@ -0,0 +1,43 @@
package com.dfsek.terra.forge.world.entity;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldAccess;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldHandle;
import net.minecraft.world.server.ServerWorld;
public class ForgeEntity implements Entity {
private final net.minecraft.entity.Entity delegate;
public ForgeEntity(net.minecraft.entity.Entity delegate) {
this.delegate = delegate;
}
@Override
public void sendMessage(String message) {
}
@Override
public Object getHandle() {
return null;
}
@Override
public Location getLocation() {
return new Location(new ForgeWorldAccess(delegate.level), ForgeAdapter.adapt(delegate.blockPosition()));
}
@Override
public void setLocation(Location location) {
delegate.teleportTo(location.getX(), location.getY(), location.getZ());
delegate.setLevel((ServerWorld) ((ForgeWorldHandle) location).getWorld());
}
@Override
public World getWorld() {
return new ForgeWorldAccess(delegate.level);
}
}

View File

@ -0,0 +1,16 @@
package com.dfsek.terra.forge.world.entity;
import com.dfsek.terra.api.platform.entity.EntityType;
public class ForgeEntityType implements EntityType {
private final net.minecraft.entity.EntityType<?> type;
public ForgeEntityType(net.minecraft.entity.EntityType<?> type) {
this.type = type;
}
@Override
public net.minecraft.entity.EntityType<?> getHandle() {
return type;
}
}

View File

@ -0,0 +1,42 @@
package com.dfsek.terra.forge.world.entity;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldAccess;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.text.StringTextComponent;
public class ForgePlayer implements Player {
private final PlayerEntity delegate;
public ForgePlayer(PlayerEntity delegate) {
this.delegate = delegate;
}
@Override
public void sendMessage(String message) {
delegate.displayClientMessage(new StringTextComponent(message), false);
}
@Override
public Object getHandle() {
return delegate;
}
@Override
public Location getLocation() {
return ForgeAdapter.adapt(delegate.blockPosition()).toLocation(new ForgeWorldAccess(delegate.level));
}
@Override
public World getWorld() {
return new ForgeWorldAccess(delegate.level);
}
@Override
public void setLocation(Location location) {
delegate.teleportTo(location.getX(), location.getY(), location.getZ());
}
}

View File

@ -0,0 +1,34 @@
package com.dfsek.terra.forge.world.features;
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.mojang.serialization.Codec;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ISeedReader;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.NoFeatureConfig;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
/**
* Feature wrapper for Terra populator
*/
public class PopulatorFeature extends Feature<NoFeatureConfig> {
public PopulatorFeature(Codec<NoFeatureConfig> codec) {
super(codec);
}
@Override
public boolean place(@NotNull ISeedReader world, @NotNull ChunkGenerator generator, @NotNull Random random, 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));
return true;
}
}

View File

@ -0,0 +1,37 @@
package com.dfsek.terra.forge.world.generator;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunk;
import org.jetbrains.annotations.NotNull;
public class ForgeChunkData implements ChunkData {
private final IChunk handle;
public ForgeChunkData(IChunk handle) {
this.handle = handle;
}
@Override
public IChunk getHandle() {
return handle;
}
@Override
public int getMaxHeight() {
return handle.getMaxBuildHeight();
}
@Override
public void setBlock(int x, int y, int z, @NotNull BlockData blockData) {
handle.setBlockState(new BlockPos(x, y, z), ((ForgeBlockData) blockData).getHandle(), false);
}
@Override
public @NotNull BlockData getBlockData(int x, int y, int z) {
return new ForgeBlockData(handle.getBlockState(new BlockPos(x, y, z)));
}
}

View File

@ -0,0 +1,16 @@
package com.dfsek.terra.forge.world.generator;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
public class ForgeChunkGenerator implements ChunkGenerator {
private final net.minecraft.world.gen.ChunkGenerator delegate;
public ForgeChunkGenerator(net.minecraft.world.gen.ChunkGenerator delegate) {
this.delegate = delegate;
}
@Override
public net.minecraft.world.gen.ChunkGenerator getHandle() {
return delegate;
}
}

View File

@ -0,0 +1,141 @@
package com.dfsek.terra.forge.world.generator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.config.pack.ConfigPack;
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.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.math.ChunkPos;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.world.Blockreader;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
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.StructureManager;
import net.minecraft.world.gen.feature.template.TemplateManager;
import net.minecraft.world.gen.settings.DimensionStructuresSettings;
import net.minecraft.world.gen.settings.StructureSpreadSettings;
import org.jetbrains.annotations.NotNull;
public class ForgeChunkGeneratorWrapper extends ChunkGenerator implements GeneratorWrapper {
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(TerraForgePlugin.getInstance().getConfigRegistry()::get))));
public static final Codec<ForgeChunkGeneratorWrapper> 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(ForgeChunkGeneratorWrapper::new)));
private final ConfigPack pack;
public ConfigPack getPack() {
return pack;
}
public ForgeChunkGeneratorWrapper(TerraBiomeSource biomeSource, long seed, ConfigPack configPack) {
super(biomeSource, new DimensionStructuresSettings(false));
this.pack = configPack;
this.delegate = new DefaultChunkGenerator3D(pack, TerraForgePlugin.getInstance());
delegate.getMain().logger().info("Loading world with config pack " + pack.getTemplate().getID());
this.biomeSource = biomeSource;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return CODEC;
}
@Override
public @NotNull ChunkGenerator withSeed(long seed) {
return new ForgeChunkGeneratorWrapper((TerraBiomeSource) this.biomeSource.withSeed(seed), seed, pack);
}
@Override
public void buildSurfaceAndBedrock(@NotNull WorldGenRegion p_225551_1_, @NotNull IChunk p_225551_2_) {
}
@Override
public boolean hasStronghold(@NotNull ChunkPos 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_) {
}
@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
}
@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));
}
@Override
public int getBaseHeight(int x, int z, Heightmap.@NotNull Type p_222529_3_) {
TerraWorld world = TerraForgePlugin.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);
int height = world.getWorld().getMaxHeight();
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
BlockState[] array = new BlockState[256];
for(int y = 255; y >= 0; y--) {
if(y > height) {
if(y > getSeaLevel()) {
array[y] = Blocks.AIR.defaultBlockState();
} else {
array[y] = Blocks.WATER.defaultBlockState();
}
} else {
array[y] = Blocks.STONE.defaultBlockState();
}
}
return new Blockreader(array);
}
@Override
public TerraChunkGenerator getHandle() {
return delegate;
}
}

View File

@ -0,0 +1,127 @@
package com.dfsek.terra.forge.world.handles;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.block.ForgeBlock;
import com.dfsek.terra.forge.world.entity.ForgeEntity;
import com.dfsek.terra.forge.world.handles.chunk.ForgeChunk;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldHandle;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.server.ServerWorld;
import java.io.File;
import java.util.UUID;
public class ForgeWorld implements World, ForgeWorldHandle {
private final Handle delegate;
public ForgeWorld(ServerWorld world, ChunkGenerator generator) {
this.delegate = new Handle(world, generator);
}
@Override
public long getSeed() {
return delegate.world.getSeed();
}
@Override
public int getMaxHeight() {
return delegate.world.getHeight();
}
@Override
public ChunkGenerator getGenerator() {
return delegate.generator;
}
@Override
public String getName() {
return delegate.world.toString();
}
@Override
public UUID getUID() {
return null;
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
return new ForgeChunk(delegate.world.getChunk(x, z));
}
@Override
public File getWorldFolder() {
return null;
}
@Override
public Block getBlockAt(int x, int y, int z) {
BlockPos pos = new BlockPos(x, y, z);
return new ForgeBlock(pos, delegate.world);
}
@Override
public int hashCode() {
return ((IServerWorld) delegate.world).getLevel().hashCode();
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof ForgeWorld)) return false;
return ((IServerWorld) ((ForgeWorld) obj).delegate.world).getLevel().equals(((IServerWorld) delegate.world).getLevel());
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
net.minecraft.entity.Entity entity = ForgeAdapter.adapt(entityType).create(delegate.world);
entity.setPos(location.getX(), location.getY(), location.getZ());
delegate.world.addFreshEntity(entity);
return new ForgeEntity(entity);
}
@Override
public int getMinHeight() {
return 0;
}
@Override
public Handle getHandle() {
return null;
}
@Override
public ServerWorld getWorld() {
return delegate.getWorld();
}
public static final class Handle {
private final ServerWorld world;
private final ChunkGenerator generator;
private Handle(ServerWorld world, ChunkGenerator generator) {
this.world = world;
this.generator = generator;
}
public ChunkGenerator getGenerator() {
return generator;
}
public ServerWorld getWorld() {
return world;
}
}
}

View File

@ -0,0 +1,52 @@
package com.dfsek.terra.forge.world.handles.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.world.block.ForgeBlockData;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.NotNull;
public class ForgeChunk implements Chunk {
private final net.minecraft.world.chunk.Chunk chunk;
public ForgeChunk(net.minecraft.world.chunk.Chunk chunk) {
this.chunk = chunk;
}
@Override
public int getX() {
return chunk.getPos().x;
}
@Override
public int getZ() {
return chunk.getPos().z;
}
@Override
public World getWorld() {
return null;
}
@Override
public Block getBlock(int x, int y, int z) {
return null;
}
@Override
public net.minecraft.world.chunk.Chunk getHandle() {
return chunk;
}
@Override
public void setBlock(int x, int y, int z, @NotNull BlockData blockData) {
chunk.setBlockState(new BlockPos(x, y, z), ((ForgeBlockData) blockData).getHandle(), false);
}
@Override
public @NotNull BlockData getBlockData(int x, int y, int z) {
return getBlock(x, y, z).getBlockData();
}
}

View File

@ -0,0 +1,60 @@
package com.dfsek.terra.forge.world.handles.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.world.block.ForgeBlock;
import com.dfsek.terra.forge.world.block.ForgeBlockData;
import com.dfsek.terra.forge.world.handles.world.ForgeWorldAccess;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import org.jetbrains.annotations.NotNull;
public class ForgeChunkWorldAccess implements Chunk {
private final IWorld chunkRegion;
private final int x;
private final int z;
public ForgeChunkWorldAccess(IWorld chunkRegion, int x, int z) {
this.chunkRegion = chunkRegion;
this.x = x << 4;
this.z = z << 4;
}
@Override
public int getX() {
return x >> 4;
}
@Override
public int getZ() {
return z >> 4;
}
@Override
public World getWorld() {
return new ForgeWorldAccess(chunkRegion);
}
@Override
public Block getBlock(int x, int y, int z) {
BlockPos pos = new BlockPos(x + this.x, y, z + this.z);
return new ForgeBlock(pos, chunkRegion);
}
@Override
public IWorld getHandle() {
return chunkRegion;
}
@Override
public void setBlock(int x, int y, int z, @NotNull BlockData blockData) {
chunkRegion.setBlock(new BlockPos(x + this.x, y, z + this.z), ((ForgeBlockData) blockData).getHandle(), 0);
}
@Override
public @NotNull BlockData getBlockData(int x, int y, int z) {
return getBlock(x, y, z).getBlockData();
}
}

View File

@ -0,0 +1,133 @@
package com.dfsek.terra.forge.world.handles.world;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.block.ForgeBlock;
import com.dfsek.terra.forge.world.entity.ForgeEntity;
import com.dfsek.terra.forge.world.generator.ForgeChunkGenerator;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.IWorld;
import net.minecraft.world.server.ServerWorld;
import java.io.File;
import java.util.UUID;
public class ForgeSeededWorldAccess implements World, ForgeWorldHandle {
private final Handle handle;
public ForgeSeededWorldAccess(IWorld access, long seed, net.minecraft.world.gen.ChunkGenerator generator) {
this.handle = new Handle(access, seed, generator);
}
@Override
public long getSeed() {
return handle.getSeed();
}
@Override
public int getMaxHeight() {
return handle.getWorldAccess().getMaxBuildHeight();
}
@Override
public ChunkGenerator getGenerator() {
return new ForgeChunkGenerator(handle.getGenerator());
}
@Override
public String getName() {
return handle.toString(); // TODO: implementation
}
@Override
public UUID getUID() {
return UUID.randomUUID(); // TODO: implementation
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
return null;
}
@Override
public File getWorldFolder() {
return null;
}
@Override
public Block getBlockAt(int x, int y, int z) {
BlockPos pos = new BlockPos(x, y, z);
return new ForgeBlock(pos, handle.worldAccess);
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
net.minecraft.entity.Entity entity = ForgeAdapter.adapt(entityType).create((ServerWorld) handle.worldAccess);
entity.setPos(location.getX(), location.getY(), location.getZ());
handle.worldAccess.addFreshEntity(entity);
return new ForgeEntity(entity);
}
@Override
public int getMinHeight() {
return 0;
}
@Override
public int hashCode() {
return ((IServerWorld) handle.worldAccess).getLevel().hashCode();
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof ForgeSeededWorldAccess)) return false;
return ((IServerWorld) ((ForgeSeededWorldAccess) obj).handle.worldAccess).getLevel().equals(((IServerWorld) handle.worldAccess).getLevel());
}
@Override
public Handle getHandle() {
return handle;
}
@Override
public IWorld getWorld() {
return handle.worldAccess;
}
public static class Handle {
private final IWorld worldAccess;
private final long seed;
private final net.minecraft.world.gen.ChunkGenerator generator;
public Handle(IWorld worldAccess, long seed, net.minecraft.world.gen.ChunkGenerator generator) {
this.worldAccess = worldAccess;
this.seed = seed;
this.generator = generator;
}
public net.minecraft.world.gen.ChunkGenerator getGenerator() {
return generator;
}
public long getSeed() {
return seed;
}
public IWorld getWorldAccess() {
return worldAccess;
}
}
}

View File

@ -0,0 +1,108 @@
package com.dfsek.terra.forge.world.handles.world;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.forge.world.ForgeAdapter;
import com.dfsek.terra.forge.world.block.ForgeBlock;
import com.dfsek.terra.forge.world.entity.ForgeEntity;
import com.dfsek.terra.forge.world.generator.ForgeChunkGenerator;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ISeedReader;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.IWorld;
import java.io.File;
import java.util.UUID;
public class ForgeWorldAccess implements World, ForgeWorldHandle {
private final IWorld delegate;
public ForgeWorldAccess(IWorld delegate) {
this.delegate = delegate;
}
@Override
public long getSeed() {
return ((ISeedReader) delegate).getSeed();
}
@Override
public int getMaxHeight() {
return delegate.getHeight();
}
@Override
public ChunkGenerator getGenerator() {
return new ForgeChunkGenerator(((IServerWorld) delegate).getLevel().getChunkSource().getGenerator());
}
@Override
public String getName() {
return ((IServerWorld) delegate).getLevel().toString();
}
@Override
public UUID getUID() {
return null;
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
return null;
}
@Override
public File getWorldFolder() {
return null;
}
@Override
public Block getBlockAt(int x, int y, int z) {
BlockPos pos = new BlockPos(x, y, z);
return new ForgeBlock(pos, delegate);
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
net.minecraft.entity.Entity entity = ForgeAdapter.adapt(entityType).create(((IServerWorld) delegate).getLevel());
entity.setPos(location.getX(), location.getY(), location.getZ());
delegate.addFreshEntity(entity);
return new ForgeEntity(entity);
}
@Override
public int getMinHeight() {
return 0;
}
@Override
public IWorld getHandle() {
return delegate;
}
@Override
public IWorld getWorld() {
return delegate;
}
@Override
public int hashCode() {
return ((IServerWorld) delegate).getLevel().hashCode();
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof ForgeWorldAccess)) return false;
return ((IServerWorld) ((ForgeWorldAccess) obj).delegate).getLevel().equals(((IServerWorld) delegate).getLevel());
}
}

View File

@ -0,0 +1,7 @@
package com.dfsek.terra.forge.world.handles.world;
import net.minecraft.world.IWorld;
public interface ForgeWorldHandle {
IWorld getWorld();
}