Skip to content

Registering objects

TheThing edited this page Mar 9, 2011 · 1 revision

Preparing an object for Registration

In order to register an object it has to implement only one interface, and that is INetworkData. INetworkData has a string property called NetworkId. Network Library uses that to distinguish between one object from another. With this network id it will know which object at host corresponds to the same object at the client. Enough about that, lets see a sample object implementing this interface:

public class TestClass : INetworkData
{
	private string[] _stringArray;
	private string _networkId;

	public TestClass()
	{
	}

	public string NetworkId
	{
		get { return _networkId; }
		set { _networkId = value; }
	}

	public string[] StringArray
	{
		get { return _stringArray; }
		set { _stringArray = value; }
	}
}

You might recognize this object from the Registering Events section. Filling the requirement of registering an object into the Network Library is in the most basic words, making the object implement the INetworkData interface and add the following inside:

private string _networkId;

public string NetworkId
{
	get { return _networkId; }
	set { _networkId = value; }
}

That is the only requirement for registering objects into the Network Library.

Registering the object

The network id has to be unique between objects. It also cannot be null. If you do not specify the network id yourself, the Network Library does it for you. In almost all cases you do not need to specifically specifying the network id yourself. Since the Network Library does it for you, such a task is mundane. Only the host however has the privileged to assign the network id. If you register an object to the client, the client will request a unique id from the host. For this reason the client has to be connected to the host before you can assign id to empty objects.

All object registration and such is done inside the INetworkDataHandler inside the INetwork. To register the object, all you have to do is following:

theConnection.NetworkDataHandler.Register( theObject );

You can also register an object recursively. When you have cascading objects, like object called Game, containing collection called PlayerList, each entry inside of type GamePlayer, registering such can be time consuming for each and every object. However with the register recursively, the Network Library will do you for you.

theConnection.NetworkDataHandler.RegisterRecursive( theObject );

The Network Library will search each property and if it implements INetworkData, it will register it. If the property is a type of collection of some sort, it will check each entry and check for INetworkData objects and register each one it finds.

Requesting objects

Due to the nature of how only the Host can assign network id's the client is in no position to register objects. However if you create a host, register an object called Game you can make the Client request it from the host. Doing such is what I recommend that should be done. Doing that will create a unique Game object that is consistent between the host and the client. If any data that is sent between the client and host and that data contains a reference to the Game, only the reference is kept. It will not send the Game along and the reference stays consisted. Lets look at an sample.

Game mainObject = theConnection.NetworkDataHandler.RequestInstance<Game>();

When running this command, the client will send a request to the host and request any object of type Game that has been registered on the host. It will then return that instance of the Game that exists at the host machine. You can also send the request synchronized. This is done like follows:

theConnection.NetworkDataHandler.RequestInstanceAsyncronised<Game>((fromHost) =>
{
	Game mainObject = fromHost;
});

And that is how you register and request registered objects.

The power of registration

To demonstrate why registering objects can be nothing but beneficial, I am going to create a basic example. I am going to create a basic 5 x 5 grid of GamePlot objects, and create an event MoveEvent. The data I am going to send is a basic UnitMoved object that contains 2 parameters: Source plot and the Target plot. Thanks to the powers of registering, all I have to do is directly move the unit inside like this:

theConnection.RegisterEvent((int)PacketCode.UnitMoved, UnitHasMoved);

//...

private static void UnitHasMoved(object source, NetworkEventArgs args)
{
	UnitMoved movement = args.Data as UnitMoved;
	movement.Target.Unit = movement.Source.Unit;
	movement.Source.Unit = null;
	theGame.Print();
}

The full code:

using System;
using System.Collections.Generic;
using NetworkLibrary.Core;
using NetworkLibrary.Exceptions;

namespace ConsoleGame
{
	public class MainProgram
	{
		enum PacketCode { UnitMoved = 0 }

		static INetwork theConnection;
		static Game theGame;

		public static void Main(params string[] args)
		{
			Console.Write("Type 'h' to create host or 'c' to create a client\nInput: ");
			if (Console.ReadLine() == "h")
			{
				theConnection = new ConnectionHost(33050);

				try
				{
					(theConnection as ConnectionHost).StartBroadcasting();
				}
				catch (Exception e)
				{
					Console.WriteLine("\nError while creating host: {0}.", e.Message);
					Console.ReadLine();
					return;
				}
			}
			else
			{
				theConnection = new ConnectionClient();
				try
				{
					(theConnection as ConnectionClient).Connect("127.0.0.1", 33050);
				}
				catch (Exception e)
				{
					Console.WriteLine("\nError while connecting: {0}.", e.Message);
					Console.ReadLine();
					return;
				}
			}
			StartGame();
		}

		private static void StartGame()
		{
			Console.Clear();
			//Register all types of custom objects directly into the Network Library
			theConnection.NetworkDataHandler.RegisterTypeFromAssembly(System.Reflection.Assembly.GetCallingAssembly());
			theConnection.IgnoreDispatcher = true;
			theConnection.OnExceptionOccured += new delegateException(theConnection_OnExceptionOccured);
			theConnection.OnWarningOccured += new delegateWarning(theConnection_OnWarningOccured);
			theConnection.OnNotificationOccured += new delegateNotification(theConnection_OnNotificationOccured);
			//Initialise our Game object
			if (theConnection.NetworkType == NetworkType.Host)
				theConnection.NetworkDataHandler.RegisterRecursive(theGame = new Game(true));
			else
				theGame = theConnection.NetworkDataHandler.RequestInstance<Game>();
			theConnection.RegisterEvent((int)PacketCode.UnitMoved, UnitHasMoved);

			while (true)
			{
				theGame.Print();
				if (theGame.Input())
				{
					theConnection.SendEvent((int)PacketCode.UnitMoved, new UnitMoved(theGame.ActivePlot, theGame.SelectedPlot), true);
					theGame.ActivePlot = null;
				}
			}
		}

		static void theConnection_OnNotificationOccured(object source, string message)
		{
			Console.WriteLine("Notification: " + message);
		}

		static void theConnection_OnWarningOccured(object source, Warning warning)
		{
			Console.WriteLine("Warning: " + warning.ToString());
		}

		private static void UnitHasMoved(object source, NetworkEventArgs args)
		{
			UnitMoved movement = args.Data as UnitMoved;
			movement.Target.Unit = movement.Source.Unit;
			movement.Source.Unit = null;
			theGame.Print();
		}

		static void theConnection_OnExceptionOccured(object source, Exception exception)
		{
			Console.WriteLine(exception.ToString());
		}
	}

	public class UnitMoved
	{
		GamePlot _source;
		GamePlot _target;

		public UnitMoved()
		{
		}

		public UnitMoved(GamePlot source, GamePlot target)
		{
			_source = source;
			_target = target;
		}

		public GamePlot Source
		{
			get { return _source; }
			set { _source = value; }
		}

		public GamePlot Target
		{
			get { return _target; }
			set { _target = value; }
		}
	}

	public class Game : INetworkData
	{
		private string _networkId;
		private GamePlotCollection _plots;
		private GamePlot _selectedPlot;
		private GamePlot _activePlot;

		public Game()
		{
			_plots = new GamePlotCollection();
		}

		public Game(bool createGame)
			: this()
		{
			if (createGame)
			{
				for (int i = 0; i < 25; i++)
				{
					_plots.Add(new GamePlot());
					if (i < 5)
						_plots[_plots.Count - 1].Unit = new GameUnit("X");
					else if (i >= 20)
						_plots[_plots.Count - 1].Unit = new GameUnit("O");
				}
				_selectedPlot = _plots[_plots.Count / 2 + 2];
			}
		}

		public void Print()
		{
			for (int i = 0; i < _plots.Count; i++)
			{
				Console.SetCursorPosition((i % 5 * 3), (i / 5 * 3) + 1);
				if (_plots[i] == _selectedPlot)
					Console.Write(">");
				else
					Console.Write(" ");

				if (_plots[i].Unit != null)
					Console.Write(_plots[i].Unit.TheUnit);
				else
					Console.Write(" ");

				if (_plots[i] == _selectedPlot)
					Console.Write("<");
				else
					Console.Write(" ");
			}
		}

		public bool Input()
		{
			ConsoleKeyInfo key = Console.ReadKey();
			if (key.Key == ConsoleKey.LeftArrow && _selectedPlot != _plots[0])
				_selectedPlot = _plots[_plots.IndexOf(_selectedPlot) - 1];
			else if (key.Key == ConsoleKey.RightArrow && _selectedPlot != _plots[_plots.Count - 1])
				_selectedPlot = _plots[_plots.IndexOf(_selectedPlot) + 1];
			else if (key.Key == ConsoleKey.UpArrow && _plots.IndexOf(_selectedPlot) / 5 > 0)
				_selectedPlot = _plots[_plots.IndexOf(_selectedPlot) - 5];
			else if (key.Key == ConsoleKey.DownArrow && _plots.IndexOf(_selectedPlot) / 5 < 4)
				_selectedPlot = _plots[_plots.IndexOf(_selectedPlot) + 5];
			else if (key.Key == ConsoleKey.Spacebar)
			{
				if (_activePlot != null)
					if (_activePlot.Unit != null && _selectedPlot.Unit == null)
						return true;
				_activePlot = _selectedPlot;
			}
			return false;
		}

		public List<GamePlot> Plots
		{
			get { return _plots; }
		}

		public GamePlot SelectedPlot
		{
			get { return _selectedPlot; }
			set { _selectedPlot = value; }
		}

		public GamePlot ActivePlot
		{
			get { return _activePlot; }
			set { _activePlot = value; }
		}

		public string NetworkId
		{
			get { return _networkId; }
			set { _networkId = value; }
		}
	}

	public class GamePlotCollection : List<GamePlot>, INetworkData
	{
		private string _networkId;

		public GamePlotCollection()
			: base()
		{
		}

		public string NetworkId
		{
			get { return _networkId; }
			set { _networkId = value; }
		}
	}

	public class GamePlot : INetworkData
	{
		GameUnit _unit;
		private string _networkId;

		public GamePlot()
		{
		}

		public GameUnit Unit
		{
			get { return _unit; }
			set { _unit = value; }
		}

		public string NetworkId
		{
			get { return _networkId; }
			set { _networkId = value; }
		}
	}

	public class GameUnit : INetworkData
	{
		string theUnit;
		private string _networkId;

		public GameUnit()
		{
		}

		public GameUnit(string type)
		{
			theUnit = type;
		}

		public string TheUnit
		{
			get { return theUnit; }
			set { theUnit = value; }
		}

		public string NetworkId
		{
			get { return _networkId; }
			set { _networkId = value; }
		}
	}
}