private void RemoveVoxelEntity(EntityCollectionEventArgs e) { //Remove the entity from Visual Model lock (_syncRoot) { foreach (var pair in _visualVoxelEntities) { pair.Value.RemoveAll(x => x.Entity == e.Entity); } } var lightEntity = e.Entity as ILightEmitterEntity; if (e.AtChunkCreationTime == false && lightEntity != null) { //Get the Cube where is located the entity var entityWorldPosition = lightEntity.Position; var entityBlockPosition = new Vector3I(MathHelper.Floor(entityWorldPosition.X), MathHelper.Floor(entityWorldPosition.Y), MathHelper.Floor(entityWorldPosition.Z)); this.UpdateOrder = 1; //Compute the Range impacted by the cube change var cubeRange = new Range3I { Position = new Vector3I(entityBlockPosition.X, 0, entityBlockPosition.Z), Size = Vector3I.One }; _chunkEntityImpactManager.CheckImpact(this, cubeRange); } }
//Light Propagation ================================================================================================================= private void PropagatesLightSources(VisualChunk chunk) { Range3I cubeRangeWithOffset = chunk.CubeRange; PropagateLightSources(ref cubeRangeWithOffset, false, maxHeight: chunk.BlockData.ChunkMetaData.ChunkMaxHeightBuilt); PropagateLightInsideStaticEntities(chunk); }
private void PropagatesBorderLightSources(VisualChunk chunk) { //Get surrending cubes from this chunk Range3I cubeRangeWithBorder = chunk.CubeRange; cubeRangeWithBorder.Position.X--; cubeRangeWithBorder.Position.Z--; cubeRangeWithBorder.Size.X += 2; cubeRangeWithBorder.Size.Z += 2; var test = cubeRangeWithBorder.AllExclude(chunk.CubeRange); foreach (var BorderCube in cubeRangeWithBorder.AllExclude(chunk.CubeRange)) { PropagateLightSourcesForced(BorderCube, chunk); } //Propagate the light from Entities located in chunks around me, but that have a light source block inside my chunk ! foreach (var surrendingChunk in chunk.FourSurroundingChunks) { //Propagate the light from light entities linked to border ! foreach (ILightEmitterEntity LightingEntity in surrendingChunk.OutOfChunkLightSourceStaticEntities) { //Get the Cube where is located the entity Vector3I entityBlockPosition = LightingEntity.Position.ToCubePosition(); if (chunk.CubeRange.Contains(entityBlockPosition)) { PropagateLightSourcesForced(entityBlockPosition, chunk); } } } PropagateLightInsideStaticEntities(chunk); }
private GeneratedChunk[,,] Generate(Range3I range) { if (_processors.Count == 0) { throw new InvalidOperationException("Add at least one genereation process (stage) before starting"); } var chunks = new GeneratedChunk[range.Size.X, range.Size.Y, range.Size.Z]; for (int x = 0; x < range.Size.X; x++) { for (int y = 0; y < range.Size.Y; y++) { for (int z = 0; z < range.Size.Z; z++) { chunks[x, y, z] = new GeneratedChunk { Position = new Vector3I(x + range.Position.X, y + range.Position.Y, z + range.Position.Z) }; } } } foreach (var processor in _processors) { processor.Generate(range, chunks); } return(chunks); }
/// <summary> /// Starts generation process. /// </summary> public void Generate(Range3I generationRange, GeneratedChunk[,,] chunks) { _totalChunks = generationRange.Count; _chunksDone = 0; generationRange.Foreach(pos => { var chunk = chunks[pos.X - generationRange.Position.X, pos.Y - generationRange.Position.Y, pos.Z - generationRange.Position.Z]; var chunkBytes = new byte[AbstractChunk.ChunkBlocksByteLength]; for (int y = 0; y < AbstractChunk.ChunkSize.Y; y++) { for (int x = 0; x < AbstractChunk.ChunkSize.X; x++) { for (int z = 0; z < AbstractChunk.ChunkSize.Z; z++) { var index = x * AbstractChunk.ChunkSize.Y + y + z * AbstractChunk.ChunkSize.Y * AbstractChunk.ChunkSize.X; if (y >= AbstractChunk.ChunkSize.Y / 2) { chunkBytes[index] = 0; //Air } else { chunkBytes[index] = FlatProcessorParams.CubeId.Ground; //First "Custom block" } } } } chunk.BlockData.SetBlockBytes(chunkBytes); _chunksDone++; }); }
/// <summary> /// Check the impact of the block/Item replacement. /// Mostly will check wish of the surrounding visualchunks must be refresh (lighting or cube masked face reason). /// This is only for drawing purpose, not landscape modification here. /// </summary> /// <param name="cubeCoordinates">The cube where the modification has been realized</param> /// <param name="replacementCubeId">The type of the modified cube</param> public void CheckImpact(VisualChunkBase cubeChunk, Range3I cubeRange) { Vector3I mainChunkId; #if PERFTEST Utopia.Worlds.Chunks.WorldChunks.perf.AddData("CheckImpact BEGIN"); #endif //Add lighting step to the range cubeRange.Position = new Vector3I(cubeRange.Position.X - _lightManager.LightPropagateSteps, 0, cubeRange.Position.Z - _lightManager.LightPropagateSteps); cubeRange.Size = new Vector3I(cubeRange.Size.X + (2 * _lightManager.LightPropagateSteps), _worldChunks.VisualWorldParameters.WorldVisibleSize.Y, cubeRange.Size.Z + (2 * _lightManager.LightPropagateSteps)); //Get the chunk collections var minChunkPosition = BlockHelper.BlockToChunkPosition(cubeRange.Position); var maxChunkPosition = BlockHelper.BlockToChunkPosition(cubeRange.Max); maxChunkPosition.Y = 0; Range3I chunkRange = new Range3I() { Position = minChunkPosition, Size = (maxChunkPosition - minChunkPosition) + Vector3I.One }; //recompute the light sources without the range _lightManager.CreateLightSources(ref cubeRange); cubeRange.Position.X--; cubeRange.Position.Z--; cubeRange.Size.X += 2; cubeRange.Size.Z += 2; //Propagate the light, we add one cube around the previous Range !! <= !! _lightManager.PropagateLightSources(ref cubeRange, true, true); //Find the chunks that have been impacted around the 8 surrounding chunks cubeChunk.State = ChunkState.OuterLightSourcesProcessed; mainChunkId = cubeChunk.Position; //Console.WriteLine(cubeChunk.ChunkID + " => " + cubeChunk.UpdateOrder); #if PERFTEST Utopia.Worlds.Chunks.WorldChunks.perf.cubeChunkID = mainChunkId; Utopia.Worlds.Chunks.WorldChunks.perf.AddData("Modified chunk is : " + mainChunkId); #endif VisualChunk NeightBorChunk; foreach (var chunklocation in chunkRange) { NeightBorChunk = _worldChunks.GetChunkFromChunkCoord(chunklocation); if (NeightBorChunk.Position != mainChunkId && NeightBorChunk.State > ChunkState.OuterLightSourcesProcessed) { NeightBorChunk.State = ChunkState.OuterLightSourcesProcessed; NeightBorChunk.UpdateOrder = cubeChunk.UpdateOrder == 1 ? 2 : 1; } } #if PERFTEST Utopia.Worlds.Chunks.WorldChunks.perf.AddData("CheckImpact END"); #endif }
//Can only be done if surrounding chunks have their landscape initialized ! public void PropagateLightSources(ref Range3I cubeRange, bool borderAsLightSource = false, bool withRangeEntityPropagation = false, byte maxHeight = 0) { // speed optimization _worldRange = _visualWorldParameters.WorldRange.Position; _worldRangeMax = _visualWorldParameters.WorldRange.Max; int index; TerraCube cube; int maxheight = maxHeight == 0 ? cubeRange.Max.Y - 1 : maxHeight; //Foreach Blocks in the Range for (int X = cubeRange.Position.X; X < cubeRange.Max.X; X++) { for (int Z = cubeRange.Position.Z; Z < cubeRange.Max.Z; Z++) { index = _cubesHolder.Index(X, maxheight, Z); for (int Y = maxheight; Y >= cubeRange.Position.Y; Y--) { cube = _cubesHolder.Cubes[index]; if (cube.IsSunLightSource || (borderAsLightSource)) { PropagateLight(X, Y, Z, cube.EmissiveColor.A, LightComponent.SunLight, true, index); } if (cube.EmissiveColor.R > 0 || (borderAsLightSource)) { PropagateLight(X, Y, Z, cube.EmissiveColor.R, LightComponent.Red, true, index); } if (cube.EmissiveColor.G > 0 || (borderAsLightSource)) { PropagateLight(X, Y, Z, cube.EmissiveColor.G, LightComponent.Green, true, index); } if (cube.EmissiveColor.B > 0 || (borderAsLightSource)) { PropagateLight(X, Y, Z, cube.EmissiveColor.B, LightComponent.Blue, true, index); } index -= _cubesHolder.MoveY; } } } if (withRangeEntityPropagation) { PropagateLightInsideStaticEntities(ref cubeRange); } }
//Propagate the light inside the chunk entities private void PropagateLightInsideStaticEntities(ref Range3I cubeRange) { VisualChunk chunk; //Find all chunk from the Cube range ! for (int i = 0; i < WorldChunk.Chunks.Length; i++) { chunk = WorldChunk.Chunks[i]; if ((chunk.CubeRange.Max.X < cubeRange.Position.X) || (chunk.CubeRange.Position.X > cubeRange.Max.X)) { continue; } if ((chunk.CubeRange.Max.Y < cubeRange.Position.Y) || (chunk.CubeRange.Position.Y > cubeRange.Max.Y)) { continue; } PropagateLightInsideStaticEntities(chunk); } }
/// <summary> /// Specialy created to render quickly the landscape in order to be used by LandscapeItem Manager /// </summary> /// <param name="chunkBytes"></param> /// <param name="chunkPosition"></param> public void GenerateMacroLandscape(Vector3I chunkPosition, out Biome biome, out byte[] chunkBytes, out FastRandom chunkRnd, out ChunkColumnInfo[] columnsInfo) { Range3I chunkWorldRange = new Range3I() { Position = new Vector3I(chunkPosition.X * AbstractChunk.ChunkSize.X, 0, chunkPosition.Z * AbstractChunk.ChunkSize.Z), Size = AbstractChunk.ChunkSize }; chunkBytes = new byte[AbstractChunk.ChunkBlocksByteLength]; columnsInfo = new ChunkColumnInfo[AbstractChunk.ChunkSize.X * AbstractChunk.ChunkSize.Z]; chunkRnd = new FastRandom(_worldParameters.Seed + chunkPosition.GetHashCode()); double[,] biomeMap; GenerateLandscape(chunkBytes, ref chunkWorldRange, out biomeMap); TerraForming(chunkBytes, columnsInfo, ref chunkWorldRange, biomeMap, chunkRnd); var metaData = CreateChunkMetaData(columnsInfo); biome = _config.ProcessorParam.Biomes[metaData.ChunkMasterBiomeType]; }
/// <summary> /// Will start a full client chunk sync with server ! /// </summary> public void ResyncClientChunks() { List <Vector3I> chunkPosition = new List <Vector3I>(); List <Md5Hash> chunkHash = new List <Md5Hash>(); foreach (var chunk in GetChunks(GetChunksFilter.All)) { //Requesting server chunks, for validation var md5Hash = chunk.GetMd5Hash(); chunkPosition.Add(chunk.Position); chunkHash.Add(md5Hash); chunk.IsServerRequested = true; chunk.IsServerResyncMode = true; } 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 ) ); _server.ServerConnection.Send( new GetChunksMessage() { Range = chunkRange, Md5Hashes = chunkHash.ToArray(), Positions = chunkPosition.ToArray(), HashesCount = chunkHash.Count, Flag = GetChunksMessageFlag.DontSendChunkDataIfNotModified } ); }
public void Generate(Range3I generationRange, GeneratedChunk[,,] chunks) { generationRange.Foreach(pos => { //Get the chunk var chunk = chunks[pos.X - generationRange.Position.X, pos.Y - generationRange.Position.Y, pos.Z - generationRange.Position.Z]; var chunkWorldPosition = new Vector3D(chunk.Position.X * AbstractChunk.ChunkSize.X, 0.0, chunk.Position.Z * AbstractChunk.ChunkSize.Z); //Create the Rnd component to be used by the landscape creator var chunkRnd = new FastRandom(_worldParameters.Seed + chunk.Position.GetHashCode()); //If already generated, the buffer will take care of sending back directly the landscape from buffer zone, otherwhile landscape is generated. //The buffer has the advantage to be shared between client/server in "Single player" mode. //It means that a chunk, if generated by the server, won't need to be generated by the client because it will be stored into the buffer. //The buffer is heavily use for landscape entities that can span on multiple chunks like trees. LandscapeChunkBuffer landscapeBuffer = _landscapeBufferManager.Get(chunk.Position); while (landscapeBuffer.ProcessingState != LandscapeChunkBuffer.LandscapeChunkBufferState.Processed) { Thread.Sleep(100); landscapeBuffer = _landscapeBufferManager.Get(chunk.Position); } var columnsInfo = new ChunkColumnInfo[AbstractChunk.ChunkSize.X * AbstractChunk.ChunkSize.Z]; var chunkBytes = new byte[AbstractChunk.ChunkBlocksByteLength]; Array.Copy(landscapeBuffer.chunkBytesBuffer, chunkBytes, landscapeBuffer.chunkBytesBuffer.Length); Array.Copy(landscapeBuffer.ColumnsInfoBuffer, columnsInfo, columnsInfo.Length); var metaData = CreateChunkMetaData(columnsInfo); chunk.BlockData.ColumnsInfo = columnsInfo; //Save Columns info Array chunk.BlockData.ChunkMetaData = metaData; //Save the metaData Informations PopulateChunk(chunk, chunkBytes, metaData, chunkRnd, _entityFactory, landscapeBuffer.Entities); RefreshChunkMetaData(metaData, columnsInfo); chunk.BlockData.SetBlockBytes(chunkBytes); //Save block array }); }
private void PlayerDisplacementChunkEvents() { double distance = MVector3.Distance2D(_lastPlayerTriggeredPosition, PlayerManager.Player.Position); //Triggered when player has move a distance of 8 blocks (half chunk distance) if (distance > (AbstractChunk.ChunkSize.X / 2d)) { var newEventNotificationArea = new Range3I { Position = BlockHelper.EntityToChunkPosition(PlayerManager.Player.Position) - _eventNotificationArea.Size / 2, Size = _eventNotificationArea.Size }; var chunks2Syncro = newEventNotificationArea.AllExclude(_eventNotificationArea); if (chunks2Syncro != null) { bool synchroFullyRequested = true; //Get all new chunk in the area that are in a state ready to be requested ! //Check that the concerned chunks are in a correct state to be requested. foreach (var chunkPosition in chunks2Syncro) { if (ResyncChunk(chunkPosition, false) == false) { synchroFullyRequested = false; break; } } if (synchroFullyRequested) { _eventNotificationArea = newEventNotificationArea; } } _lastPlayerTriggeredPosition = PlayerManager.Player.Position; ChunkNeed2BeSorted = true; } }
public VisualChunkBase( D3DEngine d3DEngine, WorldFocusManager worldFocusManager, VisualWorldParameters visualWorldParameter, Range3I cubeRange, CameraManager <ICameraFocused> cameraManager, WorldChunks worldChunkManager, VoxelModelManager voxelModelManager, IChunkEntityImpactManager chunkEntityImpactManager, ChunkDataProvider provider = null) : base(provider) { _cachedTrees = new Dictionary <TreeBpSeed, VisualVoxelModel>(); Graphics = new ChunkGraphics(this, d3DEngine); _d3DEngine = d3DEngine; _worldFocusManager = worldFocusManager; _worldChunkManager = worldChunkManager; _chunkEntityImpactManager = chunkEntityImpactManager; #if DEBUG _blockpickedUPEffect = new HLSLVertexPositionColor(_d3DEngine.Device); #endif _visualWorldParameters = visualWorldParameter; _cameraManager = cameraManager; _voxelModelManager = voxelModelManager; _visualVoxelEntities = new Dictionary <string, List <VisualVoxelEntity> >(); EmitterStaticEntities = new List <EntityMetaData>(); OutOfChunkLightSourceStaticEntities = new List <ILightEmitterEntity>(); SoundStaticEntities = new List <IItem>(); CubeRange = cubeRange; State = ChunkState.Empty; Entities.EntityAdded += EntitiesEntityAdded; Entities.EntityRemoved += EntitiesEntityRemoved; Entities.CollectionCleared += EntitiesCollectionCleared; }
public VisualChunk3D( D3DEngine d3DEngine, WorldFocusManager worldFocusManager, VisualWorldParameters visualWorldParameter, Range3I cubeRange, CameraManager <ICameraFocused> cameraManager, WorldChunks worldChunkManager, VoxelModelManager voxelModelManager, IChunkEntityImpactManager chunkEntityImpactManager, ChunkDataProvider provider = null) : base( d3DEngine, worldFocusManager, visualWorldParameter, cubeRange, cameraManager, worldChunkManager, voxelModelManager, chunkEntityImpactManager, provider) { _lights = new ByteColor[BlockData.ChunkSize.Volume]; }
public VisualChunk(D3DEngine d3DEngine, WorldFocusManager worldFocusManager, VisualWorldParameters visualWorldParameter, ref Range3I cubeRange, SingleArrayChunkContainer singleArrayContainer, CameraManager <ICameraFocused> cameraManager, WorldChunks worldChunkManager, VoxelModelManager voxelModelManager, IChunkEntityImpactManager chunkEntityImpactManager, ChunkDataProvider provider = null) : base(d3DEngine, worldFocusManager, visualWorldParameter, cubeRange, cameraManager, worldChunkManager, voxelModelManager, chunkEntityImpactManager, new SingleArrayDataProvider(singleArrayContainer)) { ((SingleArrayDataProvider)base.BlockData).DataProviderUser = this; //Didn't find a way to pass it inside the constructor _singleArrayContainer = singleArrayContainer; }
private ToolImpact Selection(IDynamicEntity owner, GodEntity godEntity, GodHandToolState godHandToolState) { if (!godEntity.EntityState.MouseUp) { if (owner.EntityState.IsBlockPicked) { _selectionStart = owner.EntityState.PickedBlockPosition; } return(new ToolImpact()); } if (godEntity.EntityState.IsBlockPicked) { Faction faction = EntityFactory.GlobalStateManager.GlobalState.Factions[godEntity.FactionId]; var select = !faction.Designations.OfType <DigDesignation>().Any(d => d.BlockPosition == godEntity.EntityState.PickedBlockPosition); if (godHandToolState != null && _selectionStart.Y == godHandToolState.SliceValue - 1) { _selectionStart.y--; } var range = Range3I.FromTwoVectors(_selectionStart, godEntity.EntityState.PickedBlockPosition); var cursor = EntityFactory.LandscapeManager.GetCursor(range.Position); foreach (var vector in range) { cursor.GlobalPosition = vector; if (cursor.Read() == WorldConfiguration.CubeId.Air) { continue; } if (select) { if (!faction.Designations.OfType <DigDesignation>().Any(d => d.BlockPosition == vector)) { faction.Designations.Add(new DigDesignation { BlockPosition = vector }); } } else { if (faction.Designations.OfType <DigDesignation>().Any(d => d.BlockPosition == vector)) { faction.Designations.RemoveAll(d => d is DigDesignation && ((DigDesignation)d).BlockPosition == vector); } } } } if (godEntity.EntityState.IsEntityPicked) { godEntity.SelectedEntities.Clear(); godEntity.SelectedEntities.Add(godEntity.EntityState.PickedEntityLink); logger.Warn("Selected entity " + godEntity.EntityState.PickedEntityLink); } return(new ToolImpact()); }
//Create light source on a specific Cube Range (not specific to a single chunk) public void CreateLightSources(ref Range3I cubeRange, byte maxHeight = 0) { int index; bool blockLight = false; int SunLight; BlockProfile blockProfile; int maxheight = maxHeight == 0 ? cubeRange.Max.Y - 1 : maxHeight; for (int X = cubeRange.Position.X; X < cubeRange.Max.X; X++) { for (int Z = cubeRange.Position.Z; Z < cubeRange.Max.Z; Z++) { blockLight = false; SunLight = 255; index = _cubesHolder.Index(X, maxheight, Z); for (int Y = maxheight; Y >= cubeRange.Position.Y; Y--) { //Create SunLight LightSources from AIR blocs blockProfile = _visualWorldParameters.WorldParameters.Configuration.BlockProfiles[_cubesHolder.Cubes[index].Id]; if ((!blockLight && blockProfile.IsBlockingLight)) { blockLight = true; //If my block is blocking light, stop sunlight propagation ! } if (!blockLight) { SunLight -= blockProfile.LightAbsorbed; if (SunLight < 0) { SunLight = 0; _cubesHolder.Cubes[index].IsSunLightSource = true; } else { _cubesHolder.Cubes[index].IsSunLightSource = true; } _cubesHolder.Cubes[index].EmissiveColor.A = (byte)SunLight; } else { _cubesHolder.Cubes[index].EmissiveColor.A = 0; _cubesHolder.Cubes[index].IsSunLightSource = false; } if (blockProfile.IsEmissiveColorLightSource) { _cubesHolder.Cubes[index].EmissiveColor.R = _visualWorldParameters.WorldParameters.Configuration.BlockProfiles[_cubesHolder.Cubes[index].Id].EmissiveColor.R; _cubesHolder.Cubes[index].EmissiveColor.G = _visualWorldParameters.WorldParameters.Configuration.BlockProfiles[_cubesHolder.Cubes[index].Id].EmissiveColor.G; _cubesHolder.Cubes[index].EmissiveColor.B = _visualWorldParameters.WorldParameters.Configuration.BlockProfiles[_cubesHolder.Cubes[index].Id].EmissiveColor.B; } else { _cubesHolder.Cubes[index].EmissiveColor.R = 0; _cubesHolder.Cubes[index].EmissiveColor.G = 0; _cubesHolder.Cubes[index].EmissiveColor.B = 0; } index -= _cubesHolder.MoveY; } } } //Find all chunk from the Cube range ! foreach (VisualChunk chunk in WorldChunk.Chunks) { if ((chunk.CubeRange.Max.X < cubeRange.Position.X) || (chunk.CubeRange.Position.X > cubeRange.Max.X)) { continue; } if ((chunk.CubeRange.Max.Y < cubeRange.Position.Y) || (chunk.CubeRange.Position.Y > cubeRange.Max.Y)) { continue; } CreateEntityLightSources(chunk); } }
//Light Source Creation ============================================================================================================ //Create the landscape for the chunk private void CreateLightSources(VisualChunk chunk) { Range3I cubeRange = chunk.CubeRange; CreateLightSources(ref cubeRange, chunk.BlockData.ChunkMetaData.ChunkMaxHeightBuilt); }
private void AddVoxelEntity(EntityCollectionEventArgs e) { var voxelEntity = e.Entity as IVoxelEntity; if (voxelEntity == null) { return; //My static entity is not a Voxel Entity => Not possible to render it so !!! } //Create the Voxel Model Instance for the Item VisualVoxelModel model = null; if (!string.IsNullOrEmpty(voxelEntity.ModelName)) { model = _voxelModelManager.GetModel(voxelEntity.ModelName, false); } if (model != null && voxelEntity.ModelInstance == null) //The model blueprint is existing, and I need to create an instance of it ! { var treeGrowing = e.Entity as TreeGrowingEntity; if (treeGrowing != null) { if (treeGrowing.Scale > 0) { // we need to use generated voxel model TreeBpSeed key; key.TreeTypeId = treeGrowing.TreeTypeId; key.TreeSeed = treeGrowing.TreeRndSeed; VisualVoxelModel treeModel; if (_cachedTrees.TryGetValue(key, out treeModel)) { model = treeModel; } else { var voxelModel = VoxelModel.GenerateTreeModel(treeGrowing.TreeRndSeed, _visualWorldParameters.WorldParameters.Configuration.TreeBluePrintsDico[ treeGrowing.TreeTypeId]); model = new VisualVoxelModel(voxelModel, _voxelModelManager.VoxelMeshFactory); model.BuildMesh(); _cachedTrees.Add(key, model); } } } var treeSoul = e.Entity as TreeSoul; if (treeSoul != null) { TreeBpSeed key; key.TreeTypeId = treeSoul.TreeTypeId; key.TreeSeed = treeSoul.TreeRndSeed; _cachedTrees.Remove(key); } voxelEntity.ModelInstance = new VoxelModelInstance(model.VoxelModel); //Assign state in case of growing entity ! var growingEntity = e.Entity as PlantGrowingEntity; if (growingEntity != null) { voxelEntity.ModelInstance.SetState(growingEntity.GrowLevels[growingEntity.CurrentGrowLevelIndex].ModelState); } var visualVoxelEntity = new VisualVoxelEntity(voxelEntity, _voxelModelManager); //Get default world translation Matrix instanceTranslation = Matrix.Translation(voxelEntity.Position.AsVector3()); //Apply special rotation to the creation instance Quaternion instanceRotation = Quaternion.Identity; if (voxelEntity is IRndYRotation && ((IRndYRotation)voxelEntity).RndRotationAroundY) { instanceRotation = Quaternion.RotationAxis(Vector3.UnitY, (float)(_rnd.NextDouble() * MathHelper.TwoPi)); } else if (voxelEntity is IItem) { var item = voxelEntity as IItem; instanceRotation = item.Rotation; } //Apply special scaling to created entity (By default all blue print are 16 times too big. Matrix instanceScaling = Matrix.Scaling(1.0f / 16.0f); if (treeGrowing != null && treeGrowing.Scale > 0) { instanceScaling = Matrix.Scaling(treeGrowing.Scale); } //Create the World transformation matrix for the instance. //We take the Model instance world matrix where we add a Rotation and scaling proper to the instance visualVoxelEntity.VoxelEntity.ModelInstance.World = instanceScaling * instanceTranslation; visualVoxelEntity.VoxelEntity.ModelInstance.Rotation = instanceRotation; var result = GetCube(visualVoxelEntity.VoxelEntity.Position.ToCubePosition()); if (result.IsValid) { visualVoxelEntity.BlockLight = result.Cube.EmissiveColor; } else { visualVoxelEntity.BlockLight = new ByteColor(255, 255, 255, 255); } if (visualVoxelEntity.VisualVoxelModel.Initialized == false) { visualVoxelEntity.VisualVoxelModel.BuildMesh(); } if (voxelEntity.ModelInstance.CanPlay("Idle")) { voxelEntity.ModelInstance.Play("Idle", true); } lock (_syncRoot) { List <VisualVoxelEntity> list; if (_visualVoxelEntities.TryGetValue(voxelEntity.ModelName, out list)) { list.Add(visualVoxelEntity); } else { _visualVoxelEntities.Add(voxelEntity.ModelName, new List <VisualVoxelEntity> { visualVoxelEntity }); } } var lightEntity = e.Entity as ILightEmitterEntity; if (e.AtChunkCreationTime == false && lightEntity != null) { //Get the Cube where is located the entity var entityWorldPosition = lightEntity.Position; var entityBlockPosition = new Vector3I(MathHelper.Floor(entityWorldPosition.X), MathHelper.Floor(entityWorldPosition.Y), MathHelper.Floor(entityWorldPosition.Z)); //new TerraCubeWithPosition(entityBlockPosition, WorldConfiguration.CubeId.Air, _visualWorldParameters.WorldParameters.Configuration), this.UpdateOrder = 1; var cubeRange = new Range3I { Position = new Vector3I(entityBlockPosition.X, 0, entityBlockPosition.Z), Size = Vector3I.One }; _chunkEntityImpactManager.CheckImpact(this, cubeRange); } } }
//Multiple blocks replace logic public bool ReplaceChunkBlocks(VisualChunk impactedChunk, List <TerraCubePositionTag> blocks, bool isNetworkChanged) { if (impactedChunk.State != ChunkState.DisplayInSyncWithMeshes && isNetworkChanged) { return(false); } Vector2I Min = new Vector2I(int.MaxValue, int.MaxValue); Vector2I Max = new Vector2I(int.MinValue, int.MinValue); foreach (var block in blocks) { var existingCube = _cubesHolder.Cubes[_cubesHolder.Index(ref block.Position)]; var inChunkPos = BlockHelper.GlobalToInternalChunkPosition(block.Position); //Cube not changed - Check Tags if (existingCube.Id == block.Cube.Id) { var needChunkMeshUpdate = false; var oldTag = impactedChunk.BlockData.GetTag(inChunkPos); if (oldTag != null && oldTag.RequireChunkMeshUpdate) { needChunkMeshUpdate = true; } if (block.Tag != null && block.Tag.RequireChunkMeshUpdate) { needChunkMeshUpdate = true; } if (!needChunkMeshUpdate) { impactedChunk.BlockData.SetTag(block.Tag, inChunkPos); continue; } } if (Min.X > block.Position.X) { Min.X = block.Position.X; } if (Min.Y > block.Position.Z) { Min.Y = block.Position.Z; } if (Max.X < block.Position.X) { Max.X = block.Position.X; } if (Max.Y < block.Position.Z) { Max.Y = block.Position.Z; } // Change the cube in the big array impactedChunk.BlockData.SetBlock(inChunkPos, block.Cube.Id, block.Tag); } //Compute the Range impacted by the cube change var cubeRange = new Range3I { Position = new Vector3I(Min.X, 0, Min.Y), Size = new Vector3I((Max.X - Min.X) + 1, 0, (Max.Y - Min.Y) + 1) }; impactedChunk.UpdateOrder = 1; ThreadsManager.RunAsync(() => CheckImpact(impactedChunk, cubeRange), ThreadsManager.ThreadTaskPriority.High); // Save the modified Chunk in local buffer DB SendChunkForBuffering(impactedChunk); return(true); }
private void TerraForming(byte[] ChunkCubes, ChunkColumnInfo[] columnsInfo, ref Range3I chunkWorldRange, double[,] biomeMap, FastRandom chunkRnd) { int surface, surfaceLayer; int inWaterMaxLevel = 0; Biome currentBiome; ChunkColumnInfo columnInfo; int index = 0; int noise2DIndex = 0; for (int X = 0; X < AbstractChunk.ChunkSize.X; X++) { for (int Z = 0; Z < AbstractChunk.ChunkSize.Z; Z++) { //Get Biomes informations for this Column============================================ bool mustPlacedSnow; double temperature = biomeMap[noise2DIndex, 1]; double moisture = biomeMap[noise2DIndex, 2]; double zoneValue = biomeMap[noise2DIndex, 3]; byte biomeId = _biomeHelper.GetBiome(biomeMap[noise2DIndex, 0], temperature, moisture, zoneValue); //Get this landscape Column Biome value currentBiome = _config.ProcessorParam.Biomes[biomeId]; //Get Temperature and Moisture columnInfo = new ChunkColumnInfo() { Biome = biomeId, Moisture = (byte)(moisture * 255), Temperature = (byte)(temperature * 255), MaxHeight = byte.MaxValue, Zone = (byte)(zoneValue * 255), IsWild = true }; mustPlacedSnow = (temperature <0.2 && moisture> 0.5); //==================================================================================== surface = chunkRnd.Next(currentBiome.UnderSurfaceLayers.Min, currentBiome.UnderSurfaceLayers.Max + 1); inWaterMaxLevel = 0; surfaceLayer = 0; bool solidGroundHitted = false; for (int Y = _worldGeneratedHeight - 1; Y >= 0; Y--) //Y { index = ((Z * AbstractChunk.ChunkSize.X) + X) * AbstractChunk.ChunkSize.Y + Y; byte cubeId = ChunkCubes[index]; //Restart Surface layer if needed if (surfaceLayer > 0 && cubeId == UtopiaProcessorParams.CubeId.Air && Y > (_config.ProcessorParam.WaterLevel - 5)) { surfaceLayer = 1; } if (cubeId == UtopiaProcessorParams.CubeId.Stone) { if (solidGroundHitted == false) { if (columnInfo.MaxHeight < Y || inWaterMaxLevel == 0) { columnInfo.MaxHeight = (byte)Y; } columnInfo.MaxGroundHeight = (byte)Y; solidGroundHitted = true; } cubeId = currentBiome.GroundCube; //Under water soil if (Y < _config.ProcessorParam.WaterLevel && inWaterMaxLevel != 0) { if (cubeId == currentBiome.GroundCube) { ChunkCubes[index] = currentBiome.UnderSurfaceCube; } break; } inWaterMaxLevel = 0; //Surface Layer handling if (surface > surfaceLayer) { if (surfaceLayer == 0) { if (mustPlacedSnow) { //Get cube index above this one //Place a snow block on it ChunkCubes[((Z * AbstractChunk.ChunkSize.X) + X) * AbstractChunk.ChunkSize.Y + (Y + 1)] = UtopiaProcessorParams.CubeId.Snow; mustPlacedSnow = false; } ChunkCubes[index] = currentBiome.SurfaceCube; } else { ChunkCubes[index] = currentBiome.UnderSurfaceCube; } surfaceLayer++; } } else //This block is not Stone (Air, Water, or BedRock) { if (cubeId == UtopiaProcessorParams.CubeId.WaterStill) { if (mustPlacedSnow) { //Get cube index above this one //Place a snow block on it ChunkCubes[index] = UtopiaProcessorParams.CubeId.Ice; } inWaterMaxLevel = Y; columnInfo.MaxHeight = (byte)Y; } else { if (inWaterMaxLevel > 0 && cubeId == UtopiaProcessorParams.CubeId.Air) { ChunkCubes[index] = UtopiaProcessorParams.CubeId.WaterStill; } } } } columnsInfo[noise2DIndex] = columnInfo; noise2DIndex++; } } }
//public INoise FonctionTesting(Gradient ground_gradient, INoise terrainDelimiter, out INoise landScapeTypeFct) //{ // //Create various landcreation Algo. =================================================================== // //Montains forms // INoise montainFct = new Montain(_worldParameters.Seed + 28051979, ground_gradient).GetLandFormFct(); // //MidLand forms // INoise midlandFct = new Midland(_worldParameters.Seed + 08092007, ground_gradient).GetLandFormFct(); // //Plains forms // INoise hillFct = new Hill(_worldParameters.Seed + 1, ground_gradient).GetLandFormFct(); // INoise plainFct = new Plain(_worldParameters.Seed, ground_gradient).GetLandFormFct(); // INoise flatFct = new Flat(_worldParameters.Seed + 96, ground_gradient).GetLandFormFct(); // INoise plainsCtrl = new PlainCtrl(_worldParameters.Seed + 96).GetLandFormFct(); //Noise That will merge hillFct, plainFct and flatFct together // //Oceans forms // INoise oceanBaseFct = new Ocean(_worldParameters.Seed + 10051956, ground_gradient).GetLandFormFct(); // //Surface main controler // INoise surfaceCtrl = new SurfaceCtrl(_worldParameters.Seed + 123).GetLandFormFct(); // var param = _worldParameters.Configuration.UtopiaProcessorParam; // //===================================================================================================== // // TESTING PURPOSE // landScapeTypeFct = new Constant((double)enuLandFormType.Hill); // return hillFct; //} private void GenerateLandscape(byte[] ChunkCubes, ref Range3I chunkWorldRange, out double[,] biomeMap) { //Create the test Noise, A new object must be created each time INoise mainLandscape, underground, landScapeType, temperature, moisture, zones; CreateNoises(out mainLandscape, out underground, out landScapeType, out temperature, out moisture, out zones); //Create value from Noise Fct sampling //noiseLandscape[x,0] = MainLandscape //noiseLandscape[x,1] = underground mask double[,] noiseLandscape = NoiseSampler.NoiseSampling(new Vector3I(AbstractChunk.ChunkSize.X / 4, _worldGeneratedHeight / 8, AbstractChunk.ChunkSize.Z / 4), chunkWorldRange.Position.X / 320.0, (chunkWorldRange.Position.X / 320.0) + 0.05, AbstractChunk.ChunkSize.X, chunkWorldRange.Position.Y / 2560.0, (chunkWorldRange.Position.Y / 2560.0) + 0.4, _worldGeneratedHeight, chunkWorldRange.Position.Z / 320.0, (chunkWorldRange.Position.Z / 320.0) + 0.05, AbstractChunk.ChunkSize.Z, mainLandscape, underground); //biomeMap[x,0] = Biome Type //biomeMap[x,1] = temperature //biomeMap[x,2] = Moisture //biomeMap[x,3] = Zone Map biomeMap = NoiseSampler.NoiseSampling(new Vector2I(AbstractChunk.ChunkSize.X, AbstractChunk.ChunkSize.Z), chunkWorldRange.Position.X / 320.0, (chunkWorldRange.Position.X / 320.0) + 0.05, AbstractChunk.ChunkSize.X, chunkWorldRange.Position.Z / 320.0, (chunkWorldRange.Position.Z / 320.0) + 0.05, AbstractChunk.ChunkSize.Z, landScapeType, temperature, moisture, zones); //Create the chunk Block byte from noiseResult int noiseValueIndex = 0; byte cube; for (int X = 0; X < AbstractChunk.ChunkSize.X; X++) { for (int Z = 0; Z < AbstractChunk.ChunkSize.Z; Z++) { for (int Y = 0; Y < _worldGeneratedHeight; Y++) { double value = noiseLandscape[noiseValueIndex, 0]; //Get landScape value double valueUnderground = noiseLandscape[noiseValueIndex, 1]; //Get underground value //Create underground "Mask" //0 => Will create a Hole in the landscape = Create a underground cave //1 => Will leave the landscape as is. valueUnderground = valueUnderground > 0.6 ? 0.0 : 1.0; value *= valueUnderground; cube = UtopiaProcessorParams.CubeId.Air; if (value > 0.5) { cube = UtopiaProcessorParams.CubeId.Stone; } //BedRock if (Y == 0) { cube = UtopiaProcessorParams.CubeId.Rock; } //Be sure that the last landscape row is composed of air if (Y == _worldGeneratedHeight - 1) { cube = UtopiaProcessorParams.CubeId.Air; } //Create Bottom Lava lake if (Y <= 3 && cube == UtopiaProcessorParams.CubeId.Air) { cube = UtopiaProcessorParams.CubeId.LavaStill; } //Place "StillWater" block at SeaLevel if (Y == _config.ProcessorParam.WaterLevel && cube == UtopiaProcessorParams.CubeId.Air && valueUnderground == 1) { cube = UtopiaProcessorParams.CubeId.WaterStill; } //Save block if changed if (cube != UtopiaProcessorParams.CubeId.Air) { ChunkCubes[((Z * AbstractChunk.ChunkSize.X) + X) * AbstractChunk.ChunkSize.Y + Y] = cube; } noiseValueIndex++; } } } }
/// <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(); }
private void GenerateLandscapeBuffer(LandscapeChunkBuffer buffer) { //Get the minimum chunk range that need to be computed to validate current chunk landscape entities generation var chunkRange = new Range3I(buffer.ChunkLocation - _chunkRangeLookUp, new Vector3I(_chunkRangeLookUp.X * 2, 1, _chunkRangeLookUp.Z * 2)); var chunkBuffers = new List <LandscapeChunkBuffer>(chunkRange.Count); foreach (var chunkPosition in chunkRange) { //Check if all those chunks have been / have their landscape item processed (They could potentially impact this chunk). LandscapeChunkBuffer surrendingChunkBuffer; bool need2Process = false; lock (_syncLock) { if (_buffers.TryGetValue(chunkPosition, out surrendingChunkBuffer) == false) { surrendingChunkBuffer = new LandscapeChunkBuffer { ChunkLocation = chunkPosition, ProcessingState = LandscapeChunkBuffer.LandscapeChunkBufferState.NotProcessed }; _buffers.Add(chunkPosition, surrendingChunkBuffer); } if (surrendingChunkBuffer.ProcessingState == LandscapeChunkBuffer.LandscapeChunkBufferState.NotProcessed) { surrendingChunkBuffer.ProcessingState = LandscapeChunkBuffer.LandscapeChunkBufferState.Processing; need2Process = true; } } chunkBuffers.Add(surrendingChunkBuffer); if (need2Process) { //Process Landscape FastRandom chunkNewRnd; Biome chunkMasterBiome; ChunkColumnInfo[] columnsInfo; byte[] chunkBytes; Processor.GenerateMacroLandscape(surrendingChunkBuffer.ChunkLocation, out chunkMasterBiome, out chunkBytes, out chunkNewRnd, out columnsInfo); //Process chunk Entity landscape creation Processor.LandscapeEntities.GenerateChunkItems(surrendingChunkBuffer.ChunkLocation, chunkMasterBiome, chunkBytes, columnsInfo, chunkNewRnd); surrendingChunkBuffer.chunkBytesBuffer = chunkBytes; surrendingChunkBuffer.ColumnsInfoBuffer = columnsInfo; surrendingChunkBuffer.ProcessingState = LandscapeChunkBuffer.LandscapeChunkBufferState.Processed; } } //Here, all chunk have been at least processed, some could still be in Processing state, waiting for all of them to finish. while (chunkBuffers.Count(x => x.ProcessingState != LandscapeChunkBuffer.LandscapeChunkBufferState.Processed) > 0) { //Wait for all lanscape entity from our range to be processed Thread.Sleep(1); } Processor.GenerateMicroLandscape(buffer); //Sort the final landscape entity items by their chunk origine. if (buffer.Entities != null) { buffer.Entities = buffer.Entities.OrderBy(x => x.ChunkLocation.GetHashCode()).ToList(); } buffer.isReady = true; }
public void EntityGrowCheck(UtopiaTime now, GrowingEntity entity, ServerChunk chunk, Random random) { if (entity.LastGrowUpdate.IsZero) { return; } var checkTimeSpan = now - entity.LastGrowUpdate; bool updated; bool rotten; // grow time left at the current season var tillTheEndOfSeason = UtopiaTimeSpan.FromSeasons(1d - entity.LastGrowUpdate.TotalSeasons % 1d); if (checkTimeSpan <= tillTheEndOfSeason) { // small grow update updated = GrowSeasonLogic(entity, now.Season, checkTimeSpan, random, chunk, out rotten); if (rotten) { return; } } else { // grow at the end of the first season updated = GrowSeasonLogic(entity, now.Season, tillTheEndOfSeason, random, chunk, out rotten); if (rotten) { return; } // align time to the beginning of next season checkTimeSpan -= tillTheEndOfSeason; while (checkTimeSpan.TotalSeconds > 0) { var seasonCheckSpan = checkTimeSpan.TotalSeasons > 0 ? UtopiaTimeSpan.FromSeasons(1) : checkTimeSpan; updated = GrowSeasonLogic(entity, (now - checkTimeSpan).Season, seasonCheckSpan, random, chunk, out rotten) || updated; if (rotten) { return; } checkTimeSpan -= seasonCheckSpan; } } if (updated) { if (entity is PlantGrowingEntity) { if (chunk != null) { chunk.Entities.RemoveById(entity.StaticId); chunk.Entities.Add(entity); } } var tree = entity as TreeGrowingEntity; if (tree != null) { var treeBlueprint = _server.EntityFactory.Config.TreeBluePrintsDico[tree.TreeTypeId]; if (tree.CurrentGrowTime > treeBlueprint.GrowTime) { // the tree is ready var model = VoxelModel.GenerateTreeModel(tree.TreeRndSeed, treeBlueprint); // create tree blocks var rootOffset = model.States[0].PartsStates[0].Translation; var cursor = _server.LandscapeManager.GetCursor(tree.Position); var frame = model.Frames[0]; var range = new Range3I(new Vector3I(), frame.BlockData.ChunkSize); using (cursor.TransactionScope()) { foreach (var position in range) { var value = frame.BlockData.GetBlock(position); if (value == 0) { continue; } var blockType = value == 1 ? treeBlueprint.TrunkBlock : treeBlueprint.FoliageBlock; var worldPos = (Vector3I)(tree.Position + rootOffset) + position; cursor.GlobalPosition = worldPos; if (cursor.Read() == WorldConfiguration.CubeId.Air) { cursor.Write(blockType); } } } // create tree soul var soul = _server.EntityFactory.CreateEntity <TreeSoul>(); soul.Position = tree.Position; soul.TreeRndSeed = tree.TreeRndSeed; soul.TreeTypeId = tree.TreeTypeId; chunk.Entities.Add(soul); // remove the growing tree chunk.Entities.RemoveById(tree.StaticId); } else { // just make the model bigger tree.Scale = (float)tree.CurrentGrowTime.TotalSeconds / treeBlueprint.GrowTime.TotalSeconds; chunk.Entities.RemoveById(tree.StaticId); chunk.Entities.Add(tree); } } } }
public bool ReplaceBlock(int cubeArrayIndex, ref Vector3I cubeCoordinates, byte replacementCubeId, bool isNetworkChanged, BlockTag blockTag = null) { VisualChunk impactedChunk = _worldChunks.GetChunk(cubeCoordinates.X, cubeCoordinates.Z); if (impactedChunk.State != ChunkState.DisplayInSyncWithMeshes && isNetworkChanged) { return(false); } try { // Check if the cube is not already the same ? ! ? var existingCube = _cubesHolder.Cubes[cubeArrayIndex]; var inChunkPos = BlockHelper.GlobalToInternalChunkPosition(cubeCoordinates); if (existingCube.Id == replacementCubeId) { // tag change event // some tags changes requires chunk mesh rebuild (LiquidTag), some not (DamageTag) // we will update the mesh only if at least one tag (current or previous) requires mesh update var needChunkMeshUpdate = false; var oldTag = impactedChunk.BlockData.GetTag(inChunkPos); if (oldTag != null && oldTag.RequireChunkMeshUpdate) { needChunkMeshUpdate = true; } if (blockTag != null && blockTag.RequireChunkMeshUpdate) { needChunkMeshUpdate = true; } if (!needChunkMeshUpdate) { impactedChunk.BlockData.SetTag(blockTag, inChunkPos); return(true); } } // Change the cube in the big array impactedChunk.BlockData.SetBlock(inChunkPos, replacementCubeId, blockTag); // Start Chunk Visual Impact to decide what needs to be redraw, will be done in async mode, // quite heavy, will also restart light computations for the impacted chunk range. var cube = new TerraCubeWithPosition(cubeCoordinates, replacementCubeId, _visualWorldParameters.WorldParameters.Configuration.BlockProfiles[replacementCubeId]); #if PERFTEST if (Utopia.Worlds.Chunks.WorldChunks.perf.Actif == false) { Utopia.Worlds.Chunks.WorldChunks.perf.Actif = true; Utopia.Worlds.Chunks.WorldChunks.perf.CollectedData = new List <string>(); Utopia.Worlds.Chunks.WorldChunks.perf.AddData("Started New User Action"); Utopia.Worlds.Chunks.WorldChunks.perf.sw.Restart(); } #endif impactedChunk.UpdateOrder = !cube.BlockProfile.IsBlockingLight ? 1 : 2; //Compute the Range impacted by the cube change var cubeRange = new Range3I { Position = new Vector3I(cube.Position.X, 0, cube.Position.Z), Size = Vector3I.One }; ThreadsManager.RunAsync(() => CheckImpact(impactedChunk, cubeRange), ThreadsManager.ThreadTaskPriority.High); // Raise event for sound OnBlockReplaced(new LandscapeBlockReplacedEventArgs { IsLocalPLayerAction = !isNetworkChanged, Position = cubeCoordinates, NewBlockType = replacementCubeId, PreviousBlock = existingCube }); return(true); } finally { // Save the modified Chunk in local buffer DB SendChunkForBuffering(impactedChunk); } }
private void Wrap(ChunkWrapType operationType) { _processingType = operationType; Range3I NewCubeRange, ActualCubeRange, NewWorldRange; Vector2I NewWrapEnd; int NewMinWorldValue; NewWorldRange = WorldChunks.VisualWorldParameters.WorldRange; NewWrapEnd = WorldChunks.VisualWorldParameters.WrapEnd; switch (operationType) { case ChunkWrapType.X_Plus1: //GameConsole.Write("Row of chunks generated : Xmax"); //Find the Xmin chunks ! (They will be recycled with newwww cube Range) foreach (VisualChunk chunk in WorldChunks.GetChunksWithFixedX(WorldChunks.VisualWorldParameters.WorldRange.Position.X, WorldChunks.VisualWorldParameters.WorldRange.Position.Z)) { chunk.State = ChunkState.Empty; chunk.Graphics.IsExistingMesh4Drawing = false; NewMinWorldValue = WorldChunks.VisualWorldParameters.WorldRange.Max.X; ActualCubeRange = chunk.CubeRange; NewCubeRange = new Range3I() { Position = new Vector3I(NewMinWorldValue, ActualCubeRange.Position.Y, ActualCubeRange.Position.Z), Size = AbstractChunk.ChunkSize }; chunk.CubeRange = NewCubeRange; } //Update World Range NewWorldRange.Position.X += AbstractChunk.ChunkSize.X; if (NewWorldRange.Position.X > NewWrapEnd.X) { NewWrapEnd.X += WorldChunks.VisualWorldParameters.WorldVisibleSize.X; } break; case ChunkWrapType.X_Minus1: //GameConsole.Write("Row of chunks generated : Xmin"); //Find the Xmin chunks ! (They will be recycled with newwww cube Range) foreach (VisualChunk chunk in WorldChunks.GetChunksWithFixedX(WorldChunks.VisualWorldParameters.WorldRange.Max.X - AbstractChunk.ChunkSize.X, WorldChunks.VisualWorldParameters.WorldRange.Position.Z)) { chunk.State = ChunkState.Empty; chunk.Graphics.IsExistingMesh4Drawing = false; NewMinWorldValue = WorldChunks.VisualWorldParameters.WorldRange.Position.X; ActualCubeRange = chunk.CubeRange; NewCubeRange = new Range3I() { Position = new Vector3I(NewMinWorldValue - AbstractChunk.ChunkSize.X, ActualCubeRange.Position.Y, ActualCubeRange.Position.Z), Size = AbstractChunk.ChunkSize }; chunk.CubeRange = NewCubeRange; } //Update World Range NewWorldRange.Position.X -= AbstractChunk.ChunkSize.X; if (NewWorldRange.Position.X <= NewWrapEnd.X - (WorldChunks.VisualWorldParameters.WorldVisibleSize.X)) { NewWrapEnd.X -= WorldChunks.VisualWorldParameters.WorldVisibleSize.X; } break; case ChunkWrapType.Z_Plus1: //GameConsole.Write("Row of chunks generated : ZMax"); //Find the Xmin chunks ! (They will be recycled with new cube Range) foreach (VisualChunk chunk in WorldChunks.GetChunksWithFixedZ(WorldChunks.VisualWorldParameters.WorldRange.Position.Z, WorldChunks.VisualWorldParameters.WorldRange.Position.X)) { chunk.State = ChunkState.Empty; chunk.Graphics.IsExistingMesh4Drawing = false; NewMinWorldValue = WorldChunks.VisualWorldParameters.WorldRange.Max.Z; ActualCubeRange = chunk.CubeRange; NewCubeRange = new Range3I() { Position = new Vector3I(ActualCubeRange.Position.X, ActualCubeRange.Position.Y, NewMinWorldValue), Size = AbstractChunk.ChunkSize }; chunk.CubeRange = NewCubeRange; } //Update World Range NewWorldRange.Position.Z += AbstractChunk.ChunkSize.Z; if (NewWorldRange.Position.Z > NewWrapEnd.Y) { NewWrapEnd.Y += WorldChunks.VisualWorldParameters.WorldVisibleSize.Z; } break; case ChunkWrapType.Z_Minus1: //GameConsole.Write("Row of chunks generated : Zmin"); foreach (VisualChunk chunk in WorldChunks.GetChunksWithFixedZ(WorldChunks.VisualWorldParameters.WorldRange.Max.Z - AbstractChunk.ChunkSize.Z, WorldChunks.VisualWorldParameters.WorldRange.Position.X)) { chunk.State = ChunkState.Empty; chunk.Graphics.IsExistingMesh4Drawing = false; NewMinWorldValue = WorldChunks.VisualWorldParameters.WorldRange.Position.Z; ActualCubeRange = chunk.CubeRange; NewCubeRange = new Range3I() { Position = new Vector3I(ActualCubeRange.Position.X, ActualCubeRange.Position.Y, NewMinWorldValue - AbstractChunk.ChunkSize.Z), Size = AbstractChunk.ChunkSize }; chunk.CubeRange = NewCubeRange; } //Update World Range NewWorldRange.Position.Z -= AbstractChunk.ChunkSize.Z; if (NewWorldRange.Position.Z <= NewWrapEnd.Y - (WorldChunks.VisualWorldParameters.WorldVisibleSize.Z)) { NewWrapEnd.Y -= WorldChunks.VisualWorldParameters.WorldVisibleSize.Z; } break; default: break; } //Save the new World Range after Wrapping WorldChunks.VisualWorldParameters.WorldRange = NewWorldRange; WorldChunks.VisualWorldParameters.WrapEnd = NewWrapEnd; PostWrappingStep(); }
/// <summary> /// Performs world generation asynchronously /// </summary> /// <param name="range">chunks to generate</param> /// <param name="callback">this callback will be called when world will be generated</param> /// <param name="state"></param> public IAsyncResult GenerateAsync(Range3I range, AsyncCallback callback, object state) { var del = new GenerateDelegate(Generate); return(del.BeginInvoke(range, callback, state)); }