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); }
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); } } }
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; } } }
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); }
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; } } }
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; } }
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); }
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; } } } }