LogoLogo
API Status
  • 👋Welcome
  • 🌐What is Morpheus Platform?
    • Interoperability
  • â„šī¸Help
    • 📗Glossary
    • 🆘Support
    • Firewall problems
    • EULA
  • CREATION
    • 🎮Unreal Development
      • ⚡Get Started
        • âš’ī¸Download the Editor
        • âĢUpload Content
        • 🌎Creating your own map
        • 📝Morpheus Base Project
        • ❓Differences from Unreal
          • 🧍Character Configuration
        • 📡Morpheus Networking
          • Introduction to Morpheus Networking
          • Network Levels
          • Replicated Properties
          • RPCs
          • Morpheus Render Targets
          • Morpheus Array
          • Networking FAQ
          • Replicating Sublevels
      • 📚Features & Guides
        • 📒Example Plugin
          • Nameplates
          • In-game roles
          • Resizing
        • 🏊Actor Pooling
        • 🔊Audio
        • 🎭Avatars
          • Creating an Avatar
          • Attachments
            • MML Attachments
          • Custom Animation Variables
          • Importing an NFT collection
          • Capsules and Mesh Transforms
        • 🤖Bots
        • đŸŽ™ī¸Chat
          • Unreal Text Chat
        • đŸŽ›ī¸Control Panels
          • Control Panel Configuration
          • DJ booth mission control
          • Observer Controls
        • 🔉Crowd Audio
        • đŸ¤ŧCrowd Rendering
          • Legacy Animated Crowd
            • Animated Crowd Console Commands
            • Attaching static meshes to crowd members
          • Crowd Materials
          • Performance Parameters
          • Live Config Settings
          • Crowd Animation
            • Crowd Anim Blueprint
              • User Guide - Crowd Anim Blueprint
              • Reference Guide - ABP Nodes
                • Animation Playback
                • States and State Machines
                • Variables
                • Transitions
                • Special
                • Blends
                • Additional Notes
        • 🍱Helpers & Extras
          • "Instanced Objects" in Blueprints
          • Objects with "world context"
          • Making DataAsset classes
          • Duplicate Objects
          • The Bootflow Subsystem
          • The "Wait For Condition" System
          • Advanced Graphics settings
          • Listening to inputs on UObjects
          • Morpheus UserID
          • World Services
          • M2Extras: Skins System
        • đŸ–Ĩī¸Loading Screen
        • ⚡Live Config
          • Editing for a World
          • Editing Locally
          • Default Settings
          • Accessing via Blueprint
          • Adding New Settings
          • Overriding Defaults
          • Using Arrays
        • 🧊MML
        • đŸ•ēMotion Capture
        • 📡Networking
        • đŸ“ĸNotifications
        • Raycastable Crowd
        • 🌐Singletons
        • 📱Streaming & Multiplatform
          • GFN on mobile
        • đŸ–Ĩī¸UI
          • "UI Mode"
        • đŸ—ƒī¸User Collections
          • Creating a New Object Definition
          • Accessing from Unreal
            • Creating Objects Definitions
            • Transfer Objects
            • User Collection Views
            • Receiving Updates
        • đŸ“ēVideo Players
          • Embedded Video Player
          • Millicast video streaming
            • How to Setup an In-Game Video Stream
            • Picture-in-Picture mode
          • Streaming Video Player
            • How to Setup a URL Video Player
            • Picture-in-Picture mode
        • 🐞Visual Debugging
          • Inspector
        • đŸĒŸWeb UI
        • Online Services
          • KV Store Service
        • 💠Web Requests
          • Http Requests
            • Legacy HTTP Nodes
          • JSON Handling
          • WebSockets
          • Identity Validation
          • Allowed External URLs
          • Walkthrough Example
            • Example Counter Service
        • âœˆī¸World Travel
          • World Travel in the editor
        • Avatar Physics Assets
        • Action Gameplay Helper Components
      • 🔑Workflows
        • â†—ī¸Upgrade the Editor
          • đŸ–Ĩī¸Version History
        • âš™ī¸Editing Project Settings
        • 📈Profiling
        • đŸ§ēMarketplace Importing
        • đŸ› ī¸Extra Workflows
          • Setup Play-in-Editor
          • Setup Local Asset Validation
          • Adding Gameplay Tags
          • Validating Game Assets
          • Custom Connection Modes
          • Connect Editor to a World
          • Common Issues
      • 📚Useful Reading
        • ⭐Best Practices
    • 🌎Worlds
      • 📩Invite Players
        • Setting Role Groups
      • Persistent Worlds
      • Always on Worlds
    • 📅Running events
      • ✅Large scale events - Checklist
      • 👾Anti-Cheat (EAC)
      • 🎮Player Entry
        • 📱React Native
        • Steam
        • đŸ’ģHardware Reqs
      • đŸŽĨBroadcast
        • 📹OBS Integration
      • Failover
      • 🏁Capacity And Queue Management
  • ADMINS
    • đŸ‘ĒAccess Control
      • Adding metaverse contributors
      • Creating a new project
    • 💲Pricing
      • Development Support
      • Included Usage & Overages
      • Cloud Streaming
      • Access Modes
      • War Room Support
      • Platform SLA
    • âš™ī¸Settings
      • đŸ—ƒī¸Projects
  • APIs and Tooling
    • đŸ–Ĩī¸API Reference
      • Accounts
      • Events
      • Key/Value Store
      • Organizations
      • Realtime
      • User Profile
      • World Builder
      • Worlds
    • đŸ’ģTemplate Web App
      • đŸ’ĸModeration
    • Pixel Streaming
    • 🚀Launcher
  • Integrations
    • 📊Analytics
      • Sending events from web
      • 🎮Sending Events from Unreal
    • đŸ’ŦChat
      • 🎮Integrating Pubnub with your Unreal Project
      • Adding Moderation to Chat
Powered by GitBook
On this page
  • Intro
  • Pooled Render Target Actors
  • Technical Usage
  • How to Test
  • "Lingering" delegates
  • Pooling Verbose Logging

Was this helpful?

  1. CREATION
  2. Unreal Development
  3. Features & Guides

Actor Pooling

PreviousResizingNextAudio

Last updated 7 months ago

Was this helpful?

Intro

Actor pooling is a concept which allows us to swap in and out actors at runtime without creating and destroying them, by caching actors in a list called a pool. When a new actor of a particular type is required, if one exists in the pool we can grab that actor and use it instead of creating a new one, eliminating much of the overhead involved in creating an actor at the expense of using up some memory.

MSquared's actor pooling system is almost entirely standard, and this article will concentrate less on technical details and more on common usages together with the kinds of situations which can catch people out!

Pooled Render Target Actors

The main use of the actor pooling system is in our LOD system for characters. With up to 20k players in a level where only the nearest ~35 are displayed in full fidelity (the rest being represented with Crowd Rendering), we need a way of efficiently assigning and removing render target actors from player MAs as they run around.

Actor pooling fulfills that brief by returning a render target to the pool when a player moves into the crowd, and grabbing a render target from the pool when they move out of the crowd.

NOTE: This only applies to other clients' characters. The authoritative client's render target actor is not pooled, and cannot go into the crowd.

When Actor Pooling Goes Wrong

The main downside of actor pooling is that if e.g. a render target actor is moved to the pool, it retains any state on it that occurred during natural gameplay involving its previous owner. This can lead to visual and logical inconsistencies, where the newly-obtained render target is still doing things based on its state before it was returned to the pool.

Therefore, most of the work in actor pooling is in making sure that any such state is reset before the actor is returned to the pool (or after it’s taken from the pool, depending on what’s appropriate).

Typically if a visual or logical bug occurs only when swapping roles or when large amounts of people are running around, it’s likely to do with state not being reset during actor pooling.

The main implication of the above is that any component on a player render target should be checked for state which may cause issues during pooling when work is done on it.

We also have to be careful to gracefully handle any components which are dynamically added or removed as when pooling the actor they may need to be removed or added respectively.

Technical Usage

The lifecycle of pooled actors, and the relevant transition events is as follows:

  • To enable actor pooling on an actor or component, implement the IMorpheusPooledActor interface on it.

    • For the interface on the component to work, it will need to be on an actor that also implements the interface.

  • To enable actor pooling on a render target, implement the IMorpheusPooledRenderTarget interface on it.

    • This is a more specialised version of IMorpheusPooledActor, that adds the OnEndPlayToPoolWithOwner event.

And that’s it! Everything else is handled for you. The interfaces provide three functions, and a fourth for the render target one specifically:

  • OnBeginPlayFromPool() can be implemented to perform logic when an actor is taken from the pool. Logic such as making the actor visible again, or setting up the state based on the latest MorpheusActor associated with the actor is done here.

  • OnEndPlayToPool() can be implemented to perform logic when an actor is returned to the pool. Logic such as hiding the actor, or cleaning up any added visuals is done here.

  • IsPoolingEnabled() can be implemented to provide an additional conditional check for pooling. If false, the actor won't be pooled. NOTE: This interface function has no effect when implemented on a component; it will perform its begin/end logic regardless, dependent entirely on whether IsPoolingEnabled() returns true for its owning actor.

  • OnEndPlayToPoolWithOwner() on the render target version only is a version of OnEndPlayToPool() which provides a MorpheusActor owner as an argument. (This is because the association between the render target actor and its old MorpheusActor is cleaned up before it is returned to the pool)

How to Test

Naturally, each usage of actor pooling will require a different testing procedure due to it being specific to particular actors. However, a general solution for testing render targets or components on those render targets is to simulate targets moving into and out of LoD0.

We can do this by overriding the PlayerClient.Rendering.NumInLoD0 live config value in the editor (or in live config, if testing a deployment) to e.g. 1 and then having 3 clients present. This means that one client can observe as the other two run in and out of LoD0.

The following sections refer to functionality added in release v29

"Lingering" delegates

If a render target actor has been returned to the pool, but hasn't unbound any delegates that it bound to on its previous Morpheus Actor (or any components on that Morpheus Actor), you could see strange bugs present themselves, since the pooled actor would still be listening to that old Morpheus Actor's events. If it then re-enters play out of the pool, being assigned a new Morpheus Actor, it could appear to be mostly working, but be listening to events on the old owner, instead of (or as well as) the new one.

We have added some additional warnings that will be printed if this is the case, to help track issues like this down.

We also have automatic logic, gated behind the Pooling.RemoveDelegatesBoundToOldMorpheusActor live config flag, to unbind such delegates. This should at least minimise the damage of not fully implementing actor pooling (the delegates will still need to be bound when the actor is returned to the pool though!)

Pooling Verbose Logging

If you have verbose logging enabled for LogMorpheusActorPooling category, it will print additional details on the actor returning to the pool, comparing it to the base class's default values.

These logs will print any differences from a reference actor, which hasn't yet begun play. Some of these may not be issues, but worth considering any differences that you don't expect, relevant to components/properties you added!

This can be set by doing e.g.:

  • Using the Log LogMorpheusActorPooling Verbose command

  • Adding the LogMorpheusActorPooling=Verbose line to the [Core.Log] section of your Engine .ini file.

Characters changing LOD levels can be easily triggered via the Morpheus Inspector - see

🎮
📚
🏊
Rendering related options
This example has 3 clients, with the max number in LOD0 set to 1. Of the other clients, one character will be a render target actor, and the other will be in the crowd. As you move around, and the other characters move in and out of the crowd, they will use the same BP_Origin_PlayerCharacter. Therefore, there will only ever be 2 actors, your one, and whichever other client is in LOD0.
An example warning if there is a delegate that hasn't been cleaned up. In this example, we automatically unbind it.