From ab816a52d4a456c5c70858681dbe500c811d7d01 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Tue, 7 Mar 2017 17:59:02 +0100 Subject: [PATCH] add basic cave world structure --- .../mod/ActuallyAdditions.java | 7 + .../mod/cave/CaveEvents.java | 125 ++++++++++++++++++ .../mod/cave/ChunkProviderCave.java | 125 ++++++++++++++++++ .../mod/cave/WorldTypeCave.java | 56 ++++++++ .../mod/data/PlayerData.java | 12 +- .../actuallyadditions/mod/data/WorldData.java | 41 +++++- .../mod/event/CommonEvents.java | 6 + .../actuallyadditions/mod/gen/OreGen.java | 7 +- .../assets/actuallyadditions/lang/en_US.lang | 3 + 9 files changed, 367 insertions(+), 15 deletions(-) create mode 100644 src/main/java/de/ellpeck/actuallyadditions/mod/cave/CaveEvents.java create mode 100644 src/main/java/de/ellpeck/actuallyadditions/mod/cave/ChunkProviderCave.java create mode 100644 src/main/java/de/ellpeck/actuallyadditions/mod/cave/WorldTypeCave.java diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/ActuallyAdditions.java b/src/main/java/de/ellpeck/actuallyadditions/mod/ActuallyAdditions.java index 17a332c42..27f394932 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/ActuallyAdditions.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/ActuallyAdditions.java @@ -14,6 +14,7 @@ import de.ellpeck.actuallyadditions.api.ActuallyAdditionsAPI; import de.ellpeck.actuallyadditions.mod.achievement.InitAchievements; import de.ellpeck.actuallyadditions.mod.blocks.InitBlocks; import de.ellpeck.actuallyadditions.mod.booklet.InitBooklet; +import de.ellpeck.actuallyadditions.mod.cave.WorldTypeCave; import de.ellpeck.actuallyadditions.mod.config.ConfigurationHandler; import de.ellpeck.actuallyadditions.mod.crafting.CrusherCrafting; import de.ellpeck.actuallyadditions.mod.crafting.InitCrafting; @@ -70,6 +71,8 @@ public class ActuallyAdditions{ public static boolean teslaLoaded; public static boolean commonCapsLoaded; + public static boolean isCaveMode = true; + static{ //For some reason, this has to be done here FluidRegistry.enableUniversalBucket(); @@ -100,6 +103,10 @@ public class ActuallyAdditions{ new UpdateChecker(); proxy.preInit(event); + if(isCaveMode){ + new WorldTypeCave(); + } + ModUtil.LOGGER.info("PreInitialization Finished."); } diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/cave/CaveEvents.java b/src/main/java/de/ellpeck/actuallyadditions/mod/cave/CaveEvents.java new file mode 100644 index 000000000..286f6d434 --- /dev/null +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/cave/CaveEvents.java @@ -0,0 +1,125 @@ +/* + * This file ("CaveEvents.java") is part of the Actually Additions mod for Minecraft. + * It is created and owned by Ellpeck and distributed + * under the Actually Additions License to be found at + * http://ellpeck.de/actaddlicense + * View the source code at https://github.com/Ellpeck/ActuallyAdditions + * + * © 2015-2017 Ellpeck + */ + +package de.ellpeck.actuallyadditions.mod.cave; + +import de.ellpeck.actuallyadditions.mod.blocks.InitBlocks; +import de.ellpeck.actuallyadditions.mod.data.PlayerData; +import de.ellpeck.actuallyadditions.mod.data.PlayerData.PlayerSave; +import de.ellpeck.actuallyadditions.mod.data.WorldData; +import de.ellpeck.actuallyadditions.mod.gen.WorldGenLushCaves; +import de.ellpeck.actuallyadditions.mod.items.InitItems; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent; + +import java.util.Map; +import java.util.Random; +import java.util.UUID; + +public class CaveEvents{ + + private static final int TRIES_BEFORE_FAILURE = 500; + private static final int DISTANCE_INBETWEEN = 1000; + private static final int CAVE_SPAWN_SPREAD = 50000; + + @SubscribeEvent + public void onPlayerUpdate(PlayerTickEvent event){ + EntityPlayer player = event.player; + if(!player.world.isRemote){ + if(WorldTypeCave.is(player.world)){ + WorldData data = WorldData.get(player.world); + if(data != null){ + BlockPos spawn = data.generatedCaves.get(player.getUniqueID()); + if(spawn == null){ + BlockPos cavePos = generateCave(player, data.generatedCaves); + + data.generatedCaves.put(player.getUniqueID(), cavePos); + data.markDirty(); + } + else{ + if(player.posY >= player.world.getHeight()){ + putPlayerInCave(player, spawn); + } + } + } + } + } + } + + private static BlockPos generateCave(EntityPlayer player, Map generatedCaves){ + BlockPos worldSpawn = player.world.getSpawnPoint(); + Random rand = new Random(player.world.getSeed()); + + BlockPos spawn = null; + tries: + for(int i = 0; i < TRIES_BEFORE_FAILURE; i++){ + int randX = MathHelper.getInt(rand, -CAVE_SPAWN_SPREAD, CAVE_SPAWN_SPREAD); + int randY = MathHelper.getInt(rand, 56, 200); + int randZ = MathHelper.getInt(rand, -CAVE_SPAWN_SPREAD, CAVE_SPAWN_SPREAD); + + spawn = new BlockPos(worldSpawn.getX()+randX, randY, worldSpawn.getZ()+randZ); + + for(BlockPos pos : generatedCaves.values()){ + if(pos.distanceSq(spawn) <= DISTANCE_INBETWEEN*DISTANCE_INBETWEEN){ + continue tries; + } + } + + break; + } + + int chunkX = spawn.getX() >> 4; + int chunkZ = spawn.getZ() >> 4; + for(int x = -12; x <= 12; x++){ + for(int z = -12; z <= 12; z++){ + player.world.getChunkProvider().provideChunk(chunkX+x, chunkZ+z); + } + } + + StructureBoundingBox box = new StructureBoundingBox(spawn.getX()-7, 0, spawn.getZ()-7, spawn.getX()+7, player.world.getHeight(), spawn.getZ()+7); + new WorldGenLushCaves().generate(player.world, rand, spawn, box); + + putPlayerInCave(player, spawn); + + MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); + server.saveAllWorlds(false); + + return spawn; + } + + private static void putPlayerInCave(EntityPlayer player, BlockPos spawn){ + if(!player.isSpectator() && player instanceof EntityPlayerMP){ + player.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 400, 4)); + player.addPotionEffect(new PotionEffect(MobEffects.FIRE_RESISTANCE, 400)); + player.addPotionEffect(new PotionEffect(MobEffects.NIGHT_VISION, 400)); + + PlayerSave save = PlayerData.getDataFromPlayer(player); + if(save != null && !save.bookGottenAlready){ + player.inventory.addItemStackToInventory(new ItemStack(InitItems.itemBooklet)); + player.inventory.addItemStackToInventory(new ItemStack(InitBlocks.blockTinyTorch, 2)); + + save.bookGottenAlready = true; + WorldData.get(player.world).markDirty(); + } + + ((EntityPlayerMP)player).connection.setPlayerLocation(spawn.getX()+0.5, spawn.getY()+1, spawn.getZ()+0.5, 0F, 0F); + } + } +} diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/cave/ChunkProviderCave.java b/src/main/java/de/ellpeck/actuallyadditions/mod/cave/ChunkProviderCave.java new file mode 100644 index 000000000..59e692e8d --- /dev/null +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/cave/ChunkProviderCave.java @@ -0,0 +1,125 @@ +/* + * This file ("ChunkProviderCaves.java") is part of the Actually Additions mod for Minecraft. + * It is created and owned by Ellpeck and distributed + * under the Actually Additions License to be found at + * http://ellpeck.de/actaddlicense + * View the source code at https://github.com/Ellpeck/ActuallyAdditions + * + * © 2015-2017 Ellpeck + */ + +package de.ellpeck.actuallyadditions.mod.cave; + +import net.minecraft.block.BlockStone; +import net.minecraft.block.BlockStone.EnumType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.EnumCreatureType; +import net.minecraft.init.Biomes; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.chunk.IChunkGenerator; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +public class ChunkProviderCave implements IChunkGenerator{ + + private final World world; + private final Random rand; + + public ChunkProviderCave(World world){ + this.world = world; + this.rand = new Random(world.getSeed()); + } + + @Override + public Chunk provideChunk(int chunkX, int chunkZ){ + ChunkPrimer primer = new ChunkPrimer(); + + int height = this.world.getHeight(); + for(int y = 0; y < height; y++){ + boolean isTopOrBottom = y == 0 || y == height-1; + + for(int x = 0; x < 16; ++x){ + for(int z = 0; z < 16; ++z){ + if(isTopOrBottom){ + primer.setBlockState(x, y, z, Blocks.BEDROCK.getDefaultState()); + } + else{ + IBlockState state; + + int rand = this.rand.nextInt(485); + if(rand <= 250){ + state = Blocks.STONE.getDefaultState(); + } + else if(rand <= 350){ + state = Blocks.COBBLESTONE.getDefaultState(); + } + else if(rand <= 360){ + state = Blocks.STONE.getDefaultState().withProperty(BlockStone.VARIANT, EnumType.ANDESITE); + } + else if(rand <= 370){ + state = Blocks.STONE.getDefaultState().withProperty(BlockStone.VARIANT, EnumType.DIORITE); + } + else if(rand <= 380){ + state = Blocks.STONE.getDefaultState().withProperty(BlockStone.VARIANT, EnumType.GRANITE); + } + else if(rand <= 430){ + state = Blocks.DIRT.getDefaultState(); + } + else if(rand <= 450){ + state = Blocks.CLAY.getDefaultState(); + } + else if(rand <= 480){ + state = Blocks.GRAVEL.getDefaultState(); + } + else{ + state = Blocks.MOSSY_COBBLESTONE.getDefaultState(); + } + + primer.setBlockState(x, y, z, state); + } + } + } + } + + Chunk chunk = new Chunk(this.world, primer, chunkX, chunkZ); + + byte[] biomes = chunk.getBiomeArray(); + Arrays.fill(biomes, (byte)Biome.getIdForBiome(Biomes.FOREST)); + + chunk.generateSkylightMap(); + return chunk; + } + + @Override + public void populate(int x, int z){ + + } + + @Override + public boolean generateStructures(Chunk chunkIn, int x, int z){ + return false; + } + + @Override + public List getPossibleCreatures(EnumCreatureType creatureType, BlockPos pos){ + Biome biome = this.world.getBiome(pos); + return biome.getSpawnableList(creatureType); + } + + @Override + public BlockPos getStrongholdGen(World worldIn, String structureName, BlockPos position, boolean bool){ + return null; + } + + @Override + public void recreateStructures(Chunk chunkIn, int x, int z){ + + } +} diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/cave/WorldTypeCave.java b/src/main/java/de/ellpeck/actuallyadditions/mod/cave/WorldTypeCave.java new file mode 100644 index 000000000..8b904d3f7 --- /dev/null +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/cave/WorldTypeCave.java @@ -0,0 +1,56 @@ +/* + * This file ("WorldTypeCave.java") is part of the Actually Additions mod for Minecraft. + * It is created and owned by Ellpeck and distributed + * under the Actually Additions License to be found at + * http://ellpeck.de/actaddlicense + * View the source code at https://github.com/Ellpeck/ActuallyAdditions + * + * © 2015-2017 Ellpeck + */ + +package de.ellpeck.actuallyadditions.mod.cave; + +import de.ellpeck.actuallyadditions.mod.ActuallyAdditions; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.WorldType; +import net.minecraft.world.chunk.IChunkGenerator; + +import java.util.Random; + +public class WorldTypeCave extends WorldType{ + + public WorldTypeCave(){ + super("actaddcaves"); + } + + @Override + public float getCloudHeight(){ + return 1024F; + } + + @Override + public boolean showWorldInfoNotice(){ + return true; + } + + @Override + public boolean handleSlimeSpawnReduction(Random random, World world){ + return true; + } + + @Override + public int getSpawnFuzz(WorldServer world, MinecraftServer server){ + return 1; + } + + @Override + public IChunkGenerator getChunkGenerator(World world, String generatorOptions){ + return new ChunkProviderCave(world); + } + + public static boolean is(World world){ + return ActuallyAdditions.isCaveMode && world.getWorldType() instanceof WorldTypeCave; + } +} diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/data/PlayerData.java b/src/main/java/de/ellpeck/actuallyadditions/mod/data/PlayerData.java index b124ed2f9..48384bc21 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/data/PlayerData.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/data/PlayerData.java @@ -23,17 +23,15 @@ import net.minecraftforge.fml.relauncher.SideOnly; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; public final class PlayerData{ public static PlayerSave getDataFromPlayer(EntityPlayer player){ - WorldData worldData = WorldData.get(player.getEntityWorld()); - ConcurrentHashMap data = worldData.playerSaveData; + WorldData data = WorldData.get(player.getEntityWorld()); UUID id = player.getUniqueID(); - if(data.containsKey(id)){ - PlayerSave save = data.get(id); + if(data.playerSaveData.containsKey(id)){ + PlayerSave save = data.playerSaveData.get(id); if(save != null && save.id != null && save.id.equals(id)){ return save; } @@ -41,8 +39,8 @@ public final class PlayerData{ //Add Data if none is existant PlayerSave save = new PlayerSave(id); - data.put(id, save); - worldData.markDirty(); + data.playerSaveData.put(id, save); + data.markDirty(); return save; } diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/data/WorldData.java b/src/main/java/de/ellpeck/actuallyadditions/mod/data/WorldData.java index 8eada7218..d36cf07ba 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/data/WorldData.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/data/WorldData.java @@ -11,6 +11,7 @@ package de.ellpeck.actuallyadditions.mod.data; import de.ellpeck.actuallyadditions.api.laser.Network; +import de.ellpeck.actuallyadditions.mod.ActuallyAdditions; import de.ellpeck.actuallyadditions.mod.data.PlayerData.PlayerSave; import de.ellpeck.actuallyadditions.mod.misc.apiimpl.LaserRelayConnectionHandler; import de.ellpeck.actuallyadditions.mod.util.ModUtil; @@ -18,6 +19,7 @@ import io.netty.util.internal.ConcurrentSet; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldSavedData; import net.minecraft.world.WorldServer; @@ -26,9 +28,7 @@ import net.minecraftforge.common.WorldSpecificSaveHandler; import java.io.File; import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class WorldData extends WorldSavedData{ @@ -37,8 +37,9 @@ public class WorldData extends WorldSavedData{ //TODO Remove this as well public static List legacyLoadWorlds = new ArrayList(); private static WorldData data; - public final ConcurrentSet laserRelayNetworks = new ConcurrentSet(); - public final ConcurrentHashMap playerSaveData = new ConcurrentHashMap(); + public final Set laserRelayNetworks = new ConcurrentSet(); + public final Map playerSaveData = new ConcurrentHashMap(); + public final Map generatedCaves = new ConcurrentHashMap(); public WorldData(String name){ super(name); @@ -149,6 +150,20 @@ public class WorldData extends WorldSavedData{ save.readFromNBT(data, true); this.playerSaveData.put(id, save); } + + this.generatedCaves.clear(); + + if(ActuallyAdditions.isCaveMode){ + NBTTagList caveList = compound.getTagList("GeneratedCaves", 10); + for(int i = 0; i < caveList.tagCount(); i++){ + NBTTagCompound cave = caveList.getCompoundTagAt(i); + + UUID id = cave.getUniqueId("UUID"); + BlockPos pos = new BlockPos(cave.getInteger("X"), cave.getInteger("Y"), cave.getInteger("Z")); + + this.generatedCaves.put(id, pos); + } + } } @Override @@ -179,6 +194,22 @@ public class WorldData extends WorldSavedData{ } compound.setTag("PlayerData", playerList); + if(ActuallyAdditions.isCaveMode){ + NBTTagList caveList = new NBTTagList(); + for(Map.Entry entry : this.generatedCaves.entrySet()){ + NBTTagCompound cave = new NBTTagCompound(); + + cave.setUniqueId("UUID", entry.getKey()); + BlockPos pos = entry.getValue(); + cave.setInteger("X", pos.getX()); + cave.setInteger("Y", pos.getY()); + cave.setInteger("Z", pos.getZ()); + + caveList.appendTag(cave); + } + compound.setTag("GeneratedCaves", caveList); + } + return compound; } } diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/event/CommonEvents.java b/src/main/java/de/ellpeck/actuallyadditions/mod/event/CommonEvents.java index 55e4c7893..ab4f6ec6e 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/event/CommonEvents.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/event/CommonEvents.java @@ -10,8 +10,10 @@ package de.ellpeck.actuallyadditions.mod.event; +import de.ellpeck.actuallyadditions.mod.ActuallyAdditions; import de.ellpeck.actuallyadditions.mod.achievement.InitAchievements; import de.ellpeck.actuallyadditions.mod.achievement.TheAchievements; +import de.ellpeck.actuallyadditions.mod.cave.CaveEvents; import de.ellpeck.actuallyadditions.mod.config.values.ConfigBoolValues; import de.ellpeck.actuallyadditions.mod.data.PlayerData; import de.ellpeck.actuallyadditions.mod.data.WorldData; @@ -41,6 +43,10 @@ public class CommonEvents{ public CommonEvents(){ MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(new DungeonLoot()); + + if(ActuallyAdditions.isCaveMode){ + MinecraftForge.EVENT_BUS.register(new CaveEvents()); + } } public static void checkAchievements(ItemStack gotten, EntityPlayer player, InitAchievements.Type type){ diff --git a/src/main/java/de/ellpeck/actuallyadditions/mod/gen/OreGen.java b/src/main/java/de/ellpeck/actuallyadditions/mod/gen/OreGen.java index 64d54305c..d4feb5742 100644 --- a/src/main/java/de/ellpeck/actuallyadditions/mod/gen/OreGen.java +++ b/src/main/java/de/ellpeck/actuallyadditions/mod/gen/OreGen.java @@ -13,6 +13,7 @@ package de.ellpeck.actuallyadditions.mod.gen; import de.ellpeck.actuallyadditions.mod.blocks.InitBlocks; import de.ellpeck.actuallyadditions.mod.blocks.metalists.TheMiscBlocks; import de.ellpeck.actuallyadditions.mod.blocks.metalists.TheWildPlants; +import de.ellpeck.actuallyadditions.mod.cave.WorldTypeCave; import de.ellpeck.actuallyadditions.mod.config.values.ConfigBoolValues; import de.ellpeck.actuallyadditions.mod.config.values.ConfigIntListValues; import de.ellpeck.actuallyadditions.mod.config.values.ConfigIntValues; @@ -57,9 +58,9 @@ public class OreGen implements IWorldGenerator{ @Override public void generate(Random random, int chunkX, int chunkZ, World world, IChunkGenerator chunkGenerator, IChunkProvider chunkProvider){ - int dimension = world.provider.getDimension(); - if(dimension != -1 && dimension != 1){ - if(world.getWorldType() != WorldType.FLAT && !ArrayUtils.contains(ConfigIntListValues.ORE_GEN_DIMENSION_BLACKLIST.getValue(), world.provider.getDimension())){ + if(world.getWorldType() != WorldType.FLAT && !WorldTypeCave.is(world)){ + int dimension = world.provider.getDimension(); + if(dimension != -1 && dimension != 1 && !ArrayUtils.contains(ConfigIntListValues.ORE_GEN_DIMENSION_BLACKLIST.getValue(), dimension)){ this.generateDefault(world, random, chunkX, chunkZ); } } diff --git a/src/main/resources/assets/actuallyadditions/lang/en_US.lang b/src/main/resources/assets/actuallyadditions/lang/en_US.lang index 619c7f281..b08820841 100644 --- a/src/main/resources/assets/actuallyadditions/lang/en_US.lang +++ b/src/main/resources/assets/actuallyadditions/lang/en_US.lang @@ -663,6 +663,9 @@ info.actuallyadditions.laserRelay.mode.both=Both Directions info.actuallyadditions.laserRelay.mode.outputOnly=Only into adjacent Blocks info.actuallyadditions.laserRelay.mode.inputOnly=Only out of adjacent Blocks info.actuallyadditions.laserRelay.mode.noCompasss=Hold a %s to modify! +info.actuallyadditions.cave.generating=Generating cave for player %s, server might lag for a bit... +info.actuallyadditions.cave.generated=Finished generating cave for player %s. +info.actuallyadditions.cave.generatingScreen=Generating cave... #Container Names container.actuallyadditions.inputter.name=ESD