public bool LoadChunk(Vec2i chunk, bool forceLoad = false) { //Check if chunk is loaded if (LoadedChunks.ContainsKey(chunk)) { Debug.Log("Chunk " + chunk + " is already loaded!", Debug.CHUNK_LOADING); return(true); } //Retrieve data ChunkData data = GetChunk(chunk.x, chunk.z); if (data == null) { Debug.Log("Chunk " + chunk + " could not be found!", Debug.CHUNK_LOADING); return(false); } if (forceLoad) { LoadInSingleChunk(data); } else if (!ToLoadIn.Contains(data)) { Debug.Log("Added " + chunk + " to load in", Debug.CHUNK_LOADING); ToLoadIn.Add(data); } return(true); }
private void TryToDeleteQueuedChunks() { var chunksToRemove = ChunksToRemove.ToList(); foreach (var chunkPosition in chunksToRemove) { if (RequestedChunks.ContainsKey(chunkPosition)) { RequestedChunks.Remove(chunkPosition); ChunksToRemove.Remove(chunkPosition); } else if (LoadedChunks.ContainsKey(chunkPosition)) { var chunk = LoadedChunks[chunkPosition]; chunk.Remove(); LoadedChunks.Remove(chunkPosition); ChunksToRemove.Remove(chunkPosition); } else if (!ChunksBeingGenerated.ContainsKey(chunkPosition)) { ChunksToRemove.Remove(chunkPosition); } } }
private void LoadInSingleChunk(ChunkData data) { Debug.BeginDeepProfile("chunk_load"); //Initiate chunk Vec2i chunk = new Vec2i(data.X, data.Z); if (LoadedChunks.ContainsKey(chunk)) { return; } GameObject chunkObject = Instantiate(ResourceManager.ChunkPrefab); chunkObject.transform.parent = transform; chunkObject.name = "Chunk " + chunk; //LoadedChunk loadedChunk = chunkObject.AddComponent<LoadedChunk>(); LoadedChunk loadedChunk = chunkObject.GetComponent <LoadedChunk>(); ChunkData[] neigh = { GetChunk(chunk.x, chunk.z + 1), GetChunk(chunk.x + 1, chunk.z + 1), GetChunk(chunk.x + 1, chunk.z) }; //ChunkData[] neigh = { null, null, null }; loadedChunk.SetChunkData(data, neigh); LoadedChunks.Add(chunk, loadedChunk); GameManager.EntityManager.LoadChunk(World.ChunkBases[chunk.x, chunk.z], chunk); Debug.EndDeepProfile("chunk_load"); }
public TerrainChunk GetGeneratedChunk(Vector2i chunkPosition) { if (LoadedChunks.ContainsKey(chunkPosition)) return LoadedChunks[chunkPosition]; return null; }
public bool GetNeighbouringChunkTile(Vector2Int chunk, Vector2Int direction, Vector2Int tilePosition, out Tile tile) { if (LoadedChunks.ContainsKey(chunk + direction)) { // 15 -> 0 (+1) // 0 -> 15 (-1) int xPosition = (int)tilePosition.x; int yPosition = (int)tilePosition.y; if (xPosition == -1) { xPosition = Chunk.SIZE - 1; } else if (xPosition == Chunk.SIZE) { xPosition = 0; } if (yPosition == -1) { yPosition = Chunk.SIZE - 1; } else if (yPosition == Chunk.SIZE) { yPosition = 0; } tile = LoadedChunks[chunk + direction].Tiles[xPosition, yPosition]; return(true); } tile = null; return(false); }
public bool ChunkCanBeRemoved(int x, int z) { var key = new Vector2i(x, z); return RequestedChunks.ContainsKey(key) || ChunksBeingGenerated.ContainsKey(key) || LoadedChunks.ContainsKey(key); }
/// <summary> /// Checks if the specified chunk coordinate is currently loaded, /// checking both the world, and checking if a subworld is loaded /// </summary> /// <param name="chunkPos"></param> /// <returns></returns> public bool IsCurrentChunkPositionLoaded(Vec2i chunkPos) { if (InSubworld) { return(SubworldChunks.ContainsKey(chunkPos)); } return(LoadedChunks.ContainsKey(chunkPos)); }
/// <summary> /// Chunks the can be added. /// </summary> /// <returns><c>true</c>, if can be added was chunked, <c>false</c> otherwise.</returns> /// <param name="x">The x coordinate.</param> /// <param name="z">The z coordinate.</param> public bool ChunkCanBeAdded(int x, int z) { var key = new XVec2I(x, z); return (!(RequestedChunks.ContainsKey(key) || ChunksBeingGenerated.ContainsKey(key) || LoadedChunks.ContainsKey(key))); }
public TerrainChunk GetGeneratedChunk(Vector2i chunkPosition) { if (LoadedChunks.ContainsKey(chunkPosition)) { return(LoadedChunks[chunkPosition]); } return(null); }
/// <summary> /// Iterates over a list of chunk positions and removes any position that is loaded in the world /// </summary> /// <param name="chunkPositions">The collection of chunk positions to filter</param> public void FilterLoadedChunks(List <Vector2Int> chunkPositions) { for (int i = chunkPositions.Count - 1; i >= 0; i--) { if (LoadedChunks.ContainsKey(chunkPositions[i])) { chunkPositions.RemoveAt(i); } } }
public void UnloadChunk(Vec2i chunk) { if (LoadedChunks.ContainsKey(chunk)) { LoadedChunk loaded = LoadedChunks[chunk]; LoadedChunks.Remove(chunk); GameManager.EntityManager.UnloadChunk(chunk); Destroy(loaded.gameObject); } }
/// <summary> /// Runs physics around a block. /// </summary> /// <param name="start">The location of the block.</param> public void SurroundRunPhysics(Location start) { start = start.GetBlockLocation(); Vector3i vec = ChunkLocFor(start); if (!LoadedChunks.ContainsKey(vec)) { // Don't physics on an unloaded block. The chunk load sequence will remind us to tick it. return; } RunBlockPhysics(start); foreach (Entity e in GetEntitiesInRadius(start + new Location(0.5), 2f)) { e.PotentialActivate(); } }
public void UnloadChunk(Vec2i chunk) { if (LoadedChunks.ContainsKey(chunk)) { LoadedChunk2 loaded = LoadedChunks[chunk]; lock (LoadedChunksLock) { LoadedChunks.Remove(chunk); } //We set inactive, and add it the chunk Loaders ChunkBuffer loaded.gameObject.SetActive(false); ChunkLoader.AddToChunkBuffer(loaded); //GameManager.EntityManager.UnloadChunk(chunk); //Destroy(loaded.gameObject); } }
public static Blocks GetBlock(int gx, int gy, int gz) { // Chunk position int cx = gx / SubChunk.WIDTH; int cz = gz / SubChunk.WIDTH; // Local position int lx = gx - (cx * SubChunk.WIDTH); int ly = gy; int lz = gz - (cz * SubChunk.WIDTH); if (ly > Chunk.MAX_BLOCK_HEIGHT - 1 || ly < 0) { return(Blocks.Air); } if (gx < 0) { if (gx % SubChunk.WIDTH != 0) { cx = gx / SubChunk.WIDTH - 1; } lx = gx - (SubChunk.WIDTH * cx); } if (gz < 0) { if (gz % SubChunk.WIDTH != 0) { cz = gz / SubChunk.WIDTH - 1; } lz = gz - (SubChunk.WIDTH * cz); } //Renderer.AddDebugBox(new DebugBox(new Vector3(gx + 0.5f, gy + 0.5f, gz + 0.5f), Color.Green)); Vector2 cv = new Vector2(cx, cz); if (LoadedChunks.ContainsKey(cv)) { return(LoadedChunks[cv].GetBlock(lx, ly, lz)); } return(Blocks.Air); }
/// <summary> /// Immediately updates all clouds known to the server. /// Called by the standard server tick loop. /// </summary> public void TickClouds() { foreach (Chunk chunk in LoadedChunks.Values) { // TODO: Only if pure air? if (chunk.WorldPosition.Z >= 2 && chunk.WorldPosition.Z <= 5) // TODO: Better estimating. Also, config? { if (Utilities.UtilRandom.Next(400) > 399) // TODO: Config? { double d1 = Utilities.UtilRandom.NextDouble() * Chunk.CHUNK_SIZE; double d2 = Utilities.UtilRandom.NextDouble() * Chunk.CHUNK_SIZE; double d3 = Utilities.UtilRandom.NextDouble() * Chunk.CHUNK_SIZE; Cloud cloud = new Cloud(this, chunk.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE + new Location(d1, d2, d3)); SpawnCloud(cloud); } } } for (int i = Clouds.Count - 1; i >= 0; i--) { // TODO: if in non-air chunk, dissipate rapidly? Location ppos = Clouds[i].Position; Clouds[i].Position = ppos + Wind + Clouds[i].Velocity; bool changed = (Utilities.UtilRandom.Next(100) > Clouds[i].Points.Count) && (Utilities.UtilRandom.Next(100) > Clouds[i].Points.Count) && (Utilities.UtilRandom.Next(100) > Clouds[i].Points.Count) && (Utilities.UtilRandom.Next(100) > Clouds[i].Points.Count); for (int s = 0; s < Clouds[i].Sizes.Count; s++) { Clouds[i].Sizes[s] += 0.05f; if (Clouds[i].Sizes[s] > Clouds[i].EndSizes[s]) { Clouds[i].Sizes[s] = Clouds[i].EndSizes[s]; } } foreach (PlayerEntity player in Players) { bool prev = player.ShouldSeeLODPositionOneSecondAgo(ppos); bool curr = player.ShouldLoadPosition(Clouds[i].Position); if (prev && !curr) { player.Network.SendPacket(new RemoveCloudPacketOut(Clouds[i].CID)); } else if (curr && (Clouds[i].IsNew || !prev)) { player.Network.SendPacket(new AddCloudPacketOut(Clouds[i])); } } Clouds[i].IsNew = false; if (changed) { AddToCloud(Clouds[i], 0f); foreach (PlayerEntity player in Players) { bool curr = player.ShouldLoadPosition(Clouds[i].Position); if (curr) { player.Network.SendPacket(new AddToCloudPacketOut(Clouds[i], Clouds[i].Points.Count - 1)); } } } Vector3i cpos = ChunkLocFor(Clouds[i].Position); if (!LoadedChunks.ContainsKey(cpos)) { DeleteCloud(Clouds[i]); continue; } } foreach (PlayerEntity player in Players) { player.losPos = player.GetPosition(); } }
public override void Update() { if (_unloaded) { return; } //Update entities foreach (var playerEntity in PlayerEntities) { playerEntity.Update(); } foreach (var entity in Entities) { entity.Update(); } lock (_chunksReadyToRemove) { while (_chunksReadyToRemove.Count > 0) { var chunkPos = _chunksReadyToRemove.First(); if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { lock (LoadedChunks) { LoadedChunks.Remove(chunkPos); } _populatedChunks.Remove(chunkPos); chunk.Dispose(); } _chunksReadyToRemove.Remove(chunkPos); } } lock (_chunksReadyToAdd) { while (_chunksReadyToAdd.Count > 0) { var entry = _chunksReadyToAdd.First(); lock (LoadedChunks) { if (!LoadedChunks.ContainsKey(entry.Key)) { LoadedChunks.Add(entry.Key, new Chunk(entry.Value)); } else { Logger.Error("Chunk has already been loaded! " + entry.Key); } } _populatedChunks.Add(entry.Key); _chunksReadyToAdd.Remove(entry.Key); } } while (_chunksReadyToUploadHp.Count > 0) { lock (_chunksReadyToUploadHp) { _chunksReadyToUploadHp.Dequeue().Upload(); } } while (_chunksReadyToUploadLp.Count > 0) { lock (_chunksReadyToUploadLp) { _chunksReadyToUploadLp.Dequeue().Upload(); } } }
private void LoadThread() { var chunksWaitingForNeighbours = new HashSet <Vector3i>(); while (!_unloaded) { //Remove chunks waiting that have been unloaded var chunksToRemove = chunksWaitingForNeighbours.Where( chunkPos => !_populatedChunks.Contains(chunkPos) && !_chunksReadyToAdd.ContainsKey(chunkPos) || _populatedChunks.Contains(chunkPos) && !LoadedChunks.ContainsKey(chunkPos)).ToList(); chunksToRemove.ForEach(chunkPos => chunksWaitingForNeighbours.Remove(chunkPos)); //Update chunks waiting for neighbours var chunksToUpdate = chunksWaitingForNeighbours.Where( chunkPos => BlockFaceHelper.Faces.All( face => _populatedChunks.Contains(chunkPos + face.GetNormali()))) .ToList(); foreach (var chunkPos in chunksToUpdate) { QueueChunkUpdate(chunkPos, true); chunksWaitingForNeighbours.Remove(chunkPos); } var playerChunksLists = new List <List <Vector3i> >(); foreach (var playerEntity in PlayerEntities) { var playerChunksToLoad = new List <Vector3i>(); var playerChunk = ChunkInWorld(playerEntity.Position.ToVector3i()); //Load 7x7x7 around player for (var x = -3; x <= 3; x++) { for (var y = -3; y <= 3; y++) { for (var z = -3; z <= 3; z++) { var chunkPos = playerChunk + new Vector3i(x, y, z); if (playerChunksToLoad.Contains(chunkPos)) { continue; } if (_populatedChunks.Contains(chunkPos) || _chunksReadyToAdd.ContainsKey(chunkPos)) { //Reset chunk time so it will not be unloaded if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { chunk.Time = DateTime.Now; } continue; } playerChunksToLoad.Add(chunkPos); } } } //Load 61x3x61 terrain if overworld //heightmap(x*Chunk.Size + Chunk.Size/2, z*Chunk.Size + Chunk.Size/2) var height = 0 + Chunk.Size / 2; var heightMapChunkY = ChunkInWorld(0, height, 0).Y; for (var x = -30; x <= 30; x++) { for (var y = -1; y <= 1; y++) { for (var z = -30; z <= 30; z++) { if (x <= 3 && x >= -3 && y <= 3 && y >= -3 && z <= 3 && z >= -3) { continue; } var chunkPos = new Vector3i(playerChunk.X + x, heightMapChunkY + y, playerChunk.Z + z); if (_populatedChunks.Contains(chunkPos) || _chunksReadyToAdd.ContainsKey(chunkPos)) { //Reset chunk time so it will not be unloaded if (LoadedChunks.TryGetValue(chunkPos, out var chunk)) { chunk.Time = DateTime.Now; } continue; } playerChunksToLoad.Add(chunkPos); } } } playerChunksToLoad.Sort( (v0, v1) => (int)(v0.ToVector3() - playerChunk.ToVector3()).LengthSquared - (int)(v1.ToVector3() - playerChunk.ToVector3()).LengthSquared); //Cap player chunk load tasks to 16 if (playerChunksToLoad.Count > 16) { playerChunksToLoad.RemoveRange(16, playerChunksToLoad.Count - 16); } playerChunksLists.Add(playerChunksToLoad); } var merged = ExtensionHelper.ZipMerge(playerChunksLists.ToArray()); foreach (var chunkPos in merged) { var cachedChunk = LoadChunk(chunkPos); if (cachedChunk.IsEmpty) { //Empty chunks dont need to be added to LoadedChunks lock (_populatedChunks) { _populatedChunks.Add(chunkPos); } } else { lock (_chunksReadyToAdd) { _chunksReadyToAdd.Add(chunkPos, cachedChunk); } chunksWaitingForNeighbours.Add(chunkPos); } } Thread.Sleep(10); } }
public static bool IsChunkLoaded(Vector2 position) { return(LoadedChunks.ContainsKey(position)); }