public void CreateInitialEmbarkment(Generation.ChunkGeneratorSettings Settings) { // If no file exists, we have to create the balloon and balloon port. if (!string.IsNullOrEmpty(Settings.Overworld.InstanceSettings.ExistingFile)) { return; // Todo: Don't call in the first place?? } var port = GenerateInitialBalloonPort(Renderer.Camera.Position.X, Renderer.Camera.Position.Z, 1, Settings); PlayerFaction.Economy.Funds = Settings.Overworld.InstanceSettings.InitalEmbarkment.Funds; Settings.Overworld.PlayerCorporationFunds -= Settings.Overworld.InstanceSettings.InitalEmbarkment.Funds; Settings.Overworld.PlayerCorporationFunds -= Settings.Overworld.InstanceSettings.CalculateLandValue(); foreach (var res in Settings.Overworld.InstanceSettings.InitalEmbarkment.Resources.Enumerate()) { AddResources(res); Settings.Overworld.PlayerCorporationResources.Remove(res); } var portBox = port.GetBoundingBox(); ComponentManager.RootComponent.AddChild(Balloon.CreateBalloon( portBox.Center() + new Vector3(0, 100, 0), portBox.Center() + new Vector3(0, 10, 0), ComponentManager, PlayerFaction)); foreach (var applicant in Settings.Overworld.InstanceSettings.InitalEmbarkment.Employees) { Settings.Overworld.PlayerCorporationFunds -= applicant.SigningBonus; HireImmediately(applicant); } Renderer.Camera.Target = portBox.Center(); Renderer.Camera.Position = Renderer.Camera.Target + new Vector3(0, 15, -15); }
public static void CastSunlightColumn(int X, int Z, ChunkGeneratorSettings Settings) { for (var y = (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1; y >= 0; y--) { var v = Settings.World.ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(X, y, Z)); if (!v.IsValid) { break; } v.Sunlight = true; v.RawSetIsExplored(); if (v.Type.ID != 0 && !v.Type.IsTransparent) { break; } else { foreach (var neighbor in VoxelHelpers.EnumerateManhattanNeighbors2D(v.Coordinate)) { var nv = Settings.World.ChunkManager.CreateVoxelHandle(neighbor); if (nv.IsValid) { nv.RawSetIsExplored(); } } } } }
public static void GenerateWater(VoxelChunk chunk, ChunkGeneratorSettings Settings) { var iceID = Library.GetVoxelType("Ice"); for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { if (Settings.Overworld.Map.GetBiomeAt(new Vector3(x, 0, z) + chunk.Origin.ToVector3(), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { var globalY = y + chunk.Origin.Y; if (globalY > Settings.NormalizedSeaLevel) { break; } var voxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (voxel.IsEmpty && voxel.Sunlight) { if (globalY == Settings.NormalizedSeaLevel && biome.WaterSurfaceIce) { voxel.RawSetType(iceID); } else { voxel.QuickSetLiquid(biome.WaterIsLava ? LiquidType.Lava : LiquidType.Water, WaterManager.maxWaterLevel); } } } } } } }
public static float GetAverageHeight(int X, int Z, int Width, int Height, ChunkGeneratorSettings Settings) { var avgHeight = 0; var numHeight = 0; for (var dx = 0; dx < Width; dx++) { for (var dz = 0; dz < Height; dz++) { var worldPos = new Vector3(X + dx, (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1, Z + dz); var baseVoxel = VoxelHelpers.FindFirstVoxelBelowIncludingWater(Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); if (!baseVoxel.IsValid) { continue; } avgHeight += baseVoxel.Coordinate.Y + 1; numHeight += 1; } } if (numHeight == 0) { return(0); } return(avgHeight / numHeight); }
public static void GenerateCaveFauna(VoxelHandle CaveFloor, BiomeData Biome, ChunkGeneratorSettings Settings) { var spawnLikelihood = (Settings.Overworld.Difficulty.CombatModifier + 0.1f); foreach (var animalType in Biome.Fauna) { if (!(MathFunctions.Random.NextDouble() < animalType.SpawnProbability * spawnLikelihood)) { continue; } var lambdaAnimalType = animalType; if (!GameSettings.Current.FogofWar) { EntityFactory.CreateEntity <GameComponent>(lambdaAnimalType.Name, CaveFloor.WorldPosition + new Vector3(0.5f, 1.5f, 0.5f)); } else { Settings.World.ComponentManager.RootComponent.AddChild(new SpawnOnExploredTrigger(Settings.World.ComponentManager, CaveFloor) { EntityToSpawn = lambdaAnimalType.Name, SpawnLocation = CaveFloor.WorldPosition + new Vector3(0.5f, 1.5f, 0.5f) }); } break; // Prevent spawning multiple animals in same spot. } }
public void CreateInitialEmbarkment(Generation.ChunkGeneratorSettings Settings) { PlayerFaction.Economy.Funds = Settings.Overworld.InstanceSettings.InitalEmbarkment.Funds; Settings.Overworld.PlayerCorporationFunds -= Settings.Overworld.InstanceSettings.InitalEmbarkment.Funds; Settings.Overworld.PlayerCorporationFunds -= Settings.Overworld.InstanceSettings.CalculateLandValue(); foreach (var res in Settings.Overworld.InstanceSettings.InitalEmbarkment.Resources.Enumerate()) { AddResources(res); Settings.Overworld.PlayerCorporationResources.Remove(res); } if (GenerateInitialBalloonPort(Renderer.Camera.Position.X, Renderer.Camera.Position.Z, 1, Settings).HasValue(out var port)) { var portBox = port.GetBoundingBox(); ComponentManager.RootComponent.AddChild(Balloon.CreateBalloon( // Bypassing the entity factory because we need to set the target. portBox.Center() + new Vector3(0, 10, 0), portBox.Center() + new Vector3(0, 10, 0), ComponentManager, PlayerFaction)); Renderer.Camera.Target = portBox.Center(); Renderer.Camera.Position = Renderer.Camera.Target + new Vector3(0, 15, -15); } foreach (var applicant in Settings.Overworld.InstanceSettings.InitalEmbarkment.Employees) { Settings.Overworld.PlayerCorporationFunds -= applicant.SigningBonus; HireImmediately(applicant); } }
public static void GenerateOres(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { var overworldPosition = OverworldMap.WorldToOverworld(new Vector2(x + Chunk.Origin.X, z + Chunk.Origin.Z), Settings.Overworld.InstanceSettings.Origin); var normalizedHeight = NormalizeHeight(Settings.Overworld.Map.LinearInterpolate(overworldPosition, OverworldField.Height)); var height = MathFunctions.Clamp(normalizedHeight * Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY, 0.0f, Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY - 2); for (int y = 0; y < VoxelConstants.ChunkSizeY; y++) { if (Chunk.Origin.Y + y >= height) { break; } if (Chunk.Origin.Y + y == 0) { continue; } var v = Chunk.Manager.CreateVoxelHandle(new GlobalVoxelCoordinate(Chunk.Origin.X + x, Chunk.Origin.Y + y, Chunk.Origin.Z + z)); if (v.Sunlight) { continue; } foreach (var voxelType in Library.EnumerateVoxelTypes()) { if (voxelType.SpawnClusters) { if (Chunk.Origin.Y + y < voxelType.MinSpawnHeight) { continue; } if (Chunk.Origin.Y + y > voxelType.MaxSpawnHeight) { continue; } var vRand = new Random(voxelType.ID); var noiseVector = new Vector3(Chunk.Origin.X + x, Chunk.Origin.Y + y, Chunk.Origin.Z + z) * Settings.CaveNoiseScale * 2.0f; noiseVector += new Vector3(vRand.Next(0, 64), vRand.Next(0, 64), vRand.Next(0, 64)); var fade = 1.0f - ((Chunk.Origin.Y + y - voxelType.MinSpawnHeight) / voxelType.MaxSpawnHeight); var oreNoise = Settings.CaveNoise.GetValue(noiseVector.X, noiseVector.Y, noiseVector.Z); if (Math.Abs(oreNoise) < voxelType.Rarity * fade) { v.RawSetType(voxelType); } } } } } } }
public static void CastSunlight(VoxelChunk TopChunk, ChunkGeneratorSettings Settings) { for (var x = TopChunk.Origin.X; x < TopChunk.Origin.X + VoxelConstants.ChunkSizeX; x++) { for (var z = TopChunk.Origin.Z; z < TopChunk.Origin.Z + VoxelConstants.ChunkSizeZ; z++) { CastSunlightColumn(x, z, Settings); } } }
private static void FillRuinColumn(ChunkGeneratorSettings Settings, MaybeNull <VoxelType> WallType, int gap, int wallHeight, VoxelHandle baseVoxel, float decay) { for (int dy = gap; dy < wallHeight * (1.0f - decay) && dy < (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 2; dy++) { var currVoxel = Settings.World.ChunkManager.CreateVoxelHandle(baseVoxel.Coordinate + new GlobalVoxelOffset(0, dy, 0)); if (currVoxel.IsValid) { currVoxel.RawSetType(WallType); } } }
private static void FillBelowRuins(ChunkGeneratorSettings Settings, MaybeNull <VoxelType> ruinWallType, VoxelHandle baseVoxel, VoxelHandle underVoxel) { for (int dy = 1; dy < (baseVoxel.Coordinate.Y - underVoxel.Coordinate.Y); dy++) { var currVoxel = Settings.World.ChunkManager.CreateVoxelHandle(underVoxel.Coordinate + new GlobalVoxelOffset(0, dy, 0)); if (!currVoxel.IsValid) { continue; } currVoxel.RawSetType(ruinWallType); } underVoxel.RawSetGrass(0); }
public static Zone GenerateInitialBalloonPort(float x, float z, int size, Generation.ChunkGeneratorSettings Settings) { var roomVoxels = Generation.Generator.GenerateBalloonPort(Settings.World.ChunkManager, x, z, size, Settings); // Actually create the BuildRoom. var toBuild = Library.CreateZone("Balloon Port", Settings.World); Settings.World.AddZone(toBuild); toBuild.CompleteRoomImmediately(roomVoxels.StockpileVoxels); var box = toBuild.GetBoundingBox(); var at = new Vector3((box.Min.X + box.Max.X - 1) / 2, box.Max.Y, (box.Min.Z + box.Max.Z - 1) / 2); var flag = EntityFactory.CreateEntity <Flag>("Flag", at + new Vector3(0.5f, 0.5f, 0.5f)); Settings.World.PlayerFaction.OwnedObjects.Add(flag); return(toBuild); }
public static void GenerateLava(VoxelChunk chunk, ChunkGeneratorSettings Settings) { if (chunk.Origin.Y >= Settings.LavaLevel) { return; } for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { for (var y = 0; y < Settings.LavaLevel - chunk.Origin.Y; ++y) { var voxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (voxel.IsEmpty && voxel.LiquidLevel == 0) { voxel.QuickSetLiquid(LiquidType.Lava, WaterManager.maxWaterLevel); } } } } }
private void CreateNewWorld() { SetLoadingMessage("Creating Sky..."); Renderer.Sky = new SkyRenderer(); #region Initialize static data bool actionComplete = false; Game.DoLazyAction(new Action(() => { Renderer.InstanceRenderer = new InstanceRenderer(); Renderer.bloom = new BloomComponent(Game) { Settings = BloomSettings.PresetSettings[5] }; Renderer.bloom.Initialize(); SoundManager.Content = Content; if (PlanService != null) { PlanService.Restart(); } MonsterSpawner = new MonsterSpawner(this); EntityFactory.Initialize(this); }), () => { actionComplete = true; return(true); }); while (!actionComplete) { Thread.Sleep(10); } #endregion SetLoadingMessage("Creating Planner ..."); PlanService = new PlanService(); SetLoadingMessage("Creating Liquids ..."); #region liquids Renderer.WaterRenderer = new WaterRenderer(GraphicsDevice); #endregion #region Load Components // Create updateable systems. foreach (var updateSystemFactory in AssetManager.EnumerateModHooks(typeof(UpdateSystemFactoryAttribute), typeof(EngineModule), new Type[] { typeof(WorldManager) })) { UpdateSystems.Add(updateSystemFactory.Invoke(null, new Object[] { this }) as EngineModule); } Time = new WorldTime(); Renderer.Camera = new OrbitCamera(this, // Todo: Is setting the camera position and target redundant here? new Vector3(VoxelConstants.ChunkSizeX, WorldSizeInVoxels.Y - 1.0f, VoxelConstants.ChunkSizeZ), new Vector3(VoxelConstants.ChunkSizeX, WorldSizeInVoxels.Y - 1.0f, VoxelConstants.ChunkSizeZ) + Vector3.Up * 10.0f + Vector3.Backward * 10, MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 0.1f, GameSettings.Default.VertexCullDistance); PersistentData = new PersistentWorldData(); ChunkManager = new ChunkManager(Content, this); Splasher = new Splasher(ChunkManager); Renderer.ChunkRenderer = new ChunkRenderer(ChunkManager); Renderer.Camera.Position = new Vector3(0, 10, 0) + new Vector3(WorldSizeInChunks.X * VoxelConstants.ChunkSizeX, 0, WorldSizeInChunks.Z * VoxelConstants.ChunkSizeZ) * 0.5f; Renderer.Camera.Target = new Vector3(0, 10, 1) + new Vector3(WorldSizeInChunks.X * VoxelConstants.ChunkSizeX, 0, WorldSizeInChunks.Z * VoxelConstants.ChunkSizeZ) * 0.5f; ComponentManager = new ComponentManager(this); ComponentManager.SetRootComponent(new GameComponent(ComponentManager, "root", Matrix.Identity, Vector3.Zero, Vector3.Zero)); #region Prepare Factions Factions = new FactionSet(); //Factions.Initialize(this, Settings.Company); foreach (var faction in Overworld.Natives) { Factions.AddFaction(new Faction(this, faction)); } Point playerOrigin = new Point((int)(Overworld.InstanceSettings.Origin.X), (int)(Overworld.InstanceSettings.Origin.Y)); PlayerFaction = Factions.Factions["Player"]; PlayerFaction.Economy = new Company(PlayerFaction, 300.0m, Overworld.Company); #endregion EventScheduler = new Events.Scheduler(); TutorialManager = new Tutorial.TutorialManager(); TutorialManager.TutorialEnabled = !GameSettings.Default.TutorialDisabledGlobally; Tutorial("new game start"); foreach (var item in Library.EnumerateCraftables()) { if (!String.IsNullOrEmpty(item.Tutorial)) { TutorialManager.AddTutorial(item.Name, item.Tutorial, item.Icon); } } Renderer.Camera.World = this; //Drawer3D.Camera = Camera; #endregion SetLoadingMessage("Creating Particles ..."); Game.DoLazyAction(new Action(() => ParticleManager = new ParticleManager(ComponentManager))); SetLoadingMessage("Creating GameMaster ..."); TaskManager = new TaskManager(); TaskManager.World = this; Time.NewDay += (time) => PayEmployees(); var generatorSettings = new Generation.ChunkGeneratorSettings(MathFunctions.Random.Next(), 0.02f, Overworld) { WorldSizeInChunks = WorldSizeInChunks, SetLoadingMessage = SetLoadingMessage, World = this }; SetLoadingMessage("Generating Chunks..."); Generation.Generator.Generate(Overworld.InstanceSettings.Cell.Bounds, ChunkManager, this, generatorSettings, SetLoadingMessage); CreateInitialEmbarkment(generatorSettings); ChunkManager.NeedsMinimapUpdate = true; ChunkManager.RecalculateBounds(); if (PlayerFaction.Economy.Information == null) { throw new InvalidProgramException(); } if (MathFunctions.RandEvent(0.01f)) { SetLoadingMessage("Reticulating Splines..."); } ChunkManager.StartThreads(); SetLoadingMessage("Presimulating ..."); ShowingWorld = false; OnLoadedEvent(); Thread.Sleep(1000); ShowingWorld = true; SetLoadingMessage("Complete."); LoadStatus = LoadingStatus.Success; }
public static void GenerateSurfaceLife(VoxelChunk TopChunk, ChunkGeneratorSettings Settings) { var creatureCounts = new Dictionary <string, Dictionary <string, int> >(); var worldDepth = Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY; for (var x = TopChunk.Origin.X; x < TopChunk.Origin.X + VoxelConstants.ChunkSizeX; x++) { for (var z = TopChunk.Origin.Z; z < TopChunk.Origin.Z + VoxelConstants.ChunkSizeZ; z++) { var overworldPosition = OverworldMap.WorldToOverworld(new Vector2(x, z), Settings.Overworld.InstanceSettings.Origin); if (Settings.Overworld.Map.GetBiomeAt(new Vector3(x, 0, z), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { var normalizedHeight = NormalizeHeight(Settings.Overworld.Map.LinearInterpolate(overworldPosition, OverworldField.Height)); var height = (int)MathFunctions.Clamp(normalizedHeight * worldDepth, 0.0f, worldDepth - 2); var voxel = Settings.World.ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(x, height, z)); if (!voxel.IsValid || voxel.Coordinate.Y == 0 || voxel.Coordinate.Y >= worldDepth - Settings.TreeLine) { continue; } if (voxel.LiquidLevel != 0) { continue; } var above = VoxelHelpers.GetVoxelAbove(voxel); if (above.IsValid && (above.LiquidLevel != 0 || !above.IsEmpty)) { continue; } foreach (var animal in biome.Fauna) { if (MathFunctions.RandEvent(animal.SpawnProbability)) { if (!creatureCounts.ContainsKey(biome.Name)) { creatureCounts[biome.Name] = new Dictionary <string, int>(); } var dict = creatureCounts[biome.Name]; if (!dict.ContainsKey(animal.Name)) { dict[animal.Name] = 0; } if (dict[animal.Name] < animal.MaxPopulation) { EntityFactory.CreateEntity <GameComponent>(animal.Name, voxel.WorldPosition + Vector3.Up * 1.5f); } break; } } if (voxel.Type.Name != biome.SoilLayer.VoxelType) { continue; } foreach (VegetationData veg in biome.Vegetation) { if (voxel.GrassType == 0) { continue; } if (MathFunctions.RandEvent(veg.SpawnProbability) && Settings.NoiseGenerator.Noise(voxel.Coordinate.X / veg.ClumpSize, veg.NoiseOffset, voxel.Coordinate.Z / veg.ClumpSize) >= veg.ClumpThreshold) { var treeSize = MathFunctions.Rand() * veg.SizeVariance + veg.MeanSize; EntityFactory.CreateEntity <Plant>(veg.Name, voxel.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f), Blackboard.Create("Scale", treeSize)); break; } } } } } }
private static CaveGenerationData GetCaveGenerationData(GlobalVoxelCoordinate At, int LayerIndex, ChunkGeneratorSettings Settings) { var frequency = LayerIndex < Settings.CaveFrequencies.Count ? Settings.CaveFrequencies[LayerIndex] : Settings.CaveFrequencies[Settings.CaveFrequencies.Count - 1]; var noiseVector = At.ToVector3() * Settings.CaveNoiseScale * new Vector3(frequency, 3.0f, frequency); var noise = Settings.CaveNoise.GetValue(noiseVector.X, noiseVector.Y, noiseVector.Z); var heightVector = At.ToVector3() * Settings.NoiseScale * new Vector3(frequency, 3.0f, frequency); var height = Settings.NoiseGenerator.Noise(heightVector); return(new CaveGenerationData { CaveHere = noise > Settings.CaveSize, Noise = noise, Height = Math.Min(Math.Max((int)(height * Settings.CaveHeightScaleFactor), 1), Settings.MaxCaveHeight) }); }
public static void GenerateCaves(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { if (Library.GetBiome("Cave").HasValue(out BiomeData caveBiome) && Library.GetBiome("Hell").HasValue(out BiomeData hellBiome)) { for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { for (int i = 0; i < Settings.CaveLevels.Count; i++) { // Does layer intersect this voxel? int y = Settings.CaveLevels[i]; if (y + Settings.MaxCaveHeight < Chunk.Origin.Y) { continue; } if (y >= Chunk.Origin.Y + VoxelConstants.ChunkSizeY) { continue; } var coordinate = new GlobalVoxelCoordinate(Chunk.Origin.X + x, y, Chunk.Origin.Z + z); var data = GetCaveGenerationData(coordinate, i, Settings); var biome = (y <= Settings.HellLevel) ? hellBiome : caveBiome; if (!data.CaveHere) { continue; } for (int dy = 0; dy < data.Height; dy++) { var globalY = y + dy; // Prevent caves punching holes in bedrock. if (globalY <= 0) { continue; } // Check if voxel is inside chunk. if (globalY <= 0 || globalY < Chunk.Origin.Y || globalY >= Chunk.Origin.Y + VoxelConstants.ChunkSizeY) { continue; } var voxel = VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(x, globalY - Chunk.Origin.Y, z)); // Prevent caves from breaking surface. bool caveBreaksSurface = false; foreach (var neighborCoordinate in VoxelHelpers.EnumerateAllNeighbors(voxel.Coordinate)) { var v = Chunk.Manager.CreateVoxelHandle(neighborCoordinate); if (!v.IsValid || (v.Sunlight)) { caveBreaksSurface = true; break; } } if (caveBreaksSurface) { break; } voxel.RawSetType(Library.EmptyVoxelType); if (dy == 0) { // Place soil voxel and grass below cave. var below = VoxelHelpers.GetVoxelBelow(voxel); if (below.IsValid) { below.RawSetType(Library.GetVoxelType(biome.SoilLayer.VoxelType)); var grassType = Library.GetGrassType(biome.GrassDecal); if (grassType != null) { below.RawSetGrass(grassType.ID); } } // Spawn flora and fauna. if (data.Noise > Settings.CaveSize * 1.8f && globalY > Settings.LavaLevel) { GenerateCaveFlora(below, biome, Settings); GenerateCaveFauna(below, biome, Settings); } } } } } } } }
private static void GenerateCaveFlora(VoxelHandle CaveFloor, BiomeData Biome, ChunkGeneratorSettings Settings) { foreach (var floraType in Biome.Vegetation) { if (!MathFunctions.RandEvent(floraType.SpawnProbability)) { continue; } if (Settings.NoiseGenerator.Noise(CaveFloor.Coordinate.X / floraType.ClumpSize, floraType.NoiseOffset, CaveFloor.Coordinate.Z / floraType.ClumpSize) < floraType.ClumpThreshold) { continue; } var plantSize = MathFunctions.Rand() * floraType.SizeVariance + floraType.MeanSize; var lambdaFloraType = floraType; if (!GameSettings.Current.FogofWar) { EntityFactory.CreateEntity <GameComponent>( lambdaFloraType.Name, CaveFloor.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f), Blackboard.Create("Scale", plantSize)); } else { Settings.World.ComponentManager.RootComponent.AddChild(new SpawnOnExploredTrigger(Settings.World.ComponentManager, CaveFloor) { EntityToSpawn = lambdaFloraType.Name, SpawnLocation = CaveFloor.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f), BlackboardData = Blackboard.Create("Scale", plantSize) }); } break; // Don't risk spawning multiple plants in the same spot. } }
public static MaybeNull <Zone> GenerateInitialBalloonPort(float x, float z, int size, Generation.ChunkGeneratorSettings Settings) { var roomVoxels = Generation.Generator.GenerateBalloonPort(Settings.World.ChunkManager, x, z, size, Settings); if (Library.CreateZone("Balloon Port", Settings.World).HasValue(out var zone)) { Settings.World.AddZone(zone); zone.CompleteRoomImmediately(roomVoxels.StockpileVoxels); var box = zone.GetBoundingBox(); var at = new Vector3((box.Min.X + box.Max.X - 1) / 2, box.Max.Y, (box.Min.Z + box.Max.Z - 1) / 2); var flag = EntityFactory.CreateEntity <Flag>("Flag", at + new Vector3(0.5f, 0.5f, 0.5f)); Settings.World.PlayerFaction.OwnedObjects.Add(flag); return(zone); } else { return(null); } }
public static VoxelChunk GenerateChunk(GlobalChunkCoordinate ID, ChunkGeneratorSettings Settings) { var origin = new GlobalVoxelCoordinate(ID, new LocalVoxelCoordinate(0, 0, 0)); var worldDepth = Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY; var waterHeight = NormalizeHeight(Settings.Overworld.GenerationSettings.SeaLevel + 1.0f / worldDepth); var c = new VoxelChunk(Settings.World.ChunkManager, ID); if (GameSettings.Current.NoStone) { return(c); } for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { var overworldPosition = OverworldMap.WorldToOverworld(new Vector2(x + origin.X, z + origin.Z), Settings.Overworld.InstanceSettings.Origin); if (Settings.Overworld.Map.GetBiomeAt(new Vector3(x + origin.X, 0, z + origin.Z), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biomeData)) { var normalizedHeight = NormalizeHeight(Settings.Overworld.Map.LinearInterpolate(overworldPosition, OverworldField.Height)); var height = MathFunctions.Clamp(normalizedHeight * worldDepth, 0.0f, worldDepth - 2); var stoneHeight = (int)MathFunctions.Clamp((int)(height - (biomeData.SoilLayer.Depth + (Math.Sin(overworldPosition.X) + Math.Cos(overworldPosition.Y)))), 1, height); for (int y = 0; y < VoxelConstants.ChunkSizeY; y++) { var globalY = origin.Y + y; var voxel = VoxelHandle.UnsafeCreateLocalHandle(c, new LocalVoxelCoordinate(x, y, z)); if (globalY == 0) { voxel.RawSetType(Library.GetVoxelType("Bedrock")); continue; } // Below the stone line, use subsurface layers. if (globalY <= stoneHeight && stoneHeight > 1) { var depth = stoneHeight - globalY - biomeData.SubsurfaceLayers[0].Depth + 1; var subsurfaceLayer = 0; while (depth > 0 && subsurfaceLayer < biomeData.SubsurfaceLayers.Count - 1) { depth -= biomeData.SubsurfaceLayers[subsurfaceLayer].Depth; subsurfaceLayer += 1; } voxel.RawSetType(Library.GetVoxelType(biomeData.SubsurfaceLayers[subsurfaceLayer].VoxelType)); } // Otherwise, on the surface. else if ((globalY == (int)height || globalY == stoneHeight) && normalizedHeight > waterHeight) { voxel.RawSetType(Library.GetVoxelType(biomeData.SoilLayer.VoxelType)); if (!String.IsNullOrEmpty(biomeData.GrassDecal)) { if (!biomeData.ClumpGrass || (biomeData.ClumpGrass && Settings.NoiseGenerator.Noise(overworldPosition.X / biomeData.ClumpSize, 0, overworldPosition.Y / biomeData.ClumpSize) > biomeData.ClumpTreshold)) { voxel.RawSetGrass(Library.GetGrassType(biomeData.GrassDecal).ID); } } } else if (globalY > height && globalY > 0) { voxel.RawSetType(Library.EmptyVoxelType); } else if (normalizedHeight <= waterHeight) { voxel.RawSetType(Library.GetVoxelType(biomeData.ShoreVoxel)); } else { voxel.RawSetType(Library.GetVoxelType(biomeData.SoilLayer.VoxelType)); } } } } } return(c); }
public static IEnumerable <VoxelChunk> EnumerateTopChunks(ChunkGeneratorSettings Settings) { return(Settings.World.ChunkManager.GetChunkEnumerator().Where(c => c.ID.Y == Settings.WorldSizeInChunks.Y - 1)); }
public static void GenerateRuin(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { var noiseVector = Chunk.Origin.ToVector3() * Settings.CaveNoiseScale; var ruinsNoise = Settings.CaveNoise.GetValue(noiseVector.X, noiseVector.Y, noiseVector.Z); if (Math.Abs(ruinsNoise) > GameSettings.Default.GenerationRuinsRate) { return; } int structureWidth = MathFunctions.RandInt(4, 16); int structureDepth = MathFunctions.RandInt(4, 16); int xOffset = MathFunctions.RandInt(0, VoxelConstants.ChunkSizeX - structureWidth); int zOffset = MathFunctions.RandInt(0, VoxelConstants.ChunkSizeZ - structureDepth); int wallHeight = MathFunctions.RandInt(2, 6); int heightOffset = MathFunctions.RandInt(-4, 2); if (Settings.Overworld.Map.GetBiomeAt(Chunk.Origin.ToVector3(), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { var avgHeight = GetAverageHeight(Chunk.Origin.X, Chunk.Origin.Z, structureWidth, structureDepth, Settings); bool[] doors = new bool[4]; for (int k = 0; k < 4; k++) { doors[k] = MathFunctions.RandEvent(0.5f); } for (int dx = 0; dx < structureWidth; dx++) { for (int dz = 0; dz < structureDepth; dz++) { var worldPos = new Vector3(Chunk.Origin.X + dx + xOffset, avgHeight + heightOffset, Chunk.Origin.Z + dz + zOffset); var baseVoxel = Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos)); var underVoxel = VoxelHelpers.FindFirstVoxelBelow(Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); var decay = Settings.NoiseGenerator.Generate(worldPos.X * 0.05f, worldPos.Y * 0.05f, worldPos.Z * 0.05f); if (decay > 0.7f) { continue; } if (!baseVoxel.IsValid) { continue; } if (baseVoxel.Coordinate.Y == (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1) { continue; } if (!underVoxel.IsValid) { continue; } var edge = (dx == 0 || dx == structureWidth - 1) || (dz == 0 || dz == structureDepth - 1); if (!edge && !baseVoxel.IsEmpty) { continue; } if (edge) { baseVoxel.RawSetType(Library.GetVoxelType(biome.RuinWallType)); } else { baseVoxel.RawSetType(Library.GetVoxelType(biome.RuinFloorType)); } bool[] wallState = new bool[4]; wallState[0] = dx == 0; wallState[1] = dx == structureWidth - 1; wallState[2] = dz == 0; wallState[3] = dz == structureDepth - 1; bool[] doorState = new bool[4]; doorState[0] = Math.Abs(dz - structureDepth / 2) < 1; doorState[1] = doorState[0]; doorState[2] = Math.Abs(dx - structureWidth / 2) < 1; doorState[3] = doorState[2]; for (int dy = 1; dy < (baseVoxel.Coordinate.Y - underVoxel.Coordinate.Y); dy++) { var currVoxel = Settings.World.ChunkManager.CreateVoxelHandle(underVoxel.Coordinate + new GlobalVoxelOffset(0, dy, 0)); if (!currVoxel.IsValid) { continue; } currVoxel.RawSetType(underVoxel.Type); } underVoxel.RawSetGrass(0); if (edge) { for (int dy = 1; dy < wallHeight * (1.0f - decay) && dy < (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 2; dy++) { var currVoxel = Settings.World.ChunkManager.CreateVoxelHandle(baseVoxel.Coordinate + new GlobalVoxelOffset(0, dy, 0)); if (!currVoxel.IsValid) { continue; } if (currVoxel.Coordinate.Y == VoxelConstants.ChunkSizeY - 1) { continue; } bool door = false; for (int k = 0; k < 4; k++) { if (wallState[k] && doors[k] && doorState[k]) { door = true; break; } } if (door && dy < 3) { continue; } currVoxel.RawSetType(Library.GetVoxelType(biome.RuinWallType)); } } } } } }
public static BalloonPortVoxelSets GenerateBalloonPort(ChunkManager chunkManager, float x, float z, int size, ChunkGeneratorSettings Settings) { var centerCoordinate = GlobalVoxelCoordinate.FromVector3(new Vector3(x, (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1, z)); var averageHeight = (int)GetAverageHeight(centerCoordinate.X - size, centerCoordinate.Y - size, size * 2 + 1, size * 2 + 1, Settings); // Next, create the balloon port by deciding which voxels to fill. var balloonPortDesignations = new List <VoxelHandle>(); for (int dx = -size; dx <= size; dx++) { for (int dz = -size; dz <= size; dz++) { var worldPos = new Vector3(centerCoordinate.X + dx, centerCoordinate.Y, centerCoordinate.Z + dz); var baseVoxel = VoxelHelpers.FindFirstVoxelBelow(chunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); if (!baseVoxel.IsValid) { continue; } var h = baseVoxel.Coordinate.Y + 1; for (int y = averageHeight; y < h && y < chunkManager.World.WorldSizeInVoxels.Y; y++) { var v = chunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(baseVoxel.Coordinate.X, y, baseVoxel.Coordinate.Z)); v.RawSetType(Library.EmptyVoxelType); v.RawSetIsExplored(); v.QuickSetLiquid(LiquidType.None, 0); } if (averageHeight < h) { h = averageHeight; } bool isPosX = (dx == size && dz == 0); bool isPosZ = (dz == size & dx == 0); bool isNegX = (dx == -size && dz == 0); bool isNegZ = (dz == -size && dz == 0); bool isSide = (isPosX || isNegX || isPosZ || isNegZ); Vector3 offset = Vector3.Zero; if (isSide) { if (isPosX) { offset = Vector3.UnitX; } else if (isPosZ) { offset = Vector3.UnitZ; } else if (isNegX) { offset = -Vector3.UnitX; } else if (isNegZ) { offset = -Vector3.UnitZ; } } // Fill from the top height down to the bottom. for (int y = Math.Max(0, h - 1); y < averageHeight && y < chunkManager.World.WorldSizeInVoxels.Y; y++) { var v = chunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(baseVoxel.Coordinate.X, y, baseVoxel.Coordinate.Z)); if (!v.IsValid) { throw new InvalidProgramException("Voxel was invalid while creating a new game's initial zones. This should not happen."); } v.RawSetType(Library.GetVoxelType("Scaffold")); v.IsPlayerBuilt = true; v.QuickSetLiquid(LiquidType.None, 0); v.Sunlight = false; if (y == averageHeight - 1) { v.RawSetIsExplored(); balloonPortDesignations.Add(v); } if (isSide) { var ladderPos = new Vector3(worldPos.X, y, worldPos.Z) + offset + Vector3.One * 0.5f; var ladderVox = chunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(ladderPos)); if (ladderVox.IsValid && ladderVox.IsEmpty) { var ladder = EntityFactory.CreateEntity <Ladder>("Ladder", ladderPos); Settings.World.PlayerFaction.OwnedObjects.Add(ladder); ladder.Tags.Add("Moveable"); ladder.Tags.Add("Deconstructable"); } } } CastSunlightColumn(baseVoxel.Coordinate.X, baseVoxel.Coordinate.Z, Settings); } } return(new BalloonPortVoxelSets { StockpileVoxels = balloonPortDesignations, }); }
public static void Generate(Rectangle spawnRect, ChunkManager ChunkData, WorldManager World, ChunkGeneratorSettings Settings, Action <String> SetLoadingMessage) { SetLoadingMessage(String.Format("{0} chunks to generate!", Settings.WorldSizeInChunks.X * Settings.WorldSizeInChunks.Y * Settings.WorldSizeInChunks.Z)); SetLoadingMessage(""); for (int dx = 0; dx < Settings.WorldSizeInChunks.X; dx++) { for (int dy = 0; dy < Settings.WorldSizeInChunks.Y; dy++) { for (int dz = 0; dz < Settings.WorldSizeInChunks.Z; dz++) { SetLoadingMessage(String.Format("#Generating chunk {0} {1} {2}...", dx, dy, dz)); ChunkData.AddChunk(GenerateChunk(new GlobalChunkCoordinate(dx, dy, dz), Settings)); } } } var worldDepth = Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY; Settings.NormalizedSeaLevel = Math.Min((int)(worldDepth * NormalizeHeight(Settings.Overworld.GenerationSettings.SeaLevel + 1.0f / worldDepth)), worldDepth - 1); SetLoadingMessage(""); foreach (var chunk in EnumerateTopChunks(Settings)) { SetLoadingMessage(String.Format("#Casting light in chunk {0} {1} {2}...", chunk.ID.X, chunk.ID.Y, chunk.ID.Z)); CastSunlight(chunk, Settings); GenerateRuin(chunk, Settings); } // Todo: Can these be sped up by doing multiple in one iteration of the outer x,z? if (!GameSettings.Default.FastGen) { SetLoadingMessage(""); foreach (var chunk in ChunkData.ChunkMap) { SetLoadingMessage(String.Format("#Generating caves, ore, water in chunk {0} {1} {2}...", chunk.ID.X, chunk.ID.Y, chunk.ID.Z)); GenerateOres(chunk, Settings); GenerateCaves(chunk, Settings); GenerateWater(chunk, Settings); GenerateLava(chunk, Settings); } } SetLoadingMessage(""); foreach (var chunk in EnumerateTopChunks(Settings)) { SetLoadingMessage(String.Format("#Spawning life in chunk {0} {1} {2}...", chunk.ID.X, chunk.ID.Y, chunk.ID.Z)); GenerateSurfaceLife(chunk, Settings); ChunkData.EnqueueInvalidColumn(chunk.ID.X, chunk.ID.Z); } }
public static void GenerateRuin(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { // Todo: Support ruins deep underground - empty out their interiors. LoadRuinTemplates(); var noiseVector = Chunk.Origin.ToVector3() * Settings.CaveNoiseScale; var ruinsNoise = Settings.CaveNoise.GetValue(noiseVector.X, noiseVector.Y, noiseVector.Z); if (Math.Abs(ruinsNoise) > GameSettings.Current.GenerationRuinsRate) { return; } var avgHeight = GetAverageHeight(Chunk.Origin.X, Chunk.Origin.Z, 16, 16, Settings); var ruinWallType = Library.GetVoxelType("Cobble"); // Todo: Should make this data so this doesn't break if tile names change? var ruinFloorType = Library.GetVoxelType("Blue Tile"); if (Settings.Overworld.Map.GetBiomeAt(Chunk.Origin.ToVector3(), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { ruinWallType = Library.GetVoxelType(biome.RuinWallType); ruinFloorType = Library.GetVoxelType(biome.RuinFloorType); } if (!ruinWallType.HasValue() || !ruinFloorType.HasValue()) { return; } int wallHeight = MathFunctions.RandInt(2, 6); var template = RuinTemplates[MathFunctions.RandInt(0, RuinTemplates.Count)]; var rotations = MathFunctions.RandInt(0, 3); for (var i = 0; i < rotations; ++i) { template = TextureTool.RotatedCopy(template); } for (int dx = 0; dx < 16; dx++) { for (int dz = 0; dz < 16; dz++) { var worldPos = new Vector3(Chunk.Origin.X + dx, avgHeight, Chunk.Origin.Z + dz); var baseVoxel = Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos)); var underVoxel = VoxelHelpers.FindFirstVoxelBelow(Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); var decay = Settings.NoiseGenerator.Generate(worldPos.X * 0.05f, worldPos.Y * 0.05f, worldPos.Z * 0.05f); if (decay > 0.7f) { continue; } if (!baseVoxel.IsValid) { continue; } if (baseVoxel.Coordinate.Y == (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1) { continue; } if (!underVoxel.IsValid) { continue; } var templateColor = template.Data[template.Index(dx, dz)]; if (templateColor == new Color(0, 0, 255, 255)) // Border { continue; } else if (templateColor == new Color(0, 0, 0, 255)) // Space { continue; } else if (templateColor == new Color(255, 0, 0, 255)) // Wall { baseVoxel.RawSetType(ruinWallType); FillBelowRuins(Settings, ruinWallType, baseVoxel, underVoxel); FillRuinColumn(Settings, ruinWallType, 1, wallHeight, baseVoxel, decay); } else if (templateColor == new Color(128, 128, 0, 255)) // Door { baseVoxel.RawSetType(ruinWallType); FillBelowRuins(Settings, ruinWallType, baseVoxel, underVoxel); FillRuinColumn(Settings, ruinWallType, 3, wallHeight, baseVoxel, decay); } else if (templateColor == new Color(128, 0, 0, 255)) // Floor { FillBelowRuins(Settings, ruinWallType, baseVoxel, underVoxel); baseVoxel.RawSetType(ruinFloorType); } } } }
public static MaybeNull <Zone> GenerateInitialBalloonPort(float x, float z, int size, Generation.ChunkGeneratorSettings Settings) { var roomVoxels = Generation.Generator.GenerateBalloonPort(Settings.World.ChunkManager, x, z, size, Settings); if (Library.CreateZone("Balloon Port", Settings.World).HasValue(out var zone)) { Settings.World.AddZone(zone); zone.CompleteRoomImmediately(roomVoxels.StockpileVoxels); var box = zone.GetBoundingBox(); var at = new Vector3((box.Min.X + box.Max.X) / 2, box.Max.Y + 0.5f, (box.Min.Z + box.Max.Z) / 2); var flag = new Flag(Settings.World.ComponentManager, at, Settings.World.PlayerFaction.Economy.Information, new Resource("Flag")); Settings.World.PlayerFaction.OwnedObjects.Add(flag); flag.Tags.Add("Deconstructable"); return(zone); } else { return(null); } }