private void ChunkResyncing_Threaded(VisualChunk chunk) { if (chunk.IsServerResyncMode) { _landscapeManager.CreateLandScape(chunk); } chunk.ThreadStatus = ThreadsManager.ThreadStatus.Idle; }
/// <summary> /// Get a world's chunk from a chunk location in world coordinate with array bound test /// </summary> /// <param name="X">Chunk X coordinate</param> /// <param name="Z">Chunk Z coordinate</param> /// <returns></returns> public bool GetSafeChunkFromChunkCoord(int X, int Z, out VisualChunk chunk) { //From Chunk coordinate to World Coordinate X *= AbstractChunk.ChunkSize.X; Z *= AbstractChunk.ChunkSize.Z; return(GetSafeChunk(X, Z, out chunk)); }
//Will create the chunk buffer, ready to be sent to the GC private void CreateChunkMeshes_Threaded(VisualChunk chunk) { #if PERFTEST Utopia.Worlds.Chunks.WorldChunks.perf.AddData("CreateChunkMeshes_Threaded Started " + chunk.ChunkID); #endif //The chunk surrounding me must all have their landscape created ! _chunkMeshManager.CreateChunkMesh(chunk); chunk.ThreadStatus = ThreadsManager.ThreadStatus.Idle; }
/// <summary> /// Get a world's chunk from a Cube location in world coordinate with out of array check /// </summary> /// <param name="X">Cube X coordinate in world coordinate</param> /// <param name="Z">Cube Z coordinate in world coordinate</param> /// <param name="chunk">The VisualChunk return</param> /// <returns>True if the chunk was found</returns> public bool GetSafeChunk(int X, int Z, out VisualChunk chunk) { if (X < VisualWorldParameters.WorldRange.Position.X || X >= VisualWorldParameters.WorldRange.Max.X || Z < VisualWorldParameters.WorldRange.Position.Z || Z >= VisualWorldParameters.WorldRange.Max.Z) { chunk = null; return(false); } chunk = GetChunk(X, Z); return(true); }
/// <summary> /// Get a world's chunk from a chunk location in world coordinate /// </summary> /// <param name="X">Chunk X coordinate</param> /// <param name="Z">Chunk Z coordinate</param> /// <returns></returns> public VisualChunk[] GetFourSurroundingChunkFromChunkCoord(int X, int Z) { VisualChunk[] surroundingChunk = new VisualChunk[4]; surroundingChunk[0] = GetChunkFromChunkCoord(X + 1, Z); surroundingChunk[1] = GetChunkFromChunkCoord(X, Z + 1); surroundingChunk[2] = GetChunkFromChunkCoord(X - 1, Z); surroundingChunk[3] = GetChunkFromChunkCoord(X, Z - 1); return(surroundingChunk); }
//Will propagate light from chunk surrounding the current chunk private void ChunkOuterLightPropagation_Threaded(VisualChunk chunk) { #if PERFTEST Utopia.Worlds.Chunks.WorldChunks.perf.AddData("ChunkOuterLightPropagation_Threaded Started " + chunk.ChunkID); #endif _lightingManager.PropagateOutsideChunkLightSources(chunk); chunk.ThreadStatus = ThreadsManager.ThreadStatus.Idle; //The state will always be OuterLightSourcesProcessed, but the logic could not be implementated if the chunk was a Border chunk. In this case its //IsOutsideLightSourcePropagated will be False, it will be process as soon as the chunk isBorderChunk change to false ! }
public void DrawStaticEntitiesShadow(DeviceContext context, VisualChunk chunk) { //For Each different entity Model foreach (var pair in chunk.AllPairs()) { if (pair.Value.Count == 0) { continue; } var entity = pair.Value.First(); entity.VisualVoxelModel.DrawInstanced(context, pair.Value.Where(ve => IsEntityVisible(ve.Entity.Position)).Select(ve => ve.VoxelEntity.ModelInstance).ToList()); } }
//Will create new chunks based on chunks with state = Empty private void CreateNewChunk() { //Process each chunk that are in Empty state, and not currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => (x.State == ChunkState.Empty || x.State == ChunkState.LandscapeCreated) && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle)) { VisualChunk localChunk = chunk; //Start chunk creation process in a threaded way ! localChunk.ThreadStatus = ThreadsManager.ThreadStatus.Locked; //Lock the thread before entering async process. #if DEBUG localChunk.ThreadLockedBy = "CreateNewChunk"; #endif //SmartThread.ThreadPool.QueueWorkItem(ChunkCreationThreadedSteps_Threaded, chunk, WorkItemPriority.Normal); S33M3DXEngine.Threading.ThreadsManager.RunAsync(() => ChunkCreationThreadedSteps_Threaded(localChunk)); } }
private void DrawStaticEntities(DeviceContext context, VisualChunk chunk) { //For Each different entity Model foreach (var pair in chunk.AllPairs()) { // For each instance of the model - update data foreach (var staticEntity in pair.Value) { //The staticEntity.Color is affected at entity creation time in the LightingManager.PropagateLightInsideStaticEntities(...) var sunPart = (float)staticEntity.BlockLight.A / 255; var sunColor = Skydome.SunColor * sunPart; var resultColor = Color3.Max(staticEntity.BlockLight.ToColor3(), sunColor); staticEntity.VoxelEntity.ModelInstance.LightColor = resultColor; staticEntity.VoxelEntity.ModelInstance.SunLightLevel = sunPart; if (!DrawStaticInstanced) { if (IsEntityVisible(staticEntity.Entity.Position)) { var sw = Stopwatch.StartNew(); staticEntity.VisualVoxelModel.Draw(context, _voxelModelEffect, staticEntity.VoxelEntity.ModelInstance); sw.Stop(); _staticEntityDrawTime += sw.Elapsed.TotalMilliseconds; _staticEntityDrawCalls++; } } } if (DrawStaticInstanced) { if (pair.Value.Count == 0) { continue; } var entity = pair.Value.First(); var sw = Stopwatch.StartNew(); entity.VisualVoxelModel.DrawInstanced(context, _voxelModelInstancedEffect, pair.Value.Where(ve => IsEntityVisible(ve.Entity.Position)).Select(ve => ve.VoxelEntity.ModelInstance).ToList()); sw.Stop(); _staticEntityDrawTime += sw.Elapsed.TotalMilliseconds; _staticEntityDrawCalls++; } } }
//Will take the newly created chunks || the chunk that didn't had the outside light propagate (Border chunk), and propagate the light from the surroundings chunks private void PropagateOuterChunkLights() { //Process each chunk that are in InnerLightsSourcePropagated state, and not being currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => (x.State == ChunkState.InnerLightsSourcePropagated || (x.IsOutsideLightSourcePropagated == false && x.IsBorderChunk == false && x.State >= ChunkState.InnerLightsSourcePropagated)) && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle)) { VisualChunk localChunk = chunk; //all the surrounding chunks must have had their LightSources Processed at minimum. if (localChunk.IsBorderChunk == true || localChunk.SurroundingChunksMinimumState(ChunkState.InnerLightsSourcePropagated)) { //Check if the surrounding chunk from this chunk are in the correct state = ChunkState.InnerLightsSourcePropagated localChunk.ThreadStatus = ThreadsManager.ThreadStatus.Locked; //Lock the thread before entering async process. #if DEBUG localChunk.ThreadLockedBy = "PropagateOuterChunkLights"; #endif S33M3DXEngine.Threading.ThreadsManager.RunAsync(() => ChunkOuterLightPropagation_Threaded(localChunk)); } } }
private void CreateChunkMeshes(int maximumUpdateOrderPossible) { //Process each chunk that are in IsOutsideLightSourcePropagated state, and not currently processed foreach (VisualChunk chunk in SortedChunks.Where(x => x.State == ChunkState.OuterLightSourcesProcessed && x.ThreadStatus == ThreadsManager.ThreadStatus.Idle)) { VisualChunk localChunk = chunk; if (maximumUpdateOrderPossible > 0 && localChunk.UpdateOrder == 0) { continue; } //all the surrounding chunks must have had their LightSources Processed at minimum. if (localChunk.SurroundingChunksMinimumState(ChunkState.OuterLightSourcesProcessed)) { localChunk.ThreadStatus = ThreadsManager.ThreadStatus.Locked; #if DEBUG localChunk.ThreadLockedBy = "CreateChunkMeshes"; #endif S33M3DXEngine.Threading.ThreadsManager.RunAsync(() => CreateChunkMeshes_Threaded(localChunk), localChunk.UpdateOrder > 0 ? ThreadsManager.ThreadTaskPriority.High : ThreadsManager.ThreadTaskPriority.Normal); } } }
//Chunk creation steps //The process done isnight this step is impacting only the chunk that need to be creation private void ChunkCreationThreadedSteps_Threaded(VisualChunk chunk) { #if PERFTEST Utopia.Worlds.Chunks.WorldChunks.perf.AddData("ChunkCreationThreadedSteps_Threaded Started " + chunk.ChunkID); #endif //Create the landscape, by updating the "Big Array" area under the chunk if (chunk.State == ChunkState.Empty) { _landscapeManager.CreateLandScape(chunk); } //Was my landscape Creation, if not it means that the chunk has been requested to the server, waiting for server answer if (chunk.State == ChunkState.LandscapeCreated) { //Create Inner chunk Light sources _lightingManager.CreateChunkLightSources(chunk); //Propagate Inner chunk LightSources _lightingManager.PropagateInnerChunkLightSources(chunk); //The Thread status will be ChunkState.InnerLightsSourcePropagated if going out of this } chunk.ThreadStatus = ThreadsManager.ThreadStatus.Idle; }
/// <summary> /// Initiliaze the chunks array /// </summary> private void InitChunks() { //Init serverEventArea around player var areaSize = _server.GameInformations.AreaSize; var notificationAreaSize = new Vector3I(areaSize.X / AbstractChunk.ChunkSize.X, 0, areaSize.Y / AbstractChunk.ChunkSize.Z) + Vector3I.One; _eventNotificationArea = new Range3I { Position = BlockHelper.EntityToChunkPosition(PlayerManager.Player.Position) - notificationAreaSize / 2, Size = notificationAreaSize }; //Defining the World Offset, to be used to reference the 2d circular array of dim defined in chunk VisualWorldParameters.WorldRange = new Range3I() { Size = VisualWorldParameters.WorldVisibleSize, Position = VisualWorldParameters.WorldChunkStartUpPosition }; //Create the chunks that will be used as "Rendering" array Chunks = new VisualChunk[VisualWorldParameters.VisibleChunkInWorld.X * VisualWorldParameters.VisibleChunkInWorld.Y]; SortedChunks = new VisualChunk[VisualWorldParameters.VisibleChunkInWorld.X * VisualWorldParameters.VisibleChunkInWorld.Y]; Range3I cubeRange; //Used to define the blocks inside the chunks int arrayX, arrayZ; //Chunk Array indexes VisualChunk chunk; //Chunk Server request variables List <Vector3I> chunkPosition = new List <Vector3I>(); List <Md5Hash> chunkHash = new List <Md5Hash>(); Md5Hash chunkMD5; for (int chunkX = 0; chunkX < VisualWorldParameters.VisibleChunkInWorld.X; chunkX++) { for (int chunkZ = 0; chunkZ < VisualWorldParameters.VisibleChunkInWorld.Y; chunkZ++) { cubeRange = new Range3I() { Position = new Vector3I(VisualWorldParameters.WorldChunkStartUpPosition.X + (chunkX * AbstractChunk.ChunkSize.X), 0, VisualWorldParameters.WorldChunkStartUpPosition.Z + (chunkZ * AbstractChunk.ChunkSize.Z)), Size = AbstractChunk.ChunkSize //Max = new Vector3I(VisualWorldParameters.WorldChunkStartUpPosition.X + ((chunkX + 1) * AbstractChunk.ChunkSize.X), AbstractChunk.ChunkSize.Y, VisualWorldParameters.WorldChunkStartUpPosition.Y + ((chunkZ + 1) * AbstractChunk.ChunkSize.Z)) }; arrayX = MathHelper.Mod(cubeRange.Position.X, VisualWorldParameters.WorldVisibleSize.X); arrayZ = MathHelper.Mod(cubeRange.Position.Z, VisualWorldParameters.WorldVisibleSize.Z); //Create the new VisualChunk chunk = new VisualChunk(_d3dEngine, _worldFocusManager, VisualWorldParameters, ref cubeRange, _cubesHolder, _camManager, this, _voxelModelManager, _chunkEntityImpactManager); chunk.IsServerRequested = true; //Ask the chunk Data to the DB, in case my local MD5 is equal to the server one. chunk.StorageRequestTicket = _chunkstorage.RequestDataTicket_async(chunk.Position); chunk.ReadyToDraw += ChunkReadyToDraw; //Store this chunk inside the arrays. Chunks[(arrayX >> VisualWorldParameters.ChunkPOWsize) + (arrayZ >> VisualWorldParameters.ChunkPOWsize) * VisualWorldParameters.VisibleChunkInWorld.X] = chunk; SortedChunks[(arrayX >> VisualWorldParameters.ChunkPOWsize) + (arrayZ >> VisualWorldParameters.ChunkPOWsize) * VisualWorldParameters.VisibleChunkInWorld.X] = chunk; //Is this chunk inside the Client storage manager ? if (_chunkstorage.ChunkHashes.TryGetValue(chunk.Position, out chunkMD5)) { chunkPosition.Add(new Vector3I((VisualWorldParameters.WorldChunkStartUpPosition.X + (chunkX * AbstractChunk.ChunkSize.X)) / AbstractChunk.ChunkSize.X, 0, (VisualWorldParameters.WorldChunkStartUpPosition.Z + (chunkZ * AbstractChunk.ChunkSize.Z)) / AbstractChunk.ChunkSize.Z)); chunkHash.Add(chunkMD5); } } } var chunkRange = new Range3I( new Vector3I( VisualWorldParameters.WorldChunkStartUpPosition.X / AbstractChunk.ChunkSize.X, 0, VisualWorldParameters.WorldChunkStartUpPosition.Z / AbstractChunk.ChunkSize.Z ), new Vector3I( VisualWorldParameters.VisibleChunkInWorld.X, 1, VisualWorldParameters.VisibleChunkInWorld.Y ) ); #if DEBUG logger.Trace("Chunk bulk request to server (Init Phases, data in chunk unit) position : {0} ; Size : {1}", chunkRange.Position, chunkRange.Size); #endif _server.ServerConnection.Send( new GetChunksMessage() { Range = chunkRange, Md5Hashes = chunkHash.ToArray(), Positions = chunkPosition.ToArray(), HashesCount = chunkHash.Count, Flag = GetChunksMessageFlag.DontSendChunkDataIfNotModified } ); ChunkNeed2BeSorted = true; // Will force the SortedChunks array to be sorted against the "camera position" (The player). OnChunksArrayInitialized(); }
/// <summary> /// Get a world's chunk from a Cube location in world coordinate with out of array check /// </summary> /// <param name="X">Cube X coordinate in world coordinate</param> /// <param name="Z">Cube Z coordinate in world coordinate</param> /// <param name="chunk">The VisualChunk return</param> /// <returns>True if the chunk was found</returns> public bool GetSafeChunk(float X, float Z, out VisualChunk chunk) { return(GetSafeChunk((int)X, (int)Z, out chunk)); }
/// <summary> /// Get a world's chunk from a chunk location in world coordinate with array bound test /// </summary> /// <param name="X">Chunk X coordinate</param> /// <param name="Z">Chunk Z coordinate</param> /// <returns></returns> public bool GetSafeChunkFromChunkCoord(Vector3I chunkPos, out VisualChunk chunk) { return(GetSafeChunkFromChunkCoord(chunkPos.X, chunkPos.Z, out chunk)); }