程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 【FOL】第九周,fol第九周

【FOL】第九周,fol第九周

編輯:Delphi

【FOL】第九周,fol第九周


不知不覺又是三周過去了。

這幾周忙了一下,其他時間全都在搞服務端,簡直是酸爽的不行。。。不過還好出了些成果。

目前服務端有:

1、版本服務:游戲版本更新

2、賬號服務:用戶身份驗證,返回各種連接(代理服務、聊天服務)

3、代理服務:獲取游服列表、獲取游服狀態(是否需要排隊)、進入游戲的驗證、游服數據轉發

4、隊列服務:處理排隊隊列中用戶的隊列情況變化,並廣播(本來這個是放在代理服務器上做的,但是我覺得廣播起來有點惡心就分出來了,看起來各個服務的功能也清晰些)

5、游戲服務:游戲業務邏輯處理(作為1-n個特殊的客戶端連接到代理服務器)

6、聊天服務

客戶端方面,優化了一些網絡通訊方面的代碼,把各種消息重新整理了一遍。界面表現方面幾乎沒動過。

整個框架基本上實現了登錄、選服、排隊(等待、結束)、進入游戲、聊天。

 

想了一下,還是放段代碼。

unit gate.handler;

interface

uses
  System.SysUtils, System.Classes, System.Math, diocp_coder_tcpServer,
  diocp_tcp_server, fol.msgcode, fol.types, fol.simpleMsgPack,
  fol.server.types, fol.server.session, gate.session, gate.cache;

procedure pushMsgData(pvMsgData: TSimpleMsgPack; pvContext: TIocpClientContext);
procedure execHeart(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext);
procedure execOffline(pvContext: TIOCPCoderClientContext);

function execRequest(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
function execRegister(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
function execRegisterGameServiceClient(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): string;
function execRequestServerList(pvMsgData: TSimpleMsgPack): Integer;
function execRequestServerState(const pvServerID: Integer; pvMsgData: TSimpleMsgPack): Integer;
function execRequestStartGame(const pvServerID,pvUserID: Integer;
  pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
function execRequestGameService(pvMsgData: TSimpleMsgPack): Integer;
function execTranspond(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;

implementation

uses utils_safeLogger;

procedure pushMsgData(pvMsgData: TSimpleMsgPack; pvContext: TIocpClientContext);
var
  lvStream: TMemoryStream;
begin
  lvStream:= TMemoryStream.Create;
  try
    if Assigned(pvContext) then
    begin
      pvMsgData.Add('result',MSG_RESULT_Success);
      pvMsgData.EncodeToStream(lvStream);
      lvStream.Position:= 0;
      TIOCPCoderClientContext(pvContext).WriteObject(lvStream);
    end;
  finally
    lvStream.Free;
  end;
end;

procedure execHeart(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext);
begin
  if pvContext.LockContext('keeplive', nil) then
  try
    gvSessionManager.validChecked(pvContext);
    pvMsgData.Clear;
  finally
    pvContext.UnLockContext('keeplive', nil);
  end;
end;

procedure execOffline(pvContext: TIOCPCoderClientContext);
var
  lvServerID: Integer;
  lvUserID, lvServerKey: string;
begin
  if pvContext.Data <> nil then
  begin
    {
       1. 游戲客戶端: 只是連接了代理服務器,並未選服登錄游戲 (斷開不需要處理)
       2. 游戲客戶端: 已經進入游戲的,斷開需要更新對應服務器freenum
       3. OM工具: 斷開不需要處理
       4. 游戲服務: 斷開需要把游服記錄刪除(或者更新state)
    }
    lvServerID:= TClientSession(pvContext.Data).ServerID;
    lvUserID:= TClientSession(pvContext.Data).SessionID;
    case TClientSession(pvContext.Data).ClientType of
      tfctGameClient:
        begin
          sfLogger.logMessage('[INFO]: Client offline, serverid='+inttostr(lvServerID));
          if lvServerID = 0 then exit;
          //更新freenum(freenum+1)
          sfLogger.logMessage('[INFO]: Client offline, userid='+lvUserID);
          lvServerKey:= Format('server:%.3d',[lvServerID]);
          redisClient.HINCRBY(lvServerKey,'freenum',1);
          //kickOut這個session(或者設置為無效session)
          gvSessionManager.kickOutGameClient(lvUserID);
        end;
      tfctGameServiceClient:
        begin
          //更新游服列表
          lvServerKey:= Format('server:%.3d',[StrToInt(lvUserID)]);
          redisClient.DEL([lvServerKey]);
          gvSessionManager.kickOutGameService(lvUserID);
        end;
      tfctOMClient:
        begin
          sfLogger.logMessage('[INFO]: OMClient offline');
          gvSessionManager.kickOutOMClient(lvUserID);
        end;
    end;
  end;
end;

function execRegister(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvClientType: Integer;
  lvSessionID: string;
begin
  if pvContext.LockContext('register', nil) then
  try
    lvClientType:= pvMsgData.I['client_type'];
    case lvClientType of
      ord(tfctGameClient):
        lvSessionID:= gvSessionManager.takeAGameClientSession(pvContext, pvMsgData.S['client_id']);
      ord(tfctGameServiceClient):
        lvSessionID:= execRegisterGameServiceClient(pvMsgData, pvContext);
      ord(tfctOMClient):
        lvSessionID:= gvSessionManager.takeAOMClientSession(pvContext, pvMsgData.S['client_id']);
    end;
    pvMsgData.Clear;
    pvMsgData.S['token']:= '(gate)token_'+lvSessionID;
    result:= MSG_RESULT_Success;
  finally
    pvContext.UnLockContext('register', nil);
  end;
end;

function execRegisterGameServiceClient(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): string;
var
  lvServiceID, lvServiceName, lvServerKey, lvMaxConn: string;
begin
  lvServiceID:= pvMsgData.S['client_id'];
  lvServiceName:= pvMsgData.S['client_name'];
  lvMaxConn:= pvMsgData.S['client_maxconn'];
  result:= gvSessionManager.takeAGameServiceSession(pvContext,lvServiceID);

  //example: hmset server:001 name 五行之始 state 1 freenum 1000
  lvServerKey:= Format('server:%.3d',[StrToInt(lvServiceID)]);
  redisClient.HMSET(lvServerKey,['name','state','freenum'],[lvServiceName,'0',lvMaxConn]);
end;

function execRequest(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvMsgcode, lvCallbackID, lvServerID, lvUserID: Integer;
begin
  lvMsgcode:= pvMsgData.I['msg_code'];
  lvCallbackID:= pvMsgData.I['callbackid'];
  sfLogger.logMessage('[INFO]: Receive a message package, msgcode=' + inttostr(lvMsgcode));
  case lvMsgcode of
    MSG_NET_Register: result:= execRegister(pvMsgData, pvContext);
    MSG_NET_GetServerList:
      begin
        pvMsgData.Clear;
        result:= execRequestServerList(pvMsgData);
      end;
    MSG_NET_GetServerState:
      begin
        lvServerID:= pvMsgData.I['serverid'];
        pvMsgData.Clear;
        result:= execRequestServerState(lvServerID,pvMsgData);
      end;
    MSG_NET_StartGame:
      begin
        lvServerID:= pvMsgData.I['serverid'];
        lvUserID:= pvMsgData.I['userid'];
        pvMsgData.Clear;
        result:= execRequestStartGame(lvServerID,lvUserID,pvMsgData,pvContext);
      end;
    else
      begin
        execRequestGameService(pvMsgData);
        pvMsgData.Clear;
        exit;
      end;
  end;
  pvMsgData.Add('callbackid', lvCallbackID);
end;

function execRequestServerList(pvMsgData: TSimpleMsgPack): Integer;
var
  i: Integer;
  lvServerKey: string;
  lvData: TArray<string>;
begin
  for i:= 1 to 999 do
  begin
    lvServerKey:= Format('server:%.3d',[i]);
    lvData:= redisClient.HMGET(lvServerKey, ['name', 'state']);
    if (Length(lvData)=0) or (lvData[0]='') then break;
    pvMsgData.Add(lvData[0], StrToInt(lvData[1]));
  end;
  result:= MSG_RESULT_Success;
end;

function execRequestServerState(const pvServerID: Integer; pvMsgData: TSimpleMsgPack): Integer;
var
  lvServerKey: string;
  lvFreeNum: Integer;
begin
  lvServerKey:= Format('server:%.3d',[pvServerID]);
  redisClient.HGET(lvServerKey,'freenum',lvFreeNum);
  case lvFreeNum of
    0: result:= MSG_RESULT_Queue;
   -1: raise exception.Create('invalid freenum.');
    else result:= MSG_RESULT_Success;
  end;
end;

function execRequestStartGame(const pvServerID,pvUserID: Integer;
  pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvServerKey, lvQueueKey: string;
  lvFreeNum, lvState: Integer;
begin
  if pvContext.Data <> nil then
  begin
    lvServerKey:= Format('server:%.3d',[pvServerID]);
    redisClient.HGET(lvServerKey,'state',lvState);
    if lvState <> 0 then raise Exception.Create('Service is Closed.');
    redisClient.HGET(lvServerKey,'freenum',lvFreeNum);
    if lvFreeNum <= 0 then raise Exception.Create('Invalid request, free num is zero.');
    //
    TClientSession(pvContext.Data).ServerID:= pvServerID;
    TClientSession(pvContext.Data).State:= tusOnline;
    //更新freenum(freenum-1)
    lvFreeNum:= Max(lvFreeNum - 1,0);
    redisClient.HSET(lvServerKey,'freenum',lvFreeNum);
    //廣播上線消息給好友
  end;
  result:= MSG_RESULT_Success;
end;

function execRequestGameService(pvMsgData: TSimpleMsgPack): Integer;
var
  lvServerID: string;
  lvContext: TIocpClientContext;
begin
  lvServerID:= IntToStr(pvMsgData.I['serverid']);
  lvContext:= gvSessionManager.findGameServiceContext(lvServerID);
  pushMsgData(pvMsgData,lvContext);
end;

function execTranspond(pvMsgData: TSimpleMsgPack; pvContext: TIOCPCoderClientContext): Integer;
var
  lvUserID: string;
  lvContext: TIocpClientContext;
begin
  lvUserID:= pvMsgData.S['userid'];
  lvContext:= gvSessionManager.findGameClientContext(lvUserID);
  pushMsgData(pvMsgData,lvContext);
end;

end.

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved