CatGunner CookbookBardCat 1.1.59 · L1 ANALYSIS · tài liệu học
Trang chủCookbook › 10 — Tiến trình & thang mở khoá
Nguồn: 10-tien-trinh-mo-khoa.md · Cập nhật lần cuối: 2026-09-06 22:46 +07 · sha256 nguồn 898ead25f408

10 — Tiến trình & thang mở khoá

Nguồn framework: docs/framework/07-progression-managers.md §2–§4, docs/framework/09-prestige-rebirth.md §2, §3.2, [liveops catalog: UNLOCK_GATES.md] §1–§5, [liveops catalog: SCREEN_CATALOG.md] §7, [liveops catalog: LIVEOPS_SURFACE.md] §4. Cấp bằng chứng: L1 ANALYSIS — dựng lại clean-room từ disasm + metadata + quan sát runtime; không phải source gốc. Mỗi dòng bên dưới mang nhãn bằng chứng riêng.

Mục tiêu

Bạn muốn làm một game idle có nhiều "phòng" (Rebirth, Mine, Fish, Boss, Pet, Hunt, Trip…) mở dần theo tiến độ, và mỗi phòng là một hệ thống nhỏ có nâng cấp, gacha, buff, nhiệm vụ riêng. Recipe này cho biết game gốc mở khoá bằng đúng một con số, tổ chức 35 hệ thống bằng một khuôn manager lặp lại, và cân bằng bằng bảng đã bake vào scene — kèm tất cả con số thật.

Game gốc làm gì

Biến cổng duy nhất và thang mở khoá 7 nút chính

Điều game làm Con số / hằng số Mức bằng chứng Nguồn
Biến cổng trung tâm là Tree_manager.Stage_Value_Max (field 0x30) Stage_Value = Level_Now + 10 × Stage_Now; Stage_Value_Max = giá trị cao nhất từng đạt VERIFIED Tree_manager.Game_Win RVA 0x2B452E4, lệnh 0x2B45520/0x2B45534; UNLOCK_GATES §1.2
Stage_Value_Max không bao giờ giảm — chỉ ghi khi >=, và Rebirth() không đụng tới monotonic VERIFIED UNLOCK_GATES §1.2; doc 09 §2
Mỗi stage có 5 level: Level_Now chạy 0..4, Stage_Now 0-based 5 level/stage VERIFIED Tree_manager.StageAdvance RVA 0x2B45820
UI hiển thị 1-based: "Stage {Stage_Now+1}-{Level_Now+1}" literal @0x5E94A48 VERIFIED GameSlider.Stage_Reload RVA 0x2B156E4
Hàm cổng: Locked_obj.SetActive(Stage_Value_Max < N) cho 7 nút 7 ngưỡng VERIFIED Tree_manager.Contents_Lock_Reload RVA 0x2B4441C
Hàm nút Content_Btn_* kiểm lại cùng ngưỡng; chưa đủ thì UI_manager.Alert(ScriptLocalization.Alarm.StageUnlock, <số stage>)đọc trọn 7 handler (G395): N = 3 / 4 / 6 / 10 / 12 / 12 / 35; Alert = round-robin 3 hộp cảnh báo (mọi cảnh báo từng câm trong bản dựng lại) 7 VERIFIED (cả tên lẫn số) UNLOCK_GATES §2; doc 07 §2.7 (G395)

Thang mở khoá (mọi ngưỡng là bội số của 10 ⇒ luôn mở ở level 1 của stage tương ứng):

# Feature (nhãn UI) Field ổ khoá Stage_Value_Max ≥ RVA SetActive Handler nút Mở tại stage hiển thị Mức
1 Rebirth Rebirth_manager.Rebirth_Btn_Locked_obj (0x30) 20 0x2B444EC Content_Btn_Rebirth 0x2B44B58 Stage 3-1 VERIFIED
2 Mine Mine_manager.Mine_Btn_Locked_obj (0x50) 30 0x2B44554 Content_Btn_Mine 0x2B44CE4 Stage 4-1 VERIFIED
3 Fish Fish_manager.Fish_Btn_Locked_obj (0x70) 50 0x2B44520 Content_Btn_Fish 0x2B44C10 Stage 6-1 VERIFIED
4 Boss Boss_manager.Boss_Btn_Locked_obj (0x38) 90 0x2B44598 Content_Btn_Boss 0x2B44DCC Stage 10-1 VERIFIED
5 Pet Pet_manager.Pet_Btn_Locked_obj (0x38) 110 0x2B445DC Content_Btn_Pet 0x2B44E94 Stage 12-1 VERIFIED
6 Hunt (Monster) Monster_manager.Monster_Btn_Locked_obj (0x30) 110 0x2B44620 Content_Btn_Monster 0x2B44F54 Stage 12-1 VERIFIED
7 Trip (Adventure) Adventure_manager.Adventure_Btn_Locked_obj (0x50) 340 0x2B4466C Content_Btn_Adventure 0x2B4501C Stage 35-1 VERIFIED

Đối chiếu độc lập: ảnh chụp save thật "Stage 5-4" ⇒ Stage_Value = 3 + 40 = 43 ⇒ Rebirth(20) và Mine(30) mở, Fish/Boss/Pet/Hunt/Trip khoá — khớp 100 % với ảnh (UNLOCK_GATES §1.5, VERIFIED).

Cổng phụ và nút không có cổng

Đối tượng Điều kiện Mức bằng chứng Nguồn
Nâng cấp Rebirth bằng IAP Stage_Value_Max > 988 (⇒ giá trị đạt được kế tiếp 990 ⇒ Stage hiển thị 100-1, quy đổi là suy luận) VERIFIED (ngưỡng) UpgradeRebirth_IAP_Unlocked_return RVA 0x2B232D0; const UpgradeRebirth_IAP_UnlockStageValue = 989 dump.cs:598987
Trip — mở từng map Adventure_manager.instance.Lv >= Adventure_Unlock_Balance[map] (theo Lv của Trip, MaxLv = 15, không phải stage); Adventure_Unlock_Balance = [0, 1, 3, 6, 10] VERIFIED (công thức) + runtime + metadata-proven (blob SHA, G353) is_Unlock_return RVA 0x2ADB684; doc 07 §2.9
Skin — mở từng skin num == 0 luôn mở; còn lại bool[] trong save VERIFIED Skin_manager.is_Unlock RVA 0x2B3F514
DiaPig static[+8] \|\| static[+9] của Shop_manager (2 cờ bool tĩnh) công thức VERIFIED; ý nghĩa 2 cờ UNKNOWN Shop_manager.is_DiaPig_Unlock RVA 0x2B27764
WeeklyShop VIP WeeklyShop.Is_VIP_Unlocked(); const int Unlock_Degree = 3 hằng VERIFIED; thân hàm chưa giải mã RVA 0x2B3EA58
StepUp banner const int Banner_Unlock_Degree = 2; Duration_Days = 7, StepCount = 5 hằng VERIFIED dump.cs class StepUp
PlusPack banner const int Banner_Stage_Min = 190 (⇒ Stage hiển thị 20-1) hằng VERIFIED dump.cs class PlusPack
Pet lock group khoá do người chơi tự đặt, không phải cổng tiến trình VERIFIED Pet_manager.IsPetLocked dump.cs:598030
Mission SequenceLocked / LuxuryLocked / VIPLocked gắn battle-pass Luxury/VIP cấu trúc VERIFIED; ngưỡng UNKNOWN dump.cs:587516, :587575-587576
Raid KHÔNG có cổng nào: không có Raid_Btn, không có mặt trong Contents_Lock_Reload VERIFIED (negative) SCREEN_CATALOG §6
Lớp tutorial cho hàng 27 nút HUD Tutorial_manager.Start: chưa xong tutorial Lv(Power) < 1 ⇒ tắt bộ 32 object (cả hàng nút); ngược lại CompleteTutorial bật lại tất cả ⇒ hàng nút xuất hiện sau lần nâng Power đầu tiên; HUD tối giản trên save mới là đúng SOT disasm-proven doc 07 §2.7/§2.8 (G375)
Máy trạng thái tutorial Upgrade → Challenge → GunOpen → GunBuy → GunEquip → Done; mỗi bước có coroutine kiểm điều kiện; bước Upgrade poll level Power mỗi 0.2 s ⇒ game gốc chịu được việc Start chạy trước khi save nạp xong (tự thoát khi level đã restore) 6 bước disasm-proven doc 07 §2.8 (G385)
Bước mua súng của tutorial nạp dia theo kịch bản: Dia ≤ 99 ⇒ cấp 100 − Dia để lần mua đầu chắc chắn mua được — hướng dẫn, không phải đường kiếm tiền 100 dia disasm-proven doc 10 §10 (G385)
Chế độ Play (SpeedRun): cây clamp(15·stage + 20, 20..190) xếp vòng tròn, bậc ngẫu nhiên 1/1.8/3 trên đường cong stage, 60 s; thắng = cây cuối đổ ⇒ Stage_Now++ (tutorial poll chính số này) + 30 dia (×4 auto, quảng cáo bonus +90); thua = hết giờ; quét tự động khi sức mạnh ≥ máu stage × n × 193 / 100 / 24; map = chủ đề stage % 10 60 s / 30 dia disasm-proven doc 07 §2.11 (G406)
Chế độ Raid (ẩn): boss của tuần = tuần kể từ 2024-01-01 mod 5; súng buff theo tuần (EXPLOSIVE → LASER → MISSILE → BLAST_SNIPER → PIERCE); loadout 3 ô tối thiểu 2; 30 s; boss hồi sinh sau mỗi lần giết; điểm ≥ mốc ⇒ 10 dia (20 auto); kết thúc chỉ theo đồng hồ 5 tuần / 30 s disasm-proven doc 07 §2.12 (G406)
Chế độ Hunt (Monster): rào HP = 1 — một con quái chạm rào = thua; mỗi wave 5 level, giết 90/120/160/200/240 con, spawn mỗi 0.35/0.2/0.17/0.12/0.08 s; máu wave ×3 (500 → 1 500 → 4 500…), quái to (xác suất Lv × 0.2) máu ×3; thưởng 30 PetCoin × hệ số gói PlusPack, ×2 auto; quét cần gói Auto; chỉ kết thúc khi thua hoặc bỏ cuộc; nộp điểm Wave × 10 + Lv HP 1 / 30 PetCoin disasm-proven doc 07 §2.13 (G408)
Chế độ Boss: máu 50 000 → 250 000 → 1.2 M (×5), skin = Stage % 9; 60 s (×2 với gói Time — nhưng thanh thời gian giữ max 60 ⇒ tràn > 100 %, cùng quirk Mine); thắng = Stage++ rồi mới nộp điểm, thưởng 150 dia × hệ số gói, ×3 auto, quảng cáo +2×; quét (không cần gói) khi sức mạnh ≥ máu / max(1, round(timer × 0.7)) 150 dia / 60 s disasm-proven doc 07 §2.14 (G408)
Bản học: hệ số gói PlusPack (Reward_Mult_*, Is_Active = 7 ngày) và Is_RewardBonus_Auto còn stub ⇒ thưởng Hunt/Boss = 0 — lỗi bản dựng lại, đang sửa (R13) blocker G408
Chế độ Mine: màn 60 s; vào bằng (Ticket_MaxCount_return từng là return 0 ⇒ không bao giờ vào được); quặng đặt bằng nhiễu Perlin trong vành r 8..20; điểm = dia. Hai quirk của game gốc: lượt có boost PlusPack bắt đầu với thanh thời gian tràn > 100 % (đồng hồ dùng max đã cộng, thanh dùng max thô 60 s); chỉ 100 quặng đầu của pool được xáo nên chỉ chúng có sprite dia 60 s / 8..20 / 100 disasm-proven doc 07 §2.10 (G393)
Dia: mỗi dia nhận được cộng 3 vào sổ gem gửi máy chủ (_getDia += v × 3); tiêu dia không kẹp ở 0 (khác PetCoin, có kẹp) ×3 disasm-proven doc 01 §2 (G395)
Bản địa hoá giá tiền nằm trong static ctor của Shop_manager: bảng 23 tiền tệ → chuỗi định dạng + tập 6 tiền tệ không thập phân KRW, JPY, VND, IDR, CLP, HUF (VND hiện 52,000đ, không 52,000.00đ); cùng ctor cấp danh sách giao dịch đã xử lý / lịch sử mua — thiếu là autosave save mới ném 23 / 6 disasm-proven doc 10 §6.3 (G399)

Nút không có cổng (mở từ Stage 1-1): Shop_Btn, Gun_Btn, Skin_Btn, SpeedRun_Btn (Play), Mission_Btn, EcoMode_Btn, Auto_Btn, Setting_Btn, DailyCheck_Btn, DiaPig_Btn, PowerBuff_Btn, MoneyBuff_Btn, Rank_Btn (UNLOCK_GATES §4). Các nút liveops (StepUp_Btn/DailyGun_Btn/WeeklyShop_Btn/FreeCash_Btn/OfferWall_Btn) mặc định m_IsActive: 0, bật bởi thời gian/liveops, không phải stage.

Bộ khung manager

Điều game làm Con số / hằng số Mức bằng chứng Nguồn
35 singleton *_manager / Gamemanager / UpdateManager / OfflineProgressManager, mỗi cái đúng 1 instance 35 scene-census doc 07 §2.1; [report: codegen_lane.md] §1.2
Assembly-CSharp có 731 type, chỉ 190 vào scene; tập làm việc 66 class / 1 284 method 731 / 190 / 66 scene-census [index: scene_census.json]
Hai biến thể singleton: field static trần (đa số) và property (Sound_manager) metadata-proven dump.cs:590265
Time_manager, RedeemCode_manager có 0 instance trong scene — dựng lúc chạy 0 scene-census codegen_lane.md §1.3
Mỗi manager có SaveData_return() + LoadData(SaveData) metadata-proven Upgrade_manager RVA 0x2B4A68C/0x2B4A750
Mỗi manager có Balance_Reload() — nhưng xem "Bẫy" bên dưới: dead code trong 1.1.59 disasm-proven + VERIFIED (IDA xrefs) doc 07 §2.1; doc 09 §2
UI vẽ lại từ state: First_Reload() (một lần) vs Value_Reload() (thường xuyên) Mission_Reward_Item.First_Reload 200× / Value_Reload 150× runtime-observed runtime_ranking.json
Dữ liệu nhạy cảm dùng ObscuredInt (Anti-Cheat Toolkit, Asset Store 202695) Gamemanager.Dia, Rebirth_Upgrade_Info.Lv metadata-proven + package-source doc 07 §2.1

Nâng cấp trong vòng (Upgrade_manager)

Điều game làm Con số / hằng số Mức bằng chứng Nguồn
Trần level MaxLv = 10000 metadata-proven dump.cs:602928
Hằng số thiết kế trong binary PowerMultPerLv = 1.08, MoneyMultPerLv = 1.08, SpeedAddPerLv = 8, PriceBase = 50, PriceGrowth = 1.38, PriceSoftCapLv = 5000, PriceLateGrowth = 2, SpeedStagePenalty = 2 metadata-proven dump.cs:602928
Bảng THẬT lúc chạy = mảng serialize trong Main.unity, sinh bằng lặp có cắt v[i] = trunc3(v[i-1] × 1.08) 0/360 lệch khi tái tạo scene-YAML + VERIFIED Main.unity:20353425…20413434; doc 09 §3.2; sim mục [M]
Speed_balance[lv] = 100 + 8·lv (tuyến tính, khớp chính xác) Speed_balance[46] = 468 = ảnh chụp scene-YAML + observed Main.unity:20413434; [device evidence: user_screenshot_stage5-4.png]
Price_balance[1] = 68, không phải 69 — vì 1.38 là double nhị phân 1.3799999999999998… 68 scene-YAML + VERIFIED doc 09 §2
AutoUpgrade_All(), Upgrade_Silent(int) — nâng cấp hàng loạt không hiệu ứng metadata-proven dump.cs:602928
Thanh "mua được" của 3 panel nâng cấp (SlicedFilledImage hướng Up, fill = Money / Price) đo với tiền thật trên save đã nạp: 47.7 / 48.5 / 57.2 % chiều cao panel, ổn định 3 thanh build-measured G371

Buff, súng, relic, skin, nhiệm vụ

Điều game làm Con số / hằng số Mức bằng chứng Nguồn
Buff = thời gian còn lại, hai đồng hồ moneyBuffTime @0x28 / powerBuffTime @0x2C BUFF_DURATION = 300, BUFF_MAX = 900 metadata-proven dump.cs:592886
Một coroutine BuffTickCoroutine chỉ chạy khi cần; IsPermanentBuff là property riêng IsPermanentBuff 103×, IsBuffActive 92× / 40 s runtime-observed runtime_ranking.json
Kho súng cố định int[16] Owned_Gun_list, -1 = trống metadata-proven dump.cs:596607
Gacha: DrawRandomGun(Degree), DrawRandom_Normal/Epic, DrawGun_Degree_5 metadata-proven RVA 0x2B0A278, 0x2B0A410, 0x2B0A92C, 0x2B0A930
Auto-merge có trần cứng const int AutoMerge_Exclude_Degree = 7 metadata-proven dump.cs:596607
Bậc súng = gunNum / 5; 10 bậc (Weapon_Get_Counts) 5 khẩu/bậc, 10 bậc disasm-proven + metadata-proven Gun_Item_Demo.Reload RVA 0x2B11A18; dump.cs:596607
Súng thưởng quảng cáo có hạn dùng AD_GUN_EVENT_GUN_NUM = 14, AD_GUN_EVENT_COOLTIME = 1800 metadata-proven dump.cs:596607
Gun_manager chứa URL Google Sheets export?format=tsv&range=A2:I66 + Request_Sheet() 65 dòng × 9 cột metadata-proven dump.cs:596607; LIVEOPS_SURFACE §4
Relic_manager phơi 7 static: Dmg_Value, Money_Value, CriDmg_Value (InfVal) + MoveSpeed_Value, Offline_Value, Rebirth_Value, Skip_Value (int) DrawPrice = 20 metadata-proven dump.cs:592186
Bảng relic: một đường cong 300 cấp, seed 105, ×1.05/cấp ở 3 chữ số có nghĩa rồi −100, dùng chung Damage/Money/CriDmg; bậc _0/_1/_2 = ×1 / ×1.5 (bỏ thập phân) / ×2; relic đơn: MoveSpeed & Skip = 2·Lv+2, Offline = 10·Lv+10 phút, Rebirth = 5·Lv+5; baseline 100 / 100 / 100 / 0 / 0 / 100 / 0 300 cấp disasm-proven doc 07 §2.4 (G360, G361)
Value_Reload làm mới có chọn lọc: gọi Cat.Balance_Reload chỉ khi một giá trị chiến đấu đổi; InvalidateMoneyCache chỉ khi Money_Value đổi disasm-proven G361
Skin_manager phơi 3 static int: Damage_Accum, Speed_Accum, Money_Accum; có is_skinValueZero 3 metadata-proven dump.cs:601415
Mission_Type chỉ 4 giá trị: TreeCount=0, StageClear=1, Rebirth=2, PlayMine=3 4 metadata-proven dump.cs:587114
Một API tiến độ: MissionValue_Increase(Mission_Type); người gọi cho cây là Tree_manager.Tree_Destroyed (được Tree.Die_Reload gọi — hai hàm từng bị công cụ gộp làm một, G346); Tree.Die_Reload 85× → 86× disasm-proven + runtime-observed doc 05 §3.6; runtime_ranking.json
Mission_manager.HighTier_Gun_Table = [16, 18, 20, 22, 24, 25, 27, 29] (8 khẩu bậc A → SS) và is_Vipstatic 8 metadata-proven (blob SHA, G353) + disasm-proven (G329) doc 11 §3.1, §8.1; nơi dùng bảng chưa đọc
Phần thưởng nhận theo thứ tự (is_Reward_SequenceLocked 150×) + hệ mùa (Season_Reload, is_Season_Closed) metadata-proven + runtime-observed doc 07 §2.5

Trip (Adventure_manager): vé, XP, bảng mở khoá — đợt 3

Điều game làm Con số / hằng số Mức bằng chứng Nguồn
Vé nạp 1 vé / 4 giờ: Ticket_Charge_Interval = TimeSpan.FromHours(4); Ticket_Max = 20 4 h / 20 disasm-proven + runtime doc 07 §2.9 (G321)
Quy tắc hai mốc của Ticket_Refresh: dưới trần — mốc nạp tiến đúng số khoảng 4 h nguyên đã tiêu, phần dư mang sang; tại trần — mốc đặt về NOW, phần dư bỏ ⇒ vắng dài không tích vé quá 20 disasm-proven G321
5 bậc mở map theo Trip Lv [0, 1, 3, 6, 10] (static) và 5 thời lượng chuyến [1, 2, 4, 8, 16] giờ (ctor) — hai nguồn độc lập (đọc bộ nhớ runtime + blob tĩnh) trùng nhau 5 + 5 runtime + metadata-proven (blob SHA) doc 07 §2.9 (G353)
XP Trip: thân Exp_Balance_Reload sinh Exp_balance[i] = (20 + 3·i)·i + 5050, 73, 102, 137, 178, …, 918 (15 cấp, bậc hai) 15 disasm-proven (thân hàm) G311
✅ Đã giải (G361): bảng scene 10, 60, 100, 130, 180, …, 920 là bảng SỐNG (scene lưu dạng hex blob; HUD EXP 0/10); công thức chỉ là fallback khi mảng null/rỗng — hai điểm gọi trong ContinueLoad đều có guard. Bản dựng lại từng gọi vô điều kiện (ghi đè đường cong designer mỗi lần nạp) — đã sửa 15 disasm-proven + scene-YAML doc 07 §2.9
Stub Ticket_Charge_Interval trả default(TimeSpan) = 0 từng gây chia cho 0 ở hai method sau — mặc định giá trị nổ ở nơi dùng, không ở nơi khai báo bài học khôi phục G321

Công thức / pseudocode

# Cổng mở khoá — Tree_manager (VERIFIED, RVA 0x2B4441C / 0x2B452E4 / 0x2B45820)
Stage_Value      = Level_Now + 10 * Stage_Now          # Level_Now 0..4, Stage_Now 0-based
on Game_Win:                                           # G347 — thân hàm đầy đủ ở doc 05 §3.6
    StageAdvance(ref Stage_Now, ref Level_Now)
    if Random(0,100) < Relic.Skip_Value and Level_Now + 10*Stage_Now < Stage_Value_Max:
        StageAdvance(...)                              # relic "Skip": chỉ nhảy TRONG vùng đã chinh phục
    Stage_Value = Level_Now + 10 * Stage_Now
    if Stage_Value >= Stage_Value_Max:
        Stage_Value_Max = Stage_Value                  # chỉ tăng, Rebirth không reset
        Rank_manager.SubmitScore(...)                  # [R1] leaderboard
        Contents_Lock_Reload()

Contents_Lock_Reload():
    Rebirth_Btn_Locked_obj.SetActive(Stage_Value_Max < 20)
    Mine_Btn_Locked_obj.SetActive(Stage_Value_Max < 30)
    Fish_Btn_Locked_obj.SetActive(Stage_Value_Max < 50)
    Boss_Btn_Locked_obj.SetActive(Stage_Value_Max < 90)
    Pet_Btn_Locked_obj.SetActive(Stage_Value_Max < 110)
    Monster_Btn_Locked_obj.SetActive(Stage_Value_Max < 110)
    Adventure_Btn_Locked_obj.SetActive(Stage_Value_Max < 340)
    FreeCash_manager.Hud_Reload(); OfferWall_manager.Hud_Reload()   # [R1] ad exposure

Content_Btn_X():
    if Stage_Value_Max >= N: mở panel X
    else: UI_manager.Alert(Format(Alarm.StageUnlock, N/10 + 1))   # số stage hiển thị

StageAdvance(ref stage, ref level):
    if level >= 4: level = 0; stage += 1
    else:          level += 1
// Khuôn manager lặp lại ở ~30 hệ thống (doc 07 §3.1)
public class X_manager : MonoBehaviour
{
    public static X_manager instance;          // field static trần, Awake: instance = this
    public void Balance_Reload() { … }         // sinh bảng — DEAD CODE trong 1.1.59, bảng thật nằm trong scene
    public int[] SaveData_return() { … }       // xuất state
    public void LoadData(SaveData data) { … }  // nạp state
    public void First_Reload() { … }           // thiết lập 1 lần (sprite, tên)
    public void Value_Reload() { … }           // cập nhật thường xuyên (số, tiến độ, khoá)
    public static T X_return() { … }           // phơi giá trị dẫn xuất cho hệ khác
}
# Buff (doc 07 §3.4) — thời gian còn lại có trần, không phải danh sách instance
AddBuff(type):   remaining[type] = min(remaining[type] + 300, 900)
IsBuffActive(t): IsPermanentBuff || remaining[t] > 0

# Súng (doc 07 §3.3)
degree(gunNum)   = gunNum / 5                          # 10 bậc, 5 khẩu/bậc
DrawRandomGun(d) -> slot = FindFirstEmptyOwned()       # int[16], -1 = trống
                 -> Owned_Gun_list[slot] = gunNum; Weapon_Get_Counts[d]++
TryStartAutoMerge(): limit = min(AutoMerge_Degree, Max_Collected_Degree); bậc >= 7 KHÔNG BAO GIỜ tự ghép

# Quota theo ngày (doc 07 §3.7) — khuôn dùng chung cho điểm danh, vé, lượt rút thưởng
Quota_Reload(key, maxPending):
    if savedDate.Date >= Today:            return    # Today = giờ local ĐÃ HIỆU CHỈNH, không phải giờ máy
    if !CanRolloverDaily(key, maxPending): return    # bị chặn -> KHÔNG ghi ngày mới, lần sau thử lại
    RecordGain(key); used = 0; savedDate = Today     # ghi sổ TRƯỚC, phát SAU, đánh dấu CUỐI
OnClockSynced(): savedDate = ClampFutureLocalDate(savedDate)      # trần = Today + 1 ngày

Bẫy đã gặp

  • Balance_Reload không chạy ở runtime. CodeRefsTo = [] cho Upgrade_manager (0x2B4A02C), Rebirth_manager (0x2B21CB4), Gun_manager (0x2B0AB4C); không có string literal, không có UnityEvent trong scene. Bảng thật là mảng serialize trong Main.unity, sinh bằng lặp có cắt chứ không phải pow(). Dùng 100·1.08^lv sẽ lệch −10.2 % ở lv 50 và ×6.5 ở lv 1 000 (doc 09 §3.2; G138a; CONVERGENCE). Doc 01 §2 và doc 07 §2.1 còn dòng "bảng sinh bằng công thức lúc chạy" — đó là bản cũ, doc 09 đã đính chính.
  • Kết luận "field không được tham chiếu" từ dump.cs là sai phương pháp. dump.cs chỉ liệt kê khai báo field, không liệt kê truy cập. Rebirth_Btn_Locked_obj từng bị ghi UNKNOWN vì thế; thực tế nó được Contents_Lock_Reload điều khiển qua static-instance + offset thô +48 (UNLOCK_GATES §2.3; G139 METHODOLOGY). Muốn chứng minh dead code / dead field: dùng IDA CodeRefsTo / DataRefsTo.
  • Stage_Value_Max không reset khi Rebirth — nếu framework của bạn reset nó, nút sẽ khoá lại sau mỗi lần prestige (VERIFIED, doc 09 §2).
  • Game_Win gọi Rank_manager.SubmitScore ngay sau khi tăng Stage_Value_Max — mọi probe ghi field này phải no-op SubmitScore, nếu không sẽ làm bẩn leaderboard production (G148 SAFETY).
  • Ràng buộc bảo vệ người chơi phải là const trong code: AutoMerge_Exclude_Degree = 7. Designer chỉnh nhầm cấu hình sẽ tự ghép mất súng hiếm (doc 07 §3.3).
  • Khớp nối chéo toàn phần: cặp Tree.Die_ReloadTree_manager.Tree_Destroyed chạm 5 singleton cho một cây đổ — không ship được Gamemanager dạng overlay 70 method vì nó kéo theo cả đồ thị (doc 07 §3.1; G129).
  • Mặc định giá trị bị công cụ decompile bỏ rơi: Ticket_Charge_Interval = 0 ⇒ chia cho 0 hai method sau; GameTime_Max = 0 ⇒ màn thua ở frame 1. Đọc .ctor của mọi class trước (doc 08 §3.6; G306, G321).
  • Tích luỹ base-100 rỗng = nhân về 0 trong im lặng (R13). Relic.Dmg_Value = 0 ⇒ mèo 0 sát thương; Skin_Value_Reload rỗng ⇒ 0 damage, 0 tốc độ; không ngoại lệ, không cảnh báo. Trước khi ship bất kỳ thứ gì nhân X / 100, truy X tới setter (G359, G361, G363).
  • Cân bằng súng có endpoint Google Sheet nhưng 0 code-xref tới Balance_Reload — HYPOTHESIS là design-time only; nếu sai, cân bằng súng là remote-driven và kết luận "liveops không ghi đè kinh tế" phải sửa (G144 OPEN-HIGH-RISK).
  • Đừng xếp hạng công việc theo tên class: 731 type, 190 vào scene, 66 class chiếm phần lớn thời gian chạy (doc 07 §4.10).
  • Đánh dấu "đã phát" trước khi phát, ở quota theo ngày. Ghi savedDate = Today trước khi qua cổng chống chỉnh giờ ⇒ người chơi mất trắng quota hôm đó và không có lỗi nào hiện ra. Đúng thứ tự là: kiểm ngày → kiểm cổng trust → ghi sổ → phát → mới đánh dấu ngày (doc 07 §3.7).
  • Quên kẹp ngày lưu nằm ở TƯƠNG LAI. Không có bước ClampFutureLocalDate khi đồng hồ được đồng bộ, người chơi đẩy giờ máy tới năm sau rồi trả về là quota đóng băng vĩnh viễn (điều kiện savedDate < Today không bao giờ đúng nữa).
  • Dựng đúng một hàm có thể KÍCH HOẠT một stub ở lớp khác đang nằm im. ClampFutureLocalDate từng là return default(DateTime) và vô hại — cho tới khi một lô khác dựng đúng OnTimeSynced; từ đó mỗi lần đồng bộ giờ ghi 0001-01-01 vào ngày lưu, tức reset quota mỗi lần. Trước khi đóng một lô, quét stub trên toàn bộ callee mà lô vừa mở đường tới, không chỉ các hàm mình viết.

Checklist khi tự làm

  • [ ] Một biến tiến độ tổng hợp (Stage_Value), lưu max từng đạt, không reset khi prestige.
  • [ ] Ngưỡng mở khoá là hằng số trong code, bội số của "số level mỗi stage" để luôn mở ở level 1.
  • [ ] Cùng một ngưỡng kiểm ở hai chỗ: hàm bật/tắt ổ khoá và handler nút (kèm alert số stage).
  • [ ] Gọi hàm cổng ở Start và ở mỗi lần lập kỷ lục stage; không nối qua UnityEvent nếu muốn tìm được bằng xref.
  • [ ] Khuôn manager: instance + SaveData_return/LoadData + First_Reload/Value_Reload + X_return static.
  • [ ] Nếu bake bảng cân bằng vào asset: bảng là nguồn sự thật; hàm sinh là công cụ Editor; ghi rõ luật cắt/tròn và số chữ số.
  • [ ] Buff = float remaining có trần + IsPermanent property; một coroutine chỉ chạy khi có buff.
  • [ ] Kho vật phẩm nhỏ: mảng cố định + giá trị lính canh (-1), quét tuyến tính.
  • [ ] Mọi quota theo ngày đi qua một khuôn: giờ đã hiệu chỉnh + sổ nợ có trần theo khoá + giữ nguyên ngày cũ khi bị chặn + kẹp ngày ở tương lai.
  • [ ] Gọi Quota_Reloadcả hai đường: mỗi lần vẽ lại UI của bề mặt, khi đồng hồ vừa đồng bộ lúc UI đang đóng.
  • [ ] Ràng buộc bảo vệ người chơi (bậc không tự ghép) là const.
  • [ ] Ít loại nhiệm vụ (4 là đủ), một API tăng tiến độ, phần thưởng nhận theo thứ tự.
  • [ ] Tách máy móc toàn vẹn (Time_manager, anti-cheat) khỏi manager kinh tế, sau ITrustedTime.
  • [ ] Cấu hình từ xa đi qua IRemoteConfigService fail-closed; ghi rõ số nào có thể bị ghi đè.
  • [ ] Có một cheat panel riêng cho QA (như Cheat_manager), tắt bằng GameObject; loại cheat cấp tài nguyên khỏi mọi probe tự động.

Điều chưa biết (UNKNOWN)

  • ~~Giá trị Adventure_Unlock_Balance[], Adventure_PetSlot_Unlock_Balance[]~~ — ĐÃ ĐÓNG: [0,1,3,6,10][0,2,7] (runtime; UnlockDuration còn xác nhận tĩnh bằng blob — G353).
  • ~~Adventure_manager.Exp_balance[] mâu thuẫn~~ — ĐÃ GIẢI (G361): mảng scene sống (hex blob), công thức chỉ là fallback khi mảng trống.
  • HighTier_Gun_Table, MonsterCountPerLevel, SpawnIntervalPerLevel — giá trị đã đọc, nơi dùng chưa đọc (ý nghĩa UNKNOWN; doc 07 §5).
  • Ngưỡng Mission SequenceLocked theo Reward_Degree/LvUNKNOWN.
  • Ý nghĩa 2 cờ tĩnh trong Shop_manager.is_DiaPig_UnlockUNKNOWN.
  • 2/5 code-xref còn lại tới Contents_Lock_ReloadUNKNOWN.
  • Có đường mở khoá Raid nào ở runtime không — bằng chứng tĩnh: KHÔNG; cần probe xác nhận (G142/G153).
  • Thân WeeklyShop.Is_VIP_Unlocked (RVA 0x2B3EA58) — chưa giải mã.
  • Thân Gun_manager.DrawRandomGun (RVA 0x2B0A278) — tỉ lệ rơi gacha UNKNOWN, chưa hề được đọc (doc 07 §5).
  • Nội dung Google Sheet 65×9 và việc nó có được nạp ở runtime không — UNKNOWN, HYPOTHESIS "không" (G144).
  • Request_Sheet có chạy lúc boot không — CHƯA XÁC MINH (không thấy trong cửa sổ trace 40 s).
  • ~~Cấu trúc SaveData~~ — ĐÃ ĐÓNG: bản đồ 22 + 5 + 35 field, thứ tự nạp, vị trí AllowSave — xem 14 Lưu game & offline.
  • Shop_manager, Adventure_manager, Fish_manager, Monster_manager, Raid_managerkhảo sát một phần (đường nạp save, vé/XP Trip, bể cá, các bảng static — doc 07 §5); Mine_manager, Boss_manager, SpeedRun_managerchưa khảo sát ngoài số method và field restore.
  • Relic_manager.Rebirth_Value nhận giá trị từ đâu — UNKNOWN (doc 09 §5).
  • Điểm gãy ×1.002 (lv ≥ 14999) của giá node prestige trong mảng scene — UNKNOWN (chỉ tồn tại trong Balance_Reload đã chết).

Đọc thêm

  • ../framework/07-progression-managers.md — bộ khung 35 manager, buff, gacha, nhiệm vụ, ranh giới R1
  • ../framework/09-prestige-rebirth.md — bảng scene vs công thức designer, cổng Rebirth
  • 14 — Lưu game & offline — đường nạp save 35 field, AllowSave, kẹp buff, cửa sổ offline
  • ../framework/01-economy-money.md — mắt Upgrade/Rebirth trong chuỗi thu nhập
  • [liveops catalog: UNLOCK_GATES.md] — bảng ngưỡng đầy đủ + chuỗi bằng chứng scene YAML
  • [liveops catalog: SCREEN_CATALOG.md] — kiểm kê màn hình, Raid ẩn, Cheat_manager
  • [liveops catalog: LIVEOPS_SURFACE.md] — Google Sheet súng (§4), lịch trình shop cố định (§6)
  • [phân tích nội bộ] — hai phân tích độc lập hội tụ về U1/U4 và Balance_Reload
  • gap list (nội bộ) — G129, G134, G136, G138a, G139, G144, G147, G148