物品、库存与经济系统
“经济”在 CS:GO 代码里有两层含义,必须分开理解:
- 回合金钱:每回合的购买资金
m_iAccount、团队奖励、连败补偿——属于玩法规则,见 玩家 与 规则与回合。 - 物品经济(econ):物品定义 schema、玩家库存与装备栏位、物品属性、与 Game Coordinator(GC)的同步——本页主题。
相关页面:武器与射击 · 特殊武器机制 · 匹配与 GC · 审计
相关源码文件#
- 通用 econ:
game/shared/econ/(19 个.cpp),核心game/shared/econ/econ_item_schema.cpp、game/shared/econ/econ_item_system.cpp、game/shared/econ/econ_item_inventory.cpp、game/shared/econ/econ_item_view.cpp、game/shared/econ/attribute_manager.h - CS:GO 派生:
game/shared/cstrike15/cstrike15_item_schema.h、game/shared/cstrike15/cstrike15_item_system.h、game/shared/cstrike15/cstrike15_item_inventory.h - 工程:
game/client/client_econ_base.vpc、game/server/server_econ_base.vpc
1. README 与代码的差异(文档漂移)#
根目录 README 声称“经济源码在泄露前已被移除”:README.md:3。但仓库实际包含 econ 实现,并被两端工程编译:client 与 server 的 econ 基础工程都列出 econ_item_schema.cpp、econ_item_inventory.cpp、econ_item_system.cpp 等文件,并 include GC SDK 的游戏侧配置:game/client/client_econ_base.vpc、game/server/server_econ_base.vpc;CS:GO 派生类同样被两端编译:game/client/client_cstrike15.vpc:122-128、game/server/server_cstrike15_inc.vpc:63-71。
更准确的描述是:econ 代码存在但被部分裁剪。econ 相关文件中有多处 Removed for partner depot 标记(例如 econ_item_inventory.cpp 11 处、econ_item_schema.cpp 7 处、econ_item_view.cpp 4 处),GC 后端与 gc_clientsystem.h 缺失(见 匹配与 GC)。
2. 类型层次#
| 通用类 | CS:GO 派生 | 职责 | 证据 |
|---|---|---|---|
CEconItemSchema | CCStrike15ItemSchema | 物品/属性/品质等定义表 | game/shared/cstrike15/cstrike15_item_schema.h:79 |
CEconItemDefinition | CCStrike15ItemDefinition | 单个物品定义(含装备栏位) | game/shared/cstrike15/cstrike15_item_schema.h:19 |
CEconItemSystem | CCStrike15ItemSystem | 持有 schema,生成物品 | game/shared/cstrike15/cstrike15_item_system.h:32 |
CPlayerInventory | CCSPlayerInventory | 玩家库存与装备栏位查询 | game/shared/cstrike15/cstrike15_item_inventory.h:32 |
注意:cs_item_inventory.h 中也定义了一个同名的 CCSPlayerInventory,但两端工程编译的是 cstrike15_item_inventory.*:game/shared/cstrike15/cs_item_inventory.h:70、game/client/client_cstrike15.vpc:122-123。
3. Schema 的加载路径#
CEconItemSchema::BInit(file, pathID)用 KeyValues 读取文件;客户端还会尝试加载同名的_live补充文件:game/shared/econ/econ_item_schema.cpp:5804-5830。- 物品定义查找:按索引查表,找不到时根据
bNoDefault返回NULL或默认定义;在CSTRIKE_DLL下没有默认定义时返回NULL:game/shared/econ/econ_item_schema.cpp:8501-8531。按名字查找为线性遍历:game/shared/econ/econ_item_schema.cpp:8538-8559。 - GC 下发:
CGCUpdateItemSchema作业在非公共宇宙且带-use_local_item_data时从本地scripts/items/items_game.txt加载,否则接受 GC 直接下发的数据或通过 HTTP 下载:game/shared/econ/econ_item_system.cpp:472-560。但该作业被#if GC_UPDATE_ITEM_SCHEMA_SUPPORTED包裹,而本仓库中没有任何地方定义这个宏(本次全仓检索),因此该路径在当前快照中不会被编译(推断:未定义的宏在#if中视为 0)。 CEconItemSystem::Init只在客户端触发item_schema_initialized事件:game/shared/econ/econ_item_system.cpp:96-105;它由库存管理器的PostInit调用:game/shared/econ/econ_item_inventory.cpp:314-318。ParseItemSchemaFile在仓库中没有调用者:game/shared/econ/econ_item_system.cpp:238-250。- 服务端有一个隐藏的开发命令
load_master_item_schema从items_master.txt重载 schema(公共宇宙中无效):game/shared/econ/econ_item_schema.cpp:8948-8970。
异常代码:
CItemLevelingDefinition的析构函数在释放字符串后调用GEconItemSchema().BInit( "scripts/items/unencrypted/items_master.txt", ... ):game/shared/econ/econ_item_schema.cpp:8909-8922。在析构函数中重新初始化整个 schema 不符合常规语义,这很可能是裁剪/拼接产生的残留,应视为不可信代码(推断)。
3.1 候选加载入口逐一排查(审计 U1)#
schema 对象是 CEconItemSystem 的成员 m_itemSchema,GetItemSchema() 只返回它的地址,没有懒加载:game/shared/econ/econ_item_system.h:93、game/shared/econ/econ_item_system.h:114。CS:GO 派生的 CCStrike15ItemSchema::BInitSchema 只是转调基类,本身不读文件:game/shared/cstrike15/cstrike15_item_schema.cpp:776-778。全仓检索所有能填充它的入口(BInit、BInitTextBuffer、BInitBinaryBuffer、MaybeInitFromBuffer、BInitFromDelayedBuffer)后:
| 入口 | 在客户端/服务端游戏 DLL 中的状态 | 证据 |
|---|---|---|
CEconItemSystem::ParseItemSchemaFile | 全仓没有调用者 | game/shared/econ/econ_item_system.cpp:238-250 |
CEconItemSystem::Init(由库存管理器 PostInit 调用) | 不读文件,只在客户端触发 item_schema_initialized 事件 | game/shared/econ/econ_item_system.cpp:96-105、game/shared/econ/econ_item_inventory.cpp:314-318 |
| GC 更新作业与 HTTP 下载回调 | 整段位于 #if GC_UPDATE_ITEM_SCHEMA_SUPPORTED 至 #endif 之间,宏全仓无定义;MaybeInitFromBuffer 的两个调用者都在这段里 | game/shared/econ/econ_item_system.cpp:472、game/shared/econ/econ_item_system.cpp:542、game/shared/econ/econ_item_system.cpp:631、game/shared/econ/econ_item_system.cpp:645 |
MaybeInitFromBuffer / BInitFromDelayedBuffer | 后者只被前者在客户端“未进入游戏”时调用;前者没有其他调用者 | game/shared/econ/econ_item_schema.cpp:5904-5935 |
开发命令 load_master_item_schema | 隐藏、作弊、仅开发;公共宇宙中直接返回 | game/shared/econ/econ_item_schema.cpp:8948-8970 |
~CItemLevelingDefinition 中的 BInit | 只在等级定义对象被销毁时执行;但 Reset 对等级表只 Purge 指针(PurgeAndDeleteElements 已被注释),BInitItemLevels 也只 RemoveAll,存放等级定义的向量从未被删除,因此按代码推断该析构在正常流程中不会运行 | game/shared/econ/econ_item_schema.cpp:8909-8922、game/shared/econ/econ_item_schema.cpp:5728-5729、game/shared/econ/econ_item_schema.cpp:8005-8020 |
CEconItemFactory::BYieldingInit | GC 端代码(含 SQL 查询);全仓 VPC 检索未发现游戏工程编译该文件 | game/shared/econ/econ_item_factory.cpp:42-65 |
此外,cdll_client_int.cpp 与 cs_gameinterface.cpp 中共 18 处裁剪点所在的函数,分别与 GC 信息与预约、连接与文件校验、比赛证据与 Demo 回放、UI 事件或 Scaleform 插槽有关,没有一个是 DLL 初始化函数,例如 game/server/cstrike15/cs_gameinterface.cpp:149-151、game/client/cdll_client_int.cpp:4799-4801(本次逐一查看了两文件的全部裁剪点)。
结论(仍未决,但已收窄):在本快照的客户端/服务端游戏 DLL 中,找不到任何在正常启动时向 m_itemSchema 填充数据的代码路径:接收 GC/HTTP 数据或按需读本地文件的 GC 作业被未定义宏编译掉,其余入口要么无人调用、要么是开发命令或按代码推断不可达的析构。缺少的证据是:原始版本中加载 schema 的代码(若存在,推断已在裁剪中删除),或运行时日志。若 schema 为空,所有经 FX_FireBullets 的射击会在查物品定义时提前返回,见 特殊武器机制 第 11 节(推断,未运行验证)。武器数值另有一条不依赖 schema 的回退:属性访问器在物品视图上查不到属性时读武器脚本字段 game/shared/cstrike15/cs_weapon_parse.cpp:1060-1093;武器脚本由自动注册的游戏系统 CWeaponDatabase 在 Init 时按 scripts/weapon_manifest.txt 清单独立加载 game/shared/weapon_parse.h:226、game/shared/weapon_parse.cpp:524-528、game/shared/weapon_parse.cpp:538。但 FX_FireBullets 在用到这些数据之前就先查物品定义,因此这条回退救不了射击路径。
4. 物品如何影响玩法#
- 购买:购买流程先通过库存的装备栏位找到物品定义,再据此决定实际发放的武器;竞技模式使用开局缓存的装备,保证整场一致:
game/server/cstrike15/cs_player.cpp:7689-7693、game/server/cstrike15/cs_player.cpp:7733-7744、game/server/cstrike15/cs_player.cpp:7908-7960。 - 属性钩子:武器数值可被物品属性修改,例如连发与开镜时的射击间隔:
game/shared/cstrike15/weapon_csbasegun.cpp:321-334;宏定义见game/shared/econ/attribute_manager.h:35。 - 武器数据读取:伤害、射程、穿透等都以
CEconItemView*为参数读取:game/shared/cstrike15/fx_cs_shared.cpp:336-343。
5. 与 GC 的协议#
物品 schema 更新消息 CMsgUpdateItemSchema 定义在通用 GC 消息中:game/shared/base_gcmessages.proto:467。CS:GO 专有 GC 消息见 匹配与 GC。
约束与边界#
items_game.txt、items_master.txt等 schema 文件不在仓库中。- 审计 U1(schema 在正常启动时如何加载)仍未决,候选入口的排查结果见第 3.1 节;射击传入物品定义索引 0 的后果(U2)见 特殊武器机制。
- 未展开物品描述(
econ_item_description.cpp)、交易/开箱、贴纸/涂装等功能;它们大量依赖被裁剪的部分与 GC。