/// <summary> /// Ray traces the blocks along the ray. This method takes approx 0.1ms per 50-60 metres. /// </summary> /// <returns> /// The first block hit /// </returns> /// <param name='rayStart'> /// Ray start. /// </param> /// <param name='rayEnd'> /// Ray end. /// </param> public RayTraceHitBlock RayTraceBlocks(AbsWorldCoords rayStart, AbsWorldCoords rayEnd) { UniversalCoords startCoord = UniversalCoords.FromAbsWorld(rayStart); UniversalCoords endCoord = UniversalCoords.FromAbsWorld(rayEnd); UniversalCoords previousPoint; UniversalCoords currentPoint = startCoord; Vector3 rayStartVec = rayStart.ToVector(); Vector3 rayEndVec = rayEnd.ToVector(); Vector3 stepVector = (rayEndVec - rayStartVec).Normalize(); bool xDirectionPositive = stepVector.X > 0; bool yDirectionPositive = stepVector.Y > 0; bool zDirectionPositive = stepVector.Z > 0; Vector3 currentVec = rayStartVec; previousPoint = currentPoint; RayTraceHitBlock blockTrace = null; int blockCheckCount = 0; try { // Step along the ray looking for block collisions while (true) { #region Check adjacent blocks if necessary (to prevent skipping over the corner of one) bool xChanged = currentPoint.WorldX - previousPoint.WorldX != 0; bool yChanged = currentPoint.WorldY - previousPoint.WorldY != 0; bool zChanged = currentPoint.WorldZ - previousPoint.WorldZ != 0; // When we change a coord, need to check which adjacent block also needs to be checked (to prevent missing blocks when jumping over their corners) if (xChanged && yChanged && zChanged) { // -X,Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(previousPoint.WorldX, currentPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // X,-Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, previousPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // X,Y,-Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, currentPoint.WorldY, previousPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // -X,Y,-Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(previousPoint.WorldX, currentPoint.WorldY, previousPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // -X,-Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(previousPoint.WorldX, previousPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // X,-Y,-Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, previousPoint.WorldY, previousPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; } else if (xChanged && zChanged) { // -X,Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(previousPoint.WorldX, currentPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // X,Y,-Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, currentPoint.WorldY, previousPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; } else if (xChanged && yChanged) { // -X,Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(previousPoint.WorldX, currentPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // X,-Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, previousPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; } else if (zChanged && yChanged) { // X,Y,-Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, currentPoint.WorldY, previousPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; // X,-Y,Z blockCheckCount++; blockTrace = DoRayTraceBlock(UniversalCoords.FromWorld(currentPoint.WorldX, previousPoint.WorldY, currentPoint.WorldZ), rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; } #endregion // Check the currentPoint blockCheckCount++; blockTrace = DoRayTraceBlock(currentPoint, rayStartVec, rayEndVec); if (blockTrace != null) return blockTrace; if (currentPoint == endCoord) { //Console.WriteLine("Reach endCoord with no hits"); break; } #region Get the next coordinate previousPoint = currentPoint; do { currentVec += stepVector; currentPoint = UniversalCoords.FromAbsWorld(currentVec.X, currentVec.Y, currentVec.Z); } while(previousPoint == currentPoint); // check we haven't gone past the endCoord if ((xDirectionPositive && currentPoint.WorldX > endCoord.WorldX) || (!xDirectionPositive && currentPoint.WorldX < endCoord.WorldX) || (yDirectionPositive && currentPoint.WorldY > endCoord.WorldY) || (!yDirectionPositive && currentPoint.WorldY < endCoord.WorldY) || (zDirectionPositive && currentPoint.WorldZ > endCoord.WorldZ) || (!zDirectionPositive && currentPoint.WorldZ < endCoord.WorldZ)) { //Console.WriteLine("Went past endCoord: {0}, {1}", startCoord, endCoord); break; } #endregion } } finally { //Console.WriteLine("Block check count {0}", blockCheckCount); } return null; }
public Player GetClosestPlayer(AbsWorldCoords coords, double radius) { var radiusSqrd = radius * radius; Vector3 coordVector = coords.ToVector(); return (from c in Server.GetAuthenticatedClients().Where(client => client.Owner.World == this) let distance = coordVector.DistanceSquared(c.Owner.Position.ToVector()) where distance <= radiusSqrd orderby distance select c.Owner).FirstOrDefault(); }
private static void DoSpawn(WorldManager world, HashSet<int> chunksToSpawnIn, Mob[] mobEntities, List<WeightedValue<MobType>> mobGroup, int maximumMobs, bool inWater = false) { // Based on original server spawn logic and minecraft wiki (http://www.minecraftwiki.net/wiki/Spawn) // Check that we haven't already reached the maximum number of this type of mob if (mobGroup.Count > 0 && (mobEntities.Where(e => mobGroup.Where(mob => mob.Value == e.Type).Any()).Count() <= maximumMobs * chunksToSpawnIn.Count / 256)) { foreach (var packedChunk in chunksToSpawnIn) { MobType mobType = mobGroup.SelectRandom(world.Server.Rand); UniversalCoords packSpawnPosition = GetRandomPointInChunk(world, UniversalCoords.FromPackedChunkToX(packedChunk), UniversalCoords.FromPackedChunkToZ(packedChunk)); byte? blockId = world.GetBlockId(packSpawnPosition); if (blockId == null) continue; BlockBase blockClass = BlockHelper.Instance((byte)blockId); if (!blockClass.IsOpaque && ((!inWater && blockClass.Type == BlockData.Blocks.Air) || (inWater && blockClass.IsLiquid))) // Lava is Opaque, so IsLiquid is safe to use here for water & still water { int spawnedCount = 0; int x = packSpawnPosition.WorldX; int y = packSpawnPosition.WorldY; int z = packSpawnPosition.WorldZ; for (int i = 0; i < 21; i++) { // Every 4th attempt reset the coordinates to the centre of the pack spawn if (i % 4 == 0) { x = packSpawnPosition.WorldX; y = packSpawnPosition.WorldY; z = packSpawnPosition.WorldZ; } const int distance = 6; x += world.Server.Rand.Next(distance) - world.Server.Rand.Next(distance); y += world.Server.Rand.Next(1) - world.Server.Rand.Next(1); z += world.Server.Rand.Next(distance) - world.Server.Rand.Next(distance); if (CanMobTypeSpawnAtLocation(mobType, world, x, y, z)) { AbsWorldCoords spawnPosition = new AbsWorldCoords(x + 0.5, y, z + 0.5); // Check that no player is within a radius of 24 blocks of the spawnPosition if (world.GetClosestPlayer(spawnPosition, 24.0) == null) { // Check that the squared distance is more than 576 from spawn (24 blocks) if (spawnPosition.ToVector().DistanceSquared(new AbsWorldCoords(world.Spawn).ToVector()) > 576.0) { Mob newMob = MobFactory.CreateMob(world, world.Server.AllocateEntity(), mobType); if (newMob == null) break; newMob.Position = spawnPosition; newMob.Yaw = world.Server.Rand.NextDouble()*360.0; // Finally apply any mob specific rules about spawning here if (newMob.CanSpawnHere()) { //Event EntitySpawnEventArgs e = new EntitySpawnEventArgs(newMob, newMob.Position); world.Server.PluginManager.CallEvent(Plugins.Events.Event.EntitySpawn, e); if (e.EventCanceled) continue; newMob.Position = e.Location; //End Event ++spawnedCount; MobSpecificInitialisation(newMob, world, spawnPosition); world.Server.AddEntity(newMob); if (spawnedCount >= newMob.MaxSpawnedPerGroup) { // This chunk is full - move to the next break; } } } } } } } } } }
public Player GetClosestPlayer(AbsWorldCoords coords, double radius) { Vector3 coordVector = coords.ToVector(); return (from c in Server.GetAuthenticatedClients().Where(client => client.Owner.World == this) let distanceVector = coordVector - c.Owner.Position.ToVector() where distanceVector.X <= radius && distanceVector.Y <= radius && distanceVector.Z <= radius orderby distanceVector select c.Owner).FirstOrDefault(); }
public BoundingBox(AbsWorldCoords minimum, AbsWorldCoords maximum) : this(minimum.ToVector(), maximum.ToVector()) { }