private static void BuildVoxelTopFaceGeometry( RawPrimitive Into, VoxelChunk Chunk, Cache Cache, BoxPrimitive Primitive, VoxelHandle V, BoxPrimitive.BoxTextureCoords UVs, int i) { var face = (BoxFace)i; var delta = FaceDeltas[i]; var faceVoxel = new VoxelHandle(Chunk.Manager, V.Coordinate + GlobalVoxelOffset.FromVector3(delta)); if (!IsFaceVisible(V, faceVoxel, face)) { return; } var faceDescriptor = Primitive.GetFace(face); int exploredVerts = 0; var vertexColors = new VertexColorInfo[4]; var vertexTint = new Color[4]; // Find all verticies to use for geometry later, and for the fringe var vertexPositions = new Vector3[4]; for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; faceVertex++) { var vertex = Primitive.Vertices[faceDescriptor.VertexOffset + faceVertex]; var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var rampOffset = Vector3.Zero; if (V.IsExplored && V.Type.CanRamp && ShouldRamp(voxelVertex, V.RampType)) { rampOffset = new Vector3(0, -V.Type.RampSize, 0); } var worldPosition = V.WorldPosition + vertex.Position + rampOffset; //worldPosition += VertexNoise.GetNoiseVectorFromRepeatingTexture(worldPosition); vertexPositions[faceVertex] = worldPosition; } if (V.IsExplored) { exploredVerts = 4; } else { for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; ++faceVertex) { var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var cacheKey = GetCacheKey(V, voxelVertex); bool anyNeighborExplored = true; if (!Cache.ExploredCache.TryGetValue(cacheKey, out anyNeighborExplored)) { anyNeighborExplored = VoxelHelpers.EnumerateVertexNeighbors2D(V.Coordinate, voxelVertex) .Select(c => new VoxelHandle(V.Chunk.Manager, c)) .Any(n => n.IsValid && n.IsExplored); Cache.ExploredCache.Add(cacheKey, anyNeighborExplored); } if (anyNeighborExplored) { exploredVerts += 1; } } } for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; ++faceVertex) { var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var cacheKey = GetCacheKey(V, voxelVertex); VertexColorInfo vertexColor; if (!Cache.LightCache.TryGetValue(cacheKey, out vertexColor)) { vertexColor = CalculateVertexLight(V, voxelVertex, Chunk.Manager); Cache.LightCache.Add(cacheKey, vertexColor); } vertexColors[faceVertex] = vertexColor; vertexTint[faceVertex] = new Color(1.0f, 1.0f, 1.0f, 1.0f); if (exploredVerts != 4) { bool anyNeighborExplored = true; if (!Cache.ExploredCache.TryGetValue(cacheKey, out anyNeighborExplored)) { throw new InvalidProgramException("Failed cache lookup"); } if (!anyNeighborExplored) { vertexTint[faceVertex] = new Color(0.0f, 0.0f, 0.0f, 1.0f); } } vertexTint[faceVertex] = new Color(vertexTint[faceVertex].ToVector4() * V.Type.Tint.ToVector4()); } if (exploredVerts != 0) { var baseUVs = UVs.Uvs[11]; // EW var baseUVBounds = new Vector4(baseUVs.X + 0.001f, baseUVs.Y + 0.001f, baseUVs.X + (1.0f / 16.0f) - 0.001f, baseUVs.Y + (1.0f / 16.0f) - 0.001f); // Draw central top tile. AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, faceDescriptor, vertexPositions, vertexColors, vertexTint, Vector2.One, baseUVs, baseUVBounds); if (V.GrassType != 0) { BuildGrassFringeGeometry(Into, Chunk, Cache, Primitive, V, vertexColors, vertexTint, vertexPositions, faceDescriptor, exploredVerts); } } else { if (!Debugger.Switches.HideSliceTop) { var indexOffset = Into.VertexCount; for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; faceVertex++) { Into.AddVertex(new ExtendedVertex( vertexPositions[faceVertex] + VertexNoise.GetNoiseVectorFromRepeatingTexture(vertexPositions[faceVertex]), new Color(0, 0, 0, 255), new Color(0, 0, 0, 255), new Vector2(12.5f / 16.0f, 0.5f / 16.0f), new Vector4(12.0f / 16.0f, 0.0f, 13.0f / 16.0f, 1.0f / 16.0f))); } for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = Primitive.Indexes[idx]; ushort offset0 = Primitive.Indexes[faceDescriptor.IndexOffset]; Into.AddIndex((short)(indexOffset + offset - offset0)); } } } }
// This will loop through the whole world and draw out all liquid primatives that are handed to the function. public static void InitializePrimativesFromChunk(VoxelChunk chunk, List <LiquidPrimitive> primitivesToInit) { LiquidPrimitive[] lps = new LiquidPrimitive[(int)LiquidType.Count]; if (!AddCaches(primitivesToInit, ref lps)) { return; } LiquidType curLiqType = LiquidType.None; LiquidPrimitive curPrimitive = null; ExtendedVertex[] curVertices = null; ushort[] curIndexes = null; int[] maxVertices = new int[lps.Length]; int[] maxIndexes = new int[lps.Length]; int maxVertex = 0; int maxIndex = 0; int totalFaces = 6; bool fogOfWar = GameSettings.Default.FogofWar; for (int y = 0; y < Math.Min(chunk.Manager.World.Master.MaxViewingLevel + 1, VoxelConstants.ChunkSizeY); y++) { if (chunk.Data.LiquidPresent[y] == 0) { continue; } for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { var voxel = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (fogOfWar && !voxel.IsExplored) { continue; } if (voxel.LiquidLevel > 0) { var liqType = voxel.LiquidType; // We need to see if we changed types and should change the data we are writing to. if (liqType != curLiqType) { LiquidPrimitive newPrimitive = lps[(int)liqType]; // We weren't passed a LiquidPrimitive object to work with for this type so we'll skip it. if (newPrimitive == null) { continue; } maxVertices[(int)curLiqType] = maxVertex; maxIndexes[(int)curLiqType] = maxIndex; curVertices = newPrimitive.Vertices; curIndexes = newPrimitive.Indexes; curLiqType = liqType; curPrimitive = newPrimitive; maxVertex = maxVertices[(int)liqType]; maxIndex = maxIndexes[(int)liqType]; } int facesToDraw = 0; for (int i = 0; i < totalFaces; i++) { BoxFace face = (BoxFace)i; // We won't draw the bottom face. This might be needed down the line if we add transparent tiles like glass. if (face == BoxFace.Bottom) { continue; } var delta = faceDeltas[(int)face]; // Pull the current neighbor DestinationVoxel based on the face it would be touching. var vox = VoxelHelpers.GetNeighbor(voxel, delta); if (vox.IsValid) { if (face == BoxFace.Top) { if (!(vox.LiquidLevel == 0 || y == (int)chunk.Manager.World.Master.MaxViewingLevel)) { cache.drawFace[(int)face] = false; continue; } } else { if (vox.LiquidLevel != 0 || !vox.IsEmpty) { cache.drawFace[(int)face] = false; continue; } } } else { cache.drawFace[(int)face] = false; continue; } cache.drawFace[(int)face] = true; facesToDraw++; } // There's no faces to draw on this voxel. Let's go to the next one. if (facesToDraw == 0) { continue; } // Now we check to see if we need to resize the current Vertex array. int vertexSizeIncrease = facesToDraw * 4; int indexSizeIncrease = facesToDraw * 6; lock (curPrimitive.VertexLock) { // Check vertex array size if (curVertices == null) { curVertices = new ExtendedVertex[256]; curPrimitive.Vertices = curVertices; } else if (curVertices.Length <= maxVertex + vertexSizeIncrease) { ExtendedVertex[] newVerts = new ExtendedVertex[MathFunctions.NearestPowerOf2(maxVertex + vertexSizeIncrease)]; curVertices.CopyTo(newVerts, 0); curVertices = newVerts; curPrimitive.Vertices = curVertices; } // Check index array size if (curIndexes == null) { curIndexes = new ushort[256]; curPrimitive.Indexes = curIndexes; } else if (curIndexes.Length <= maxIndex + indexSizeIncrease) { ushort[] newIdxs = new ushort[MathFunctions.NearestPowerOf2(maxIndex + indexSizeIncrease)]; curIndexes.CopyTo(newIdxs, 0); curIndexes = newIdxs; curPrimitive.Indexes = curIndexes; } } // Now we have a list of all the faces that will need to be drawn. Let's draw them. CreateWaterFaces(voxel, chunk, x, y, z, curVertices, curIndexes, maxVertex, maxIndex); // Finally increase the size so we can move on. maxVertex += vertexSizeIncrease; maxIndex += indexSizeIncrease; } } } } // The last thing we need to do is make sure we set the current primative's maxVertices to the right value. maxVertices[(int)curLiqType] = maxVertex; maxIndexes[(int)curLiqType] = maxIndex; // Now actually force the VertexBuffer to be recreated in each primative we worked with. for (int i = 0; i < lps.Length; i++) { LiquidPrimitive updatedPrimative = lps[i]; if (updatedPrimative == null) { continue; } maxVertex = maxVertices[i]; maxIndex = maxIndexes[i]; if (maxVertex > 0) { try { lock (updatedPrimative.VertexLock) { updatedPrimative.VertexCount = maxVertex; updatedPrimative.IndexCount = maxIndex; updatedPrimative.VertexBuffer = null; updatedPrimative.IndexBuffer = null; } } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } else { try { lock (updatedPrimative.VertexLock) { updatedPrimative.VertexBuffer = null; updatedPrimative.Vertices = null; updatedPrimative.IndexBuffer = null; updatedPrimative.Indexes = null; updatedPrimative.VertexCount = 0; updatedPrimative.IndexCount = 0; } } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } } updatedPrimative.IsBuilding = false; } cache.inUse = false; cache = null; }
public BuildVoxelOrder(BuildZoneOrder Order, Zone ToBuild, VoxelHandle Voxel) { this.Order = Order; this.ToBuild = ToBuild; this.Voxel = Voxel; }
private static void UpdateChunk(VoxelChunk chunk) { var addGrassToThese = new List <Tuple <VoxelHandle, byte> >(); for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Skip empty slices. if (chunk.Data.VoxelsPresentInSlice[y] == 0) { continue; } for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { var voxel = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z)); // Allow grass to decay if (voxel.GrassType != 0) { var decal = GrassLibrary.GetGrassType(voxel.GrassType); if (decal.NeedsSunlight && voxel.SunColor < 255) { voxel.GrassType = 0; } else if (decal.Decay) { voxel.GrassDecay -= 1; if (voxel.GrassDecay == 0) { var newDecal = GrassLibrary.GetGrassType(decal.BecomeWhenDecays); if (newDecal != null) { voxel.GrassType = newDecal.ID; } else { voxel.GrassType = 0; } } } } else if (voxel.Type.GrassSpreadsHere) { // Spread grass onto this tile - but only from the same biome. var biome = Overworld.GetBiomeAt(voxel.Coordinate.ToVector3()); var grassyNeighbors = VoxelHelpers.EnumerateManhattanNeighbors2D(voxel.Coordinate) .Select(c => new VoxelHandle(voxel.Chunk.Manager.ChunkData, c)) .Where(v => v.IsValid && v.GrassType != 0) .Where(v => biome == Overworld.GetBiomeAt(v.Coordinate.ToVector3())) .ToList(); if (grassyNeighbors.Count > 0) { if (MathFunctions.RandEvent(0.1f)) { addGrassToThese.Add(Tuple.Create(voxel, grassyNeighbors[MathFunctions.RandInt(0, grassyNeighbors.Count)].GrassType)); } } } } } } foreach (var v in addGrassToThese) { var l = v.Item1; var grassType = GrassLibrary.GetGrassType(v.Item2); if (grassType.NeedsSunlight && l.SunColor != 255) { continue; } l.GrassType = v.Item2; } }
// Inverts GetMoveActions. So, returns the list of move actions whose target is the current voxel. // Very, very slow. public IEnumerable <MoveAction> GetInverseMoveActions(MoveState currentstate, List <GameComponent> teleportObjects) { if (Parent == null) { yield break; } if (Creature == null) { yield break; } var current = currentstate.Voxel; if (Can(MoveType.Teleport)) { foreach (var obj in teleportObjects) { if ((obj.Position - current.WorldPosition).LengthSquared() > 2) { continue; } for (int dx = -TeleportDistance; dx <= TeleportDistance; dx++) { for (int dz = -TeleportDistance; dz <= TeleportDistance; dz++) { for (int dy = -TeleportDistance; dy <= TeleportDistance; dy++) { if (dx * dx + dy * dy + dz * dz > TeleportDistanceSquared) { continue; } VoxelHandle teleportNeighbor = new VoxelHandle(Parent.World.ChunkManager, current.Coordinate + new GlobalVoxelOffset(dx, dy, dz)); var adjacent = VoxelHelpers.GetNeighbor(teleportNeighbor, new GlobalVoxelOffset(0, -1, 0)); if (teleportNeighbor.IsValid && teleportNeighbor.IsEmpty && adjacent.IsValid && adjacent.IsEmpty) { yield return(new MoveAction() { InteractObject = obj, Diff = new Vector3(dx, dx, dz), SourceVoxel = teleportNeighbor, DestinationState = currentstate, MoveType = MoveType.Teleport, CostMultiplier = 1.0f }); } } } } } } var storage = new MoveActionTempStorage(); foreach (var v in VoxelHelpers.EnumerateCube(current.Coordinate) .Select(n => new VoxelHandle(current.Chunk.Manager, n)) .Where(h => h.IsValid)) { foreach (var a in GetMoveActions(new MoveState() { Voxel = v }, teleportObjects, storage).Where(a => a.DestinationState == currentstate)) { yield return(a); } if (!Can(MoveType.RideVehicle)) { continue; } // Now that dwarfs can ride vehicles, the inverse of the move actions becomes extremely complicated. We must now // iterate through all rails intersecting every neighbor and see if we can find a connection from that rail to this one. // Further, we must iterate through the entire rail network and enumerate all possible directions in and out of that rail. // Yay! // Actually - why not just not bother with rails when inverse pathing, since it should only be invoked when forward pathing fails anyway? // Also NOT hacking in inverse elevators! /* * var bodies = new HashSet<GameComponent>(); * OctTree.EnumerateItems(v.GetBoundingBox(), bodies); * * var rails = bodies.OfType<Rail.RailEntity>().Where(r => r.Active); * foreach (var rail in rails) * { * if (rail.GetContainingVoxel() != v) * continue; * * foreach (var neighborRail in rail.NeighborRails.Select(neighbor => Creature.Manager.FindComponent(neighbor.NeighborID) as Rail.RailEntity)) * { * var actions = GetMoveActions(new MoveState() * { * Voxel = v, * VehicleType = VehicleTypes.Rail, * Rail = rail, * PrevRail = neighborRail * }, OctTree, teleportObjects, storage); * foreach (var a in actions.Where(a => a.DestinationState == currentstate)) * { * yield return a; * } * } * * foreach (var a in GetMoveActions(new MoveState() { Voxel = v, VehicleType = VehicleTypes.Rail, Rail = rail, PrevRail = null }, OctTree, teleportObjects, storage).Where(a => a.DestinationState == currentstate)) * yield return a; * } */ } }
public void SetTarget(VoxelHandle target) { Agent.Blackboard.SetData(TargetName, target); }
private static void UpdateChunk(VoxelChunk chunk) { var addGrassToThese = new List <Tuple <VoxelHandle, byte> >(); for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Skip empty slices. if (chunk.Data.VoxelsPresentInSlice[y] == 0) { continue; } for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x) { for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z) { var voxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); // Allow grass to decay if (voxel.GrassType != 0) { var grass = Library.GetGrassType(voxel.GrassType); if (grass.NeedsSunlight && !voxel.Sunlight) { voxel.GrassType = 0; } else if (grass.Decay) { if (voxel.GrassDecay == 0) { var newDecal = Library.GetGrassType(grass.BecomeWhenDecays); if (newDecal != null) { voxel.GrassType = newDecal.ID; } else { voxel.GrassType = 0; } } else { voxel.GrassDecay -= 1; } } } //#if false else if (voxel.Type.GrassSpreadsHere) { // Spread grass onto this tile - but only from the same biome. // Don't spread if there's an entity here. var entityPresent = chunk.Manager.World.EnumerateIntersectingObjects( new BoundingBox(voxel.WorldPosition + new Vector3(0.1f, 1.1f, 0.1f), voxel.WorldPosition + new Vector3(0.9f, 1.9f, 0.9f)), CollisionType.Static).Any(); if (entityPresent) { continue; } var biome = chunk.Manager.World.Overworld.Map.GetBiomeAt(voxel.Coordinate.ToVector3(), chunk.Manager.World.Overworld.InstanceSettings.Origin); var grassyNeighbors = VoxelHelpers.EnumerateManhattanNeighbors2D(voxel.Coordinate) .Select(c => new VoxelHandle(voxel.Chunk.Manager, c)) .Where(v => v.IsValid && v.GrassType != 0) .Where(v => Library.GetGrassType(v.GrassType).Spreads) .Where(v => biome == chunk.Manager.World.Overworld.Map.GetBiomeAt(v.Coordinate.ToVector3(), chunk.Manager.World.Overworld.InstanceSettings.Origin)) .ToList(); if (grassyNeighbors.Count > 0) { if (MathFunctions.RandEvent(0.1f)) { addGrassToThese.Add(Tuple.Create(voxel, grassyNeighbors[MathFunctions.RandInt(0, grassyNeighbors.Count)].GrassType)); } } } //#endif } } } foreach (var v in addGrassToThese) { var l = v.Item1; var grassType = Library.GetGrassType(v.Item2); if (grassType.NeedsSunlight && !l.Sunlight) { continue; } l.GrassType = v.Item2; } }
private void DiscreteUpdate(ChunkManager ChunkManager, VoxelChunk chunk) { for (var y = 0; y < VoxelConstants.ChunkSizeY; ++y) { // Apply 'liquid present' tracking in voxel data to skip entire slices. if (chunk.Data.LiquidPresent[y] == 0) { continue; } var layerOrder = SlicePermutations[MathFunctions.RandInt(0, SlicePermutations.Length)]; for (var i = 0; i < layerOrder.Length; ++i) { var x = layerOrder[i] % VoxelConstants.ChunkSizeX; var z = (layerOrder[i] >> VoxelConstants.XDivShift) % VoxelConstants.ChunkSizeZ; var currentVoxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z)); if (currentVoxel.TypeID != 0) { continue; } if (currentVoxel.LiquidType == LiquidType.None || currentVoxel.LiquidLevel < 1) { continue; } // Evaporate. if (currentVoxel.LiquidLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f)) { if (currentVoxel.LiquidType == LiquidType.Lava && Library.GetVoxelType("Stone").HasValue(out VoxelType stone)) { currentVoxel.Type = stone; } NeedsMinimapUpdate = true; currentVoxel.QuickSetLiquid(LiquidType.None, 0); continue; } var voxBelow = ChunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(currentVoxel.Coordinate.X, currentVoxel.Coordinate.Y - 1, currentVoxel.Coordinate.Z)); if (voxBelow.IsValid && voxBelow.IsEmpty) { // Fall into the voxel below. // Special case: No liquid below, just drop down. if (voxBelow.LiquidType == LiquidType.None) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType); voxBelow.QuickSetLiquid(currentVoxel.LiquidType, currentVoxel.LiquidLevel); currentVoxel.QuickSetLiquid(LiquidType.None, 0); continue; } var belowType = voxBelow.LiquidType; var aboveType = currentVoxel.LiquidType; var spaceLeftBelow = maxWaterLevel - voxBelow.LiquidLevel; if (spaceLeftBelow >= currentVoxel.LiquidLevel) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType); voxBelow.LiquidLevel += currentVoxel.LiquidLevel; currentVoxel.QuickSetLiquid(LiquidType.None, 0); HandleLiquidInteraction(voxBelow, aboveType, belowType); continue; } if (spaceLeftBelow > 0) { NeedsMinimapUpdate = true; CreateSplash(currentVoxel.Coordinate.ToVector3(), aboveType); currentVoxel.LiquidLevel = (byte)(currentVoxel.LiquidLevel - maxWaterLevel + voxBelow.LiquidLevel); voxBelow.LiquidLevel = maxWaterLevel; HandleLiquidInteraction(voxBelow, aboveType, belowType); continue; } } else if (voxBelow.IsValid && currentVoxel.LiquidType == LiquidType.Lava && !voxBelow.IsEmpty && voxBelow.GrassType > 0) { voxBelow.GrassType = 0; } if (currentVoxel.LiquidLevel <= 1) { continue; } // Nothing left to do but spread. RollArray(NeighborPermutations[MathFunctions.RandInt(0, NeighborPermutations.Length)], NeighborScratch, MathFunctions.RandInt(0, 4)); for (var n = 0; n < NeighborScratch.Length; ++n) { var neighborOffset = VoxelHelpers.ManhattanNeighbors2D[NeighborScratch[n]]; var neighborVoxel = new VoxelHandle(Chunks, currentVoxel.Coordinate + neighborOffset); if (neighborVoxel.IsValid && neighborVoxel.IsEmpty) { if (neighborVoxel.LiquidLevel < currentVoxel.LiquidLevel) { NeedsMinimapUpdate = true; var amountToMove = (int)(currentVoxel.LiquidLevel * GetSpreadRate(currentVoxel.LiquidType)); if (neighborVoxel.LiquidLevel + amountToMove > maxWaterLevel) { amountToMove = maxWaterLevel - neighborVoxel.LiquidLevel; } if (amountToMove > 2) { CreateSplash(neighborVoxel.Coordinate.ToVector3(), currentVoxel.LiquidType); } var newWater = currentVoxel.LiquidLevel - amountToMove; var sourceType = currentVoxel.LiquidType; var destType = neighborVoxel.LiquidType; currentVoxel.QuickSetLiquid(newWater == 0 ? LiquidType.None : sourceType, (byte)newWater); neighborVoxel.QuickSetLiquid(destType == LiquidType.None ? sourceType : destType, (byte)(neighborVoxel.LiquidLevel + amountToMove)); HandleLiquidInteraction(neighborVoxel, sourceType, destType); break; } } } } } }
public void GenerateCaves(VoxelChunk chunk, WorldManager world) { Vector3 origin = chunk.Origin; BiomeData biome = BiomeLibrary.GetBiome("Cave"); for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { var topVoxel = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle( chunk, new LocalVoxelCoordinate(x, VoxelConstants.ChunkSizeY - 1, z))); for (int i = 0; i < CaveLevels.Count; i++) { int y = CaveLevels[i]; if (y <= 0 || y >= topVoxel.Coordinate.Y) { continue; } Vector3 vec = new Vector3(x, y, z) + chunk.Origin; double caveNoise = CaveNoise.GetValue((x + origin.X) * CaveNoiseScale * CaveFrequencies[i], (y + origin.Y) * CaveNoiseScale * 3.0f, (z + origin.Z) * CaveNoiseScale * CaveFrequencies[i]); double heightnoise = NoiseGenerator.Noise((x + origin.X) * NoiseScale * CaveFrequencies[i], (y + origin.Y) * NoiseScale * 3.0f, (z + origin.Z) * NoiseScale * CaveFrequencies[i]); int caveHeight = Math.Min(Math.Max((int)(heightnoise * 5), 1), 3); if (!(caveNoise > CaveSize)) { continue; } bool invalidCave = false; for (int dy = 0; dy < caveHeight; dy++) { if (y - dy <= 0) { continue; } var voxel = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y - dy, z)); foreach (var coord in VoxelHelpers.EnumerateAllNeighbors(voxel.Coordinate)) { VoxelHandle v = new VoxelHandle(Manager.ChunkData, coord); if (v.IsValid && (v.WaterCell.WaterLevel > 0 || v.SunColor > 0)) { invalidCave = true; break; } } if (!invalidCave) { voxel.RawSetType(VoxelLibrary.emptyType); } else { break; } } if (!invalidCave && caveNoise > CaveSize * 1.8f && y - caveHeight > 0) { GenerateCaveVegetation(chunk, x, y, z, caveHeight, biome, vec, world, NoiseGenerator); GenerateCaveFauna(chunk, world, biome, y - caveHeight, x, z); } } } } /* * // Second pass sets the caves to empty as needed * for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) * { * for (int y = 0; y < VoxelConstants.ChunkSizeY; y++) * { * for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) * { * VoxelHandle handle = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y, z)); * if (handle.Type == magicCube) * { * handle.RawSetType(VoxelLibrary.emptyType); * } * } * } * } */ }
public BuildVoxelOrder GetBuildDesignation(VoxelHandle v) { return(BuildDesignations.SelectMany(room => room.VoxelOrders).FirstOrDefault(buildDesignation => buildDesignation.Voxel == v)); }
public bool IsInStockpile(VoxelHandle v) { return(Stockpiles.Any(s => s.ContainsVoxel(v))); }
public bool IsBuildDesignation(VoxelHandle v) { return(BuildDesignations.SelectMany(room => room.VoxelOrders).Any(buildDesignation => buildDesignation.Voxel == v)); }
public bool IsInRoom(VoxelHandle v) { return(DesignatedRooms.Any(r => r.ContainsVoxel(v)) || Faction.IsInStockpile(v)); }
private static void BuildGrassFringeGeometry( RawPrimitive Into, VoxelChunk Chunk, Cache Cache, BoxPrimitive Primitive, VoxelHandle V, VertexColorInfo[] VertexColors, Color[] VertexTint, Vector3[] VertexPositions, BoxPrimitive.FaceDescriptor Face, int ExploredVerts) { if (V.GrassType == 0) { return; } var decalType = Library.GetGrassType(V.GrassType); AddGrassGeometry(Into, Cache.AmbientValues, Primitive, V, Face, ExploredVerts, VertexPositions, VertexColors, VertexTint, decalType); // Draw fringe if (decalType.FringeTransitionUVs == null) { return; } for (var s = 0; s < 4; ++s) { var neighborCoord = V.Coordinate + VoxelHelpers.ManhattanNeighbors2D[s]; var neighbor = new VoxelHandle(Chunk.Manager, neighborCoord); if (!neighbor.IsValid) { continue; } var aboveNeighbor = new VoxelHandle(Chunk.Manager, neighborCoord + new GlobalVoxelOffset(0, 1, 0)); if (!aboveNeighbor.IsValid || aboveNeighbor.IsEmpty) { // Draw horizontal fringe. if (!neighbor.IsEmpty) { if (neighbor.GrassType != 0 && Library.GetGrassType(neighbor.GrassType).FringePrecedence >= decalType.FringePrecedence) { continue; } } // Twizzle vertex positions. var newPositions = new Vector3[4]; newPositions[FringeIndicies[s, 0]] = VertexPositions[FringeIndicies[s, 4]]; newPositions[FringeIndicies[s, 1]] = VertexPositions[FringeIndicies[s, 4]] + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * 0.5f); newPositions[FringeIndicies[s, 2]] = VertexPositions[FringeIndicies[s, 5]] + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * 0.5f); newPositions[FringeIndicies[s, 3]] = VertexPositions[FringeIndicies[s, 5]]; var newColors = new VertexColorInfo[4]; newColors[FringeIndicies[s, 0]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 1]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 2]] = VertexColors[FringeIndicies[s, 5]]; newColors[FringeIndicies[s, 3]] = VertexColors[FringeIndicies[s, 5]]; var slopeTweak = new Vector3(0.0f, 0.0f, 0.0f); if (neighbor.IsEmpty) { slopeTweak.Y = -0.5f; } else { slopeTweak.Y = 0.125f; } newPositions[FringeIndicies[s, 1]] += slopeTweak; newPositions[FringeIndicies[s, 2]] += slopeTweak; var newTints = new Color[4]; newTints[FringeIndicies[s, 0]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 1]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 2]] = VertexTint[FringeIndicies[s, 5]]; newTints[FringeIndicies[s, 3]] = VertexTint[FringeIndicies[s, 5]]; AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, Face, newPositions, newColors, newTints, SideFringeUVScales[s], decalType.FringeTransitionUVs[s].UV, decalType.FringeTransitionUVs[s].Bounds); } else { // Draw vertical fringe! var newPositions = new Vector3[4]; newPositions[FringeIndicies[s, 0]] = VertexPositions[FringeIndicies[s, 4]]; newPositions[FringeIndicies[s, 1]] = VertexPositions[FringeIndicies[s, 4]] + new Vector3(0.0f, 0.5f, 0.0f) + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * -0.05f); newPositions[FringeIndicies[s, 2]] = VertexPositions[FringeIndicies[s, 5]] + new Vector3(0.0f, 0.5f, 0.0f) + (VoxelHelpers.ManhattanNeighbors2D[s].AsVector3() * -0.05f); newPositions[FringeIndicies[s, 3]] = VertexPositions[FringeIndicies[s, 5]]; var newColors = new VertexColorInfo[4]; newColors[FringeIndicies[s, 0]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 1]] = VertexColors[FringeIndicies[s, 4]]; newColors[FringeIndicies[s, 2]] = VertexColors[FringeIndicies[s, 5]]; newColors[FringeIndicies[s, 3]] = VertexColors[FringeIndicies[s, 5]]; var newTints = new Color[4]; newTints[FringeIndicies[s, 0]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 1]] = VertexTint[FringeIndicies[s, 4]]; newTints[FringeIndicies[s, 2]] = VertexTint[FringeIndicies[s, 5]]; newTints[FringeIndicies[s, 3]] = VertexTint[FringeIndicies[s, 5]]; AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, Face, newPositions, newColors, newTints, SideFringeUVScales[s], decalType.FringeTransitionUVs[s].UV, decalType.FringeTransitionUVs[s].Bounds); } } for (var s = 0; s < 4; ++s) { var neighborCoord = V.Coordinate + VoxelHelpers.DiagonalNeighbors2D[s]; var handle = new VoxelHandle(Chunk.Manager, neighborCoord); if (handle.IsValid) { if (!handle.IsEmpty) { if (handle.GrassType != 0 && Library.GetGrassType(handle.GrassType).FringePrecedence >= decalType.FringePrecedence) { continue; } } var manhattanA = new VoxelHandle(Chunk.Manager, V.Coordinate + VoxelHelpers.ManhattanNeighbors2D[s]); if (!manhattanA.IsValid || (manhattanA.GrassType == V.GrassType)) { continue; } manhattanA = new VoxelHandle(Chunk.Manager, V.Coordinate + VoxelHelpers.ManhattanNeighbors2D[FringeIndicies[4 + s, 5]]); if (!manhattanA.IsValid || (manhattanA.GrassType == V.GrassType)) { continue; } // Twizzle vertex positions. var newPositions = new Vector3[4]; var pivot = VertexPositions[FringeIndicies[4 + s, 4]]; var nDelta = VoxelHelpers.DiagonalNeighbors2D[s].AsVector3(); newPositions[FringeIndicies[4 + s, 0]] = pivot; newPositions[FringeIndicies[4 + s, 1]] = pivot + new Vector3(nDelta.X * 0.5f, 0, 0); newPositions[FringeIndicies[4 + s, 2]] = pivot + new Vector3(nDelta.X * 0.5f, 0, nDelta.Z * 0.5f); newPositions[FringeIndicies[4 + s, 3]] = pivot + new Vector3(0, 0, nDelta.Z * 0.5f); var slopeTweak = new Vector3(0.0f, 0.0f, 0.0f); if (handle.IsEmpty) { slopeTweak.Y = -0.5f; } else { slopeTweak.Y = 0.125f; } newPositions[FringeIndicies[4 + s, 1]] += slopeTweak; newPositions[FringeIndicies[4 + s, 2]] += slopeTweak; newPositions[FringeIndicies[4 + s, 3]] += slopeTweak; var newColors = new VertexColorInfo[4]; newColors[FringeIndicies[4 + s, 0]] = VertexColors[FringeIndicies[4 + s, 4]]; newColors[FringeIndicies[4 + s, 1]] = VertexColors[FringeIndicies[4 + s, 4]]; newColors[FringeIndicies[4 + s, 2]] = VertexColors[FringeIndicies[4 + s, 4]]; newColors[FringeIndicies[4 + s, 3]] = VertexColors[FringeIndicies[4 + s, 4]]; var newTints = new Color[4]; newTints[FringeIndicies[4 + s, 0]] = VertexTint[FringeIndicies[4 + s, 4]]; newTints[FringeIndicies[4 + s, 1]] = VertexTint[FringeIndicies[4 + s, 4]]; newTints[FringeIndicies[4 + s, 2]] = VertexTint[FringeIndicies[4 + s, 4]]; newTints[FringeIndicies[4 + s, 3]] = VertexTint[FringeIndicies[4 + s, 4]]; AddTopFaceGeometry(Into, Cache.AmbientValues, Primitive, Face, newPositions, newColors, newTints, new Vector2(0.5f, 0.5f), decalType.FringeTransitionUVs[4 + s].UV, decalType.FringeTransitionUVs[4 + s].Bounds); } } }
public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { var body = Parent as Body; System.Diagnostics.Debug.Assert(body != null); Vector3 targetVelocity = TargetPosition - body.GlobalTransform.Translation; if (targetVelocity.LengthSquared() > 0.0001f) { targetVelocity.Normalize(); targetVelocity *= MaxVelocity; } Matrix m = body.LocalTransform; m.Translation += targetVelocity * (float)gameTime.ElapsedGameTime.TotalSeconds; body.LocalTransform = m; body.HasMoved = true; switch (State) { case BalloonState.DeliveringGoods: { var voxel = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(body.GlobalTransform.Translation)); if (voxel.IsValid) { var surfaceVoxel = VoxelHelpers.FindFirstVoxelBelow(voxel); var height = surfaceVoxel.Coordinate.Y + 1; TargetPosition = new Vector3(body.GlobalTransform.Translation.X, height + 5, body.GlobalTransform.Translation.Z); Vector3 diff = body.GlobalTransform.Translation - TargetPosition; if (diff.LengthSquared() < 2) { State = BalloonState.Waiting; } } else { State = BalloonState.Leaving; } } break; case BalloonState.Leaving: TargetPosition = Vector3.UnitY * 100 + body.GlobalTransform.Translation; if (body.GlobalTransform.Translation.Y > 65) { Die(); } break; case BalloonState.Waiting: TargetPosition = body.GlobalTransform.Translation; if (!shipmentGiven) { shipmentGiven = true; } else { State = BalloonState.Leaving; } break; } }
public static void GenerateCaveVegetation(VoxelChunk chunk, int x, int y, int z, int caveHeight, BiomeData biome, Vector3 vec, WorldManager world, Perlin NoiseGenerator) { var vUnder = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y - 1, z)); var wayUnder = new VoxelHandle(chunk, new LocalVoxelCoordinate(x, y - caveHeight, z)); wayUnder.RawSetType(VoxelLibrary.GetVoxelType(biome.SoilLayer.VoxelType)); wayUnder.RawSetGrass(GrassLibrary.GetGrassType(biome.GrassDecal).ID); foreach (VegetationData veg in biome.Vegetation) { if (!MathFunctions.RandEvent(veg.SpawnProbability)) { continue; } if (NoiseGenerator.Noise(vec.X / veg.ClumpSize, veg.NoiseOffset, vec.Y / veg.ClumpSize) < veg.ClumpThreshold) { continue; } if (!vUnder.IsEmpty && vUnder.Type.Name == biome.SoilLayer.VoxelType) { vUnder.RawSetType(VoxelLibrary.GetVoxelType(biome.SoilLayer.VoxelType)); vUnder.RawSetGrass(0); float treeSize = MathFunctions.Rand() * veg.SizeVariance + veg.MeanSize; EntityFactory.DoLazy(() => { if (!GameSettings.Default.FogofWar) { GameComponent entity = EntityFactory.CreateEntity <GameComponent>(veg.Name, vUnder.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f), Blackboard.Create("Scale", treeSize)); } else { world.ComponentManager.RootComponent.AddChild(new ExploredListener( world.ComponentManager, world.ChunkManager, vUnder) { EntityToSpawn = veg.Name, SpawnLocation = vUnder.WorldPosition + new Vector3(0.5f, 1.0f, 0.5f), BlackboardData = Blackboard.Create("Scale", treeSize) }); } }); } } foreach (FaunaData animal in biome.Fauna) { if (y <= 0 || !(MathFunctions.Random.NextDouble() < animal.SpawnProbability)) { continue; } FaunaData animal1 = animal; EntityFactory.DoLazy(() => { if (!GameSettings.Default.FogofWar) { var entity = EntityFactory.CreateEntity <GameComponent>(animal1.Name, wayUnder.WorldPosition + Vector3.Up * 1.5f); } else { world.ComponentManager.RootComponent.AddChild(new ExploredListener (world.ComponentManager, world.ChunkManager, new VoxelHandle(chunk, wayUnder.Coordinate.GetLocalVoxelCoordinate())) { EntityToSpawn = animal1.Name, SpawnLocation = wayUnder.WorldPosition + Vector3.Up * 1.5f }); } }); break; } }
public void Update(ParticleManager manager, DwarfTime gameTime, ChunkManager chunks, Camera camera) { ParticleEmitter._camera = camera; List <Particle> toRemove = new List <Particle>(); TriggerTimer.Update(gameTime); if (TriggerTimer.HasTriggered && Data.ParticlesPerFrame > 0) { Trigger(Data.ParticlesPerFrame, Vector3.Zero, new Color(255, 255, 0)); } bool particlePhysics = GameSettings.Default.ParticlePhysics; foreach (Particle p in Particles) { float vel = p.Velocity.LengthSquared(); if (Data.EmitsLight && p.Scale > 0.1f) { DynamicLight.TempLights.Add(new DynamicLight(10.0f, 255.0f, false) { Position = p.Position }); } p.Position += p.Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds; if (Data.RotatesWithVelocity) { Vector3 cameraVel = camera.Project(p.Velocity + camera.Position); float projectionX = cameraVel.X; float projectionY = cameraVel.Y; p.Angle = (float)Math.Atan2(projectionY, projectionX); } else { p.Angle += (float)(p.AngularVelocity * gameTime.ElapsedGameTime.TotalSeconds); } if (!Data.Sleeps || vel > 0.01f) { p.Velocity += Data.ConstantAccel * (float)gameTime.ElapsedGameTime.TotalSeconds; } p.Velocity *= Data.LinearDamping; p.AngularVelocity *= Data.AngularDamping; if (!Data.UseManualControl) { p.LifeRemaining -= Data.ParticleDecay * (float)gameTime.ElapsedGameTime.TotalSeconds; } else if (p.TimeAlive > 60) { p.LifeRemaining = 0; } p.Scale += Data.GrowthSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; p.Scale = Math.Max(p.Scale, 0.0f); var v = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(p.Position)); if (Data.HasLighting) { if (v.IsValid) { p.LightRamp = new Color(v.Sunlight ? 255 : 0, 255, 0); } } else { p.LightRamp = new Color(255, 255, 0); } if (Data.CollidesWorld && particlePhysics && vel > 0.2f) { if (v.IsValid && !v.IsEmpty) { BoundingBox b = new BoundingBox(p.Position - Vector3.One * p.Scale * 0.5f, p.Position + Vector3.One * p.Scale * 0.5f); BoundingBox vBox = v.GetBoundingBox(); Physics.Contact contact = new Physics.Contact(); if (Physics.TestStaticAABBAABB(b, vBox, ref contact)) { p.Position += contact.NEnter * contact.Penetration; Vector3 newVelocity = Vector3.Reflect(p.Velocity, -contact.NEnter); p.Velocity = newVelocity * Data.Damping; p.AngularVelocity *= 0.5f; if (Data.Sleeps) { p.Velocity = Vector3.Zero; p.AngularVelocity = 0.0f; vel = 0.0f; } if (!String.IsNullOrEmpty(Data.SpatterType)) { var above = VoxelHelpers.GetVoxelAbove(v); if (!above.IsValid || above.IsEmpty) { float x = MathFunctions.Clamp(p.Position.X, vBox.Min.X + 0.1f, vBox.Max.X - 0.1f); float z = MathFunctions.Clamp(p.Position.Z, vBox.Min.Z + 0.1f, vBox.Max.Z - 0.1f); manager.Create(Data.SpatterType, VertexNoise.Warp(new Vector3(x, v.RampType == RampType.None ? v.WorldPosition.Y + 1.02f : v.WorldPosition.Y + 0.6f, z)), Vector3.Zero, Color.White, Vector3.Up); } else { manager.Create(Data.SpatterType, p.Position - contact.NEnter * contact.Penetration * 0.95f, Vector3.Zero, Color.White, contact.NEnter); } p.LifeRemaining = -1.0f; } } } } if (p.LifeRemaining < 0) { if (p.InstanceData != null) { p.InstanceData.ShouldDraw = false; p.InstanceData.Transform = Matrix.CreateTranslation(camera.Position + new Vector3(-1000, -1000, -1000)); Sprites[p.Frame].Remove(p.InstanceData); } toRemove.Add(p); } else if (p.InstanceData != null) { p.TimeAlive += (float)gameTime.ElapsedGameTime.TotalSeconds + MathFunctions.Rand() * 0.01f; int prevFrame = p.Frame; int newFrame = AnimPlayer.GetFrame(p.TimeAlive); if (vel < 0.2f && Data.Sleeps) { newFrame = prevFrame; } if (newFrame != prevFrame) { p.Frame = newFrame; if (Sprites.Count > 0) { Sprites[prevFrame].Remove(p.InstanceData); Sprites[newFrame].Add(p.InstanceData); } if (/*!Data.Animation.Loops && */ p.Frame == Data.Animation.Frames.Count - 1) { p.LifeRemaining *= 0.1f; } } p.InstanceData.ShouldDraw = true; p.InstanceData.Transform = MatrixFromParticle(Data, p); p.InstanceData.LightRamp = p.LightRamp; } } foreach (Particle p in toRemove) { Particles.Remove(p); } foreach (var sprites in Sprites) { sprites.Update(gameTime, camera, GameState.Game.GraphicsDevice, chunks.World.Master.MaxViewingLevel); } }
public VoxelChunk GenerateChunk(Vector3 origin, WorldManager World) { float waterHeight = SeaLevel + 1.0f / VoxelConstants.ChunkSizeY; VoxelChunk c = new VoxelChunk(Manager, origin, GlobalVoxelCoordinate.FromVector3(origin).GetGlobalChunkCoordinate()); for (int x = 0; x < VoxelConstants.ChunkSizeX; x++) { for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++) { Vector2 v = new Vector2(x + origin.X, z + origin.Z) / WorldScale; var biome = Overworld.Map[(int)MathFunctions.Clamp(v.X, 0, Overworld.Map.GetLength(0) - 1), (int)MathFunctions.Clamp(v.Y, 0, Overworld.Map.GetLength(1) - 1)].Biome; BiomeData biomeData = BiomeLibrary.Biomes[biome]; Vector2 pos = new Vector2(x + origin.X, z + origin.Z) / WorldScale; float hNorm = Overworld.LinearInterpolate(pos, Overworld.Map, Overworld.ScalarFieldType.Height); float h = MathFunctions.Clamp(hNorm * VoxelConstants.ChunkSizeY, 0.0f, VoxelConstants.ChunkSizeY - 2); int stoneHeight = (int)(MathFunctions.Clamp((int)(h - (biomeData.SoilLayer.Depth + (Math.Sin(v.X) + Math.Cos(v.Y)))), 1, h)); int currentSubsurfaceLayer = 0; int depthWithinSubsurface = 0; for (int y = VoxelConstants.ChunkSizeY - 1; y >= 0; y--) { var voxel = new VoxelHandle(c, new LocalVoxelCoordinate(x, y, z)); if (y == 0) { voxel.RawSetType(VoxelLibrary.GetVoxelType("Bedrock")); voxel.Health = 255; // ? continue; } if (y <= stoneHeight && stoneHeight > 1) { voxel.RawSetType(VoxelLibrary.GetVoxelType(biomeData.SubsurfaceLayers[currentSubsurfaceLayer].VoxelType)); depthWithinSubsurface++; if (depthWithinSubsurface > biomeData.SubsurfaceLayers[currentSubsurfaceLayer].Depth) { depthWithinSubsurface = 0; currentSubsurfaceLayer++; if (currentSubsurfaceLayer > biomeData.SubsurfaceLayers.Count - 1) { currentSubsurfaceLayer = biomeData.SubsurfaceLayers.Count - 1; } } } else if ((y == (int)h || y == stoneHeight) && hNorm > waterHeight) { if (biomeData.ClumpGrass && NoiseGenerator.Noise(pos.X / biomeData.ClumpSize, 0, pos.Y / biomeData.ClumpSize) > biomeData.ClumpTreshold) { voxel.RawSetType(VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType)); if (!String.IsNullOrEmpty(biomeData.GrassDecal)) { var decal = GrassLibrary.GetGrassType(biomeData.GrassDecal); voxel.RawSetGrass(decal.ID); } } else if (!biomeData.ClumpGrass) { voxel.RawSetType(VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType)); if (!String.IsNullOrEmpty(biomeData.GrassDecal)) { var decal = GrassLibrary.GetGrassType(biomeData.GrassDecal); voxel.RawSetGrass(decal.ID); } } else { voxel.RawSetType(VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType)); } } else if (y > h && y > 0) { voxel.RawSetType(VoxelLibrary.emptyType); } else if (hNorm <= waterHeight) { voxel.RawSetType(VoxelLibrary.GetVoxelType(biomeData.ShoreVoxel)); } else { voxel.RawSetType(VoxelLibrary.GetVoxelType(biomeData.SoilLayer.VoxelType)); } } } } GenerateWater(c); GenerateLava(c); UpdateSunlight(c, 255); return(c); }
private bool ValidatePlanting(VoxelHandle voxel) { if (!voxel.Type.IsSoil) { World.UserInterface.ShowTooltip("Can only plant on soil!"); return(false); } if (Library.GetResourceType(PlantType).Tags.Contains(Resource.ResourceTags.AboveGroundPlant)) { if (voxel.Sunlight == false) { World.UserInterface.ShowTooltip("Can only plant " + PlantType + " above ground."); return(false); } } else if (Library.GetResourceType(PlantType).Tags.Contains(Resource.ResourceTags.BelowGroundPlant)) { if (voxel.Sunlight) { World.UserInterface.ShowTooltip("Can only plant " + PlantType + " below ground."); return(false); } } if (World.PersistentData.Designations.GetVoxelDesignation(voxel, DesignationType.Plant).HasValue(out var designation)) { World.UserInterface.ShowTooltip("You're already planting here."); return(false); } var boundingBox = new BoundingBox(voxel.Coordinate.ToVector3() + new Vector3(0.2f, 0.2f, 0.2f), voxel.Coordinate.ToVector3() + new Vector3(0.8f, 0.8f, 0.8f)); var entities = World.EnumerateIntersectingObjects(boundingBox, CollisionType.Static).OfType <IVoxelListener>(); if (entities.Any()) { if (Debugger.Switches.DrawToolDebugInfo) { Drawer3D.DrawBox(boundingBox, Color.Red, 0.03f, false); foreach (var entity in entities) { Drawer3D.DrawBox((entity as GameComponent).GetBoundingBox(), Color.Yellow, 0.03f, false); } } World.UserInterface.ShowTooltip("There's something in the way."); return(false); } var voxelBox = voxel.GetBoundingBox().Expand(-0.2f); if (World.EnumerateZones().Where(room => room.Intersects(voxelBox)).Any()) { World.UserInterface.ShowTooltip("Can't plant inside zones."); return(false); } World.UserInterface.ShowTooltip("Click to plant."); return(true); }
public void Update() { MouseState mouse = Mouse.GetState(); KeyboardState keyboard = Keyboard.GetState(); var underMouse = GetVoxelUnderMouse(); // Keep track of whether a new voxel has been selected. bool newVoxel = underMouse.IsValid && underMouse != VoxelUnderMouse; if (!underMouse.IsValid) { return; } VoxelUnderMouse = underMouse; // Update the cursor light. World.CursorLightPos = underMouse.WorldPosition + new Vector3(0.5f, 0.5f, 0.5f); // Get the type of the voxel and display it to the player. if (Enabled && !underMouse.IsEmpty && underMouse.IsExplored) { string info = underMouse.Type.Name; // If it belongs to a room, display that information. if (World.PlayerFaction.RoomBuilder.IsInRoom(underMouse)) { Room room = World.PlayerFaction.RoomBuilder.GetMostLikelyRoom(underMouse); if (room != null) { info += " (" + room.ID + ")"; } } World.ShowInfo(info); } // Do nothing if not enabled. if (!Enabled) { return; } bool altPressed = false; // If the left or right ALT keys are pressed, we can adjust the height of the selection // for building pits and tall walls using the mouse wheel. if (keyboard.IsKeyDown(Keys.LeftAlt) || keyboard.IsKeyDown(Keys.RightAlt)) { var change = mouse.ScrollWheelValue - LastMouseWheel; BoxYOffset += (change) * 0.01f; int offset = (int)BoxYOffset; if (offset != PrevBoxYOffsetInt) { DragSound.Play(World.CursorLightPos); newVoxel = true; } PrevBoxYOffsetInt = offset; altPressed = true; } else { PrevBoxYOffsetInt = 0; } LastMouseWheel = mouse.ScrollWheelValue; // Draw a box around the current voxel under the mouse. if (underMouse.IsValid && DrawVoxel) { BoundingBox box = underMouse.GetBoundingBox().Expand(0.05f); Drawer3D.DrawBox(box, CurrentColor, CurrentWidth, true); } // If the left mouse button is pressed, update the slection buffer. if (isLeftPressed) { // On release, select voxels. if (mouse.LeftButton == ButtonState.Released) { ReleaseSound.Play(World.CursorLightPos); isLeftPressed = false; LeftReleasedCallback(); BoxYOffset = 0; PrevBoxYOffsetInt = 0; } // Otherwise, update the selection buffer else { if (SelectionBuffer.Count == 0) { FirstVoxel = underMouse; SelectionBuffer.Add(underMouse); } else { SelectionBuffer.Clear(); SelectionBuffer.Add(FirstVoxel); SelectionBuffer.Add(underMouse); BoundingBox buffer = GetSelectionBox(); // Update the selection box to account for offsets from mouse wheel. if (BoxYOffset > 0) { buffer.Max.Y += (int)BoxYOffset; } else if (BoxYOffset < 0) { buffer.Min.Y += (int)BoxYOffset; } SelectionBuffer = Select(buffer, FirstVoxel.WorldPosition, underMouse.WorldPosition).ToList(); if (!altPressed && Brush != VoxelBrush.Stairs) { if (SelectionType == VoxelSelectionType.SelectFilled) { SelectionBuffer.RemoveAll(v => { if (v.Equals(underMouse)) { return(false); } return(!VoxelHelpers.DoesVoxelHaveVisibleSurface(World, v)); }); } } if (newVoxel) { DragSound.Play(World.CursorLightPos, SelectionBuffer.Count / 20.0f); Dragged.Invoke(SelectionBuffer, InputManager.MouseButton.Left); } } } } // If the mouse was not previously pressed, but is now pressed, then notify us of that. else if (mouse.LeftButton == ButtonState.Pressed) { ClickSound.Play(World.CursorLightPos);; isLeftPressed = true; BoxYOffset = 0; PrevBoxYOffsetInt = 0; } // Case where the right mouse button is pressed (mirrors left mouse button) // TODO(Break this into a function) if (isRightPressed) { if (mouse.RightButton == ButtonState.Released) { ReleaseSound.Play(World.CursorLightPos); isRightPressed = false; RightReleasedCallback(); BoxYOffset = 0; PrevBoxYOffsetInt = 0; } else { if (SelectionBuffer.Count == 0) { SelectionBuffer.Add(underMouse); FirstVoxel = underMouse; } else { SelectionBuffer.Clear(); SelectionBuffer.Add(FirstVoxel); SelectionBuffer.Add(underMouse); BoundingBox buffer = GetSelectionBox(); if (BoxYOffset > 0) { buffer.Max.Y += (int)BoxYOffset; } else if (BoxYOffset < 0) { buffer.Min.Y += (int)BoxYOffset; } SelectionBuffer = VoxelHelpers.EnumerateCoordinatesInBoundingBox(buffer) .Select(c => new VoxelHandle(Chunks.ChunkData, c)) .Where(v => v.IsValid) .ToList(); if (newVoxel) { DragSound.Play(World.CursorLightPos, SelectionBuffer.Count / 20.0f); Dragged.Invoke(SelectionBuffer, InputManager.MouseButton.Right); } } } } else if (mouse.RightButton == ButtonState.Pressed) { ClickSound.Play(World.CursorLightPos); RightPressedCallback(); BoxYOffset = 0; isRightPressed = true; } }
public bool IsCameraUnderwater() { var handle = new VoxelHandle(ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(Camera.Position)); return(handle.IsValid && handle.WaterCell.WaterLevel > 0); }
private void Place(VoxelHandle Location) { var assignments = new List <Task>(); for (var i = 0; i < PreviewBodies.Count; ++i) { var body = PreviewBodies[i]; var piece = Pattern.Pieces[i]; var actualPosition = new VoxelHandle(Location.Chunk.Manager.ChunkData, Location.Coordinate + new GlobalVoxelOffset(piece.Offset.X, 0, piece.Offset.Y)); var addNewDesignation = true; foreach (var entity in Player.World.CollisionManager.EnumerateIntersectingObjects(actualPosition.GetBoundingBox().Expand(-0.2f), CollisionManager.CollisionType.Static)) { if (!addNewDesignation) { break; } if (Object.ReferenceEquals(entity, body)) { continue; } var possibleCombination = FindPossibleCombination(piece, entity); if (possibleCombination != null) { var combinedPiece = new Rail.JunctionPiece { RailPiece = possibleCombination.Result, Orientation = Rail.OrientationHelper.Rotate((entity as RailPiece).Piece.Orientation, (int)possibleCombination.ResultRelativeOrientation), }; var existingDesignation = Player.Faction.Designations.EnumerateEntityDesignations(DesignationType.Craft).FirstOrDefault(d => Object.ReferenceEquals(d.Body, entity)); if (existingDesignation != null) { (entity as RailPiece).UpdatePiece(combinedPiece, actualPosition); (existingDesignation.Tag as CraftDesignation).Progress = 0.0f; body.Delete(); addNewDesignation = false; } else { (entity as RailPiece).Die(); body.UpdatePiece(combinedPiece, actualPosition); } } } if (addNewDesignation) { var startPos = body.Position + new Vector3(0.0f, -0.3f, 0.0f); var endPos = body.Position; var designation = new CraftDesignation { Entity = body, WorkPile = new WorkPile(Player.World.ComponentManager, startPos), OverrideOrientation = false, Valid = true, ItemType = RailCraftItem, SelectedResources = SelectedResources, Location = new VoxelHandle(Player.World.ChunkManager.ChunkData, GlobalVoxelCoordinate.FromVector3(body.Position)), HasResources = false, ResourcesReservedFor = null, Orientation = 0.0f, Progress = 0.0f, }; Player.World.ComponentManager.RootComponent.AddChild(designation.WorkPile); designation.WorkPile.AnimationQueue.Add(new EaseMotion(1.1f, Matrix.CreateTranslation(startPos), endPos)); Player.World.ParticleManager.Trigger("puff", endPos, Color.White, 10); Player.Faction.Designations.AddEntityDesignation(body, DesignationType.Craft, designation); assignments.Add(new CraftItemTask(designation)); } } if (assignments.Count > 0) { Player.World.Master.TaskManager.AddTasks(assignments); } }
private IEnumerable <MoveAction> EnumerateSuccessors( MoveState state, VoxelHandle voxel, MoveActionTempStorage Storage, bool inWater, bool standingOnGround, bool topCovered, bool hasNeighbors) { bool isClimbing = false; if (state.VehicleType == VehicleTypes.Rail) { if (Can(MoveType.ExitVehicle)) // Possibly redundant... If they can ride they should be able to exit right? { yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { VehicleType = VehicleTypes.None, Voxel = state.Voxel }, MoveType = MoveType.ExitVehicle, Diff = new Vector3(1, 1, 1), CostMultiplier = 1.0f }); } if (Can(MoveType.RideVehicle)) { foreach (var neighbor in Rail.RailHelper.EnumerateForwardNetworkConnections(state.PrevRail, state.Rail)) { var neighborRail = Creature.Manager.FindComponent(neighbor) as Rail.RailEntity; if (neighborRail == null || !neighborRail.Active) { continue; } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { Voxel = neighborRail.GetContainingVoxel(), Rail = neighborRail, PrevRail = state.Rail, VehicleType = VehicleTypes.Rail }, MoveType = MoveType.RideVehicle, CostMultiplier = 1.0f }); } } yield break; // Nothing can be done without exiting the rails first. } if (CanClimb || Can(MoveType.RideVehicle)) { //Climbing ladders and riding rails. var bodies = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(voxel.GetBoundingBox())); // if the creature can climb objects and a ladder is in this voxel, // then add a climb action. if (CanClimb) { var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable")); if (ladder != null) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 2, 1), MoveType = MoveType.Climb, InteractObject = ladder, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 2, 1] }); if (!standingOnGround) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 0, 1), MoveType = MoveType.Climb, InteractObject = ladder, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 2, 1] }); } standingOnGround = true; } } if (Can(MoveType.RideVehicle)) { var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active); if (rails.Count() > 0 && Can(MoveType.RideVehicle)) { { foreach (var rail in rails) { if (rail.GetContainingVoxel() != state.Voxel) { continue; } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { VehicleType = VehicleTypes.Rail, Rail = rail, Voxel = rail.GetContainingVoxel() }, MoveType = MoveType.EnterVehicle, Diff = new Vector3(1, 1, 1), CostMultiplier = 1.0f }); } } } var elevators = bodies.OfType <Elevators.ElevatorShaft>().Where(r => r.Active && System.Math.Abs(r.Position.Y - voxel.Center.Y) < 0.5f); foreach (var elevator in elevators) { foreach (var elevatorExit in Elevators.Helper.EnumerateExits(elevator.Shaft)) { if (object.ReferenceEquals(elevator, elevatorExit.ShaftSegment)) { continue; // Ignore exits from the segment we are entering at. } yield return(new MoveAction() { SourceState = state, DestinationState = new MoveState() { Voxel = elevatorExit.OntoVoxel, VehicleType = VehicleTypes.None, Tag = new Elevators.ElevatorMoveState { Entrance = elevator, Exit = elevatorExit.ShaftSegment } }, MoveType = MoveType.RideElevator, CostMultiplier = elevator.GetQueueSize() + 1.0f }); } } } } // If the creature can fly and is not underwater, it can fly // to any adjacent empty cell. if (CanFly && !inWater) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { for (int dy = 0; dy <= 2; dy++) { if (dx == 1 && dz == 1 && dy == 1) { continue; } if (Storage.Neighborhood[dx, dy, dz].IsValid && Storage.Neighborhood[dx, dy, dz].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(dx, dy, dz), MoveType = MoveType.Fly, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[dx, dy, dz] }); } } } } } // If the creature is not in water and is not standing on ground, // it can fall one voxel downward in free space. if (!inWater && !standingOnGround) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 0, 1), MoveType = MoveType.Fall, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 0, 1] }); } // If the creature can climb walls and is not blocked by a voxl above. if (CanClimbWalls && !topCovered) { // This monstrosity is unrolling an inner loop so that we don't have to allocate an array or // enumerators. var wall = VoxelHandle.InvalidHandle; var n211 = Storage.Neighborhood[2, 1, 1]; if (n211.IsValid && !n211.IsEmpty) { wall = n211; } else { var n011 = Storage.Neighborhood[0, 1, 1]; if (n011.IsValid && !n011.IsEmpty) { wall = n011; } else { var n112 = Storage.Neighborhood[1, 1, 2]; if (n112.IsValid && !n112.IsEmpty) { wall = n112; } else { var n110 = Storage.Neighborhood[1, 1, 0]; if (n110.IsValid && !n110.IsEmpty) { wall = n110; } } } } if (wall.IsValid) { isClimbing = true; yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 2, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 2, 1] }); if (!standingOnGround) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 0, 1), MoveType = MoveType.ClimbWalls, ActionVoxel = wall, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 0, 1] }); } } } // If the creature either can walk or is in water, add the // eight-connected free neighbors around the voxel. if ((CanWalk && standingOnGround) || (CanSwim && inWater)) { // If the creature is in water, it can swim. Otherwise, it will walk. var moveType = inWater ? MoveType.Swim : MoveType.Walk; if (Storage.Neighborhood[0, 1, 1].IsValid && Storage.Neighborhood[0, 1, 1].IsEmpty) { // +- x yield return(new MoveAction { SourceState = state, DestinationVoxel = Storage.Neighborhood[0, 1, 1], Diff = new Vector3(0, 1, 1), MoveType = moveType, CostMultiplier = 1.0f }); } if (Storage.Neighborhood[2, 1, 1].IsValid && Storage.Neighborhood[2, 1, 1].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(2, 1, 1), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[2, 1, 1] }); } if (Storage.Neighborhood[1, 1, 0].IsValid && Storage.Neighborhood[1, 1, 0].IsEmpty) { // +- z yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 1, 0), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 1, 0] }); } if (Storage.Neighborhood[1, 1, 2].IsValid && Storage.Neighborhood[1, 1, 2].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(1, 1, 2), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[1, 1, 2] }); } // Only bother worrying about 8-connected movement if there are // no full neighbors around the voxel. if (!hasNeighbors) { if (Storage.Neighborhood[2, 1, 2].IsValid && Storage.Neighborhood[2, 1, 2].IsEmpty) { // +x + z yield return(new MoveAction { SourceState = state, Diff = new Vector3(2, 1, 2), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[2, 1, 2] }); } if (Storage.Neighborhood[2, 1, 0].IsValid && Storage.Neighborhood[2, 1, 0].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(2, 1, 0), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[2, 1, 0] }); } if (Storage.Neighborhood[0, 1, 2].IsValid && Storage.Neighborhood[0, 1, 2].IsEmpty) { // -x -z yield return(new MoveAction { SourceState = state, Diff = new Vector3(0, 1, 2), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[0, 1, 2] }); } if (Storage.Neighborhood[0, 1, 0].IsValid && Storage.Neighborhood[0, 1, 0].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(0, 1, 0), MoveType = moveType, CostMultiplier = 1.0f, DestinationVoxel = Storage.Neighborhood[0, 1, 0] }); } } } // If the creature's head is free, and it is standing on ground, // or if it is in water, or if it is climbing, it can also jump // to voxels that are 1 cell away and 1 cell up. if (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing)) { for (int dx = 0; dx <= 2; dx++) { for (int dz = 0; dz <= 2; dz++) { if (dx == 1 && dz == 1) { continue; } if (Storage.Neighborhood[dx, 1, dz].IsValid && !Storage.Neighborhood[dx, 1, dz].IsEmpty) { yield return(new MoveAction { SourceState = state, Diff = new Vector3(dx, 2, dz), MoveType = MoveType.Jump, DestinationVoxel = Storage.Neighborhood[dx, 2, dz], CostMultiplier = 1.0f }); } } } } /* * if (CanDig) * { * // This loop is unrolled for speed. It gets the manhattan neighbors and tells the creature that it can mine * // the surrounding rock to get through. * VoxelHandle neighbor = Storage.Neighborhood[0, 1, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(0, 1, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[2, 1, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(2, 1, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 1, 2]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 1, 2), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 1, 0]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 1, 0), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 2, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 2, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * * neighbor = Storage.Neighborhood[1, 0, 1]; * if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt)) * { * yield return (new MoveAction * { * SourceState = state, * Diff = new Vector3(1, 0, 1), * MoveType = MoveType.Dig, * DestinationVoxel = neighbor, * CostMultiplier = 1.0f * }); * } * } */ }
public void Sense() { if (Name == "turret-sensor") { var x = 5; } if (!Active) { return; } if (Creature != null) { Allies = Creature.Faction; } // Don't sense enemies if we're inside the ground?? var currentVoxel = new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(Position)); if (!(currentVoxel.IsValid && currentVoxel.IsEmpty)) { return; } var sensed = new List <CreatureAI>(); var myRoot = GetRoot(); foreach (var body in Manager.World.EnumerateIntersectingObjects(BoundingBox, b => !Object.ReferenceEquals(b, myRoot) && b.IsRoot())) { if (body.GetComponent <Flammable>().HasValue(out var flames) && flames.IsOnFire) { if (GetRoot().GetComponent <CreatureAI>().HasValue(out var myAI)) { var task = new FleeEntityTask(body, 5) { Priority = TaskPriority.Urgent, AutoRetry = false, ReassignOnDeath = false }; if (!myAI.HasTaskWithName(task)) { myAI.AssignTask(task); } continue; } } if (body.GetComponent <CreatureAI>().HasValue(out var minion)) { if (!minion.Active) { continue; } if (!DetectCloaked && minion.Creature.IsCloaked) { continue; } else if (DetectCloaked && minion.Creature.IsCloaked) { minion.Creature.IsCloaked = false; } if (World.Overworld.GetPolitics(Allies.ParentFaction, minion.Faction.ParentFaction).GetCurrentRelationship() != Relationship.Hateful) { continue; } if (!VoxelHelpers.DoesRayHitSolidVoxel(Manager.World.ChunkManager, Position, minion.Position)) { sensed.Add(minion); } } } if (sensed != null && sensed.Count > 0 && OnEnemySensed != null) { OnEnemySensed.Invoke(sensed); } }
public void SetVoxel(VoxelHandle voxel) { Agent.Blackboard.SetData(VoxelName, voxel); }
private List <VoxelHandle> SpiralVoxels() { // Process voxels into a neat grid. if (Voxels.Count == 0) { throw new InvalidOperationException(); } var bounds = this.GetBoundingBox(); var voxelGrid = new VoxelHandle[(int)(bounds.Max.X - bounds.Min.X), (int)(bounds.Max.Z - bounds.Min.Z)]; foreach (var voxel in Voxels) { voxelGrid[(int)(voxel.Coordinate.X - bounds.Min.X), (int)(voxel.Coordinate.Z - bounds.Min.Z)] = voxel; } // if any invalid voxels in grid, go ahead and abort. foreach (var voxel in voxelGrid) { if (!voxel.IsValid) { return(Voxels); } } // Find center voxel. Actually want to round UP - or - spiral in positive direction? var center_c = GlobalVoxelCoordinate.FromVector3(bounds.Center()); var current_v = Voxels.FirstOrDefault(v => v.Coordinate == center_c); if (!current_v.IsValid) { return(Voxels); } var direction = Direction.East; var results = new List <VoxelHandle>(); results.Add(current_v); // Starting at center, spiral around, starting to the right. while (true) { var next_voxel = Voxels.FirstOrDefault(v => v.Coordinate == current_v.Coordinate + GetDirectionOffset(direction)); if (next_voxel.IsValid) { results.Add(next_voxel); current_v = next_voxel; var possible_turn = TurnRight(direction); var possible_ahead = Voxels.FirstOrDefault(v => v.Coordinate == current_v.Coordinate + GetDirectionOffset(possible_turn)); if (possible_ahead.IsValid && !results.Any(v => v.Coordinate == possible_ahead.Coordinate)) { direction = possible_turn; } } else { break; } } // Recover any voxels we missed. foreach (var voxel in Voxels) { if (!results.Any(v => v.Coordinate == voxel.Coordinate)) { results.Add(voxel); } } return(results); // For each voxel - step one in the current direction and return. // If we've hit an edge - try and turn. // If the next direction is unvisited - turn }
private static void CreateWaterFaces( VoxelHandle voxel, VoxelChunk chunk, int x, int y, int z, ExtendedVertex[] vertices, ushort[] Indexes, int startVertex, int startIndex) { // Reset the appropriate parts of the cache. cache.Reset(); // These are reused for every face. var origin = voxel.WorldPosition; float centerWaterlevel = voxel.LiquidLevel; float[] foaminess = new float[4]; for (int i = 0; i < cache.drawFace.Length; i++) { if (!cache.drawFace[i]) { continue; } BoxFace face = (BoxFace)i; var faceDescriptor = primitive.GetFace(face); int indexOffset = startVertex; for (int vertOffset = 0; vertOffset < faceDescriptor.VertexCount; vertOffset++) { VoxelVertex currentVertex = primitive.Deltas[faceDescriptor.VertexOffset + vertOffset]; // These will be filled out before being used lh . //float foaminess1; foaminess[vertOffset] = 0.0f; bool shoreLine = false; Vector3 pos = Vector3.Zero; Vector3 rampOffset = Vector3.Zero; var uv = primitive.UVs.Uvs[vertOffset + faceDescriptor.VertexOffset]; // We are going to have to reuse some vertices when drawing a single so we'll store the position/foaminess // for quick lookup when we find one of those reused ones. // When drawing multiple faces the Vertex overlap gets bigger, which is a bonus. if (!cache.vertexCalculated[(int)currentVertex]) { float count = 1.0f; float emptyNeighbors = 0.0f; float averageWaterLevel = centerWaterlevel; var vertexSucc = VoxelHelpers.VertexNeighbors[(int)currentVertex]; // Run through the successors and count up the water in each voxel. for (int v = 0; v < vertexSucc.Length; v++) { var neighborVoxel = new VoxelHandle(chunk.Manager.ChunkData, voxel.Coordinate + vertexSucc[v]); // Only continue if it's a valid (non-null) voxel. if (!neighborVoxel.IsValid) { continue; } // Now actually do the math. count++; if (neighborVoxel.LiquidLevel < 1) { emptyNeighbors++; } if (neighborVoxel.LiquidType == LiquidType.None && !neighborVoxel.IsEmpty) { shoreLine = true; } } foaminess[vertOffset] = emptyNeighbors / count; if (foaminess[vertOffset] <= 0.5f) { foaminess[vertOffset] = 0.0f; } // Check if it should ramp. else if (!shoreLine) { //rampOffset.Y = -0.4f; } pos = primitive.Vertices[vertOffset + faceDescriptor.VertexOffset].Position; if ((currentVertex & VoxelVertex.Top) == VoxelVertex.Top) { pos.Y -= 0.6f;// Minimum ramp position var neighbors = VoxelHelpers.EnumerateVertexNeighbors2D(voxel.Coordinate, currentVertex) .Select(c => new VoxelHandle(chunk.Manager.ChunkData, c)) .Where(h => h.IsValid) .Select(h => (float)h.LiquidLevel / 8.0f); if (neighbors.Count() > 0) { pos.Y *= neighbors.Average(); } } else { uv.Y -= 0.6f; } pos += VertexNoise.GetNoiseVectorFromRepeatingTexture(voxel.WorldPosition + primitive.Vertices[vertOffset + faceDescriptor.VertexOffset].Position); pos += origin + rampOffset; // Store the vertex information for future use when we need it again on this or another face. cache.vertexCalculated[(int)currentVertex] = true; cache.vertexFoaminess[(int)currentVertex] = foaminess[vertOffset]; cache.vertexPositions[(int)currentVertex] = pos; } else { // We've already calculated this one. Time for a cheap grab from the lookup. foaminess[vertOffset] = cache.vertexFoaminess[(int)currentVertex]; pos = cache.vertexPositions[(int)currentVertex]; } vertices[startVertex].Set(pos, new Color(foaminess[vertOffset], 0.0f, 1.0f, 1.0f), Color.White, uv, new Vector4(0, 0, 1, 1)); startVertex++; } bool flippedQuad = foaminess[1] + foaminess[3] > foaminess[0] + foaminess[2]; for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = flippedQuad ? primitive.FlippedIndexes[idx] : primitive.Indexes[idx]; ushort offset0 = flippedQuad ? primitive.FlippedIndexes[faceDescriptor.IndexOffset] : primitive.Indexes[faceDescriptor.IndexOffset]; Indexes[startIndex] = (ushort)(indexOffset + offset - offset0); startIndex++; } } // End cache.drawFace loop }
public override void AddVoxel(VoxelHandle Voxel) { base.AddVoxel(Voxel); RecalculateMaxResources(); Voxels = SpiralVoxels(); }
public static bool IsValidPlacement( VoxelHandle Location, CraftItem CraftType, WorldManager World, GameComponent PreviewBody, String Verb, String PastParticple) { if (CraftType == null) { return(false); } if (!String.IsNullOrEmpty(CraftType.CraftLocation) && World.PlayerFaction.FindNearestItemWithTags(CraftType.CraftLocation, Location.WorldPosition, false, null) == null) { World.UserInterface.ShowTooltip("Can't " + Verb + ", need " + CraftType.CraftLocation); return(false); } foreach (var req in CraftType.Prerequisites) { switch (req) { case CraftItem.CraftPrereq.NearWall: { var neighborFound = VoxelHelpers.EnumerateManhattanNeighbors2D(Location.Coordinate) .Select(c => new VoxelHandle(World.ChunkManager, c)) .Any(v => v.IsValid && !v.IsEmpty); if (!neighborFound) { World.UserInterface.ShowTooltip("Must be " + PastParticple + " next to wall!"); return(false); } break; } case CraftItem.CraftPrereq.OnGround: { var below = VoxelHelpers.GetNeighbor(Location, new GlobalVoxelOffset(0, -1, 0)); if (!below.IsValid || below.IsEmpty) { World.UserInterface.ShowTooltip("Must be " + PastParticple + " on solid ground!"); return(false); } break; } } } if (PreviewBody != null) { // Just check for any intersecting body in octtree. var previewBox = PreviewBody.GetRotatedBoundingBox(); var sensorBox = previewBox; var sensor = PreviewBody.GetComponent <GenericVoxelListener>(); if (sensor != null) { sensorBox = sensor.GetRotatedBoundingBox(); } if (Debugger.Switches.DrawToolDebugInfo) { Drawer3D.DrawBox(sensorBox, Color.Yellow, 0.1f, false); } foreach (var intersectingObject in World.EnumerateIntersectingObjects(sensorBox, CollisionType.Static)) { if (Object.ReferenceEquals(intersectingObject, sensor)) { continue; } var objectRoot = intersectingObject.GetRoot() as GameComponent; if (objectRoot is WorkPile) { continue; } if (objectRoot == PreviewBody) { continue; } if (objectRoot != null && objectRoot.GetRotatedBoundingBox().Intersects(previewBox)) { World.UserInterface.ShowTooltip("Can't " + Verb + " here: intersects " + objectRoot.Name); return(false); } } bool intersectsWall = VoxelHelpers.EnumerateCoordinatesInBoundingBox (PreviewBody.GetRotatedBoundingBox().Expand(-0.1f)).Any( v => { var tvh = new VoxelHandle(World.ChunkManager, v); return(tvh.IsValid && !tvh.IsEmpty); }); var current = new VoxelHandle(World.ChunkManager, GlobalVoxelCoordinate.FromVector3(PreviewBody.Position)); bool underwater = current.IsValid && current.LiquidType != LiquidType.None; if (underwater) { World.UserInterface.ShowTooltip("Can't " + Verb + " here: underwater or in lava."); return(false); } if (intersectsWall && !CraftType.Prerequisites.Contains(CraftItem.CraftPrereq.NearWall)) { World.UserInterface.ShowTooltip("Can't " + Verb + " here: intersects wall."); return(false); } } World.UserInterface.ShowTooltip(""); return(true); }
private static void BuildVoxelFaceGeometry( RawPrimitive Into, VoxelChunk Chunk, Cache Cache, BoxPrimitive Primitive, VoxelHandle V, Color Tint, BoxPrimitive.BoxTextureCoords UVs, Matrix VertexTransform, int i, bool ApplyLighting) { var face = (BoxFace)i; var delta = FaceDeltas[i]; var faceVoxel = new VoxelHandle(Chunk.Manager, V.Coordinate + GlobalVoxelOffset.FromVector3(delta)); if (!IsFaceVisible(V, faceVoxel, face)) { return; } var faceDescriptor = Primitive.GetFace(face); var indexOffset = Into.VertexCount; for (int faceVertex = 0; faceVertex < faceDescriptor.VertexCount; faceVertex++) { var vertex = Primitive.Vertices[faceDescriptor.VertexOffset + faceVertex]; var voxelVertex = Primitive.Deltas[faceDescriptor.VertexOffset + faceVertex]; var vertexColor = new VertexColorInfo { SunColor = 255, AmbientColor = 255, DynamicColor = 255, }; if (ApplyLighting) { var cacheKey = GetCacheKey(V, voxelVertex); if (!Cache.LightCache.TryGetValue(cacheKey, out vertexColor)) { vertexColor = CalculateVertexLight(V, voxelVertex, Chunk.Manager); Cache.LightCache.Add(cacheKey, vertexColor); } Cache.AmbientValues[faceVertex] = vertexColor.AmbientColor; } var rampOffset = Vector3.Zero; if (V.IsExplored && V.Type.CanRamp && ShouldRamp(voxelVertex, V.RampType)) { rampOffset = new Vector3(0, -V.Type.RampSize, 0); } var baseWorldPosition = V.WorldPosition + vertex.Position + rampOffset; var noise = VertexNoise.GetNoiseVectorFromRepeatingTexture(baseWorldPosition); var localPosition = Vector3.Transform(vertex.Position + rampOffset + noise, VertexTransform); Into.AddVertex(new ExtendedVertex( V.WorldPosition + localPosition, vertexColor.AsColor(), Tint, UVs.Uvs[faceDescriptor.VertexOffset + faceVertex], UVs.Bounds[faceDescriptor.IndexOffset / 6])); } bool flippedQuad = ApplyLighting && (Cache.AmbientValues[0] + Cache.AmbientValues[2] > Cache.AmbientValues[1] + Cache.AmbientValues[3]); for (int idx = faceDescriptor.IndexOffset; idx < faceDescriptor.IndexCount + faceDescriptor.IndexOffset; idx++) { ushort offset = flippedQuad ? Primitive.FlippedIndexes[idx] : Primitive.Indexes[idx]; ushort offset0 = flippedQuad ? Primitive.FlippedIndexes[faceDescriptor.IndexOffset] : Primitive.Indexes[faceDescriptor.IndexOffset]; Into.AddIndex((short)(indexOffset + offset - offset0)); } }