public Chunk GetChunk(float x, float z) { Vector2Int key = Chunk.NormalizeToChunkPosition(x, z); m_Chunks.TryGetValue(key, out Chunk chunk); return(chunk); }
private void UpdatePlayerPositionOnMainThread() { if (m_ChunksUpdatingRequired) // 上一次update未完成 { return; } Vector3 pos = m_PlayerTransform.localPosition; Vector3 forward = m_PlayerTransform.forward; Vector2Int lastChunkPos = Chunk.NormalizeToChunkPosition(m_PlayerPositionX, m_PlayerPositionZ); Vector2Int chunkPos = Chunk.NormalizeToChunkPosition(pos.x, pos.z); Interlocked.Exchange(ref m_PlayerPositionY, pos.y); if (lastChunkPos != chunkPos || forward.x != m_PlayerForwardX || forward.z != m_PlayerForwardZ) { Interlocked.Exchange(ref m_PlayerPositionX, pos.x); Interlocked.Exchange(ref m_PlayerPositionZ, pos.z); Interlocked.Exchange(ref m_PlayerForwardX, forward.x); Interlocked.Exchange(ref m_PlayerForwardZ, forward.z); m_ChunksUpdatingRequired = true; } }
private void RandomTickChunkOnMainThread() { m_TickChunkDeltaTime += Time.deltaTime; if (m_TickChunkDeltaTime < m_TickChunkInterval) { return; } m_TickChunkDeltaTime = 0; Vector3 pos = m_PlayerTransform.localPosition; Vector2Int chunkPos = Chunk.NormalizeToChunkPosition(pos.x, pos.z); // 只tick玩家周围的9个chunk中的一个 int i = m_TickChunkRandom.Next(-1, 2); int j = m_TickChunkRandom.Next(-1, 2); chunkPos.x += i * ChunkWidth; chunkPos.y += j * ChunkWidth; if (m_Chunks.TryGetValue(chunkPos, out Chunk chunk)) { chunk.RandomTick(m_TickChunkRandom, m_PlayerPositionY); } }
private void UpdateChunksThreadMethod() { ChunkPriorityComparer priorityComparer = new ChunkPriorityComparer(); PriorityQueue <ChunkNeedsLoading> updateChunkQueue = new PriorityQueue <ChunkNeedsLoading>(priorityComparer); HashSet <Vector2Int> inRangeChunks = new HashSet <Vector2Int>(m_ChunkPositionComparer); // 求交集优化 while (!m_Disposed) { if (!m_ChunksUpdatingRequired) // 不需要更新 { continue; } Profiler.BeginSample("Update Chunks"); updateChunkQueue.Clear(); inRangeChunks.Clear(); float playerX = m_PlayerPositionX; float playerZ = m_PlayerPositionZ; float forwardX = m_PlayerForwardX; float forwardZ = m_PlayerForwardZ; Vector2Int playerChunkPos = Chunk.NormalizeToChunkPosition(playerX, playerZ); Vector2 player = new Vector2(playerX, playerZ); Vector2 forward = new Vector2(forwardX, forwardZ).normalized; for (int x = -m_RenderChunkRadius; x <= m_RenderChunkRadius; x++) { for (int z = -m_RenderChunkRadius; z <= m_RenderChunkRadius; z++) { Vector2Int chunkPos = new Vector2Int(playerChunkPos.x + x * ChunkWidth, playerChunkPos.y + z * ChunkWidth); inRangeChunks.Add(chunkPos); lock (m_ChunksToRender) { if (m_ChunksToRender.Contains(chunkPos)) // 已经在渲染队列 { continue; } } Vector2 chunkCenterPos = chunkPos + new Vector2(ChunkWidth >> 1, ChunkWidth >> 1); Vector2 toChunkCenter = chunkCenterPos - player; float sqrDis = toChunkCenter.sqrMagnitude; float angle = Vector2.Angle(toChunkCenter, forward); bool close = sqrDis < SqrMinChunkDistance; bool inAngle = angle < m_HorizontalFOVInDEG; if (m_IsStartUp || inAngle || close) { updateChunkQueue.Enqueue(new ChunkNeedsLoading { ChunkPosition = chunkPos, PriorityFactor = sqrDis / m_SqrRenderRadius + angle / m_HorizontalFOVInDEG }); } } } lock (m_ChunksToRender) { m_ChunksToRender.IntersectWith(inRangeChunks); } while (updateChunkQueue.Count > 0) { Vector2Int chunk = updateChunkQueue.Dequeue().ChunkPosition; lock (m_ChunksToRender) { m_ChunksToRender.Add(chunk); } if (!m_Chunks.ContainsKey(chunk)) { m_ChunksToLoad.Enqueue(chunk); } } Profiler.EndSample(); if (m_Chunks.Count > m_MaxChunkCountInMemory) { Parallel.ForEach(m_Chunks, pair => { Vector2 playerPos = new Vector2(m_PlayerPositionX, m_PlayerPositionZ); pair.Value.MarkAsStartUp(); if ((pair.Key - playerPos).sqrMagnitude > 4 * m_SqrRenderRadius) { m_ChunksToUnload.Enqueue(pair.Key); } }); } //END m_ChunksUpdatingRequired = false; } }
private void LightBlocksOnMainThread() { // https://github.com/ddevault/TrueCraft/wiki/Lighting // https://github.com/ddevault/TrueCraft/blob/master/TrueCraft.Core/Lighting/WorldLighting.cs int count = m_BlocksToLightQueue.Count; if (count > MaxLightBlockCountPerFrame) { count = MaxLightBlockCountPerFrame; // 防止卡死 } WorldManager world = WorldManager.Active; while (count-- > 0) { Vector3Int blockPos = m_BlocksToLightQueue.Pop(); Vector2Int chunkPos = Chunk.NormalizeToChunkPosition(blockPos.x, blockPos.z); if (!m_Chunks.ContainsKey(chunkPos)) { continue; } int x = blockPos.x; int y = blockPos.y; int z = blockPos.z; Block block = world.GetBlock(x, y, z); int opacity = block.LightOpacity < MinBlockLightOpacity ? MinBlockLightOpacity : block.LightOpacity; int current = world.GetBlockLight(x, y, z); int finalLight = 0; if (opacity < MaxLight || block.LightValue > 0) // 不然就是0 { int max = world.GetBlockLight(x + 1, y, z); int temp; if ((temp = world.GetBlockLight(x - 1, y, z)) > max) { max = temp; } if ((temp = world.GetBlockLight(x, y + 1, z)) > max) { max = temp; } if ((temp = world.GetBlockLight(x, y - 1, z)) > max) { max = temp; } if ((temp = world.GetBlockLight(x, y, z + 1)) > max) { max = temp; } if ((temp = world.GetBlockLight(x, y, z - 1)) > max) { max = temp; } finalLight = max - opacity; if (block.LightValue > finalLight) { finalLight = block.LightValue; // 假设这个值一定是合法的(不过确实应该是合法的) } else if (finalLight < 0) { finalLight = 0; } //else if (finalLight > MaxLight) //{ // finalLight = MaxLight; //} } if (current != finalLight) { world.SetBlockLight(x, y, z, (byte)finalLight); m_BlocksToLightQueue.Push(new Vector3Int(x - 1, y, z)); m_BlocksToLightQueue.Push(new Vector3Int(x, y - 1, z)); m_BlocksToLightQueue.Push(new Vector3Int(x, y, z - 1)); m_BlocksToLightQueue.Push(new Vector3Int(x + 1, y, z)); m_BlocksToLightQueue.Push(new Vector3Int(x, y + 1, z)); m_BlocksToLightQueue.Push(new Vector3Int(x, y, z + 1)); } } }