public override void OnTeleportTo(AbsWorldCoords absCoords) { foreach (Client c in Server.GetNearbyPlayers(World, absCoords)) { if (!Equals(this)) c.SendTeleportTo(this); else { c.SendPacket(new PlayerPositionRotationPacket { X = absCoords.X, Y = absCoords.Y + Player.EyeGroundOffset, Z = absCoords.Z, Yaw = (float)Position.Yaw, Pitch = (float)Position.Pitch, Stance = c.Stance, OnGround = false } ); } } }
public void InitializePosition() { World = Server.GetDefaultWorld(); Position = new AbsWorldCoords( World.Spawn.WorldX, World.Spawn.WorldY + this.EyeHeight, World.Spawn.WorldZ); }
// TODO: This should be removed in favor of the one below /// <summary> /// Sends a packet in parallel to each nearby player. /// </summary> /// <param name="world">The world containing the coordinates.</param> /// <param name="absCoords>The center coordinates.</param> /// <param name="packet">The packet to send</param> public void SendPacketToNearbyPlayers(WorldManager world, AbsWorldCoords absCoords, Packet packet) { Client[] nearbyClients = GetNearbyPlayers(world, absCoords).ToArray(); if (nearbyClients.Length == 0) return; packet.SetShared(Logger, nearbyClients.Length); Parallel.ForEach(nearbyClients, (client) => { client.SendPacket(packet); }); }
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(); }
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 IEnumerable<EntityBase> GetNearbyLivings(WorldManager world, AbsWorldCoords coords) { int radius = Settings.Default.SightRadius << 4; foreach (EntityBase entity in GetEntities()) { if (!(entity is LivingEntity)) continue; if (entity.World == world && Math.Abs(coords.X - entity.Position.X) <= radius && Math.Abs(coords.Y - entity.Position.Y) <= radius && Math.Abs(coords.Z - entity.Position.Z) <= radius) yield return (entity as LivingEntity); } }
public void GlobalTimer(object state) { int time = Interlocked.Increment(ref _time); if(time % 5 == 0) { Random randGen = new Random(); double randX = 0.05 + randGen.NextDouble()*0.1; double randZ = 0.05 + randGen.NextDouble() * 0.1; Position = new AbsWorldCoords(Position.X + randX, Position.Y, Position.Z + randZ); SendPacket(new PlayerPacket{OnGround = true}); SendPacket(new PlayerPositionPacket{OnGround = true, X = Position.X, Y = Position.Y, Z = Position.Z}); } }
public override void OnTeleportTo(AbsWorldCoords absCoords) { base.OnTeleportTo(absCoords); Client.StopUpdateChunks(); UpdateChunks(1, CancellationToken.None, true, false); Client.SendPacket(new PlayerPositionRotationPacket { X = absCoords.X, Y = absCoords.Y + EyeHeight, Z = absCoords.Z, Yaw = (float)Yaw, Pitch = (float)Pitch, Stance = Client.Stance, OnGround = false }); UpdateEntities(); Server.SendEntityToNearbyPlayers(World, this); Client.ScheduleUpdateChunks(); }
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; } } } } } } } } } }
private static void MobSpecificInitialisation(Mob mob, WorldManager world, AbsWorldCoords coords) { // 1 in 100 chance to spawn a skeleton riding a spider if (mob.Type == MobType.Spider && world.Server.Rand.Next(100) == 0) { LivingEntity skeleton = MobFactory.CreateMob(world, world.Server.AllocateEntity(), MobType.Skeleton); skeleton.Position = coords; skeleton.Yaw = mob.Yaw; world.Server.AddEntity(skeleton); skeleton.MountEntity(mob); } }
public BoundingBox(AbsWorldCoords minimum, AbsWorldCoords maximum) : this(minimum.ToVector(), maximum.ToVector()) { }
public EntitySpawnEventArgs(EntityBase entity, AbsWorldCoords Location) : base(entity) { this.Location = Location; }
public EntityMoveEventArgs(EntityBase entity, AbsWorldCoords newPosition, AbsWorldCoords oldPosition) : base(entity) { NewPosition = newPosition; OldPosition = oldPosition; }
/// <summary> /// Move less than four blocks to the given destination. /// </summary> /// <param name="x">The X coordinate of the target.</param> /// <param name="y">The Y coordinate of the target.</param> /// <param name="z">The Z coordinate of the target.</param> public override void MoveTo(AbsWorldCoords absCoords) { base.MoveTo(absCoords); UpdateEntities(); }
public static void HandlePacketAnimation(Client client, AnimationPacket packet) { Player p = client.Owner; AbsWorldCoords absCoords = new AbsWorldCoords(p.Position.X, p.Position.Y, p.Position.Z); foreach (Client c in p.Server.GetNearbyPlayers(p.World, absCoords)) { if (c == client) continue; c.SendPacket(new AnimationPacket { Animation = packet.Animation, PlayerId = p.EntityId }); } }
/// <summary> /// Move less than four blocks to the given destination and rotate. /// </summary> /// <param name="x">The X coordinate of the target.</param> /// <param name="y">The Y coordinate of the target.</param> /// <param name="z">The Z coordinate of the target.</param> /// <param name="yaw">The absolute yaw to which client should change.</param> /// <param name="pitch">The absolute pitch to which client should change.</param> public override void MoveTo(AbsWorldCoords absCoords, float yaw, float pitch) { base.MoveTo(absCoords, yaw, pitch); UpdateEntities(); }
public static void HandlePacketPlayerPositionRotation(Client client, PlayerPositionRotationPacket packet) { double feetY = packet.Y - client.Owner.EyeHeight; if(client.WaitForInitialPosAck) { AbsWorldCoords coords = new AbsWorldCoords(packet.X, feetY, packet.Z); if(coords == client.Owner.LoginPosition) { client.WaitForInitialPosAck = false; client.SendSecondLoginSequence(); } } else { double threshold = 0.001; double diffX = Math.Abs(client.Owner.Position.X - packet.X); double diffY = Math.Abs(client.Owner.Position.Y - feetY); double diffZ = Math.Abs(client.Owner.Position.Z - packet.Z); if (diffX < threshold && diffY < threshold && diffZ < threshold) return; client.Owner.MoveTo(new AbsWorldCoords(packet.X, feetY, packet.Z), packet.Yaw, packet.Pitch); client.OnGround = packet.OnGround; client.Stance = packet.Stance; client.CheckAndUpdateChunks(packet.X, packet.Z); } }
public void SynchronizeEntities() { AbsWorldCoords absCoords = new AbsWorldCoords(Position.X, Position.Y, Position.Z); foreach (EntityBase e in Server.GetNearbyEntities(World, absCoords)) { if (e.Equals(this)) continue; _client.SendPacket(new EntityTeleportPacket { EntityId = e.EntityId, X = e.Position.X, Y = e.Position.Y, Z = e.Position.Z, Yaw = e.PackedYaw, Pitch = e.PackedPitch }); } }
public static void HandlePacketUseEntity(Client client, UseEntityPacket packet) { //Console.WriteLine(e.Packet.Target); //this.SendMessage("You are interacting with " + e.Packet.Target + " " + e.Packet.LeftClick); Player handledPlayer = client.Owner; AbsWorldCoords absCoords = new AbsWorldCoords(handledPlayer.Position.X, handledPlayer.Position.Y, handledPlayer.Position.Z); foreach (EntityBase eb in handledPlayer.Server.GetNearbyEntities(handledPlayer.World, absCoords)) { if (eb.EntityId != packet.Target) continue; if (eb is Player) { Player player = (Player)eb; if (packet.LeftClick) { handledPlayer.Attack(player); } else { // TODO: Store the object being ridden, so we can update player movement. // This will ride the entity, sends -1 to dismount. foreach (Client cl in handledPlayer.Server.GetNearbyPlayers(handledPlayer.World, absCoords)) { cl.SendPacket(new AttachEntityPacket { EntityId = handledPlayer.EntityId, VehicleId = player.EntityId }); } } } else if (eb is Mob) { Mob m = (Mob)eb; if (packet.LeftClick) { handledPlayer.Attack(m); } else { // We are interacting with a Mob - tell it what we are using to interact with it m.InteractWith(handledPlayer.Client, handledPlayer.Inventory.ActiveItem); // TODO: move the following to appropriate mob locations // TODO: Check Entity has saddle set. //// This will ride the entity, sends -1 to dismount. //foreach (Client c in Server.GetNearbyPlayers(World, Position.X, Position.Y, Position.Z)) //{ // c.PacketHandler.SendPacket(new AttachEntityPacket // { // EntityId = this.EntityId, // VehicleId = c.EntityId // }); //} } } /*else { this.SendMessage(e.Packet.Target + " has no interaction handler!"); }*/ } }
/// <summary> /// Yields an enumerable of nearby entities, including players. Thread-safe. /// </summary> /// <param name="world">The world containing the coordinates.</param> /// <param name="x">The center X coordinate.</param> /// <param name="y">The center Y coordinate.</param> /// <param name="z">The center Z coordinate.</param> /// <returns>A lazy enumerable of nearby entities.</returns> public IEnumerable<EntityBase> GetNearbyEntities(WorldManager world, AbsWorldCoords coords) { int radius = Settings.Default.SightRadius << 4; foreach (EntityBase e in GetEntities()) { if (e.World == world && Math.Abs(coords.X - e.Position.X) <= radius && Math.Abs(coords.Y - e.Position.Y) <= radius && Math.Abs(coords.Z - e.Position.Z) <= radius) yield return e; } }
public void GlobalTimer(object state) { int time = Interlocked.Increment(ref _time); if (!WaitInitialPositionRequest && (time % 5) == 0) { int factor = 1; double rand1; double rand2; if ((rand1 = _rand.NextDouble()) > (rand2 = _rand.NextDouble())) factor = -1; double randX = (0.1 + rand1 * 0.2) * factor; double randZ = (0.1 + rand2 * 0.2) * factor; Position = new AbsWorldCoords(Position.X + randX, Position.Y, Position.Z + randZ); SendPacket(new PlayerPacket{OnGround = true}); SendPacket(new PlayerPositionPacket{OnGround = true, X = Position.X, Y = Position.Y, Z = Position.Z}); } if((time % 50) == 0) { SendPacket(new KeepAlivePacket{KeepAliveID = 1}); } }
// TODO: This should be removed in favor of the one below /// <summary> /// Yields an enumerable of nearby players, thread-safe. /// </summary> /// <param name="world">The world containing the coordinates.</param> /// <param name="absCoords">The center coordinates.</param> /// <returns>A lazy enumerable of nearby players.</returns> public IEnumerable<Client> GetNearbyPlayers(WorldManager world, AbsWorldCoords absCoords) { int radius = Settings.Default.SightRadius << 4; foreach (Client c in GetAuthenticatedClients()) { if (c.Owner.World == world && Math.Abs(absCoords.X - c.Owner.Position.X) <= radius && Math.Abs(absCoords.Z - c.Owner.Position.Z) <= radius) yield return c; } }
public override void OnTeleportTo(AbsWorldCoords absCoords) { base.OnTeleportTo(absCoords); CheckDrowning(); CheckSuffocation(); TouchNearbyBlocks(); }
public static UniversalCoords FromAbsWorld(AbsWorldCoords absWorldCoords) { return FromAbsWorld(absWorldCoords.X, absWorldCoords.Y, absWorldCoords.Z); }
/// <summary> /// Handles the respawning of the Client, called from respawn packet. /// </summary> public void HandleRespawn() { // This can no doubt be improved as waiting on the updatechunk thread is quite slow. Server.RemoveEntity(this); Position = new AbsWorldCoords( World.Spawn.WorldX, World.Spawn.WorldY + this.EyeHeight, World.Spawn.WorldZ); _client.StopUpdateChunks(); UpdateChunks(1, CancellationToken.None, false); _client.SendPacket(new RespawnPacket { }); UpdateEntities(); //SendSpawnPosition(); _client.SendInitialPosition(); _client.SendInitialTime(); InitializeInventory(); InitializeHealth(); _client.ScheduleUpdateChunks(); Server.AddEntity(this); }
/// <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; }
/// <summary> /// Sends a packet in parallel to each nearby player. /// </summary> /// <param name="world">The world containing the coordinates.</param> /// <param name="absCoords>The center coordinates.</param> /// <param name="packet">The packet to send</param> public void SendPacketToNearbyPlayers(WorldManager world, AbsWorldCoords absCoords, Packet packet) { Parallel.ForEach(this.GetNearbyPlayers(world, absCoords), (client) => { client.SendPacket(packet); }); }