Как связать сервер-клиент с библиотекой lidgren?
Я пытаюсь сделать проект сервер-клиент (сервер - приложение concole, клиент - winFrom), но у меня возникли некоторые проблемы. Этот проект был в сети, но я хотел изменить в моих потребностях. Проблема в том, что статус соединения подключен, но сервер "отказывается" отправлять какие-либо данные клиенту. Server.SendMessage() не удалось не подключен!!!! Я не знаю что делать. Оригинальный проект, который я скачал, работает отлично, с той разницей, что в оригинальном проекте клиент также находится в консольном приложении.
приложение консоли сервера:
class Program
{
// Server object
static NetServer Server;
// Configuration object
static NetPeerConfiguration Config;
static void Main(string[] args)
{
// Create new instance of configs. Parameter is "application Id". It has to be same on client and server.
Config = new NetPeerConfiguration("game");
// Set server port
Config.Port = 14242;
// Max client amount
Config.MaximumConnections = 200;
// Enable New messagetype. Explained later
Config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
// Create new server based on the configs just defined
Server = new NetServer(Config);
// Start it
Server.Start();
// Eh..
Console.WriteLine("Server Started");
// Create list of "Characters" ( defined later in code ). This list holds the world state. Character positions
List<Character> GameWorldState = new List<Character>();
// Object that can be used to store and read messages
NetIncomingMessage inc;
// Check time
DateTime time = DateTime.Now;
// Create timespan of 30ms
TimeSpan timetopass = new TimeSpan(0, 0, 0, 0, 30);
// Write to con..
Console.WriteLine("Waiting for new connections and updateing world state to current ones");
// Main loop
// This kind of loop can't be made in XNA. In there, its basically same, but without while
// Or maybe it could be while(new messages)
while (true)
{
// Server.ReadMessage() Returns new messages, that have not yet been read.
// If "inc" is null -> ReadMessage returned null -> Its null, so dont do this :)
if ((inc = Server.ReadMessage()) != null)
{
// Theres few different types of messages. To simplify this process, i left only 2 of em here
switch (inc.MessageType)
{
// If incoming message is Request for connection approval
// This is the very first packet/message that is sent from client
// Here you can do new player initialisation stuff
case NetIncomingMessageType.ConnectionApproval:
// Read the first byte of the packet
// ( Enums can be casted to bytes, so it be used to make bytes human readable )
if (inc.ReadByte() == (byte)PacketTypes.LOGIN)
{
Console.WriteLine("Incoming LOGIN");
// Approve clients connection ( Its sort of agreenment. "You can be my client and i will host you" )
inc.SenderConnection.Approve();
// Init random
Random r = new Random();
// Add new character to the game.
// It adds new player to the list and stores name, ( that was sent from the client )
// Random x, y and stores client IP+Port
GameWorldState.Add(new Character("Shkelqim", r.Next(1, 40), r.Next(1, 20), inc.SenderConnection));
// Create message, that can be written and sent
NetOutgoingMessage outmsg = Server.CreateMessage();
// first we write byte
outmsg.Write((byte)PacketTypes.WORLDSTATE);
// then int
outmsg.Write(GameWorldState.Count);
// iterate trought every character ingame
foreach (Character ch in GameWorldState)
{
// This is handy method
// It writes all the properties of object to the packet
outmsg.WriteAllProperties(ch);
}
// Now, packet contains:
// Byte = packet type
// Int = how many players there is in game
// character object * how many players is in game
// Send message/packet to all connections, in reliably order, channel 0
// Reliably means, that each packet arrives in same order they were sent. Its slower than unreliable, but easyest to understand
Server.SendMessage(outmsg, inc.SenderConnection, NetDeliveryMethod.ReliableOrdered, 0);
// Debug
Console.WriteLine("Approved new connection and updated the world status");
}
break;
// Data type is all messages manually sent from client
// ( Approval is automated process )
case NetIncomingMessageType.Data:
// Read first byte
if (inc.ReadByte() == (byte)PacketTypes.MOVE)
{
// Check who sent the message
// This way we know, what character belongs to message sender
foreach (Character ch in GameWorldState)
{
// If stored connection ( check approved message. We stored ip+port there, to character obj )
// Find the correct character
if (ch.Connection != inc.SenderConnection)
continue;
// Read next byte
byte b = inc.ReadByte();
// Handle movement. This byte should correspond to some direction
if ((byte)MoveDirection.UP == b)
ch.Y--;
if ((byte)MoveDirection.DOWN == b)
ch.Y++;
if ((byte)MoveDirection.LEFT == b)
ch.X--;
if ((byte)MoveDirection.RIGHT == b)
ch.X++;
// Create new message
NetOutgoingMessage outmsg = Server.CreateMessage();
// Write byte, that is type of world state
outmsg.Write((byte)PacketTypes.WORLDSTATE);
// Write int, "how many players in game?"
outmsg.Write(GameWorldState.Count);
// Iterate throught all the players in game
foreach (Character ch2 in GameWorldState)
{
// Write all the properties of object to message
outmsg.WriteAllProperties(ch2);
}
// Message contains
// Byte = PacketType
// Int = Player count
// Character obj * Player count
// Send messsage to clients ( All connections, in reliable order, channel 0)
Server.SendMessage(outmsg, Server.Connections, NetDeliveryMethod.ReliableOrdered, 0);
break;
}
}
break;
case NetIncomingMessageType.StatusChanged:
// In case status changed
// It can be one of these
// NetConnectionStatus.Connected;
// NetConnectionStatus.Connecting;
// NetConnectionStatus.Disconnected;
// NetConnectionStatus.Disconnecting;
// NetConnectionStatus.None;
// NOTE: Disconnecting and Disconnected are not instant unless client is shutdown with disconnect()
Console.WriteLine(inc.SenderConnection.ToString() + " status changed. " + (NetConnectionStatus)inc.SenderConnection.Status);
if (inc.SenderConnection.Status == NetConnectionStatus.Disconnected || inc.SenderConnection.Status == NetConnectionStatus.Disconnecting)
{
// Find disconnected character and remove it
foreach (Character cha in GameWorldState)
{
if (cha.Connection == inc.SenderConnection)
{
GameWorldState.Remove(cha);
break;
}
}
}
break;
default:
// As i statet previously, theres few other kind of messages also, but i dont cover those in this example
// Uncommenting next line, informs you, when ever some other kind of message is received
//Console.WriteLine("Not Important Message");
break;
}
} // If New messages
// if 30ms has passed
if ((time + timetopass) < DateTime.Now)
{
// If there is even 1 client
if (Server.ConnectionsCount != 0)
{
// Create new message
NetOutgoingMessage outmsg = Server.CreateMessage();
// Write byte
outmsg.Write((byte)PacketTypes.WORLDSTATE);
// Write Int
outmsg.Write(GameWorldState.Count);
// Iterate throught all the players in game
foreach (Character ch2 in GameWorldState)
{
// Write all properties of character, to the message
outmsg.WriteAllProperties(ch2);
}
// Message contains
// byte = Type
// Int = Player count
// Character obj * Player count
// Send messsage to clients ( All connections, in reliable order, channel 0)
Server.SendMessage(outmsg, Server.Connections, NetDeliveryMethod.ReliableOrdered, 0);
}
// Update current time
time = DateTime.Now;
}
// While loops run as fast as your computer lets. While(true) can lock your computer up. Even 1ms sleep, lets other programs have piece of your CPU time
//System.Threading.Thread.Sleep(1);
}
}
И Клиент в winform:
static NetClient Client;
// Clients list of characters
static List<Character> GameStateList;
public Form1()
{
InitializeComponent();
NetPeerConfiguration Config = new NetPeerConfiguration("game");
// Create new client, with previously created configs
Client = new NetClient(Config);
// Create new outgoing message
NetOutgoingMessage outmsg = Client.CreateMessage();
//LoginPacket lp = new LoginPacket("Katu");
// Start client
Client.Start();
// Write byte ( first byte informs server about the message type ) ( This way we know, what kind of variables to read )
outmsg.Write((byte)PacketTypes.LOGIN);
// Write String "Name" . Not used, but just showing how to do it
//outmsg.Write("MyName");
// Connect client, to ip previously requested from user
Client.Connect("localhost", 14242, outmsg);
//Console.WriteLine("Connections status: " + (NetConnectionStatus)Client.ServerConnection.Status);
Console.WriteLine("Client Started");
// Create the list of characters
GameStateList = new List<Character>();
}
private void timer1_Tick(object sender, EventArgs e)
{
CheckServerMessages();
}
private static void CheckServerMessages()
{
// Create new incoming message holder
NetIncomingMessage inc;
// While theres new messages
//
// THIS is exactly the same as in WaitForStartingInfo() function
// Check if its Data message
// If its WorldState, read all the characters to list
while ((inc = Client.ReadMessage()) != null)
{
if (inc.MessageType == NetIncomingMessageType.Data)
{
if (inc.ReadByte() == (byte)PacketTypes.WORLDSTATE)
{
GameStateList.Clear();
int jii = 0;
jii = inc.ReadInt32();
for (int i = 0; i < jii; i++)
{
Character ch = new Character();
inc.ReadAllProperties(ch);
GameStateList.Add(ch);
}
}
}
}