MMORPG大型游戏设计与开发(part6 of net)

上一部分,讲述了一个服务器与服务器之间的通信实例,客户端其实原理大同小异。网络部分准备就暂时讲到这里,不过我们不妨再回头过来想想在这过程中有没有优化和改进的地方。这部分讲解的是以网络包代码作分析,实现自动生成其代码的功能。

网络包代码

/**

 * PAP Engine ( -- )

 * $Id connect.h

 * @link -- for the canonical source repository

 * @copyright Copyright (c) 2013-2013 viticm( [email protected] )

 * @license

 * @user viticm<[email protected]>

 * @date 2014-01-16 17:20:14

 * @uses packet Connect class

 */

#ifndef PAP_SERVER_COMMON_NET_PACKETS_SERVERSERVER_CONNECT_H_

#define PAP_SERVER_COMMON_NET_PACKETS_SERVERSERVER_CONNECT_H_



#include "server/common/net/config.h"

#include "server/common/net/connection/base.h"

#include "common/net/packet/base.h"

#include "common/net/packet/factory.h"

#include "server/common/game/define/all.h"





namespace pap_server_common_net {



namespace packets {



namespace serverserver {



class Connect : public pap_common_net::packet::Base {



 public:

   Connect();

   virtual ~Connect() {};



 public:  

   virtual bool read(pap_common_net::socket::InputStream& inputstream);

   virtual bool write(pap_common_net::socket::OutputStream& outputstream) const;

   virtual uint32_t execute(connection::Base* connection);

   virtual uint16_t getid() const;

   virtual uint32_t getsize() const;

   

 public: 

   int16_t get_serverid();

   void set_serverid(int16_t serverid);

   int16_t get_worldid();

   void set_worldid(int16_t worldid);

   int16_t get_zoneid();

   void set_zoneid(int16_t zoneid);



 private:

   int16_t serverid_; //服务器ID

   int16_t worldid_; //世界ID

   int16_t zoneid_; //区域ID



};



class ConnectFactory : public pap_common_net::packet::Factory {



 public:

   pap_common_net::packet::Base* createpacket();

   uint16_t get_packetid() const;

   uint32_t get_packet_maxsize() const;



};



class ConnectHandler {



 public:

   static uint32_t execute(Connect* packet, 

                           connection::Base* connection);



};



}; //namespace serverserver



}; //namespace packets



}; //namespace pap_server_common_net



#endif //PAP_SERVER_COMMON_NET_PACKETS_SERVERSERVER_CONNECT_H_
#include "server/common/net/packets/serverserver/connect.h"



namespace pap_server_common_net {



namespace packets {



namespace serverserver {



Connect::Connect() {

  __ENTER_FUNCTION

  __LEAVE_FUNCTION

}



bool Connect::read(pap_common_net::socket::InputStream& inputstream) {

  __ENTER_FUNCTION

    inputstream.read((char*)(&serverid_), sizeof(serverid_));

    inputstream.read((char*)(&worldid_), sizeof(worldid_));

    inputstream.read((char*)(&zoneid_), sizeof(zoneid_));

  __LEAVE_FUNCTION

    return false;

}



bool Connect::write(pap_common_net::socket::OutputStream& outputstream) const {

  __ENTER_FUNCTION

    outputstream.write((char*)(&serverid_), sizeof(serverid_));

    outputstream.write((char*)(&worldid_), sizeof(worldid_));

    outputstream.write((char*)(&zoneid_), sizeof(zoneid_));

  __LEAVE_FUNCTION

    return false;

}



uint32_t Connect::execute(connection::Base* connection) {

  __ENTER_FUNCTION

    uint32_t result = 0;

    result = ConnectHandler::execute(this, connection);

    return result;

  __LEAVE_FUNCTION

    return 0;

}



uint16_t Connect::getid() const {

  using namespace pap_server_common_game::define;

  return id::packet::serverserver::kConnect;

}



uint32_t Connect::getsize() const {

  uint32_t result = sizeof(serverid_) +

                    sizeof(worldid_) +

                    sizeof(zoneid_);

  return result;

}



int16_t Connect::get_serverid() {

  return serverid_;

}

void Connect::set_serverid(int16_t serverid) {

  serverid_ = serverid;

}

int16_t Connect::get_worldid() {

  return worldid_;

}

void Connect::set_worldid(int16_t worldid) {

  worldid_ = worldid;

}

int16_t Connect::get_zoneid() {

  return zoneid_;

}

void Connect::set_zoneid(int16_t zoneid) {

  zoneid_ = zoneid;

}



pap_common_net::packet::Base* ConnectFactory::createpacket() {

  __ENTER_FUNCTION

    return new Connect();

  __LEAVE_FUNCTION

    return NULL;

}



uint16_t ConnectFactory::get_packetid() const {

  using namespace pap_server_common_game::define;

  return id::packet::serverserver::kConnect;

}



uint32_t ConnectFactory::get_packet_maxsize() const {

  uint32_t result = sizeof(int16_t) +

                    sizeof(int16_t) +

                    sizeof(int16_t);

  return result;

}



} //namespace serverserver



} //namespace packets



} //namespace pap_server_common_net

  这个网络包代码,即是上一部分服务器连接服务器的包,其他网络包都大同小异。所以我们不妨实现一个代码自动实现的工具,让大部分的代码通过工具自动实现。因为网络包在编程中可能会根据不同的游戏非常的多,有了这样的工具那么我们开发时间和精力上就不必费事了。

网络包文本

/** 注释行 可以用来描述该文件的作用 **/

/* author: viticm */

/* date: 2014-1-16 10:36:39 */

/* desc: 服务器与服务器之间的连接包 */



ModelType: Server /* Server 服务器专用 Common 客户端与服务器公用 */

ModelName: serverserver /* 模块名 */

PacketName: Connect /* 包名 将作为类名使用 */

FileName: connect /* 文件名 */

/* 0 不用包含 1 服务器与公用 2 服务器 3 公用 --包括定义文件define/all.h

 * 服务器为pap_server_game_common::define 公用为pap_game_common::define

 */ 

IncludeDefineFile: 2



 

/* 数据名称将作为变量名,数据类型可用c99所有整型以及字符和数组,不允许使用指针 

   不使用指针的原因是在32位与64位之间长度大小有区别

 */

/** 

[数据名称] [数据类型] [长度] [描述?]

如果长度为0,对于字符和float等来说就只是单纯的字符或者float,

否则为对应的数组,多维数组以逗号分开。

多维数组的示例:[account] [char] [10,20] 

长度可以为数字也可以为相应的宏或者枚举,不过你要确保它的存在

描述将作为注释生成在头文件中如 uint16_t playerid_; //玩家ID,描述可以为空

**/



/*packet define begin {*/ 

[serverid] [int16_t] [0] [服务器ID]

[worldid] [int16_t] [0] [世界ID]

[zoneid] [int16_t] [0] [区域ID]

/*packet define end }*/

  有了这样的文本,我们就可以用工具实现上面的代码。

工具

<?php

include_once '../include/base.php';



// $packetcode = new PacketCode();



// $codecontent = file_get_contents('example_packetcode.txt');

// $packetcode->get_formatcode($codecontent);

// $packetcode->create_codefile();



/**

 * 从目录生成包的代码

 * @param string $indir

 * @param string $outdir

 */

function createcode_fromdir($indir = NULL, $outdir = NULL) {

  if (NULL == $indir || NULL == $outdir) return false;

  $starttime = time();

  $totalfile = 0;

  $successfile = 0;

  $formatcode_files = glob($indir.'*.txt');

  $totalfile = count($formatcode_files);

  if (0 === $totalfile) return false;

  $packetcode = new PacketCode();

  foreach ($formatcode_files as $file) {

    $codecontent = file_get_contents($file);

    $packetcode->get_formatcode($codecontent);

    $result = $packetcode->create_codefile($outdir);

    if (true === $result) ++$successfile;

  }

  $endtime = time();

  echo 'create code completed, use time: ',$endtime - $starttime,'s',LF;

  echo 'toalfile: ',$totalfile,' success file: ',$successfile,LF;

  unset($packetcode);

}



/**

 * enter function

 * @param void

 * @return void

 */

function main() {

  $argc = $GLOBALS['argc'];

  $argv = $GLOBALS['argv'];

  $outputdir = './packet/code';

  $indir = './packet/txt';

  if (3 === $argc) {

    list($indir, $outputdir) = $argv;

  }

  createcode_fromdir(complementpath($indir), complementpath($outputdir));

}



main();

  这是主代码,使用PHP实现,大家不妨用其他语言实现也可。

你可能感兴趣的:(part)