/// <summary> /// Adds this loaded chunk to the generation que /// </summary> /// <param name="chunk"></param> public void AddToGenerationQue(LoadedChunk2 chunk) { Debug.Log("Added to gen que"); float priority = chunk.LOD; //If we already contain this chunk, then we don't need to add again //Stay thread safe - add object lock (ChunkToLoadLock) { if (ChunksToLoad2.Contains(chunk)) { return; } ChunksToLoad2.Enqueue(chunk, priority); } if (MainThread == null || !MainThread.IsAlive) { //We start/restart the internal load loop MainThread = new Thread(() => InternalThreadLoop()); Debug.Log("[ChunkLoader] Chunk Loader thread starting", Debug.CHUNK_LOADING); MainThread.Start(); } }
/// <summary> /// Takes a 'preloadedchunk' and forms a loaded chunk /// This must be called from the main thread. /// </summary> /// <param name="pChunk"></param> /// <returns></returns> private LoadedChunk2 CreateChunk(PreLoadedChunk pChunk, ChunkData cd) { GameObject cObj = Instantiate(ChunkPrefab); cObj.transform.parent = ChunkHolder.transform; cObj.transform.position = pChunk.Position.AsVector3() * World.ChunkSize; cObj.name = "chunk_" + pChunk.Position; LoadedChunk2 loaded = cObj.GetComponent <LoadedChunk2>(); MeshFilter mf = loaded.GetComponent <MeshFilter>(); //Create the terrain mesh mf.mesh = PreLoadedChunk.CreateMesh(pChunk.TerrainMesh); mf.mesh.RecalculateNormals(); MeshCollider mc = loaded.GetComponent <MeshCollider>(); mc.sharedMesh = mf.mesh; //Iterate all voxels foreach (Voxel v in MiscUtils.GetValues <Voxel>()) { if (v == Voxel.none) { continue; } if (pChunk.VoxelMesh.TryGetValue(v, out PreMesh pmesh)) { GameObject voxelObj = Instantiate(ChunkVoxelPrefab); MeshFilter voxelMf = voxelObj.GetComponent <MeshFilter>(); voxelMf.mesh = PreLoadedChunk.CreateMesh(pmesh); Material voxMat = ResourceManager.GetVoxelMaterial(v); //Debug.Log(voxMat + " vox mat"); voxelObj.GetComponent <MeshRenderer>().material = voxMat; MeshCollider voxelMc = voxelObj.GetComponent <MeshCollider>(); voxelMc.sharedMesh = voxelMf.mesh; voxelObj.transform.parent = cObj.transform; voxelObj.transform.localPosition = Vector3.zero; voxelMf.mesh.RecalculateNormals(); } } if (cd.WorldObjects != null) { foreach (WorldObjectData objDat in cd.WorldObjects) { WorldObject obj = WorldObject.CreateWorldObject(objDat, cObj.transform, 0.7f); //if(objDat.AutoHeight) // obj.AdjustHeight(); //obj.transform.position = objDat.Position; //obj.transform.localPosition = objDat.Position.Mod(World.ChunkSize); } } loaded.SetChunk(pChunk.ChunkData); return(loaded); }
public override bool Equals(object other) { if (other == null || (other as LoadedChunk2) == null) { return(false); } LoadedChunk2 lc = other as LoadedChunk2; return(lc.Position == Position); }
private LoadedChunk2 CreateChunk(PreLoadedChunk pChunk) { GameObject cObj = Instantiate(ChunkPrefab); cObj.transform.parent = transform; cObj.name = "chunk_" + pChunk.Position; LoadedChunk2 loaded = cObj.GetComponent<LoadedChunk2>(); MeshFilter mf = loaded.GetComponent<MeshFilter>(); //Create the terrain mesh mf.mesh = PreLoadedChunk.CreateMesh(pChunk.TerrainMesh); mf.mesh.RecalculateNormals(); MeshCollider mc = loaded.GetComponent<MeshCollider>(); mc.sharedMesh = mf.mesh; //Iterate all voxels foreach (Voxel v in MiscUtils.GetValues<Voxel>()) { if (v == Voxel.none) continue; if (pChunk.VoxelMesh.TryGetValue(v, out PreMesh pmesh)) { GameObject voxelObj = Instantiate(ChunkVoxelPrefab); MeshFilter voxelMf = voxelObj.GetComponent<MeshFilter>(); MeshRenderer voxelMr = voxelObj.GetComponent<MeshRenderer>(); voxelMr.material = ResourceManager.GetVoxelMaterial(v); voxelMf.mesh = PreLoadedChunk.CreateMesh(pmesh); MeshCollider voxelMc = voxelObj.GetComponent<MeshCollider>(); voxelMc.sharedMesh = voxelMf.mesh; voxelObj.transform.parent = cObj.transform; voxelObj.transform.localPosition = Vector3.up * (pChunk.ChunkData.BaseHeight + 0.7f); voxelMf.mesh.RecalculateNormals(); } } cObj.transform.position = pChunk.Position.AsVector3() * World.ChunkSize; loaded.SetChunk(pChunk.ChunkData); if (pChunk.ChunkData.WorldObjects != null) { foreach (WorldObjectData objData in pChunk.ChunkData.WorldObjects) { Vec2i localPos = Vec2i.FromVector3(objData.Position.Mod(World.ChunkSize)); float off = loaded.Chunk.GetHeight(localPos); WorldObject obj = WorldObject.CreateWorldObject(objData, loaded.transform, off + 0.7f); obj.AdjustHeight(); } } return loaded; }
/// <summary> /// Adds the loaded chunk to the chunk buffer. /// This should be used when a chunk position is no longer required /// </summary> /// <param name="chunk"></param> public void AddToChunkBuffer(LoadedChunk2 chunk) { chunk.gameObject.name = "Unloaded"; if (chunk.HasLoadedWorldObjects || chunk.HasGeneratedVoxels) { foreach (Transform t in chunk.transform) { Destroy(t.gameObject); } } ChunkBuffer.Add(chunk); }
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); } }
private void LoadSingleObject(int count = 0) { if (count > 10) { return; } WorldObjectData objData = null; lock (ObjectsToLoadLock) { objData = ObjectsToLoad[0]; ObjectsToLoad.RemoveAt(0); } //Find the chunk for the first object to generate Vec2i chunk = World.GetChunkPosition(objData.Position); LoadedChunk2 lc2 = ChunkRegionManager.GetLoadedChunk(chunk); if (lc2 == null) { //Debug.Log(chunk); Debug.Log("[ChunkLoader] Chunk ( " + chunk + " ) for object ( " + objData + " ) is not loaded, attempting another object"); //if the chunk is null, we throw this object to the end of the que and try again. lock (ObjectsToLoadLock) { ObjectsToLoad.Add(objData); } LoadSingleObject(count + 1); return; } Vec2i localPos = Vec2i.FromVector3(objData.Position.Mod(World.ChunkSize)); float off = lc2.Chunk.GetHeight(localPos); WorldObject obj = WorldObject.CreateWorldObject(objData, lc2.transform, off + 0.7f); //Debug.Log("Created object " + obj); //obj.AdjustHeight(); }
/// <summary> /// Loads all chunks within a square of size 2*radius centred on the player /// </summary> /// <param name="middle"></param> /// <param name="radius"></param> public void LoadChunks(Vec2i middle, int radius, bool forceLoad) { Debug.BeginDeepProfile("load_chunks"); //We define a list of chunks to unload List <Vec2i> toUnload = new List <Vec2i>(); HashSet <int> currentlyLoadedH = new HashSet <int>(); lock (LoadedChunksLock) { //A list containing all the chunks currently loaded foreach (KeyValuePair <Vec2i, LoadedChunk2> kvp in LoadedChunks) { int distSqr = middle.QuickDistance(kvp.Key); if (distSqr > radius * radius) { toUnload.Add(kvp.Key); } currentlyLoadedH.Add(kvp.Key.GetHashCode()); } } lock (ToGetLoadedChunksLOCK) { foreach (KeyValuePair <ChunkData, int> kvp in ToGetLoadedChunks) { currentlyLoadedH.Add(kvp.Key.Position.GetHashCode()); } } foreach (Vec2i v in ChunkLoader.GetCurrentlyLoadingChunks()) { currentlyLoadedH.Add(v.GetHashCode()); } //We iterate each chunk too far from the player, and unload it foreach (Vec2i v in toUnload) { UnloadChunkSafe(v); //UnloadChunk(v); } LoadedChunksCentre = middle; Debug.EndDeepProfile("load_chunks"); Debug.BeginDeepProfile("load_chunks1"); //We now iterate the position of each chunk we require for (int x = -radius; x <= radius; x++) { for (int z = -radius; z <= radius; z++) { //Check if the requested position is inside world bounds if (x + middle.x < 0 || x + middle.x >= World.WorldSize - 1 || z + middle.z < 0 || z + middle.z >= World.WorldSize - 1) { continue; } Vec2i pos = new Vec2i(x + middle.x, z + middle.z); int distSqr = middle.QuickDistance(pos); if (distSqr > radius * radius) { continue; } int lod = CalculateLOD(distSqr); int posHash = pos.GetHashCode(); //if our currently loaded does not contain the position, we must generate it if (!currentlyLoadedH.Contains(posHash)) { //Attempt to get the chunk data ChunkData cd = GetChunk(pos); if (cd == null) { // Debug.Log("Chunk at " + pos + " was null"); continue; } lock (ToGetLoadedChunksLOCK) { ToGetLoadedChunks.Add(cd, lod); } //Load the entities for this chunk //TODO - check this doesn't cause issues with entities loading before chunks? //ChunkLoader.LoadChunk(cd); } else if (toUnload.Contains(pos)) { //We check if 'toUnload' contains this position (this should always happen if the chunk //isn't already loaded. //We then remove it from this list, as this list will define which chunks need to be unloaded. toUnload.Remove(pos); } else { //If the chunk is loaded, we get it and set its LOD - this ensures it will update if required LoadedChunk2 lc = GetLoadedChunk(pos); lc.SetLOD(lod); } } } Debug.BeginDeepProfile("load_chunks1"); }
/// <summary> /// Takes a 'preloadedchunk' and forms a loaded chunk /// This must be called from the main thread. /// </summary> /// <param name="pChunk"></param> /// <returns></returns> private LoadedChunk2 CreateChunk(PreLoadedChunk pChunk) { GameObject cObj = pChunk.LoadedChunk.gameObject; cObj.transform.parent = transform; cObj.name = "chunk_" + pChunk.Position; LoadedChunk2 loaded = pChunk.LoadedChunk; loaded.SetPreLoadedChunk(pChunk); loaded.gameObject.SetActive(true); MeshFilter mf = loaded.GetComponent <MeshFilter>(); //Create the terrain mesh mf.mesh = PreLoadedChunk.CreateMesh(pChunk.TerrainMesh); /*try * { * mf.mesh.RecalculateNormals(); * }catch(System.Exception e) * { * Debug.Log(e); * }*/ if (pChunk.LoadedChunk.LOD == 1) { MeshCollider mc = loaded.GetComponent <MeshCollider>(); mc.sharedMesh = mf.mesh; mc.enabled = true; } else { MeshCollider mc = loaded.GetComponent <MeshCollider>(); mc.sharedMesh = null; mc.enabled = false; } if (loaded.PreLoaded.VoxelMesh != null) { loaded.SetHasGeneratedVoxels(true); } if (loaded.LOD < 4 && loaded.HasGeneratedVoxels) { //loaded.SetHasGeneratedVoxels(true); //Iterate all voxels foreach (Voxel v in MiscUtils.GetValues <Voxel>()) { if (v == Voxel.none) { continue; } if (pChunk.VoxelMesh.TryGetValue(v, out PreMesh pmesh)) { GameObject voxelObj = Instantiate(ChunkVoxelPrefab); MeshFilter voxelMf = voxelObj.GetComponent <MeshFilter>(); MeshRenderer voxelMr = voxelObj.GetComponent <MeshRenderer>(); voxelMr.material = ResourceManager.GetVoxelMaterial(v); voxelMf.mesh = PreLoadedChunk.CreateMesh(pmesh); MeshCollider voxelMc = voxelObj.GetComponent <MeshCollider>(); voxelMc.sharedMesh = voxelMf.mesh; voxelObj.transform.parent = cObj.transform; voxelObj.transform.localPosition = Vector3.zero; // voxelMf.mesh.RecalculateNormals(); } } } cObj.transform.position = pChunk.Position.AsVector3() * World.ChunkSize; if (loaded.LOD < 3 && !loaded.HasLoadedWorldObjects) { loaded.SetHasLoadedWorldObjects(true); //loaded.SetChunk(pChunk.ChunkData); lock (ObjectsToLoadLock) { if (pChunk.ChunkData.WorldObjects != null) { ObjectsToLoad.AddRange(pChunk.ChunkData.WorldObjects); } } } return(loaded); }
public void SetLoadedChunk(LoadedChunk2 lc) { LoadedChunk = lc; }