02-kinh-te-so-lon.md · Cập nhật lần cuối: 2026-09-06 23:06 +07 · sha256 nguồn 7c3b72391f6b02 — Kinh tế & số lớn: InfVal, chuỗi nhân, và bảng bake bằng lặp cắt cụt
Nguồn framework:
docs/framework/01-economy-money.md§2–§6,docs/framework/09-prestige-rebirth.md§3.2 (bảng cân bằng thật),[phân tích nội bộ](hai nhà phân tích hội tụ),gap list (nội bộ)G138a / G142 / G143. 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.Đính chính quan trọng: doc 01 §2 (viết trước) có hai dòng đã bị doc 09 §3.2 + CONVERGENCE + G138a thay thế: (a)
ToPrecision(n)CẮT về phía 0, không làm tròn; (b)Balance_Reloadlà dead code — bảng thật là mảng bake sẵn trongMain.unity, sinh bằng lặp có cắt cụt. Trang này dùng phiên bản mới. Mô hình tham chiếueconomy_reference_sim.pytái tạo mảng scene 0/360 lệch với mô hình cắt (mục [M]).
Mục tiêu
Muốn một game idle có tiền tăng vượt double, nhân qua nhiều nguồn multiplier mà không sửa công thức mỗi lần thêm hệ thống,
hiển thị gọn trên điện thoại (134.58b), và — quan trọng nhất — bảng cân bằng bạn ship phải đúng bằng bảng designer nghĩ.
CatGunner giải quyết trọn bộ này, và cũng để lại một bài học đắt: công thức trong code và bảng trong game không giống nhau.
Game gốc làm gì
| Điều game làm | Con số / hằng số | Mức bằng chứng | Nguồn |
|---|---|---|---|
Kiểu số lớn là package thương mại InfiniteValue.InfVal (Asset Store 194963), không tự viết bignum |
value = _digits × 10^s_exponent; serialize string s_digits rồi int s_exponent |
package-source + scene-census | doc 01 §2 (G007, G122) |
| Precision mặc định của đường kinh tế | 5 chữ số có nghĩa (20 → (20000,-3), 152.2 → (15220,-2)) |
runtime-verified | doc 01 §2 (parity samples) |
ToPrecision(n) cắt về n chữ số (không làm tròn) |
code 0x44E0E5C → 0x44DF888; 1 202 phần tử mảng scene khớp 100 % mô hình cắt, 0 % mô hình tròn |
VERIFIED | doc 09 §2; CONVERGENCE U3 |
Tiền tệ là static field trên Gamemanager |
Money @+0x28, Money_Accum @+0x48, Ruby @+0x68 (InfVal); PetCoin @+0xB8 (int); Dia là ObscuredInt |
disasm-proven | doc 01 §2 |
| 4 event đổi tiền tệ | OnMoneyChanged / OnDiaChanged / OnRubyChanged / OnPetCoinChanged (static Action, field-like event) — HUD số dư làm mới chỉ qua chúng; bản dựng lại từng có 14 event bất động do công cụ decompile render accessor rỗng (G376) |
disasm-proven | doc 01 §2 |
Get_Money(v) |
v' = MoneyValue_return(v); Money += v'; Money_Accum += v'; OnMoneyChanged?.Invoke() — 85 lần / 40 s |
disasm-proven + runtime-verified | doc 01 §2 (RVA 0x2A4ECBC) |
MoneyValue_return là chuỗi nhân thu nhập |
Upgrade × Rebirth × Skin × Pet × Relic (mỗi cái /100) rồi × 3 nếu Money_Buff |
disasm-proven + runtime-verified | doc 01 §3.2 (RVA 0x2A4E7B0) |
| Chuỗi là thuần nhân, không có cộng/offset | 20 → 152.2, 60 → 456.6 ⇒ hệ số ×7.61 ổn định; 25 mẫu đều khớp k·x |
runtime-verified | doc 01 §2, §6 |
| Cache LRU cho chuỗi nhân, khoá theo giá trị input | Dictionary<string,InfVal> + Queue<string>, trần 50 (MoneyCacheMaxSize const) |
disasm-proven + metadata-proven | doc 01 §2, §3.3 |
| Cache phải bị xoá khi bất kỳ multiplier nào đổi | Gamemanager.InvalidateMoneyCache() xoá cả dictionary lẫn queue |
disasm-proven | doc 01 §3.3 (RVA 0x2A4E324) |
Lose_Money clamp bằng ((InfVal)0).ToPrecision(5); Lose_Ruby clamp bằng (InfVal)0 trần |
bất đối xứng thật trong binary | disasm-proven | doc 01 §2 (RVA 0x2A4F6E4 / 0x2A4FACC) |
Money_Accum chỉ tăng (wallet vs lifetime) — nhưng bị reset khi Rebirth |
Money_Reset() đặt cả hai về 0 |
disasm-proven | doc 01 §3.4, §6 (RVA 0x2A4F1F8) |
Dia (tiền premium): Get_Dia cộng v vào ví và v × 3 vào sổ gem gửi máy chủ (_getDia); Lose_Dia phản chiếu vào _useDia, không kẹp ở 0; Lose_PetCoin thì có kẹp |
×3 | disasm-proven | doc 01 §2 (G395) |
Save() của game throttle 5 s thời gian thực (nhiều biến đổi tiền tệ liên tiếp không ghi đĩa dồn dập) |
5 s | disasm-proven | doc 01 §2 (G395) |
| Notation hiển thị: ≤ 3 chữ số có nghĩa + đơn vị chữ cái thường, bước 3 bậc | InfVal_change(): mag = exp + len(digits); if mag>=4: mag=(mag-1)%3+3; ToString(mag) — ví dụ 297a, 203.09a |
disasm-proven + runtime-verified | doc 01 §3.5 (RVA 0x44E47D4; 14 cặp parity) |
| Formatter hiển thị cắt | (45660,-2) = 456.6 → "456" (làm tròn sẽ ra 457) |
runtime-verified (1 mẫu phân biệt) | doc 01 §3.5 |
| Đơn vị viết HOA ở text bay trong thế giới, thường ở HUD — cùng giá trị | 3.12A (text sát thương) vs 3.12a (panel nâng cấp), 149.75A (tiền bay) vs 134.58b (số dư) |
observed | doc 01 §3.5.1 (ảnh user_screenshot_stage5-4.png) |
| Throttle floating text theo ô lưới không gian | BUCKET_SIZE = 1.5, DAMAGE_TEXT_COOLDOWN = 0.12, MONEY_TEXT_COOLDOWN = 0.2; CanSpawnText 287 lần / 40 s |
metadata-proven + runtime-observed | doc 01 §2 (dump.cs:583820) |
| Bảng cân bằng lúc chạy = mảng serialize trong scene, không phải hàm sinh | Upgrade_manager Price/Power/Money/Speed @Main.unity:20353425/20373428/20393431/20413434; Rebirth_manager Value ×3 @20451299/20491308/20531317, Price @20571320 |
scene-YAML | doc 09 §2, §3.2 |
Balance_Reload không bao giờ chạy trong 1.1.59 |
CodeRefsTo = [] cho 0x2B4A02C (Upgrade), 0x2B21CB4 (Rebirth), 0x2B0AB4C (Gun); không string literal, không UnityEvent trong scene |
VERIFIED | doc 09 §2; CONVERGENCE; G138a |
| Mảng Money/Power của upgrade sinh bằng lặp có cắt cụt | [0]=100; [i]=trunc3([i-1]·1.08) — tái tạo 0/60 lệch |
VERIFIED | doc 09 §3.2 |
Giá upgrade dùng double nhị phân 1.38 |
acc=50; acc=trunc4(acc·1.38); price=trunc3(int(acc)) ⇒ [1] = 68, không phải 69 (vì 1.38 = 1.3799999999999998…) |
VERIFIED | doc 09 §2 |
Sai lệch tích luỹ so với dạng đóng 100·1.08^lv |
lv 10: 210 vs 215.89 (−2.73 %); lv 46: 3 120 vs 3 447 (−9.50 %); lv 50: −10.24 %; lv 1 000: ~6.5 lần | VERIFIED | doc 09 §3.2 |
| Ảnh chụp save thật khớp mảng scene 4/4 | Speed[46] = 468, Power[46] = Money[46] = 3 120 → 3.12a, Price[46] = 1.34×10⁸ → 134b |
observed + scene-YAML | doc 09 §3.2 |
| Mô hình tham chiếu Python thuần tự kiểm | 58/58 vector (hạng A oracle-live + hạng B dẫn xuất) + mục [M] mảng scene 0/360 lệch | derived | doc 01 §5.6; doc 09 §3.2 |
| Liveops không ghi đè kinh tế qua kênh nào | ServerConfig 15 field toàn ads; Firebase RC 5 key version/offerwall; PlayFab không TitleData | VERIFIED (G144 còn mở) | LIVEOPS_SURFACE §0; CONVERGENCE U4 |
Công thức / pseudocode
1. Kiểu số (mô hình hoá InfVal) — L1 ANALYSIS, doc 01 §3.1 / §5.2
BigNum { digits: BigInteger, exponent: int } value = digits × 10^exponent
precision = 5 chữ số có nghĩa (bằng chứng: (20000,-3), (15220,-2))
serialize = (string digits, int exponent) khớp s_digits / s_exponent của SOT
ToPrecision(n) → CẮT về n chữ số có nghĩa (về phía 0) [VERIFIED: 0x44E0E5C, doc 09]
ToString(n) → CẮT, dùng cho hiển thị [runtime-verified: 456.6 → "456"]
2. Chuỗi thu nhập — L1 ANALYSIS, RVA 0x2A4E7B0 (runtime-verified)
private static InfVal MoneyValue_return(InfVal value)
{
string key = GetMoneyCacheKey(value);
if (_moneyCache != null && _moneyCache.TryGetValue(key, out InfVal cached))
return cached; // hit — không tính lại
InfVal r = value * Upgrade_manager.Money_return() / 100; // Money_balance[Lv] (mảng scene) — RESET khi rebirth
r = r * Rebirth_manager.Money_return() / 100; // Value_balance[2][Lv] + 100 — BỀN qua rebirth
r = r * Skin_manager.Money_Accum / 100; // int %
r = r * Pet_manager.Pet_Money_Accum / 100; // InfVal %
r = r * Relic_manager.Money_Value / 100; // InfVal %
if (Buff_manager.instance != null &&
Buff_manager.instance.IsBuffActive(AD_Type.Money_Buff))
r = r * 3; // buff quảng cáo: ×3 cứng, KHÔNG phải +200 %
if (_moneyCache != null) { // LRU trần 50
if (_moneyCache.Count >= 50) _moneyCache.Remove(_moneyCacheKeys.Dequeue());
_moneyCache[key] = r; _moneyCacheKeys.Enqueue(key);
}
return r;
}
// Gamemanager.InvalidateMoneyCache() [0x2A4E324] xoá cả hai — BẮT BUỘC gọi sau khi mua upgrade / đổi skin / pet / relic / buff.
Gợi ý framework (doc 01 §4, không phải SOT): mỗi nguồn là một IMultiplierSource.PercentFor(kind) trả 100 = trung tính;
pipeline sources.Aggregate(base, (acc, s) => acc * s.PercentFor(kind) / 100); buff/event là tầng riêng nhân sau và phải đi qua
service fail-closed; source bắn event để cache tự invalidate thay vì trông chờ call-site nhớ.
3. Formatter hiển thị — L1 ANALYSIS, RVA 0x44E47D4
public readonly string InfVal_change()
{
int mag = exponent + digits.ToString().Length; // tổng bậc độ lớn
if (mag >= 4) mag = (mag - 1) % 3 + 3; // ép về 3..5, canh theo nhóm nghìn
return ToString(mag); // maxDisplayedDigits; đơn vị a, b, c… bước 3 bậc; CẮT
}
// Ground truth: (100,0)→"100" (500,-1)→"50" (297,3)→"297a" (45660,-2)→"456" (15220,-2)→"152" (0,-4)→"0"
4. Bảng cân bằng — BAKE BẰNG LẶP CẮT CỤT, không phải pow() — VERIFIED, doc 09 §3.2
# Tái tạo đúng mảng trong Main.unity (0/360 lệch, lv 0..59 đã đối chiếu) — economy_reference_sim.py mục [M]
def trunc(x, n): ... # cắt về n chữ số có nghĩa, về phía 0 (ToPrecision của InfVal)
# Upgrade Money_balance / Power_balance (Main.unity:20393431 / :20373428)
v = 100
for i in range(1, N): v = trunc(v * 1.08, 3) # KHÔNG PHẢI 100 * 1.08**i
# Upgrade Speed_balance (:20413434) — tuyến tính, khớp chính xác
speed[lv] = 100 + 8 * lv
# Upgrade Price_balance (:20353425) — 1.38 là DOUBLE NHỊ PHÂN 1.3799999999999998…
acc = 50
for i in range(1, N):
acc = trunc(acc * 1.38, 4)
price[i] = trunc(int(acc), 3) # price[1] = 68, không phải 69
# Rebirth Value_balance[0] (Damage) và [2] (Money) (:20451299 / :20531317)
value[lv] = trunc(int(trunc(1.05**lv * 100 - 100, 3)), 3) # ≈ 1.05^lv nhưng LUÔN thấp hơn
# Rebirth Value_balance[1] (Speed) (:20491308)
value[lv] = 5 * lv
# Rebirth Price_balance (Ruby, :20571320)
price[lv] = trunc(int(trunc(3 * (lv + 1) ** 1.6, 4)), 3)
Bảng lệch (doc 09 §3.2, đọc thẳng từ mảng scene):
| lv | Money_balance mảng thật |
100·1.08^lv |
lệch |
|---|---|---|---|
| 1 | 108 | 108.00 | 0 % |
| 2 | 116 | 116.64 | −0.55 % |
| 10 | 210 | 215.89 | −2.73 % |
| 46 | 3 120 | 3 447.41 | −9.50 % |
| 50 | 4 210 | 4 690.16 | −10.24 % |
| 1 000 | 4.06e34 |
2.65e35 |
~6.5 lần |
Sai số luôn một chiều (thấp hơn) vì cắt không bao giờ làm tăng.
4b. Bảng chỉ số theo HẠNG — hàm mũ hai cơ số + làm tròn theo chữ số có nghĩa (doc 01 §4 mục 8–9)
Bảng ở §4 là bảng cấp nâng cấp (hàng trăm mức, bake bằng lặp cắt cụt). Còn khi bạn cần một bảng hạng vật phẩm ngắn (10–13 hạng: pet, cá, súng), khuôn đã chạy thật đơn giản hơn nhiều — và mỗi trục chỉ số được một cơ số riêng:
# 13 hạng cá — công thức thật, đã đối chiếu với mảng bake bằng hai tổng đọc trên máy
for i in range(13):
Damage = round_sig(4 * 3 ** i, 2) # trục CHÍNH, cơ số 3
CriPer = clamp(round_sig( 2.5 ** i, 2), 0, 100) # trục PHỤ, cơ số 2.5, có TRẦN
CriVal = round_sig(8 * 2.5 ** i, 2)
def round_sig(x, digits=2): # 2 chữ số có nghĩa
if x == 0: return 0
exp = floor(log10(abs(x)))
scale = 10 ** (digits - exp - 1)
return int(round(round(x * scale) / scale)) # LÀM TRÒN ToEven: 125 -> 120, không phải 130
| hạng | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Damage % | 4 | 12 | 36 | 110 | 320 | 970 | 2900 | 8700 | 26000 | 79000 | 240000 | 710000 | 2100000 |
| CriPer % | 1 | 2 | 6 | 16 | 39 | 98 | 100 | 100 | 100 | 100 | 100 | 100 | 100 |
| CriVal % | 8 | 20 | 50 | 120 | 310 | 780 | 2000 | 4900 | 12000 | 31000 | 76000 | 190000 | 480000 |
Ba thứ đáng chép:
round_sig(x, 2)chứ không phải số thô. Bảng đọc lên như bảng do người viết (110,320,970) chứ không phải108,324,972. Chi phí: sáu dòng. Nhớ khai báo tường minh là làm tròn ToEven, không phải cắt nhưToPrecisionở §4 — hai thao tác khác nhau, dùng lẫn là ra bảng khác (xem "Bẫy đã gặp").- Hai cơ số tách hai trục ra theo thời gian.
3^12 ≈ 531 000so với2.5^12 ≈ 60 000: sau 12 bậc trục chính bỏ xa trục phụ ~9 lần. Bạn chọn tốc độ tương đối giữa các chỉ số bằng một con số mỗi trục, không phải bằng 13 ô bảng gõ tay. - Chỉ số phụ nên có TRẦN, và trần nên nằm GIỮA bảng.
CriPerchạm 100 ngay từ hạng 6 ⇒ một nửa bảng không cộng thêm một điểm tỉ lệ chí mạng nào. Cố ý: nó ngăn con số vô nghĩa ("chí mạng 400%") mà vẫn giữ công thức gọn, và rút gọn không gian quyết định theo thời gian — đầu game người chơi cân ba chỉ số, cuối game chỉ còn một trục. Kỹ thuật:clampphải nằm trong hàm sinh (bảng bake đã sạch) và lặp lại ở chỗ hiển thị TỔNG — tổng của nhiều vật phẩm vẫn vượt trần dù mỗi vật phẩm đã bị chặn.
Mẹo đối chiếu rẻ nhất (khi không muốn mở file scene hàng trăm MB để đọc mảng bake): chọn một hồ
sơ save có các hạng khác nhau rồi so TỔNG hiển thị trên UI, không so từng ô. Với kho
[0, 0, 1, 2, 5], bảng trên cho tổng Damage = 1026 và tổng CriVal = 866; màn hình in +1.02a%
và 991% (= 866 + hằng nền 125). Hai tổng độc lập khớp là đủ để kết luận mảng bake đúng bằng
công thức — mà chỉ tốn một lần chụp màn hình.
5. Ví tiền — hợp đồng hành vi (doc 01 §5.3)
GetMoney(v) : v' = Chain(v); Money += v'; MoneyAccum += v'; fire(OnMoneyChanged); return v'
GetMoney(v, pos) : v' = GetMoney(v); SpawnText(v'.ToDisplayString(), pos) [text bay trong thế giới]
LoseMoney(v) : Money -= v; if (Money < 0) Money = Zero.ToPrecision(5); fire()
MoneyReset() : Money = 0; MoneyAccum = 0; fire() [gọi bởi Rebirth()]
GetRuby / LoseRuby : Ruby ±= v; if (Ruby < 0) Ruby = 0 [KHÔNG ToPrecision]; fire()
LosePetCoin : clamp >= 0; có call-site analytics (R1 → IAnalyticsService)
Bẫy đã gặp
- Dùng
pow()/ dạng đóng để sinh bảng. Mô hình đầu tiên của chính dự án này dùng công thức + làm tròn: dự đoán panel Lv.46 là3.5avà giá136b; ảnh chụp thật là3.12avà134b. Sai 2/3 ô — và chính hai ô lệch đó lật lại mô hình (doc 09 §3.2, D008/D010). Bảng là nguồn sự thật; hàm sinh chỉ là công cụ Editor. Với restore: giữ nguyên mảng serialize, đừng gọiBalance_Reload. - Nhầm hai thao tác "làm tròn" và "cắt".
ToPrecision(n)(số học) vàToString(n)(hiển thị) đều cắt trong SOT; doc 01 §2/§3.5 còn ghiToPrecisionlàm tròn — đó là dòng cũ, đã bị doc 09 §2 + CONVERGENCE U3 thay thế. Một InfVal khác version (làm tròn) sẽ sinh ra một nền kinh tế khác SOT (G007a: bản store v2.2.0 có thể làm tròn — phải chạyInfVal.ParityTest.csđể chốt). 1.38không phải 1.38. Hằng số là double nhị phân;Price_balance[1] = 68chứ không 69. Nếu bạn bake bằngdecimalbạn sẽ ra bảng khác.- Quên
InvalidateMoneyCache()sau khi mua upgrade ⇒ người chơi trả tiền mà thu nhập không tăng cho tới khi key bị đẩy khỏi LRU — bug im lặng, cực khó truy (doc 01 §3.3). - Một formatter cho mọi chỗ. SOT hiển thị
3.12Aở text bay và3.12aở HUD. Restore chỉ dùngInfVal_change()sẽ sai ở text bay. Đường code viết hoa chưa biết (UNKNOWN-pending) — đừng giả định.ToUpper(). - Đổi tên field serialize của kiểu số.
Main.unityserializeInfValinline (s_digits/s_exponent) vào hàng nghìn component; nâng version package mà đổi tên field = âm thầm mất toàn bộ số liệu kinh tế (doc 01 §3.1; G122 đã kiểm layout v2.2.0 khớp). - Trộn kinh tế với máy móc toàn vẹn. Một nửa
Gamemanager(70 method) là chống gian lận thời gian / autosave; tầng kinh tế phải chạy được không cần Unity, không cần mạng — đó là lý do có simulator (doc 01 §5). - Stub quảng cáo trả "đã thưởng". Nhánh
×3chỉ được bật bởi service thật;NullAdServicetrảNotAvailable(R1, doc 01 §3.6). - Lấy bảng số từ CONSTRUCTOR thay vì từ scene. Với field
public/[SerializeField]có mặt trong scene, scene THẮNG lúc chạy; ctor chỉ là mặc định khiAddComponentlên một prefab mới. Dự án này sai hai lần vì bỏ qua điều đó:FormationRadius(ctor 10 / scene 2.5) và bảng tỉ lệ gacha cá (ctor{40,30,20,10}/ scene{60,30,10,0}— đã publish bảng sai ra dashboard trước khi bị bắt). Luật đọc:public/[SerializeField]có trong scene ⇒ scene thắng;privatekhông[SerializeField]⇒ ctor là giá trị thật (scene không cứu được);const/static readonly⇒ ctor thắng. Với bảng chỉ số cá (§4b) thì hai nguồn khớp nhau — nên bài học không phải "đừng tin ctor" mà là "phải kiểm loại field trước khi tin bất kỳ con số cân bằng nào". Phép thử rẻ khi chưa đọc được dữ liệu gốc: một kiểm tra tần suất — N lượt liên tiếp ra cùng kết quả có xác suất bao nhiêu với mỗi bảng? (0,6⁵ ≈ 7,8%với bảng thật so với0,4⁵ ≈ 1%với bảng ctor — đủ lệch để đi đọc lại.)
Checklist khi tự làm
- [ ] Tiền là một kiểu bignum theo chữ số có nghĩa, serialize được dạng text; không có
doubletrên đường thu nhập. - [ ] Mọi nguồn multiplier trả phần trăm, mặc định 100; thêm hệ thống = đăng ký thêm source, không sửa công thức.
- [ ] Buff / event / ad là tầng riêng, nhân sau, đi qua service fail-closed.
- [ ] Cache theo giá trị input, LRU trần nhỏ, và invalidate tự động khi source đổi (source bắn event).
- [ ] Tách
Wallet(tiêu được) khỏiLifetimeEarned(chỉ tăng); quyết định rõ cái nào reset khi prestige. - [ ] Formatter là contract có test parity (bộ cặp
(giá trị → chuỗi)), quy tắc cắt/làm tròn khai báo tường minh. - [ ] Bảng cân bằng: chọn tường minh "đệ quy có lượng tử" hay "dạng đóng", ghi
quantizeDigits, và bake ra asset — asset là nguồn sự thật. - [ ] Nếu bake, kiểm bằng bộ vector thật (ảnh chụp / oracle) ở ít nhất 3 level cách xa nhau.
- [ ] Bảng hạng vật phẩm (10–13 hạng): một cơ số mũ cho mỗi trục chỉ số, làm tròn 2 chữ số có nghĩa, và ít nhất một trục phụ có trần chạm giữa bảng (§4b).
- [ ]
clampcủa trục phụ phải có ở hai chỗ: trong hàm sinh và ở chỗ cộng tổng để hiển thị. - [ ] Đối chiếu bảng bake bằng TỔNG của một hồ sơ nhiều hạng khác nhau, không cần đọc mảng trong scene.
- [ ] Throttle floating text ở tầng framework (ô lưới + cooldown theo loại text).
- [ ] Tầng kinh tế chạy độc lập (simulator không đồ hoạ) trước khi cắm vào Unity.
Điều chưa biết (UNKNOWN)
Chép từ doc 01 §6 và doc 09 §5, cập nhật theo CONVERGENCE:
- Đường code viết HOA đơn vị ở text bay (
3.12A) vs thường ở HUD (3.12a): UNKNOWN-pending — hiện tượng đã xác nhận bằng ảnh, đường code chưa. Khoá bằng disasmDamage_Txt_Spawn0x2A50594,Critical_Txt_Spawn0x2A506AC,Money_Txt_Spawn0x2A4EF48. ToString(int)cắt: đã chốt CẮT nhưng dựa trên một mẫu phân biệt (456.6 → "456"). Khoá bằng mở rộng parity ở giá trị lớn +InfVal.ParityTest.cs.- Thứ tự đơn vị sau
z(aa,ab… hayA,B) ở bậc rất lớn: UNKNOWN — mẫu hiện tại dừng ởa. - ~~
GetMoneyCacheKeysinh key chính xác thế nào~~: ĐÃ ĐÓNG (G400) — chuỗi 7 phầngiá trị | Upgrade | Rebirth | Skin | Pet | Relic | buff đang bật, tức key liệt kê đúng mọi nguồn multiplier của chuỗi thu nhập ⇒ đổi bất kỳ mắt nào là key khác, cache tự vô hiệu (bổ sung choInvalidateMoneyCache). Stub trả null của nó từng làm tra cache ném và huỷ khoản trả offline trên thiết bị (G394). - Phân rã hệ số ×7.61 theo từng nguồn: UNKNOWN — chỉ đo được tích, trên một save đã tiến xa không ghi lại state (G142). Lần oracle
sau phải log 5 getter
Money_return+IsBuffActivecùng lúc. - Version InfVal chính xác mà SOT ship: UNKNOWN — chỉ biết "cũ hơn 2.2.0, có API
unitsList/DisplayOption/InfVal_change". - Kinh tế offline là một mô hình riêng (
OfflineProgressSimulator, capMaxOfflineSeconds 28800+ relicOffline_Value·60): đã dựng trọn — harness độc lập tái tạo khoản trả của game gốc 17 chữ số (G382; 12 luật + ví dụ ở 14). Đính chính: Skin/Pet/Relic có áp offline, chỉ buff quảng cáo ×3 không. FallbackMath.Pow(1.08)không thể chạy trong 1.1.59 (doc 01 §5.8). Mô hình tham chiếueconomy_reference_sim.pykhông có mô hình clear-wave nên không cho ra được con số tiền — gap đã ghi (G1000). - Cache LRU (
_moneyCache,_moneyCacheKeys) và_textCooldownsđược cấp trong static ctor củaGamemanager— công cụ decompile bỏ rơi khởi tạo này; bản dựng lại thiếu nó NRE ở lần đầu chạm cache (G319). Không phải UNKNOWN, là bẫy khôi phục đã đóng. - Mảng scene chỉ mới đối chiếu lv 0…59; điểm gãy
×1.002(lv ≥ 14 999) và×2.0(lv ≥ 5 000) chỉ tồn tại trongBalance_Reloadđã chết — UNKNOWN trong mảng thật ở tầm level đó. - Đã giải quyết (không còn UNKNOWN, ghi để khỏi tìm lại): lệch giá
136bvs134bvà panel3.12a≠3500trong doc 01 §6 là do mô hình cũ dùng công thức + làm tròn; mảng scene khớp 4/4 (doc 09 §3.2).Money_Accumcó bị reset khi rebirth: CÓ. Liveops ghi đè kinh tế: KHÔNG (CONVERGENCE U4), ngoại trừ rủi ro G144 (Google Sheet súng) còn phải probe.
Đọc thêm
docs/framework/01-economy-money.md— đặc tả module kinh tế chạy độc lập + simulator (§5)docs/framework/09-prestige-rebirth.md§3.2 — "công thức của designer vs bảng đã ship"[F001: economy_reference_sim.py]— chạypython3để tự kiểm 58 vector + mục [M][phân tích nội bộ]— U3 (ToPrecisioncắt), U4 (không remote override), dead code[liveops catalog: LIVEOPS_SURFACE.md]§0, §4 — liveops và rủi ro G144- 03 Prestige / Rebirth — mắt
Rebirth_manager.Money_return()trong chuỗi gap list (nội bộ)— G007, G007a, G122, G129, G138a, G142, G143