异步(延时)逻辑难题,以及采用lua的解决方法

2023-11-16

        在网游程序里混过一阵子的程序员大都知道,“异步逻辑”是游戏逻辑里最容易失误的地方之一。刷钱、刷经验、不花钱得到道具,然后关服、回档、删号等等等等,其可能造成的危害不胜枚举。而且实际上银行系统之类的地方遇到这种问题就更有趣了:)。

        不同团队对此类问题的称呼不同,我喜欢称其为“异步”。它是说这样一类问题:

        玩家满足某条件时(比如身上有10金币),与NPC对话触发一个对话选项:花10金获得一个道具。玩家选择此选项后,失去10金,获得道具。问题出在:逻辑上看这是一个连续的事件,但是由于玩家点击是一个延时操作(我们称为“异步”),程序里必然要有两个入口:

        1、玩家与NPC对话——判断金钱数,打开NPC对话框

        2、玩家选择了交换选项——(再次判断金钱数),扣除金币,给予道具

        这个例子很简单,关键是玩家选择交易的时候,已经是一段时间之后了,这段时间玩家的金钱很可能已经变化了。刚开始写逻辑程序的人,往往会忘记“再次判断金钱”这一步,造成后续逻辑错误,同样的没经验的测试人员也往往漏测这步,此BUG放出去的风险取决于具体逻辑,不可预计。


        大部分情况下,需要判断的地方比上面的例子要隐蔽。例如:

        玩家在特定场景使用收费道具,触发逻辑:3秒后召唤落石。那么3秒后主逻辑就会调用召唤落石的实现函数,而这个函数被调用的时候有几种情况:

        1、之前的这个玩家已经下线,函数应当判断后退出。

        2、玩家已经切换到了另一个场景,这个情况比较危险,因为如果没有判断场景,那么玩家就会在另一个场景使用落石技能。这个例子确实的发生在了某款游戏中:),而且这么有趣的事情必然在玩家之间传播的很快。

        3、玩家被定身无法使用落石技能。这种情况和具体设计有关,如果要完全解决会比较复杂,不光是这一个道具的问题了。


        逻辑程序员在犯过几次类似的错误之后,会抱怨——这种逻辑太容易写错了。我现在依然有这种感觉。而这种问题其实用Lua、Python等等支持“函数重入”的语言来说有很好的解决方法。其中Lua可以使用协程coroutine,Python用yield和signal语法就可以了。多说无益,贴代码:

g_condition = 0
-- 检查函数
function check_condition()
    if g_condition == 0 then
        print('Check Failed.')
        return false
    else
        print('Check OK.')
        return true
    end
    return false
end
-- 我们的具体某个操作operate,分成三步走,每一步打印信息提示
function operate()
    if ( not check_condition() ) then
        return
    end
    print('operating...1')
    local par = coroutine.yield()

    if ( not check_condition() ) then
        return
    end
    print('operating...2')
    par = coroutine.yield()

    if ( not check_condition() ) then
        return
    end
    print('operating...3')
    return 'finished'
end

-- 以下模拟主逻辑用于测试
co = coroutine.create(operate)

print('Test 1: Normal procedure')
g_condition = 1
while true do
    status, value = coroutine.resume(co, 'hahaha')
    print('coroutine:',status, value)
    if not status or value=='finished' then
        break
    end
end

print('---------------------------')
print('Test 2: The environment changes in the procedure ')
g_condition = 1
co = coroutine.create(operate)
g_condition = 1
status, value = coroutine.resume(co, 'hahaha')
print('coroutine:',status, value)
g_condition = 0
status, value = coroutine.resume(co, 'hahaha')
print('coroutine:',status, value)

status, value = coroutine.resume(co, 'hahaha')
print('coroutine:',status, value)




        说明:我们的operate要求某个环境变量(可以是玩家金钱、任务标记等等)不等于0,如果是0则终止此操作,而operate本身无法连续执行,比如需要提出扣信用卡的请求、等待玩家确认等等,所以操作不得不被分成三步。

        上面的例子基本演示清楚了整个思路。写operator的程序员思路可以保持连贯,然后在必要的地方插入中断yield,再加上判断函数,一个可能很健壮的流程就被写好了!


        现实情况肯定比这个复杂。有趣的地方在于:

        1、如何抽象出好用的判断函数?相信一个项目里有许多判断都是类似的可以复用的。

        2、由于yield函数的返回值可以由主逻辑从外围送进来,yield也可以把参数送到外面去。那么我们就多了一个内外交互的手段。用这个手段,我们可以很好的实现时间回调接口;我猜还会有其他很多神奇的功能,只要你想做。

        3、很多时候,遇到检查失败的时候,不是简单返回,而是要做rollback,消除之前的影响。这就比较麻烦了。个人建议一方面在项目里提供规范的回滚方法,另一方面要尽量避免这种情况,实际上大多逻辑问题很容易避免回滚(逻辑模块不要把破碎的接口注册给上层脚本去组织,而应该提供尽量方便的要么成功、要么失败的一锤子买卖的接口:)    )


        简单有趣的事情,不宜讲的太多,相信每个乐在其中的程序员都会给出不同的具体解决方案。我也不罗嗦了,赶紧写代码去。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

异步(延时)逻辑难题,以及采用lua的解决方法 的相关文章

随机推荐

  • 安卓中高级开发面试知识点之——缓存

    几乎所有的项目都做了缓存 但是缓存做的怎么样 其实只有我们自己知道 缓存做的好 没有网络也能流畅的使用 再多的数据请求都不会出现卡顿延迟等待很久的情况 程序中除了图片缓存 三级缓存 还有信息缓存 当用户无法联网时 app会默认显示缓存的数据
  • 线速度和角速度

    转自 https baike baidu com item E7 BA BF E9 80 9F E5 BA A6 1532652 fr aladdin https baike baidu com item E8 A7 92 E9 80 9F
  • 人脸识别是最早走向实际应用的技术之一

    会员的刷脸消费 适合特殊场景下的消费 如健身俱乐部 夜店等无卡场所 目前 众多连锁超市 商城百货等多家医院 地铁都在普及刷脸支付 没有什么人和事可以随随便便成成功 商海战役亦如是 正因为刷脸支付给商家和消费者带来了如此多的便利和实惠 所以刷
  • (转)StyleCop

    微软的StyleCop作为一款代码分析插件 集成到Visual Studio 2008和Visual Studio 2010之中 可以帮助开发人员迅速地理清编程规范问题 对确保软件质量 确保软件开发效率而言 意义非凡 与同样出自微软的另一款
  • python运行时:ModuleNotFoundError: No module named ‘tensorflow‘

    TensorFlow报错 python或者anaconda运行时显示 一般的解决方案 pip install upgrade ignore installed tensorflow 或者 pip install user upgrade i
  • oom killer 详解

    一 oom killer理解和日志分析 知识储备 oom killer日志分析 这是前篇 准备一些基础知识 带着问题看 1 什么是oom killer 是Linux内核设计的一种机制 在内存不足的时候 选择一个占用内存较大的进程并kill掉
  • Navicat使用HTTP通道服务器进行连接mysql数据库(超简单三分钟完成),centos安装nginx和php,docker安装nginx+php合并版

    序言 因为数据库服务器在外网是不能直接连接访问的 但是可以访问网站 网站后台就能访问数据库 所以在此之前 访问数据库的数据是一件非常麻烦的事情 在平时和运维的交流中发现 他们会使用ssh通道进行连接访问数据库 之前并没在意这个东西 直到运维
  • moment函数转换后的时间不正确,带有 “sa“等奇怪的字母

    目录 一 问题 二 解决方法 三 总结 一 问题 1 使用moment函数转换当前日期的格式为 年 月 日 结果转换出来竟然有一些 字母 迷之自信 这不就是这样吗 给了转换格式 给了转换时间 字母就出现这种奇葩的情况 1 代码如下 let
  • 子类化QAbstractTableModel,实现table列排序和整列拖动功能

    子类化QAbstractTableModel 实现table列排序和整列拖动功能 本程序基于Qt5 9 9 Qt creator 4 11 0实现 效果图 1 子类化QAbstractTableModel 主要是实现QAbstractTab
  • 减一天 日期函数_【Excel】日期加减运算法则

    前几天小八和大家分享了如何使用快捷键和函数 快速的输入日期 如果有人不记得了 可以再回顾下 链接如下 Excel 日期木有改 又被领导骂了 除了怎么输入 我想大家更头疼的是 日期怎么参与计算 今天小八就来分享几个日期计算的方法 1 加减1天
  • python实现简易五子棋小游戏(三种方式)

    tkinter库 Python的标准Tk GUI工具包的接口 示例 from tkinter import root Tk 你的ui代码 Label root text hello world pack root mainloop 弹窗结果
  • VS Code集成终端字体修改 & 字体颜色、大小修改方法

    文章目录 VS Code中设置颜色的方法 字体以及字体大小修改 参考 VS Code中设置颜色的方法 通过将以下内容添加到用户设置中 ctrl 并搜索 workbench 然后点击 Edit in settings json 在最后加上如下
  • 国家智慧教育公共服务平台(2023年暑期教师研修)

    前言 最近又要看2023年暑期教师研修高等教育教师专业发展 抓包发现开启倍数无效了 要一个一个点击看视频 岂不是累死人 于是想个办法解放双手 该网站观看视频时 客户端间隔20 50s向服务端发送一个POST请求 服务器每秒返回ts响应 1
  • python数据分析预处理z-score标准化

    一 z score标准化的python代码 import pandas from pandas import read excel from sklearn import preprocessing dataset read excel p
  • 强化学习入门《Easy RL》

    什么是强化学习 强化学习关注的是智能体 Agent 在复杂的环境 Environment 中如何最大化获得的奖励 Reward 智能体和环境两部分组成了强化学习 在强化学习过程中 智能体与环境一直在交互 智能体在环境中获取某个状态后 它会利
  • python学习笔记#2元组和列表

    python学习笔记 2元组和列表 文章目录 python学习笔记 2元组和列表 前言 一 string包含引号 二 复杂数据类型 1 序列 2 tuple 元组 2 list 列表 总结 前言 学习python的复杂数据类型 tuple和
  • 以element ui为例分析前端各种弹窗和对话框的使用场景与区别

    文章目录 摘要 Dialog 对话框 Drawer 抽屉 Notice 通知 MessageBox 弹框 Popconfirm 气泡确认框 Message 消息提示 Notification 通知 Dialog 对话框与Drawer 抽屉的
  • MySQL中的锁机制详解

    概述 事务的隔离性 隔离级别 是由锁来保证的 并发访问数据的情况分为 1 读 读 即并发事务相继读取相同的记录 因为没涉及到数据的更改 所以不会有并发安全问题 允许这种情况发生 2 写 写 即并发事务对相同记录进行修改 会出现脏写问题 因为
  • python flask 网页适应手机端浏览器的编程方法

    1 使用flask在电脑端开发了一个论坛网址 想在手机端浏览看看 却发现根本装不下 并且导航栏元素还消失了 先看电脑端访问是正常的 而手机端导航条不见了 这是因为手机和电脑屏幕分辨率不同导致的 最简单的办法就是添加自适应宽度 并缩放页面 这
  • 异步(延时)逻辑难题,以及采用lua的解决方法

    在网游程序里混过一阵子的程序员大都知道 异步逻辑 是游戏逻辑里最容易失误的地方之一 刷钱 刷经验 不花钱得到道具 然后关服 回档 删号等等等等 其可能造成的危害不胜枚举 而且实际上银行系统之类的地方遇到这种问题就更有趣了 不同团队对此类问题