space-pew/SpacePew/Networking/UdpServer.cs
Magnus von Wachenfeldt 2a9d8ce416 move to github
2015-12-04 10:23:49 +01:00

405 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using Microsoft.Xna.Framework;
using SpacePew.Extensions;
using Lidgren.Network;
using System.Net;
using Microsoft.Xna.Framework.Graphics;
using System.Net.NetworkInformation;
using SpacePew.Models;
using SpacePew.Common;
namespace SpacePew.Networking
{
public class UdpServer : UdpBase
{
private NetPeerConfiguration _configuration;
private NetServer _server;
private Level _level;
private readonly List<ScoreBoardItem> _scoreBoard;
private readonly List<string> _players;
private readonly Vector2 _defaultPosition = new Vector2(300, 280);
private IPEndPoint _masterServerEndpoint;
public UdpServer()
: base()
{
_masterServerEndpoint = NetUtility.Resolve("spacepew.wodanaz.se", Constants.MasterServerPort); // TODO: Fixa upp masterserver någonstans
_scoreBoard = new List<ScoreBoardItem>();
_players = new List<string>();
}
public void CreateSession()
{
if (_server == null)
{
_configuration = new NetPeerConfiguration("SpacePew")
{
MaximumConnections = 16,
Port = SpacePew.Common.Constants.GameServerPort
};
_configuration.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
_configuration.EnableMessageType(NetIncomingMessageType.DiscoveryResponse);
_configuration.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
_server = new NetServer(_configuration);
_server.Start();
}
}
public void SetLevel(Level level)
{
_level = level;
}
public void Shutdown()
{
if (_server != null && _server.Status == NetPeerStatus.Running)
{
_server.Shutdown("Quitting");
}
}
public void Listen()
{
System.Diagnostics.Trace.WriteLine("Server.Listen()");
while (_server.Status == NetPeerStatus.Running)
{
NetIncomingMessage message;
while ((message = _server.ReadMessage()) != null)
{
ReadBuffer(message, message.SenderConnection);
}
if (NetTime.Now > lastRegistered + 60)
{
RegisterWithMasterServer();
}
StreamLevelToClients();
}
}
private void StreamLevelToClients()
{
foreach (var conn in _server.Connections)
{
var client = conn.Tag as StreamingClient;
if (client != null)
client.Heartbeat();
}
}
float lastRegistered = -60.0f;
private void RegisterWithMasterServer()
{
IPAddress mask;
IPAddress localAddress = NetUtility.GetMyAddress(out mask);
var message = _server.CreateMessage();
message.Write((byte)UdpNetworkPacketType.RegisterHost);
message.Write(_server.UniqueIdentifier);
message.Write(new IPEndPoint(localAddress, Constants.GameServerPort));
_server.SendUnconnectedMessage(message, _masterServerEndpoint);
lastRegistered = (float)NetTime.Now;
}
private void ReadBuffer(NetIncomingMessage message, NetConnection sender)
{
switch (message.MessageType)
{
case NetIncomingMessageType.Data:
{
var packetType = (UdpNetworkPacketType)message.ReadInt32();
switch (packetType)
{
case UdpNetworkPacketType.PlayerUpdate:
WritePlayerUpdate(message, sender);
break;
case UdpNetworkPacketType.EntitiesCreated:
WriteEntities(message, sender);
break;
case UdpNetworkPacketType.MessageSent:
WriteMessage(message, sender);
break;
case UdpNetworkPacketType.EntityCreated:
WriteEntity(message, sender);
break;
case UdpNetworkPacketType.PlayerDying:
WritePlayerDied(message, sender);
break;
case UdpNetworkPacketType.RequestingScoreboard:
WriteScoreBoard(sender);
break;
case UdpNetworkPacketType.PlayerJoining:
{
string name = message.ReadString();
_players.Add(name);
sender.Tag = name;
_scoreBoard.Add(new ScoreBoardItem() { Name = name, Joined = DateTime.Now });
WritePlayerJoinedPacket(sender, name);
break;
}
case UdpNetworkPacketType.PlayerDisconnecting:
{
string name = message.ReadString();
WritePlayerDisconnectedPacket(sender, name);
break;
}
case UdpNetworkPacketType.LevelRequest:
{
WriteLevelResponse(message);
break;
}
}
}
break;
case NetIncomingMessageType.ConnectionApproval:
AuthorizeConnection(sender);
break;
case NetIncomingMessageType.DiscoveryRequest:
WriteDiscoveryResponse(sender);
break;
case NetIncomingMessageType.StatusChanged:
{
var status = (NetConnectionStatus)message.ReadByte();
var msg = message.ReadString();
break;
}
}
_server.Recycle(message);
}
private void WriteLevelResponse(NetIncomingMessage message)
{
message.SenderConnection.Tag = new StreamingClient(message.SenderConnection, _level.FilePath);
}
private void WriteDiscoveryResponse(NetConnection sender)
{
if (sender == null)
return;
var message = _server.CreateMessage();
// TODO: Skicka med lite stats
_server.SendDiscoveryResponse(message, sender.RemoteEndPoint);
}
private void WritePlayerDisconnectedPacket(NetConnection sender, string name)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerDisconnected);
message.Write(name);
_server.SendToAll(message, sender, NetDeliveryMethod.ReliableUnordered, 0);
_players.Remove(name);
}
private void WriteScoreBoard(NetConnection sender)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.SendingScoreBoard);
int count = _scoreBoard.Count;
message.Write(count);
var ping = new Ping();
foreach (var item in _scoreBoard)
{
message.Write(item.Name);
message.Write(item.Kills);
message.Write(item.Deaths);
message.Write(item.Joined.ToString(CultureInfo.InvariantCulture));
//TODO: Fixa riktig ping
//NetConnection connection = _server.Connections.Find(s => s.Tag.ToString() == item.Name);
//long pingTime = ping.Send(connection.RemoteEndpoint.Address).RoundtripTime;
const long pinglong = 14;
message.Write(pinglong);
}
_server.SendMessage(message, sender, NetDeliveryMethod.UnreliableSequenced);
}
private void WriteMessage(NetIncomingMessage incomingMessage, NetConnection sender)
{
Vector3 colorVector = incomingMessage.ReadVector3();
string dateString = incomingMessage.ReadString();
string message = incomingMessage.ReadString();
bool isChatMessage = incomingMessage.ReadBoolean();
var outgoingMessage = _server.CreateMessage();
outgoingMessage.Write((int)UdpNetworkPacketType.MessageReceived);
outgoingMessage.Write(colorVector);
outgoingMessage.Write(dateString);
outgoingMessage.Write(message);
outgoingMessage.Write(isChatMessage);
_server.SendToAll(outgoingMessage, sender, NetDeliveryMethod.UnreliableSequenced, 1);
}
private void WritePlayerDied(NetIncomingMessage incomingMessage, NetConnection sender)
{
string playerName = incomingMessage.ReadString();
string killedBy = incomingMessage.ReadString();
if (playerName != killedBy)
{
AddKillScore(killedBy);
}
AddDeathScore(playerName);
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerDied);
message.Write(playerName);
_server.SendToAll(message, sender, NetDeliveryMethod.ReliableUnordered, 0);
}
private void AddKillScore(string name)
{
ScoreBoardItem item = _scoreBoard.Find(i => i.Name == name);
item.Kills++;
_scoreBoard[_scoreBoard.IndexOf(item)] = item;
}
private void AddDeathScore(string name)
{
ScoreBoardItem item = _scoreBoard.Find(i => i.Name == name);
item.Deaths++;
_scoreBoard[_scoreBoard.IndexOf(item)] = item;
}
private void WriteEntities(NetIncomingMessage incomingMessage, NetConnection sender)
{
int count = incomingMessage.ReadInt32();
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.EntitiesCreated);
message.Write(count);
for (int i = 0; i < count; i++)
{
message.Write(incomingMessage.ReadString());
message.Write(incomingMessage.ReadString());
message.Write(incomingMessage.ReadVector2());
message.Write(incomingMessage.ReadVector2());
message.Write(incomingMessage.ReadFloat());
}
_server.SendToAll(message, sender, NetDeliveryMethod.UnreliableSequenced, 1);
}
private void AuthorizeConnection(NetConnection sender)
{
string name = Encoding.ASCII.GetString(sender.RemoteHailMessage.Data);
if (!string.IsNullOrEmpty(name) && !_players.Contains(name))
{
sender.Approve();
}
else
{
sender.Deny("A player with that name is already playing.");
}
}
private void WritePlayerJoinedPacket(NetConnection sender, string name)
{
System.Diagnostics.Trace.WriteLine("In WritePlayerJoined()...");
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerJoined);
message.Write(name);
message.Write(_server.Connections.IndexOf(sender));
message.Write(_defaultPosition); // TODO: positions should be stored on the level somehow
message.Write(Vector2.Zero);
message.Write(0f);
_level.BuildCollisionDataFromLevel();
byte[] collisionData = ObjectToByteArray(_level.CollisionData);
message.Write(collisionData.Length);
message.Write(collisionData);
_server.SendMessage(message, sender, NetDeliveryMethod.ReliableUnordered);
System.Diagnostics.Trace.WriteLine("Sent joined...");
}
private void WriteEntity(NetIncomingMessage message, NetConnection sender)
{
string entityType = message.ReadString();
string owner = message.ReadString();
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
WriteEntityPacket(sender, entityType, owner, ref pos, ref velocity, angle);
}
private void WriteEntityPacket(NetConnection connectionToExclude, string entityType, string owner, ref Vector2 pos, ref Vector2 velocity, float angle)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.EntityCreated);
message.Write(entityType);
message.Write(owner);
message.Write(pos);
message.Write(velocity);
message.Write(angle);
_server.SendToAll(message, connectionToExclude, NetDeliveryMethod.UnreliableSequenced, 1);
}
private void WritePlayerUpdate(NetIncomingMessage message, NetConnection sender)
{
string owner = message.ReadString();
int colorIndex = message.ReadInt32();
Vector2 pos = message.ReadVector2();
Vector2 velocity = message.ReadVector2();
float angle = message.ReadFloat();
WritePlayerUpdatePacket(sender, owner, colorIndex, ref pos, ref velocity, angle);
}
private void WritePlayerUpdatePacket(NetConnection connectionToExclude, string owner, int colorIndex, ref Vector2 pos, ref Vector2 velocity, float angle)
{
var message = _server.CreateMessage();
message.Write((int)UdpNetworkPacketType.PlayerUpdate);
message.Write(owner);
message.Write(colorIndex);
message.Write(pos);
message.Write(velocity);
message.Write(angle);
_server.SendToAll(message, connectionToExclude, NetDeliveryMethod.UnreliableSequenced, 1);
}
}
}