Panduan ini menguraikan beberapa teknik untuk menggunakan streaming instance dalam permainan secara efisien dan efektif. Meskipun tidak ada solusi "satu ukuran untuk semua" untuk merancang permainan streaming, mengikuti langkah-langkah tingkat tinggi ini akan membawa Anda sebagian besar ke sana.
Properti Streaming
Setelah StreamingEnabled diaktifkan untuk objek Workspace di Studio, atur properti terkaitnya ke nilai yang direkomendasikan berikut:
| Properti | Rekomendasi |
|---|---|
| EnableSLIMAvatars | Gunakan Enabled untuk merender avatar rig standar sebagai pengganti ringan yang dianimasikan saat sesuai. Lihat avatar SLIM untuk informasi lebih lanjut. |
| ModelStreamingBehavior | Gunakan Improved untuk mengaktifkan streaming yang paling efisien untuk Models dengan keturunan BasePart. |
| StreamingIntegrityMode | Gunakan PauseOutsideLoadedArea untuk menyeimbangkan integritas gameplay tanpa menghentikan secara tidak perlu atau terlalu sering. |
| StreamingMinRadius | Gunakan default 64 untuk memaksimalkan seberapa banyak mesin dapat mengurangi ukuran permainan untuk perangkat low-end. |
| StreamingTargetRadius | Gunakan default 1024 untuk mencapai keseimbangan yang baik antara visibilitas untuk pemain di perangkat high-end dan jejak memori yang wajar. |
| StreamOutBehavior | Gunakan Opportunistic untuk memungkinkan klien mengumpulkan konten secara agresif, secara signifikan mengurangi penggunaan memori dan membantu mencegah crash karena kehabisan memori. |
Tingkat Detail Model
Model.LevelOfDetail membantu mengisi konten Model yang tidak di-stream dengan mesh komposit atau imposter yang ringan, membuat dunia terlihat secara visual lengkap. SLIM (Model Interaktif Ringan yang Dapat Diskalakan) sangat efektif, karena pemain sering kali tidak dapat membedakan mesh SLIM dari yang asli yang sepenuhnya di-stream.
Untuk hasil terbaik:
- Kelompokkan bagian yang terkait secara spasial dan logis, misalnya semua bagian dari sebuah mobil.
- Atur LevelOfDetail ke SLIM pada model yang berisi mesh dan bagian statis. Model yang dimodifikasi saat runtime atau memainkan animasi tidak didukung.
- Jaga agar luas spasial setiap model di bawah ~64 stud kubik untuk meningkatkan kemungkinan bahwa seluruh model yang sebenarnya di-stream bersama. Jika sebuah model memiliki luas yang sangat besar, pecah menjadi model modular yang lebih kecil dan terapkan LevelOfDetail yang sesuai pada masing-masing.
Struktur Model
Selain mengatur tingkat detail model, struktur dan pengaturan Models Anda memiliki dampak signifikan pada seberapa baik streaming berfungsi. Saat Anda membangun atau mengonversi permainan yang ada:
Gunakan model atomik untuk pengelompokan logis — Ketika sebuah skrip perlu mengakses semua bagian dalam sebuah model, atur ModelStreamingMode ke Atomic. Ini memungkinkan skrip sisi klien untuk mengakses instance di dalam model tanpa penggunaan berlebihan dari WaitForChild() (meskipun skrip semacam itu masih harus menggunakan WaitForChild() untuk model atomik secara keseluruhan).
Minimalkan model persisten — Model Persisten dimuat setelah bergabung dan tidak pernah di-stream keluar, secara permanen menghabiskan memori. Atur ModelStreamingMode model ke Persistent hanya jika model tersebut harus tetap tersedia dan dapat diakses oleh skrip setiap saat.
Dekomposisi model kontainer — Pola non-streaming yang umum adalah sebuah Model besar yang berisi banyak NPC, properti, atau pengelompokan serupa. Di bawah streaming, model kontainer mengurangi efisiensi streaming dan tidak optimal untuk tingkat detail model yang bekerja paling baik dengan instance yang dikelompokkan dengan erat. Dekomposisi model kontainer menjadi model yang lebih kecil dengan bagian yang dekat secara fisik atau terkait secara logis.
Avatar SLIM
Avatar platform di luar area yang sedang di-stream tidak terlihat secara default, tetapi mengaktifkan Workspace.EnableSLIMAvatars merender avatar rig standar sebagai pengganti ringan yang dianimasikan saat sesuai. Secara efektif, mesin:
- Merender versi SLIM ketika model avatar yang sebenarnya di-stream keluar.
- Beralih antara representasi SLIM dan resolusi penuh berdasarkan sumber daya yang tersedia, bahkan di dalam radius streaming.
- Mengatur animasi SLIM berdasarkan pentingnya adegan dan bandwidth yang tersedia.
Avatar SLIM mendukung karakter pemain rig standar R15 dengan tubuh, kepala, pakaian berlapis, dan aksesori. Avatar R6, NPC, dan avatar dengan proporsi kustom dikecualikan. Untuk daftar lengkap konfigurasi avatar yang didukung dan dikecualikan, data kinerja, dan tips pemecahan masalah, lihat avatar SLIM.
Pola Skrip
Pola skrip berikut ini paling sering dipengaruhi oleh streaming. Strategi yang benar tergantung pada maksud kode, jadi setiap pola mencantumkan beberapa opsi jika sesuai.
Indeks langsung ke keturunan
Mengindeks ke keturunan Workspace dengan operator . akan menghasilkan kesalahan jika ada instance dalam jalur yang tidak sedang di-stream. Hal yang sama berlaku untuk FindFirstChild(), FindFirstChildWhichIsA(), dan FindFirstChildOfClass() yang mengembalikan nil jika anak tersebut belum di-stream.
local house1 = workspace:FindFirstChild("House1") -- nil jika "House1" belum di-stream
local door = workspace.House1.Door -- Rusak jika "House1" atau "Door" belum di-streamPola serupa adalah mengakses Humanoid atau keturunan karakter lainnya secara langsung di dalam koneksi Player.CharacterAdded. Di bawah streaming, model karakter diparent ke Workspace sebelum semua keturunannya direplikasi, sehingga pengindeksan langsung gagal.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
player.CharacterAdded:Connect(function(character)
local humanoid = character.Humanoid
end)Jika skrip tidak dapat melanjutkan tanpa sebuah instance, tunggu dengan WaitForChild():
local house1 = workspace:WaitForChild("House1")
local door = house1:WaitForChild("Door")Instance yang dikirim secara jarak jauh
Sinyal RemoteEvent/RemoteFunction dan instance yang dirujuknya bergerak secara independen, sehingga sinyal dapat tiba di klien sebelum instance hadir — atau instance mungkin tidak pernah ada sama sekali. Dua penyebab yang mungkin termasuk:
Di bawah streaming, mungkin ada sedikit penundaan antara saat sebuah bagian/model dibuat di server dan saat itu direplikasi ke klien. Secara efektif, sebuah bagian yang dirujuk oleh RemoteEvent/RemoteFunction mungkin saja belum ada, bahkan di dalam area yang di-stream.
Mengirim referensi bagian/model dari server ke klien melalui RemoteEvent atau RemoteFunction memerlukan bahwa instance tersebut direplikasi ke klien yang menerima. Mengirim jalur instance sebagai string memiliki masalah yang sama, karena jalur tersebut mungkin mengarah ke lokasi yang tidak ada di klien:
Skrip Klienlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")remoteEvent.OnClientEvent:Connect(function(data)local checkpoint = data.checkpoint -- Kesalahan jika "checkpoint" tidak di-streamlocal level = workspace.Levels[data.levelPath] -- Kesalahan jika jalur tidak di-streamend)
Jika skrip klien yang menerima memerlukan instance untuk melanjutkan, sertakan WaitForChild() sebelum menggunakannya. Perhatikan bahwa ini dapat menunggu tanpa batas jika instance tidak pernah di-stream, jadi pertimbangkan untuk menambahkan batas waktu sebagai parameter kedua dari WaitForChild().
Desinkronisasi Klien
Desinkronisasi sisi klien harus diperlakukan sebagai pengecualian, bukan pola desain standar. Memperkenalkan salinan hanya klien atau memindahkan instance secara lokal dapat menyebabkan masalah serius. Audit kode Anda untuk tempat-tempat yang bergantung pada jenis perubahan ini yang bertahan di klien.
Sebagai contoh, memindahkan instance secara lokal dari ReplicatedStorage ke Workspace dapat membuat instance tersebut memenuhi syarat untuk di-stream keluar. Demikian pula, mengkloning instance secara lokal (Instance:Clone()) dari ReplicatedStorage ke dalam Workspace menciptakan salinan hanya klien yang tidak lagi menjadi bagian dari jalur replikasi server dan tidak akan menerima pembaruan properti dari instance yang dimiliki server asli.
Konsep yang sama berlaku saat memanggil Instance:Destroy() di klien untuk objek yang dimiliki server. Ini menghapus instance secara lokal tetapi server masih memilikinya, sehingga akan di-stream kembali dengan keadaan aslinya saat memenuhi syarat.
Streaming Proaktif
Ketika tujuan berikutnya seorang pemain dapat diperkirakan, lakukan panggilan sisi server ke Player:RequestStreamAroundAsync() untuk meng-stream area sementara untuk pemuatan sementara, atau gunakan Player:AddReplicationFocus() pada basis terbatas untuk area yang harus tetap dimuat hingga secara eksplisit dilepaskan.
Sebagai contoh, ketika karakter pemain akan teleportasi dengan perubahan CFrame ke rumah pemain lain di lokasi yang jauh, Anda dapat mengambil area tujuan sebelumnya untuk meminimalkan pop-in dan memberikan transisi yang lebih halus. Skrip berikut menunjukkan bagaimana sebuah acara jarak jauh dari klien ke server dapat dipicu untuk memindahkan karakter pemain menggunakan metode pengambilan sebelumnya. Jika permintaan pengambilan sebelumnya berhasil saat fungsi mengembalikan, radius minimum di sekitar lokasi target harus ada di klien.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportEvent = ReplicatedStorage:WaitForChild("TeleportEvent")
local function teleportPlayer(player, teleportTarget)
-- Minta streaming di sekitar lokasi target
player:RequestStreamAroundAsync(teleportTarget)
-- Teleport karakter
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(teleportTarget))
end
end
-- Panggil fungsi teleportasi saat klien memicu acara jarak jauh
teleportEvent.OnServerEvent:Connect(teleportPlayer)Pembacaan Properti Instance
Setelah sebuah instance di-stream keluar, pembaruan propertinya tidak lagi direplikasi ke klien tersebut. Membaca properti seperti BasePart.Position terus berhasil tetapi mengembalikan nilai terakhir yang direplikasi yang dapat sangat usang.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- Posisi mungkin usang jika "target" telah di-stream keluar
local dist = (target.Position - player.Character.HumanoidRootPart.Position).MagnitudePindahkan logika ke server, karena skrip sisi server melihat semua instance setiap saat. Ini umumnya merupakan opsi yang paling dapat diandalkan untuk pemeriksaan jarak dan logika lain yang sensitif terhadap posisi.
Menunggu di Jalur Kritis
Beberapa permainan non-streaming memuat peta mereka dengan mengkloningnya dari ReplicatedStorage ke Workspace, kemudian menunggu di klien sebelum menutup layar pemuatan dan memberi sinyal kesiapan. Di bawah streaming, ini menggantung tanpa batas — karakter klien belum muncul, jadi tidak ada fokus replikasi, dan instance peta spasial tidak pernah di-stream.
Pindahkan logika layar pemuatan sehingga tidak bergantung pada instance spasial tertentu yang ada, misalnya dengan memberi sinyal kesiapan setelah karakter muncul dan area sekitarnya di-stream.
Penanganan Perubahan Sinyal
Sinyal seperti Instance.ChildAdded/Instance.ChildRemoved dan sinyal CollectionService seperti GetInstanceAddedSignal() atau GetInstanceRemovedSignal() juga dipicu saat streaming masuk/keluar, tidak dapat dibedakan dari pemunculan/penghilangan yang nyata. Skrip yang menerima tidak dapat membedakan dari sinyal itu sendiri, jadi logika yang mengasumsikan sinyal sesuai dengan peristiwa "nyata" perlu diperbarui.
Audit skrip untuk setiap pendengar sinyal yang dapat rusak atau berubah secara signifikan ketika dipicu oleh streaming masuk dan/atau streaming keluar. Misalnya, jika Anda memutar audio atau efek visual saat NPC musuh muncul ke dunia, tetapkan setiap musuh dengan atribut seperti Spawned pada pemunculan pertama, dan lewati pemutaran audio/efek yang sama pada pemunculan musuh di streaming berikutnya.
local CollectionService = game:GetService("CollectionService")
local TAG_NAME = "Enemy"
CollectionService:GetInstanceAddedSignal(TAG_NAME):Connect(function(enemy)
if not enemy:GetAttribute("Spawned") then
-- Tetapkan atribut "Spawned" pada musuh untuk pemunculan awal
enemy:SetAttribute("Spawned", true)
-- Putar efek audio/visual untuk pemunculan awal ini
playSpawnEffects(enemy)
end
end)Iterasi atas Koleksi
Iterasi koleksi sisi klien seperti Instance:GetChildren() dan Instance:GetDescendants() hanya mengembalikan subset keturunan yang di-stream. Ini berlaku bahkan ketika parent itu sendiri selalu direplikasi, seperti Folder yang langsung berada di bawah Workspace yang keturunan spasialnya di-stream masuk dan keluar.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- Folder "Homes" selalu direplikasi tetapi anak-anaknya di-stream masuk dan keluar
-- Loop ini mungkin melewatkan rumah yang tidak sedang di-stream
for _, home in workspace.Homes:GetChildren() do
if home.Settings.Owner.Value == player.Name then
return home
end
endJika enumerasi lengkap diperlukan, lakukan pemindaian di server dan kirim hasilnya ke pemain melalui RemoteEvent jika diperlukan.
Kuery Spasial
Kuery spasial sisi klien seperti WorldRoot:Raycast(), WorldRoot:GetPartBoundsInBox(), dan Model:GetBoundingBox() hanya mencerminkan konten yang di-stream. Apakah itu masalah tergantung pada untuk apa kuery tersebut digunakan.
Gunakan server untuk kuery yang hasilnya harus mencerminkan dunia secara penuh, misalnya raycast yang memeriksa apakah pemain memiliki garis pandang ke target yang jauh.
Pola Lainnya
Pola berikut ini juga mungkin berlaku dan harus dipertimbangkan dengan hati-hati:
Sebuah Sound atau AudioPlayer yang diparent ke objek 3D berhenti saat objek tersebut di-stream keluar. Untuk audio ambient yang harus bertahan terlepas dari streaming, parent emitter ke model persisten atau ke kontainer non-streaming.
Objek UI dalam permainan seperti BillboardGui atau SurfaceGui serta efek visual seperti Beams atau Highlights yang adornee atau lampirannya di-stream keluar akan berhenti merender. Ini mungkin merupakan perilaku yang diinginkan, tetapi Anda harus memverifikasinya.
Peristiwa BasePart.Touched, ProximityPrompts, DragDetectors, dan ClickDetectors tidak berfungsi untuk pemain yang kliennya tidak memiliki bagian/model terkait yang di-stream. Jika interaksi harus mungkin dari jarak mana pun, model perlu persisten atau interaksi memerlukan mekanisme yang berbeda.
Untuk PathfindingService dan pathfinding sisi klien, pencari jalur hanya melihat geometri yang di-stream di klien dan mungkin merutekan melalui rintangan yang ada di server. Lihat di sini untuk strategi.
Kondisi Uji yang Realistis
Setelah skrip diperbarui, uji permainan secara menyeluruh. Bug streaming sering kali hanya muncul di tepi area yang di-stream atau selama transisi, jadi hanya menguji dekat spawn atau di radius target tidak cukup.
Uji dengan Workspace.StreamingTargetRadius diatur ke nilai minimumnya (64). Beberapa bug streaming hanya muncul ketika area yang di-stream kecil.
Mainkan melalui pola traversal penuh permainan, teleportasi antara area yang jauh, dan kunjungi area setelah meninggalkannya. Ini adalah situasi yang paling banyak menguji streaming masuk dan keluar.
Gunakan overlay debug streaming untuk memantau pengaturan streaming aktif, wilayah yang saat ini dimuat, dan status streaming runtime.
Perhatikan jendela Output dan Developer Console untuk kesalahan, karena banyak dari pola skrip menghasilkan kesalahan daripada perilaku yang tidak terlihat. Perhatikan khususnya kesalahan dengan bentuk attempt to index nil with ... yang sering menunjukkan panggilan WaitForChild() yang hilang.
Lengkapi dan aktifkan Tools, tembak senjata, dan picu berbagai interaksi permainan.
Keahlian Konversi Streaming AI
Untuk membantu dengan konversi dan optimasi streaming, Roblox menawarkan keahlian streaming AI, yang dapat diakses dari server MCP Studio. Keahlian ini secara otomatis mengevaluasi permainan Anda, menerapkan konfigurasi yang direkomendasikan, dan membersihkan masalah kompatibilitas, termasuk:
- Mengonfigurasi pengaturan streaming ke baseline yang direkomendasikan.
- Mengatur tingkat detail untuk model ke SLIM jika berlaku.
- Mereformasi struktur model untuk mencapai ukuran dan kualitas visual yang optimal.
Untuk menggunakan keahlian AI dalam permainan Anda:
- PENTINGCadangkan permainan Anda. Proses konversi bisa rumit, jadi Anda harus selalu menyimpan cadangan (File ⟩ Publish to Roblox As) sebelum menjalankan keahlian.
Anda dapat menjalankan keahlian ini menggunakan LLM apa pun yang Anda pilih melalui Model Context Protocol (MCP) di Studio. Model AI kelas atas dengan jendela konteks besar disarankan; di Claude Opus, konversi biasanya memakan waktu 20-30 menit dan menggunakan sekitar 200.000 token konteks.
- Buka permainan Anda di Studio.
- Unduh keahlian dan, di klien AI Anda, buka folder yang tidak terkompresi (roblox-streaming-conversion) sebagai proyek saat ini.
- Jalankan keahlian dengan /rbx-convert-to-streaming.
- Seperti halnya output AI, verifikasi hasilnya dan uji permainan Anda secara ekstensif di bawah kondisi uji yang realistis.

