H2Engine 脚本化设计

H2Engine 脚本化设计

  H2Engine脚本化设计的思路是:c++做数据结构和接口,脚本无状态处理逻辑。采用这种设计由如下几个原因。

c++做数据结构缓存数据

  游戏服务器一般都会使用比较多的内存,处于对接口相应速度的要求,服务器一般会缓存非常多的数据,如果使用脚本缓存数据,事实上脚本也是可以缓存数据的,但是当超过1G内存后,脚本的内存管理会非常的受限制,一般而言脚本都会有大内存的限制,超过阈值甚至是普通的内存分配都会失败比如lua。另外脚本因为大多都要对象引用计数和垃圾回收,如果脚本中出现循环引用导致内存泄漏,说实话,比c++的内存泄漏难查多了。所以in fact,c++中缓存数据是最科学的,这就是c++做数据结构的原因。

C++可以实现某些接口直接操作数据

  c++做数据结构保留开发者用c++实现逻辑的能力,我们知道有些少数接口是对效率要求非常高,同时调用频率又非常大,这种接口非常适合用c++实现,比如走路这种。加入用脚本缓存数据,那么你c++再去访问脚本就非常的难做。

脚本接口一次编写,人人可用

  因为c++编写数据结构和接口,比如某开发者开发了好用的一个功能模块比如成就系统,那么这个c++部分共享出来是每个项目都可以用的,但是脚本部分就不能通用了,因为两个项目可能用的脚本语言不一样,H2Engine很好的解决了这个问题,H2Engine提供了一个Scirpt注册的工具一统各个脚本的函数扩展,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
static userid_t Entity_getUid(EntityPtr p){
if (p){
return p->getUid();
}
return 0;
}
static size_t Entity_totalNum(){
return Entity::EntityPtr2Ref.size();
}
//!这里演示的是如何注册脚本接口
SCRIPT_UTIL.reg("Entity.getUid", Entity_getUid);
SCRIPT_UTIL.reg("Entity.totalNum", Entity_totalNum);

  当SCRIPT_UTIL用注册接口后,无论你使用什么脚本语言,都可以在脚本中调用此函数,比如在lua中

1
numEntity = h2ext.callFunc('Entity.totalNum')

  python中调用

1
2
import h2ext
numEntity = h2ext.callFunc('Entity.totalNum')

  几乎是统一的调用方式,真真正正是一次编写,人人可用,这个设计的初衷是为了给H2Engine提供一个好的模块分享的生态,必须保证开发者开发的模块,无缝的可以应用到其他项目中,一旦有门槛或限制,出于大部分开发者的尿性都会觉得还不如自己重写。所以这个特性是非常的有价值。需要注明一点,SCRIPT_UTIL注册的函数最多支持9个参数,基本数据类型以及stl的常用数据结构已经做了模板泛化,方便了开发者使用。