Photon Server を使用した MMO 開発に関する Christian Richards のチュートリアルに従っています。それが何であるかを知らない人のために説明すると、MMO タイプのアーキテクチャを使用して、フォトン フレームワークをゼロから書き直すことを本質的にカバーしています。回避策または修正を見つけた多くの問題に遭遇しましたが、このエラーには困惑しています。サーバーが起動し、プロキシ サーバーとログイン サーバーをロードした後、次のエラーが発生します。サーバーは正常に起動し、正常に検索されますが、サブサーバーを登録しようとするとすぐに、プロキシ ログにこのエラーがスローされます。
プロキシ サーバー ログ:
2015-07-22 14:56:10,892 [1] INFO Photon.SocketServer.ApplicationBase [(null)] アプリケーション停止: AppId=Proxy
2015-07-22 14:57:01,913 [1] INFO Photon.SocketServer.ApplicationBase [(null)] - アプリケーションの開始: AppId=Proxy; AppPath=C:\Photon\deploy\ComplexServer、タイプ=ComplexServer.ComplexProxyServer
2015-07-22 14:57:01,968 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - AverageCounter の作成: Name=''
2015-07-22 14:57:01,977 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - NumericCounter の作成: Name=''
2015-07-22 14:57:01,986 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:01,993 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:02,001 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - NumericCounter の作成: Name=''
2015-07-22 14:57:02,008 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:02,017 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - NumericCounter の作成: Name=''
2015-07-22 14:57:02,026 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:02,035 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:02,043 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - NumericCounter の作成: Name=''
2015-07-22 14:57:02,051 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:02,058 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - CountsPerSecondCounter の作成: Name=''
2015-07-22 14:57:02,066 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - NumericCounter の作成: Name=''
2015-07-22 14:57:02,084 [13] DEBUG Photon.SocketServer.ApplicationBase [(null)] - OnInit - ConnID=2、ポート 4520 の IP 127.0.0.1、タイプ = TCPListener
2015-07-22 14:57:02,108 [13] DEBUG Photon.SocketServer.Protocol [(null)] - アプリケーション マスター、クライアント バージョン 3.0.5、プロトコル GpBinaryV2 バージョン 1.6 の解析済み初期化メッセージ
2015-07-22 14:57:02,120 [11] DEBUG MMO.Photon.Application.PhotonConnectionCollection [(null)] - 初期化リクエストを受信しました 127.0.0.1:4520 - Photon.SocketServer.InitRequest
2015-07-22 14:57:02,127 [11] DEBUG MMO.Photon.Application.PhotonApplication [(null)] - サブサーバーからの初期化要求を受け取りました
2015-07-22 14:57:02,154 [11] DEBUG Photon.SocketServer.ApplicationBase [(null)] - OnInit - SendResult Ok で ConnId 2 に送信された応答
2015-07-22 14:57:02,331 [7] エラー Photon.SocketServer.ApplicationBase [(null)] - System.NotImplementedException: メソッドまたは操作が実装されていません。MMO.Photon.Application.PhotonRequest.MMO.Framework.IMessage.get_Code() c:\Programming\SoftwareDevelopment\C#\MMO\MMO.Photon\Application\PhotonRequest.cs:line 48 at MMO.Photon.Server.PhotonServerHandlerList .HandleMessage(IMessageメッセージ、PhotonServerPeerピア) c:\Programming\SoftwareDevelopment\C#\MMO\MMO.Photon\Server\PhotonServerHandlerList.cs:MMO.Photon.Server.PhotonServerPeer.OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)の140行目c:\Programming\SoftwareDevelopment\C#\MMO\MMO.Photon\Server\PhotonServerPeer.cs:36行目 Photon.SocketServer.ServerToServer.ServerPeerBase.OnReceiveInternal(Byte[] data,
*ご覧のとおり、サブサーバーを登録しようとするまで、初期化応答/要求をメインサーバーとログインに適切に送信します。以下の Login.log を観察し、「サブ サーバーの登録」のタイム スタンプを比較すると、ログイン サーバーがサブ サーバーの登録を試みてからほぼ 1 秒後に上記の例外がスローされることがわかります。
2015-07-22 14:56:10,845 [1] INFO Photon.SocketServer.ApplicationBase [(null)] - アプリケーション停止: AppId=Login 2015-07-22 14:57:01,541 [12] DEBUG Photon.SocketServer.ServerToServer .TemporaryServerPeer [(null)] - OnOutboundConnectionEstablished: 初期化要求の送信 2015-07-22 14:57:01,541 [1] DEBUG MMO.Photon.Application.PhotonApplication [(null)] - 127.0.0.1:4520 2015 でのマスターへの接続-07-22 14:57:01,584 [1] INFO Photon.SocketServer.ApplicationBase [(null)] - アプリケーションの開始: AppId=Login; AppPath=C:\Photon\deploy\ComplexServer, Type=LoginServer.LoginServer 2015-07-22 14:57:01,592 [12] DEBUG Photon.SocketServer.ServerToServer.TemporaryServerPeer [(null)] - SentInitRequest: ConnID=2, ChannelId =0, result=Ok サイズ=41 バイト 2015-07-22 14:57:02,157 [13] DEBUG ExitGames.Diagnostics.Counter.CounterBase [(null)] - AverageCounter の作成:
次のコードは、関連するクラスと思われるものからのものです。
PhotonRequest クラス:
class PhotonRequest : IMessage
{
private readonly byte _code;
private readonly Dictionary<byte, object> _parameters;
private readonly int? _subCode;
public PhotonRequest(byte code, int? subCode, Dictionary<byte, object> parameters)
{
_code = code;
_parameters = parameters;
_subCode = subCode;
}
public short Code
{
get { return _code; }
}
public MessageType Type
{
get { return MessageType.Response; }
}
public int? SubCode
{
get { return _subCode; }
}
public Dictionary<byte, object> Parameters
{
get { return _parameters; }
}
byte IMessage.Code
{
get { throw new NotImplementedException(); }
}
}
PhotonServerHandlerList クラス:
public class PhotonServerHandlerList
{
private readonly DefaultRequestHandler _defaultRequestHandler;
private readonly DefaultResponseHandler _defaultResponseHandler;
private DefaultEventHandler _defaultEventHandler;
protected readonly ILogger Log;
private readonly Dictionary<int, PhotonServerHandler> _requestHandlerList;
private readonly Dictionary<int, PhotonServerHandler> _responseHandlerList;
private readonly Dictionary<int, PhotonServerHandler> _eventHandlerList;
public PhotonServerHandlerList(IEnumerable<IHandler<PhotonServerPeer>> handlers,
DefaultRequestHandler defaultRequestHandler, DefaultResponseHandler defaultResponseHandler,
DefaultEventHandler defaultEventHandler, PhotonApplication application)
{
_defaultRequestHandler = defaultRequestHandler;
_defaultResponseHandler = defaultResponseHandler;
_defaultEventHandler = defaultEventHandler;
Log = application.Log;
_requestHandlerList = new Dictionary<int, PhotonServerHandler>();
_responseHandlerList = new Dictionary<int, PhotonServerHandler>();
_eventHandlerList = new Dictionary<int, PhotonServerHandler>();
foreach (PhotonServerHandler handler in handlers)
{
if(!RegisterHandler(handler))
{
Log.WarnFormat("attempted to register handler {0} for type{1}|{2}", handler.GetType().Name, handler.Type, handler.Code);
}
}
}
public bool RegisterHandler(PhotonServerHandler handler)
{
var registered = false;
if((handler.Type & MessageType.Request) == MessageType.Request)
{
if (handler.SubCode.HasValue && !_requestHandlerList.ContainsKey(handler.SubCode.Value))
{
_requestHandlerList.Add(handler.SubCode.Value, handler);
registered = true;
}
else if (!_requestHandlerList.ContainsKey(handler.Code))
{
_requestHandlerList.Add(handler.Code, handler);
registered = true;
}
else
{
Log.ErrorFormat("RequestHandler list already contains handler for {0} - cannot add {1}", handler.Code, handler.GetType().Name);
}
}
if ((handler.Type & MessageType.Response) == MessageType.Response)
{
if (handler.SubCode.HasValue && !_responseHandlerList.ContainsKey(handler.SubCode.Value))
{
_responseHandlerList.Add(handler.SubCode.Value, handler);
registered = true;
}
else if (!_responseHandlerList.ContainsKey(handler.Code))
{
_responseHandlerList.Add(handler.Code, handler);
registered = true;
}
else
{
Log.ErrorFormat("Response Handler list already contains handler for {0} - cannot add {1}", handler.Code, handler.GetType().Name);
}
}
if ((handler.Type & MessageType.Async) == MessageType.Async)
{
if (handler.SubCode.HasValue && !_eventHandlerList.ContainsKey(handler.SubCode.Value))
{
_eventHandlerList.Add(handler.SubCode.Value, handler);
registered = true;
}
else if (!_eventHandlerList.ContainsKey(handler.Code))
{
_eventHandlerList.Add(handler.Code, handler);
registered = true;
}
else
{
Log.ErrorFormat("event Handler list already contains handler for {0} - cannot add {1}", handler.Code, handler.GetType().Name);
}
}
return registered;
}
public bool HandleMessage(IMessage message, PhotonServerPeer peer)
{
bool handled = false;
switch (message.Type)
{
case MessageType.Request:
if (message.SubCode.HasValue && _requestHandlerList.ContainsKey(message.SubCode.Value))
{
_requestHandlerList[message.SubCode.Value].HandleMessage(message, peer);
handled = true;
}
else if (!message.SubCode.HasValue && _requestHandlerList.ContainsKey(message.Code))
{
_requestHandlerList[message.Code].HandleMessage(message, peer);
handled = true;
}
else
{
_defaultRequestHandler.HandleMessage(message, peer);
}
break;
case MessageType.Response:
if (message.SubCode.HasValue && _responseHandlerList.ContainsKey(message.SubCode.Value))
{
_responseHandlerList[message.SubCode.Value].HandleMessage(message, peer);
handled = true;
}
else if (!message.SubCode.HasValue && _responseHandlerList.ContainsKey(message.Code))
{
_responseHandlerList[message.Code].HandleMessage(message, peer);
handled = true;
}
else
{
_defaultResponseHandler.HandleMessage(message, peer);
}
break;
case MessageType.Async:
if (message.SubCode.HasValue && _eventHandlerList.ContainsKey(message.SubCode.Value))
{
_eventHandlerList[message.SubCode.Value].HandleMessage(message, peer);
handled = true;
}
else if (!message.SubCode.HasValue && _eventHandlerList.ContainsKey(message.Code))
{
_eventHandlerList[message.Code].HandleMessage(message, peer);
handled = true;
}
else
{
_defaultEventHandler.HandleMessage(message, peer);
}
break;
}
return handled;
}
}
IMessage インターフェイス:
public interface IMessage
{
MessageType Type { get; }
byte Code { get; }
int? SubCode { get; } // nullable int
Dictionary<byte, object> Parameters { get; }
}