差异更新

#include <iostream>
//下面说的是在服务器差异脏标记,不管在想客户端还是在数据库中经常用到的一种方法
//由于其实直接拿为进行操作,所以速度是非常快的,也许刚开始不太好理解,但只要熟悉之后就非常好用
//对于包而言如果Update包只改变一项你把整个结构体都发过去会大大增加网络带快,现在基本都走差异更新
enum UpdateAtt
{
    eUpdate1,
    eUpdate2,
    eUpdate3,
    eUpdate4,
    eUpdate5,
    eUpdate6,
    eUpdate7,
    eUpdateMax
};
#define Update_Att_Max_Num ((eUpdateMax >> 3) + 1)

/**
 *@brief 脏标记类,关键理解此类
 */
struct UserAttrFlag
{
    bool IsUpdated(int nAttr) const
    {
        if(m_Flags[nAttr/8] & (1<<(nAttr%8)))
            return true;
        return false;
    }
    void SetBitFlag(int nAttr)
    {
        m_Flags[nAttr/8] |= (1<<(nAttr%8));
    }
    void ClearBitFlag()
    {
        memset(m_Flags, 0, Update_Att_Max_Num);
    }
    char m_Flags[Update_Att_Max_Num];
};

struct UserReg
{
    unsigned char    m_AttrOffset[eUpdateMax];        ///< 角色属性偏移量,距离首地址的偏移位置
    unsigned char    m_AttrSize[eUpdateMax];            ///< 角色属性大小
};

struct Update
{
private://需要将此类的所有数据成员设置成私有,针对没个成员提供set/get接口
    int nUpdate1;
    int nUpdate2;
    int nUpdate3;
    int nUpdate4;
    int nUpdate5;
    int nUpdate6;
    int nUpdate7;
public:
    void SetUpdate1(int nData)
    {
        if(nUpdate1 != nData)
        {
            nUpdate1 = nData;
            SetDBEnumAttrDirty(eUpdate1);
        }
    }
    void SetUpdate7(int nData)
    {
        if(nUpdate7 != nData)
        {
            nUpdate7 = nData;
            SetDBEnumAttrDirty(eUpdate7);
        }
    }
    int GetUpdate1(){return nUpdate1;}
    int GetUpdate7(){return nUpdate7;}
    Update()
    {
        RegisterAttributes();
        memset(&m_attrFlag, 0, sizeof(m_attrFlag));
    }
    void RegisterAttributes();//注册标记

    void _RegAttr(UpdateAtt eAtt, int nOffset, int nSize)
    {
        /// 角色属性偏移量,距离首地址的偏移位置,之前看到天龙代码直接存的是变量的地址,这种只适合单线程使用,多线程会发生内存拷贝
        /// 所以用偏移量更合适
        m_attReg.m_AttrOffset[eAtt] = nOffset;
        m_attReg.m_AttrSize[eAtt] = nSize;
    }
    void SetDBEnumAttrDirty(UpdateAtt eUpdateAttr)
    {
        m_attrFlag.SetBitFlag(eUpdateAttr);
    }
    UserAttrFlag m_attrFlag;//属相脏标记
    UserReg         m_attReg;//属相注册
public:
    const UserAttrFlag* GetAttrFlag() const  {return &m_attrFlag;}
    const UserReg*  GetAttrReg() const {return &m_attReg;}
};

void Update::RegisterAttributes()
{
    #define REG_DB_ATTR(type,var) _RegAttr(type, ((int)&(var) - (int)this), sizeof(var));
    REG_DB_ATTR(eUpdate1, nUpdate1)
    REG_DB_ATTR(eUpdate2, nUpdate2)
    REG_DB_ATTR(eUpdate3, nUpdate3)
    REG_DB_ATTR(eUpdate4, nUpdate4)
    REG_DB_ATTR(eUpdate5, nUpdate5)
    REG_DB_ATTR(eUpdate6, nUpdate6)
    REG_DB_ATTR(eUpdate7, nUpdate7)
}

int main()
{
    Update update;
    update.SetUpdate1(12);
    update.SetUpdate7(120);
    char* buff = new char[1024];//拼buff
    //拼包操作
    int nOffset = 0;
    for (int i = 0; i < eUpdateMax; i++)
    {
        if (update.GetAttrFlag()->IsUpdated(i))//判断其是否为脏
        {
            memcpy(buff + nOffset, &i, sizeof(int));
            nOffset += sizeof(int);
            memcpy(buff + nOffset, &update + update.GetAttrReg()->m_AttrOffset[i], update.GetAttrReg()->m_AttrSize[i]);
            nOffset += update.GetAttrReg()->m_AttrSize[i];
        }
    }
    getchar();
    return 0;
}

//现在简单解释一下脏标记的处理
/*
#define Update_Att_Max_Num ((eUpdateMax >> 3) + 1)
定义的宏,根据此宏就知道定义多大的char数组,他是吧将8个枚举作为一个char,而一个char正好是8位,+1是为了不足8位,也为其分配一个char

void SetBitFlag(int nAttr)
{
    m_Flags[nAttr/8] |= (1<<(nAttr%8));
}
m_Flags[nAttr/8]是定位其在那个char上,如0,肯定是char[0],如果是9就是char[1]
(1<<(nAttr%8))表示其在某个char的哪个位上,如9,(1<<(nAttr%8))就是第二个char[1]&10,这样就正确的设置到对应的位上了
其实将char[..]看出1011111这样位,而此种方法方法就是能更方便的操作,c++没有对应的位的类型,stl里面好像有个bitset,但复杂类型在某些场合不适用的
|=或操作正好将其设置成1

bool IsUpdated(int nAttr) const
{
if(m_Flags[nAttr/8] & (1<<(nAttr%8)))
    return true;
return false;
}
上面那个理解了,这个就好理解了
m_Flags[nAttr/8]也是定位哪个char,(1<<(nAttr%8)))也是对应char那个位置
&操作获取对应为是0,还是1

对于其他的大小和偏移量,为了打包更好获取其地址和大小,更快的打包而设置的,好理解

*/

/*
额外补充
对于DBSvr怎么解析,是根绝实现定义好的function,然后根据类型直接调用,那个类型里面关于数据类型都是写死的,个人觉得不是太好
客户端我问了,他是根绝枚举,硬猜是哪个包,已醉
*/
时间: 2024-08-05 18:45:43

差异更新的相关文章

游戏差异更新—PC蛋蛋源码下载BSDiff算法解析

PC蛋蛋源码下载联系方式:QQ:2747044651 网址请添加链接描述----pi2502差异更新即在软件更新时只更新差异化的部分,以达到用最小的下载量完成软件的更新需求.该思想由来已久,从刚接触电脑时的操作系统.应用软件快速更新功能或填补漏洞,到迭代更加频繁的移动应用时代更多了节省下载流量费用的需求.尤其在移动游戏领域,随着手机性能的提升和玩家对游戏体验的追求,安装包亦是越来越大,并且会频繁的更新以不断给玩家带来更新的玩法和更为优化的体验.然而,这种频繁的更新也同样会带来负面的影响:更新包太

差异更新两个表

CREATE TABLE Temp_A ( Emp_No VARCHAR(7) , Emp_Name VARCHAR(20) ) CREATE TABLE Temp_B ( Emp_No VARCHAR(7) , Emp_Name VARCHAR(20) ) INSERT INTO Temp_A VALUES ( '0000001', '张飞' ) INSERT INTO Temp_A VALUES ( '0000002', '吕布' ) INSERT INTO Temp_A VALUES (

【原创】我所理解的自动更新-概要

概述    一般来说,游戏在开发完成后会通过渠道分发至玩家的手机上.这也就涉及到游戏的下载,安装.但是游戏还有一个重要的步骤,更新.对于手游而言,更新分为大版本更新和当前内容更新(大版本更新也会包含当前内容更新).大版本更新需要开发商重新提交游戏安装包,玩家重新下载安装包安装.而当前内容更新更多的是指更新脚本/资源等.那么问题来了,就技术而言,游戏通过什么方式下载安装?内容通过什么方式更新?恰好刚完成某手游的下载更新模块,就自己的理解,和大家聊聊游戏更新的那些事儿. 本文适用人群 本文档适用于自

CRL快速开发框架系列教程三(更新数据)

本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框架系列教程四(删除数据) CRL快速开发框架系列教程五(使用缓存) CRL快速开发框架系列教程六(分布式缓存解决方案) CRL快速开发框架系列教程七(使用事务) CRL快速开发框架系列教程八(使用CRL.Package) CRL快速开发框架系列教程九(导入/导出数据) CRL快速开发框架系列教程十(

GS(道具,帮会)定时存储

//最近数据库存储做了重大改变,数据库内部的回头再说,先看看GS这边的 1.现在感觉数据库的状态将请求包放入命令队列中,以前是全部放进去,这样让其他的数据库操作不会随着数据库定时器而变慢,GS线程去驱动,一分钟不太可能还存不完 2.差异更新,GS只获取更改了的记录,这样不用每次都把全部的记录都放进去,这个过程是数据库改观不少 外面搞个mgr,内部使用可以重用的模板类,感觉是比之前封装的要好,但复杂度也上去了 m_spSaveOptMgr.reset(new SaveOptMgr(m_spAsyn

Python数据类型及其方法详解

Python数据类型及其方法详解 我们在学习编程语言的时候,都会遇到数据类型,这种看着很基础也不显眼的东西,却是很重要,本文介绍了python的数据类型,并就每种数据类型的方法作出了详细的描述,可供知识回顾. 一.整型和长整型 整型:数据是不包含小数部分的数值型数据,比如我们所说的1.2.3.4.122,其type为"int" 长整型:也是一种数字型数据,但是一般数字很大,其type为"long" 在python2中区分整型和长整型,在32位的机器上,取值范围是-2

python学习笔记4:基础(集合,collection系列,深浅拷贝)

转载至:http://www.cnblogs.com/liu-yao/p/5146505.html 一.集合 1.集合(set): 把不同的元素组成一起形成集合,是python基本的数据类型.集合元素(set elements):组成集合的成员 python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)

优化Angular应用的性能

优化Angular应用的性能 MVVM框架的性能,其实就取决于几个因素: 监控的个数 数据变更检测与绑定的方式 索引的性能 数据的大小 数据的结构 我们要优化Angular项目的性能,也需要从这几个方面入手. 1. 减少监控值的个数 监控值的个数怎么减少呢? 考虑极端情况,在不引入Angular的时候,监控的个数是为0的,每当我们有需要绑定的数据项,就产生了监控值. 我们注意到,Angular里面使用了一种HTML模板语法来做绑定,开发业务项目非常方便,但考虑一下,这种所谓的“模板”,其实与我们

服务器buff管理

关于buff和玩家自动回血buff { m_StatusTimer.reset(pFT->createTimer()); m_StatusTimer->setInterval(500); m_StatusTimer->regTimer(std::bind(&StatusMgr::RunOnce, this)); m_StatusTimer->start(); m_StatusTimer.reset(pFT->createTimer()); m_StatusTimer-