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); }
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); } }
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; } }
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); }
/// <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); }