VIP 結算異常說明

發生日期:2026-07-01 凌晨 00:00
影響範圍:24,668 位應降級玩家
修正完成時間:2026-07-01 15:00


一、問題描述

每季 VIP 等級結算時(每 3 個月一次),系統會檢查玩家的保級值是否達標:

本次結算中,應降級的玩家等級沒有正確降低,但經驗值被重置為降級後的數值。導致玩家看到的現象是:


二、影響人數與處理結果

項目 數量
應降級玩家 24,668 人
等級已修正 24,668 人(全部修正完成)
多發獎勵信已刪除 59,785 封
正確獎勵已補發 21,791 封
已領取錯誤獎勵無法追回 673 組(586 人)

三、多發獎勵無法追回的損失

有 673 組玩家(586 人)在修正前已領取了錯誤等級的獎勵,這部分無法追回。淨損失如下:

道具 多發數量
瘋頑票i幣 48,490
小紅扭蛋幣 360
小藍扭蛋幣 374
小黑扭蛋幣 257
小黑十連抽扭蛋幣 603

已領取錯誤獎勵的等級分佈:

等級 組數 實際發的(錯誤) 應該發的(正確)
VIP4→VIP3 129 i幣x10, 小紅x1
VIP5→VIP4 217 i幣x20, 小紅x2, 小藍x1 i幣x10, 小紅x1
VIP6→VIP5 173 i幣x50, 小藍x2, 小黑x1 i幣x20, 小紅x2, 小藍x1
VIP7→VIP6 100 i幣x300, 小黑x2, 十連x1 i幣x50, 小藍x2, 小黑x1
VIP8→VIP7 42 i幣x500, 十連x10 i幣x300, 小黑x2, 十連x1
VIP9→VIP8 12 i幣x1000, 十連x20 i幣x500, 十連x10

四、各等級降級人數

降級情況 人數
VIP4 → VIP3 14,698
VIP5 → VIP4 7,216
VIP6 → VIP5 2,252
VIP7 → VIP6 404
VIP8 → VIP7 73
VIP9 → VIP8 25

五、原因說明

系統在今年初從舊版環境(Python 2)升級到新版環境(Python 3)。程式碼本身沒有改動,但 Python 語言本身的底層行為在版本升級後有所不同。

具體來說,程式內部有一份「對照表」,用來把玩家資料存回資料庫。這份對照表裡有兩個名稱不同的欄位("level" 和 "vipLevel"),但它們都指向資料庫中同一個位置。在降級時,程式只更新了 "level" 而沒有同步更新 "vipLevel"。

簡單來說,同一段程式碼原本靠「運氣好」才正確運作,升級環境後運氣不再,潛藏的問題就暴露了。


技術細節(程式碼說明)

問題架構圖

flowchart TD A[VIP 結算開始] --> B[玩家保級值不足] B --> C["player['level'] -= 1<br/>(降級:6 → 5)"] C --> D["player['vipLevel'] 仍為 6<br/>(未同步更新)"] D --> E[呼叫 updatePlayer 寫入 DB] E --> F[convertToDBFormat 遍歷對照表] F --> G{Python 版本?} G -->|Python 2<br/>順序隨機| H["可能順序:<br/>1. vipLevel=6 → DB<br/>2. level=5 → DB(覆蓋)"] G -->|Python 3<br/>插入順序| I["固定順序:<br/>1. level=5 → DB<br/>2. vipLevel=6 → DB(覆蓋)"] H --> J[DB 最終值 = 5 ✓ 正確] I --> K[DB 最終值 = 6 ✗ 錯誤] style J fill:#90EE90 style K fill:#FFB6C1

對照表覆蓋問題

flowchart LR subgraph 對照表 PLAYER_WITH_STORE_DB_TABLE L1["'level' → 'platformInfo.level'"] L2["'vipLevel' → 'platformInfo.level'"] end subgraph 記憶體中的 player dict P1["player['level'] = 5(已降級)"] P2["player['vipLevel'] = 6(未更新)"] end subgraph DB 寫入過程 Python 3 D1["第1步:platformInfo.level = 5"] D2["第2步:platformInfo.level = 6 ← 覆蓋!"] end P1 --> D1 P2 --> D2 style D2 fill:#FFB6C1

修正方式

flowchart TD A["player['level'] -= 1(降級:6 → 5)"] --> B["player['vipLevel'] = player['level']<br/>(加這行同步更新)"] B --> C[updatePlayer 寫入 DB] C --> D["level=5 → platformInfo.level = 5"] D --> E["vipLevel=5 → platformInfo.level = 5(相同值)"] E --> F[DB 最終值 = 5 ✓] style B fill:#90EE90 style F fill:#90EE90

對照表定義PlayerTableData.py):

PLAYER_WITH_STORE_DB_TABLE = {
    ...
    "level": "platformInfo.level",      # ← 第 72 行
    "vipLevel": "platformInfo.level",   # ← 第 73 行(指向同一個 DB 欄位)
    ...
}

"level" 和 "vipLevel" 都映射到資料庫的 platformInfo.level,寫入時後者會覆蓋前者。

降級程式碼ResetSettingSystem.py):

def _resetPlayer(self, player):
    ...
    player["level"] -= 1        # 降一級(例如 6 → 5)
    # 但 player["vipLevel"] 仍然是 6(沒有同步更新)
    ...
    self.server.playerSystem.updatePlayer(player)  # 寫入 DB

寫入 DB 時的行為差異

updatePlayer 會遍歷對照表,把 player 的值轉換成 DB 格式寫入:

Python 2(dict 順序隨機):
  → 可能先寫 vipLevel=6,再寫 level=5
  → DB 最終值 platformInfo.level = 5(正確)

Python 3(dict 保持插入順序):
  → 一定先寫 level=5,再寫 vipLevel=6
  → DB 最終值 platformInfo.level = 6(錯誤,被舊值覆蓋)

修正方式

player["level"] -= 1
player["vipLevel"] = player["level"]  # 加這行,同步更新

六、修正措施

  1. 即時修正:已將所有受影響玩家的等級修正為正確的降級後等級
  2. 獎勵修正:已刪除多發的獎勵信件,並重新發送正確等級的獎勵
  3. 補發信件修正:補發信件初始設定了錯誤的領取模式(recvMode),導致玩家看到信件但無法領取扭蛋幣,已修正為正確模式
  4. 已讀未入帳修正:29 位玩家在修正前已點擊領取但道具未入帳,已將信件重置為未領取狀態,玩家可重新領取
  5. 已領取多發獎勵的玩家:313 組玩家已領取原等級獎勵且無法追回,不再重複補發
  6. 保級獎勵誤刪補發:刪除多發信件時條件以 playerNum 為單位,導致同一玩家在其他店家的「保級獎勵」也被連帶刪除。已比對備份機資料確認缺失清單,補發 1,754 封保級獎勵信(678 組玩家+店家)
  7. 程式修正:已修正程式碼,下次結算(2026-10-01)不會再發生此問題

七、保級獎勵誤刪補發明細

原因:同一位玩家可能在 A 店降級、B 店保級。刪除多發信件時以 playerNum 過濾,連帶把 B 店的正確保級獎勵也刪除了。

項目 數量
被誤刪的保級獎勵信 1,754 封
涉及玩家+店家組合 678 組

補發等級分佈:

等級 信件數
VIP4 保級 550 封
VIP5 保級 747 封
VIP6 保級 369 封
VIP7 保級 78 封
VIP8 保級 6 封
VIP9 保級 4 封

補發道具總量:

道具 數量
瘋頑票i幣 25,180
小紅扭蛋幣 773
小藍扭蛋幣 495
小黑扭蛋幣 175
小黑十連抽扭蛋幣 96

八、相關檔案

檔案 說明
vip_reset_check_20260701_142613.csv 修正前全部降級玩家檢查清單
vip_reset_fix_20260701_144950.csv 修正執行結果(含已領取標記)
vip_over_received_20260701.csv 已領取無法追回的玩家明細(573 筆)
vip_deleted_mails_detail_20260701.csv 被刪除的信件備份明細
vip_resend_reset_received_20260701.csv 已讀未入帳重置為未領取的信件明細(80 封/29 人)
vip_duplicate_resend_deleted_20260701.csv 已領舊獎勵又被重複補發,刪除的補發信明細(7 封/3 人)
vip_relegation_resend_check_20260701_180149.csv 保級獎勵誤刪檢查清單(1,754 封)
vip_relegation_resend_fix_*.csv 保級獎勵補發執行結果