void FloodFrom(Region tregion, Vector3i start, double maxRad, HashSet <Vector3i> locs) { Queue <Vector3i> toCheck = new Queue <Vector3i>(128); Dictionary <Vector3i, Chunk> chks = new Dictionary <Vector3i, Chunk>(128); // TODO: Arbitrary constant. toCheck.Enqueue(start); while (toCheck.Count > 0) { Vector3i c = toCheck.Dequeue(); if ((c.ToLocation() - start.ToLocation()).LengthSquared() > maxRad * maxRad) { continue; } if (tregion.GetBlockMaterial(chks, c.ToLocation()) != Material.AIR) { continue; } if (locs.Contains(c)) { continue; } locs.Add(c); foreach (Vector3i dir in FloodDirs) { toCheck.Enqueue(c + dir); } } }
public bool TryChunk(Vector3i cworldPos, int posMult, Chunk chi = null) // TODO: Efficiency? { if (pkick) { return(false); } if (!ChunksAwareOf.ContainsKey(cworldPos) || ChunksAwareOf[cworldPos].LOD > posMult) // TODO: Efficiency - TryGetValue? { double dist = (cworldPos.ToLocation() * Chunk.CHUNK_SIZE - LoadRelPos).LengthSquared(); bool async = chi == null && dist > (Chunk.CHUNK_SIZE * Chunk.CHUNK_SIZE * 2 * 2); if (async) { TheRegion.LoadChunk_Background(cworldPos, (chn) => { if (!pkick && chn != null) { ChunkNetwork.SendPacket(new ChunkInfoPacketOut(chn, posMult)); } }); } else { Chunk chk = chi != null ? chi : TheRegion.LoadChunk(cworldPos); ChunkNetwork.SendPacket(new ChunkInfoPacketOut(chk, posMult)); } ChunksAwareOf.Remove(cworldPos); ChunksAwareOf.Add(cworldPos, new ChunkAwarenessInfo() { ChunkPos = cworldPos, LOD = posMult }); return(true); } return(false); }
public void GenerateTrees(SimpleGeneratorCore sgc, Vector3i chunkPos, int Seed, int seed, int seed3, int seed4, int seed5) { Trees = new List <KeyValuePair <Vector2i, int> >(); ChunkPosition = chunkPos; CPos = chunkPos.ToLocation() * Chunk.CHUNK_SIZE; MTRandom random = new MTRandom((ulong)chunkPos.GetHashCode()); // TODO: Biome basis! int c = 0; if (random.Next(1, 5) == 1) { if (random.Next(1, 5) == 1) { if (random.Next(1, 5) == 1) { c = random.Next(1, 3); } else { c = random.Next(1, 2); } } else { c = 1; } } for (int i = 0; i < c; i++) { Trees.Add(new KeyValuePair <Vector2i, int>(new Vector2i(random.Next(Chunk.CHUNK_SIZE), random.Next(Chunk.CHUNK_SIZE)), random.Next())); } }
public override void Populate(int seed, int seed2, int seed3, int seed4, int seed5, Chunk chunk) { double scale = chunk.OwningRegion.TheWorld.GeneratorScale; scale *= scale; Location cCenter = (chunk.WorldPosition.ToLocation() + new Location(0.5, 0.5, 0.5)) * Constants.CHUNK_WIDTH; if (cCenter.LengthSquared() > scale * 4.0) { // TODO: Is this excessive? for (int i = 0; i < chunk.BlocksInternal.Length; i++) { chunk.BlocksInternal[i] = BlockInternal.AIR; } return; } double one_over_scale = 1.0 / scale; Vector3i cLow = chunk.WorldPosition * Constants.CHUNK_WIDTH; for (int x = 0; x < Constants.CHUNK_WIDTH; x++) { for (int y = 0; y < Constants.CHUNK_WIDTH; y++) { for (int z = 0; z < Constants.CHUNK_WIDTH; z++) { Vector3i current = cLow + new Vector3i(x, y, z); double distSq = current.ToLocation().LengthSquared(); double rel = distSq * one_over_scale; if (rel > 1.0) { chunk.SetBlockAt(x, y, z, BlockInternal.AIR); } else if (rel > (0.9 * 0.9)) { chunk.SetBlockAt(x, y, z, new BlockInternal((ushort)Material.DIRT, 0, 0, 0)); } // TODO: More layers? else { chunk.SetBlockAt(x, y, z, new BlockInternal((ushort)Material.STONE, 0, 0, 0)); } } } } }
public void Generate(SimpleGeneratorCore sgc, Vector3i chunkPos, int Seed, int seed2, int seed3, int seed4, int seed5) { List <MountainData> mountains = sgc.GenMountainPositionsAround(new Vector2i(chunkPos.X, chunkPos.Y), Seed); ChunkPosition = chunkPos; CPos = chunkPos.ToLocation() * Chunk.CHUNK_SIZE; Heights = new double[Chunk.CHUNK_SIZE * Chunk.CHUNK_SIZE]; for (int x = 0; x < Chunk.CHUNK_SIZE; x++) { for (int y = 0; y < Chunk.CHUNK_SIZE; y++) { // Prepare basics int cx = (int)CPos.X + x; int cy = (int)CPos.Y + y; double hheight = sgc.GetHeight(Seed, seed2, seed3, seed4, seed5, cx, cy, mountains, true); Heights[y * Chunk.CHUNK_SIZE + x] = hheight; } } }
/// <summary> /// Finds a path from the start to the end, if one exists. /// Current implementation is A-Star (A*). /// Thanks to fullwall for the reference sources this was originally built from. /// Possibly safe for Async usage. /// </summary> /// <param name="startloc">The starting location.</param> /// <param name="endloc">The ending location.</param> /// <param name="maxRadius">The maximum radius to search through.</param> /// <param name="goaldist">The maximum distance from the goal allowed.</param> /// <param name="cts">A cancellation token, if any.</param> /// <returns>The shortest path, as a list of blocks to travel through.</returns> public List <Location> FindPath(Location startloc, Location endloc, double maxRadius, double goaldist, CancellationTokenSource cts = null) { // TODO: Improve async safety! startloc = startloc.GetBlockLocation() + new Location(0.5, 0.5, 1.0); endloc = endloc.GetBlockLocation() + new Location(0.5, 0.5, 1.0); double mrsq = maxRadius * maxRadius; double gosq = goaldist * goaldist; if (startloc.DistanceSquared(endloc) > mrsq) { cts.Cancel(); return(null); } PathFindNodeSet nodes; PriorityQueue <PFEntry> open; Dictionary <Vector3i, Chunk> map; lock (PFNodeSetLock) { if (PFNodeSet.Count == 0) { nodes = null; open = null; map = null; } else { nodes = PFNodeSet.Pop(); open = PFQueueSet.Pop(); map = PFMapSet.Pop(); } } if (nodes == null) { nodes = new PathFindNodeSet() { Nodes = new PathFindNode[8192] }; open = new PriorityQueue <PFEntry>(8192); map = new Dictionary <Vector3i, Chunk>(1024); } int nloc = 0; int start = GetNode(nodes, ref nloc, startloc.ToVec3i(), 0.0, 0.0, -1); // TODO: Grab these from a stack too? Dictionary <Vector3i, PathFindNode> closed = new Dictionary <Vector3i, PathFindNode>(); Dictionary <Vector3i, PathFindNode> openset = new Dictionary <Vector3i, PathFindNode>(); PFEntry pfet; pfet.Nodes = nodes; pfet.ID = start; open.Enqueue(ref pfet, 0.0); openset[startloc.ToVec3i()] = nodes.Nodes[start]; while (open.Count > 0) { if (cts.IsCancellationRequested) { return(null); } int nextid = open.Dequeue().ID; PathFindNode next = nodes.Nodes[nextid]; if (openset.TryGetValue(next.Internal, out PathFindNode pano) && pano.F < next.F) { continue; } openset.Remove(next.Internal); if (next.Internal.ToLocation().DistanceSquared(endloc) < gosq) { open.Clear(); map.Clear(); lock (PFNodeSetLock) { PFNodeSet.Push(nodes); PFQueueSet.Push(open); PFMapSet.Push(map); } return(Reconstruct(nodes.Nodes, nextid)); } if (closed.TryGetValue(next.Internal, out PathFindNode pfn) && pfn.F < next.F) { continue; } closed[next.Internal] = next; foreach (Vector3i neighbor in PathFindNode.Neighbors) { Vector3i neighb = next.Internal + neighbor; if (startloc.DistanceSquared(neighb.ToLocation()) > mrsq) { continue; } // Note: Add `&& fbv.F <= next.F)` to enhance precision of results... but it makes invalid searches take forever. if (closed.TryGetValue(neighb, out PathFindNode fbv)) { continue; } // Note: Add `&& pfv.F <= next.F)` to enhance precision of results... but it makes invalid searches take forever. if (openset.TryGetValue(neighb, out PathFindNode pfv)) { continue; } // TODO: Check solidity from very solid entities too! if (GetBlockMaterial(map, neighb).GetSolidity() != MaterialSolidity.NONSOLID) // TODO: Better solidity check { continue; } if (GetBlockMaterial(map, neighb + new Vector3i(0, 0, -1)).GetSolidity() == MaterialSolidity.NONSOLID && GetBlockMaterial(map, neighb + new Vector3i(0, 0, -2)).GetSolidity() == MaterialSolidity.NONSOLID && GetBlockMaterial(map, next.Internal + new Vector3i(0, 0, -1)).GetSolidity() == MaterialSolidity.NONSOLID && GetBlockMaterial(map, next.Internal + new Vector3i(0, 0, -2)).GetSolidity() == MaterialSolidity.NONSOLID) { continue; } int node = GetNode(nodes, ref nloc, neighb, next.G + 1.0, next.F + 1.0 + neighb.ToLocation().Distance(endloc), nextid); PFEntry tpfet; tpfet.Nodes = nodes; tpfet.ID = node; open.Enqueue(ref tpfet, nodes.Nodes[node].F); openset[neighb] = nodes.Nodes[node]; } } open.Clear(); map.Clear(); lock (PFNodeSetLock) { PFNodeSet.Push(nodes); PFQueueSet.Push(open); PFMapSet.Push(map); } cts.Cancel(); return(null); }
/// <summary> /// Ticks the region, including all primary calculations and lighting updates. /// </summary> public void TickWorld(double delta) { rTicks++; if (rTicks >= CVars.r_shadowpace.ValueI) { Vector3i playerChunkPos = TheRegion.ChunkLocFor(Player.GetPosition()); if (playerChunkPos != SunChunkPos) // TODO: Or sun/planet angle changed! { SunChunkPos = playerChunkPos; Location corPos = (SunChunkPos.ToLocation() * Constants.CHUNK_WIDTH) + new Location(Constants.CHUNK_WIDTH * 0.5); TheSun.Direction = Utilities.ForwardVector_Deg(SunAngle.Yaw, SunAngle.Pitch); TheSun.Reposition(corPos - TheSun.Direction * 30 * 6); TheSunClouds.Direction = TheSun.Direction; TheSunClouds.Reposition(TheSun.EyePos); PlanetDir = Utilities.ForwardVector_Deg(PlanetAngle.Yaw, PlanetAngle.Pitch); ThePlanet.Direction = PlanetDir; ThePlanet.Reposition(corPos - ThePlanet.Direction * 30 * 6); Vector3 tsd = TheSun.Direction.ToBVector(); Vector3 tpd = PlanetDir.ToBVector(); Quaternion.GetQuaternionBetweenNormalizedVectors(ref tsd, ref tpd, out Quaternion diff); PlanetSunDist = (float)Quaternion.GetAngleFromQuaternion(ref diff) / (float)Utilities.PI180; if (PlanetSunDist < 75) { TheSun.InternalLights[0].color = new OpenTK.Vector3((float)Math.Min(SunLightDef.X * (PlanetSunDist / 15), 1), (float)Math.Min(SunLightDef.Y * (PlanetSunDist / 20), 1), (float)Math.Min(SunLightDef.Z * (PlanetSunDist / 60), 1)); TheSunClouds.InternalLights[0].color = new OpenTK.Vector3((float)Math.Min(CloudSunLightDef.X * (PlanetSunDist / 15), 1), (float)Math.Min(CloudSunLightDef.Y * (PlanetSunDist / 20), 1), (float)Math.Min(CloudSunLightDef.Z * (PlanetSunDist / 60), 1)); //ThePlanet.InternalLights[0].color = new OpenTK.Vector3(0, 0, 0); } else { TheSun.InternalLights[0].color = ClientUtilities.Convert(SunLightDef); TheSunClouds.InternalLights[0].color = ClientUtilities.Convert(CloudSunLightDef); //ThePlanet.InternalLights[0].color = ClientUtilities.Convert(PlanetLightDef * Math.Min((PlanetSunDist / 180f), 1f)); } PlanetLight = PlanetSunDist / 180f; if (SunAngle.Pitch < 10 && SunAngle.Pitch > -30) { float rel = 30 + (float)SunAngle.Pitch; if (rel == 0) { rel = 0.00001f; } rel = 1f - (rel / 40f); rel = Math.Max(Math.Min(rel, 1f), 0f); float rel2 = Math.Max(Math.Min(rel * 1.5f, 1f), 0f); TheSun.InternalLights[0].color = new OpenTK.Vector3(TheSun.InternalLights[0].color.X * rel2, TheSun.InternalLights[0].color.Y * rel, TheSun.InternalLights[0].color.Z * rel); TheSunClouds.InternalLights[0].color = new OpenTK.Vector3(TheSunClouds.InternalLights[0].color.X * rel2, TheSunClouds.InternalLights[0].color.Y * rel, TheSunClouds.InternalLights[0].color.Z * rel); MainWorldView.DesaturationAmount = (1f - rel) * 0.75f; MainWorldView.ambient = BaseAmbient * ((1f - rel) * 0.5f + 0.5f); sl_min = 0.2f - (1f - rel) * (0.2f - 0.05f); sl_max = 0.8f - (1f - rel) * (0.8f - 0.15f); SkyColor = SkyApproxColDefault * rel; } else if (SunAngle.Pitch >= 10) { TheSun.InternalLights[0].color = new OpenTK.Vector3(0, 0, 0); TheSunClouds.InternalLights[0].color = new OpenTK.Vector3(0, 0, 0); MainWorldView.DesaturationAmount = 0.75f; MainWorldView.ambient = BaseAmbient * 0.5f; sl_min = 0.05f; sl_max = 0.15f; SkyColor = Location.Zero; } else { sl_min = 0.2f; sl_max = 0.8f; MainWorldView.DesaturationAmount = 0f; MainWorldView.ambient = BaseAmbient; TheSun.InternalLights[0].color = ClientUtilities.Convert(SunLightDef); TheSunClouds.InternalLights[0].color = ClientUtilities.Convert(CloudSunLightDef); SkyColor = SkyApproxColDefault; } shouldRedrawShadows = true; } rTicks = 0; } TheRegion.TickWorld(delta); }
void ChunkMarchAndSend() { // TODO: is this the most efficient it can be? int maxChunks = TheServer.CVars.n_chunkspertick.ValueI; int chunksFound = 0; if (LoadRelPos.IsNaN() || LoadRelDir.IsNaN() || LoadRelDir.LengthSquared() < 0.1f) { return; } Matrix proj = Matrix.CreatePerspectiveFieldOfViewRH(Max_FOV * (double)Utilities.PI180, 1, 0.5f, 3000f); Matrix view = Matrix.CreateLookAtRH((LoadRelPos - LoadRelDir * 8).ToBVector(), (LoadRelPos + LoadRelDir * 8).ToBVector(), new Vector3(0, 0, 1)); Matrix combined = view * proj; BFrustum bfs = new BFrustum(combined); Vector3i start = TheRegion.ChunkLocFor(LoadRelPos); HashSet <Vector3i> seen = new HashSet <Vector3i>(); Queue <Vector3i> toSee = new Queue <Vector3i>(); toSee.Enqueue(start); while (toSee.Count > 0) { Vector3i cur = toSee.Dequeue(); seen.Add(cur); if (Math.Abs(cur.X - start.X) > (ViewRadiusInChunks + ViewRadExtra5) || Math.Abs(cur.Y - start.Y) > (ViewRadiusInChunks + ViewRadExtra5) || Math.Abs(cur.Z - start.Z) > (ViewRadiusInChunks + ViewRadExtra5Height)) { continue; } if (Math.Abs(cur.X - start.X) <= ViewRadiusInChunks && Math.Abs(cur.Y - start.Y) <= ViewRadiusInChunks && Math.Abs(cur.Z - start.Z) <= ViewRadiusInChunks) { if (TryChunk(cur, 1)) { chunksFound++; if (chunksFound > maxChunks) { return; } } } else if (Math.Abs(cur.X - start.X) <= (ViewRadiusInChunks + ViewRadExtra2) && Math.Abs(cur.Y - start.Y) <= (ViewRadiusInChunks + ViewRadExtra2) && Math.Abs(cur.Z - start.Z) <= (ViewRadiusInChunks + ViewRadExtra2Height)) { if (TryChunk(cur, 2)) { chunksFound++; if (chunksFound > maxChunks) { return; } } } else { if (TryChunk(cur, 5)) { chunksFound++; if (chunksFound > maxChunks) { return; } } } for (int i = 0; i < MoveDirs.Length; i++) { Vector3i t = cur + MoveDirs[i]; if (!seen.Contains(t) && !toSee.Contains(t)) { //toSee.Enqueue(t); for (int j = 0; j < MoveDirs.Length; j++) { if (Vector3.Dot(MoveDirs[j].ToVector3(), LoadRelDir.ToBVector()) < -0.8f) // TODO: Wut? { continue; } Vector3i nt = cur + MoveDirs[j]; if (!seen.Contains(nt) && !toSee.Contains(nt)) { bool val = false; Chunk ch = TheRegion.GetChunk(t); if (ch == null) { val = true; } // TODO: Oh, come on! else if (MoveDirs[i].X == -1) { if (MoveDirs[j].X == -1) { val = ch.Reachability[(int)ChunkReachability.XP_XM]; } else if (MoveDirs[j].Y == -1) { val = ch.Reachability[(int)ChunkReachability.XP_YM]; } else if (MoveDirs[j].Y == 1) { val = ch.Reachability[(int)ChunkReachability.XP_YP]; } else if (MoveDirs[j].Z == -1) { val = ch.Reachability[(int)ChunkReachability.ZM_XP]; } else if (MoveDirs[j].Z == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_XP]; } } else if (MoveDirs[i].X == 1) { if (MoveDirs[j].X == 1) { val = ch.Reachability[(int)ChunkReachability.XP_XM]; } else if (MoveDirs[j].Y == -1) { val = ch.Reachability[(int)ChunkReachability.XM_YM]; } else if (MoveDirs[j].Y == 1) { val = ch.Reachability[(int)ChunkReachability.XM_YP]; } else if (MoveDirs[j].Z == -1) { val = ch.Reachability[(int)ChunkReachability.ZM_XM]; } else if (MoveDirs[j].Z == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_XM]; } } else if (MoveDirs[i].Y == -1) { if (MoveDirs[j].Y == 1) { val = ch.Reachability[(int)ChunkReachability.YP_YM]; } else if (MoveDirs[j].X == -1) { val = ch.Reachability[(int)ChunkReachability.XM_YP]; } else if (MoveDirs[j].X == 1) { val = ch.Reachability[(int)ChunkReachability.XP_YP]; } else if (MoveDirs[j].Z == -1) { val = ch.Reachability[(int)ChunkReachability.ZM_YP]; } else if (MoveDirs[j].Z == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_YP]; } } else if (MoveDirs[i].Y == 1) { if (MoveDirs[j].Y == -1) { val = ch.Reachability[(int)ChunkReachability.YP_YM]; } else if (MoveDirs[j].X == -1) { val = ch.Reachability[(int)ChunkReachability.XM_YP]; } else if (MoveDirs[j].X == 1) { val = ch.Reachability[(int)ChunkReachability.XP_YP]; } else if (MoveDirs[j].Z == -1) { val = ch.Reachability[(int)ChunkReachability.ZM_YP]; } else if (MoveDirs[j].Z == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_YP]; } } else if (MoveDirs[i].Z == -1) { if (MoveDirs[j].Z == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_ZM]; } else if (MoveDirs[j].X == -1) { val = ch.Reachability[(int)ChunkReachability.ZP_XM]; } else if (MoveDirs[j].X == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_XP]; } else if (MoveDirs[j].Y == -1) { val = ch.Reachability[(int)ChunkReachability.ZP_YM]; } else if (MoveDirs[j].Y == 1) { val = ch.Reachability[(int)ChunkReachability.ZP_YP]; } } else if (MoveDirs[i].Z == 1) { if (MoveDirs[j].Z == -1) { val = ch.Reachability[(int)ChunkReachability.ZP_ZM]; } else if (MoveDirs[j].X == -1) { val = ch.Reachability[(int)ChunkReachability.ZM_XM]; } else if (MoveDirs[j].X == 1) { val = ch.Reachability[(int)ChunkReachability.ZM_XP]; } else if (MoveDirs[j].Y == -1) { val = ch.Reachability[(int)ChunkReachability.ZM_YM]; } else if (MoveDirs[j].Y == 1) { val = ch.Reachability[(int)ChunkReachability.ZM_YP]; } } if (val) { Location min = nt.ToLocation() * Chunk.CHUNK_SIZE; if (bfs.ContainsBox(min, min + new Location(Chunk.CHUNK_SIZE))) { toSee.Enqueue(nt); } else { seen.Add(nt); } } } } } } } }
// TODO: Efficiency? public bool TryChunk(Vector3i cworldPos, int posMult, Chunk chi = null) { if (pkick) { return false; } if (!ChunksAwareOf.ContainsKey(cworldPos) || ChunksAwareOf[cworldPos].LOD > posMult) // TODO: Efficiency - TryGetValue? { double dist = (cworldPos.ToLocation() * Chunk.CHUNK_SIZE - LoadRelPos).LengthSquared(); bool async = chi == null && dist > (Chunk.CHUNK_SIZE * Chunk.CHUNK_SIZE * 2 * 2); if (async) { TheRegion.LoadChunk_Background(cworldPos, (chn) => { if (!pkick && chn != null) { ChunkNetwork.SendPacket(new ChunkInfoPacketOut(chn, posMult)); } }); } else { Chunk chk = chi != null ? chi : TheRegion.LoadChunk(cworldPos); ChunkNetwork.SendPacket(new ChunkInfoPacketOut(chk, posMult)); } ChunksAwareOf.Remove(cworldPos); ChunksAwareOf.Add(cworldPos, new ChunkAwarenessInfo() { ChunkPos = cworldPos, LOD = posMult }); return true; } return false; }