V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dfgxcvbcv
V2EX  ›  数据库

游戏中每隔 xx 分钟回复一格体力 数据库一般是怎么存储的?

  •  1
     
  •   dfgxcvbcv · 88 天前 · 5831 次点击
    这是一个创建于 88 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不太可能每分钟都遍历一次体力没满的用户吧

    37 条回复    2022-07-10 23:28:44 +08:00
    joesonw
        1
    joesonw  
       88 天前 via iPhone
    1 ,数据一般是在内存里,然后落地到数据库的
    2 ,有用时间轮的,有每次请求检查上次更新的
    3 ,离线用户是登录的时候计算
    elioti
        2
    elioti  
       88 天前
    那就查询的时候更新呗
    banmuyutian
        3
    banmuyutian  
       88 天前
    盲猜延时消费消息?
    MoYi123
        4
    MoYi123  
       88 天前
    和令牌桶一样的做法啊.
    ranleng
        5
    ranleng  
       88 天前   ❤️ 1
    上一次恢复的时间,当前时间,每恢复 1hp 的时间, 就能算出来了。
    算完之后更新下上一次恢复的时间就行了
    fanyingmao
        6
    fanyingmao  
       88 天前
    现在就在写体力恢复的代码,就更查询时更新,数据库存一个时间和当前体力值,查询就对比当前时间和存的时间差多少,恢复多少体力,然后在把时间加上恢复体力*单位时间。
    wfhtqp
        7
    wfhtqp  
       88 天前
    只存储剩余体力以及上次消耗体力的时间,下次消耗的时候计算是否满足并更新数据。前端直接根据上次体力计算显示当前体力
    libook
        8
    libook  
       88 天前   ❤️ 1
    没做过游戏,只是有个脑洞,尽可能避免定时任务。

    记录上一次查询时间以及同时计算出来的体力值,活跃的用户每次来请求体力值的时候用上一次体力值与上一次到现在的时间长度来算涨多少体力值,超过体力上限就设为上限值,然后把新算的体力值和当前时间记录下来。性能和 PV 有关,和总用户数量无关。
    xianyv
        9
    xianyv  
       88 天前
    unity 的话有 Time 类可以计算时间间隔,或者使用协程间隔时间
    ahill
        10
    ahill  
       88 天前
    当前体力=当前时间- 上限范围内使用体力总数
    所以不需要记录当前体力,只需要记录 160*8min 内每次使用体力的时间和数量即可。最多是 160/20=8 条记录
    登陆的时候查询计算一次之后就在客户端计算,扣体力的时候后台校验一下
    IssacTomatoTan
        11
    IssacTomatoTan  
       88 天前   ❤️ 1
    体力值 +1 是游戏客户端根据人物状态自己展示 + - 的,不和服务端交流。

    服务端负责存下最后一次对体力值的修改,当游戏客户端发起请求说有人砍了我一刀我死了没呀?服务端就获取最后体力修改的时间,来计算到当前时间应有的体力值,然后计算这一刀的减去值,记录下最新的体力值,返回客户端死没死。
    mango88
        12
    mango88  
       88 天前
    数据库存上一次恢复时间,算的时候,
    min( (当前时间 - 上一次恢复时间) / 恢复一点体力需要的时间 + 当前剩余体力, 体力上限)
    yolee599
        13
    yolee599  
       88 天前 via Android
    存一个时间戳,用时更新
    v23x
        14
    v23x  
       88 天前
    这种东西就直接按时间加上去就好了呀....用户什么时候离线的这些全都是有的
    churchill
        15
    churchill  
       88 天前
    @IssacTomatoTan 那我找到这个发请求的方法 jump 掉 不就无敌了吗
    tairan2006
        16
    tairan2006  
       88 天前 via Android
    异步落库常规操作

    没听说过服务器回档么?
    rekulas
        17
    rekulas  
       88 天前
    时间相减即可计算出来,很简单
    升级版问题:facebook 是如何推送用户消息的,要知道头部用户一个贴可能要推送给上千万人,而每个用户可能关注了数百个甚至上千个其他用户
    weidaizi
        18
    weidaizi  
       88 天前   ❤️ 1
    像体力这种一般不落库,在追求速度的游戏当中(第一人称射击类,即使战略类)基本都是客户端自己算,服务器为了反外挂,会落一些数据到文件而不是数据库。MMORPG 类型的,我早年做游戏的时候,有服务器算的,也有客户端算的,但是也都不落库。一般需要落库的是一些等级,充值以及装备呀之类的
    Martens
        19
    Martens  
       88 天前
    服务器记一个时间戳,查询时更新
    客户端登录时同步,自己维护
    moen
        20
    moen  
       88 天前
    我曾经玩过的一个手游就是记录某个时刻和当时的体力值,下面是客户端反编译的代码相关的部分:
    ```
    public new int St
    {
    get
    {
    if (base.St >= SingletonInstance<UserService>.SharedInstance.MaxSt)
    {
    return base.St;
    }
    double num = (SingletonInstance<TimeService>.SharedInstance.ServerDateTime - base.StUpdatedAt).TotalSeconds / ServerConsts.HealStInterval.TotalSeconds;
    return Mathf.Min(SingletonInstance<UserService>.SharedInstance.MaxSt, base.St + (int)num);
    }
    }
    ```
    nightwitch
        21
    nightwitch  
       88 天前 via Android
    只是内存里的一个 actor ,不会落库,客户端自行计算。为了反作弊服务端可能会采样记录一些信息。
    FakNoCNName
        22
    FakNoCNName  
       88 天前
    以前做过游戏,当时的逻辑是:

    1. 玩家上线时:把数据从库加载到内存
    2. 玩家在线时:用户基本数据在内存里面,正面状态( buff )、负面状态( debuff )实时计算并修改内存的值。
    2.1 触发式更新:当玩家参加活动、做任务时,每次开始、结束写一次库。
    2.2 其它累死 2.1 的场景,也使用触发式更新
    3. 玩家掉线时:(不论什么原因掉线)触发写库操作
    4. 服务器故障恢复:多节点组集群、使用 redis 做缓存(还会引入中间件故障恢复等问题,尽量少用)

    注:
    1~3 能解决大部分问题,这里采用触发式更新而不是定时(或时间轮)可以:避免 io 密集操作、玩家数据和数据库数据操作异步(偶尔遇到瓶颈也允许阻塞一小段时间)、保证玩家关键时刻的关键数据得以保存。

    玩家的行为是随机的,哪怕都在做活动,大多数情况也比时间轮随机,玩家多的时候时间轮压力也不小。
    FakNoCNName
        23
    FakNoCNName  
       88 天前
    所以你说的回血,不论前后端很可能是在内存中计算,在一个战斗节点或者战斗开始(结束)的时候存一次库。当然定时保存也是可能的。
    lscho
        24
    lscho  
       88 天前
    研究过外挂的应该都知道,血量 /体力 /攻击力等值一般都是登录的时候初始化到本地内存中的。。。然后战斗结算 /任务结算的时候才会与服务端通讯。

    当然有反作弊系统的话,即使不结算也会随机检测一下,数值不对就踢下线。
    nekochyan
        25
    nekochyan  
       88 天前
    体力这个肯定是前端向后端查询的时候才实时更新,然后其他时间前端起一个定时器去计算倒计时、什么时候恢复之类的
    dabaibai
        26
    dabaibai  
       88 天前
    上线才会处理
    x86
        27
    x86  
       88 天前 via iPhone
    本地内存中计算的,你看看那些锁血之类的修改差不多都一个原理
    Exdui
        28
    Exdui  
       88 天前
    @rekulas 粉丝登录 facebook 之后,查询一下有没有给他推送的消息?
    还是博主发帖时候,顺便把内容推送给所有关注的粉丝?
    junwind
        29
    junwind  
       87 天前
    游戏中一般是存在内存数据库中的,定期落地, 可以根据实际用的语言,框架, 比如 workerman 可以用定时器,或者定时任务来处理, 更新后推送一下到前端即可
    bruce0
        30
    bruce0  
       87 天前
    数据都在内存里,每次修改数据会同步到数据库, 像这种每小时恢复多少的, 一般都是记录一个时间, 比如上次恢复的时间戳, 每次获取数据的时候, 计算一下当前应该恢复到多少. 也有一些特殊的情况, 需要用一个定时器, 定时计算的, 这种情况非常少了
    Torpedo
        31
    Torpedo  
       87 天前
    为啥不用定时器啊,这不很正常么。这种类似的模型,编程语言里不就有,比如 js
    dfgxcvbcv
        32
    dfgxcvbcv  
    OP
       87 天前
    @Torpedo #31 用定时器玩家下线后怎么办?
    Torpedo
        33
    Torpedo  
       87 天前
    @dfgxcvbcv 这不是典型的用了事件,记得清除副作用么
    yyt6801
        34
    yyt6801  
       87 天前 via Android
    中间件??? 这种数据不会和数据库直接交互吧,都是在内存中
    hhjswf
        35
    hhjswf  
       87 天前
    @Exdui 一般都是推拉结合吧
    Jokerbj
        36
    Jokerbj  
       86 天前
    unity 或者虚幻里面可以加个触发功能,拿时间记一下,到时间直接自动触发一下
    d29107d
        37
    d29107d  
       86 天前 via Android
    @dfgxcvbcv 下线时记录时间戳,上线时再取时间戳,然后就可以计算出这个时间段内得到的体力
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2122 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 51ms · UTC 03:22 · PVG 11:22 · LAX 20:22 · JFK 23:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.