游戏服务器开发指南(七):资源流通保证先减后增的顺序

【Claude Code · VibeCoding】13|实战演示:水果消消乐 VibeCoding 用「水果消消乐」走一遍 VibeCoding:提示、生成、试玩、改需求、再生成。 阅读详情

大家好!我是长三月,一位在游戏行业工作多年的老程序员,专注于分享服务器开发相关的文章。

本文是通用程序设计主题下的第二篇。这个主题主要探讨如何编写高效、健壮、易读的游戏业务代码,每篇从一个小点切入。本次讨论的原则是:资源流通应保证先减后增的逻辑顺序,这样编写的代码通常具有更好的健壮性。

从数值的角度来看,游戏本质上是就是不同资源的持续流通。资源的流通包括两种:一种是资源转换,即消耗A资源生成B资源,例如购买商品就是花钱获得物品;另一种是资源转移,即从A所有者转移到B所有者手中,例如为公会捐钱,钱从个人转移到了公会下面。

无论是哪种资源流通,我们都有两种处理顺序:先增后减,或者先减后增。粗略看上去这两者没有什么不同,但实际在容错性上有显著差别。

让我们回顾在前一篇《条件判断永远放在状态变更前》中讲到的购买商品例子,假设我们将其逻辑修改为先增后减:

public Msg buy(int playerId, int commodityId, int num) {
	if (!isCommodityIdValid(commodityId)) {	// 判断商品id是否存在
		return newFailMsg("错误的商品id");
	}
	if (!isCommodityEnough(commodityId)) {	// 判断商店中商品数量是否足够
		return newFailMsg("这种商品剩余数量已不足");
	}
	int costMoney = getCommodityCost(commodityId, num);
	if (!isMoneyEnough(playerId, costMoney)) {	// 判断玩家金币是否足够
		return newFailMsg("您的金币不足");
	}
	deliverCommodity(playerId, commodity, num);	// 发送商品给玩家
	consumeMoney(playerId, costMoney);	// 消耗金币 
	return newSuccMsg(playerId, commodityId, num);
}

那么当代码执行consumeMoney出错而中断逻辑时,会造成非常糟糕的后果:玩家每调用一次购买接口,都会无偿获得商品,而不用消耗任何钱!这就是最让人头大的刷资源情况。如果刷资源的人数众多,而且刷到的资源又被转换成了其他资源不好追溯,那么不得已只能使用最后的保留手段——回档。这对玩家体验无疑是巨大的伤害。

再让我们考虑改回先减后增的顺序。如果在deliverCommodity这一步报错,那么会造成玩家花了钱却没能获得商品。这样的影响相对可控,因为玩家尝试过几次之后就会发现问题而主动停下来,即使没有发现,等钱花完也会被迫停下来。更重要的是,数据在事后是可恢复的,只需要检查报错日志和接口日志,就能计算出玩家错误扣除的金币数额,再给玩家补上,而不像刷资源那样只能使用回档的方式来暴力解决。所以,先减后增优于先增后减的第一个理由是,前者在代码出错时造成的影响更小更可控。

很多游戏服务器使用Actor模型来开发,这样可以避免加锁和线程同步的烦恼。不过,Actor模型也引入了其他并发模型下所没有的一些陷阱,常见的例如,Actor异步通信下接口执行不再保证原子性,而可能分步乱序执行。在这种情况下,先减后增和先增后减两种逻辑顺序也会带来不同的结果。

让我们看一个为公会捐钱的例子。玩家加入公会后,可以为公会捐钱,让公会变得更强。这个过程是钱从玩家手中转移到公会下面,用Skynet来写就是:

function command.endow(player, endow_num)
    if player.money < endow_num then   -- 如果玩家持有的金币数不够,直接返回
        return
    end
    local success = skynet.call(union, "lua", "endow",  endow_num);	-- 向公会agent请求捐款
    if success then
        player.money = player.money - endow_num
    end
end

以上代码是按照先增后减的顺序,即先向公会agent请求,让公会得到这笔钱,然后如果捐款成功,那么再扣除自己的钱。

这样写的问题在于,Skynet在处理阻塞操作时,会暂停当前协程的执行,转而执行别的协程逻辑,直到阻塞操作返回才从暂停上下文重新开始执行。如果在执行别的协程逻辑时,恰好遇到了一个扣玩家钱的操作,如购买商品,那么可能导致后面再实际扣捐款钱时已经不够,钱扣成负的。

解决办法是调整逻辑顺序,改为先减后增的顺序,即先行扣除要捐的钱,再向公会agent请求捐款,如果捐款失败,那么再把钱返还给玩家。具体代码如下:

function command.endow(player, endow_num)
    if player.money < endow_num then   -- 如果玩家持有的金币数不够,直接返回
        return
    end
    player.money = player.money - endow_num	-- 先扣钱
    local success = skynet.call(union, "lua", "endow",  endow_num);	-- 向公会agent请求捐款
    if not success then	-- 如果捐款失败,再把钱加回来
        player.money = player.money + endow_num
    end
end

这里不难得出先减后增更优的第二个理由:在Actor模型下,先减后增有助于避免异步通信下接口乱序执行带来的逻辑错误。

全国充电站分布数据 CnOpenData推出的充电站数据覆盖全国34个省份的3万条数据,包含充电站名称、省份名称、省份代码、商圈、经纬度等地理信息以及商业类型、评分、消费等衍生信息,能为城市规划、环境科学、市场分析、技术发展和社会经济研究等多个领域提供宝贵的数据支持。 阅读详情

相关推荐

基于PCA的故障诊断方法(matlab)

1. PCA原理分析 PCA的原理主要是将原始数据进行降维。其具体工作原理参照:CodingLabs - PCA的数学原理 2. 数据预处理 训练数据集(只有正样本)为维数据,即有n个采样值,每个采样值有m个特征。 2.1 数据归一化 将数据X针对每个特征归一化为均值为0,均方根为1的数据。 其中: 3. PCA降维 3.1 首先求取协方差矩阵 协方差矩阵的公式为: 计算出来的协方差矩阵为特征m*m维矩阵。 3.2 求取特征值和特征向量 求取协方差矩阵R的特征值.

tangxianyu的博客 1万+

【Unity知识速递】第7期 Unity 6.6 深度解析:WebGPU 正式版与 WebAssembly64,Web 游戏的内存革命

如何启用 Wasm64?需要注意的是,Wasm64 需要浏览器支持 Memory64 提案,目前主流浏览器的最新版本都已支持。一句话总结: Unity 6.6 用 WebGPU 转正、Wasm64 16GB 内存和渐进式加载三连击,将 Web 游戏的体验天花板又往上推了一大截——Web 平台不再是"妥协版",正在成为真正的一等公民。Unity 6.6 新增了 WebAssembly64(Wasm64) 构建选项,这可能是本次更新中对 Web 游戏开发者影响最大的一项升级。

crystal_WJT的博客 425

Streamlit(九) widgets-input

st.text_input / st.number_input / st.date_input / st.time_input 源码路径:${python}\Lib\site-packages\streamlit\elements\text_widgets.py(number_input.py, time_widgets.py) st.text_input st.text_input(label, value="", max_chars=None, key=None,\

heianduck的博客 3354

设计模式(unity游戏研发版)

当你使用图形用户界面类时通常会遇到一个问题。比如,你创建了自定义按钮类并允许客户端在按钮中注入自定义代码,这样当用户按下按钮时就会触发这些代码。观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。你可在按钮中添加订阅机制,允许客户端通过自定义订阅类注入自定义代码。在Unity中,这就像UnityEvent在Inspector中绑定多个回调。

m0_63330263的博客 99

PyCharm 2023最新版安装配置全攻略(附永久激活教程)

本文详细介绍了PyCharm 2023最新版的安装配置全流程,包括版本选择、初始配置、插件生态、工程模板、调试优化及团队协作等关键步骤。特别针对专业版和社区版的功能差异进行对比,帮助开发者高效搭建Python开发环境,提升编码效率与团队协作能力。

p4q5r6s7t的博客 869

一文讲清CAN和CANFD的区别

本文将从技术原理、协议特性到应用场景,深度解析两者的核心差异。

文章主要涉及嵌入式软件开发、测试、项目管理等,欢迎交流,共同进步。 3209

我给 DeepSeek 大肥鱼做了一款马里奥式闯关游戏

当全网都在把大肥鱼做成直播虚拟主播的时候,我决定给她做一款横版闯关游戏。

2301_79028807的博客 897

canoe安装完成开启之后因为VectorDeviceParams30_64.dll报错崩溃打不开...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值。

**My Coding Family** 1079

Claude Fable 5.2 登顶:65 分、单发做游戏,和一份 $26.54 一单的账单

Anthropic 发布 Claude Fable 5.2:AA 智能指数 65 分登顶历史第一,但性能 #71、成本 #73、冗余度 #72——最强能力、最贵成本、最慢速度的矛盾体。同底层 Mythos 5.2 无护栏反而更强。文章拆解:65 分构成、官方实战验收、基准提升真伪、一条提示词一晚做出街机游戏的完整流水线(自写机器人跑完 12 关自检)、$26.54 账单与 98% 缓存折扣下的真实成本重估。

johnsong2009的博客 229

车载以太网:PHY(物理层)介绍

本文以TJA1101芯片为实例介绍了车载以太网PHY(物理层)组成。

kevin1499的博客 6231

WiFi基本概念(六)(L-STF,L-LTF)

L-STF它由10个OFDM symbol(1,0,1,0,1,0,1,0,1,0)构成,每个symbol是0.8us,GI是0.2us,总计10us。Symbol的长度是正常长度的1/4,因此称为Short training field,主要用于快速进行信号检测,信号同步,自动增益控制,接收天线选择(Diversity Selection)。 由于symbol长度是正常的1/4,子载波的宽度是正常的4倍,能进行初略的信道估计,其使用了-24, -20, -16, -12, -8, -4, 4, 8, 1

reekyli的专栏 6863

Unity 数据存储指南:本地存储、个性化设置、缓存与 Resources/StreamingAssets 的区别

在 Unity 开发中,“数据存到哪里”、“缓存能不能清”、“打包后资源有什么区别” 是新手最容易混淆、老手也经常踩坑的问题。Unity 本地存储机制(包括 Unity 放在 C 盘的内容);Unity 个性化设置(编辑器首选项 Editor Preferences);Unity 缓存的打开、关闭与清理;打包后 Resources 与 StreamingAssets 的区别;其他可自定义存储的内容汇总。为方便理解,本文配有一个可直接运行的演示工程,所有代码见文末"配套工程说明"。

zhchyun 209

基于OpenCV实现暗通道先验去雾算法及改进,效果惊人

深度技术文,前方高能

公号:一条coding 2万+

Claude Code做Unity项目移植(三): 使用SKILL进行自动化Git提交

本文介绍基于ClaudeCodeSkill的Unity自动化Git提交助手——unity-git-commit,通过四大模块实现提交前的智能检查与安全修复:1)校验Git仓库状态;2)验证Unity项目文件(如排除Library/Temp,确保.meta文件完整);3)依据可配置的C#命名规范自动识别并安全修复命名问题(避免序列化、反射等高危场景误改);4)生成精准提交注释,但强制人工确认。全程仅本地commit,不自动推送或破坏性操作,保障安全。核心思想为“机械化工作交AI,关键决策留人工”,显著提升提交

Aman1984的博客 643

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

HarmonyOS 游戏与图形渲染入门:Canvas、渲染管线与掉帧排查

本文详解鸿蒙图形渲染选型与优化,指出多数“游戏感”需求仅需Canvas+requestAnimationFrame即可实现。通过deltaTime保证跨设备流畅性,优先使用animateTo声明式动画,避免逐帧绘制开销。强调性能优化应从主线程长任务、过度绘制、对象分配入手,结合Profiler排查掉帧。XComponent适用于高负载场景,但需权衡开发成本。最后提醒引擎迁移三要点:性能模型差异、打包流程匹配、版本兼容。核心结论:先用简单方案验证,再决定是否上引擎。

信息安全领域优质创作者|操作系统领域专家 411

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Windows远程桌面实现之二十:实现 moonlight 游戏串流协议之(一)

本文介绍在xdisp_virt中集成Moonlight游戏串流协议的实现过程。基于开源项目Sunshine逆向的GameStream协议,作者从零研究并自研实现Moonlight服务端网络通信部分,涵盖mDNS设备发现、nvhttp/nvhttps加密通信、nvrtsp协议交互及三类UDP数据通道(视频、音频、控制)。重点解决多客户端并发问题,采用串行处理机制确保连接一致性。通过自定义证书验证与密钥管理,完成配对与安全通信,最终实现低延迟、高性能的游戏串流体验,显著优于WebRTC浏览器方案。

fanxiushu的专栏 167

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

二进制木马免杀-游戏嵌套与图标替换

二进制木马免杀-游戏嵌套与图标替换

2503_94637398的博客 236

mark 黑塞《玻璃球游戏》

【最近在读黑塞的《玻璃球游戏》-“ai预言“ - 优快云 App】

2502_94306440的博客 192

Cocos Creator3.8.8 + Xcode27.2 编译运行失败

Cocos Creator3.8构建IOS工程后,使用最新的Xcode27.2版本进行真机调试,遇到C++标准库冲突,如is_floating_point、is_arithmetic和is_signed失败,以及webp对齐失败等问题。

HYNN12的博客 399

给 AI 一台贴图工厂:TexGen 程序化贴图引擎与 MCP 架构实践

但它很快就撞墙——一张贴图往往是多层叠加的:底色 + 噪波 + 砖缝 + 暗角 + 高光。所以 TexGen 的核心抽象是图层栈 + JSON 指令表codeTgSpec├── 几何: shape(8 种) + center / size / radius / rotation / cornerRadius├── 绘制: fill(7 种) + color / edgeColor / 渐变 + pattern + warp└── 合成: blend(11 种) + opacity / blur。

邹杭特的博客 372

(开源)游戏攻略分享系统实战指南 基于 Java + SpringBoot + uni-app + Vue + MySQL

这是一个基于 Java + SpringBoot + uni-app + Vue + MySQL 构建的完整游戏攻略分享系统,功能持续优化中...游戏攻略管理 游戏分类管理 旅游资讯管理 用户管理 管理员管理

小小码农身兼魔法师职位!除你武器~ 330

itch.io 用开源模拟器 Ruffle 恢复 Flash 游戏支持

itch.io 创始人宣布平台已用开源 Flash 模拟器 Ruffle 重新实现 Flash 游戏支持,现有 2,581 款 Flash 游戏,开发者无需改动现有项目。

老孙正经胡说 109

老题新解|NOIP 2008 普及组 T3:传球游戏

传球游戏是 NOIP 2008 普及组 T3,核心是「环形边界用取模处理」的二维 DP。本文给出状态定义 + 转移推导 + C++14 代码 + 易错点清单,代码可直接提交主流评测平台。

ZLOJ 343

游戏支付通道安全吗?靠谱吗?

资质之外,商家还可以查看通道方的清算背景和合作机构,多方信息交叉验证,判断更准确,正规的通道方经得起多方核实,信息越透明,合作越放心,这是选择安全通道的基本功课,交叉验证后的判断更可靠,正规通道的信息透明,查证过程本身就是信心的来源,合作更踏实,每一步都有依据,核实越细,信心越足。安全配合要落到实处,商家如实上报异常情况,通道方及时处理反馈,双方信息互通,风险才能及时化解,安全不是单方面的承诺,而是双方协作的结果,配合越紧密,保障越到位,双方信息互通,安全网越牢固,风险越小,信息互通有无,风险共同化解。

jingyun_2026的博客 84

云游戏边缘节点部署架构与机房选址实践:网络拓扑、GPU选型与延迟优化

云游戏边缘节点部署需系统优化端到端延迟:机房选址应控制光纤距离以压低RTT(<1ms/100km),优先双运营商接入;网络拓扑推荐三层ECMP或EVPN-VXLAN,保障收敛速度与故障隔离;GPU选型依编码需求——T4/L4适配H.264/AV1,A10支持高密度编码。三者协同,方能实现50–80ms延迟目标。

2601_96920793的博客 357

unity3d 程序部署Hololens2的错误

在unity3d中重新发布时重新搞一下,参考下面。

moonlightpeng的博客 37
上一篇: 近年GDC服务器分享合集(二): 《太空工程师》中基于预测物理的多人游戏
下一篇: 近年GDC服务器分享合集(三): 《Sky光·遇》实现百万在线:一种云原生的扩容方法
长三月
博客等级 码龄9年 228粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值