graph TD
A["比赛结束"] --> B["获取双方 ELO"]
B --> C{"Lua 脚本可用?"}
C -->|"是"| D["Lua VM 计算 delta"]
C -->|"否"| E["Go builtinELO 计算"]
D --> F["Redis Pipeline 原子更新"]
E --> F
F --> G["更新 ELO 分"]
F --> H["更新赛季排行榜"]
F --> I["记录比赛历史"]
双引擎:Lua 优先,Go 兜底
为什么需要 Lua 热更新?因为游戏上线后,ELO 的 K 值、段位阈值、赛季奖励规则可能需要频繁调整。如果每次改参数都要重新编译、部署、重启服务器,运维成本太高。
var da, db int if s.luaVM != nil { // 优先用 Lua 脚本计算 result, err := s.luaVM.Call("calculate", ra, rb, outcome) if err == nil { da, db = result[0], result[1] } else { // Lua 失败,回退到 Go 内置 da, db = builtinELO(ra, rb, outcome) } } else { da, db = builtinELO(ra, rb, outcome) }
-- scripts/elo.lua functioncalculate(ra, rb, outcome) local k = 32-- 可以随时改 K 值 local ea = 1 / (1 + 10 ^ ((rb - ra) / 400)) local eb = 1 - ea local sa, sb if outcome == "a_win"then sa, sb = 1, 0 elseif outcome == "b_win"then sa, sb = 0, 1 else sa, sb = 0.5, 0.5 end returnmath.floor(k * (sa - ea) + 0.5), math.floor(k * (sb - eb) + 0.5) end
functierForELO(elo int) Tier { switch { case elo >= 2500: return TierDiamond case elo >= 2000: return TierPlatinum case elo >= 1500: return TierGold case elo >= 1000: return TierSilver default: return TierBronze } }