An App From Scratch
This tutorial will try to help you understand how to build an application from scratch.
Build a Simple Chat Server In 10 Minutes.
This tutorial is thought as a first step in understanding the
basics of the main concepts in Photon Application and Peer.
- Download the Photon Server SDK and unzip it.
- Using Visual Studio, create a new class library project
ChatServer
. - Add references to ExitGamesLibs.dll, Photon.SocketServer.dll and PhotonHostRuntimeInterfaces.dll
Now, create a new class ChatServer
that inherits from Photon.SocketServer.ApplicationBase
:
C#
using Photon.SocketServer;
public class ChatServer : ApplicationBase
{
protected override PeerBase CreatePeer(InitRequest initRequest)
{
}
protected override void Setup()
{
}
protected override void TearDown()
{
}
}
Create a new class ChatPeer
that inherits from Photon.SocketServer.ClientPeer
:
C#
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
public class ChatPeer : ClientPeer
{
public ChatPeer(InitRequest initRequest)
: base(initRequest)
{
}
protected override void OnDisconnect(DisconnectReason disconnectCode, string reasonDetail)
{
}
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
}
}
Return a new instance of ChatPeer
at ChatServer.CreatePeer
:
C#
protected override PeerBase CreatePeer(InitRequest initRequest)
{
return new ChatPeer(initRequest);
}
The ChatServer
assembly will be loaded by Photon native core on the Default
Photon instance.
Thus, the server configuration file, PhotonServer.config
, should contain the proper definition of that application.
The following snippet illustrates an easy way to do this:
XML
<?xml version="1.0"?>
<Configuration>
<ChatServer DisplayName="Chat Server">
<TCPListeners>
<TCPListener
IPAddress="0.0.0.0"
Port="4530"
OverrideApplication="ChatServer"
>
</TCPListener>
</TCPListeners>
<!-- Defines the Photon Runtime Assembly to use. -->
<Runtime
Assembly="PhotonHostRuntime, Culture=neutral"
Type="PhotonHostRuntime.PhotonDomainManager"
UnhandledExceptionPolicy="Ignore">
</Runtime>
<!-- other elements -->
<Applications Default="ChatServer">
<Application
Name="ChatServer"
BaseDirectory="ChatServer"
Assembly="ChatServer"
Type="ChatServer">
</Application>
<!-- any other applications -->
</Applications>
<!-- other elements -->
</ChatServer>
</Configuration>
This configuration requires that the server binaries are located under deploy/ChatServer/bin and that class ChatServer
does not belong to a namespace.
For more information about server configuration please refer to the respective documentation page.
Create a new console project for a chat client.
Add reference to Photon3DotNet.dll to the new project.
Client code should read as follows.
C#
using System;
using System.Collections.Generic;
using ExitGames.Client.Photon;
using System.Threading;
public class ChatClient : IPhotonPeerListener
{
private bool connected;
PhotonPeer peer;
public static void Main()
{
var client = new ChatClient();
client.peer = new PhotonPeer(client, ConnectionProtocol.Tcp);
// connect
client.DebugReturn(DebugLevel.INFO, "Connecting to server at 127.0.0.1:4530 using TCP");
client.peer.Connect("127.0.0.1:4530", "ChatServer");
// client needs a background thread to dispatch incoming messages and send outgoing messages
client.Run();
while (true)
{
if (!client.connected) { continue; }
// read input
string buffer = Console.ReadLine();
// send to server
var parameters = new Dictionary<byte, object> { { 1, buffer } };
client.peer.OpCustom(1, parameters, true);
}
}
private void UpdateLoop()
{
while (true)
{
peer.Service();
}
}
public void Run()
{
Thread thread = new Thread(UpdateLoop);
thread.IsBackground = true;
thread.Start();
}
#region IPhotonPeerListener
public void DebugReturn(DebugLevel level, string message)
{
Console.WriteLine(string.Format("{0}: {1}", level, message));
}
public void OnEvent(EventData eventData)
{
DebugReturn(DebugLevel.INFO, eventData.ToStringFull());
if (eventData.Code == 1)
{
DebugReturn(DebugLevel.INFO, string.Format("Chat Message: {0}", eventData.Parameters[1]));
}
}
public void OnMessage(object messages)
{
throw new NotImplementedException();
}
public void OnOperationResponse(OperationResponse operationResponse)
{
DebugReturn(DebugLevel.INFO, operationResponse.ToStringFull());
}
public void OnStatusChanged(StatusCode statusCode)
{
if (statusCode == StatusCode.Connect)
{
connected = true;
}
switch (statusCode)
{
case StatusCode.Connect:
DebugReturn(DebugLevel.INFO, "Connected");
connected = true;
break;
default:
DebugReturn(DebugLevel.ERROR, statusCode.ToString());
break;
}
}
#endregion
}
If we now start the server the client will be able to connect and to send text messages.
The server logic to process these text messages is still missing.
To verify that the message was received we answer with an OperationResponse
at ChatPeer.OnOperationRequest
.
C#
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
// send operation response (~ACK) back to peer
var response = new OperationResponse(operationRequest.OperationCode);
SendOperationResponse(response, sendParameters);
}
The chat client should now be able to print the event code and the chat
message.
Next thing we want to do is to receive the chat messages on other clients.
We implement the receiver using a publish/subscribe pattern.
C#
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
using System;
public class ChatPeer : ClientPeer
{
public ChatPeer(InitRequest request)
: base(request)
{
BroadcastMessage += OnBroadcastMessage;
}
private static event Action<ChatPeer, EventData, SendParameters> BroadcastMessage;
protected override void OnDisconnect(DisconnectReason disconnectCode, string reasonDetail)
{
BroadcastMessage -= OnBroadcastMessage;
}
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
if (operationRequest.OperationCode == 1) // Chat Custom Operation Code = 1
{
// broadcast chat custom event to other peers
var eventData = new EventData(1) { Parameters = operationRequest.Parameters }; // Chat Custom Event Code = 1
BroadcastMessage(this, eventData, sendParameters);
// send operation response (~ACK) back to peer
var response = new OperationResponse(operationRequest.OperationCode);
SendOperationResponse(response, sendParameters);
}
}
private void OnBroadcastMessage(ChatPeer peer, EventData eventData, SendParameters sendParameters)
{
if (peer != this) // do not send chat custom event to peer who called the chat custom operation
{
SendEvent(eventData, sendParameters);
}
}
}
If you now start two clients both will be able to exchange messages. Do not forget to start Photon server or to restart it with the new configuration. Go to the documentation page if you have troubles with it.
Back to top