Beispiel #1
0
        public bool Subscribe(IEventListener <ChunkState> listener, ChunkState evt, bool registerListener)
        {
            if (listener == null || listener == this)
            {
                return(false);
            }

            ChunkEvent chunkListener = (ChunkEvent)listener;

            // Register
            if (registerListener)
            {
                // Make sure this section is not registered yet
                for (int i = 0; i < Listeners.Length; i++)
                {
                    ChunkEvent l = Listeners[i];

                    // Do not register if already registred
                    if (l == listener)
                    {
                        return(false);
                    }
                }

                // Subscribe in the first free slot
                for (int i = 0; i < Listeners.Length; i++)
                {
                    ChunkEvent l = Listeners[i];
                    if (l == null)
                    {
                        ++ListenerCount;
                        Assert.IsTrue(ListenerCount <= 6);
                        Listeners[i] = chunkListener;
                        return(true);
                    }
                }

                // We want to register but there is no free space
                Assert.IsTrue(false);
            }
            // Unregister
            else
            {
                // Only unregister already registered sections
                for (int i = 0; i < Listeners.Length; i++)
                {
                    ChunkEvent l = Listeners[i];

                    if (l == listener)
                    {
                        --ListenerCount;
                        Assert.IsTrue(ListenerCount >= 0);
                        Listeners[i] = null;
                        return(true);
                    }
                }
            }

            return(false);
        }
Beispiel #2
0
 public void NotifyAll(ChunkState state)
 {
     // Notify each registered listener
     for (int i = 0; i < Listeners.Length; i++)
     {
         ChunkEvent l = Listeners[i];
         if (l != null)
         {
             l.OnNotified(this, state);
         }
     }
 }
Beispiel #3
0
 public void NotifyOne(IEventListener <ChunkState> listener, ChunkState state)
 {
     // Notify one of the listeners
     for (int i = 0; i < Listeners.Length; i++)
     {
         ChunkEvent l = Listeners[i];
         if (l == listener)
         {
             l.OnNotified(this, state);
             return;
         }
     }
 }
Beispiel #4
0
        private ChunkBlocks HandleNeighborBack(ref Vector3Int pos)
        {
            ChunkStateManagerClient stateManager = chunk.stateManager;
            int i = DirectionUtils.Get(Direction.south);

            // If it is an edge position, notify neighbor as well
            // Iterate over neighbors and decide which ones should be notified to rebuild
            var        listeners = stateManager.Listeners;
            ChunkEvent listener  = listeners[i];

            if (listener == null)
            {
                return(null);
            }

            ChunkStateManagerClient listenerClient = (ChunkStateManagerClient)listener;
            Chunk listenerChunk = listenerClient.chunk;

            int cx = chunk.pos.x;
            int cy = chunk.pos.y;
            int cz = chunk.pos.z;
            int lx = listenerChunk.pos.x;
            int ly = listenerChunk.pos.y;
            int lz = listenerChunk.pos.z;

            if (ly != cy && lx != cx)
            {
                return(null);
            }

            if (pos.z != 0 || (lz + m_sideSize != cz))
            {
                return(null);
            }

            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
            return(listenerChunk.blocks);
        }
Beispiel #5
0
        public void HandleNeighbors(BlockData block, Vector3Int pos)
        {
            if (!NeedToHandleNeighbors(ref pos))
            {
                return;
            }

            int cx = chunk.pos.x;
            int cy = chunk.pos.y;
            int cz = chunk.pos.z;

            ChunkStateManagerClient stateManager = chunk.stateManager;

            // If it is an edge position, notify neighbor as well
            // Iterate over neighbors and decide which ones should be notified to rebuild their geometry
            var listeners = stateManager.Listeners;

            for (int i = 0; i < listeners.Length; i++)
            {
                ChunkEvent listener = listeners[i];
                if (listener == null)
                {
                    continue;
                }

                ChunkStateManagerClient listenerClient = (ChunkStateManagerClient)listener;
                Chunk       listenerChunk       = listenerClient.chunk;
                ChunkBlocks listenerChunkBlocks = listenerChunk.blocks;

                int lx = listenerChunk.pos.x;
                int ly = listenerChunk.pos.y;
                int lz = listenerChunk.pos.z;

                if (ly == cy || lz == cz)
                {
                    // Section to the left
                    if ((pos.x == 0) && (lx + m_sideSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(m_sideSize, pos.y, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                    // Section to the right
                    else if ((pos.x == (m_sideSize - 1)) && (lx - m_sideSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(-1, pos.y, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                }

                if (lx == cx || lz == cz)
                {
                    // Section to the bottom
                    if ((pos.y == 0) && (ly + m_sideSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, m_sideSize, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                    // Section to the top
                    else if ((pos.y == (m_sideSize - 1)) && (ly - m_sideSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, -1, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                }

                if (ly == cy || lx == cx)
                {
                    // Section to the back
                    if ((pos.z == 0) && (lz + m_sideSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, m_sideSize, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                    // Section to the front
                    else if ((pos.z == (m_sideSize - 1)) && (lz - m_sideSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, -1, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                }

                // No further checks needed once we know all neighbors need to be notified
                if (rebuildMaskGeometry == 0x3f)
                {
                    break;
                }
            }
        }
Beispiel #6
0
        public void Update()
        {
            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            if (m_setBlockQueue.Count > 0)
            {
                if (rebuildMaskGeometry < 0)
                {
                    rebuildMaskGeometry = 0;
                }
                if (rebuildMaskCollider < 0)
                {
                    rebuildMaskCollider = 0;
                }

                // Modify blocks
                for (int j = 0; j < m_setBlockQueue.Count; j++)
                {
                    SetBlockContext context = m_setBlockQueue[j];

                    int x, y, z;
                    Helpers.GetChunkIndex3DFrom1D(context.Index, out x, out y, out z);

                    Vector3Int pos       = new Vector3Int(x, y, z);
                    Vector3Int globalPos = pos + chunk.pos;

                    BlockData oldBlockData = blocks.Get(context.Index);

                    Block oldBlock = m_blockTypes[oldBlockData.Type];
                    Block newBlock = m_blockTypes[context.Block.Type];
                    oldBlock.OnDestroy(chunk, pos, globalPos);
                    newBlock.OnCreate(chunk, pos, globalPos);

                    blocks.Set(context.Index, context.Block);

                    if (context.SetBlockModified)
                    {
                        BlockModified(new BlockPos(x, y, z), globalPos, context.Block);

                        chunk.blocks.contentsInvalidated = true;
                    }

                    if (
                        // Only check neighbors if it is still needed
                        rebuildMaskGeometry == 0x3f ||
                        // Only check neighbors when it is a change of a block on a chunk's edge
                        (((pos.x + 1) & Env.ChunkMask) > 1 &&
                         ((pos.y + 1) & Env.ChunkMask) > 1 &&
                         ((pos.z + 1) & Env.ChunkMask) > 1)
                        )
                    {
                        continue;
                    }

                    int cx = chunk.pos.x;
                    int cy = chunk.pos.y;
                    int cz = chunk.pos.z;

                    // If it is an edge position, notify neighbor as well
                    // Iterate over neighbors and decide which ones should be notified to rebuild
                    for (int i = 0; i < stateManager.Listeners.Length; i++)
                    {
                        ChunkEvent listener = stateManager.Listeners[i];
                        if (listener == null)
                        {
                            continue;
                        }

                        // No further checks needed once we know all neighbors need to be notified
                        if (rebuildMaskGeometry == 0x3f)
                        {
                            break;
                        }

                        ChunkStateManagerClient listenerChunk = (ChunkStateManagerClient)listener;

                        int lx = listenerChunk.chunk.pos.x;
                        int ly = listenerChunk.chunk.pos.y;
                        int lz = listenerChunk.chunk.pos.z;

                        if ((ly == cy || lz == cz) &&
                            (
                                // Section to the left
                                ((pos.x == 0) && (lx + Env.ChunkSize == cx)) ||
                                // Section to the right
                                ((pos.x == Env.ChunkMask) && (lx - Env.ChunkSize == cx))
                            ))
                        {
                            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
                        }

                        if ((lx == cx || lz == cz) &&
                            (
                                // Section to the bottom
                                ((pos.y == 0) && (ly + Env.ChunkSize == cy)) ||
                                // Section to the top
                                ((pos.y == Env.ChunkMask) && (ly - Env.ChunkSize == cy))
                            ))
                        {
                            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
                        }

                        if ((ly == cy || lx == cx) &&
                            (
                                // Section to the back
                                ((pos.z == 0) && (lz + Env.ChunkSize == cz)) ||
                                // Section to the front
                                ((pos.z == Env.ChunkMask) && (lz - Env.ChunkSize == cz))
                            ))
                        {
                            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
                        }
                    }

                    rebuildMaskCollider |= rebuildMaskGeometry;
                }

                m_setBlockQueue.Clear();
            }

            long now = Globals.Watch.ElapsedMilliseconds;

            // Request a geometry update at most 10 times a second
            if (rebuildMaskGeometry >= 0 && now - lastUpdateTimeGeometry >= 100)
            {
                lastUpdateTimeGeometry = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildVerticesNow);;

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskGeometry > 0)
                {
                    for (int j = 0; j < stateManager.Listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)stateManager.Listeners[j];
                        if (listener != null && ((rebuildMaskGeometry >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            listener.RequestState(ChunkState.BuildVerticesNow);
                        }
                    }
                }

                rebuildMaskGeometry = -1;
            }

            // Request a collider update at most 4 times a second
            if (chunk.NeedsCollider && rebuildMaskCollider >= 0 && now - lastUpdateTimeCollider >= 250)
            {
                lastUpdateTimeCollider = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildCollider);

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskCollider > 0)
                {
                    for (int j = 0; j < stateManager.Listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)stateManager.Listeners[j];
                        if (listener != null && ((rebuildMaskCollider >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            if (listener.chunk.NeedsCollider)
                            {
                                listener.RequestState(ChunkState.BuildCollider);
                            }
                        }
                    }
                }

                rebuildMaskCollider = -1;
            }
        }
Beispiel #7
0
        public bool Subscribe(IEventListener <ChunkState> listener, ChunkState evt, bool registerListener)
        {
            if (listener == null || listener == this)
            {
                return(false);
            }

            // Determine neighbors's direction as compared to current chunk
            Chunk      chunk         = ((ChunkStateManager)this).chunk;
            Chunk      chunkNeighbor = ((ChunkStateManager)listener).chunk;
            Vector3Int p             = chunk.pos - chunkNeighbor.pos;
            Direction  dir           = Direction.up;

            if (p.x < 0)
            {
                dir = Direction.east;
            }
            else if (p.x > 0)
            {
                dir = Direction.west;
            }
            else if (p.z < 0)
            {
                dir = Direction.north;
            }
            else if (p.z > 0)
            {
                dir = Direction.south;
            }
            else if (p.y > 0)
            {
                dir = Direction.down;
            }

            ChunkEvent chunkListener = (ChunkEvent)listener;

            // Register
            if (registerListener)
            {
                ChunkEvent l = Listeners[(int)dir];

                // Do not register if already registred
                if (l == listener)
                {
                    return(false);
                }

                // Subscribe in the first free slot
                if (l == null)
                {
                    ++ListenerCount;
                    Assert.IsTrue(ListenerCount <= 6);
                    Listeners[(int)dir] = chunkListener;
                    return(true);
                }

                // We want to register but there is no free space
                Assert.IsTrue(false);
            }
            // Unregister
            else
            {
                ChunkEvent l = Listeners[(int)dir];

                // Do not unregister if it's something else than we expected
                if (l != listener && l != null)
                {
                    Assert.IsTrue(false);
                    return(false);
                }

                // Only unregister already registered sections
                if (l == listener)
                {
                    --ListenerCount;
                    Assert.IsTrue(ListenerCount >= 0);
                    Listeners[(int)dir] = null;
                    return(true);
                }
            }

            return(false);
        }
Beispiel #8
0
        private void ProcessSetBlockQueue(BlockData block, int index, bool setBlockModified)
        {
            int x, y, z;

            Helpers.GetChunkIndex3DFrom1D(index, out x, out y, out z);

            if (x < 0 || y < 0 || z < 0 || x > Env.ChunkMask || y > Env.ChunkMask || z > Env.ChunkMask)
            {
                Assert.IsTrue(false, "Chunk index out of range in setBlockQueue");
                return;
            }

            Vector3Int pos       = new Vector3Int(x, y, z);
            Vector3Int globalPos = pos + chunk.pos;

            BlockData oldBlockData = blocks[index];

            Block oldBlock = m_blockTypes[oldBlockData.Type];
            Block newBlock = m_blockTypes[block.Type];

            oldBlock.OnDestroy(chunk, pos);
            newBlock.OnCreate(chunk, pos);

            SetInternal(index, ref pos, block);

            if (setBlockModified)
            {
                BlockModified(new BlockPos(x, y, z), globalPos, block);

                chunk.blocks.contentsInvalidated = true;
            }

            if (
                // Only check neighbors if it is still needed
                rebuildMaskGeometry == 0x3f ||
                // Only check neighbors when it is a change of a block on a chunk's edge
                (((pos.x + 1) & Env.ChunkMask) > 1 &&
                 ((pos.y + 1) & Env.ChunkMask) > 1 &&
                 ((pos.z + 1) & Env.ChunkMask) > 1)
                )
            {
                return;
            }

            int cx = chunk.pos.x;
            int cy = chunk.pos.y;
            int cz = chunk.pos.z;

            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            // If it is an edge position, notify neighbor as well
            // Iterate over neighbors and decide which ones should be notified to rebuild
            for (int i = 0; i < stateManager.Listeners.Length; i++)
            {
                ChunkEvent listener = stateManager.Listeners[i];
                if (listener == null)
                {
                    continue;
                }

                // No further checks needed once we know all neighbors need to be notified
                if (rebuildMaskGeometry == 0x3f)
                {
                    break;
                }

                ChunkStateManagerClient listenerClient = (ChunkStateManagerClient)listener;
                Chunk listenerChunk = listenerClient.chunk;

                int lx = listenerChunk.pos.x;
                int ly = listenerChunk.pos.y;
                int lz = listenerChunk.pos.z;

                if (ly == cy || lz == cz)
                {
                    // Section to the left
                    if ((pos.x == 0) && (lx + Env.ChunkSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(Env.ChunkSize, y, z);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                    // Section to the right
                    else if ((pos.x == Env.ChunkMask) && (lx - Env.ChunkSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(-1, y, z);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                }

                if (lx == cx || lz == cz)
                {
                    // Section to the bottom
                    if ((pos.y == 0) && (ly + Env.ChunkSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, Env.ChunkSize, y);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                    // Section to the top
                    else if ((pos.y == Env.ChunkMask) && (ly - Env.ChunkSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, -1, y);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                }

                if (ly == cy || lx == cx)
                {
                    // Section to the back
                    if ((pos.z == 0) && (lz + Env.ChunkSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, y, Env.ChunkSize);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                    // Section to the front
                    else if ((pos.z == Env.ChunkMask) && (lz - Env.ChunkSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, y, -1);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                }
            }
        }