Quick Start

This Quick Start guide will help you create a new server for listening and a client for talking to the server.  I’ll show you how to create a server-side event handler as well as creating a State Object to handle simulation.

Hosting the Server

Pixi server is easy to host by creating a Console or Windows service project.  We will create a Console project and add a few lines of code to get it up and running.  The code that follows is not the recommended way of getting the data required to set up a Pixi server but is only used to illustrate the steps needed.  In actual practice, Configuration data, ApplicationDomains, Zones and StateObjects would probably be stored in a configuration file or database.

To start, create a Console application using Visual Studio 2010 or SharpDevelop.  Find and add a reference to Pixi.Server.dll.

The Pixi server requires one Application Domain that contains at least one Zone. Adding the following lines of code will create a Pixi server listening for TCP and UDP connections.

static void Main(string[] args)
{
//Create a new instance of the PixiServer class
PixiServer pixiServer = new PixiServer();

//Add an application domain and a zone
IApplicationDomain appDomain = pixiServer.AddApplicationDomain(1,
"PixiDomain", SimulationStorageType.Quadtree);

// Add a zone to the Application Domain passing in the zoneid, a
// name for the zone, the x and y position of the upper left corner
// and the width and the height of the zone.
appDomain.AddZone(1, "Zone1", 0, 0, 5000, 5000);

//Start the server passing in the IP Address of your Pixi server
// the TCP and the UDP Ports the server will listen on. If you
// are going to access this server from outside your network,
// remember to configure your firewall and router to forward TCP and UDP
// traffic to your server
pixiServer.StartServer("Your IP Address", 11000, 11001);

//Wait until the user hits a key and then exit the program
Console.ReadKey();

//Remember to stop the server
pixiServer.StopServer();
}

Connecting the Client

To create a client that connects to the Pixi server you will have to extend the ClientNetwork class.  Create a Class Library project using Visual Studio or SharpDevelop. Find and add a reference to Pixi.Client.Network.dll, Pixi.Logging.dll and Pixi.PC.Client.dll.  Create a new class and name it GameNetwork.  Derive this class from the ClientNetwork class as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Pixi.PC.Client;
using Pixi.Client.Network;
using Pixi.Logging;
using PixiChat.Common;

namespace PixiClient.Network
{
public class GameNetwork : ClientNetwork
{
public GameNetwork(IClientTransceiverFactory
clientTransceiverFactory, ILogger logger)
: base(clientTransceiverFactory, logger)
{
}


}
}

You can now use this class in your game.  Just reference your Class Library project, the Pixi.Network.dll, Pixi.Client.Network.dll, Pixi.PC.Client.dll and Pixi.Logging.dll and use these lines of code to connect and login to your Pixi server.  _gameNetwork should be a class level instance of the GameNetwork class.

// Pass a reference of the ClientTransceiverFacotry and Logger
// to the GameNetwork class
IClientTransceiverFactory factory = new ClientTransceiverFactory();
ILogger logger = new Logger();

//Initialize and start the gameNetwork
_gameNetwork = new GameNetwork(factory, logger);
_gameNetwork.Start("Server IP", 11000, 11001, 0, 100);

// Login to the Pixi server using the user provided
// username and password
_gameNetwork.Login(“Your UserName”, "Your Password");

Now your client should connect to the server.

Creating Server-Side Event Handlers

Logging in is essential because many messages will not pass through the system unless the client is logged in. In the default form of logging in, the Pixi server receives the username and sends back the login successful message. This default behavior can be overridden by creating your own server-side event handler.  In addition to overriding certain system events, custom event handlers can be created for any combination of MessageClass and MessageType the designer can conceive. 

A MessageClass is a system or user-defined byte that represents a class of messages.  For example, you might have a byte that represents ‘Chat’ as a class of messages. 

A MessageType is a short integer that represents a type of message within the class.  For example, MessageTypes for the preceding ‘Chat’ class might be short values to represent Shout, Say, GuildSay and Whisper.

To create a server-side message event handler the developer must create a class that implements the IServerEventHandler interface found in the Pixi.Server.dll class library.  This interface allows the user to indicate the MessageClass and MessageType the event handler will handle.  If the MessageType is –1, this indicates that the handler handles all messages for the given MessageClass.  Also implemented is the HandleMessage method that receives the ServerMessage being handled, a logger for logging messages and the instance of the ApplicationDomain class that provides the services needed for interacting with the Pixi server framework.

After the developer creates and compiles the project, the resulting dll must be placed in the same directory as Pixi server so that it can be picked up and used in the framework.  To illustrate creating of a server-side event, we’ll override the system login event and just return a LoginSuccessful message to the client.

Create a new Class Library project for your IServerEventHandlers.  Find and add references to Lidgren.Network.dll, Pixi.Logging.dll, Pixi.Network, and Pixi.Server. Create a class and name it LoginHandler and implement the IServerEventHandler interface.  The resulting class will look like the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Pixi.Server.DataStructures;
using Pixi.Server.Network;
using Pixi.Network;
using Pixi.Server;
using Lidgren.Network;

namespace MyPixiServer.EventHandlers
{
public class LoginHandler : IServerEventHandler
{
#region IServerEventHandler Members

public void HandleMessage(ServerMessage message,
ILogger logger, IApplicationDomain applicationDomain)
{
//Send a login success message back to the client
//Get the current network timestamp for the return message
float now = (float)NetTime.Now;

ServerMessage successMessage = new ServerMessage(now,
(byte)SystemMessageClass.System, (short)SystemMessageType.LoginSuccess);

successMessage.SourceId = 0;

//SourceID of the message sent in becomes the TargetID on the way back
successMessage.TargetId = message.SourceId;

//Send using tcp
successMessage.UseUdp = false;

//Add the message to the Application Domain to be sent back to the client
applicationDomain.AddOutgoingMessage(successMessage);
}

public byte MessageClassHandled
{
get { return (byte)SystemMessageClass.System; }
}

public short MessageTypeIDHandled
{
get { return (short)SystemMessageType.LoginRequest; }
}

#endregion
}
}

Creating Server-Side State Objects

The server-side state objects are required for simulation.  There are two abstract objects that can be inherited from to provide the developer the ability of creating their own simulation objects.  The StateObject class is the base of all simulation objects.  It can be directly inherited from to create static simulation objects such as walls.  The StateDynamicEntity class is itself derived from the StateObject class and is used by the developer for creating dynamic simulation objects such as players, mobs, doors or anything else that needs to run code during a simulation. 

The StateDynamicEntity class provides a method named Update that must be overridden.  This method provides the IApplicationDomain object required for interacting with the Pixi framework as well as a logger for logging messages. It returns a list of ServerMessage objects that are generated during the running of the Update method.  This method is called during the simulation loop and should not perform any tasks taking longer than a few milliseconds to run.  Here is where game object movement, collision detection and any other conceivable simulation operations are performed.

The IApplicationDomain object provides services to help interact with the Pix environment.  Other StateDynamicEntity objects can be queried and ServerMessages can be created and added directly to those objects to be processed when their own Update turn comes.  Outgoing ServerMessages that need to be sent to other clients can be generated, added to a list and returned from the Update method for processing by the IApplicationDomain object.

The following code shows the bare-bones necessary for creating a Player class.  Create a Class Library project in Visual Studio and add a reference to Pixi.Server.dll,  Pixi.Math.dll, Pixi.Logging.dll and Lidgren.Network.dll. Add the following class and code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using Pixi.Server;
using Pixi.Server.DataStructures;
using Pixi.Server.Network;
using Pixi.Logging;
using Pixi.Math;

namespace MyPixiServer.GameObjects
{
public class Player : StateDynamicEntity
{
// Constructor required for the base StateDynamicEntity class construction
public Player(int stateObjectId, string name, byte stateObjectType,
Vector3F originalPosition, Vector3F heading, short zoneId,
RectangleF size)
: base(stateObjectId, name, stateObjectType, originalPosition, heading,
zoneId, size)
{
}

// This method is called frequently from the simulation loop
public override List<ServerMessage> Update(
IApplicationDomain applicationDomain, ILogger logger)
{
//Create a list of ServerMessages to return
List<ServerMessage> returnMessages = new List<ServerMessage>();

// Do any simulation code here including movement and interaction
// with other StateDynamicEntity objects

//Illustrates getting other players in my current zone
List<StateDynamicEntity> players =
applicationDomain.GetStateDynamicEntitiesByType(this.CurrentZoneId, 0);
foreach (StateDynamicEntity player in players)
{
//Add some server message such as my position to the
// returnMessages for each player

}

//Illustrates getting StateObjects in my general vacinity
RectangleF areaOfInterest = new RectangleF(this.CurrentPosition.X + 50,
this.CurrentPosition.Y - 50, 100, 100);

List<StateObject> stateObjects =
applicationDomain.QueryStateObjects(this.CurrentZoneId, areaOfInterest);

foreach (StateObject stateObject in stateObjects)
{
// check the stateObject.StateObjectType, stateObject.StateObjectID,
// or add a servermessage if this is a StateDynamicEntity.
// Let your imagination go wild.

}

return returnMessages;
}
}
}

Further Information

For further information and more examples, please see the Tutorials section of this wiki.  We will try to add more tutorials as time goes on.

Last edited Feb 15, 2012 at 10:04 PM by gary123long, version 23

Comments

No comments yet.