Example #1
0
        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);
            }
        }
Example #2
0
        //Light Propagation =================================================================================================================
        private void PropagatesLightSources(VisualChunk chunk)
        {
            Range3I cubeRangeWithOffset = chunk.CubeRange;

            PropagateLightSources(ref cubeRangeWithOffset, false, maxHeight: chunk.BlockData.ChunkMetaData.ChunkMaxHeightBuilt);
            PropagateLightInsideStaticEntities(chunk);
        }
Example #3
0
        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);
        }
Example #4
0
        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
        }
Example #7
0
        //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);
            }
        }
Example #8
0
        //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);
            }
        }
Example #9
0
        /// <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];
        }
Example #10
0
        /// <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
            }
                );
        }
Example #11
0
        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
            });
        }
Example #12
0
        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;
            }
        }
Example #13
0
        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;
        }
Example #14
0
 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];
 }
Example #15
0
 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;
 }
Example #16
0
        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());
        }
Example #17
0
        //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);
            }
        }
Example #18
0
        //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);
        }
Example #19
0
        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);
        }
Example #21
0
        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++;
                }
            }
        }
Example #22
0
        //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++;
                    }
                }
            }
        }
Example #23
0
        /// <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();
        }
Example #24
0
        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);
            }
        }
Example #27
0
        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();
        }
Example #28
0
        /// <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));
        }