public void ProcessChunk(Chunk chunk) { Profiler.BeginSample("ProcessChunk"); ChunkStateManagerClient stateManager = chunk.stateManager; int tx = m_clipmap.TransformX(chunk.pos.x / Env.ChunkSize); int ty = m_clipmap.TransformY(chunk.pos.y / Env.ChunkSize); int tz = m_clipmap.TransformZ(chunk.pos.z / Env.ChunkSize); // Chunk is too far away. Remove it if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz)) { stateManager.RequestState(ChunkState.Remove); } else { // Dummy collider example - create a collider for chunks directly surrounding the viewer int xd = Helpers.Abs((m_viewerPos.x - chunk.pos.x) / Env.ChunkSize); int yd = Helpers.Abs((m_viewerPos.y - chunk.pos.y) / Env.ChunkSize); int zd = Helpers.Abs((m_viewerPos.z - chunk.pos.z) / Env.ChunkSize); chunk.NeedsCollider = xd <= 1 && yd <= 1 && zd <= 1; if (!UseFrustumCulling) { ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz); // Chunk is in visibilty range. Full update with geometry generation is possible if (item.IsInVisibleRange) { //chunk.LOD = item.LOD; stateManager.PossiblyVisible = true; stateManager.Visible = true; } // Chunk is in cached range. Full update except for geometry generation else { //chunk.LOD = item.LOD; stateManager.PossiblyVisible = true; stateManager.Visible = false; } } } }
/// <summary> /// Sends a save request to all chunk currently loaded /// </summary> /// <param name="world">World holding chunks</param> /// <returns>List of chunks waiting to be saved.</returns> public static List <Chunk> SaveAll(World world) { if (world == null || !Features.UseSerialization) { return(null); } List <Chunk> chunksToSave = new List <Chunk> (); foreach (Chunk chunk in world.chunks.chunkCollection) { // Ignore chunks that can't be saved at the moment ChunkStateManagerClient stateManager = chunk.stateManager; if (!stateManager.IsSavePossible) { continue; } chunksToSave.Add(chunk); stateManager.RequestState(ChunkState.PrepareSaveData); } return(chunksToSave); }
public void ProcessChunk(Chunk chunk) { Profiler.BeginSample("ProcessChunk"); ChunkStateManagerClient stateManager = chunk.stateManager; int xd = (m_viewerPos.x - chunk.pos.x) / Env.ChunkSize; int yd = (m_viewerPos.y - chunk.pos.y) / Env.ChunkSize; int zd = (m_viewerPos.z - chunk.pos.z) / Env.ChunkSize; int hRadius = HorizontalChunkLoadRadius; int vRadius = VerticalChunkLoadRadius; int xDist = xd * xd + zd * zd; int yDist = yd * yd; // Remove the chunk if it is too far away if (xDist > hRadius * hRadius || yDist > vRadius * vRadius) { stateManager.RequestState(ChunkState.Remove); } else { // Dummy collider example - create a collider for chunks directly surrounding the viewer chunk.NeedsCollider = Helpers.Abs(xd) <= 1 && Helpers.Abs(yd) <= 1 && Helpers.Abs(zd) <= 1; if (!UseFrustumCulling) { // Update visibility information stateManager.Visible = xDist <= HorizontalChunkLoadRadius * HorizontalChunkLoadRadius && yDist <= VerticalChunkLoadRadius * VerticalChunkLoadRadius; stateManager.PossiblyVisible = true; } } Profiler.EndSample(); }
public void Update() { ChunkStateManagerClient stateManager = chunk.stateManager; if (!stateManager.IsUpdateBlocksPossible) { return; } //UnityEngine.Debug.Log(m_setBlockQueue.Count); if (m_setBlockQueue.Count > 0) { if (rebuildMaskGeometry < 0) { rebuildMaskGeometry = 0; } if (rebuildMaskCollider < 0) { rebuildMaskCollider = 0; } var timeBudget = Globals.SetBlockBudget; // Modify blocks int j; for (j = 0; j < m_setBlockQueue.Count; j++) { timeBudget.StartMeasurement(); m_setBlockQueue[j].Apply(this); timeBudget.StopMeasurement(); // Sync edges if there's enough time /*if (!timeBudget.HasTimeBudget) * { ++j; * break; * }*/ } rebuildMaskCollider |= rebuildMaskGeometry; if (j == m_setBlockQueue.Count) { m_setBlockQueue.Clear(); } else { m_setBlockQueue.RemoveRange(0, j); return; } } 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 rebuild their geometry if (rebuildMaskGeometry > 0) { var listeners = stateManager.Listeners; for (int j = 0; j < listeners.Length; j++) { ChunkStateManagerClient listener = (ChunkStateManagerClient)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.BuildColliderNow); // Notify neighbors that they need to rebuilt their geometry if (rebuildMaskCollider > 0) { var listeners = stateManager.Listeners; for (int j = 0; j < listeners.Length; j++) { ChunkStateManagerClient listener = (ChunkStateManagerClient)listeners[j]; if (listener != null && ((rebuildMaskCollider >> j) & 1) != 0) { // Request rebuild on neighbor chunks if (listener.chunk.NeedsCollider) { listener.RequestState(ChunkState.BuildColliderNow); } } } } rebuildMaskCollider = -1; } }
public void ProcessChunk(Chunk chunk) { int xd = Helpers.Abs((m_viewerPos.x - chunk.pos.x) >> Env.ChunkPower); int yd = Helpers.Abs((m_viewerPos.y - chunk.pos.y) >> Env.ChunkPower); int zd = Helpers.Abs((m_viewerPos.z - chunk.pos.z) >> Env.ChunkPower); int tx = m_clipmap.TransformX(chunk.pos.x >> Env.ChunkPower); int ty = m_clipmap.TransformY(chunk.pos.y >> Env.ChunkPower); int tz = m_clipmap.TransformZ(chunk.pos.z >> Env.ChunkPower); ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager; // Chunk is too far away. Remove it if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz)) { stateManager.RequestState(ChunkState.Remove); } else { // Dummy collider example - create a collider for chunks directly surrounding the viewer chunk.NeedsCollider = xd <= 1 && yd <= 1 && zd <= 1; // Chunk is within view frustum if (FullLoadOnStartUp || IsChunkInViewFrustum(chunk)) { ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz); // Chunk is within visibilty range. Full update with geometry generation is possible if (item.IsWithinVisibleRange) { //chunk.LOD = item.LOD; stateManager.PossiblyVisible = true; stateManager.Visible = true; } // Chunk is within cached range. Full update except for geometry generation else // if (item.IsWithinCachedRange) { //chunk.LOD = item.LOD; stateManager.PossiblyVisible = true; stateManager.Visible = false; } } else { ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz); // Chunk is not in the view frustum but still within cached range if (item.IsWithinCachedRange) { //chunk.LOD = item.LOD; stateManager.PossiblyVisible = false; stateManager.Visible = false; } else // Weird state { Assert.IsFalse(true); stateManager.RequestState(ChunkState.Remove); } } } }
private void ProcessSetBlockQueue() { if (m_setBlockQueue.Count <= 0) { return; } StateManager.RequestState(ChunkState.FinalizeData | ChunkState.BuildVerticesNow); int rebuildMask = 0; // Modify blocks for (int j = 0; j < m_setBlockQueue.Count; j++) { SetBlockContext context = m_setBlockQueue[j]; int x, y, z; Helpers.GetIndex3DFrom1D(context.Index, out x, out y, out z); this[x, y, z] = context.Block; if ( // Only check neighbors if it is still needed rebuildMask == 0x3f || // Only check neighbors when it is a change of a block on a chunk's edge (((x + 1) & EngineSettings.ChunkConfig.Mask) > 1 && ((y + 1) & EngineSettings.ChunkConfig.Mask) > 1 && ((z + 1) & EngineSettings.ChunkConfig.Mask) > 1) ) { continue; } int cx = Pos.X; int cy = Pos.Y; int cz = 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 (rebuildMask == 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 ((x == 0) && (lx + EngineSettings.ChunkConfig.Mask == cx)) || // Section to the right ((x == EngineSettings.ChunkConfig.Mask) && (lx - EngineSettings.ChunkConfig.Mask == cx)) )) { rebuildMask = rebuildMask | (1 << i); } if ((lx == cx || lz == cz) && ( // Section to the bottom ((y == 0) && (ly + EngineSettings.ChunkConfig.Mask == cy)) || // Section to the top ((y == EngineSettings.ChunkConfig.Mask) && (ly - EngineSettings.ChunkConfig.Mask == cy)) )) { rebuildMask = rebuildMask | (1 << i); } if ((ly == cy || lx == cx) && ( // Section to the back ((z == 0) && (lz + EngineSettings.ChunkConfig.Mask == cz)) || // Section to the front ((z == EngineSettings.ChunkConfig.Mask) && (lz - EngineSettings.ChunkConfig.Mask == cz)) )) { rebuildMask = rebuildMask | (1 << i); } } } m_setBlockQueue.Clear(); // Notify neighbors that they need to rebuilt their geometry if (rebuildMask > 0) { for (int j = 0; j < StateManager.Listeners.Length; j++) { ChunkStateManagerClient listener = (ChunkStateManagerClient)StateManager.Listeners[j]; if (listener != null && ((rebuildMask >> j) & 1) != 0) { listener.RequestState(ChunkState.FinalizeData | ChunkState.BuildVerticesNow); } } } }
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 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]; if (!context.IsRange()) { ProcessSetBlockQueue(context.Block, context.IndexFrom, context.SetBlockModified); } else { int sx, sy, sz, ex, ey, ez; Helpers.GetChunkIndex3DFrom1D(context.IndexFrom, out sx, out sy, out sz); Helpers.GetChunkIndex3DFrom1D(context.IndexTo, out ex, out ey, out ez); for (int y = sy; y <= ey; y++) { for (int z = sz; z <= ez; z++) { for (int x = sx; x <= ex; x++) { int index = Helpers.GetChunkIndex1DFrom3D(x, y, z); ProcessSetBlockQueue(context.Block, index, context.SetBlockModified); } } } } } 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; } }