源文件超过50行,已替换为不超过50行的伪代码。辅助函数为逻辑抽象,不直接执行。
1async function rollDice({ target, condition, amount, currency }) {2 // 先创建零金额记录;响应到达后才用返回金额更新。3 const identifier = ledger.create({ amount: 0, currency });45 try {6 const response = await gameClient.post("dice/roll", {7 target, condition, identifier, amount, currency8 });9 const bet = response.diceRoll;1011 await waitForMinimumRevealTime();12 ledger.applyResponse({13 identifier,14 amount: bet.amount,15 payout: bet.payout,16 currency: bet.currency17 });18 resultState.set(bet);19 return { ...bet, identifier };20 } catch (error) {21 ledger.rollback(identifier);22 throw error;23 }24}2526function finishPresentation(identifier) {27 ledger.markGameFinished(identifier);28 // 真实余额推送与本局状态满足同步条件后再清理记录。29 ledger.clearIfSynchronized(identifier);30}已确认说明
- Dice 默认 target=50.50、condition=above;由联动公式得到 chance=49.50%、payout=2.0000。amount store 初始为 0。
- target/change 更新 target 后重新计算 payout 与 chance;condition toggle 切换 above/below 并令 target=100-target,以保持胜率。
- 利润预览=格式化(amount*multiplier-amount)。请求成功后的本地 win flag 是 payoutMultiplier>=1;共享统计 classify 则 multiplier=1 为 draw、>1 win、<1 lose,不能把两者无条件当相同口径。
- Dice auto revealing entry 调用 finishGame,然后 instantResult 为真立即 TO_IDLE,否则400ms后 TO_IDLE;advanced revealing 的 finishGame 放在 exit。成功写结果,余额 settle 时机因此在两个模式略有差异。
- Dice mutation 从amount/currency/condition/target stores取值,create({amount:0,currency})产生identifier,再POST dice/roll。payload为 target、condition、identifier、amount、currency。成功返回diceRoll并补identifier;非instant等待请求开始至至少300ms。结果来自响应,前端此链未计算随机结果。
- 成功用返回amount/payout/currency做 optimisticBalanceUpdate;异常使用identifier rollback再reject。create 的amount为0,因此不能称Dice此处请求前就按实际下注金额扣款。finishGame稍后补GAME_FINISHED事件。
- UI依据xstate切 manual/automated/advanced;手动hotkey space多一层valid校验,q切condition,w/e以整数2..98调target且edgeStop不环绕。结果pastBets=[new,...old.slice(0,25)]最多26条;结果为0不会触发 if(s())的显示/声音 effect。
- 结果state.result与payoutMultiplier直接由bet响应写入stores,>=1控制positive状态。胜负判定没有对客户端target与result重新比较,依赖服务端倍率。