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


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

    网络包代码

    复制代码
    /**
     * PAP Engine ( -- )
     * $Id connect.h
     * @link -- for the canonical source repository
     * @copyright Copyright (c) 2013-2013 viticm( viticm@126.com )
     * @license
     * @user viticm<viticm@126.com>
     * @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实现,大家不妨用其他语言实现也可。

  • 相关阅读:
    【YbtOJ#20064】预算缩减
    【GMOJ6805】模拟speike
    【洛谷P5675】取石子游戏
    【YbtOJ#20061】波动序列
    【洛谷P4302】字符串折叠
    flash 上传文件
    HTTP 客户端发送的 头 格式
    FLEX 在本地使用 只访问本地文件
    as3 重写
    iis7 上传限制问题
  • 原文地址:https://www.cnblogs.com/liuzhi/p/4084575.html
Copyright © 2020-2023  润新知