1. 程式人生 > >【PhotonEngine 學習筆記】(一)簡單使用

【PhotonEngine 學習筆記】(一)簡單使用

【PhotonEngine 學習筆記】(一)簡單使用


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(我們主要說這個):自主新增伺服器邏輯的
Photon SDKs

SDK:SELF-HOSTED

SELF-HOSTED

下載安裝

下載並安裝,得到以下資料夾
本地Server

依次開啟:…\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;
        }
    }
}