首先在这里庆祝香港回归祖国的怀抱25周年,想起那年还是一个小学生戴着红领巾和胸章激动不已,实现祖国的统一是每个中华儿女从小的梦想!趁着这欢庆的日子,突然想要写些什么,其实最近也在做一些事,由于工作繁忙加上自身的懒惰,因此对于自己所维护的这个框架感觉有些疏远。但我还是没有忘记8年前,当初实现这个框架的激情和梦想,在这里我用一个具体的例子来看看PF框架到底能做些什么。

  例子

  这次的选择是以一个实际运营的项目做测试,其实我在以前的文章中也提到过这个应用,也许大家都并不陌生,它就是现在还比较火爆的剑侠3,一款多人在线的MMO游戏。网络上很久以前就流出了其部分的源代码,很久以前我也对它经过一定的分析,不过感觉到并没有修复和学习的必要,也就没有再看。现在想来最大的原因就是那份代码缺少的东西太多,就连一些基本的头文件都缺失,那么参考的意义就不大,除非有极深的兴趣和足够的精力。

  这次选择的是几年前稍微完整的一份代码,当然也只是冲着研究和学习的目的,毕竟那么一个大型的项目还是有一定的研究价值,不过想要实际运行并没有那么容易,虽然一份可以32编译的版本,但我是索然无味的。其最大的原因,就是我想要将plain framework(PF)应用到这里面。其实从残缺的代码中可以看到其实确实比较重要的地方就是网络方面,而正好PF拥有这个能力,一切就自此开始了。

  PF的网络

  修复那流出并不太全的代码,最大的就是需要实现网络方面的接口,好在PF主要做这方面的,而在修改这部分代码之前,我还以为可能会费一番周折。可是经过一段时间的思考后,结果就如果下面的短短代码,一切都如同古语说的那样:大道至简!

// 这个线程池目前只用于重连
pf_sys::ThreadPool g_thread_pool(6); void reconnect(
pf_net::connection::Basic *conn,
const std::string &name,
const std::string &ip,
uint16_t port) {
for (;;) {
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
KGLogPrintf(KGLOG_DEBUG,
"reconnect: %s(%s:%d)", name.c_str(), ip.c_str(), port);
auto r = conn->connect(ip.c_str(), port);
if (r) {
get_conn_mgr().add(conn); //线程不安全?
get_conn_mgr().set_connection_name(conn->get_id(), name);
conn->set_name(name);
break;
}
}
}; std::unique_ptr < pf_net::connection::manager::Connector > g_connector;
// static bool g_connector_init{ false };
pf_net::connection::manager::Connector & get_conn_mgr()
{
if (is_null(g_connector)) {
auto connector = new pf_net::connection::manager::Connector;
unique_move(pf_net::connection::manager::Connector, connector, g_connector);
g_connector->callback_disconnect([](pf_net::connection::Basic *conn){
auto flag = conn->get_param("no_reconnect"); // 如果设置了不自动重连...
if (flag == true) return;
std::string ip = conn->socket()->host();
if ('\0' == ip[0]) return;
auto port = conn->socket()->port();
std::string name = conn->name();
conn->set_empty(false);
g_thread_pool.enqueue([conn, name, ip, port]{
reconnect(conn, name, ip, port);
});
});
}
return *g_connector.get();
}

  上面的代码是用于客户端连接的,也就是需要连接到服务器使用,在这个项目的构架中游戏服务器也需要连接到其他服务器的,如中心服和网关。这里在原来的基础上,实现了断线自动重连的功能,原本的服务器是断线后就必须重启所有的进程才能正常工作的,这里做了一点小小的改进,而且实现起来并不复杂。

  那么面向服务器的监听的如何实现呢?其实比较简单,直接使用PF自带的服务进行创建并监听即可,代码如下:

  listener = new pf_net::connection::manager::Listener;
unique_move(pf_net::connection::manager::Listener, listener, listener_);
bRetCode = listener_->init(m_nMaxPlayer, nPort, szIP);
KGLOG_PROCESS_ERROR(bRetCode);

  是不是感觉使用挺容易的?不过到这里功能并没有做完,如果你需要处理连接和断开时的处理则需要注册相应的处理函数(这个是在修复这段代码时,对PF做了一点小小的功能支持调整)。

  代码如下(因为原来的处理客户端连接的代码比较多,这里只截取其中一部分,如果有兴趣可以在残码中找到):

  

  listener_->callback_connect([this] (pf_net::connection::Basic * conn) {
std::pair < KPlayerTable::iterator, BOOL > InsRet;
std::string ip;
KPlayerAgency * pPlayer = NULL;
KG_PROCESS_ERROR(m_PlayerTable.size() < (size_t) m_nMaxPlayer);
while (true) {
KPlayerTable::iterator it = m_PlayerTable.find(m_nNextPlayerIndex);
if (it == m_PlayerTable.end()) {
break;
}
m_nNextPlayerIndex++;
}
...
};
  listener_->callback_disconnect([this] (pf_net::connection::Basic * conn) {
// 该设置在接受连接时进行处理
auto index = conn->get_param("player_index");
std::string ip = conn->socket()? conn->socket()->host() : "";
KPlayerAgency * pPlayer = NULL;
KGLOG_PROCESS_ERROR((index.type != pf_basic::type::kVariableTypeInvalid));
pPlayer = GetPlayer(index.get < int32_t > ());
KGLOG_PROCESS_ERROR(pPlayer);
OnDisconnect(pPlayer);
KGLogPrintf(KGLOG_INFO,
"Player disconnect from %s, index = %d\n",
ip.c_str(), index.get<int32_t>());
Exit0:
return;
});

  由于要配置这个项目的心跳逻辑,因此无法直接使用PF的运行模式(实际上是可以的,不过为了尽可能的改动不多),于是在这里PF又提供了一个基础环境初始化的接口,方便注册网络包的处理以及可以使用日志等接口。

  实现如下:

  // PF basic enviroment.
r = pf_engine::init_basic_env();
KG_PROCESS_ERROR(r);

  使用上面的模式可以脱离pf::Application启动,而且基本的接口都能正常使用,但为了正常的使用,现在需要在你的程序逻辑成功后加上如下代码:

  // 标记启动应用
GLOBALS["app.status"] = kAppStatusRunning;

  关于这份代码

  目前网络上已经有了这个游戏的一键启动,在这里我也放一张进入游戏的图:

  有兴趣的朋友们如果需要学习和研究这份残码,我这里可以简单总结一下,它是10年初的版本,因此大概就是1.5的70版本,网上由于流出的脚本是80的,而且很多的脚本残缺不全,导致了许多的AI甚至物品以及技能无法正常使用。以前也玩过这个游戏,是游戏刚出来的时候(大约09年左右),我觉得这个游戏的技术在当时还是很不错的,无论和画面还是其他各方面在当时国内算得上是前沿。如果作为学习和兴趣,尝试慢慢修复各种脚本需要很长一段时间,就算是比较精通脚本,要达到完整也不容易。

  如果喜欢本游戏的还是建议大家到官网下载该游戏,这款游戏算是目前国内花钱不太多的游戏之一了,而且经过十多年的更替,其画质和各方面都表现的比较出色。

  

  总结

  这次选择使用这段残码作为PF的一个实验,证明了PF在实际应用中还是具有其特性的简单、快速、高效的目的,当然为了完善在实际应用中做了略微的调整。当前PF还是有实际应用的不足,但是我相信在未来可以得到逐步的完善。

  PF2.0的版本或许在将来,使用全新的如C++23进行一次重大更新。

plain framework的实际应用和扩展的更多相关文章

  1. plain framework 1 一款主要用于网络(游戏)开发的C/C++开源框架 安装篇 updated

    上次介绍了一下plain framework的基础相关资料,今天该框架正式开源发布.项目的地址托管于github上,我相信大多数朋友都应该知道.今天要介绍的是该框架的目录基本结构,以及分别在linux ...

  2. 程序设计模式浅析(plain framework商业版设计模式)

    程序设计其实对程序开发者来说十分重要,但是在工作中往往我们却忽略了这一块,因为我们所用的都是现有的模式.一个设计模式的好坏,往往能够体现出程序的专业性,还有整个项目的可持续性.这就是为什么有些公司,在 ...

  3. plain framework 1 参考手册 入门指引之 模块

    模块 总述 基础 数据库 引擎 事件 文件 网络 性能 脚本 系统 工具 总述 上图为plain framework(简称简约框架)所有的模块,包括基础.数据库.引擎.事件.文件.网络.性能.脚本.系 ...

  4. plain framework 1 参考手册 入门指引之简介

    简介 简介 能做什么? LINUX WINDOWS 简介 简约框架(plain framework)是一款基于C/C++开发的,跨平台(windows/linux)应用的基础框架,开发者可以利用此框架 ...

  5. plain framework 商业版 开发总结2 项目管理器

    任何事情都有三个阶段,分析.制作.质检的过程.在程序中就分为设计.编码.调试(测试)三个阶段,其中设计最为重要,设计的不好会导致编码和调试重复,甚至最后又回到了设计的过程.为了不会重复返工,所以设计的 ...

  6. plain framework 1 1.0.4 更新 稳定版发布

    PF由于各种因素迟迟不能更新,此次更新主要是更新了以往和上个版本出现的内存问题,该版本较为稳定,如果有用到的朋友请更新至此版本. PF 1.0.4 修复1.0.0.3更新后产生的内存问题,可能导致网络 ...

  7. plain framework 1 1.0.3更新 优化编译部分、网络压缩和加密

    有些东西总是姗姗来迟,就好比这新年的钟声,我们盼望着新年同时也不太旧的一年过去.每当这个时候,我们都会总结一下在过去的一年中我们收获了什么,再计划新的一年我们要实现什么.PF并不是一个十分优秀的框架, ...

  8. plain framework 1 网络流 缓存数据详解

    网络流是什么?为什么网络流中需要存在缓存数据?为什么PF中要采用缓存网络数据的机制?带着这几个疑问,让我们好好详细的了解一下在网络数据交互中我们容易忽视以及薄弱的一块.该部分为PF现有的网络流模型,但 ...

  9. plain framework 1(简约框架)一款主要用于网络(游戏)开发的C/C++框架 即将开源发布

    在我们的日常开发中,我们往往会遇到这种情况,当我们换了一个开发环境时很可能会重新利用一套新的框架进行开发.由于不同框架有着不同的接口,所以我们不得不花时间再次熟悉这些接口,这将造成开发时间上的重复,而 ...

随机推荐

  1. Hadoop3.x 三大组件详解

    Hadoop Hadoop适合海量数据分布式存储和分布式计算 运行用户使用简单的编程模型实现跨机器集群对海量数据进行分布式计算处理 1. 概述 1.1 简介 Hadoop核心组件 HDFS (分布式文 ...

  2. c# 一些警告的处理方法

    在使用.Net 6开发程序时,发现多了很多新的警告类型.这里总结一下处理方法. CS8618 在退出构造函数时,不可为 null 的 属性"Name"必须包含非 null 值 经常 ...

  3. Win10系统链接蓝牙设备

    1. 进入控制面板,选择 设备 2. 进入设备界面,删除已有蓝牙,如果蓝牙耳机已经链接其他设备,先断开链接 3. 点击添加蓝牙或其他设备 4. 选择蓝牙,选择你的蓝牙耳机名称

  4. SSH只能用于远程Linux主机?那说明你见识太小了!

    开源Linux 长按二维码加关注~ 今天小编为大家分享一篇关于SSH 的介绍和使用方法的文章.本文从SSH是什么出发,讲述了SSH的基本用法,之后在远程登录.端口转发等多种场景下进行独立的讲述,希望能 ...

  5. .NET性能优化-为结构体数组使用StructLinq

    前言 本系列的主要目的是告诉大家在遇到性能问题时,有哪些方案可以去优化:并不是要求大家一开始就使用这些方案来提升性能. 在之前几篇文章中,有很多网友就有一些非此即彼的观念,在实际中,处处都是开发效率和 ...

  6. logging、openpyxl、第三方模块下载

    ### 日志模块的组成部分 ```pythonimport logging# 1.logger对象:产生日志logger = logging.getLogger('转账记录')# 2.filter对象 ...

  7. Kubernetes API 基础

    APIServer 在kubernetes架构概念层面上,Kubernetes由一些具有不同角色的服务节点组成.而master的控制平面由 Apiserver Controller-manager 和 ...

  8. 【Java8新特性】Stream(分类+案例)

    一.Stream概述 什么是Stream? Stream是Java8引入的全新概念,它用来处理集合中的数据,可以让你以一种声明的方式处理数据. Stream 使用一种类似用 SQL 语句从数据库查询数 ...

  9. 152-技巧-Power Query 快速合并文件夹中表格之自定义函数 TableXlsxCsv

    152-技巧-Power Query 快速合并文件夹中表格之自定义函数 TableXlsxCsv 附件下载地址:https://jiaopengzi.com/2602.html 一.背景 在我们使用 ...

  10. CF1681F Unique Occurrences

    题意:一棵树,问每条路径上只出现一次的值的个数的和. 思路: 显然想到考虑边贡献.每条边权下放到下面的哪个点.\(up_i\)为上面第一个点权等于它的点.我们需要一个子树内点权等于它的点(如果满足祖孙 ...