/// <summary> /// Returns the block that the users mouse is hovering over. /// The rules are that /// </summary> /// <param name="collidingBlock">The position of the block that collided with the ChunkTracer.</param> /// <param name="behaviour">The behaviour that defines the rules of hit testing.</param> /// <returns>If the raytrace returned any blocks.</returns> public static bool TryHitTestBlock(CollisionBehaviour behaviour, [NotNull] ChunkTracer tracer, out BlockPosition collidingBlock) { switch (behaviour) { case CollisionBehaviour.Player: return(TryHitTestPlayer(tracer, out collidingBlock)); case CollisionBehaviour.Editor: return(TryHitTestEditor(tracer, out collidingBlock)); default: throw new ArgumentOutOfRangeException("behaviour"); } }
static bool TryHitTestPlayer([NotNull] ChunkTracer tracer, out BlockPosition position) { foreach (var data in tracer) { if (data.Blocks == null || data.Positions == null) { continue; } for (var i = 0; i < data.Blocks.Count; i++) { var block = data.Blocks[i]; if (block.ID == 0 || block.Info.State == BlockState.FLUID) { continue; } position = new BlockPosition(data.ChunkPosition, data.Positions[i], data.Size); return(true); } } position = default(BlockPosition); return(false); }
static bool TryHitTestEditor([NotNull] ChunkTracer tracer, out BlockPosition position) { bool exitedSolid = false; bool exitedAir = false; bool includeLiquids = false; bool firstEnumeration = true; foreach (var traceData in tracer) { // determine if we include liquids by checking if the block we start at is also a liquid if (firstEnumeration) { if (traceData.Blocks == null) { // trace started in a non-generated chunk, which visually is air. IncludeLiquids = false firstEnumeration = false; } else { var firstBlock = traceData.Blocks.FirstOrDefault(); includeLiquids = firstBlock == null || firstBlock.Info.State != BlockState.FLUID; firstEnumeration = false; } } if (traceData.Positions == null || traceData.Blocks == null) { continue; } for (var i = 0; i < traceData.Blocks.Count; i++) { var block = traceData.Blocks[i]; // enumerate until it isn't a solid if (!exitedSolid) { if (block.Info.State != BlockState.SOLID) { exitedSolid = true; } else { continue; } } // enumerate until it isn't air if (!exitedAir) { if (block.ID != 0) { exitedAir = true; } else { continue; } } if (includeLiquids) { // enumerate to any block that isn't air if (block.ID == 0) { continue; } position = new BlockPosition(traceData.ChunkPosition, traceData.Positions[i], traceData.Size); return(true); } // enumerate to the first solid or nonsolid if (block.Info.State == BlockState.FLUID || block.ID == 0) { continue; } position = new BlockPosition(traceData.ChunkPosition, traceData.Positions[i], traceData.Size); return(true); } } position = new BlockPosition(); return(false); }