} //projectiles decay as soon as they stop /// <summary>Projectile explodes on decay.</summary> internal void OnItemDecay(FrameEventArgs e) { if (Config.IsServer || Config.IsSinglePlayer) { var positions = Coords.AdjacentPositions; var removeBlocks = new List <RemoveBlock>(); var addBlockItems = new List <AddBlockItem>(); Settings.ChunkUpdatesDisabled = true; foreach (var position in positions) { var block = position.GetBlock(); if (block.Type != Block.BlockType.Air && block.Type != Block.BlockType.Water) { WorldData.PlaceBlock(position, Block.BlockType.Air); var tempPosition = position; //copy to pass by ref removeBlocks.Add(new RemoveBlock(ref tempPosition)); if (!block.IsTransparent && position.IsValidItemLocation) { var tempCoords = position.ToCoords(); //copy to pass by ref var newBlockItem = new BlockItem(ref tempCoords, block.Type); addBlockItems.Add(new AddBlockItem(ref newBlockItem.Coords, ref newBlockItem.Velocity, newBlockItem.BlockType, newBlockItem.Id)); } } } Settings.ChunkUpdatesDisabled = false; if (Config.IsServer && removeBlocks.Count > 0) { foreach (var player in Server.Controller.Players.Values) { var removeBlockMulti = new RemoveBlockMulti { ConnectedPlayer = player }; removeBlockMulti.Blocks.AddRange(removeBlocks); removeBlockMulti.BlockItems.AddRange(addBlockItems); removeBlockMulti.Send(); } } } }
/// <summary>Projectile explodes on decay.</summary> internal void OnItemDecay(FrameEventArgs e) { if (Config.IsServer || Config.IsSinglePlayer) { var positions = Coords.AdjacentPositions; var removeBlocks = new List<RemoveBlock>(); var addBlockItems = new List<AddBlockItem>(); Settings.ChunkUpdatesDisabled = true; foreach (var position in positions) { var block = position.GetBlock(); if (block.Type != Block.BlockType.Air && block.Type != Block.BlockType.Water) { WorldData.PlaceBlock(position, Block.BlockType.Air); var tempPosition = position; //copy to pass by ref removeBlocks.Add(new RemoveBlock(ref tempPosition)); if (!block.IsTransparent && position.IsValidItemLocation) { var tempCoords = position.ToCoords(); //copy to pass by ref var newBlockItem = new BlockItem(ref tempCoords, block.Type); addBlockItems.Add(new AddBlockItem(ref newBlockItem.Coords, ref newBlockItem.Velocity, newBlockItem.BlockType, newBlockItem.Id)); } } } Settings.ChunkUpdatesDisabled = false; if (Config.IsServer && removeBlocks.Count > 0) { foreach (var player in Server.Controller.Players.Values) { var removeBlockMulti = new RemoveBlockMulti {ConnectedPlayer = player}; removeBlockMulti.Blocks.AddRange(removeBlocks); removeBlockMulti.BlockItems.AddRange(addBlockItems); removeBlockMulti.Send(); } } } }
// ReSharper restore FunctionNeverReturns private static void PlayerThread(NetworkPlayer player) { NetworkStream clientStream; //make all the introductions. we do this before sending the world so the client doesn't see them as new connections foreach (var otherPlayer in Players.Values) { try { new Connect(otherPlayer.Id, otherPlayer.UserName, otherPlayer.Coords) { ConnectedPlayer = player, Immediate = true }.Send(); } catch (Exception ex) { WriteToServerConsoleLog(string.Format("{0} {1} caused an exception and was removed: {2}", player.UserName, player.IpAddress, ex.Message)); #if DEBUG WriteToServerConsoleLog(ex.StackTrace); #endif } new Connect(player.Id, player.UserName, player.Coords) { ConnectedPlayer = otherPlayer }.Send(); } try { Players.TryAdd(player.Id, player); //note: it is not possible for the add to fail on ConcurrentDictionary, see: http://www.albahari.com/threading/part5.aspx#_Concurrent_Collections UpdateServerConsolePlayerList(); var getWorld = new GetWorld { ConnectedPlayer = player }; getWorld.Send(); WriteToServerConsoleLog(String.Format("World send complete to {0} ({1} compressed, {2} uncompressed)", player.IpAddress, getWorld.DataLength, getWorld.UncompressedLength)); //create a thread to handle communication with connected client player.TcpClient.NoDelay = true; clientStream = player.TcpClient.GetStream(); } catch (Exception ex) { HandleNetworkError(player, ex); return; } var actionTypebytes = new byte[sizeof(ushort)]; try { if (!string.IsNullOrWhiteSpace(Config.MOTD)) { new ServerMsg(Config.MOTD, player).Send(); } while (true) { Thread.Sleep(10); //bm: polling is expensive. don't remove this or the server will pin your machine when only a couple users are online GameAction gameAction; while (player.SendQueue.Count > 0 && player.SendQueue.TryDequeue(out gameAction)) { gameAction.Immediate = true; gameAction.Send(); } if (!clientStream.DataAvailable) { continue; } var bytesRead = 0; while (bytesRead < actionTypebytes.Length) { bytesRead += clientStream.Read(actionTypebytes, bytesRead, actionTypebytes.Length - bytesRead); } var actionType = (ActionType)BitConverter.ToUInt16(actionTypebytes, 0); switch (actionType) { case ActionType.AddBlock: gameAction = new AddBlock(); break; case ActionType.AddBlockItem: gameAction = new AddBlockItem(); break; case ActionType.AddBlockMulti: gameAction = new AddBlockMulti(); break; case ActionType.AddCuboid: gameAction = new AddCuboid(); break; case ActionType.AddProjectile: gameAction = new AddProjectile(); break; case ActionType.AddStaticItem: gameAction = new AddStaticItem(); break; case ActionType.AddStructure: gameAction = new AddStructure(); break; case ActionType.ChatMsg: gameAction = new ChatMsg(); break; case ActionType.Disconnect: gameAction = new Disconnect(); break; case ActionType.PickupBlockItem: gameAction = new PickupBlockItem(); break; case ActionType.PlayerInfo: gameAction = new PlayerInfo(); break; case ActionType.PlayerMove: gameAction = new PlayerMove(); break; case ActionType.PlayerOption: gameAction = new PlayerOption(); break; case ActionType.RemoveBlock: gameAction = new RemoveBlock(); break; case ActionType.RemoveBlockItem: gameAction = new RemoveBlockItem(); break; case ActionType.RemoveBlockMulti: gameAction = new RemoveBlockMulti(); break; case ActionType.ServerCommand: gameAction = new ServerCommand(); break; case ActionType.Connect: case ActionType.ServerMsg: case ActionType.ServerSync: case ActionType.GetWorld: throw new Exception(string.Format("Server should not receive action type: {0}", actionType)); case ActionType.Error: var bytes = 0; while (clientStream.ReadByte() != -1) { bytes++; } throw new Exception("GameAction 'Error' received. " + bytes + " byte(s) remained in the stream."); default: throw new Exception(string.Format("Unknown action type: {0}", actionType)); } gameAction.ConnectedPlayer = player; gameAction.Receive(); if (HasServerConsole && CaptureIncoming) //only stream messages if there is a console window and it has requested to display them { _serverConsole.UpdateStreamLogInvokable(gameAction, player, false); } if (actionType == ActionType.Disconnect) { return; } } } catch (Exception ex) { HandleNetworkError(player, ex); } }
// ReSharper restore FunctionNeverReturns private static void PlayerThread(NetworkPlayer player) { NetworkStream clientStream; //make all the introductions. we do this before sending the world so the client doesn't see them as new connections foreach (var otherPlayer in Players.Values) { try { new Connect(otherPlayer.Id, otherPlayer.UserName, otherPlayer.Coords) { ConnectedPlayer = player, Immediate = true }.Send(); } catch (Exception ex) { WriteToServerConsoleLog(string.Format("{0} {1} caused an exception and was removed: {2}", player.UserName, player.IpAddress, ex.Message)); #if DEBUG WriteToServerConsoleLog(ex.StackTrace); #endif } new Connect(player.Id, player.UserName, player.Coords) { ConnectedPlayer = otherPlayer }.Send(); } try { Players.TryAdd(player.Id, player); //note: it is not possible for the add to fail on ConcurrentDictionary, see: http://www.albahari.com/threading/part5.aspx#_Concurrent_Collections UpdateServerConsolePlayerList(); var getWorld = new GetWorld { ConnectedPlayer = player }; getWorld.Send(); WriteToServerConsoleLog(String.Format("World send complete to {0} ({1} compressed, {2} uncompressed)", player.IpAddress, getWorld.DataLength, getWorld.UncompressedLength)); //create a thread to handle communication with connected client player.TcpClient.NoDelay = true; clientStream = player.TcpClient.GetStream(); } catch (Exception ex) { HandleNetworkError(player, ex); return; } var actionTypebytes = new byte[sizeof(ushort)]; try { if (!string.IsNullOrWhiteSpace(Config.MOTD)) new ServerMsg(Config.MOTD, player).Send(); while (true) { Thread.Sleep(10); //bm: polling is expensive. don't remove this or the server will pin your machine when only a couple users are online GameAction gameAction; while (player.SendQueue.Count > 0 && player.SendQueue.TryDequeue(out gameAction)) { gameAction.Immediate = true; gameAction.Send(); } if (!clientStream.DataAvailable) continue; var bytesRead = 0; while (bytesRead < actionTypebytes.Length) bytesRead += clientStream.Read(actionTypebytes, bytesRead, actionTypebytes.Length - bytesRead); var actionType = (ActionType)BitConverter.ToUInt16(actionTypebytes, 0); switch (actionType) { case ActionType.AddBlock: gameAction = new AddBlock(); break; case ActionType.AddBlockItem: gameAction = new AddBlockItem(); break; case ActionType.AddBlockMulti: gameAction = new AddBlockMulti(); break; case ActionType.AddCuboid: gameAction = new AddCuboid(); break; case ActionType.AddProjectile: gameAction = new AddProjectile(); break; case ActionType.AddStaticItem: gameAction = new AddStaticItem(); break; case ActionType.AddStructure: gameAction = new AddStructure(); break; case ActionType.ChatMsg: gameAction = new ChatMsg(); break; case ActionType.Disconnect: gameAction = new Disconnect(); break; case ActionType.PickupBlockItem: gameAction = new PickupBlockItem(); break; case ActionType.PlayerInfo: gameAction = new PlayerInfo(); break; case ActionType.PlayerMove: gameAction = new PlayerMove(); break; case ActionType.PlayerOption: gameAction = new PlayerOption(); break; case ActionType.RemoveBlock: gameAction = new RemoveBlock(); break; case ActionType.RemoveBlockItem: gameAction = new RemoveBlockItem(); break; case ActionType.RemoveBlockMulti: gameAction = new RemoveBlockMulti(); break; case ActionType.ServerCommand: gameAction = new ServerCommand(); break; case ActionType.Connect: case ActionType.ServerMsg: case ActionType.ServerSync: case ActionType.GetWorld: throw new Exception(string.Format("Server should not receive action type: {0}", actionType)); case ActionType.Error: var bytes = 0; while (clientStream.ReadByte() != -1) { bytes++; } throw new Exception("GameAction 'Error' received. " + bytes + " byte(s) remained in the stream."); default: throw new Exception(string.Format("Unknown action type: {0}", actionType)); } gameAction.ConnectedPlayer = player; gameAction.Receive(); if (HasServerConsole && CaptureIncoming) //only stream messages if there is a console window and it has requested to display them { _serverConsole.UpdateStreamLogInvokable(gameAction, player, false); } if (actionType == ActionType.Disconnect) return; } } catch (Exception ex) { HandleNetworkError(player, ex); } }