00-README.md · Cập nhật lần cuối: 2026-09-05 08:45 +07 · sha256 nguồn 750f6217ddbdFramework game idle — chưng cất từ bản restore CatGunner
Bộ tài liệu này chưng cất các mẫu thiết kế và cơ chế của một game idle đã ship thật
(com.Chodun.CatGunner 1.1.59, tên nội bộ BardCat) thành tài liệu tái sử dụng được:
vừa là tài liệu học, vừa là hạt giống cho một framework game idle.
Ranh giới (đọc trước)
| Đây là gì | Bản khái quát hoá, tái sử dụng được, của các mẫu mà bản restore hé lộ. |
| Đây KHÔNG phải gì | Không phải source gốc. Không phải một phần của bản restore 1:1. |
| Cấp bằng chứng của mọi C# | L1 ANALYSIS — dựng lại clean-room từ ARM64 disassembly của libil2cpp.so, metadata IL2CPP đã giải mã, và quan sát runtime trên thiết bị. |
| Quan hệ với bản restore | [restore project: CatGunner] là mục tiêu 1:1 và không bị tài liệu này chạm vào. Chưng cất không bao giờ làm yếu bản restore. |
Quy tắc trích dẫn: mọi phát biểu đều kèm nguồn (RVA, đường dẫn file, file trace, scene YAML, hoặc source package). Một phỏng đoán không bao giờ được trình bày như một sự thật — nó được ghi là UNKNOWN.
Các module
| # | Tài liệu | Nội dung |
|---|---|---|
| 01 | Kinh tế & tiền tệ | Bignum InfVal, chuỗi nhân thu nhập, cache LRU, 4 loại tiền tệ, ký hiệu hiển thị, đặc tả module chạy độc lập + simulator, mảng balance scene |
| 02 | Chiến đấu & đạn | Dispatch GunType, pipeline sát thương, nổ AoE, xuyên, missile parabol, bug is_gaming |
| 03 | Particle & VFX | Pool hạt vs pool GameObject, FXThrottle, FX trúng đích, 7 718 ParticleSystem |
| 04 | Âm thanh | Sound_manager.PlaySfx, 15 SfxType, chống trùng, mute theo ngữ cảnh, 16 clip |
| 05 | Nhân vật, Pet & Kẻ địch | Đàn mèo + AI follower, boids pet, Spine 4.1.24, Enemy chung, wave, đặt cây Morton, Game_Win + relic skip, bảng degreeRates |
| 06 | Juice & Game Feel | Squash-stretch, text nổi, thanh máu 2 tầng, nướng đường cong, knockback |
| 07 | Tiến trình & Manager | 35 singleton, Balance_Reload, gacha/merge, buff, nhiệm vụ, ranh giới R1, bản đồ save/load 35 field (§2.8), vé + XP Trip (§2.9) |
| 08 | Kiến trúc & quy mô | Một scene 481 MB và hoá đơn của nó, URP mobile, mã hoá metadata, package, bài học phương pháp khôi phục đợt 3 (§3.6) |
| 09 | Prestige / Rebirth | Vòng lặp lõi của idle: reset-set/persist-set, đường cong thưởng, tiền tệ meta, công thức designer vs bảng đã ship, kinh tế offline (cửa sổ thời gian đã dựng lại) |
| 10 | Kiếm tiền: IAA + IAP | 10 AD_Type rewarded, interstitial theo điểm đặt, offerwall, FreeCash/Almedia, IAP + segment máy chủ — (lane khác biên soạn) |
| 11 | Kiểm kê nội dung | Đếm và dẫn chứng khối lượng nội dung cho hoạ sĩ — (lane khác biên soạn) |
Công cụ chạy được:
[F001: economy_reference_sim.py]
— mô hình tham chiếu Python thuần (0 phụ thuộc) cho tầng kinh tế + prestige, tự kiểm với 70 vector
lấy từ SOT thật, gồm việc tái tạo 8 mảng balance serialize trong scene (0/360 lệch).
Đọc theo mục đích
Muốn xây một game idle mới: 01 (kinh tế) → 09 (prestige) → 07 (tiến trình) → 02 (chiến đấu). Bốn tài liệu này chứa toàn bộ vòng lặp cốt lõi.
Muốn game "đã có" nhưng chưa "đã tay": 06 (juice) → 03 (VFX) → 04 (âm thanh).
Muốn hiểu quy mô thật của một game thương mại: 08 → 05.
Muốn học phương pháp reverse-engineering: 08 §3.3 (mô hình mối đe doạ của bảo vệ) và §3.5 (xếp hạng bằng dữ liệu chứ không bằng tên).
Bảng ghi công bằng chứng
| Mức | Nghĩa |
|---|---|
disasm-proven |
Đọc từ ARM64 / Hex-Rays của libil2cpp.so tại RVA được ghi. Bằng chứng mạnh nhất về logic. |
metadata-proven |
Từ IL2CPP metadata đã giải mã (dump.cs). Tên, kiểu, offset, RVA và giá trị const là chính xác. Không có thân method. |
runtime-verified |
Oracle field-delta trên thiết bị đã xác nhận việc dựng lại dự đoán đúng các phép ghi thật. |
runtime-observed |
Đã thấy chạy trên thiết bị (số lần gọi), giá trị field chưa đối chiếu. |
scene-census |
Đếm từ Main.unity (30 082 tham chiếu m_Script). |
asset-census |
Từ inventory asset (UnityPy / AssetRipper). |
package-source |
Từ package Asset Store / upstream mà user sở hữu. |
build-measured |
Đo được trong quá trình build/import thật. |
observed |
Quan sát trực tiếp trên SOT đang chạy (ảnh chụp màn hình). |
runtime-verified (live) |
Đo trực tiếp trên bản đang chạy trên thiết bị — hook hàm, đọc giá trị trả về / trường bộ nhớ, hoặc đọc trạng thái nút HUD trong một phiên có kiểm soát. Mạnh hơn observed (không chỉ nhìn màn hình) và mạnh hơn runtime-observed (có giá trị, không chỉ số lần gọi). Dùng ở doc 10 và cho các claim từ probe trong 01 / 07 / 09. |
scene-YAML |
Đọc trực tiếp từ Main.unity (số dòng được ghi kèm). Với bảng cân bằng, đây là nguồn sự thật lúc chạy. |
VERIFIED |
Nhãn của [phân tích nội bộ]: đọc trực tiếp từ binary/scene + xrefs IDA. |
derived |
Tính lại từ một công thức đã disasm-proven. Ghi riêng khỏi dữ liệu oracle. |
UNKNOWN |
Chưa biết. Không được thay bằng một con số hợp lý. |
Tổng quan số liệu
| Tài liệu | Claim có bằng chứng | UNKNOWN / bằng chứng phủ định |
|---|---|---|
| 01 — Kinh tế | 34 (+1) | 18 (1 đóng một phần) |
| 02 — Chiến đấu | 25 | 8 |
| 03 — VFX | 17 | 7 |
| 04 — Âm thanh | 18 | 9 |
| 05 — Nhân vật | 65 (+20) | 12 (1 đóng một phần, +2 mở) |
| 06 — Juice | 46 | 12 |
| 07 — Tiến trình | 103 (+32) | 20 (1 đóng, +5 mở) |
| 08 — Kiến trúc | 66 (+10 bài học §3.6) | 12 |
| 09 — Prestige | 41 (+6) | 19 (2 đóng) |
| 10 — Kiếm tiền (lane khác) | 177 | 23 (12 mở · 6 phủ định · 5 đã đóng) |
| 11 — Kiểm kê nội dung (lane khác) | — (bảng kiểm kê, không đếm claim) | — |
| Tổng | 770 (+30 đợt 12: Hunt 7, Boss 5, game feel 8, âm thanh 3, nghiệm thu ghi 3, còn lại 4) | 143 (đợt 12: 5 đóng [PlaySfx, SfxEntry, FXThrottle, chỉ số hàng Monster, null offline định danh], +3 mở LỖI THẬT [tiền ×300, TotalPlayTime, thưởng Hunt/Boss = 0 (R13)]; đường ghi trên save đã nạp = VERIFIED 122/128) |
Tỉ lệ ~3–4 claim trên mỗi UNKNOWN là cố ý. Một tài liệu chưng cất không có UNKNOWN nào là một tài liệu đang đoán.
Đợt 3 (2026-09-05, ledger G290–G353 + G700–G704): +69 claim, 4 UNKNOWN đóng (cấu trúc SaveData; 20 float
degreeRates; tên súng StepUp; nơi dùng Relic.Skip_Value), 3 đóng một phần (kinh tế offline; tham số đội hình;
Cat), và +7 UNKNOWN mới — đáng chú ý nhất là một mâu thuẫn: bảng XP Trip theo thân hàm
Exp_Balance_Reload ((20+3i)·i+50) không bằng mảng scene/bộ nhớ runtime (10, 60, 100…); bảng nào sống
sau khi nạp save chưa chốt (07 §2.9). Ghi mâu thuẫn, không chọn bên.
Đợt 4 (ledger G354–G363): mâu thuẫn trên đã giải — mảng scene sống, generator là fallback; Main.unity lưu int[]
dạng hex blob nên tìm kiếm dạng danh sách YAML đã bỏ sót (08 §3.6). Thêm: camera iso
orthographic + vì sao cây nằm ngoài khung (05 §2.4), auto-move của mèo (05 §3.1b), cụm bắn
+ pool đạn hai lượt + chuỗi 100 sát thương (02 §2), thứ tự restore đầy đủ của LoadData.Load
và bài học nghiệm thu 8/38 field lệch (07 §2.8), bảng relic (07 §2.4),
quy tắc R13 (tích luỹ base-100 / factory null là lỗi im lặng). UNKNOWN đóng: Exp_balance, Object_Polling_Smart,
nơi đọc is_Shoot_Mute, cây không hiện (G351), đường ghi Rebirth_Value; đóng một phần: số hạng Skin/Pet/Relic (2/3).
Đợt 5 (ledger G364–G371): Cat hoàn tất (65/67; follower = vệt leader 2 s với độ trễ riêng 0.15–0.6 s, hai lớp chống rung,
trạm đấu trường; finder quặng mở rộng dần, buffer non-alloc 64 — 05 §2.1/§3.1c); render state 3 shader
sprite đọc được, thân hiệu ứng còn placeholder (08 §5); nghiệm thu save thật 37/38 với 4 residual
và đường ghi save cố ý tắt (fail-safe, 112 field — 07 §2.8); bắn chạy trên thiết bị nhưng ba lỗi mở
(save mới 0 sát thương, đạn trúng vô hiệu trên save nạp, thân mèo thiếu) ghi là MỞ ở doc 02/05/07 §5 — không phải claim.
Đợt 6 (ledger G372–G377): mọi ngày giờ trong save parse UTC (AssumeUniversal|AdjustToUniversal) + guard Phật lịch ±543;
khối Adventure có hai nhánh (mới / restore, mốc hỏng ⇒ bắt đầu lại từ bây giờ); hàng 27 nút HUD do tutorial ẩn tới lần nâng Power
đầu (HUD tối giản trên save mới là đúng SOT); đường khởi tạo save mới đặt baseline base-100 (Relic_manager.Start, Skin_manager.Start);
sổ cái RecordGain (UTC + trust + session + đồng hồ đơn điệu, 32 mục, từ chối dưới Trust.None); đính chính DiaPig (_lastTickTime giữ
giá trị file, chỉ kẹp tương lai; _lastTickMono mới được đóng dấu lại). Đóng G423/G425 + residual (1); G424 vẫn mở (giả thuyết
is_gaming do tutorial); OfflineProgressSimulator 12 stub → lane riêng; DailyCheck retention đã xong (G378) — bảng
70/200/400/600/800/1000/1500 dia, chuỗi 7 ngày lặp, đồng hồ tin cậy trước, ghi sổ trước khi cấp: 10 §7.6.
Đợt 7 (ledger G379–G382, G1000–G1005) — ĐÍNH CHÍNH LỚN: OfflineProgressSimulator được dựng lại trọn và harness độc lập
tái tạo khoản trả của game gốc từ một save thật đúng 17 chữ số (+1 627 259.5021456285). Hệ quả: Skin / Pet / Relic CÓ được
áp offline — bản trước của 01 §5.8 / 09 §4b / OFFLINE_ECONOMY.md §(c) ghi
"không" là SAI (census bỏ sót lambda); chỉ buff quảng cáo ×3 vắng mặt. 12 luật offline giờ là VERIFIED với ví dụ số thật
(01 §5.8). Còn chờ: khoản trả trên thiết bị (9 stub R13). Thêm: G424 — giả thuyết is_gaming bị bác, nghi phạm chuyển sang
cài đặt project (ma trận va chạm, thứ tự script — 08 §3.6); G422 đóng (SOT); đường ghi save
bàn giao lane riêng với câu hỏi 7 Clone (07 §2.8).
Đợt 8 (ledger G383–G389): đường GHI save dựng xong — 127/128 field, 7 mảng snapshot vs 13 theo tham chiếu, xoay .tmp → .bak
— nhưng công tắc vẫn tắt: mô hình round-trip lộ ra 6 getter inline còn stub (trong đó Time_manager.UtcNow = năm 1 đầu độc
SanitizeYear = gốc rễ thật của residual ngày tháng và của hồi quy save mới) và các field phía đọc bị bỏ sót trong ContinueLoad
(07 §2.8). Ma trận va chạm layer trong export hỏng thật (mã hoá /), đã sửa về SOT — nhưng
G424 vẫn mở (sửa xong vẫn 0 sát thương); thứ tự script khớp SOT. Tutorial: SOT chịu được cuộc đua Start-vs-load bằng cách
poll level Power mỗi 0.2 s; máy trạng thái đã dựng; bước mua súng nạp 100 dia theo kịch bản (không phải monetisation). 9 blocker
offline đã điền, khoản trả trên thiết bị vẫn chưa quan sát. Phương pháp: 08 §3.6 +5 bài học.
Đợt 9 (ledger G391–G397): đồng hồ của game đọc trọn (giờ máy + offset, mốc máy chủ đơn điệu khi đang kiểm, không bao giờ lùi, kẹp
trên sàn tin cậy; .cctor thiếu = gốc rễ crash save mới và ngày năm 1 — 07 §2.6); công tắc GHI đã bật
trong overlay học (cổng mở 4 trục, round-trip 127/128) nhưng build thiết bị đầu tiên hồi quy cả đọc lẫn ghi — trạng thái "bật, đang sửa",
không phải verified; trên thiết bị: nút HUD lần đầu hiện, tutorial tới Challenge, OnTriggerEnter không bao giờ được gọi (0 dòng trace),
đường offline chạy nhưng huỷ giữa chừng và làm tiền GIẢM 2.37 M (lỗi thật của bản dựng lại, ghi trung thực), map kẹo ở bước Challenge
(chưa giải thích). Kinh tế: dia (_getDia đếm ×3 cho máy chủ, không kẹp 0 khi tiêu), 3 cổng sức mạnh theo chế độ (làm tròn ngân hàng,
bảng hệ số súng 1/7/5/pellets/5/5/10), thang mở khoá giờ VERIFIED cả tên (stage 3/4/6/10/12/12/35), bảng máu/tiền cây = seed 250/20
×3 cắt 2 chữ số (đóng UNKNOWN cũ), hệ cảnh báo round-robin (mọi cảnh báo từng câm), luật chế độ Mine (07 §2.10).
Hệ TEXT (ScriptLocalization từ binary, font TMP, cỡ chữ) là hạng mục đang làm — chưa claim. Roadmap quét stub và thứ tự tiếp tục sau
giới hạn phiên: nội bộ, 08 §3.6.
Đợt 10 (ledger G398–G400) — VÌ SAO ĐẠN KHÔNG TRÚNG: gốc rễ G424 là một hằng số vector sai một thành phần: CamForward trong
static ctor của Cat thiếu pitch 40° ⇒ phép chiếu nòng súng lên mặt phẳng y = 2 chia cho 0 ⇒ mọi viên đạn spawn ở vô cực,
không bao giờ chạm trigger (02 §2; bài học ở 08 §3.6) — chờ xác nhận thiết bị
batch 20. Cùng đợt: key cache tiền = chuỗi 7 phần liệt kê mọi nguồn multiplier (01 §2); các ngày năm 1 là vì
nửa sau của việc nạp chưa hề chạy (ngoại lệ trước continuation); "hồi quy đọc" batch 19 là quy trình test, không phải code; autosave
save mới ném vì Shop_manager..cctor thiếu (kèm bảng 23 định dạng tiền tệ + 6 tiền tệ không thập phân KRW/JPY/VND/IDR/CLP/HUF —
10 §6.3); bước Challenge không vào SpeedRun (map kẹo vẫn chưa giải thích).
Đợt 11 (ledger G402–G407) — GAME CHƠI ĐƯỢC: batch 20 xác nhận trên thiết bị: 104/104 va chạm đi trọn chuỗi sát thương, cây đổ, tờ tiền +
hạt lá, thanh máu trên xương rồng, hàng nút HUD + bàn tay tutorial; autosave ghi được trên save thật (.json + .bak). G424 ĐÓNG ở mọi
doc/bảng. Residual trung thực: autosave save mới còn ném (PlusPack), offline chạy tới cuối rồi còn một null (coroutine), đuôi nạp vẫn
chờ, tutorial dừng ở GunOpen. Thêm: throttle số bay (lưới 1.5, X/Y, làm tròn ngân hàng — 06 §2.4); chế độ Play
và Raid đọc trọn (07 §2.11–2.12) — map kẹo = chủ đề Stage_Now % 10, không phải bug; hệ text: font
giống hệt SOT, lỗi là tài nguyên stock che asset (08 §5); R2: version package phải khớp bề mặt API
của binary (ParticleImage.EmitAtWorldPosition). Phương pháp: 08 §3.6 +4 (biên cuối hàm, version package,
che khuất Resources, guard bỏ comment).
Đợt 12 (ledger G408–G415): chế độ Hunt và Boss đọc trọn (07 §2.13–2.14: rào HP 1, 5 level/wave, thưởng
PetCoin/dia × gói PlusPack, quét, quirk đĩa HP theo độ, ellipse spawn, skin boss Stage % 9); game feel đọc trọn (06 §2,
04 §5, 03 §5): thứ tự cổng sfx + volume theo hàng, không biến tấu pitch, BGM mute = volume 0, 3 FX trúng/frame,
giá trị squash, giật lùi −0.6, dia bay 8 hạt/0.3 s, rung 30 ms — và bằng chứng phủ định: game ship không có camera shake / hit-stop; null offline
định danh (ShowAfterFrame) + dự đoán harness 5.4 h chưa xác nhận; che khuất TMP đã gỡ (23 → 3), ParticleImage là code do game sửa vào vendor
(quyết định partial + file SOT-authored, 08 §3.6); nghiệm thu batch 20: đường ghi trên save đã nạp VERIFIED 122/128
với xoay .bak và đọc lại sạch — nhưng hai lỗi thật: thu nhập tiền ≈ ×300 SOT (đang điều tra) và TotalPlayTime đứng; nguy cơ đúc lại danh tính
khi nửa sau nạp bị bỏ qua. Tự mua offline khớp harness (nhiều khả năng đúng).
Phương pháp: R14 (event field-like bị bỏ rơi) ở 08 §3.6.
Trong đợt 2, 9 UNKNOWN được đóng (U1–U4 + bảng cân bằng + hai ô ảnh chụp) và nhiều UNKNOWN mới được mở — chủ yếu quanh mô hình kinh tế offline vừa phát hiện. Đó là dấu hiệu lành mạnh: hiểu sâu hơn thì thấy rõ hơn cái mình chưa biết.
⚠ Đính chính quan trọng (đợt 2)
Một phát hiện đã lật ngược một kết luận trước đó về nền kinh tế, và nó là bài học trung tâm của bộ tài liệu này:
Balance_Reload— hàm sinh bảng cân bằng — là DEAD CODE trong build 1.1.59. Bảng thật lúc chạy là mảng đã serialize trongMain.unity, sinh bằng lặp có CẮT (v[i] = trunc3(v[i-1] × 1.08)), không phải dạng đóng100·1.08^lv. Sai lệch: −10.2 % ở lv 50, ~6.5 lần ở lv 1 000.
Hệ quả: công thức của designer ≠ bảng mà game ship. Xem
09 §3.2 và 01 §5.7.
Nguồn: [phân tích nội bộ].
Ba đính chính khác (mỗi cái rút lại hoặc thay thế một phát biểu trước đó):
| Từng ghi | Sự thật đã VERIFIED |
|---|---|
| "Đơn vị viết hoa ở text sát thương — đường code UNKNOWN" | Là ART CỦA FONT. Chỉ một formatter (InfVal_change, 29 caller); không ToUpper nào; glyph a được vẽ thành "A". Đừng bao giờ thêm ToUpper. |
"4 font có m_FontData rỗng — chúng thật sự rỗng" |
Chúng là BITMAP FONT (bảng 42 ký tự + atlas PNG). Bảng + PNG chính là font; thay bằng TTF đổi cả casing lẫn metrics. |
| "Thu nhập offline có thể cao hơn ~10 % nếu fallback chạy" | RÚT LẠI — fallback không thể chạy (mảng đúng 10 001 phần tử, chỉ số kẹp [0,10000], một scene duy nhất). Giữ chỉ như bẫy khôi phục. |
Và một phát hiện lớn: kinh tế OFFLINE là một mô hình thứ hai riêng biệt — không đi qua
MoneyValue_return, bỏ qua Skin/Pet/Relic/buff ×3. Xem 01 §5.8.
Bài học phương pháp kèm theo: "field không xuất hiện trong dump.cs" không là bằng chứng
rằng nó không được dùng — dump.cs chỉ liệt kê khai báo, không bao giờ liệt kê truy cập.
Phải dùng xref của IDA (CodeRefsTo / DataRefsTo).
Đính chính đợt 3 — ba claim đã RÚT LẠI trong ledger (không được xuất hiện ở đây như sự thật)
| Claim đã rút | Sự thật | G-id |
|---|---|---|
"Không có component Gun_manager trong Main.unity" (chẩn đoán NRE trên thiết bị) |
Sai. Component có (fileID 106); .cs.meta của project bị đúc GUID mới khi dời file ⇒ Missing Script. Lỗi phương pháp: "0 lần xuất hiện của GUID X" khi chưa chứng minh X là GUID SOT |
G224 → G307, G308, G314 |
"Tree_manager.Game_Win phải là internal vì Tree.Die_Reload gọi xuyên class" |
Sai. IDA gộp Tree.Die_Reload với Tree_manager.Tree_Destroyed; người gọi thật cùng class ⇒ Game_Win private như dump.cs |
G190 → G346 |
"LoadData.InitNewGame còn 17 call telemetry (15–31) chưa dựng" |
Sai. Quét quá end_ea sang ServerConfig_manager.LoadFromSaveData; InitNewGame = đúng 14 call, hoàn chỉnh từ batch 5 |
G208 → G324 |
Toàn bộ phương pháp đợt 3 (ctor bị bỏ rơi, hàm bị gộp, oracle SHA-256 cho blob, GUID scene, guard singleton) nằm ở 08 §3.6.
Toàn vẹn tệp
docs/framework/hashes.txt giữ sha256 + kích thước của mọi tài liệu trong thư mục này
(kể cả docs 10 & 11 do lane khác biên soạn). Sinh lại bằng:
cd docs/framework && shasum -a 256 *.md
Bất kỳ lane nào sửa một tài liệu ở đây phải cập nhật hashes.txt và chạy
tools/build_cookbook.sh (R10) — dashboard lệch là một lỗi.
Lane liên quan
[liveops catalog: liveops]— danh mục màn hình + cổng mở khoá (đang chạy). Doc 07 và 09 sẽ liên kết tới nó khi bàn giao, không chép lại nội dung.[tài liệu nội bộ: codegen]— lane khôi phục thân method (nguồn của phần lớn bằng chứng disasm).[restore project: CatGunner]— bản restore 1:1. Không bị bộ tài liệu này chạm vào.