- Complete networking aspect

- only TCP, works has been tested
- Commented out Lists and replaced with arrays, the way the list was working it wouldn't have worked, if you can figure out how to make it work feel free to fix it up.
- TODO: When user types exit, the game object becomes useless, I need a Reset function of some kind to reset it for when a new player comes in to reuse that player object.
- TODO: Encryption
- TODO: Fix main person so they have admin commands like list, restart instead of a game with the main server. (ATM Just like that for testing, but now you can test with telnet client)
This commit is contained in:
u8sand_cp 2010-07-26 18:45:21 -07:00
parent c965d5e97a
commit 281fe4b320
8 changed files with 120 additions and 384 deletions

View file

@ -54,10 +54,10 @@ namespace MUDGame
//Player must be instanced AFTER BuildRealms as it needs Game.InitialRealm.InitialZone.InitialRoom //Player must be instanced AFTER BuildRealms as it needs Game.InitialRealm.InitialZone.InitialRoom
//property so that it can set it's starting room correctly. //property so that it can set it's starting room correctly.
player = new BaseCharacter(game); player = new BaseCharacter(game,true);
//Add the player to the game. //Add the player to the game.
//Note once the server is fully implemented the player will be generated automatically by Game. //Note once the server is fully implemented the player will be generated automatically by Game.
game.PlayerCollection.Add(player); //game.PlayerCollection.Add(player);
//Send game info to player //Send game info to player
Console.WriteLine(game.GameTitle); Console.WriteLine(game.GameTitle);

View file

@ -25,13 +25,10 @@ namespace MudEngine.Commands
{ {
if (player.IsAdmin) if (player.IsAdmin)
{ {
for (int i = 0; i < player.Game.PlayerCollection.Count; i++) for (int i = 0; i < player.Game.PlayerCollection./*Count*/Length; i++)
player.Game.PlayerCollection[i].Save(player.Game.PlayerCollection[i].Name + ".dat"); player.Game.PlayerCollection[i].Save(player.Game.PlayerCollection[i].Name + ".dat");
player.Game.Server.EndServer(); player.Game.Server.EndServer();
if (player.Game.ServerType == ProtocolType.Tcp) player.Game.Server.Initialize(555, ref player.Game.PlayerCollection);
player.Game.Server.InitializeTCP(555, ref player.Game.PlayerCollection);
else
player.Game.Server.InitializeUDP(555, ref player.Game.PlayerCollection);
return new CommandResults("Server Restarted."); return new CommandResults("Server Restarted.");
} }
return new CommandResults("Access Denied."); return new CommandResults("Access Denied.");

View file

@ -170,7 +170,7 @@ namespace MudEngine.GameManagement
CurrencyList = new List<Currency>(); CurrencyList = new List<Currency>();
scriptEngine = new Scripting.ScriptEngine(); scriptEngine = new Scripting.ScriptEngine();
RealmCollection = new List<Realm>(); RealmCollection = new List<Realm>();
PlayerCollection = new List<BaseCharacter>(); //PlayerCollection = new List<BaseCharacter>();
GameTitle = "New Game"; GameTitle = "New Game";
_Filename = "Game.xml"; _Filename = "Game.xml";
@ -199,7 +199,7 @@ namespace MudEngine.GameManagement
{ {
Scripting.GameObject obj = new Scripting.GameObject(); Scripting.GameObject obj = new Scripting.GameObject();
obj = scriptEngine.GetObject(t.Name); obj = scriptEngine.GetObject(t.Name);
PlayerCollection.Add((BaseCharacter)obj.Instance); //PlayerCollection.Add((BaseCharacter)obj.Instance);
} }
} }
} }
@ -294,7 +294,8 @@ namespace MudEngine.GameManagement
} }
//TODO: This should be internal only; C# property using get; internal set; so only MudEngine.dll may edit this collection //TODO: This should be internal only; C# property using get; internal set; so only MudEngine.dll may edit this collection
public List<BaseCharacter> PlayerCollection; //public List<BaseCharacter> PlayerCollection;
public BaseCharacter[] PlayerCollection;
public MudEngine.Networking.Server Server { get; internal set; } public MudEngine.Networking.Server Server { get; internal set; }
public ProtocolType ServerType = ProtocolType.Tcp; public ProtocolType ServerType = ProtocolType.Tcp;
@ -305,8 +306,12 @@ namespace MudEngine.GameManagement
private void StartServer() private void StartServer()
{ {
//PlayerCollection = new List<BaseCharacter>(MaximumPlayers);
PlayerCollection = new BaseCharacter[MaximumPlayers];
for (int i = 0; i < MaximumPlayers; i++)
PlayerCollection[i] = new BaseCharacter(this);
Server = new Networking.Server(); Server = new Networking.Server();
Server.InitializeTCP(ServerPort, ref PlayerCollection); Server.Initialize(ServerPort, ref PlayerCollection);
Server.Start(); Server.Start();
} }
} }

View file

@ -12,6 +12,9 @@ using MudEngine.GameObjects;
using MudEngine.GameObjects.Environment; using MudEngine.GameObjects.Environment;
using MudEngine.GameObjects.Items; using MudEngine.GameObjects.Items;
using System.Net;
using System.Net.Sockets;
namespace MudEngine.GameObjects.Characters namespace MudEngine.GameObjects.Characters
{ {
public class BaseCharacter : BaseObject public class BaseCharacter : BaseObject
@ -31,15 +34,21 @@ namespace MudEngine.GameObjects.Characters
/// </summary> /// </summary>
public Boolean IsAdmin { get; private set; } public Boolean IsAdmin { get; private set; }
/// <summary>
/// Gets or Sets if this player is active.
/// </summary>
public Boolean IsActive { get; private set; }
/// <summary> /// <summary>
/// Gets a reference to the currently running game. /// Gets a reference to the currently running game.
/// </summary> /// </summary>
public Game Game { get; private set; } public Game Game { get; private set; }
public BaseCharacter(Game game) public BaseCharacter(Game game,bool admin = false)
{ {
Game = game; Game = game;
IsAdmin = true; IsAdmin = admin;
IsActive = false;
CurrentRoom = game.InitialRealm.InitialZone.InitialRoom; CurrentRoom = game.InitialRealm.InitialZone.InitialRoom;
} }
@ -89,12 +98,44 @@ namespace MudEngine.GameObjects.Characters
return ""; return "";
} }
public void Initialize(ref MudEngine.Networking.ClientSocket rcs) internal void Initialize()
{ {
CurrentRoom = Game.InitialRealm.InitialZone.InitialRoom; CurrentRoom = Game.InitialRealm.InitialZone.InitialRoom;
sock = rcs;
}
public MudEngine.Networking.ClientSocket sock; IsActive = true;
}
internal void Receive(byte[] data)
{
// convert that data to string
String str;
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = enc.GetString(data);
// execute, and get result
str = ExecuteCommand(str);
// convert the result back to bytes and send it back
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Send(encoding.GetBytes(str));
if (!Game.IsRunning)
Clear();
}
internal void Send(byte[] data)
{
try
{
client.Send(data);
}
catch (Exception) // error, connection failed: close client
{
Clear();
}
}
internal void Clear()
{
// TODO: Save();
IsActive = false;
client.Close();
// TODO: Reset game so it can be used again
}
internal Socket client;
} }
} }

View file

@ -72,9 +72,7 @@
<Compile Include="GameObjects\Environment\Zone.cs" /> <Compile Include="GameObjects\Environment\Zone.cs" />
<Compile Include="GameObjects\Items\BaseItem.cs" /> <Compile Include="GameObjects\Items\BaseItem.cs" />
<Compile Include="GameObjects\Currency.cs" /> <Compile Include="GameObjects\Currency.cs" />
<Compile Include="Networking\ClientSocket.cs" />
<Compile Include="Networking\Server.cs" /> <Compile Include="Networking\Server.cs" />
<Compile Include="Networking\ServerSocket.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Scripting\GameObject.cs" /> <Compile Include="Scripting\GameObject.cs" />
<Compile Include="Scripting\GameObjectCollection.cs" /> <Compile Include="Scripting\GameObjectCollection.cs" />

View file

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
// TODO: Make ClientSocket a friend of ServerSocket so I can make sock and type private
// other, havn't thought of what else I need
namespace MudEngine.Networking
{
public class ClientSocket
{
public ClientSocket()
{
type = 0;
used = false;
}
~ClientSocket()
{
type = 0;
used = false;
}
public int Send(byte[] ba)
{
try
{
sock.Send(ba);
}
catch (Exception)
{
return -1;
}
return 1;
}
public int Receive(byte[] ba)
{
try
{
sock.Receive(ba);
}
catch (Exception)
{
return -1;
}
return 1;
}
public int CleanUp()
{
try
{
sock.Disconnect(true);
sock.Close();
sock.Dispose();
type = 0;
used = false;
}
catch (Exception)
{
return -1;
}
return 1;
}
public ProtocolType type;
public IPAddress ip;
public Socket sock;
public bool used;
}
}

View file

@ -21,129 +21,110 @@ namespace MudEngine.Networking
public Server() public Server()
{ {
stage = 0; stage = 0;
server = new ServerSocket(); port = 0;
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
} }
~Server() ~Server()
{ {
stage = 0; stage = 0;
if (server.type == ProtocolType.Tcp) port = 0;
{
for (int i = 0; i < numberOfClients; i++)
clients[i].CleanUp();
numberOfClients = 0;
}
server.CleanUp();
} }
public bool InitializeTCP(int port, ref List<BaseCharacter> pbs) public bool Initialize(int p, ref /*List<BaseCharacter>*/BaseCharacter[] pbs)
{ {
if (stage != 0) if (stage != 0)
return false; return false;
if (server.Initialize(port, ProtocolType.Tcp) < 0) if (p <= 0)
return false; return false;
port = p;
numberOfClients = pbs.Count; clientThreads = new Thread[pbs./*Capacity*/Length];
clients = new ClientSocket[pbs.Count];
clientThreads = new Thread[pbs.Count];
players = pbs; players = pbs;
stage++;
return true;
}
public bool InitializeUDP(int port, ref List<BaseCharacter> pbs)
{
if (stage != 0)
return false;
if (server.Initialize(port, ProtocolType.Udp) < 0)
return false;
players = pbs;
stage++; stage++;
return true; return true;
} }
public bool Start() public bool Start()
{ {
if (stage != 1) try
return false; {
if (server.Start() < 0) if (stage != 1)
return false;
if (server.Bind() < 0)
return false;
if (server.type == ProtocolType.Tcp)
if (server.Listen() < 0)
return false; return false;
stage++; IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
serverThread = new Thread(ServerThread); server.Bind(ipep);
serverThread.Start(); server.Listen(10);
stage++;
serverThread = new Thread(ServerThread);
serverThread.Start();
}
catch (Exception)
{
return false;
}
return true; return true;
} }
public void EndServer() public void EndServer()
{ {
stage = 0; stage = 0;
serverThread.Abort(); serverThread.Abort();
server.Close();
if (server.type == ProtocolType.Tcp)
{
for (int i = 0; i < numberOfClients; i++)
clients[i].CleanUp();
numberOfClients = 0;
}
server.CleanUp();
} }
/*
* ServerThread, if UDP: Accepts messages(ReceiveFrom) and sends in correspondence to the correct player
* if TCP: Accepts connection and opens a separate thread to receive a data stream between the clien
*/
private void ServerThread() private void ServerThread()
{ {
if (server.type == ProtocolType.Udp) while (stage == 2)
{ {
int sub = -1;
} do
else
{
while (stage == 2)
{ {
int sub = -1; for (int i = 0; i < players./*Count*/Length; i++)
do
{ {
for (int i = 0; i < numberOfClients; i++) if (!players[i].IsActive)
{ {
if (!clients[i].used) sub = i;
{ break;
sub = i;
break;
}
} }
} while (sub == -1); }
server.Accept(clients[sub]); } while (sub < 0);
clients[sub].used = true; players[sub].client = server.Accept();
players[sub].Initialize(ref clients[sub]); players[sub].Initialize();
ParameterizedThreadStart start = new ParameterizedThreadStart(ReceiveThread); //ParameterizedThreadStart start = new ParameterizedThreadStart(ReceiveThread);
clientThreads[sub] = new Thread(start); clientThreads[sub] = new Thread(ReceiveThread);
clientThreads[sub].Start(); clientThreads[sub].Start((object)sub);
}
} }
} }
private void ReceiveThread(object obj) private void ReceiveThread(object obj)
{ {
int sub = (int)obj; int sub = (int)obj;
while (stage == 2 && clients[sub].used) while (stage == 2 && players[sub].IsActive)
{ {
byte[] buf = new byte[256]; try
clients[sub].Receive(buf); {
byte[] buf = new byte[255];
int recved = players[sub].client.Receive(buf);
if(recved > 0)
players[sub].Receive(buf);
}
catch (Exception) // error receiving, close player
{
players[sub].Clear();
}
}
}
public void Disconnect(int sub)
{
if (sub > 0 && sub < players./*Capacity*/Length)
{
clientThreads[sub].Abort();
players[sub].Clear();
} }
} }
private Thread serverThread; private Thread serverThread;
private ServerSocket server; private Socket server;
private int stage; private int stage;
private int port;
List<BaseCharacter> players; //List<BaseCharacter> players;
BaseCharacter[] players;
// TCP Stuff: // TCP Stuff:
private ClientSocket[] clients;
private Thread[] clientThreads; private Thread[] clientThreads;
private int numberOfClients;
} }
} }

View file

@ -1,215 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
// TODO: ln 167 warning, catch more errors and don't return all of em as unknown :o
namespace MudEngine.Networking
{
class ServerSocket
{
public ServerSocket()
{
port = 0;
stage = 0;
type = 0;
}
~ServerSocket()
{
port = 0;
stage = 0;
type = 0;
}
public int Initialize(int p,ProtocolType pt)
{
try
{
if (stage == 0)
{
if (pt != ProtocolType.Tcp && pt != ProtocolType.Udp)
return -3;
port = p;
type = pt;
stage++;
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int Start()
{
try
{
if (stage == 1)
{
if (type == ProtocolType.Tcp)
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, type);
else
sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, type);
stage++;
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int Bind()
{
try
{
if (stage == 2)
{
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
sock.Bind(ipep);
stage++;
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int Listen()
{
try
{
if (stage == 3 && type == ProtocolType.Udp)
return -4;
if (stage == 3)
{
sock.Listen(10);
stage++;
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int Accept(ClientSocket cs)
{
try
{
if (type == ProtocolType.Udp)
return -2;
if (stage == 4)
stage++;
if (stage == 5)
{
cs.sock = sock.Accept();
cs.type = ProtocolType.Tcp;
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int SendTo(byte[] ba, ClientSocket rcs)
{
try
{
if (type != ProtocolType.Udp)
return -3;
if (stage == 3)
stage += 2;
if (stage == 5)
{
IPEndPoint ipep = new IPEndPoint(rcs.ip, port);
sock.SendTo(ba, ipep);
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int ReceiveFrom(byte[] ba, ClientSocket rcs)
{
try
{
if (type != ProtocolType.Udp)
return -3;
if (stage == 3)
stage += 2;
if (stage == 5)
{
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);
EndPoint ep = (EndPoint)ipep;
sock.ReceiveFrom(ba, ref ep);
rcs.ip = ipep.Address;
}
else
return -2;
}
catch (Exception)
{
return -1;
}
return 1;
}
public int CleanUp()
{
try
{
sock.Close();
sock.Dispose();
}
catch (Exception)
{
return -1;
}
return 1;
}
public string GetError(int er_code)
{
if (er_code > 0)
return "No Error";
switch (er_code)
{
case -2:
return "Method cannot be called yet.";
case -3:
return "ProtocolType not supported.";
case -4:
return "The ProtocolType does not support that method.";
default:
return "Unknown Error";
}
}
public int stage { get; private set; }
public int port { get; private set; }
public ProtocolType type { get; private set; }
private Socket sock;
}
}