예제 #1
0
    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);
    }
예제 #2
0
        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);
                }
            }
        }
예제 #3
0
    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");
    }
예제 #4
0
        public TerrainChunk GetGeneratedChunk(Vector2i chunkPosition)
        {
            if (LoadedChunks.ContainsKey(chunkPosition))
                return LoadedChunks[chunkPosition];

            return null;
        }
예제 #5
0
        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);
        }
예제 #6
0
 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));
 }
예제 #8
0
    /// <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)));
    }
예제 #9
0
        public TerrainChunk GetGeneratedChunk(Vector2i chunkPosition)
        {
            if (LoadedChunks.ContainsKey(chunkPosition))
            {
                return(LoadedChunks[chunkPosition]);
            }

            return(null);
        }
예제 #10
0
 /// <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);
         }
     }
 }
예제 #11
0
 public void UnloadChunk(Vec2i chunk)
 {
     if (LoadedChunks.ContainsKey(chunk))
     {
         LoadedChunk loaded = LoadedChunks[chunk];
         LoadedChunks.Remove(chunk);
         GameManager.EntityManager.UnloadChunk(chunk);
         Destroy(loaded.gameObject);
     }
 }
예제 #12
0
        /// <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();
            }
        }
예제 #13
0
    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);
        }
    }
예제 #14
0
        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);
        }
예제 #15
0
 /// <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();
     }
 }
예제 #16
0
        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();
                }
            }
        }
예제 #17
0
        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);
            }
        }
예제 #18
0
 public static bool IsChunkLoaded(Vector2 position)
 {
     return(LoadedChunks.ContainsKey(position));
 }