public void GenerateDropEntity(BlockDescriptor descriptor, IWorld world, IMultiPlayerServer server, ItemStack item) { var entityManager = server.GetEntityManagerForWorld(world); var items = new ItemStack[0]; var type = ToolType.None; var material = ToolMaterial.None; var held = ItemRepository.GetItemProvider(item.Id); if (held is ToolItem) { var tool = held as ToolItem; material = tool.Material; type = tool.ToolType; } if ((EffectiveTools & type) > 0) { if ((EffectiveToolMaterials & material) > 0) { items = GetDrop(descriptor, item); } } foreach (var i in items) { if (i.Empty) { continue; } var entity = new ItemEntity(descriptor.Coordinates.AsVector3() + new Vector3(0.5f), i); entityManager.SpawnEntity(entity); } }
public void DestroyCactus(BlockDescriptor descriptor, IMultiPlayerServer server, IWorld world) { var toDrop = 0; // Search upwards for (var y = descriptor.Coordinates.Y; y < 127; y++) { var coordinates = new Coordinates3D(descriptor.Coordinates.X, y, descriptor.Coordinates.Z); if (world.GetBlockId(coordinates) == BlockId) { world.SetBlockId(coordinates, AirBlock.BlockId); toDrop++; } } // Search downwards. for (var y = descriptor.Coordinates.Y - 1; y > 0; y--) { var coordinates = new Coordinates3D(descriptor.Coordinates.X, y, descriptor.Coordinates.Z); if (world.GetBlockId(coordinates) == BlockId) { world.SetBlockId(coordinates, AirBlock.BlockId); toDrop++; } } var manager = server.GetEntityManagerForWorld(world); manager.SpawnEntity( new ItemEntity(descriptor.Coordinates.AsVector3() + Coordinates3D.Up.AsVector3(), new ItemStack(BlockId, (sbyte)toDrop))); }
public static void HandlePlayerPositionAndLookPacket(IPacket _packet, IRemoteClient _client, IMultiPlayerServer server) { var packet = (PlayerPositionAndLookPacket)_packet; HandlePlayerMovement(_client, new Vector3((float)packet.X, (float)packet.Y, (float)packet.Z), packet.Yaw, packet.Pitch); }
private void HydrationCheckEvent(IMultiPlayerServer server, Coordinates3D coords, IWorld world) { if (world.GetBlockId(coords) != BlockId) { return; } if (MathHelper.Random.Next(3) == 0) { var meta = world.GetMetadata(coords); if (IsHydrated(coords, world) && meta != 15) { meta++; } else { meta--; if (meta == 0) { world.SetBlockId(coords, BlockId); return; } } world.SetMetadata(coords, meta); } var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("farmland", chunk, TimeSpan.FromSeconds(UpdateIntervalSeconds), _server => HydrationCheckEvent(_server, coords, world)); }
private static bool ClientCollidesWithGround(IRemoteClient client, IMultiPlayerServer server, RemoteClient remoteClient) { var position = client.Entity?.Position; if (client.Entity == null) { server.Trace.TraceEvent(TraceEventType.Error, 0, "client has no entity data"); return(false); // ??? } Debug.Assert(position != null, $"{nameof(position)} != null"); var coordinates = (Coordinates3D)position; if (!client.World.TryGetBlockId(coordinates, out var blockId)) { client.Entity.Position = remoteClient.World.SpawnPoint.AsVector3(); // fall back to world spawn point server.Trace.TraceData(TraceEventType.Error, 0, $"client gave a bad starting position: {position}, falling back to spawn point at {client.Entity.Position}"); return(true); // colliding } var head = client.World.GetBlockId((Coordinates3D)(position + Directions.Up)); var feetBox = server.BlockRepository.GetBlockProvider(blockId).BoundingBox; var headBox = server.BlockRepository.GetBlockProvider(head).BoundingBox; return(feetBox != null || headBox != null); // colliding }
public void DoSpread(IMultiPlayerServer server, IWorld world, BlockDescriptor descriptor) { foreach (var coord in SpreadableBlocks) { var check = descriptor.Coordinates + coord; if (world.GetBlockId(check) == AirBlock.BlockId) { foreach (var adj in AdjacentBlocks) { var provider = BlockRepository.GetBlockProvider( world.GetBlockId(check + adj)); if (provider.Flammable) { if (provider.Hardness == 0) { check = check + adj; } // Spread to this block world.SetBlockId(check, BlockId); ScheduleUpdate(server, world, world.GetBlockData(check)); break; } } } } }
internal static void HandleChatMessage(IPacket packet, IRemoteClient client, IMultiPlayerServer server) { // TODO: Abstract this to support things like commands // TODO: Sanitize messages server.OnChatMessageReceived(new ChatMessageEventArgs(client, ((ChatMessagePacket)packet).Message)); }
public static void HandlePlayerBlockPlacementPacket(IPacket _packet, IRemoteClient _client, IMultiPlayerServer server) { var packet = (PlayerBlockPlacementPacket)_packet; var client = (RemoteClient)_client; var slot = client.SelectedItem; var position = new Coordinates3D(packet.X, packet.Y, packet.Z); BlockDescriptor?block; if (position != -Coordinates3D.One) { if (position.DistanceTo((Coordinates3D)client.Entity.Position) > 10 /* TODO: Reach */) { return; } block = client.World.GetBlockData(position); } else { return; } var provider = server.BlockRepository.GetBlockProvider(block.Value.Id); if (provider == null) { server.SendMessage($"{ChatColor.Red}WARNING: block provider for Id {{0}} is null (player placing)", block.Value.Id); server.SendMessage($"{ChatColor.Red}Error occured from client {{0}} at coordinates {{1}}", client.Username, block.Value.Coordinates); server.SendMessage($"{ChatColor.Red}Packet logged at {{0}}, please report upstream", DateTime.UtcNow); return; } if (!provider.BlockRightClicked(block.Value, packet.Face, client.World, client)) { position += MathHelper.BlockFaceToCoordinates(packet.Face); var oldId = client.World.GetBlockId(position); var oldMeta = client.World.GetMetadata(position); client.QueuePacket(new BlockChangePacket(position.X, (sbyte)position.Y, position.Z, (sbyte)oldId, (sbyte)oldMeta)); client.QueuePacket(new SetSlotPacket(0, client.SelectedSlot, client.SelectedItem.Id, client.SelectedItem.Count, client.SelectedItem.Metadata)); return; } if (!slot.Empty) { var itemProvider = server.ItemRepository.GetItemProvider(slot.Id); if (itemProvider == null) { server.SendMessage(ChatColor.Red + "WARNING: item provider for Id {0} is null (player placing)", block.Value.Id); server.SendMessage(ChatColor.Red + "Error occured from client {0} at coordinates {1}", client.Username, block.Value.Coordinates); server.SendMessage(ChatColor.Red + "Packet logged at {0}, please report upstream", DateTime.UtcNow); } itemProvider?.ItemUsedOnBlock(position, slot, packet.Face, client.World, client); } }
public void ScheduleUpdate(IMultiPlayerServer server, IWorld world, BlockDescriptor descriptor) { var chunk = world.FindChunk(descriptor.Coordinates); server.Scheduler.ScheduleEvent("fire.spread", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(MinSpreadTime, MaxSpreadTime)), s => DoUpdate(s, world, descriptor)); }
public override void BlockLoadedFromChunk(Coordinates3D coords, IMultiPlayerServer server, IWorld world) { var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("farmland", chunk, TimeSpan.FromSeconds(UpdateIntervalSeconds), s => HydrationCheckEvent(s, coords, world)); }
public override void BlockLoadedFromChunk(Coordinates3D coords, IMultiPlayerServer server, IWorld world) { var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("crops", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(30, 60)), s => GrowBlock(s, world, coords)); }
public override void BlockLoadedFromChunk(Coordinates3D coords, IMultiPlayerServer server, IWorld world) { var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("cactus", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(MinGrowthSeconds, MaxGrowthSeconds)), s => TryGrowth(s, coords, world)); }
private static void SaveWorlds(IMultiPlayerServer server) { Server.Trace.TraceEvent(TraceEventType.Information, 0, "Saving world..."); foreach (var w in Server.Worlds) { w.Save(); } Server.Trace.TraceEvent(TraceEventType.Information, 0, "Done."); server.Scheduler.ScheduleEvent(Constants.Events.WorldSave, null, TimeSpan.FromSeconds(ServerConfiguration.WorldSaveInterval), SaveWorlds); }
public void TrySpread(Coordinates3D coords, IWorld world, IMultiPlayerServer server) { if (!world.IsValidPosition(coords + Coordinates3D.Up)) { return; } var sky = world.GetSkyLight(coords + Coordinates3D.Up); var block = world.GetBlockLight(coords + Coordinates3D.Up); if (sky < 9 && block < 9) { return; } for (int i = 0, j = MathHelper.Random.Next(GrowthCandidates.Length); i < GrowthCandidates.Length; i++, j++) { var candidate = GrowthCandidates[j % GrowthCandidates.Length] + coords; if (!world.IsValidPosition(candidate) || !world.IsValidPosition(candidate + Coordinates3D.Up)) { continue; } var Id = world.GetBlockId(candidate); if (Id == DirtBlock.BlockId) { var _sky = world.GetSkyLight(candidate + Coordinates3D.Up); var _block = world.GetBlockLight(candidate + Coordinates3D.Up); if (_sky < 4 && _block < 4) { continue; } IChunk chunk; var _candidate = world.FindBlockPosition(candidate, out chunk); var grow = true; for (var y = candidate.Y; y < chunk.GetHeight((byte)_candidate.X, (byte)_candidate.Z); y++) { var b = world.GetBlockId(new Coordinates3D(candidate.X, y, candidate.Z)); var p = world.BlockRepository.GetBlockProvider(b); if (p.LightOpacity >= 2) { grow = false; break; } } if (grow) { world.SetBlockId(candidate, BlockId); server.Scheduler.ScheduleEvent("grass", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(MinGrowthTime, MaxGrowthTime)), s => TrySpread(candidate, world, server)); } break; } } }
public void ScheduleNextEvent(Coordinates3D coords, IWorld world, IMultiPlayerServer server) { if (world.GetBlockId(coords) == StillID) { return; } var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("fluid", chunk, TimeSpan.FromSeconds(SecondsBetweenUpdates), _server => AutomataUpdate(_server, world, coords)); }
public EventScheduler(IMultiPlayerServer server) { Events = new List <ScheduledEvent>(); ImmediateEventQueue = new ConcurrentQueue <ScheduledEvent>(); LaterEventQueue = new ConcurrentQueue <ScheduledEvent>(); DisposedSubjects = new ConcurrentQueue <IEventSubject>(); Server = server; Subjects = new HashSet <IEventSubject>(); Stopwatch = new Stopwatch(); DisabledEvents = new HashSet <string>(); Stopwatch.Start(); }
public EntityManager(IMultiPlayerServer server, IWorld world) { Server = server; World = world; PhysicsEngine = new PhysicsEngine(world, (BlockRepository)server.BlockRepository); PendingDespawns = new ConcurrentBag <IEntity>(); Entities = new List <IEntity>(); // TODO: Handle loading worlds that already have entities // Note: probably not the concern of EntityManager. The server could manually set this? NextEntityID = 1; LastUpdate = DateTime.UtcNow; TimeSinceLastUpdate = TimeSpan.Zero; }
public static void HandleAnimation(IPacket _packet, IRemoteClient _client, IMultiPlayerServer server) { var packet = (AnimationPacket)_packet; var client = (RemoteClient)_client; if (packet.EntityId == client.Entity.EntityId) { var nearby = server.GetEntityManagerForWorld(client.World) .ClientsForEntity(client.Entity); foreach (var player in nearby) { player.QueuePacket(packet); } } }
public virtual bool IsSupported(BlockDescriptor descriptor, IMultiPlayerServer server, IWorld world) { var support = GetSupportDirection(descriptor); if (support != Coordinates3D.Zero) { var supportingBlock = server.BlockRepository.GetBlockProvider(world.GetBlockId(descriptor.Coordinates + support)); if (!supportingBlock.Opaque) { return(false); } } return(true); }
private void GrowBlock(IMultiPlayerServer server, IWorld world, Coordinates3D coords) { if (world.GetBlockId(coords) != BlockId) { return; } var meta = world.GetMetadata(coords); meta++; world.SetMetadata(coords, meta); if (meta < 7) { var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("crops", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(30, 60)), _server => GrowBlock(_server, world, coords)); } }
private void AutomataUpdate(IMultiPlayerServer server, IWorld world, Coordinates3D coords) { if (world.GetBlockId(coords) != FlowingID && world.GetBlockId(coords) != StillID) { return; } server.BlockUpdatesEnabled = false; var again = DoAutomata(server, world, coords); server.BlockUpdatesEnabled = true; if (again) { var chunk = world.FindChunk(coords); server.Scheduler.ScheduleEvent("fluid", chunk, TimeSpan.FromSeconds(SecondsBetweenUpdates), _server => AutomataUpdate(_server, world, coords)); } }
public bool DoAutomata(IMultiPlayerServer server, IWorld world, Coordinates3D coords) { var previousLevel = world.GetMetadata(coords); var inward = DetermineInwardFlow(world, coords); var outward = DetermineOutwardFlow(world, coords); if (outward.Length == 1 && outward[0].TargetBlock == coords + Coordinates3D.Down) { // Exit early if we have placed a fluid block beneath us (and we aren't a source block) FlowOutward(world, outward[0], server); if (previousLevel != 0) { return(true); } } // Process inward flow if (inward > MaximumFluidDepletion) { world.SetBlockId(coords, 0); return(true); } world.SetMetadata(coords, inward); if (inward == 0 && previousLevel != 0) { return(true); } // Process outward flow for (var i = 0; i < outward.Length; i++) { FlowOutward(world, outward[i], server); } // Set our block to still fluid if we are done spreading. if (outward.Length == 0 && inward == previousLevel) { world.SetBlockId(coords, StillID); return(false); } return(true); }
public void DoUpdate(IMultiPlayerServer server, IWorld world, BlockDescriptor descriptor) { var down = descriptor.Coordinates + Coordinates3D.Down; var current = world.GetBlockId(descriptor.Coordinates); if (current != BlockId && current != LavaBlock.BlockId && current != StationaryLavaBlock.BlockId) { return; } // Decay var meta = world.GetMetadata(descriptor.Coordinates); meta++; if (meta == 0xE) { if (!world.IsValidPosition(down) || world.GetBlockId(down) != NetherrackBlock.BlockId) { world.SetBlockId(descriptor.Coordinates, AirBlock.BlockId); return; } } world.SetMetadata(descriptor.Coordinates, meta); if (meta > 9) { var pick = AdjacentBlocks[meta % AdjacentBlocks.Length]; var provider = BlockRepository .GetBlockProvider(world.GetBlockId(pick + descriptor.Coordinates)); if (provider.Flammable) { world.SetBlockId(pick + descriptor.Coordinates, AirBlock.BlockId); } } // Spread DoSpread(server, world, descriptor); // Schedule next event ScheduleUpdate(server, world, descriptor); }
public static void RegisterHandlers(IMultiPlayerServer server) { server.RegisterPacketHandler(Constants.PacketIds.KeepAlive, HandleKeepAlive); server.RegisterPacketHandler(Constants.PacketIds.ChatMessage, HandleChatMessage); server.RegisterPacketHandler(Constants.PacketIds.Disconnect, HandleDisconnect); server.RegisterPacketHandler(Constants.PacketIds.Handshake, LoginHandlers.HandleHandshakePacket); server.RegisterPacketHandler(Constants.PacketIds.LoginRequest, LoginHandlers.HandleLoginRequestPacket); server.RegisterPacketHandler(Constants.PacketIds.PlayerGrounded, (a, b, c) => { /* no-op */ }); server.RegisterPacketHandler(Constants.PacketIds.PlayerPosition, EntityHandlers.HandlePlayerPositionPacket); server.RegisterPacketHandler(Constants.PacketIds.PlayerLook, EntityHandlers.HandlePlayerLookPacket); server.RegisterPacketHandler(Constants.PacketIds.PlayerPositionAndLook, EntityHandlers.HandlePlayerPositionAndLookPacket); server.RegisterPacketHandler(Constants.PacketIds.PlayerDigging, InteractionHandlers.HandlePlayerDiggingPacket); server.RegisterPacketHandler(Constants.PacketIds.PlayerBlockPlacement, InteractionHandlers.HandlePlayerBlockPlacementPacket); server.RegisterPacketHandler(Constants.PacketIds.ChangeHeldItem, InteractionHandlers.HandleChangeHeldItem); server.RegisterPacketHandler(Constants.PacketIds.PlayerAction, InteractionHandlers.HandlePlayerAction); server.RegisterPacketHandler(Constants.PacketIds.Animation, InteractionHandlers.HandleAnimation); server.RegisterPacketHandler(Constants.PacketIds.ClickWindow, InteractionHandlers.HandleClickWindowPacket); server.RegisterPacketHandler(Constants.PacketIds.CloseWindow, InteractionHandlers.HandleCloseWindowPacket); server.RegisterPacketHandler(Constants.PacketIds.UpdateSign, InteractionHandlers.HandleUpdateSignPacket); }
private void TryGrowth(IMultiPlayerServer server, Coordinates3D coords, IWorld world) { if (world.GetBlockId(coords) != BlockId) { return; } // Find current height of stalk var height = 0; for (var y = -MaxGrowHeight; y <= MaxGrowHeight; y++) { if (world.GetBlockId(coords + Coordinates3D.Down * y) == BlockId) { height++; } } if (height < MaxGrowHeight) { var meta = world.GetMetadata(coords); meta++; world.SetMetadata(coords, meta); var chunk = world.FindChunk(coords); if (meta == 15) { if (world.GetBlockId(coords + Coordinates3D.Up) == 0) { world.SetBlockId(coords + Coordinates3D.Up, BlockId); server.Scheduler.ScheduleEvent("cactus", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(MinGrowthSeconds, MaxGrowthSeconds)), _server => TryGrowth(_server, coords + Coordinates3D.Up, world)); } } else { server.Scheduler.ScheduleEvent("cactus", chunk, TimeSpan.FromSeconds(MathHelper.Random.Next(MinGrowthSeconds, MaxGrowthSeconds)), _server => TryGrowth(_server, coords, world)); } } }
private void FlowOutward(IWorld world, LiquidFlow target, IMultiPlayerServer server) { // For each block we can flow into, generate an item entity if appropriate var provider = world.BlockRepository.GetBlockProvider(world.GetBlockId(target.TargetBlock)); provider.GenerateDropEntity(new BlockDescriptor { Coordinates = target.TargetBlock, Id = provider.Id }, world, server, ItemStack.EmptyStack); // And overwrite the block with a new fluid block. world.SetBlockId(target.TargetBlock, FlowingID); world.SetMetadata(target.TargetBlock, target.Level); var chunk = world.FindChunk(target.TargetBlock); server.Scheduler.ScheduleEvent("fluid", chunk, TimeSpan.FromSeconds(SecondsBetweenUpdates), s => AutomataUpdate(s, world, target.TargetBlock)); if (FlowingID == LavaBlock.BlockId) { (BlockRepository.GetBlockProvider(FireBlock.BlockId) as FireBlock).ScheduleUpdate( server, world, world.GetBlockData(target.TargetBlock)); } }
public RemoteClient(IMultiPlayerServer server, ServerConfiguration configuration, IPacketReader packetReader, PacketHandler[] packetHandlers, Socket connection) { _configuration = configuration; _cancel = new CancellationTokenSource(); LoadedChunks = new HashSet <Coordinates2D>(); Server = server; Inventory = new InventoryWindow(server.CraftingRepository); InventoryWindow.WindowChange += HandleWindowChange; SelectedSlot = InventoryWindow.HotbarIndex; CurrentWindow = InventoryWindow; ItemStaging = ItemStack.EmptyStack; KnownEntities = new List <IEntity>(); Disconnected = false; EnableLogging = server.EnableClientLogging; NextWindowID = 1; Connection = connection; SocketPool = new SocketAsyncEventArgsPool(100, 200, 65536); PacketReader = packetReader; PacketHandlers = packetHandlers; StartReceive(); }
public override void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiPlayerServer server, IWorld world) { if (!ValidCactusPosition(descriptor, server.BlockRepository, world)) { DestroyCactus(descriptor, server, world); } base.BlockUpdate(descriptor, source, server, world); }
public override void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiPlayerServer server, IWorld world) { if (!ValidPlacement(descriptor, world)) { // Destroy self world.SetBlockId(descriptor.Coordinates, 0); GenerateDropEntity(descriptor, world, server, ItemStack.EmptyStack); } }
public QueryProtocol(IMultiPlayerServer server, ServerConfiguration configuration) { Rnd = new Random(); Server = server; _configuration = configuration; }