static int FindYAbove(Level lvl, ushort x, ushort y, ushort z) { for (; y <= lvl.Height; y++) { BlockID above = lvl.GetBlock(x, (ushort)(y + 1), z); if (above == Block.Invalid) { continue; } if (!CollideType.IsSolid(lvl.CollideType(above))) { continue; } int posY = (y + 1) * 32 - 6; BlockDefinition def = lvl.GetBlockDef(above); if (def != null) { posY += def.MinZ * 2; } return(posY); } return(-1); }
static bool SolidAt(Level lvl, ushort x, int y, ushort z) { if (y >= lvl.Height) { return(false); } BlockID block = lvl.GetBlock(x, (ushort)y, z); return(CollideType.IsSolid(lvl.CollideType(block))); }
public static int FindIntersectingSolids(AABB bb, Level lvl, ref AABB[] aabbs) { Vec3S32 min = bb.BlockMin, max = bb.BlockMax; int volume = (max.X - min.X + 1) * (max.Y - min.Y + 1) * (max.Z - min.Z + 1); if (volume > aabbs.Length) { aabbs = new AABB[volume]; } int count = 0; for (int y = min.Y; y <= max.Y; y++) { for (int z = min.Z; z <= max.Z; z++) { for (int x = min.X; x <= max.X; x++) { BlockID block = lvl.GetBlock((ushort)x, (ushort)y, (ushort)z); AABB blockBB = lvl.blockAABBs[block]; blockBB.Min.X += x * 32; blockBB.Min.Y += y * 32; blockBB.Min.Z += z * 32; blockBB.Max.X += x * 32; blockBB.Max.Y += y * 32; blockBB.Max.Z += z * 32; if (!AABB.Intersects(ref bb, ref blockBB)) { continue; } BlockDefinition def = lvl.GetBlockDef(block); bool solid = false; if (def != null) { solid = CollideType.IsSolid(def.CollideType); } else { solid = block == Block.Invalid || !Block.Walkthrough(Block.Convert(block)); } if (!solid) { continue; } aabbs[count] = blockBB; count++; } } } return(count); }
internal static void Fall(Player p, AABB bb, bool movingDown) { // Client position is slightly more precise than server's // If don't adjust, it's possible for player to land on edge of a block and not die // Only do when not moving down, so hitting a pillar while falling doesn't trigger if (!movingDown) { bb.Min.X -= 1; bb.Max.X += 1; bb.Min.Z -= 1; bb.Max.Z += 1; } bb.Min.Y -= 2; // test block below player feet Vec3S32 min = bb.BlockMin, max = bb.BlockMax; bool allGas = true; for (int z = min.Z; z <= max.Z; z++) { for (int x = min.X; x <= max.X; x++) { BlockID block = GetSurvivalBlock(p, x, min.Y, z); byte collide = p.level.CollideType(block); allGas = allGas && collide == CollideType.WalkThrough; if (!CollideType.IsSolid(collide)) { continue; } int fallHeight = p.startFallY - bb.Min.Y; if (fallHeight > p.level.Config.FallHeight * 32) { p.HandleDeath(Block.Air, null, false, true); } p.startFallY = -1; return; } } if (!allGas) { return; } if (bb.Min.Y > p.lastFallY) { p.startFallY = -1; // flying up resets fall height } p.startFallY = Math.Max(bb.Min.Y, p.startFallY); }
/// <summary> Updates the block at the given position, mainly intended for manual changes by the player. </summary> /// <remarks> Adds to the BlockDB. Also turns block below to grass/dirt depending on light. </remarks> /// <returns> Return code from DoBlockchange </returns> public ChangeResult ChangeBlock(ushort x, ushort y, ushort z, BlockID block) { BlockID old = level.GetBlock(x, y, z); ChangeResult result = level.DoBlockchange(this, x, y, z, block); if (result == ChangeResult.Unchanged) { return(result); } if (result == ChangeResult.Modified) { level.BroadcastChange(x, y, z, block); } ushort flags = BlockDBFlags.ManualPlace; if (painting && CollideType.IsSolid(level.CollideType(old))) { flags = BlockDBFlags.Painted; } level.BlockDB.Cache.Add(this, x, y, z, flags, old, block); y--; // check for growth at block below bool grow = level.Config.GrassGrow && (level.physics == 0 || level.physics == 5); if (!grow || level.CanAffect(this, x, y, z) != null) { return(result); } BlockID below = level.GetBlock(x, y, z); BlockID grass = level.Props[below].GrassBlock; if (grass != Block.Invalid && block == Block.Air) { level.Blockchange(this, x, y, z, grass); } BlockID dirt = level.Props[below].DirtBlock; if (dirt != Block.Invalid && !level.LightPasses(block)) { level.Blockchange(this, x, y, z, dirt); } return(result); }
/// <summary> Updates the block at the given position, mainly intended for manual changes by the player. </summary> /// <remarks> Adds to the BlockDB. Also turns block below to grass/dirt depending on light. </remarks> /// <returns> Return code from DoBlockchange </returns> public int ChangeBlock(ushort x, ushort y, ushort z, BlockID block) { BlockID old = level.GetBlock(x, y, z); int type = level.DoBlockchange(this, x, y, z, block); if (type == 0) { return(type); // no change performed } if (type == 2) { Player.GlobalBlockchange(level, x, y, z, block); // different visually } ushort flags = BlockDBFlags.ManualPlace; if (painting && CollideType.IsSolid(level.CollideType(old))) { flags = BlockDBFlags.Painted; } level.BlockDB.Cache.Add(this, x, y, z, flags, old, block); y--; // check for growth at block below bool grow = level.Config.GrassGrow && (level.physics == 0 || level.physics == 5); if (!grow || level.CanAffect(this, x, y, z) != null) { return(type); } BlockID below = level.GetBlock(x, y, z); BlockID grass = level.Props[below].GrassBlock; if (grass != Block.Invalid && block == Block.Air) { level.Blockchange(this, x, y, z, grass); } BlockID dirt = level.Props[below].DirtBlock; if (dirt != Block.Invalid && !level.LightPasses(block)) { level.Blockchange(this, x, y, z, dirt); } return(type); }
static int FindYAbove(Level lvl, ushort x, ushort y, ushort z) { bool foundAnySolid = false; for (ushort yCheck = y; yCheck < lvl.Height; yCheck++) { BlockID block = lvl.GetBlock(x, yCheck, z); if (block != Block.Invalid && CollideType.IsSolid(lvl.CollideType(block))) { foundAnySolid = true; continue; } BlockID above = lvl.GetBlock(x, (ushort)(yCheck + 1), z); if (above != Block.Invalid && CollideType.IsSolid(lvl.CollideType(above))) { foundAnySolid = true; continue; } BlockID below = lvl.GetBlock(x, (ushort)(yCheck - 1), z); if (below != Block.Invalid && CollideType.IsSolid(lvl.CollideType(below)) && yCheck > y) return yCheck; } return foundAnySolid ? lvl.Height : -1; }
/// <summary> Updates the block at the given position, mainly intended for manual changes by the player. </summary> /// <remarks> Adds to the BlockDB. Also turns block below to grass/dirt depending on light. </remarks> /// <returns> Return code from DoBlockchange </returns> public int ChangeBlock(ushort x, ushort y, ushort z, ExtBlock block) { ExtBlock old = level.GetBlock(x, y, z); int type = level.DoBlockchange(this, x, y, z, block); if (type == 0) { return(type); // no change performed } if (type == 2) { Player.GlobalBlockchange(level, x, y, z, block); // different visually } ushort flags = BlockDBFlags.ManualPlace; if (painting && CollideType.IsSolid(level.CollideType(old))) { flags = BlockDBFlags.Painted; } level.BlockDB.Cache.Add(this, x, y, z, flags, old, block); bool autoGrass = level.Config.GrassGrow && (level.physics == 0 || level.physics == 5); if (!autoGrass) { return(type); } ExtBlock below = level.GetBlock(x, (ushort)(y - 1), z); ushort grassIdx = level.Props[below.Index].GrassIndex; if (grassIdx != Block.Invalid && block.BlockID == Block.Air) { level.Blockchange(this, x, (ushort)(y - 1), z, ExtBlock.FromIndex(grassIdx)); } ushort dirtIdx = level.Props[below.Index].DirtIndex; if (dirtIdx != Block.Invalid && !level.LightPasses(block)) { level.Blockchange(this, x, (ushort)(y - 1), z, ExtBlock.FromIndex(dirtIdx)); } return(type); }
public static bool IntersectsSolidBlocks(AABB bb, Level lvl) { Vec3S32 min = bb.BlockMin, max = bb.BlockMax; for (int y = min.Y; y <= max.Y; y++) { for (int z = min.Z; z <= max.Z; z++) { for (int x = min.X; x <= max.X; x++) { ushort xP = (ushort)x, yP = (ushort)y, zP = (ushort)z; ExtBlock block = lvl.GetBlock(xP, yP, zP); AABB blockBB = lvl.blockAABBs[block.Index].Offset(x * 32, y * 32, z * 32); if (!AABB.Intersects(ref bb, ref blockBB)) { continue; } BlockDefinition def = lvl.GetBlockDef(block); if (def != null) { if (CollideType.IsSolid(def.CollideType)) { return(true); } } else if (block.BlockID == Block.Invalid) { if (y < lvl.Height) { return(true); } } else if (!Block.Walkthrough(Block.Convert(block.BlockID))) { return(true); } } } } return(false); }
internal static void Fall(Player p, AABB bb) { bb.Min.Y -= 2; // test block below player feet Vec3S32 min = bb.BlockMin, max = bb.BlockMax; bool allGas = true; for (int z = min.Z; z <= max.Z; z++) { for (int x = min.X; x <= max.X; x++) { ExtBlock block = GetSurvivalBlock(p, x, min.Y, z); byte collide = p.level.CollideType(block); allGas = allGas && collide == CollideType.WalkThrough; if (!CollideType.IsSolid(collide)) { continue; } int fallHeight = p.startFallY - bb.Min.Y; if (fallHeight > p.level.Config.FallHeight * 32) { p.HandleDeath(ExtBlock.Air, null, false, true); } p.startFallY = -1; return; } } if (!allGas) { return; } if (bb.Min.Y > p.lastFallY) { p.startFallY = -1; // flying up resets fall height } p.startFallY = Math.Max(bb.Min.Y, p.startFallY); }
static int FindYAbove(Level lvl, ushort x, ushort y, ushort z) { for (; y < lvl.Height; y++) { BlockID block = lvl.GetBlock(x, y, z); if (block != Block.Invalid && CollideType.IsSolid(lvl.CollideType(block))) { continue; } BlockID above = lvl.GetBlock(x, (ushort)(y + 1), z); if (above != Block.Invalid && CollideType.IsSolid(lvl.CollideType(above))) { continue; } BlockID below = lvl.GetBlock(x, (ushort)(y - 1), z); if (below != Block.Invalid && CollideType.IsSolid(lvl.CollideType(below))) { return(y); } } return(-1); }
static int FindYBelow(Level lvl, ushort x, ushort y, ushort z) { for (; y > 0; y--) { ExtBlock block = lvl.GetBlock(x, y, z); if (!block.IsInvalid && CollideType.IsSolid(lvl.CollideType(block))) { continue; } ExtBlock above = lvl.GetBlock(x, (ushort)(y + 1), z); if (!above.IsInvalid && CollideType.IsSolid(lvl.CollideType(above))) { continue; } ExtBlock below = lvl.GetBlock(x, (ushort)(y - 1), z); if (!below.IsInvalid && CollideType.IsSolid(lvl.CollideType(below))) { return(y); } } return(-1); }
public bool HitTestMap() { Level map = LevelInfo.FindExact(_curMap); int minX = _pos.X / 32 - 2; int maxX = _pos.X / 32 + 2; int minY = _pos.Y / 32 - 2; int maxY = _pos.Y / 32 + 2; int minZ = _pos.Z / 32 - 2; int maxZ = _pos.Z / 32 + 2; for (int i = minY; i <= maxY; i++) { for (int j = minX; j <= maxX; j++) { for (int k = minZ; k <= maxZ; k++) { if (!CollideType.IsSolid(map.CollideType((map.GetBlock((ushort)(j), (ushort)(i), (ushort)(k)))))) { continue; } bool touchX = _pos.X + _width > (j * 32) && _pos.X < ((j + 1) * 32); bool touchY = (_pos.Y - 32) + _height > (i * 32) && (_pos.Y - 32) < ((i + 1) * 32); bool touchZ = _pos.Z + _width > (k * 32) && _pos.Z < ((k + 1) * 32); if (touchX && touchY && touchZ) { return(true); } } } } return(false); }