12-kien-truc-scale.md · Cập nhật lần cuối: 2026-09-05 08:39 +07 · sha256 nguồn 9181bc76264612 — Kiến trúc & quy mô (một-scene-481MB và cái giá)
Nguồn framework:
docs/framework/08-architecture-and-scale.mdtoàn bộ;docs/framework/07-progression-managers.md§3.1 (35 singleton);[liveops catalog: SCREEN_CATALOG.md]§1 (đính chính số Canvas). 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
Muốn biết một game idle thương mại thật sự lớn cỡ nào, và quyết định kiến trúc nào sẽ bắt bạn trả giá về sau — trước khi bạn lặp lại nó. CatGunner chọn một scene duy nhất chứa toàn bộ game (481 MB): không loading, không bundle, nhưng import Editor > 30 phút, không merge được, và một loại bug mới (combat chạy trong menu). Trang này đưa hoá đơn đo được, ngân sách hình ảnh mobile đã ship, và bài học "đo, đừng đoán".
Game gốc làm gì
Danh tính build
| Điều game làm | Con số / hằng số | Mức bằng chứng | Nguồn |
|---|---|---|---|
com.Chodun.CatGunner, versionName 1.1.59, versionCode 227 |
— | package-source | [shared facts nội bộ] |
| Unity 6000.0.61f1, URP, IL2CPP, chỉ arm64-v8a | — | package-source | [shared facts nội bộ]; chuỗi build trong libil2cpp.so |
XAPK: base 147 557 129 B + config.arm64_v8a.apk 40 028 322 B; không OBB, không asset pack |
— | package-source | [report: asset_lane.md] §1 |
libil2cpp.so 101 516 264 B; global-metadata.dat 17 924 548 B |
— | package-source | [shared facts nội bộ] |
| minSdk 27, targetSdk 36 | — | package-source | [report: project_lane.md] §7 |
136 assembly · 18 678 type · 141 908 method sau giải mã; Assembly-CSharp = 731 type / 5 194 method |
— | metadata-proven | [shared facts nội bộ] |
Một scene — con số
| Điều game làm | Con số / hằng số | Mức bằng chứng | Nguồn |
|---|---|---|---|
Có đúng MỘT scene: Main (level0) |
1 | asset-census | [report: asset_lane.md] §3 |
| Kích thước sau export 481 217 168 B, 143 032 object | — | asset-census | như trên |
38 375 GameObject · 24 452 Transform + 13 923 RectTransform · 12 561 CanvasRenderer · 7 718 ParticleSystem · 6 491 SpriteRenderer · 31 354 MonoBehaviour |
— | asset-census | asset_lane.md §3, §4a |
30 082 tham chiếu m_Script trỏ tới 190 class của Assembly-CSharp (trên 731) |
190 / 731 | scene-census | [index: scene_census.json] |
Doc 08 ghi 25 Canvas; lane liveops đếm lại trên export đã giải mã: 21 Canvas, và chỉ 1 là Canvas UI thật (Canvas, GO 779); 20 còn lại là Canvas lồng override sorting cho Fish_item (N), tất cả m_IsActive: 0 |
21 / 1 | VERIFIED (đếm từ scene) | SCREEN_CATALOG.md §1; G152 gap list (nội bộ) |
Đơn vị màn hình thật = con của Canvas / Canvas/SafeArea / Canvas/Contents_UI: 18 nhánh gốc, ~90 panel, 221 class MonoBehaviour duy nhất |
221 | VERIFIED | SCREEN_CATALOG.md §1, §3; G152 |
Không level1..N, không AssetBundle, không Addressables, không CDN asset |
— | asset-census (phủ định) | asset_lane.md §3 |
Mọi asset trong một bundle data.unity3d (32 167 543 B) |
— | asset-census | asset_lane.md §2 |
Hoá đơn đo được của quyết định đó
| Chi phí | Số đo | Mức bằng chứng | Nguồn |
|---|---|---|---|
| Import sạch scene trong Editor | > 30 phút, CPU-bound 98 % | build-measured | G027 |
Một lần import THẤT BẠI: Editor SIGKILL (-9) sau 2 544 s — không OOM (128 GB, còn 93 %), không timeout |
42 phút | build-measured | G028 |
Rác log ReadObjectThreaded |
~24 GB | build-measured | G027 / G028 |
| Scene đã giải mã cần ~75 GB RSS đỉnh (trước giải mã ~9 GB) vì 28k component mang dữ liệu thật | 75 GB | build-measured | G124 (toolchain) |
Build trong process group của caller bị SIGKILL đúng 60 phút ⇒ phải spawn_detached.py + os.setsid() |
60 phút | build-measured | G120 |
APK dựng lại: scene chia thành level0.split0..145 |
146 mảnh | build-measured | [report: project_lane.md] §7 |
| File YAML 481 MB — không merge được, thực tế là khoá độc quyền | — | build-measured | doc 08 §3.1 |
Combat chạy trong menu nếu thiếu guard Gamemanager.is_gaming; Enemy.Damaged/Enemy.Die từng thiếu guard khi dựng lại |
— | disasm-proven (bug đã sửa) | G132b; doc 02 §3.5 |
Ngân sách hình ảnh mobile đã ship
| Cài đặt | Giá trị | Mức bằng chứng | Nguồn |
|---|---|---|---|
m_RenderScale |
0.7 (render 49 % số pixel rồi upscale) | scene-YAML | [restore project: Mobile_RPAsset.asset:29] |
m_UpscalingFilter: 1, m_FsrSharpness: 0.92 |
FSR | scene-YAML | như trên |
m_MSAA: 1 (tắt), m_SupportsHDR: 0, m_MainLightShadowsSupported: 0, m_AdditionalLightShadowsSupported: 0 |
tắt | scene-YAML | như trên |
m_RequireDepthTexture: 1, m_RequireOpaqueTexture: 0, m_EnableLODCrossFade: 0 |
— | scene-YAML | như trên |
| Texture Android ASTC: ASTC_6x6 ×78 (gồm cả hai atlas 4096²), ASTC_8x8 ×9, RGBA32 ×50, Alpha8 ×20, RGB24 ×1 | — | asset-census | asset_lane.md §0 |
2 sprite atlas: Cat (125 sprite), _UI (374 sprite), cả hai 4096×4096 ASTC 6x6 |
499 sprite | asset-census | asset_lane.md §5 |
boot.config: androidStartInFullscreen=1, androidRenderOutsideSafeArea=1, adaptive-performance boost-launch |
— | package-source | project_lane.md §7 |
Bộ khung code
| Đ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 một instance; field static trần public static X instance; |
35 | scene-census + metadata-proven | [report: codegen_lane.md] §1.2, §1.3 |
| Không DI container, không event bus tổng, không state machine tổng | — | không quan sát thấy | dump.cs toàn bộ manager |
Tập làm việc = {managers} ∪ {class ≥ 20 instance} = 66 class / 1 284 method trên 5 194 |
66 | scene-census | [index: priority_static.json] |
| Trace runtime: 505 method thực sự chạy trong boot + 40 s chơi (hook 1 279 method tại native offset) | 505 | runtime-observed | [runtime trace: runtime_ranking.json] |
BulletShooter (nghe như trái tim game): 0 lời gọi; SlicedFilledImage (thanh máu UI): 169 246 lời gọi, gấp 10 lần Bullet (16 321) |
0 / 169 246 | runtime-observed | runtime_ranking.json |
Package bên thứ ba
| Assembly đã ship | Package | Mức bằng chứng | Nguồn |
|---|---|---|---|
DOTween, DOTweenPro, DemiLib |
DOTween Pro — Asset Store 32416 | package-source | quy tắc dự án (nội bộ) R2 |
AllIn1SpriteShaderAssembly |
All In 1 Sprite Shader — 156513 | package-source | như trên |
ParticleImage |
UI Particle Image — 235001; version phải khớp bề mặt API của binary (game gọi EmitAtWorldPosition; bản cũ trong project không có ⇒ compile đỏ, G404) |
package-source | như trên |
ACTk.Runtime |
Anti-Cheat Toolkit — 202695 | package-source | như trên |
MK.Toon, MK.Toon.URP |
MK Toon — 178415 | package-source | như trên |
ShapesRuntime |
Shapes 4.6.0 — 173167 (lệch version, G117) | package-source | project_lane.md §4 |
OccaSoftware.OutlineObjects.Runtime |
Outline Objects 3.2.0 — 215454 (lệch version, G118) | package-source | như trên |
InfiniteValueAsm |
Infinite Value (BigDecimal) 2.2.0 — 194963 (SOT ship bản cũ hơn, G122) | package-source | như trên |
spine-csharp, spine-unity |
spine-unity 4.1 (miễn phí) | package-source | như trên |
Whinarn.IndMeshSimplifier.Runtime |
UnityMeshSimplifier v3.1.1 (MIT) | package-source | như trên |
SlicedFilledImage |
MIT (hiryma / Unity UI Extensions), vendor dưới dạng source | package-source | G128 |
Bảo vệ khi ship (mục nội bộ, đã lược bỏ)
Công thức / pseudocode
Ngân sách URP mobile đã ship — scene-YAML, Mobile_RPAsset.asset:
m_RenderScale: 0.7 # -51 % pixel phải tô; game 2.5D nhìn từ trên gần như không nhận ra
m_UpscalingFilter: 1 # FSR, FsrSharpness 0.92
m_MSAA: 1 # TẮT
m_SupportsHDR: 0 # TẮT
m_MainLightShadowsSupported: 0 # TẮT
m_AdditionalLightShadowsSupported: 0
m_ShadowDistance: 50
m_ShadowCascadeCount: 1
m_RequireDepthTexture: 1 # BẬT (có hiệu ứng cần depth — outline là ứng viên, chưa xác nhận)
m_RequireOpaqueTexture: 0 # TẮT
m_EnableLODCrossFade: 0 # TẮT
Bộ khung singleton — mẫu lặp ở ~30 manager (doc 07 §3.1):
public class X_manager : MonoBehaviour
{
public static X_manager instance; // field static trần
private void Awake() { instance = this; } // đăng ký, không kiểm trùng
public int[] SaveData_return() { … } // xuất state
public void LoadData(SaveData data) { … } // nạp state
public void UI_Reload() { … } // vẽ lại UI từ state
}
// Hoạt động vì game có ĐÚNG MỘT scene: mọi manager sống từ load đến thoát.
// Nguy hiểm vì khớp nối chéo toàn phần: Tree.Die_Reload -> Tree_manager.Tree_Destroyed chạm 5 singleton cho một cây đổ (G346).
Guard trạng thái toàn cục — bài học từ G132b (L1 ANALYSIS, Enemy.Damaged / Enemy.Die):
if (!Gamemanager.is_gaming) return; // BẮT BUỘC ở từng entry-point combat trong kiến trúc một-scene
// Thiếu dòng này: quái vẫn ăn damage và RƠI TIỀN khi người chơi đang mở shop — không crash, kinh tế sai âm thầm
Xếp hạng công việc bằng dữ liệu — phương pháp (doc 08 §3.5):
(khối mã nội bộ đã lược bỏ)
Gợi ý framework (không phải bằng chứng SOT): mô hình lai — một scene lõi bền + các màn hình phụ tải thêm; is_gaming thành cổng ở tầng framework (base class hoặc IDamageable gate); đo chi phí import ngay từ đầu, không đợi tới 481 MB.
Bẫy đã gặp
- Một scene cho tất cả rồi mới đo. Hoá đơn đến muộn và không đảo được: > 30 phút import (G027), SIGKILL sau 2 544 s (G028), 75 GB RSS đỉnh (G124 toolchain), file 481 MB không merge được.
- Trạng thái rò rỉ xuyên "màn hình". Vì quái/đạn/collider luôn tồn tại, thứ duy nhất chặn combat trong menu là một cờ boolean kiểm ở từng entry-point. Bản dựng lại từng thiếu guard ở
Enemy.Damaged/Enemy.Die(G132b). - Đếm Canvas để kiểm kê màn hình. Doc 08 và RULES R7 ghi "25 Canvas"; đếm lại trên export đã giải mã ra 21, và chỉ 1 là Canvas UI thật (
SCREEN_CATALOG.md§1, G152). Đơn vị màn hình đúng là con củaCanvas/SafeAreavàCanvas/Contents_UI. - Chọn target theo tên class.
BulletShooternghe như trái tim game và có 0 lần gọi;SlicedFilledImagelà class nóng nhất. Không có oracle runtime, lane khôi phục sẽ đổ công vào chỗ vô giá trị (doc 08 §3.5). - Trỏ AssetRipper vào
assets/bin/Datađơn lẻ. Không thấylib/arm64-v8a/libil2cpp.so⇒ không chạy Cpp2IL ⇒ 100 % dummy class. Cây staging phải là layout Android đầy đủ (G123). - Tưởng chữ ký + field là "khôi phục". Cpp2IL dựng chữ ký và field, không bao giờ dựng logic —
Update(),ShootBullet()đều{ }. APK từ export đó là vỏ cấu trúc, không phải game (G129, G115). - Đổ lỗi bảo vệ cho thư viện sai.
libpglarmor.sobị nghi là bộ mã hoá metadata; thực ra là Pangle AD-SDK (G001a). - Nâng version package serialize vào scene mà không kiểm layout.
InfValserialize inline (s_digits,s_exponent); đổi tên field sẽ âm thầm xoá sạch dữ liệu kinh tế (G122). - Chạy job Unity dài trong process group của caller. Bị SIGKILL đúng 60 phút (G120).
Checklist khi tự làm
- [ ] Quyết định cấu trúc scene sớm và đo chi phí import ngay khi scene còn nhỏ; ưu tiên mô hình lai (scene lõi + màn hình phụ).
- [ ] Nếu chọn một-scene: guard trạng thái game là hạ tầng bắt buộc (base class / gate), không phải dòng
ifphải nhớ chép. - [ ] Kiểm kê màn hình theo GameObject con của Canvas gốc, không đếm component
Canvas. - [ ] Ngân sách hình ảnh 2D/2.5D mobile:
RenderScale 0.7+ FSR, tắt MSAA/HDR/bóng, ASTC 6x6, ít atlas lớn (2 × 4096²). - [ ] Bốn quy ước method cho mọi manager (
Balance_Reload/SaveData_return+LoadData/First_Reload+Value_Reload/X_return) — xem 10-tien-trinh-mo-khoa.md. - [ ] Tách máy móc toàn vẹn (
Time_manager, nửaGamemanager) ra module riêng sauITrustedTime. - [ ] Xếp hạng công việc bằng scene census + topology + trace runtime; đừng tin tên.
- [ ] Mua package thật; ghi lệch version thành gap; kiểm layout serialize trước khi tin dùng.
- [ ] Hiểu bảo vệ là quản trị rủi ro: chống dịch ngược (metadata) và chống phân phối lại (license) là hai lớp khác nhau; key phải nằm trong binary nên không ngăn được người quyết tâm.
- [ ] Nói đúng về "khôi phục": chữ ký + field ≠ hành vi.
Điều chưa biết (UNKNOWN)
- Managed stripping level, API compatibility level, cấu hình compiler IL2CPP, scripting defines, thứ tự graphics API: KHÔNG khôi phục được từ evidence (G107; G131 đóng một phần nhờ ScriptableObject URP).
- Phân bố 7 718 ParticleSystem theo gameplay vs UI: UNKNOWN — chỉ biết tổng.
- Hai GUID script đông nhất trong scene (7 991 và 4 957 instance): UNKNOWN — không ánh xạ được sang class
Assembly-CSharp; nằm trong DLL plugin. Không đoán. - Gate build Android trên base đã giải mã: CHƯA CHẠY — import vẫn bị SIGKILL (G028, G123 toolchain).
- Đo hiệu năng trên thiết bị (fps, thermal, memory): CHƯA ĐO.
- 32 shader stub
DummyShaderTextExporter: ĐÓNG MỘT PHẦN (G366) — render state của 3 shader sprite đã đọc từ bundle:Sprites/Fill Amount Batched(1 931 material) vàCustom/MonsterBounce(240) blend premultiplied (One OneMinusSrcAlpha),Custom/DiamondClipSprite(6) blendSrcAlpha OneMinusSrcAlpha; cả baZWrite Off / Cull Off / Queue Transparent, không LOD. Thân hiệu ứng (fill clip, bounce đỉnh, diamond clip) còn là placeholder; dòng premultiplyc.rgb *= c.alà của bản dựng lại, không phải SOT. GLSL đã giải nén, đang port sang HLSL (sẽ dán nhãn reconstruction). .spriteatlaschoCat/_UI: gap chỉ về định dạng (G013) — bảng đóng gói có trong JSON export.- Sprite
Hand: G014 — vắng trong project export, có trong corpus UnityPy. - Hiệu ứng nào cần
RequireDepthTexture: chưa xác nhận (outline là ứng viên xét package Outline Objects — suy luận, không phải kết luận). - Giá trị 25 vs 21 Canvas trong doc 08 §2.2 chưa được doc 08 sửa lại; trang này lấy số của
SCREEN_CATALOG.md(đếm trực tiếp trên export đã giải mã). - Hệ text (đang làm — G397):
ScriptLocalization(317 term, đầu ra công cụ I2) sẽ được dựng lại từ binary như class thường (mỗi getter = một literalGetTranslation("Category/Term")); glyph lỗi ở capsule tiền/dia nghi do font asset TMP (atlas/material/fallback) chưa khớp export; cỡ text/margin là scene-serialized. Chưa có claim nào — ghi để biết đây là một hạng mục riêng của việc khôi phục. Cập nhật (G407): font đã kiểm giống hệt game gốc (18 font asset, 5 sprite asset, 27 material — GUID, atlas, glyph, metrics, fallback); lỗi tìm ra là tài nguyên mẫu của package (TMP Essential Resources, I2 Examples, Shapes) che asset gốc ở 23 đườngResources.Load— "TMP Settings" resolve không tất định ⇒ font/sprite/style mặc định có thể lệch âm thầm. Đang xoá phần che (giữ shader + LiberationSans). Bài học: sau mỗi lần import package, kiểm collisionResources.Loadvới asset của game.
Đọc thêm
docs/framework/08-architecture-and-scale.md— nguồn chínhdocs/framework/07-progression-managers.md§3.1 — bộ khung 35 singletondocs/framework/02-combat-projectiles.md§3.5 — bugis_gaming[liveops catalog: SCREEN_CATALOG.md]— kiểm kê màn hình đầy đủ, đính chính số Canvasgap list (nội bộ)— G001a, G013, G014, G027, G028, G101, G107, G117, G118, G120, G122, G123, G129, G132b, G152[phân tích nội bộ]— hai phân tích độc lập hội tụ