3 - C++ Development of "Fight the Landlord" - Detailed Analysis of the Backend & (CORE)

This article will analyze the code file structure and each code file in sequence

Directory structure

图片.png

  • Core functions
  • entity: entity class
  • Game: Game
  • module: functional module
  • network: Network
  • service: Independent service
  • utils: Tools

All Files

图片.png图片.png图片.png图片.png图片.png图片.png

【core】kernel directory

ConfigManager

Translation: Through the header file, it is evident that this class maintains a ylib::json variable named m_config, which is used to obtain information about paths, directories, MySQL connection details, and server listening information.

It can be observed that this class is implemented using the singleton pattern. It inherits from the ylib::singleton class to achieve the singleton pattern, and the rest of the Manager classes follow the same approach.

#pragma once
#include "ybase/error.h"
#include "ybase/singleton.hpp"
#include "yutil/json.h"
#include "ymysql/mysql_plus.h"
class ConfigManager:public ylib::error_base,public ylib::singleton<ConfigManager>
{
    friend class ylib::singleton<ConfigManager>;
public:
    enum PathType
    {
        PT_CONFIG,
    };
    enum DirType
    {
        DT_RES,
    };
public:
    
    bool start();
    void stop();

    std::string path(PathType type);
    std::string dir(DirType type);
    
    const mysql::mysql_conn_info& mysqlConnInfo() { return m_conn_info; }
    const ylib::AddressPort& serverListen() { return m_server_listen; }

private:
    bool save();
    ConfigManager() = default;
private:
    bool m_ok = false;
    ylib::json m_config;

    // MYSQL连接信息
    mysql::mysql_conn_info m_conn_info;
    // TCP服务监听信息
    ylib::AddressPort m_server_listen;
};

define:宏定义与提前声明

<pre class="prism-highlight prism-language-cpp">#pragma once
#include "ybase/define.h"
#include "yutil/json.h"
#include "utils/logutils.h"
#include "common.h"
#define LOG_ERROR(MSG) LogUtils::error(MSG)
#define LOG_WARN(MSG) LogUtils::warn(MSG)
#define LOG_INFO(MSG) LogUtils::info(MSG)

// SQL数据库池
#define SQLPOOL ylib::env->to<mysql::pool>("mysql_pool")
// 房间玩家
#define ROOM_PLAYER std::array<uint64,3>

HandleCenter:数据处理中心

用于处理分发网络数据包和维护项目内部定时器功能,其内部维护一个线程,该线程即为游戏主线程

<pre class="prism-highlight prism-language-cpp">#pragma once
#include <string>
#include <functional>
#include "define.h"
#include "yutil/thread.h"
#include "yutil/queue.hpp"
#include "yutil/counter.hpp"
#include "ybase/singleton.hpp"
// 处理中心
class HandleCenter:private ithread,public ylib::singleton<HandleCenter>{
    friend class ylib::singleton<HandleCenter>;
private:
    // 包
    struct Package {
        // 连接FD
        uint64 fd = 0;
        //    玩家ID
        uint64 player_id = 0;
        // JSON数据
        ylib::json data;
    };
    // 定时器
    struct Timer {
        // 仅一次
        bool once = false;
        // 间隔
        uint32 interval_msec = 0;
        // 回调函数
        std::function<void()> callback;
        // 回调时间
        timestamp call_msec = 0;
        // ID
        uint32 id = 0;
    };
public:
    /// <summary>
    /// 启动
    /// </summary>
    void start();
    /// <summary>
    /// 停止
    /// </summary>
    void stop();
    /// <summary>
    /// 置入接收数据
    /// </summary>
    /// <param name="fd">连接ID</param>
    /// <param name="player_id">玩家ID</param>
    /// <param name="data">数据指针</param>
    /// <param name="length">数据长度</param>
    void push(uint64 fd, uint64 player_id,const char* data,uint32 length);
    /// <summary>
    /// 置入内部服务
    /// </summary>
    /// <param name="data"></param>
    void pushInternal(c2s::InternalAction action,const ylib::json& data);
    /// <summary>
    /// 置入定时器
    /// </summary>
    /// <param name="once"></param>
    /// <param name="interval_msec"></param>
    /// <param name="callback"></param>
    /// <returns>定时器ID</returns>
    uint32 push_timer(bool once,uint32 interval_msec,std::function<void()> callback);
    void remove_timer(uint32 id);
private:
    HandleCenter();
    /// <summary>
    /// 处理数据包队列
    /// </summary>
    void handlePackageQueue();
    /// <summary>
    /// 处理定时器列表
    /// </summary>
    void handleTimerList();
    // 通过 ithread 继承
    bool run() override;
private:
    // 数据包队列
    ylib::queue<Package> m_queue;
    // 定时器队列
    std::list<Timer> m_timer;
    std::mutex m_timer_lock;
    ylib::counter<uint32> m_timer_idx;
};

iservice:服务父类

所有内部服务均需继承该类,并支持TYPE+ACTION的两级命令分发功能,设计理念是:N个服务对应1个TYPE(也可一对一),一个函数对应一个ACTION

<pre class="prism-highlight prism-language-cpp">#pragma once
#include <string>
#include <functional>
#include "define.h"
#include "network/request.h"
#include "ybase/environment.h"
#define REQUEST_CALLBACK std::function<void(Request&)>
class IService{
public:
    IService(int type, const std::string& name,bool haveLogined = true);
    ~IService();
    const std::string& name() { return m_name; }
    template<typename T>
    T type() { return (T)m_type; }
    bool haveLogined() { return m_haveLogined; }
protected:
    void regist(int action, REQUEST_CALLBACK callback);
protected:
    // 服务名
    std::string m_name;
    // 类型
    int m_type = -1;
    // 需要登录
    bool m_haveLogined = true;
};

main:初始化入口

初始化网络服务、数据库、其它自定义服务等

<pre class="prism-highlight prism-language-cpp">#include <iostream>


#include "ybase/environment.h"
#include "define.h"
#include "handlecenter.h"
#include "utils/utils.h"
#include "servicemanager.h"
#include "configmanager.h"
#include "network/server.h"
#include "service/user/user.h"
#include "service/user/user_ns.h"
#include "service/server_internal/internal.h"
#include "service/game/game.h"


#include "game/playermanager.h"
#include "game/roomqueue.h"
#include "game/room/roommanager.h"
void initMysql()
{
    ylib::env->set<mysql::pool>("mysql_pool", new mysql::pool());


    if (SQLPOOL->start(ConfigManager::getInstance()->mysqlConnInfo(),10) == false)
    {
        LOG_ERROR("mysql init failed,"+SQLPOOL->last_error());
        abort();
    }
    try
    {
        // 测试连接
        auto conn = SQLPOOL->get();
        if (conn == nullptr) {
            LOG_ERROR("mysql test failed," + SQLPOOL->last_error());
            abort();
        }
        SQLPOOL->recover(conn);
    }
    catch (const std::exception& e)
    {
        LOG_ERROR("mysql test failed," +std::string(e.what()));
        abort();
    }
}
void initService()
{
    new User();
    new UserNS();
    new Internal();
    new Game();
}
int main()
{
    // 启动配置管理器
    {
        Utils::assert(ConfigManager::getInstance()->start(), ConfigManager::getInstance()->last_error());
    }
    // 服务管理器
    ServiceManager::getInstance();
    // 玩家管理器
    PlayerManager::getInstance();
    // 处理中心
    HandleCenter::getInstance()->start();
    // 房间队列
    RoomQueue::getInstance();
    // 房间管理器
    RoomManager::getInstance();

    initService();
    initMysql();

    if (Server::getInstance()->start())
    {
        LOG_INFO("start success");
    }
    else
    {
        LOG_ERROR("start failed," + Server::getInstance()->last_error());
        return 0;
    }

    while (true)
        std::cin.get();

    return 0;
}

ServiceManager:自定义服务管理器

自定义的服务无需手动调用ServiceManager注册服务,IService在构造时已自动注册。

<pre class="prism-highlight prism-language-cpp">#pragma  once
#include <functional>
#include "iservice.h"
#include "ybase/error.h"
#include "ybase/singleton.hpp"
#include "network/request.h"
class ServiceManager:public ylib::error_base, public ylib::singleton<ServiceManager> {
    friend class ylib::singleton<ServiceManager>;
private:
    struct ActionCallback {
        REQUEST_CALLBACK callback;
        std::string m_name;
    };
public:
    // 获取服务
    std::shared_ptr<IService> getService(const std::string& name);
    // 删除服务
    void removeService(const std::string& name);
    // 执行
    void exec(int type,int action,Request& request);
private:
    // 注册服务
    bool registService(IService* service);
    // 注册功能
    void registAction(int action, REQUEST_CALLBACK,IService* service);
    friend class IService;
private:
    // 服务集
    std::map<std::string,std::shared_ptr<IService>> m_services;
    // 指令集
    std::map<int/*type*/, std::map<int/*action*/, ActionCallback>> m_cmds;
};

Title of this article:<3 - C++ Development of "Fight the Landlord" - Detailed Analysis of the Backend & (CORE)>Author:minimini
Original link:https://www.xxmjw.com/post/15.html
Unless otherwise specified, all content is original. Please indicate when reprinting.

Related

minimini

minimini