Pembongkaran stack teknologi sebuah game mining/factory co-op skala besar, dan cara game ini menyelesaikan tiga hal yang jadi titik lemah tim: multiplayer, terraforming, dan optimasi + save/load ukuran besar.
Game ini di-build dengan IL2CPP, bukan Mono. Tidak ada Assembly-CSharp.dll managed; kode C# sudah diterjemahkan ke C++ lalu native machine code di dalam GameAssembly.dll (95 MB). dotPeek/ILSpy/dnSpy tidak punya IL untuk dibaca. Analisis ini memakai metadata IL2CPP (global-metadata.dat, 24 MB, tidak dienkripsi — magic AF1BB1FA) yang menyimpan seluruh nama namespace, class, method, dan field sebagai teks. Dari situ + manifest assembly (ScriptingAssemblies.json) arsitektur bisa direkonstruksi. Untuk stub C# lengkap, metadata v39 ini hanya didukung Cpp2IL — Il2CppDumper berhenti di v31 (lihat Bagian C); untuk aset, AssetRipper / AssetStudio.
Tiap library/aset pihak ketiga yang terdeteksi di build, perannya, dan sumber resminya. Semua link sudah diverifikasi.
| Teknologi | Pembuat | Peran | Sumber |
|---|---|---|---|
| Unity 6.3 (6000.3.13f1) | Unity | Engine, backend IL2CPP, render URP | Docs |
| URP + GPU Resident Drawer | Unity | Render pipeline, batching GPU-driven | Docs |
| FSR 3 / FSR 4 / DLSS Upscaling | The Naked Dev | Tiga upscaler resolusi | Situs · FSR3 · FSR4 · DLSS |
| Horizon Based Ambient Occlusion | Michaël Jimenez | AO screen-space teroptimasi | Asset Store |
| Linework | Alexander Ameye | Outline & edge detection (URP) | Situs · Asset Store |
| Translucent Image | Le Loc Tai | Blur latar UI berperforma | Situs · Asset Store |
| URP Volumetric Fog | CristianQiu (open-source) | Kabut & pencahayaan volumetrik, mendukung Render Graph Unity 6 | GitHub · OpenUPM |
| Teknologi | Pembuat | Peran | Sumber |
|---|---|---|---|
| Mirror | Mirror Networking | Networking HLAPI, host/listen-server | GitHub · Docs |
| kcp2k · Telepathy · SimpleWeb | Mirror Networking | Transport UDP / TCP / WebSocket | kcp2k · Telepathy · SimpleWeb |
| FizzySteamworks | Chykary | Transport Mirror via Steam P2P/relay | GitHub · Docs |
| Steamworks.NET | Riley Labrecque | Wrapper C# untuk Steam API | GitHub |
| Toolkit for Steamworks | Heathen Engineering | Lobby, matchmaking, invite, voice | Asset Store · KB |
| Concentus | lostromb | Codec Opus untuk voice chat | GitHub |
| Teknologi | Pembuat | Peran | Sumber |
|---|---|---|---|
| Digger / Digger PRO | ofux | Terraform voxel (marching cubes) di atas Unity Terrain | Asset Store · Docs |
| Unity Terrain + Splines + ProBuilder | Unity | Terrain dasar, spline, CSG mesh | Docs |
| BurstTriangulator | andywiecko | Triangulasi Delaunay ber-Burst | GitHub |
| Clipper2 | Angus Johnson | Clipping/offset poligon 2D | GitHub |
| A* Pathfinding Project Pro | Aron Granberg | Pathfinding pekerja & kendaraan | Situs · Asset Store |
| Urban Traffic & Pedestrian System | Gley | AI lalu lintas & pejalan kaki | Situs · Asset Store |
| Simple Car Controller (SCC) | BoneCracker Games | Kontroler kendaraan berbasis fisika | Situs · Asset Store |
| Teknologi | Pembuat | Peran | Sumber |
|---|---|---|---|
| Burst · Jobs · Collections · Mathematics | Unity | Kode SIMD native multithread (DOTS core) | Docs |
| Optimizers | FImpossible Creations | LOD/culling runtime (renderer, light, fisika, audio) | Asset Store |
| Nature Renderer | Visual Design Cafe | GPU instancing vegetasi | Situs · GitHub |
| UnityMeshSimplifier | Whinarn | Decimasi mesh / LOD otomatis | GitHub |
| UniStorm | Black Horizon Studios | Cuaca dinamis, awan volumetrik | Asset Store · GitHub |
| Enviro 3 — Sky and Weather | Hendrik Haupt | Langit, awan & cuaca modular | Asset Store |
| The Toby Foliage Engine | Tobyfredson | Shader vegetasi & angin | Asset Store |
| Shatter Stone | NV3D | Aset 3D props tambang (bijih, gemstone, logam) | Bundle · Metal Ores |
| ALINE | Aron Granberg | Debug drawing runtime (Drawing.dll) | Situs |
| Teknologi | Pembuat | Peran | Sumber |
|---|---|---|---|
| NanoSave | Fullscreen | Save berbasis slot: gzip, backup, metadata + screenshot | Asset Store · Docs |
| Game Creator 2 | Catsoft Works | Framework gameplay, variabel, save system | Asset Store |
| Newtonsoft.Json | James Newton-King | Serialisasi JSON save | GitHub |
| Settings & Game Options | KAMGAM | Generator menu opsi terpadu | Asset Store · Manual |
| I2 Localization | Inter Illusion | Sistem lokalisasi | Asset Store · Manual |
| Tasty Pie Menu | XAMIN Software | Radial / pie menu UI | Asset Store |
| NAudio | Mark Heath | Pemrosesan audio (.NET) | GitHub |
| Cinemachine · Visual Scripting · Input System · Timeline · Recorder | Unity | Kamera, scripting visual, input, dsb. | Daftar paket Unity |
Seluruh library pihak ketiga yang terdeteksi sudah teridentifikasi dan link sumbernya diverifikasi. Mayoritas aset berbayar dari Asset Store, sisanya open-source (GitHub/OpenUPM).
Co-op host/listen-server lewat Steam — tanpa server dedicated, tanpa port-forwarding. Satu pemain jadi host, sisanya join via lobby Steam.
Mirror sebagai HLAPI (abstraksi [Command] [ClientRpc] SyncVar di atas transport), FizzySteamworks sebagai transport di atas Steam P2P/relay, dan Heathen Steamworks untuk lobby + matchmaking. Ada NetworkRoomManager/NetworkLobbyManager (room dulu, baru masuk game), plus NetworkDiscovery untuk LAN.
Bukan voxel dari nol. Unity Terrain sebagai dasar, Digger PRO menempelkan lapisan voxel untuk lubang, gua, dan overhang yang bisa digali real-time.
Digger PRO — voxel + MarchingCubesPolygonizer di atas Unity Terrain, dengan generasi mesh di Burst Jobs (AdvancedVoxelGenerationJob) dan native collections. Ditambah BurstTriangulator dan UnityMeshSimplifier untuk LOD hasil galian.
Dua sisi: menjaga frame-rate di dunia besar, dan menulis/membaca save yang besar tanpa nge-freeze — dengan trik "simpan delta, bukan dunia".
boot.config) + incremental GC (gc-max-time-slice=3).struct SaveData-nya sendiri + versi. Skalabel, mudah migrasi.Metadata Unity 6.3 memakai format baru (v39) yang belum didukung Il2CppDumper. Dump berhasil dengan Cpp2IL → 162 stub DLL (bisa dibuka di dotPeek) + Assembly-CSharp.dll di-decompile jadi ~57.500 baris C#. Dua pola ini terkonfirmasi dari kode asli, bukan tebakan.
IGameSaveSetiap sistem gameplay yang perlu disimpan meng-implement satu kontrak — bukan sekadar "serialize", tapi lengkap dengan identitas & mode load:
interface IGameSave {
string SaveID { get; } // kunci unik per sistem
bool IsShared { get; } // state dunia (shared) vs per-pemain
Type SaveType { get; } // tipe objek *SaveData
LoadMode LoadMode { get; } // enum: kapan/bagaimana di-load
object GetSaveData(bool includeNonSavable); // serialize
Task OnLoad(object value); // deserialize + apply (async)
}
Yang meng-implement (semua sekaligus NetworkBehaviour): FactoryManager T_ConveyorBelt CaveSystemManager T_MinerVehicle DigSiteHazardManager FactoryCustomizationManager — SaveLoadGameManager enumerasi semua, panggil GetSaveData(), lalu saat load panggil OnLoad(value) async (Task) supaya sistem berat tidak nge-block. Flag includeNonSavable membuat satu method melayani dua mode (save penuh vs capture ringan).
DiggerReplayMessengerMenggali disinkron ke client dengan dua strategi lewat Mirror NetworkMessage:
struct ReplayOp { Vector3 pos; byte brush; byte action; float size, opacity; sbyte textureIndex; } — tiap galian jadi op mungil (perhatikan tipe hemat: byte/sbyte). Dikirim batch via ReplayChunkMsg(List<ReplayOp>) dengan ReplayBeginMsg{startIndex} dan ClientReadyForReplayMsg{lastKnownIndex} → client hanya menerima op setelah yang sudah dimilikinya (catch-up inkremental), lalu memutar ulang untuk merekonstruksi terrain.
FileSnapshotBeginMsg{totalFiles} → FileDataMsg{fileName, byte[] compressedData, uncompressedSize} per file → FileSnapshotEndMsg → FileBatchAckMsg. File voxel Digger dikirim gzip, per-batch, dengan ack, diterapkan lewat coroutine Co_ApplyFileSnapshot.
Pelajaran: kirim intent kecil saat bisa (op-list deterministik), fallback ke transfer file terkompresi berbatch untuk state besar. Persistence & late-join memakai serializer yang sama.
Dari NewNetworkManager : NetworkManager dan SaveLoadGameManager — lima pola yang bikin dunia besar + multiplayer tetap stabil.
OnServerAddPlayer → HandlePlayerLoadingCompletion(conn), dan di dalamnya server menyerahkan ke DiggerReplayMessenger untuk men-stream state galian ke pemain baru. Traffic juga: SendTrafficInitialStateNextFrame._activeReasons — tiap subsistem mendaftar "masih loading"; UI hilang saat semua selesai (HasPendingOperations). Cara bersih menangani load multi-sistem tanpa menebak "kapan siap".Task SaveGame() (non-blocking) dengan ShowSavingPanelOnAllClients() / HideSavingPanelOnAllClients(). Autosave dipicu event OnDayStarted (batas hari), bukan timer sembarang.StartHostSafe / StartServerOnlySafe / StartClientSafe, dan DisconnectReason + DisconnectReasonMessage → client tahu kenapa terputus (kick, lobby penuh, host stop) dan tampilkan pesan tepat.GamePlayer + tuning streamState pemain disebar lewat SyncVar (auto server→client, dengan hook): playerName playerSteamId isInDigsite customizationIDs vehicleNetId. Aksi memakai satu pola konsisten — wrapper publik → [Command] → Server* → [ClientRpc]/[TargetRpc]: mis. NetworkTeleport → CmdTeleport → RpcTeleport → ApplyTeleportLocal; damage SendDamage → CmdReceiveDamage → ServerReceiveDamage → TargetReceiveDamage. Semua mutasi lewat server. Voice: field SteamVoiceChat voiceChat per pemain.
Nilai yang menentukan mulus-tidaknya transfer terrain besar (semua di Inspector): REPLAY_CHUNK_SIZE (op per pesan), APPLY_PER_FRAME (op diterapkan per frame — anti-hitch), FILES_PER_BATCH, FILE_BATCH_DELAY, COMPRESS_FILE_DATA (gzip), USE_ACK_FLOW_CONTROL + ACK_TIMEOUT (tunggu ack sebelum batch berikut). Per-koneksi dilacak _lastSentIndex/_lastAckReceived untuk catch-up inkremental.
IGameSave end-to-end: FactoryManager & CaveSystemManagerDua implementasi nyata — pola save + netcode yang paling layak ditiru tim.
FactorySaveData hanya { money, currentXP, level, name }; CaveSystemSaveData hanya List<CaveSaveEntry> berisi flag ringkas (aktif/pecah/item-spawned + jumlah node). OnLoad(object) cast balik & terapkan. Tidak ada GameObject/mesh yang di-serialize.CURRENT_SAVE_VERSION → migrasi save bisa per-item, bukan hanya per-file global.AddMoney → CmdAddMoney (client→server) → ServerAddMoney (validasi + tulis SyncVar _money) → auto-propagate → OnMoneyChangedHook update UI di semua client. Client tak pernah ubah uang langsung — anti-cheat + konsisten._money/_currentXP/_level → properti read-only terhitung (XPProgress, RequiredXPForNextLevel) dari LevelConfigSO. UI tidak menyentuh field mentah.ApplyCaveActive/ApplyDoorBroken), tapi yang disimpan hanya List<CaveSaveEntry> — delta, bukan geometri.IsDemoLevelLimitReached + CmdSetLevel menolak naik di atas cap demo (Level 3) di sisi server — tak bisa dibypass client.Dari sistem produksi, pekerja, logistik, dan ekonomi — pola arsitektur yang bisa langsung tim adopsi.
Item cuma data: ItemStack { string itemId; int count; } — bukan GameObject. Semua yang memegang item mewarisi satu base:
abstract class ItemContainerBase : NetworkBehaviour, IItemContainer {
protected SyncList<ItemStack> storedItemStacks; // sumber kebenaran (auto-sync)
protected Dictionary<string,int> itemCounts; // cache turunan (perf)
public virtual void ServerSetItems(...); ServerRemoveItems(...); ServerClear();
}
Storage, mesin, kendaraan, pallet — semua turunan ItemContainerBase, jadi dapat inventory yang networked + savable "gratis". Peran ditambah lewat interface kecil: IItemContainer (punya item), ICargoSource (bisa diambil cargo-nya + ServerTakeLastSackData), IEntityInfo (nama/status untuk UI). Contoh komposisi: T_MinerVehicle : NetworkBehaviour, IGameSave, ICargoSource, IItemContainer, IEntityInfo.
T_Employee — SyncVar-nya hanya identitas + state (employeeId type _workState _isCarrying _isWorking), bukan posisi. AI berjalan sebagai state machine server: EnterState + ServerUpdateIdle / GoingToTruck / PickingUp / GoingToDropOff / Dropping / ReturningHome / Error. Gerak pakai A* FollowerEntity lokal di tiap client + recovery macet (HasPathFailed, RetryReachDestination, RequestUnstuck). Cargo diambil via ICargoSource dengan sistem reservasi (GetCargoReservations/ReleaseCargoReservation) supaya dua pekerja tak rebutan. Save = EmployeeSaveData{ employeeId, position, rotation, isWorking }.
Belt = SplineContainer + speed. Item tidak punya transform sendiri di belt — posisinya parameter (laneIndex, t) sepanjang spline (EvaluateOnSpline(lane, t, out pos, out tan), multi-lane via GetLaneCount). Server yang mendaftar item: Server_RegisterItem(item, startT, laneIndex). Belt nyambung otomatis by jarak (FindNextBelt + connectionRadius + RefreshAllConnections) — taruh belt, langsung tersambung. Splitter pakai round-robin (GetNextSplitterExitIndex). Save = ConveyorBeltSaveData{ bool[] savedExitStates } + UniqueConveyorBeltId — cuma state gerbang + id stabil.
MarketPriceManager menyimpan multiplier harga per item. Jual → OnItemSold → ServerApplyPriceChange menurunkan harga (decreasePerSale), dibatasi [minPriceMultiplier, maxPriceMultiplier]. Tiap hari OnDayStarted → ServerApplyDailyDecay menarik harga kembali ke baseline. Save = List<ItemPriceModifierSaveEntry{ itemId, priceMultiplier }>.