예제 #1
0
        public void GetNextSolidBlockToPlayer(ref Vector3 FromPosition, ref Vector3I Direction, out TerraCubeWithPosition cubeWithPosition)
        {
            int index = 0;

            cubeWithPosition      = new TerraCubeWithPosition();
            cubeWithPosition.Cube = new TerraCube(WorldConfiguration.CubeId.Air);

            int X = MathHelper.Floor(FromPosition.X);
            int Z = MathHelper.Floor(FromPosition.Z);
            int Y = MathHelper.Floor(FromPosition.Y);

            if (Y >= _visualWorldParam.WorldVisibleSize.Y)
            {
                Y = _visualWorldParam.WorldVisibleSize.Y - 1;
            }

            while (!_config.BlockProfiles[cubeWithPosition.Cube.Id].IsSolidToEntity && !isIndexInError(index))
            {
                if (IndexYSafe(X, Y, Z, out index))
                {
                    if (_config.BlockProfiles[Cubes[index].Id].IsSolidToEntity)
                    {
                        cubeWithPosition.Cube = Cubes[index];
                        break;
                    }
                    X += Direction.X;
                    Y += Direction.Y;
                    Z += Direction.Z;
                }
            }

            cubeWithPosition.Position = new Vector3I(X, Y, Z);
        }
        private void PlayerEntityManager_OnLanding(double fallHeight, TerraCubeWithPosition landedCube)
        {
            //The first 5 meter are "free", no damage computed
            if (fallHeight <= 5.0)
            {
                return;
            }
            var damageComputed = (fallHeight - 5) * _healthDamagePerFallMeter;

            _playerCharacter.HealthImpact(-(float)damageComputed);
        }
예제 #3
0
        public bool isPickable(ref Vector3D position, out TerraCubeWithPosition cubewithPosition)
        {
            int cubeIndex;

            var cubePosition = new Vector3I(MathHelper.Floor(position.X), MathHelper.Floor(position.Y), MathHelper.Floor(position.Z));

            if (cubePosition.Y < _visualWorldParam.WorldRange.Max.Y - 1 && Index(ref cubePosition, true, out cubeIndex))
            {
                cubewithPosition = new TerraCubeWithPosition(cubePosition, Cubes[cubeIndex], _config.BlockProfiles[Cubes[cubeIndex].Id]);
                return(_config.BlockProfiles[cubewithPosition.Cube.Id].IsPickable);
            }

            cubewithPosition = new TerraCubeWithPosition();
            return(false);
        }
        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);
            }
        }
예제 #5
0
        public void GetNextSolidBlockToPlayer(ref BoundingBox FromBBPosition, ref Vector3I Direction, out TerraCubeWithPosition cubeWithPosition)
        {
            TerraCubeWithPosition testCube;
            Vector3 testPoint;

            testPoint = new Vector3(FromBBPosition.Minimum.X, FromBBPosition.Minimum.Y, FromBBPosition.Minimum.Z);
            GetNextSolidBlockToPlayer(ref testPoint, ref Direction, out testCube);
            cubeWithPosition = testCube;

            testPoint = new Vector3(FromBBPosition.Maximum.X, FromBBPosition.Minimum.Y, FromBBPosition.Minimum.Z);
            GetNextSolidBlockToPlayer(ref testPoint, ref Direction, out testCube);
            if (testCube.Position.Y > cubeWithPosition.Position.Y)
            {
                cubeWithPosition = testCube;
            }

            testPoint = new Vector3(FromBBPosition.Minimum.X, FromBBPosition.Minimum.Y, FromBBPosition.Maximum.Z);
            GetNextSolidBlockToPlayer(ref testPoint, ref Direction, out testCube);
            if (testCube.Position.Y > cubeWithPosition.Position.Y)
            {
                cubeWithPosition = testCube;
            }

            testPoint = new Vector3(FromBBPosition.Maximum.X, FromBBPosition.Minimum.Y, FromBBPosition.Maximum.Z);
            GetNextSolidBlockToPlayer(ref testPoint, ref Direction, out testCube);
            if (testCube.Position.Y > cubeWithPosition.Position.Y)
            {
                cubeWithPosition = testCube;
            }
        }
예제 #6
0
        public bool IsSolidToPlayer(ref BoundingBox bb, bool withCubeOffSetAccount, out TerraCubeWithPosition collidingcube)
        {
            //Get ground surface 4 blocks below the Bounding box
            int Xmin = MathHelper.Floor(bb.Minimum.X);
            int Zmin = MathHelper.Floor(bb.Minimum.Z);
            int Ymin = MathHelper.Floor(bb.Minimum.Y);
            int Xmax = MathHelper.Floor(bb.Maximum.X);
            int Zmax = MathHelper.Floor(bb.Maximum.Z);
            int Ymax = MathHelper.Floor(bb.Maximum.Y);

            for (var x = Xmin; x <= Xmax; x++)
            {
                for (var z = Zmin; z <= Zmax; z++)
                {
                    for (var y = Ymin; y <= Ymax; y++)
                    {
                        var cube    = GetCubeAt(new Vector3I(x, y, z));
                        var profile = _wp.Configuration.BlockProfiles[cube.Id];

                        if (!profile.IsSolidToEntity)
                        {
                            continue;
                        }

                        collidingcube.Cube         = cube;
                        collidingcube.Position     = new Vector3I(x, y, z);
                        collidingcube.BlockProfile = profile;

                        //Block with Offset case
                        if (withCubeOffSetAccount && profile.YBlockOffset > 0.0f)
                        {
                            //If my "Feet" are below the height of the offseted cube, then colliding true
                            FloatAsInt FeetLevel         = bb.Minimum.Y;
                            FloatAsInt OffsetedCubeLevel = 1;// profile.YBlockOffset;
                            OffsetedCubeLevel -= profile.YBlockOffset;

                            //if (bb.Minimum.Y < (y + (1-profile.YBlockOffset)))
                            if (FeetLevel < (y + OffsetedCubeLevel))
                            {
                                return(true);
                            }

                            //check the head when On a Offseted Block
                            cube    = GetCubeAt(new Vector3I(x, MathHelper.Floor(bb.Maximum.Y + profile.YBlockOffset), z));
                            profile = _wp.Configuration.BlockProfiles[cube.Id];
                            if (profile.IsSolidToEntity)
                            {
                                return(true);
                            }
                        }
                        else
                        {
                            return(true);
                        }
                    }
                }
            }

            collidingcube = new TerraCubeWithPosition();
            return(false);
        }
예제 #7
0
        /// <summary>
        /// Update player picking
        /// </summary>
        /// <param name="pickingWorldPosition"></param>
        /// <param name="pickingLookAt"></param>
        /// <param name="blockPickingDistance"></param>
        /// <returns>return true if a new Item has been picked up !</returns>
        private bool RefreshPicking(ref Vector3D pickingWorldPosition, Vector3 pickingLookAt, float blockPickingDistance)
        {
            // first we will check entities
            // after that we will check blocks because they can be closer than the entity

            PlayerManager.Player.EntityState.IsEntityPicked = false;
            PlayerManager.Player.EntityState.IsBlockPicked  = false;

            //Check the Ray against all entity first
            var pickingRay = new Ray(pickingWorldPosition.AsVector3(), pickingLookAt);

            var epr = CheckEntityPicking(pickingRay);

            if (epr.Found && epr.Distance > blockPickingDistance)
            {
                epr.Found = false;
            }

            var tool = PlayerManager.ActiveTool;

            if (tool.PickRange != 0f)
            {
                blockPickingDistance = Math.Min(tool.PickRange, blockPickingDistance);
            }

            var nbrPointToSample = (int)(Math.Min(blockPickingDistance, epr.Distance) / 0.02);

            float sliceLimitSquared = float.PositiveInfinity;

            if (_worldChunks.SliceValue != -1)
            {
                var topPlane    = new Plane(new Vector3(0, _worldChunks.SliceValue, 0), Vector3.UnitY);
                var bottomPlane = new Plane(new Vector3(0, _worldChunks.SliceValue - 5, 0), Vector3.UnitY);

                Vector3 topIntersectionPoint;
                Vector3 bottomIntersectionPoint;

                var topIntersection    = pickingRay.Intersects(ref topPlane, out topIntersectionPoint);
                var bottomIntersection = pickingRay.Intersects(ref bottomPlane, out bottomIntersectionPoint);

                if (!topIntersection && !bottomIntersection)
                {
                    return(false);
                }

                if (topIntersection && bottomIntersection)
                {
                    // find the closest one to the camera

                    var topIsCloser = Vector3D.DistanceSquared(pickingWorldPosition, new Vector3D(topIntersectionPoint)) < Vector3D.DistanceSquared(pickingWorldPosition, new Vector3D(bottomIntersectionPoint));

                    if (topIsCloser)
                    {
                        pickingWorldPosition = new Vector3D(topIntersectionPoint);
                    }
                    else
                    {
                        pickingWorldPosition = new Vector3D(bottomIntersectionPoint);
                    }

                    sliceLimitSquared = Vector3.DistanceSquared(topIntersectionPoint, bottomIntersectionPoint);
                }
                else if (topIntersection)
                {
                    sliceLimitSquared = (float)Vector3D.DistanceSquared(pickingWorldPosition, new Vector3D(topIntersectionPoint));
                }
                else
                {
                    sliceLimitSquared = (float)Vector3D.DistanceSquared(pickingWorldPosition, new Vector3D(bottomIntersectionPoint));
                }

                if (epr.Found)
                {
                    sliceLimitSquared = (float)Vector3D.DistanceSquared(pickingWorldPosition, new Vector3D(epr.PickPoint));
                    if (epr.PickPoint.Y > topIntersectionPoint.Y)
                    {
                        nbrPointToSample = 0;
                    }
                }

                //if (Vector3D.DistanceSquared(prevPosition, prevPosition) > Vector3D.DistanceSquared(prevPosition, new Vector3D(bottomPoint)))
                //    pickingWorldPosition = new Vector3D(intersectPoint);
            }

            var startPos = pickingWorldPosition;

            //Check for Cube Picking
            //Sample points in the view direction vector
            for (var ptNbr = 0; ptNbr < nbrPointToSample; ptNbr++)
            {
                pickingWorldPosition += new Vector3D(pickingLookAt * 0.02f);

                if (Vector3D.DistanceSquared(pickingWorldPosition, startPos) >= sliceLimitSquared)
                {
                    break;
                }

                //Check if a block is picked up !
                var result = _cubesHolder.GetCube(pickingWorldPosition);
                if (!result.IsValid)
                {
                    break;
                }

                var blockProfile = _cubesHolder.Config.BlockProfiles[result.Cube.Id];
                var yOffset      = blockProfile.YBlockOffset;

                var pickType = tool.CanPickBlock(blockProfile);

                if (pickType == PickType.Stop)
                {
                    // we found a block that is closer than entity (if any)
                    // don't allow to pick the entity in this case
                    epr.Found = false;
                    break;
                }

                if (pickType == PickType.Pick)
                {
                    var blockPos = pickingWorldPosition.ToCubePosition();
                    PlayerManager.Player.EntityState.PickedBlockPosition = blockPos;

                    var     cubeBB = new BoundingBox(blockPos, blockPos + new Vector3(1, 1f - (float)yOffset, 1));
                    Vector3 faceInteresection;
                    if (cubeBB.Intersects(ref pickingRay, out faceInteresection))
                    {
                        _prevCube   = _pickedCube;
                        _pickedCube = new TerraCubeWithPosition {
                            Position = blockPos, BlockProfile = blockProfile, Cube = result.Cube
                        };

                        PlayerManager.Player.EntityState.PickedBlockFaceOffset = Vector3.One - (_pickedCube.Position - faceInteresection);
                        PlayerManager.Player.EntityState.PickPoint             = faceInteresection;
                        PlayerManager.Player.EntityState.PickPointNormal       = cubeBB.GetPointNormal(faceInteresection);
                    }

                    bool newPlacechanged = false;

                    //Find the potential new block place, by rolling back !
                    while (ptNbr > 0)
                    {
                        pickingWorldPosition -= new Vector3D(pickingLookAt * 0.02f);

                        if (_cubesHolder.isPickable(ref pickingWorldPosition, out _newCube) == false)
                        {
                            PlayerManager.Player.EntityState.NewBlockPosition = _newCube.Position;
                            newPlacechanged = true;
                            break;
                        }
                        ptNbr--;
                    }

                    PlayerManager.Player.EntityState.IsEntityPicked = false;
                    PlayerManager.Player.EntityState.IsBlockPicked  = true;
                    if (_prevCube.Position == PlayerManager.Player.EntityState.PickedBlockPosition)
                    {
                        if (!newPlacechanged)
                        {
                            return(false);
                        }
                    }

                    break;
                }
            }

            // we need to decide what we have picked (block or entity)
            // if we found the block this means that it is closer than entity
            // (because we used limit as the closest picked entity)

            if (!PlayerManager.Player.EntityState.IsBlockPicked && epr.Found)
            {
                _pickedUpEntity         = epr.PickedEntity;
                _pickedUpEntityPosition = _pickedUpEntity.Entity.Position;

                PlayerManager.Player.EntityState.PickedEntityPosition = _pickedUpEntity.Entity.Position;
                PlayerManager.Player.EntityState.PickedEntityLink     = _pickedUpEntity.Entity.GetLink();
                PlayerManager.Player.EntityState.PickPoint            = epr.PickPoint;
                PlayerManager.Player.EntityState.PickPointNormal      = epr.PickNormal;
                PlayerManager.Player.EntityState.IsEntityPicked       = true;
                PlayerManager.Player.EntityState.IsBlockPicked        = false;
            }

            return(PlayerManager.Player.EntityState.IsBlockPicked || PlayerManager.Player.EntityState.IsEntityPicked);
        }