Startup, version-check & hot-update
Cold-start state machine
18 states: Logo, Permission, CheckResVersion, DownloadManifest/DownloadUpdate, LoadDataTable, GetServerList, ConnectGame, Login, LoadScene→EnterGame. 1.0.364: CheckResVersion clears cached IP/port/conn-type on every cold start so the GSL call always runs static; the cached ip/port/zone shortcut (state 6→9) is taken only on mid-session reconnect (serverInfo redirect).
Check-version
GET {host}/gameservice/getlsu3dversion.php?packageName=com.fun.lastwar.gp&...&gm=0&server=<cached zone>&table_env=table_online&buildId=<versionCode>&returnJson=1&unityVersion=440. table_env=table_online is required for the server to return table_version and locale [live, 2026-10-05 A/B]; earlier builds sent both empty and were still answered live.
- Hosts raced in parallel, first success wins; the winner becomes the base URL for
getserverlist.php,getnotice.php,probe.php. ~5% of devices are A/B'd toea-hosts viaGrayUtils.GetPercentageFromMd5=MD5(deviceId)read as LE uint64,mod 100 + 1 <= 5. Hosts:lastwar-serverlist-cf.lastwarapp.net,lastwar-serverlist-us-aws-ali.lastwargame.com,lastwar-serverlist-us-gcp-ali.lastwargame.com; ea bucket:lastwar-serverlist-ea-us-aws.lastwargame.com,-ea-us-gcp-. A valid response = non-emptycode(error) orupdateTypein 0..3 + non-emptyhotUpdateMsg. - Response fields (parser
CheckResVersionState): resMsg= Base64 DER RSA pubkey, fresh each check, feeds the GSL cryptoupdateType:0patch,1optional dialog,2forced/blocking,3falls todefault→ acts as0(Login handler rewrites 3→0);downloadurlstore linkhotUpdateMsg=;-separatedname,version,size,crc32overGameRes,DllRes,DataTable,Lua,Download,PackageRes(size/crc32 = the manifest file itself; APKgameres.version=2342,18537644,856103597) staticlwfile2=version|bzSize|bzCrc[|rawSize|rawCrc];oldVer|patchSize|patchCrc;...(patch only when the local version matches anoldVer)table_version=version,size,md5[,crc][;patch chain];locale=version,lang1,...client_config=|-separated"0"/"1"indexed by switch id (ClientSwitch.IsOn(N))checkok— review mode only (skips table+locale updates). Live iOS 1.0.344(786) reply carried only 8 of these fields plustable_version/locale/emptyx_table_versionwithtable_onlinelive.- The Login response may carry
updateType(SFS Int) +new_version(UtfString); cross-server Login with 2 fails error 9 (1.0.367); 2026-10-04 iOS gotupdateType=3,new_version=1.0.350live.new_versiononly gates role creation viaShumeiSdkManager.IsForbidCreateRolestatic. resVersion={GameRes}.{DllRes}_{lwfile2 version}F_{table_version}.{locale}; e.g.2159.1505_821F_39516.23570live. The tail is local state:CURRENT_TABLE_VERSION,LOCALE_VERSION. 1.0.364 APK baseline2342.1501_825F_39432.23557; goclient sends"0"for missing parts — accepted for months.
4 independently-patched payloads
- Asset bundles (
gameres) - C# assemblies: 118 XOR'd
.mdlinassets/Assemblies/;noUpdateAssemblies.json=[{"name":"SmartFox2X"}];dllresv1501 lists 117 remote<asm>.encrypt.bytes; nomscorlibentry; updates land inpersistentDataPath/Assemblies/<asm>.mdl, searched before the APK static - Lua bundle: flat
LWLFfile, no AssetBundle - Tables: plain ZIP
table_*.data
On-disk XOR wrap
ChaCha reduced to 8 rounds (4 double-rounds), IETF layout, detected by magic swap:
| Plain magic | Wrapped | Content | Keystream starts |
|---|---|---|---|
50 4B 03 04 | CHAC | table ZIP | byte 4 |
42 5A 68 (BZh) | PRB | bzip2 (Lua bundle) | byte 4 |
BSDIFF | PURBDP | bsdiff patch | byte 8 (bytes 6-7 plaintext) |
Keys derived via two self-referential ChaCha8 passes static.
XAssetPro (VEngine 6.1.5)
BundleFragment0.bytes = 539 MB, 8,059 UnityFS bundles end-to-end, no gaps; engine version stripped (5.x.x/0.0.0; real engine 2019.4.41f1); LZ4HC blocks. BundleOffsetTable.bytes/AliasOffsetTable.bytes map name/alias → (fragment index << 32) | offset; opened via AssetBundle.LoadFromFile(fragment, 0, offset). Manifests are text ([Version],[Directories],[Paths],[Bundles],[Groups]); bundle line id,name,crc32,size,pathIds,depIds,downloadModes,alias; alias = sha256(name w/o ext) + ext; 32-hex name suffix = MD5 of bytes; .version stamp version,size,crc32. Pack = bundles with downloadModes incl 0 (Base): 8,059 of 36,745 (gameres v2342), 539 MB of 3.04 GB; the rest on demand.
CDN & Lua bundle
- CDN:
https://lastwar-cdn.akamaized.net/hotupdate/primary, fallbackslastwar-cdn.lastwarapp.net,cdn.lastwar.com. Path<CDN>/<app id>/<Android|iOS>/<file>; manifest fetched as ZIP<name>_small_v<version>, CRC-checked; bundles by plain name only (alias HEAD → 404, name → 200) live. TLS certificate validation is disabled on this download path; integrity = manifest CRC-32 only static. - Lua bundle:
LWScripts_<version>_u440.bz2, patchLWScripts_<new>_<old>_u440.patch; app idscom.fun.lastwar.gp/com.lastwar.ios; CDN copy is plain bzip2, the disk copy is re-encrypted asLWLFv2. Versions 780–826 all HTTP 200 live. Chunk counts: v793 = 18,514 (1.0.351), v825 = 18,733 (1.0.364 APK, tag20260921_1892_App), v826 = 18,740 (live Android; 827/830 → 404), v821 = 18,740 (live iOS). Request schemas identical across all four.