H2Engine游戏服务器设计之性质管理器

图片 1

游玩服务器设计之性质管理器

  游戏中角色有所的属性值很多,运营多年的玩乐,往往会有无数个成才线,每个属性都有可能被N个成长线模块增减数值。举例当角色戴上武器时候hp+100点,卸下武器时HP-100点,这样加减逻辑只有一处还比较好控制,尽管某天有个与众不同意义当被某技能攻击时,角色武器会被击落,这样就会出现减数值的操作不止一处。假诺逻辑处理不当,比如击落的时候从不合适的减数值,再度穿戴武器就导致属性值加了两边,也就是玩家通常说的刷属性。这种bug对游戏平衡性影响很大,反响很粗劣,bug又很难被测试发现。本文将介绍一种管理属性的笔触,最大限度的避免此类bug,如若出现bug,也可以很好的排查。

二、修改Nuget程序包源:VS>工具》选项》Nuget包管理器》程序包源,如图,将下载的nupkg文件放在C:\Program
Files (x86)\Microsoft SDKs\NuGetPackages\路径下:

总结

  1. 属性提供一个名字映射有成千上万利益,比如装备配属性,buff配属性的,闻明字不无关系联会特别有利
  2. 提供一个get和set接口的映射,那样属性管理器就和求实的对象的属性字段解耦了。尽管是现有的效率模块也可以合二为一这么些特性管理器。
  3. 属性的add和sub操作,都在性能管理器中留下记录,那样固然出现问题,通过getByModule
    getAllModule多少个接口亦可以匡助查找问题。
  4. 特性管理已经合并到H2Engine中,github地址:
    https://github.com/fanchy/h2engine

 

统筹思路

  刷属性bug的中坚原因是某功能的模块数值加了N次,所以各种模块加的性质要被记录,加过了必须不可以重新加。设计这样的数据结构。

//!各个属性对应一个总值
//!各个属性对应各个模块的分值
template<typename T>
class PropCommonMgr
{
public:
    typedef T ObjType;
    typedef int64_t (*functorGet)(ObjType);
    typedef void (*functorSet)(ObjType, int64_t);
    struct PropGetterSetter
    {
        PropGetterSetter():fGet(NULL), fSet(NULL){}        
        functorGet fGet;
        functorSet fSet;
        std::map<std::string, int64_t> moduleRecord;
    };
    void regGetterSetter(const std::string& strName, functorGet fGet, functorSet fSet){
        PropGetterSetter info;
        info.fGet = fGet;
        info.fSet = fSet;
        propName2GetterSetter[strName] = info;
    }
  public:
      std::map<std::string, PropGetterSetter>    propName2GetterSetter;
  };
  1. 有关数据结构的get和set,大家为各类属性命名一个名字,这样处理数据的时候会这个有利(比如道具配扩张属性等等),角色属性有不少种,这里不可以挨个定义,所以属性管理器只是映射属性,并不成立属性值。通过regGetterSetter接口,注册get和set的操作映射。为何不需要提供add和sub接口能,因为add和sub可以透过get和set组合实现。get和set的接口实现如下:

    int64_t get(ObjType obj, const std::string& strName) {

        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet){
            return it->second.fGet(obj);
        }
        return 0;
    }
    bool set(ObjType obj, const std::string& strName, int64_t v) {
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fSet){
            it->second.fSet(obj, v);
            return true;
        }
        return false;
    }
    
  2. 至于add和sub,前边提到要避免刷属性,就非得避免重复加属性。所以每个模块再加属性前务必检查一下是否该模块已经加了性能,假设加过一定要先减后加。因为老是模块加属性都记录在性能管理器中,那么减掉的数值肯定是不错的。这样可以防止其余一种常见bug,如加了100,减的时候总计错误减了80,也会积少成多造成刷属性。add和sub的代码如下:

    int64_t addByModule(ObjType obj, const std::string& strName, const std::string& moduleName, int64_t v) {

        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            int64_t ret =it->second.fGet(obj);
            std::map<std::string, int64_t>::iterator itMod = it->second.moduleRecord.find(moduleName);
            if (itMod != it->second.moduleRecord.end()){
                ret -= itMod->second;
                itMod->second = v;
            }
            else{
                it->second.moduleRecord[moduleName] = v;
            }
            ret += v;
            it->second.fSet(obj, ret);
            return ret;
        }
        return 0;
    }
    int64_t subByModule(ObjType obj, const std::string& strName, const std::string& moduleName) {
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            int64_t ret =it->second.fGet(obj);
            std::map<std::string, int64_t>::iterator itMod = it->second.moduleRecord.find(moduleName);
            if (itMod == it->second.moduleRecord.end()){
                return ret;
            }
            ret -= itMod->second;
            it->second.moduleRecord.erase(itMod);
            it->second.fSet(obj, ret);
            return ret;
        }
        return 0;
    }
    int64_t getByModule(ObjType obj, const std::string& strName, const std::string& moduleName) {
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            int64_t ret =it->second.fGet(obj);
            std::map<std::string, int64_t>::iterator itMod = it->second.moduleRecord.find(moduleName);
            if (itMod != it->second.moduleRecord.end()){
                return itMod->second;
            }
        }
        return 0;
    }
    std::map<std::string, int64_t> getAllModule(ObjType obj, const std::string& strName) {
        std::map<std::string, int64_t> ret;
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            ret = it->second.moduleRecord;
        }
        return ret;
    }
    

  如上代码所示,addByModule和subByModule必须提供模块名,比如穿装备的时候加血量:addByModule(‘HP’,
‘Weapon’, 100),而卸下武器的时候假若subByModule(‘HP’,
‘Weapon’),因为属性管理器知道减多少。

近来在做项目进度管理时,想通过安装net.sf.mpxj-for-csharp包读取.mpp格式文件,通过Nuget在线安装时,出现以下意况,不能安装,故开启离线安装道路。

图片 2

离线安装步骤如下:

图片 3

三、如下图,拔取离线包源,左边“浏览”选项卡下就可以瞥见,你要设置的包,点击安装即可。

一、下载你需要安装的离线包nupkg文件,可以在Nuget官网下载:https://www.nuget.org/packages

 

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注