在线联机原型全集:第 18 章 城市经营
城市经营(Economy & Async|Timed Jobs, Balancing)
- 类别:模拟经营 + 异步任务 + 事务一致性
- 目标:验证离线收益、建筑队列、生产—运输—消费闭环与可控通胀/通缩;在高并发下保证定时作业的幂等、可重试与顺序一致;建立经济平衡工具链与 A/B 调参流程。
- 原型代号:
proto-018-city-async-econ - 依赖模块:
proto-014-room-escape-sync(事件溯源/快照)、proto-015-mini-race-rollback(回放一致性思想)、proto-016-mini-moba(关键帧/快照增量) - 推荐语言栈:Server(Go/Java 优先,含定时作业器与经济模拟器),Client(TS/Unity)
- 协议栈:HTTP(建造/收取/离线回流)+ WebSocket(异步事件推送)+ Cron/DelayQueue(作业驱动)
- Tick/Clock:经济系统以墙钟时间为基准(服务器可信时间),逻辑分桶(1s/5s/1m)
1. 核心玩法与范围
-
城市要素:住宅、工厂、农场、发电厂、仓库、道路/运输站、商业区、地标等。
-
资源体系:
电力/水/劳动力/原料/中间品/消费品/货币;维护费与税收。 -
异步循环:
- 产出:建筑以周期
T生产Q单位中间品/消费品; - 运输:消耗运输容量与道路通行(可拥堵衰减);
- 消费:居民/商业区消耗并回流货币或满意度;
- 维护:定时扣除维护费/折旧;
- 税收:结算周期(每日/每小时)征税与补贴。
- 产出:建筑以周期
-
离线收益:玩家离线时按封顶时长(如 8–12 小时)累计,回归时一次结算。
2. 异步/定时作业(Timed Jobs)
2.1 作业类型
- 生产作业:
Produce(building_id, start_ts, period, qty) - 维护作业:
Maintain(building_id, fee, interval) - 运输作业:
Ship(route_id, depart_ts, travel_time, capacity) - 税收作业:
Tax(city_id, interval) - 升级作业:
Upgrade(building_id, end_ts) - 离线补偿作业:
OfflineCatchup(city_id, last_seen_ts, now_ts)
2.2 调度器结构
- DelayQueue:以
next_run_ts为键; - 分片队列:按
city_id % N分片,提升并发; - 幂等键(Idempotency Key):
job_hash(city_id, type, window); - 重试策略:
exp-backoff(最多 K 次),失败落库并报警; - 事务边界:每个 job 在单事务内读/改/写,写入事件日志(Event)与账本(Ledger)。
2.3 幂等与顺序
- 幂等:作业先检查
ledger中是否存在相同job_id或window的账目,存在即跳过; - 顺序:同
city_id的作业串行;跨城并行;写前加版本号(city_versionCAS)保证单调性。
3. 经济模型(微观到宏观)
3.1 生产函数
-
单建筑
b:output_b = min(capacity_b, f(K_b, L_b, P_in_b)) × (1 - downtime_b)K_b:建筑等级/装备;L_b:分配劳动力;P_in_b:投入品;capacity_b:设计产能;downtime_b:停机率(缺电/缺料/维护)。
3.2 运输与损耗
- 运输量
ship_q = min(q_pending, route_capacity × traffic_factor) - 拥堵
traffic_factor = clamp(1 - load/throughput, 0.4, 1) - 损耗
loss = ship_q × loss_rate(route_quality, distance)
3.3 定价与税费
- NPC 基础价:每种商品
base_price_g; - 动态浮动:
p_t = base × (1 + α·excess_demand - β·excess_supply)(软约束 ±20% 封顶); - 税收:
tax = sales × τ + property_fee(city_assets) × ρ; - 维护费:
maint = ∑ building.mcost(level)。
3.4 货币与通胀
-
M(货币存量)与V(交易频率)决定通胀趋势;设目标区间π_target ∈ [1%, 4%]:- 若
π > π_hi:提高维护费/税率、降低 NPC 采购价; - 若
π < π_lo:临时补贴、提高 NPC 采购价、开“市政项目”回收产能。
- 若
-
封装为政策函数:
policy(M,V,π) -> {τ, subsidy, base_price_adjust}(见 §7 调参工具)。
4. 账户与账本(Accounting)
4.1 账户体系
city_wallet:货币余额;resource_stock[x]:资源库存;power_grid/water_grid:容量与负载;labor_pool:可用劳动力与工资支出;loan(可选)与利息。
4.2 账本结构(双录)
- 记账分录:
{entry_id, city_id, ts, account_debit, account_credit, amount, ref(job_id/event_id)} - 不可逆:只增不删;对冲通过反向分录;
- 一致性:每个作业成功 → 必有平衡分录(借贷相等)。
4.3 典型分录
- 生产入库:
WIP → Inventory[good] - 销售:
Inventory → Wallet,同时计税:Wallet → TaxPayable - 维护:
Wallet → Expense:Maintenance - 电力购买(若电网不足):
Wallet → Utility:Power
5. 离线收益与回归
5.1 离线封顶与曲线
- 封顶时长:
T_cap(如 10h); - 效率衰减曲线:
eff(t) = 1 - γ·(t/T_cap)^2(缓慢衰减,避免长期挂机过强); - 离线结算:按片段 [last_seen, now] 切分到各作业窗口,按
eff(t)折减。
5.2 恢复流程
- 客户端上报
last_seen_ts; - 服务器生成
OfflineCatchup作业; - 作业按窗口遍历所有建筑/运输/维护/税收→累计账本、库存与货币;
- 写入事件包
OfflineReward,一次推送并在客户端 UI 分段展示(生产/销售/维护/税收)。
6. 数据结构与协议
6.1 主要表
cities(id, owner, version, wallet, power_cap, water_cap, last_seen)buildings(id, city_id, type, level, state, slot_ts, cycle_sec, input, output, buffs)routes(id, city_id, from_b, to_b, cap, quality, distance)jobs(id, shard, city_id, type, next_run_ts, status, idempo_key, payload)ledger(entry_id, city_id, ts, debit, credit, amount, ref)events(city_id, seq, ts, kind, payload)(用于回放)snapshots(city_id, ts, version, blob_uri)
6.2 客户端 API(示例)
// 建造(HTTP)
POST /build
{ "city":1, "type":"factory", "pos":[12,6], "level":1 }
// 收取(WS/HTTP)
POST /collect
{ "building":101, "ts_client":1731055201 }
// 订阅异步事件(WS)
{ "t":"sub", "city":1 }
{ "t":"evt", "k":"Produced", "b":101, "q":20, "ts":1731055205 }
{ "t":"evt", "k":"Shipped", "route":7, "q":15 }
{ "t":"evt", "k":"Tax", "amt":120 }
{ "t":"evt", "k":"OfflineReward", "prod":[...], "sales":[...], "maint":[...] }
7. 经济平衡(Balancing)与工具链
7.1 目标与约束
- 体验节奏:新手 10 分钟达成“首个闭环”(农场→工厂→商店);1 小时解锁电网/仓储;24 小时达到二级产业。
- 通胀控制:日波动 |π| ≤ 1.5%;长期
π落在目标区间。 - 产销平衡:中期库存周转天数在 0.5–2 天;不出现“永远缺原料/永远爆仓”。
7.2 指标体系(Dashboard)
- 宏观:
π(日通胀)、M(货币存量)、销额/GMV、库存周转、税收/补贴比; - 微观:
产能利用率、缺料率、停机时长、运输拥堵率、维护占比; - 玩家体验:
首闭环时间、离线回归收益中央値、付费/非付费差距。
7.3 调参流程(A/B)
-
选择实验维度:
周期 T、产出 Q、维护/税率、运输损耗、NPC 价格浮动系数 α/β; -
构建沙盒模拟器(见 §8),导入 24–72h 的人口行为流(上线→下线→回归节律);
-
评估目标函数:
J = w1·π_dev^2 + w2·stockout_rate + w3·idle_rate + w4·pay_gap(越小越好);
-
最优解上线为小流量(5–15%),监控 48h → 全量。
8. 经济模拟器(离线仿真)
- 输入:城市初始状态、N 名虚拟玩家行为(上线/下线、建造偏好、升级策略)、政策参数。
- 推进:以 1s/5s 步长模拟作业队列与经济流;
- 输出:宏/微观指标时间序列、库存/现金流曲线、拥堵热图;
- 一致性:与线上共享同一规则库与随机源,确保 A/B 与线上一致。
9. 事务与一致性
- 写路径:job 执行 → 账本分录(含 idempo_key)→ 事件日志 → 快照(每 5–10 分钟一次)
- 读路径:客户端读派发事件与聚合后的视图(如城市面板:余额、库存、产能);
- 校验:周期性生成
hash_city = H(wallet, stocks, power, water, jobs_cursor),客户端重连时比对。 - 并发写防冲突:对
city_id的变更以versionCAS;对building_id的作业使用资源锁。
10. 反作弊与风控
| 场景 | 风险 | 防护 |
|---|---|---|
| 改系统时间 | 伪造离线收益 | 以服务器时间为准;离线仅用于窗口分段 |
| 重放请求 | 重复收取 | 幂等键 + 账本查重 |
| 资源溢出 | 溢出/负库存 | 所有入库/出库经账本校验 + 下限保护 |
| 扫码刷产 | 多开/脚本 | 行为特征、速率限制、异常收益熔断 |
| 价格操纵 | 集体囤货 | NPC 价浮动 + 交易限频 + 税率随交易量阶梯增加 |
11. 客户端 UX 与可视化
- 时间条:建筑卡片显示“下一产出倒计时”,支持批量收取;
- 交通热力:道路/路线以颜色显示拥堵因子;
- 库存与现金流:折线图 + 阈值预警(爆仓/缺料);
- 政策面板:展示税率/补贴/价格浮动,并给出“若调整”的即时模拟预览(客户端本地小步模拟)。
12. 测试与验证
- 幂等/重试:为作业注入超时/故障,验证重复执行不产生双计;
- 一致性回放:同一事件流回放,
wallet/stock/hash一致; - 离线回归:构造 2h/8h/24h 离线,验证封顶与衰减;
- 压力:每秒 50k 作业触发(分片 64),p95 延迟 < 200ms;
- 经济稳定性:72h 仿真,π 在目标带内,库存周转合理;
- 边界:断电/缺水/仓满/断路,产能与损耗正确收敛。
13. 参考数值(初版)
| 建筑 | 周期 T |
产出 Q |
维护费 | 电力 | 劳动力 |
|---|---|---|---|---|---|
| 农场 | 60s | 粮 10 | 2 | 1 | 1 |
| 工厂 | 120s | 罐头 6(耗 粮 12) | 5 | 3 | 2 |
| 住宅 | 300s | 劳动力 +1(维护 -1 税 +1) | 1 | 1 | - |
| 商店 | 90s | 销售 罐头×2(返现) | 2 | 1 | 1 |
| 仓库 | - | +容量 200 | 1 | 1 | - |
| 发电厂 | 60s | +电 10(耗 燃料) | - | - | 2 |
以上用于原型演示,量级便于 A/B 快速迭代。
14. 迭代路线
| 版本 | 目标 | 要点 |
|---|---|---|
| v0.1 | 作业骨架 | DelayQueue + 幂等账本 + 单城串行 |
| v0.2 | 闭环跑通 | 农场→工厂→商店→税收→维护 |
| v0.3 | 运输与拥堵 | 路网/路线容量、损耗与热力图 |
| v0.4 | 离线收益 | 封顶/衰减、回归一键结算 |
| v0.5 | 平衡工具链 | 沙盒模拟器 + A/B 管道 + 指标看板 |
| v1.0 | 稳定与风控 | 大规模并发、反作弊、经济政策联动 |
15. MVP 勾选清单
- 建筑生产/升级/维护三件套(异步作业)
- 运输与仓储(容量、拥堵、损耗)
- 税收/补贴与维护费(周期结算)
- 账本与事件日志(幂等、可回放)
- 离线收益封顶与衰减
- 经济指标面板与 A/B 调参接口
- 断线恢复(城市快照 + 事件补齐 + 哈希校验)