private void DamageNearbyBlocks(IPlayer player, BlockSelection blockSel, float damage, int leftDurability) { Block block = player.Entity.World.BlockAccessor.GetBlock(blockSel.Position); if (!CanMultiBreak(block)) { return; } Vec3d hitPos = blockSel.Position.ToVec3d().Add(blockSel.HitPosition); var orderedPositions = GetNearblyMultibreakables(player.Entity.World, blockSel.Position, hitPos).OrderBy(x => x.Value); int q = Math.Min(MultiBreakQuantity, leftDurability); foreach (var val in orderedPositions) { if (q == 0) { break; } BlockFacing facing = BlockFacing.FromVector(player.Entity.ServerPos.GetViewVector()).GetOpposite(); if (!player.Entity.World.CanPlayerAccessBlock(player, blockSel.Position, EnumBlockAccessFlags.BuildOrBreak)) { continue; } player.Entity.World.BlockAccessor.DamageBlock(val.Key, facing, damage); q--; } }
public static BlockFacing MulWithVec3_BlockFacing(float[] matrix, Vec3f vec) { float x = matrix[0] * vec.X + matrix[4] * vec.Y + matrix[8] * vec.Z; float y = matrix[1] * vec.X + matrix[5] * vec.Y + matrix[9] * vec.Z; float z = matrix[2] * vec.X + matrix[6] * vec.Y + matrix[10] * vec.Z; return(BlockFacing.FromVector(x, y, z)); }
private Block GetOrientedBlock(IWorldAccessor world, BlockSelection blockSel) { BlockFacing onBlockFace = blockSel.Face; Vec3d hitPosition = blockSel.HitPosition; //hitPosition projected on the onBlockFace to determine block orientation Vec3d normal = onBlockFace.Normalf.NormalizedCopy().ToVec3d(); normal.Mul((float)hitPosition.SubCopy(0.5, 0.5, 0.5).Dot(normal)); Vec3d projVector = hitPosition.SubCopy(normal).Sub(0.5, 0.5, 0.5); BlockFacing orientation = BlockFacing.FromVector(projVector.X, projVector.Y, projVector.Z); BlockFacing oppositeFace = onBlockFace.GetOpposite(); return(world.BlockAccessor.GetBlock(block.CodeWithParts(orientation.Code, oppositeFace.Code))); }
//API public virtual bool TryOutputConnection(IElectricity connectto) { if (outputConnections == null) { outputConnections = new List <IElectricity>(); } Vec3d vector = connectto.EBlock.Pos.ToVec3d() - Pos.ToVec3d(); BlockFacing bf = BlockFacing.FromVector(vector.X, vector.Y, vector.Z); if (distributionFaces == null) { return(false); } if (!distributionFaces.Contains(bf)) { return(false); } if (!outputConnections.Contains(connectto)) { outputConnections.Add(connectto); MarkDirty(); } return(true); }
//Allow devices to connection to each other //TODO add way to connect valid faces, especially if placed in different directions public virtual bool TryInputConnection(BEElectric connectto) { if (inputConnections == null) { inputConnections = new List <BEElectric>(); } Vec3d vector = connectto.Pos.ToVec3d() - Pos.ToVec3d(); BlockFacing bf = BlockFacing.FromVector(vector.X, vector.Y, vector.Z); if (receptionFaces == null) { return(false); } if (!receptionFaces.Contains(bf)) { return(false); } if (!inputConnections.Contains(connectto)) { inputConnections.Add(connectto); MarkDirty(); } return(true); }
public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt) { IBlockAccessor blockAccess = entity.World.BlockAccessor; FrameProfilerUtil profiler = entity.World.FrameProfiler; float dtFac = 60 * dt; double prevYMotion = pos.Motion.Y; moveDelta.Set(pos.Motion.X * dtFac, prevYMotion * dtFac, pos.Motion.Z * dtFac); nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z); bool falling = prevYMotion < 0; bool feetInLiquidBefore = entity.FeetInLiquid; bool onGroundBefore = entity.OnGround; bool swimmingBefore = entity.Swimming; controls.IsClimbing = false; entity.ClimbingOnFace = null; entity.ClimbingIntoFace = null; if (/*!onGroundBefore &&*/ entity.Properties.CanClimb == true) { int height = (int)Math.Ceiling(entity.CollisionBox.Y2); entityBox.SetAndTranslate(entity.CollisionBox, pos.X, pos.Y, pos.Z); for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int i = 0; i < collBoxes.Length; i++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = null; break; } } } if (controls.WalkVector.LengthSq() > 0.00001 && entity.Properties.CanClimbAnywhere && entity.Alive) { var walkIntoFace = BlockFacing.FromVector(controls.WalkVector.X, controls.WalkVector.Y, controls.WalkVector.Z); if (walkIntoFace != null) { tmpPos.Set((int)pos.X + walkIntoFace.Normali.X, (int)pos.Y + walkIntoFace.Normali.Y, (int)pos.Z + walkIntoFace.Normali.Z); Block nblock = blockAccess.GetBlock(tmpPos); Cuboidf[] icollBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); entity.ClimbingIntoFace = (icollBoxes != null && icollBoxes.Length != 0) ? walkIntoFace : null; } } for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++) { BlockFacing facing = BlockFacing.HORIZONTALS[i]; for (int dy = 0; dy < height; dy++) { tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z); Block nblock = blockAccess.GetBlock(tmpPos); if (!nblock.Climbable && !(entity.Properties.CanClimbAnywhere && entity.Alive)) { continue; } Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos); if (collBoxes == null) { continue; } for (int j = 0; j < collBoxes.Length; j++) { double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos); controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance; if (controls.IsClimbing) { entity.ClimbingOnFace = facing; entity.ClimbingOnCollBox = collBoxes[j]; break; } } } } } if (controls.IsClimbing) { if (controls.WalkVector.Y == 0) { pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y; if (controls.Jump) { pos.Motion.Y = 0.035 * dt * 60f; } } // what was this for? it causes jitter // moveDelta.Y = pos.Motion.Y * dt * 60f; // nextPosition.Set(pos.X + moveDelta.X, pos.Y + moveDelta.Y, pos.Z + moveDelta.Z); } profiler.Mark("prep"); collisionTester.ApplyTerrainCollision(entity, pos, dtFac, ref outposition, stepHeight); profiler.Mark("terraincollision"); if (!entity.Properties.CanClimbAnywhere) { if (smoothStepping) { controls.IsStepping = HandleSteppingOnBlocksSmooth(pos, moveDelta, dtFac, controls); } else { controls.IsStepping = HandleSteppingOnBlocks(pos, moveDelta, dtFac, controls); } } profiler.Mark("stepping-checks"); HandleSneaking(pos, controls, dt); if (entity.CollidedHorizontally && !controls.IsClimbing && !controls.IsStepping && entity.Properties.Habitat != EnumHabitat.Underwater) { if (blockAccess.GetBlock((int)pos.X, (int)(pos.Y + 0.5), (int)pos.Z).LiquidLevel >= 7 || blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z).LiquidLevel >= 7 || (blockAccess.GetBlock((int)pos.X, (int)(pos.Y - 0.05), (int)pos.Z).LiquidLevel >= 7)) { pos.Motion.Y += 0.2 * dt; controls.IsStepping = true; } else // attempt to prevent endless collisions { double absX = Math.Abs(pos.Motion.X); double absZ = Math.Abs(pos.Motion.Z); if (absX > absZ) { if (absZ < 0.001) { pos.Motion.Z += pos.Motion.Z < 0 ? -0.0025 : 0.0025; } } else { if (absX < 0.001) { pos.Motion.X += pos.Motion.X < 0 ? -0.0025 : 0.0025; } } } } if (outposition.X != pos.X && blockAccess.IsNotTraversable((pos.X + pos.Motion.X * dt * 60f), pos.Y, pos.Z)) { outposition.X = pos.X; } if (outposition.Y != pos.Y && blockAccess.IsNotTraversable(pos.X, (pos.Y + pos.Motion.Y * dt * 60f), pos.Z)) { outposition.Y = pos.Y; } if (outposition.Z != pos.Z && blockAccess.IsNotTraversable(pos.X, pos.Y, (pos.Z + pos.Motion.Z * dt * 60f))) { outposition.Z = pos.Z; } pos.SetPos(outposition); profiler.Mark("apply-motion"); // Set the motion to zero if he collided. if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0)) { pos.Motion.X = 0; } if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0)) { pos.Motion.Y = 0; } if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0)) { pos.Motion.Z = 0; } float offX = entity.CollisionBox.X2 - entity.OriginCollisionBox.X2; float offZ = entity.CollisionBox.Z2 - entity.OriginCollisionBox.Z2; int posX = (int)(pos.X + offX); int posZ = (int)(pos.Z + offZ); Block block = blockAccess.GetBlock(posX, (int)(pos.Y), posZ); Block waterOrIce = blockAccess.GetLiquidBlock(posX, (int)(pos.Y), posZ); Block middleWOIBlock = blockAccess.GetLiquidBlock(posX, (int)(pos.Y + entity.SwimmingOffsetY), posZ); entity.OnGround = (entity.CollidedVertically && falling && !controls.IsClimbing) || controls.IsStepping; entity.FeetInLiquid = false; if (waterOrIce.IsLiquid()) { Block aboveblock = blockAccess.GetLiquidBlock(posX, (int)(pos.Y + 1), posZ); entity.FeetInLiquid = ((waterOrIce.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y); } entity.InLava = block.LiquidCode == "lava"; entity.Swimming = middleWOIBlock.IsLiquid(); if (!onGroundBefore && entity.OnGround) { entity.OnFallToGround(prevYMotion); } if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming)) { entity.OnCollideWithLiquid(); } if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming)) { entity.OnExitedLiquid(); } if (!falling || entity.OnGround || controls.IsClimbing) { entity.PositionBeforeFalling.Set(outposition); } profiler.Mark("apply-collisionandflags"); Cuboidd testedEntityBox = collisionTester.entityBox; int xMax = (int)testedEntityBox.X2; int yMax = (int)testedEntityBox.Y2; int zMax = (int)testedEntityBox.Z2; int zMin = (int)testedEntityBox.Z1; for (int y = (int)testedEntityBox.Y1; y <= yMax; y++) { for (int x = (int)testedEntityBox.X1; x <= xMax; x++) { for (int z = zMin; z <= zMax; z++) { collisionTester.tmpPos.Set(x, y, z); collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1); if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox)) { // Saves us a few cpu cycles if (x == (int)pos.X && z == (int)pos.Z && y == (int)pos.Y) { block.OnEntityInside(entity.World, entity, collisionTester.tmpPos); continue; } blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos); } } } } profiler.Mark("trigger-insideblock"); }