【PhotonEngine 學習筆記】(一)簡單使用
【PhotonEngine 學習筆記】(一)簡單使用
- 前言
- PhotonEngine簡介
- 伺服器端邏輯
- 建立自己的伺服器專案(類庫)
- 匯入必要的dll檔案
- 伺服器的入口和出口(繼承ApplicationBase類)
- 伺服器和客戶端交流中心(繼承ClientPeer類)
- 生成dll包,匯入Photon伺服器軟體中
- 在Photon軟體中設定自己的伺服器
- 開啟Photon伺服器軟體,並開啟自己的伺服器邏輯
- 客戶端邏輯
https://blog.csdn.net/qq_25021249/article/details/84404009
前言
關於Photon引擎的基礎教程視訊、文章等等網上有一大堆。我們使用該引擎也有一端時間了,主要是unity專案中的多人聯機模組,這裡主要總結一下學過的知識,若對他人也有所幫助,那更是極好的。
PhotonEngine簡介
官方網址:https://www.photonengine.com/en-US/Photon
The world’s #1 independent networking engine and multiplayer platform — Fast, reliable, scalable. Made for anyone: indies, professional studios and AAA productions.
PhotonEngine是世界排名第一的網路開發引擎、多人網路服務平臺,他快速,可靠,並可擴充套件。適用於所有人:獨立開發者,專業工作室或是3A級別大作。
Photon SDKs
SDKs網址:https://www.photonengine.com/en-us/sdks#
Photon makes multiplayer game development across platforms easy,Last but not least for the broad support of platforms and APIs to develop for.
Photon可以輕鬆實現跨平臺多人遊戲開發,支援多種平臺並且提供對應的API介面。
不同功能的SDK
1.Realtime、PUN:基於Photon雲平臺的伺服器
2.Chat、Voice:主要用於通訊
3.SELF-HOSTED(我們主要說這個):自主新增伺服器邏輯的
SDK:SELF-HOSTED
下載安裝
下載並安裝,得到以下資料夾
依次開啟:…\deploy\bin_Win64
(等會我們編寫伺服器邏輯的時候需要修改這個路徑下的一些檔案)
伺服器端邏輯
建立自己的伺服器專案(類庫)
因為PhotonEngine已經完成了伺服器幾乎所有通訊邏輯程式碼,並封裝成很簡單的介面,我們只需要在此基礎上新增自己的遊戲邏輯程式碼。因此建立一個類庫專案,最終生成一個dll,丟給Photon去執行即可。
匯入必要的dll檔案
實現最基礎的通訊和日誌輸出功能,我們需要匯入以下五個dll:
(檔案目錄:"…\lib")
- ExitGamesLibs.dll
- Photon.SocketServer.dll
- PhotonHostRuntimeInterfaces.dll
- ExitGames.Logging.Log4Net.dll
- log4net.dll
伺服器的入口和出口(繼承ApplicationBase類)
using System;
using Photon.SocketServer;
using ExitGames.Logging;
using System.IO;
namespace MyServer
{
public class MyApplication : ApplicationBase
{
///日誌檔案輸出類
static readonly ILogger log = LogManager.GetCurrentClassLogger();
/// <summary>
/// 伺服器開啟後,自動呼叫該函式
/// </summary>
protected override void Setup()
{
//這四句是設定日誌檔案的格式
LogManager.SetLoggerFactory(ExitGames.Logging.Log4Net.Log4NetLoggerFactory.Instance);
log4net.GlobalContext.Properties["Photon:ApplicationLogPath"] = Path.Combine(this.ApplicationRootPath, "log");
//輸出日誌檔案的名字
log4net.GlobalContext.Properties["LogFileName"] = "LenQiy_" + this.ApplicationName;
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(this.BinaryPath, "log4net.config")));
ShowSysLog("伺服器開啟。");
}
/// <summary>
/// 伺服器關閉後,自動呼叫該函式
/// </summary>
protected override void TearDown()
{
ShowSysLog("伺服器關閉。");
}
/// <summary>
/// 當有 "新客戶端" 連線到伺服器的時候,自動呼叫該函式
/// </summary>
protected override PeerBase CreatePeer(InitRequest initRequest)
{
ShowSysLog("新連線一個客戶端。");
return new MyPeer(initRequest);
}
/// <summary>
/// 測試日誌
/// </summary>
public static void ShowTestLog(string s)
{
log.Debug("【======================Test======================】 " + s);
}
/// <summary>
/// 系統日誌
/// </summary>
/// <param name="s"></param>
public static void ShowSysLog(string s)
{
log.Debug("【System】 " + s);
}
/// <summary>
/// 錯誤日誌
/// </summary>
/// <param name="funcName"></param>
/// <param name="exc"></param>
public static void ShowErrorLog(string exc)
{
log.Debug("【>>>>>Error<<<<<】 " + exc);
}
}
}
伺服器和客戶端交流中心(繼承ClientPeer類)
舊版本(我們之前用的 v3-4-31-10808),這裡繼承PeerBase類
using System.Collections.Generic;
using Photon.SocketServer;
using PhotonHostRuntimeInterfaces;
namespace MyServer
{
public class MyPeer : ClientPeer
{
/// <summary>
/// 新連線的"客戶端物件"在伺服器端的"一一對應的物件"
/// </summary>
/// <param name="initRequest"></param>
public MyPeer(InitRequest initRequest) : base(initRequest) { }
/// <summary>
/// 客戶端斷開連線後,自動呼叫這裡
/// </summary>
protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
{
MyApplication.ShowSysLog("退出一個客戶端");
}
/// <summary>
/// 客戶端傳送訊息後,伺服器端在這裡接受
/// </summary>
protected override void OnOperationRequest(OperationRequest request, SendParameters sendParameters)
{
/* OperationResponse類的成員
* byte OperationCode: 命令程式碼,和要求時的命令代表相同,代表該要求的回傳值,該值自定義
* Dictionary<byte,object>Parameters: 回傳的內容,該值自定義
* short ReturnCode: 回傳狀態的值,該值自定義
* string DebugMessage: 回傳的日誌,該值自定義
*
* SendParameters類的成員
* byte ChannelId: 頻道,通常都用0頻道,除非特別需求否則不建議更改
* bool Encrypted: 是否加密,true為加密,預設為false
* bool Flush: 立即傳輸,會讓queue尚未傳送的往後延,預設為false
* bool Unreliable: 可靠傳輸,預設為true
*/
//從客戶端往伺服器發資料,用OperationRequest
//可以根據判斷request.OperationCode值,來處理不同型別的事件訊息
byte reqCode = request.OperationCode;
//客戶端傳來的值
Dictionary<byte, object> reqPara = request.Parameters;
switch (reqCode)
{
case 0:
object value1 = null;
reqPara.TryGetValue(0, out value1);
break;
case 1:
object value2 = null;
reqPara.TryGetValue(0, out value2);
break;
}
//從伺服器往客戶端發資料,用OperationResponse
OperationResponse response =new OperationResponse();
//回傳的命令Code和接收到的一致即可
response.OperationCode = request.OperationCode;
//這裡自定義格式,到了客戶端按照自定義的格式對應的讀取即可
response.Parameters = new Dictionary<byte, object>();
response.Parameters.Add(0, "值");
response.Parameters.Add(1, "值");
response.Parameters.Add(2, "值");
//回傳狀態的值
response.ReturnCode = 0;
//回傳日誌
response.DebugMessage = "這是我的回傳日誌。";
SendOperationResponse(response, sendParameters);
}
}
}
生成dll包,匯入Photon伺服器軟體中
選擇 生成 => 生成解決方案
(快捷鍵Ctrl+Shift+B)
生成的dll檔案預設路徑為:"…\bin\Debug"
當伺服器端寫好後,開啟之前下載的Photon SDK資料夾,“…\deploy”,並在此目錄下建立自己的伺服器端資料夾,把我們生成的MyServer.dll檔案複製貼上到該資料夾中
在Photon軟體中設定自己的伺服器
“…\deploy\bin_Win64\PhotonServer.config”
開啟PhotonServer.config檔案在"'Configuration"節點內新增
<Configuration>
//在這一層內新增下面一大段
//內容格式和原始檔已有設定檔案的一樣,把部分節點名字改成自己伺服器中對應的名字即可
</Configuration>
<MyServer
MaxMessageSize="512000"
MaxQueuedDataPerPeer="512000"
PerPeerMaxReliableDataInTransit="51200"
PerPeerTransmitRateLimitKBSec="256"
PerPeerTransmitRatePeriodMilliseconds="200"
MinimumTimeout="5000"
MaximumTimeout="30000"
DisplayName="MyServer">
<UDPListeners>
<UDPListener
IPAddress="0.0.0.0"
Port="5055">
</UDPListener>
</UDPListeners>
<TCPListeners>
<TCPListener
IPAddress="0.0.0.0"
Port="4530"
PolicyFile="Policy\assets\socket-policy.xml"
InactivityTimeout="10000"
>
</TCPListener>
</TCPListeners>
<PolicyFileListeners>
<PolicyFileListener
IPAddress="0.0.0.0"
Port="843"
PolicyFile="Policy\assets\socket-policy.xml">
</PolicyFileListener>
<PolicyFileListener
IPAddress="0.0.0.0"
Port="943"
PolicyFile="Policy\assets\socket-policy-silverlight.xml">
</PolicyFileListener>
</PolicyFileListeners>
<WebSocketListeners>
<WebSocketListener
IPAddress="0.0.0.0"
Port="9090"
DisableNagle="true"
InactivityTimeout="10000"
OverrideApplication="Master">
</WebSocketListener>
<WebSocketListener
IPAddress="0.0.0.0"
Port="9091"
DisableNagle="true"
InactivityTimeout="10000"
OverrideApplication="Game">
</WebSocketListener>
</WebSocketListeners>
<Runtime
Assembly="PhotonHostRuntime, Culture=neutral"
Type="PhotonHostRuntime.PhotonDomainManager"
UnhandledExceptionPolicy="Ignore">
</Runtime>
<Applications Default="MyServer">
<Application
Name="MyServer"
BaseDirectory="MyServer"
Assembly="MyServer"
Type="MyServer.MyApplication"
ForceAutoRestart="true"
WatchFiles="dll;config"
ExcludeFiles="log4net.config"
>
</Application>
<Application
Name="CounterPublisher"
BaseDirectory="CounterPublisher"
Assembly="CounterPublisher"
Type="Photon.CounterPublisher.Application"
ForceAutoRestart="true"
WatchFiles="dll;config"
ExcludeFiles="log4net.config">
</Application>
</Applications>
</MyServer>
開啟Photon伺服器軟體,並開啟自己的伺服器邏輯
開啟下面的應用程式
【application】可以用於Windows 普通系統:
開啟:Start as application
停止:Stop application
【service】可以用於Windows 普通系統 和 Windows Server系統
先安裝:Install service
開啟:Start service
重啟:Restart service
停止:Stop service
移除:Stop service
客戶端邏輯
Unity中匯入dll包
在自己的Unity客戶端專案中匯入Photon3Unity.dll
目錄:"…\lib"
Unity客戶端邏輯(繼承IPhotonPeerListener)
using UnityEngine;
using System.Collections.Generic;
using ExitGames.Client.Photon;
using System;
public class PhotonEngine : MonoBehaviour, IPhotonPeerListener
{
PhotonPeer peer;
void Awake()
{
//自己伺服器專案的名字
string serverName = "MyServer";
//伺服器軟體所在的電腦的Ip,區域網、廣域網皆可
string ip = "192.168.1.100";
//通訊協議:TCP為4530,Upd為5055
string port = "5055";
//伺服器請求地址
string serverAddr= ip + ":" + port;
ConnectionProtocol protocol;
//通訊協議,與埠號(port)必須保持一致
protocol = ConnectionProtocol.Tcp;
peer = new PhotonPeer(this, protocol);
//請求連線伺服器
peer.Connect(serverAddr, serverName);
}
/// <summary>
/// 實時與伺服器保持通訊
/// </summary>
void FixedUpdate()
{
if (peer != null)
{
peer.Service();
}
}
/// <summary>
/// 給伺服器傳送訊息
/// </summary>
public void SendRequest()
{
//傳送至伺服器的訊息的型別
byte opCode = 0;
//傳送至伺服器的訊息內容
Dictionary<byte, object> para = new Dictionary<byte, object>();
para.Add(0, "值1");
para.Add(1, "值2");
para.Add(2, "值3");
peer.SendOperation((byte)opCode, para, SendOptions.SendUnreliable);
}
/// <summary>
/// 伺服器傳回來的日誌,自定義的
/// </summary>
public void DebugReturn(DebugLevel level, string message)
{
Debug.Log(level + " : " + message);
}
/// <summary>
/// 服務端傳過來的事件,自定義的
/// </summary>
public void OnEvent(EventData eventData)
{
}
/// <summary>
/// 伺服器端傳回來的訊息,自定義的
/// </summary>
public void OnOperationResponse(OperationResponse operResq)
{
//伺服器傳送回來的訊息的型別code
//operResq.OperationCode
//伺服器傳送回來了的訊息內容字典,按照伺服器傳送的格式解析即可獲得
//operResq.Parameters
}
//連線狀態更改通知
public void OnStatusChanged(StatusCode statusCode)
{
switch (statusCode)
{
case StatusCode.Connect:
Debug.Log("連線伺服器成功");
break;
//case StatusCode.Disconnect:
default:
Debug.Log("與伺服器斷開連線");
break;
}
}
}