# Morpheus Platform Documentation

Welcome to the Morpheus Platform documentation!

## What is Morpheus Platform?

Morpheus Platform is a cutting-edge development and hosting environment that enables the creation of large-scale, high-fidelity virtual worlds and events using Unreal Engine 5. It is designed to support tens of thousands of concurrent users without world sharding, it offers next-gen graphics, spatial audio, and cross-device compatibility.

Developers can rapidly deploy updates, manage user access, and host secure, scalable experiences with built-in tools for event management. Morpheus Platform empowers creators to build immersive metaverse experiences with full control and seamless integration into existing systems.

## Next Steps

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Unreal development</strong></td><td>Download editor &#x26; start creating</td><td></td><td><a href="/pages/Gm2AWMpNTTkOKKC6WvdG">/pages/Gm2AWMpNTTkOKKC6WvdG</a></td><td><a href="/files/NZCxMoxki2VC0zjtCQCU">/files/NZCxMoxki2VC0zjtCQCU</a></td></tr><tr><td><strong>Production</strong></td><td>Start worlds, create events, &#x26; manage player access</td><td></td><td><a href="/pages/p2CTn1hpKNyTznL1mGeP">/pages/p2CTn1hpKNyTznL1mGeP</a></td><td><a href="/files/GKrxKWlAuaiCkNVchoGX">/files/GKrxKWlAuaiCkNVchoGX</a></td></tr><tr><td><strong>Admins</strong></td><td>Manage access, see usage, and change settings</td><td></td><td><a href="/pages/WsCVzpOPDXeb8NwYaSVj">/pages/WsCVzpOPDXeb8NwYaSVj</a></td><td><a href="/files/xHGtDgS6XMbMCFE0bQ35">/files/xHGtDgS6XMbMCFE0bQ35</a></td></tr></tbody></table>


# What is Morpheus Platform?

Morpheus Platform is a cutting-edge development and hosting environment that enables the creation of large-scale, high-fidelity virtual worlds and events using Unreal Engine 5. It is designed to support tens of thousands of concurrent users without world sharding, it offers next-gen graphics, spatial audio, and cross-device compatibility.

Developers can rapidly deploy updates, manage user access, and host secure, scalable experiences with built-in tools for event management. Morpheus Platform empowers creators to build immersive metaverse experiences with full control and seamless integration into existing systems.

{% embed url="<https://www.youtube.com/watch?v=55R5J0qPOfc>" %}
Tech Demo showing selected features of Morpheus Platform
{% endembed %}

## Next Steps

* [Glossary](/morpheus-platform/glossary)
* [Interoperability](/morpheus-platform/interoperability)
* [Support](/morpheus-platform/help-and-support)
* [EULA](/morpheus-platform/eula)


# Glossary

### Metaverse

Metaverses in M² are creatively autonomous yet interoperable. They are groups of virtual worlds that exist as part of the broader interoperable M² network.

The metaverse is M²'s unit of organisation. Every M² virtual world is part of a particular metaverse, and each metaverse has separate access control, billing, etc.

Each metaverse has its own URL based on its codename:

> **\<codename>.m2worlds.io**

### Dashboard

The dashboard is the entry point to both metaverses and tools. It is how developers and other metaverse operators interact with the M² network. From here:

* Admins can manage access across the metaverse, handle billing, and additional configuration
* Developers can download the editor, and launch virtual worlds that are made from it
* Event runners can run events in virtual worlds using content uploaded by developers

You can find your metaverse's dashboard based on your `organization id`:

> **https\://{organization-id}.m2worlds.io/dashboard**

**For example:**

* Construct's dashboard is [https://construct.m2worlds.io/dashboard](#m)

### Worlds

Worlds are single instanced virtual spaces, individually capable of up to \~10ks CCUs. Worlds are launched by clicking `Launch` in the header and involve selecting a map (from a mod), runtime, size (how many players can it handle), and more.

<figure><img src="/files/Qp04j0XJzKCrBSyr5d04" alt=""><figcaption><p>Configure a world to launch</p></figcaption></figure>

Standard worlds will be deleted after the duration of the world has ended. If this is not your desired outcome, you can set up persistent or always on worlds.

[Persistent worlds](https://docs.msquared.io/production/starting-worlds/persistent-worlds) - Worlds that always exist, but are not always on. By setting up persistent worlds for events, the creator will not have to remake or reconfigure access groups, live config, links, events, and any other world state already configured.

[Always on worlds](https://docs.msquared.io/production/starting-worlds/how-to-make-an-always-on-world) - An extension of persistent worlds that are set up without a duration end time.

### Mods

Mods are developer-uploaded Unreal projects that can be used to start worlds. Each developer gets their own mod which is automatically created for them the first time they click upload in the editor. All future uploads will be part of the same mod. When starting a world, you always select a mod (and a map within that mod) to run. By default, only the mod creator (and admins) can use a given mod to launch worlds.

Mods can be viewed in the `Mods` tab of the dashboard. Below, you can see the `ally's game` mod, and a history of the 14 different versions of it that have been uploaded.

<figure><img src="/files/drThtVyur3jCKE2Ce7Yn" alt=""><figcaption><p>Mod list</p></figcaption></figure>

### Events

Events are a dedicated concept for engagement of users into a running world. You can create an event to advertise your metaverse events ahead of time using them as placeholders on your end user website with calendar links, YouTube trailers, and more. At show time, you can link the event to a running world to connect users into a world based on your content.

<figure><img src="/files/RUJWdn6X0MhOBHnDpQuK" alt=""><figcaption></figcaption></figure>

### Projects

[Projects](https://docs.msquared.io/admins/projects) are isolated sections of a metaverse which let you separate groups of content, worlds, and people developing within your metaverse.

### Editor

The M² editor is an extended Unreal Editor including plugins for creating worlds with high-scale rendering/networking/audio, MML, interoperable objects, avatars, and tooling to upload to our content pipeline.

<figure><img src="/files/UP2MZTez91JD6eds0I09" alt=""><figcaption></figcaption></figure>


# Interoperability

Guidance around MSquared's network and interoperability mechanisms

<figure><img src="/files/z3aBVb2kh6CUOqPF2Int" alt=""><figcaption></figcaption></figure>

MSquared, besides being a platform for building high-density virtual world experiences, also features object interoperability as a first-class feature. This enables users to take their virtual possessions between many worlds with minimal work from you as a developer.

This interoperability is achieved through a combination of on-chain NFT records, an omnichain blockchain indexer, MML for interoperable object definition, and a mechanism for permissioned object storage and content moderation.

This guide explains in more detail how this mechanism works, and the current and in-development capabilities.

{% hint style="info" %}
NFTs don't necessarily need to be owned and custodied by users in a financially tradeable way - the same standard can be used for more traditional digital "entitlements" by using a mechanism called [Soulbound Tokens](https://www.coindesk.com/learn/what-are-soulbound-tokens-the-non-transferrable-nft-explained/)
{% endhint %}

### Interoperability Commitment

MSquared wants to help grow a network of interconnected experiences which the whole is greater than the sum of the parts - enabling free movement of users and their possessions between metaverses.

Part of the terms of using MSquared's platform is the commitment to this interoperability for at least user's appearance - their Characters, Clothing, Accessories and Emotes, given they pass your [moderation policy](/creation/unreal-development/features-and-tutorials/communication/moderation).

### Types of Interoperable Object

Below are currently planned types of interoperable objects, and their current implementation status

<table data-full-width="false"><thead><tr><th>Type</th><th>Description</th><th width="91.5" data-type="checkbox">Status</th><th>Mechanism</th></tr></thead><tbody><tr><td>🖼️📷 Image</td><td>Typical picture-based NFTs - could be used as profile pictures or placing in world into photo frames etc</td><td>true</td><td>Reading the <code>image</code> field on the NFT metadata</td></tr><tr><td>💃🕺 Character</td><td>Humanoid characters that can be used as the player's avatar, or used for non-player characters</td><td>true</td><td>Reading the <code>mml</code> field on the NFT metadata linking to an MML <code>&#x3C;m-character></code> - see <a href="/pages/0msVDlVqtOTJ0h0tgnCn">MML Avatars</a></td></tr><tr><td>🪩🪑 Dynamic Object</td><td>Spawnable items that may be static or interactable - a chair, a jukebox, a quiz machine, etc</td><td>true</td><td>Reading the <code>mml</code> field for a <code>wss://</code> to a live MML object - see <a href="#types-of-interoperable-object">https://mml.io</a></td></tr><tr><td>👜🎩 Accessory</td><td>Static 3D models attached to particular part of a Character such as hats, glasses, backpacks, etc</td><td>false</td><td>Currently supported as part of a Character</td></tr><tr><td>👕👖 Clothing</td><td>Skeletal meshes layered on top of a base Character</td><td>false</td><td>Currently supported as part of a Character</td></tr><tr><td>🥳👏 Emotes</td><td>Short animations that can be played to express emotions or interact</td><td>false</td><td>Currently in exploration</td></tr></tbody></table>

### Interoperable Ownership

Ownership between different metaverses is established by associating one or many web3 wallets with a particular user.

MSquared supports users linking self-owned web3 wallets such as [MetaMask ](https://metamask.io/)out of the box. Enterprise customers can request more bespoke integrations if they have existing web3 identity systems.

<figure><img src="/files/kewcYNFeP5kBjRDI4pFs" alt="" width="320"><figcaption><p>Wallet linking is a bundled feature of the reference web portal</p></figcaption></figure>

#### Delegation

Delegation is a method for NFTs (often high value ones) to be non-permanently granted in a read-only manner to another "hot" wallet which is used for more day-to-day interaction. MSquared supports both [https://warm.xyz/](https://warm.xyz) and <https://delegate.xyz/> (v1 and v2) mechanisms.

#### Ownership Logic

While delegation protocols technically support concurrent delegation of an NFT to multiple wallets, the following logic is in place to prevent scenarios where an NFT being used for access gating could be used to allow large numbers of people to share the same "ticket":

* For any wallet, it can only be linked to one user account at a time
* For any token, it can only be delegated to one wallet a time
  * If there are multiple delegations, the most recent delegation is prioritized
  * This is true across all supported delegation methods (e.g. a recent [warm.xyz](https://warm.xyz) delegation would take priority over a less recent [delegate.xyz](https://delegate.xyz) delegation)

#### User Collections

Successfully imported interoperable objects will be visible in the user's [Collection](/creation/unreal-development/features-and-tutorials/user-collections#theinventorysystem-overview), which combines both "foreign" interoperable objects across multiple blockchains with "native" off-chain digital goods for your metaverse.

### Supported NFT Tokens & Metadata

We currently support ERC-721 and ERC-1155 tokens

{% hint style="info" %}
Delegation of ERC-1155 balances is not currently supported
{% endhint %}

The following fields within an ERC-721/ERC-1155 metadata JSON are respected.\\

| Field         | Usage                                                                                                         |
| ------------- | ------------------------------------------------------------------------------------------------------------- |
| `name`        | The canonical name of the object in a user’s collection                                                       |
| `description` | The additional descriptive text for a user, used in the collections frontend react components                 |
| `image`       | Used as a preview image for any collection item, and allows its usage as a profile picture                    |
| `mml`         | The URL to a static MML document containing an `<m-character>`. Allows the user to use it as a default avatar |
| ….            | Other fields are imported, and available for querying in Unreal and Web APIs                                  |

### Classification & Moderation

{% hint style="warning" %}
While the interoperable network is in Early Access, interoperable objects are currently restricted to those approved by MSquared directly, rather than being moderated - the wider moderated network will be launching later in 2025
{% endhint %}

Some types of interoperable objects may not be suitable for your particular experience. All objects within the interoperable network will be subject to a classification process, resulting in tags being applied to the object.

Metaverses will be able to define your interoperable object import policy based upon these tags.

<figure><img src="/files/F6rFSvQryi7WyjExM1bj" alt=""><figcaption><p>All interoperable content is classified with tags, and metaverses are able to filter inbound objects by those tags</p></figcaption></figure>

### Permissioned Storage

While many NFT projects host their interoperable object content in a publicly accessible location, for many projects this many be unwanted or impractical.

Permissioned Storage is a mechanism where interoperable object content URLs can be placed on-chain, but the underlying asset is not publicly available for download. The service ensures any reader owns the underlying NFT to get access to the content.

{% hint style="info" %}
Permissioned objects are currently in Early Access with our Enterprise partners - please reach out via support if you are interested
{% endhint %}

### Adding Objects to the Network

While the interoperability network is in Early Access we’re interested in any interoperable content, starting with Avatars and Accessories.

If you have an NFT collection you’d like to be part of the network please reach out on Discord!


# Support

If you need help, please either reach out through your support contact.

If you don't have a support channel, jump onto [Discord ](https://discord.gg/2DGTBbRZ)and ask there!

## Related Pages

* [Development Support](/admins/pricing/development-support)
* [War Room Support](/admins/pricing/war-room-support)
* [Platform SLA](/admins/pricing/platform-sla)


# EULA

Morpheus Platform End User License Agreement V 2.0

(last updated 30th May 2025)\\

1. OVERVIEW\\

**1.1 Welcome.** Welcome to MSquared! At MSquared, we appreciate our community's creativity and enthusiasm. Our technology enables developers of all levels to make virtual experiences, events and virtual items and other content for use across virtual worlds (the “MSquared Network”). These Terms are designed to encourage your creativity and contributions while setting boundaries to prevent misuse. Please refer to them to understand what is allowed and what is not, ensuring that you can create and share your work confidently. If you are considering an action not explicitly addressed in these Terms, and we have not indicated approval, please assume it is not allowed without our written consent.

**1.2 Agreement.** This agreement (the “Agreement”) is between you (“you” or “your” or “User”) and Improbable MV Limited (incorporated in England) with company number 13856337 whose registered office is at 10 Bishops Square, London, E1 6EG, UK (“MSquared”, “we”, “us” or “our”). By downloading or using the MSquared platform software including any related software or features provided by Msquared (the “MSquared Platform”), you acknowledge and accept the following terms (the “Terms”). These Terms are a legally binding contract between you and us, either individually or, if applicable, on behalf of your corporate entity/employer. You can end this Agreement at any time - please see section 12.5 below on how to do this.

**1.3 Purpose.** The purpose of these Terms is to enable you to use the MSquared Platform to: (i) develop Virtual Items for your own or third party Virtual Experiences (as defined below); and (ii) develop, host and operate your own Virtual Experiences, in each case on the MSquared Network and for both non-commercial and commercial purposes, in accordance with our rules, guidelines, policies and requirements (the “Purpose”).

**1.4 Right to Modify Terms.** We have the right to modify these Terms (in whole or in part) from time to time without liability to you. When we modify these Terms we will notify you of the update on our website: <https://docs.msquared.io/help/end-user-license-agreement-eula> (the “Website”). Your continued use of the MSquared Platform following such notification shall be deemed to be your acceptance of such revised Terms.

2. KEY TERMS SUMMARY

You should read all of the Terms. To help guide you, we have summarised some of the key points for your convenience. Please note the full terms and conditions still apply, as set out below.\\

**2.1 Access.** In order to access the MSquared Platform:

* Age - you must be at least 18 years old.
* Authority - If you are acting on behalf of your employer, you must be authorised to enter into these Terms on behalf of your employer.
* Account - you will need to create an account on the MSquared Platform. You confirm that the email address and information you use for registration with us is, and shall remain, true and accurate and complete at all times. We reserve the right to suspend or terminate your account if we reasonably believe that the information you provide to us is not accurate or is not your own. You agree to keep your log-in details confidential and not to share them with anyone else. You accept full responsibility if you fail to do this and your account is accessed by a third party.

**2.2 Unreal Licence.** You will need to have your own separate and standalone Unreal Engine 5 licence (see <https://www.unrealengine.com/>) and, at all times, comply with the Unreal Engine EULA (<https://www.unrealengine.com/en-US/eula/unreal>). You will also need to accept the terms of service and privacy policy that governs the use of Epic Online Services (<https://dev.epicgames.com/en-US/services-games>).

**2.3 Development Status.** The MSquared Platform software is a continually evolving product. Therefore, there may be missing or incomplete features, bugs or errors which may be subject to further testing, development, patches and/or updates in our sole discretion. We do not make any promises, warranties or representations of any kind about (or accept any liability for) the MSquared Platform, what it does, how it does it, or about future content. The MSquared Platform is provided “as is” and without warranty or representation, express, implied or statutory, including (without limitation) warranty as to satisfactory purpose, merchantability, fitness for any particular purpose or availability for use; nor are there any warranties created by course of dealing or course of practice, performance or trade usage. All implied and/or statutory representations, conditions or warranties are excluded to the extent permissible by law.

**2.4 Availability / Downtime**. The availability service levels for the MSquared Platform can be accessed here: <https://status.msquared.io/>. In addition, there may be times when the MSquared Platform (or any part of it) is not available due to planned maintenance. Where possible we will try to give notice in advance of any planned downtime via the Website.

**2.5 Updates.** We are constantly developing and improving the MSquared Platform. Where we plan on making a material change to the MSquared Platform (for example if we plan to deprecate a MSquared Platform API), we will use our best efforts to give you at least three (3) months notice of such planned change. We will provide such advance notice in the release notes for the MSquared Platform. Where we need to make an emergency or unplanned material change to the MSquared Platform, we will use our best efforts to give you as much prior notice as possible.

**2.6 Fees.** The fees for access to the MSquared Platform and related services are set out here: <https://docs.msquared.io/admins/pricing> and may be updated from time-to-time.

**2.7 Account Suspension / Termination.** It is very important that you comply with the full Terms, including our Acceptable Use Policy set out in Appendix 1. Your failure to do so may result in us suspending or terminating your account and your access to the MSquared Platform. See section 9 (Term, Suspension and Termination) below for more details.

**2.8 Interoperability.** One of the core concepts of the MSquared Network is the interoperability of virtual items, enabling them to move freely between different Virtual Experiences on the network. When you operate a Virtual Experience or create Content, you will need to comply with our Interoperability requirements set out in section 8 (Interoperability) below.

**2.9 Privacy.** Our [Privacy Policy](https://www.improbable.io/privacy-policy) sets out how we collect, use and process your personal data when you sign up for an account with, and subsequently access, the MSquared Platform. If you do not agree to our Privacy Policy, you should not download or access the Mquared Platform.

3. DEFINITIONS

“Collaborators” is defined in section 5.4 below.

“Content” is defined in section 4.1 below.

“End User” means any participant, player or other end user of a Virtual Experience.

“Project” means each project and all work in progress that you store on our platform via your account with us.

“Virtual Experience” means a creatively autonomous, interoperable virtual world (or group of virtual worlds) built using the MSquared Platform and hosted on the MSquared Network which can be persistent or which can be time limited events or experiences.

“Virtual Items” means: (i) End User characters or avatars; (ii) “companion” or “follower” non-End User characters programmed to travel with a End User character or avatar; (iii) clothes or wearable items for End User characters or avatars; and (iv) transportable or portable tools, instruments, and other non-environmental items carried or borne by End User characters or avatars, and which, in each case, are interoperable across the MSquared Network.\\

4. INTELLECTUAL PROPERTY OWNERSHIP

**4.1 Owned by you.** You retain ownership of all intellectual property rights in: (a) all Virtual Items and Virtual Experiences that you either develop, upload, import, or otherwise make available on or through the MSquared Platform; and (b) all of your trade marks, logos and other brand assets you incorporate in any of the foregoing, including, in each case, any modifications, improvements or enhancements to the same (collectively your “Content”).

**4.2 Owned by us.** We retain ownership of all intellectual property rights in: (a) the MSquared Platform; and (b) any other assets (audio and/or visual), tools or software that we may make available via the MSquared Platform (together the “Improbable Property”), which we may make available to you via the MSquared Platform. Notwithstanding the restrictions set out in section 5 (Licences) below, to the extent that you make (or engage a third party to make) any modifications to, or any derivative works from, any of the Improbable Property, you hereby assign to us by way of present assignment of present and future rights all right, title and interest in and to all such modifications and derivative works and you agree that you will do all such things and take all such actions as we reasonably require in order to transfer such modifications and derivative works, and the intellectual property rights in them, to us. We separately retain ownership of our name, logo and associated trade marks, which we may make available to you upon written request and subject to a separate agreement.

**4.3 Feedback and Suggestions.** MSquared will own all rights in all oral and written feedback, ideas, proposals, or suggested improvements relating to any MSquared innovations, including the MSquared Platform along with other MSquared products and services. If you offer us a suggestion, please understand that you're doing so voluntarily and without any expectation of compensation. We are not required to review or use your suggestion, and if we choose to use it, we are not obligated to pay you. If you believe your suggestion has value that warrants payment, please inform us of your expectation to be paid before you share your idea. We will then let you know in writing if we are interested and agree to consider it under those terms.

**4.4 DMCA and Infringing Content.** In accordance with the Digital Millennium Copyright Act of 1998, the text of which may be found on the U.S. Copyright Office website at <http://www.copyright.gov/legislation/dmca.pdf>, MSquared will respond expeditiously to claims of copyright infringement committed using the MSquared Platform if such claims are reported to MSquared. Upon receipt of: (i) a copyright infringement notice; (ii) evidence of breach of the Acceptable Use Policy; and/or (iii) evidence of breach of any applicable moderation guidelines, MSquared will take whatever action, in its sole discretion, it deems appropriate. Such action may include: (A) removal of the challenged content from your Content within the MSquared Platform in which such products are made available; and (B) blocking access to Virtual Experiences on the MSquared Network.

5. LICENCES

**5.1 Licence to Use the MSquared Platform.** Subject to your compliance with these Terms (including the Acceptable Use Policy), MSquared grants you a personal, worldwide, non-exclusive, non-transferable, non-sublicensable, revocable limited right and licence for the term of this Agreement with you to install and use the MSquared Platform for the Purpose on compatible devices you own or control.

**5.2** You must not (unless we expressly agree otherwise in writing with you): (i) copy, modify, merge, distribute, translate, reverse engineer, decompile, disassemble, hack or interfere with the MSquared Platform editor code or any part of it; (ii) use the MSquared Platform, or upload or make available on the MSquared Network any Content which in any way which breaches the Acceptable Use Policy; or (iii) use our MSquared Platform to make or operate a competing virtual worlds platform.

**5.3 Sublicensing.** The rights given to you pursuant to these Terms are personal to you and cannot be transferred or sublicensed unless we expressly agree otherwise in writing. If you wish to collaborate with others on your Project(s) please see section 6 (Collaboration) below.

**5.4 Your Licence to MSquared.** You grant MSquared a royalty-free, perpetual, irrevocable, sub-licensable, worldwide, and non-exclusive licence to make your Content available to End Users on the MSquared Platform. This licence allows MSquared to:

**5.4.1** Publish, copy, update, modify, display, stream and distribute your Content in order to enable your Content to be made available to End Users;

**5.4.2** Host your Content on the MSquared Network to make it accessible and available to you and to End Users;

**5.4.3** Display, use, promote, market in any media, distribute, or perform your publicly available Content in any way we see fit; this includes displaying such Content in screenshots, videos, live events, trade shows, tournaments, and other materials that promote the MSquared Platform; and

**5.4.4** Provide other End Users and us with the right to stream or record gameplay of your publicly available Content (“Videos”), edit these Videos, and promote these Videos using images of gameplay (which may also include depictions of your Content) on social media and other video sharing platforms.

6. COLLABORATION

**6.1** You can invite third parties to collaborate on your Projects and/or to create Content for your Events and/or Virtual Experience (“Collaborators”) provided that:

**6.1.1** Each Collaborator must separately enter into and comply with these Terms. We can suspend or terminate a Collaborator’s use of the MSquared Platform if they breach these Terms, in accordance with Section 11 (Term, Suspension and Termination) below;

**6.1.2** You accept sole responsibility for the acts or omissions of your Collaborators and you are responsible for ensuring their compliance with these Terms. If a Collaborator’s acts or omissions cause you any loss or harm in connection with their access to your Projects or their use of the MSquared Platform as your Collaborator, you agree to bring any claim for losses or damages against them and not us; and

**6.1.3** You are liable to us for any Fees incurred by your Collaborators in connection with your Projects and their use of our Services.

**6.2** You can determine the level of access to give each Collaborator in your account settings. You can change the level of access given to a Collaborator, and you can block or remove a Collaborator's access to your Projects, at any time via your account settings.

7\. CONTENT

**7.1 Experience Creation** - All Virtual Experiences you create on the MSquared Network must comply with the terms of this Agreement, including the Acceptable Use Policy set out in Appendix 1.

**7.2 Content Creation** - All Virtual Items that you create for use in, or import into, the MSquared Network must comply with the following principles:

**7.2.1 Creation** - All Virtual Items created in the MSquared Network must be created using the MSquared Platform’s object creation tools and in accordance with the MSquared Network’s open object standards;

**7.2.2 Import** - All virtual assets and items imported into the MSquared Network must be converted into Virtual Items using MSquared Platform’s object creation tools and in accordance with the MSquared Network’s open object standards; and

**7.2.3 Interoperability** - All Virtual Items are intended to be a core part of an End User’s identity across Virtual Experiences on the MSquared Network. These objects are intended to be available to the End User owner across all Virtual Experiences on the MSquared Network, subject only to the moderation settings determined by the Virtual Experience operator set out below.

**7.3** You are solely responsible for the Content that you or your Collaborators develop using the MSquared Platform. As your Content will be uploaded to and made available via the MSquared Network, you promise to us that:

**7.3.1 Authority** - You have the right to use all assets and content (including all third party assets and content) that you include in your Content;

**7.3.2 Non-Infringement** - Your Content does not infringe or violate the rights of any third parties, including intellectual property, publicity, privacy, or any applicable laws, or the obligations outlined in these Terms;

**7.3.3 Music Rights** - To the extent your Content contains music, you promise to us that you: (i) either fully own the music or have obtained the necessary consents and licences to upload and use the sound recording(s); (ii) we are authorised to make such music available via your Content on the MSquared Network without the payment of any licensee, royalty or any other fees to you or any third party; and (iii) will comply with any relevant reporting requirements or contractual obligations to entities such as labels, publishers, performing rights societies, collective management organisations, co-writers, performers, and any other applicable payments or fees to organisations like SAG-AFTRA and/or AFM. If you cannot secure and uphold these consents or licences for MSquared’s benefit, you will not upload music to MSquared; and

**7.3.4 Harmful Code** - Your Content does not contain viruses, harmful code, malware, spyware, corrupted data, or other elements that could negatively affect how other End Users enjoy the MSquared Platform or the MSquared Network.

**7.4 Responsibility for Content** - You are solely and exclusively responsible for: (i) all legal and regulatory compliance; and (ii) any End User and/or consumer matters which arise from or in connection with any Content you make available (or allow others to make available) in your Virtual Experience, and you acknowledge that MSquared has no responsibilities, obligations or liabilities whatsoever regarding the same. This includes (but is not limited to) applicable consumer protection, data protection and other regulatory matters (as well as customer support, dealing with all sales, refunds, rebates, taxes and fees relating to sales).

**7.5** You acknowledge that we reserve the right to remove or modify any Content in our sole discretion if we reasonably believe we need to due to any applicable laws, regulations, or policies that would risk liability to, including compromising the integrity of, the MSquared Platform.

**7.6** You will make regular back-up copies of your Content. We have no responsibility or liability for your Content or the material others upload, store or share using the MSquared Platform.

8\. INTEROPERABILITY

**8.1** All Virtual Items must comply with the following interoperability principles:

**8.1.1** Subject to the moderation setting you select for your Virtual Items, all Virtual Items you create or import (or allow your End Users or Collaborators to create or import) to the MSquared Network (including your Virtual Experience) must:

1. comply with the MSquared Network’s open object standards and not technically restrict End Users from accessing, displaying or using such Virtual Item in any other Virtual Experience on the MSquared Network; and
2. be gifted, sold or licensed to End Users under terms that, at a minimum, grant the acquiring End User (and each subsequent owner of the Virtual Item) a worldwide, personal, non-commercial licence to access, use and display the relevant Virtual Item (including designs, drawings, artwork, text, images, and video linked with, or incorporated into such Virtual Item) within any Virtual Experience in the MSquared Network.

**8.1.2** Subject to the moderation settings for your Virtual Experience, you must:

1. enable and permit all third party Virtual Items to access, be displayed in and be used by End Users in your Virtual Experience;
2. treat all Virtual Items equally within your Virtual Experience, whether they are first party Virtual Items created in or imported into your Virtual Experience or third party Virtual Items; and
3. not apply any charges, limitations or restrictions on End Users for using Virtual Items in any public areas in your Virtual Experience. However, you may restrict the use of interoperable Virtual Items in certain private areas or events within your Virtual Experience (for example, to create VIP areas), provided such restrictions are clearly disclosed, and not designed to circumvent interoperability requirements.

**8.2.** We are authorised to take all steps we deem reasonably necessary to enforce your (and your End Users’ and Collaborators’) compliance with the interoperability provisions on the MSquared Network to ensure that Virtual Items can move freely between Virtual Experiences (subject to applicable moderation settings). \\

9\. MODERATION

**9.1** The MSquared Platform will enable Virtual Experience Owners to deploy Moderation settings to ensure that their Virtual Experiences and the content used and displayed within them are appropriate to the Virtual Experience’s audience. They are intended to work in the same way as a PEGI or similar ratings system and will apply at a category level. They cannot be used to block competitor brands or individual Virtual Items. You are responsible for ensuring that End Users are aware of the age rating and any moderation settings that you decide to apply to either a Virtual Experience or Virtual Items that End End Users may wish to use in your Virtual Experience.

**9.2 Content.** Content moderation settings can be applied at two levels:

**9.2.1 Moderation settings applied to Virtual Items** - you can apply moderation settings to a Virtual Item when it is imported or created by applying certain descriptors to it. For example, if you create a family friendly Virtual Item, you may want to prohibit it from appearing in a Virtual Experience aimed just at adults. If you wish to block certain Virtual Items in your Virtual Experiences, then you need to clearly state why such Content is blocked as part of the registration process for your Virtual Experience.

**9.2.2 Moderation settings applied to Virtual Experiences** - you can apply moderation settings to your Virtual Experience. If a Virtual Item is not compatible with the moderation guidelines set by you, then it will not be allowed to appear in your Virtual Experience. For example, if your Virtual Experience is intended to be a family friendly space, you may restrict violent or adult content Virtual Items from appearing in your Virtual Experience.

**9.3 Technical Moderation.** You can contact us at [contact@msquared.io\[INSERT LINK\] ](mailto:contact@msquared.io)if you believe you have a case where you need to apply technical moderation in your Virtual Experiences (for example, adding restrictions on minimum/maximum avatar sizes). Please set out in detail the limitations you require, as well as your reasons for such restrictions and one of our technical team will contact you to support you to see about granting an exception. This work may be chargeable; if it is then we will agree to any charges with you upfront.

**9.4 Communications.** You may also use our internal moderation tools (or any approved third party moderation tools that we may make available via the MSquared Network) to set and enforce moderation policies for voice and chat within your Virtual Experience.

10\. FEES

**10.1** The fees for your use of the MSquared Platform (the “Platform Fees”) and related services are set out here: <https://docs.msquared.io/admins/pricing>. These prices may be updated from time to time.

**10.2 Making Payment.** We will invoice you monthly for all costs incurred by you and your Collaborators against your account in the previous month.

**10.3 Payment Terms.** All amounts due or payable to MSquared in connection with your use (and the use by your Collaborators) of our paid-for Services shall be paid by you within thirty (30) days of being billed for such Services. Interest shall accrue on all amounts not paid by the applicable due date at a rate, calculated upon the unpaid balance, at the rate of three (3) per cent per annum above the base rate for the time being of Barclays Bank plc. All payments made hereunder shall be payable in United States Dollars; all revenues realised in other currencies shall be converted to United States Dollars at the officially published average exchange rates of the reporting period (using rates published by an international bank or recognized exchange rate website - [www.oanda.com](http://www.oanda.com), [www.x-rates.com](http://www.x-rates.com), [www.xe.com](http://www.xe.com), [www.thomsonreuters.com](http://www.thomsonreuters.com)). All payments made by you to us will be sent by wire transfer to the account of our choosing as will be separately indicated to you.

**10.4 Taxes.** You are responsible for the payment of all taxes which may arise from your Virtual Experiences and the creation and/or sale of your Virtual Items in connection with such experiences.

11\. LIABILITY.

**11.1** If you breach these Terms, including (without limitation) by failing to pay when due any fees or charges, and it causes us harm or financial loss, you agree to compensate us for all related losses, claims, and expenses. Examples of breaches include (but are not limited to): (i) unauthorised use of (a) the MSquared Platform, (b) our confidential information, or (c) third-party content in your Virtual Experiences; (ii) any third-party intellectual property claims; and (iii) any other violations of these Terms.

**11.2** We are not liable for claims based on modifications to the MSquared Platform made by others, combining our platform with other software, not using the latest version of the MSquared Platform that we provide, or matters outside our control. We will not be responsible for property damage, loss of earnings, profits, charges, expenses, data loss, business loss, reputational harm, or any indirect, special, or consequential damages. This exclusion applies regardless of the cause of action, including breach of contract, tort, negligence, or misrepresentation. However, nothing in these Terms limits liability for fraud, willful misconduct, or death or personal injury caused by negligence.

**11.3** Our total liability will be the greater of USD$100 or the amount you paid in Platform Fees in the calendar year in which you make a claim.\\

12\. TERM & TERMINATION

**12.1 Term.** These Terms shall apply from the date you register your account on the MSquared Platform and shall continue until you notify us of your intention to cease using the MSquared Platform (as set out in section 12.5 below), unless terminated earlier by us as permitted by these Terms or if we decide to shutdown the MSquared Platform.

**12.2. Suspension By us.** We may suspend access to your account, the MSquared Platform and/or your use of some or all of your Content on the MSquared Network if we believe you are, or will be, in breach of these Terms (including, but not limited to, the Acceptable Use Policy). We will notify you of the reason for your suspension and will give you a reasonable period to remedy the cause of your suspension (if, in our view, it is capable of remedy). If you fail to remedy the cause of your suspension within the stated period, we may terminate your access to your account, the MSquared Platform and/or your use of some or all of your Content on the MSquared Network without further notice to you.

**12.3 Termination By us.** Unless we and you have agreed otherwise in writing, we may terminate your access to your account, the MSquared Platform and/or your use of some or all of your Content on the MSquared Network on thirty (30) days written notice by us to you at any time.

**12.4. Termination For Inactivity.** We retain the right to terminate any accounts, in our sole discretion, where an account has been inactive for a period of at least ninety (90) days.

**12.5 Termination By you.** You may terminate these Terms at any time by notifying us by email at <contact@msquared.io> and by deleting your account and permanently ceasing all use of the MSquared Platform. In the event that you notify us under this section 12.5 and fail to delete your account, we reserve the right to delete your account at any time following receipt of such notice.

13\. CONSEQUENCES OF TERMINATION

**13.1** In the event of termination of these Terms:

**13.1.1** You must immediately cease using the MSquared Platform, and uninstall it from your devices as well as those of your Collaborators. You and your Collaborators will no longer be able to access your account and you will not be able to operate your Virtual Experience or create or sell new Virtual Items; and

**13.1.2** All Content developed by you will be retained by you. To the extent that you have provided us with any of your Content (for example, in executables) please contact <contact@msquared.io> to arrange the return or destruction of such code - we reserve the right to remove your Virtual Experience from the MSquared Platform in a reasonable timeframe following termination and, to the extent possible, we will give you advance notice before such removal. Our rights to use footage of your Content in Videos and other promotional and marketing materials shall survive the termination of these Terms.

**13.2** Any of your Virtual Items which were sold/gifted to End Users prior to termination may continue to be used and/or (where such Virtual Items have the ability to be resold/regifted to other End Users) resold/regifted across the MSquared Network by the End Users who own such items.

**13.3** All amounts due to us must be paid prior to the final termination date.

**13.4** Once you have exited the MSquared Platform, all rights and obligations of the parties will cease to have effect, save for: (i) any and all accrued rights and obligations of the parties at the termination date; and (ii) those rights and obligations of the parties necessary for the interpretation and enforcement of it.

14 DATA PROTECTION

In relation to data protection matters, you will be the data controller and MSquared will be the data processor. You will be responsible for the use of and entry into any applicable end user licence, privacy policy, acceptable use policy and other applicable documentation between you and End Users and/or consumers.

When you create an account on, or otherwise access, the MSquared Platform you will be required to provide to us, and we will process certain personal data. For information regarding the collection, processing, and use of your personal data please read our [Privacy Policy](https://www.improbable.io/privacy-policy). If you do not agree to our Privacy Policy you should not download or access the MSquared Platform.

15\. GENERAL

**15.1 Assignment.** You may not assign or transfer your rights and obligations to any other person for any reason, and any attempt will be considered void and result in the termination of these Terms.

**15.2 Governing Law and Dispute Resolution.** These Terms will be governed by and construed in accordance with the laws of England and Wales. Any dispute arising from or related to these Terms will be subject to the exclusive jurisdiction of the courts of England and Wales. Your local law may give you rights that these Terms cannot change; if so, these Terms apply as far as the law allows.

**Appendix 1: Acceptable Use Policy**

You are responsible for your behaviour and the Content you share when using the MSquared Platform. We want all Users to enjoy the MSquared Platform, show their creativity and feel like they belong to our international community. As a result, we do not want anything harmful or inappropriate on the MSquared Platform. To protect our community, you must not violate the Terms and by agreeing to the Terms, you agree to abide by the following rules:

1. Not to use the MSquared Platform in a way that violates the Unreal Engine licence terms or these Terms;
2. Not to sell, rent, lease, licence, distribute or otherwise transfer the MSquared Platform in whole or parts;
3. Not to copy, reproduce, or archive the MSquared Platform (or any part of it);
4. Not to reverse engineer, derive source code from, modify, adapt, translate, decompile, disassemble, hack or otherwise interfere with the MSquared Platform or make derivative works based on the MSquared Platform;
5. Not to breach any security or authentication measures in the MSquared Platform;
6. Not to use the MSquared Platform to create or operate a competing virtual world platform to the MSquared Platform;
7. Not to send spam, engage in phishing, or create or spread malware;
8. Not to display or share inappropriate and / or illegal content, such as bestiality, pornography, offensive language, graphic violence, or content promoting self-harm or criminal activity;
9. Not to participate in or promote illegal, fraudulent or misleading activities, such as impersonating others, creating fake accounts, or manipulating service metrics;
10. Not participate in, promote or provide a real money gambling service or virtual experience using or connected to the MSquared Platform (unless you have all the necessary permissions, licences and consents to do so, which will need to be shared with us for verification and maintained for the duration of your use of our platform); and
11. Not to invade others' privacy or otherwise infringe any End User’s rights to privacy.
12. Not to use the MSquared Platform in a manner which seeks to harm, misuse, damage or otherwise negatively impact either the MSquared Platform itself or the experience that the MSquared Platform provides to other End Users.
13. You agree to prevent any harassment, trolling or any other negative behaviour between End Users within your Virtual Experience.
14. You agree to set appropriate moderation settings for your Virtual Experience, based on the audience you are targeting for your Virtual Experience. For example, if you are providing a Virtual Experience aimed at families, you will set appropriate moderation settings to prohibit adult content themed Virtual Items from entering such experience.

To keep the community welcoming and inclusive for everyone, we have a zero-tolerance policy towards all illegal and inappropriate activity, including hate speech, terrorist or violent extremist content, bullying, harassing, sexual solicitation, fraud, or threatening others.

Please watch out if you are talking to other people in MSquared. It is hard for either you or us to know for sure that what other people say is true, or even if people are really who they say they are. We advise you not to give out any of your personal information.

To report misuse or a breach of this Acceptable Use Policy, please contact <legal@improbable.io> with relevant details (e.g. description, screenshots, or links). We will review all reports and take appropriate action as needed.

\\


# Firewall Problems

Guidance for accessing the M² platform via a corporate firewall

## Native Clients

Downloading and running the MSquared client requires access to [GCP](https://cloud.google.com/). Some corporate firewalls block access to certain ports or IPs used by GCP, which can prevent this working. You will need to allow the following ports and IPs:

#### Ports

`7000-7100`

<details>

<summary>IP Allow List</summary>

8.34.208.0/23

8.34.211.0/24

8.34.220.0/22

23.251.128.0/20

34.14.0.0/17

34.22.112.0/20

34.22.128.0/17

34.34.128.0/18

34.38.0.0/16

34.52.128.0/17

34.53.128.0/17

34.62.0.0/16

34.76.0.0/14

34.118.254.0/23

34.140.0.0/16

35.187.0.0/17

35.187.160.0/19

35.189.192.0/18

35.190.192.0/19

35.195.0.0/16

35.205.0.0/16

35.206.128.0/18

35.210.0.0/16

35.220.96.0/19

35.233.0.0/17

35.240.0.0/17

35.241.128.0/17

35.242.64.0/19

104.155.0.0/17

104.199.0.0/18

104.199.66.0/23

104.199.68.0/22

104.199.72.0/21

104.199.80.0/20

104.199.96.0/20

130.211.48.0/20

130.211.64.0/19

130.211.96.0/20

146.148.2.0/23

146.148.4.0/22

146.148.8.0/21

146.148.16.0/20

146.148.112.0/20

192.158.28.0/22

34.1.224.0/19

34.12.0.0/16

34.13.128.0/17

34.32.128.0/17

34.34.0.0/17

34.90.0.0/15

34.104.126.0/23

34.124.62.0/23

34.141.128.0/17

34.147.0.0/17

34.153.45.0/24

34.153.237.0/24

34.157.80.0/23

34.157.92.0/22

34.157.208.0/23

34.157.220.0/22

35.204.0.0/16

35.214.128.0/17

35.220.16.0/23

35.234.160.0/20

35.242.16.0/23

</details>

## GeForce Now

### Ports

In order to access events & content via Nvidia's GeForce Now pixel streaming, you should open the following ports:

> * 49003 – UDP Inbound AUDIO
> * 49004 – UDP Outbound AUDIO
> * 49005 – UDP Inbound VIDEO
> * 49006 – TCP/UDP Outbound/Inbound Remote Input
>
> If GeForce NOW is running behind a corporate or school firewall, the firewall should allow traffic to/from GeForce NOW servers’ UDP ports between 10000 and 20000.

(See [this Nvidia support page](https://nvidia.custhelp.com/app/answers/detail/a_id/4504/~/how-can-i-reduce-lag-or-improve-streaming-quality-when-using-geforce-now%3F) for more context.)

### Testing

You can check whether your network is blocking pixel-streaming traffic by trying to access an event or content and seeing whether you are presented with an error similar to:

<figure><img src="/files/hfY0oncjtFaskJejgxNE" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you are reading this page in preparation for a platform evaluation - you can see if pixel streaming is blocked on your network by going to <https://construct.msquared.io/> > `Construct Main` > `Play Now` > `Join on web` > `GeForce Now` and seeing whether you experience the error above
{% endhint %}

### Availability

As of 2025, GeForce Now should cover all major regions in the world, specific data centers are listed below, if your desired country is not listed GFN may still be accessible in those countries. For additional testing, we would recommend using a VPN and accessing the Construct test map mentioned above:

<details>

<summary>GFN On-demand datacentres</summary>

* Åland (Finland)
* Albania
* Andorra
* Anguilla
* Australia - Served via Japan
* Austria
* Bahamas
* Barbados
* Belgium
* Bermuda
* Bosnia and Herzegovina
* British Virgin Islands
* Bulgaria
* Canada
* Canary Islands (Spain)
* Cayman Islands
* Croatia
* Cyprus
* Czechia (Czech Republic)
* Denmark
* Dominica
* Dominican Republic
* El Salvador
* Estonia
* Faroe Islands
* Finland
* France
* Germany
* Gibraltar
* Greece
* Greenland
* Guadeloupe
* Guatemala
* Guernsey
* Honduras
* Hong Kong
* Hungary
* Iceland
* Ireland
* Isle of Man
* Israel
* Italy
* Japan
* Jamaica
* Jersey
* Latvia
* Liechtenstein
* Luxembourg
* Malta
* Martinique
* Mexico
* Monaco
* Mongolia
* Montenegro
* Montserrat
* Morocco
* Netherlands
* North Macedonia
* Norway
* Philippines
* Poland
* Portugal
* Puerto Rico
* Republic of Lithuania
* Romania
* Saint Barthélemy
* Saint Pierre and Miquelon
* Serbia
* Slovakia
* Slovenia
* Spain
* Sweden
* Switzerland
* Taiwan
* Trinidad and Tobago
* Tunisia
* Turks and Caicos Islands
* U.S. Virgin Islands
* Ukraine
* United Kingdom
* United States

</details>

In the follow countries, the service is only available via GeForce Now partners, and capacity must be reserved in advance:

<details>

<summary>Reserved capacity partners &#x26; countries</summary>

GFN.CO.KR

* South Korea

AU

* Japan

GAME+

* Turkey
* Cyprus

Zain

* Jordan
* Kuwait
* Oman
* Saudi Arabia

ABYA

* Argentina
* Brazil
* Chile
* Paraguay
* Uruguay

StarHub

* Singapore
* Indonesia
* Thailand
* Vietnam

Yes

* Malaysia

GFN.AM

* Armenia
* Azerbaijan
* Georgia
* Kazakhstan
* Moldova
* Ukraine
* Uzbekistan

rain

* South Africa

</details>


# Unreal Development

Morpheus Platform worlds are built on top of [Unreal Engine](https://www.unrealengine.com/).

To develop for Morpheus Platform, you'll need to work with Unreal.

{% content-ref url="/pages/tqJxRs3gJxoItp3QHfUN" %}
[Get Started](/creation/unreal-development/getting-started)
{% endcontent-ref %}


# Get Started

Practical steps to start building your experience in Unreal

{% content-ref url="/pages/Gm2AWMpNTTkOKKC6WvdG" %}
[Download the Editor](/creation/unreal-development/getting-started/downloading-the-tooling)
{% endcontent-ref %}

{% content-ref url="/pages/zsaNosNEVeTOjGDCswOz" %}
[Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project)
{% endcontent-ref %}

{% content-ref url="/pages/iB2rquVZ9NMkJ9Fgop8e" %}
[Differences from Unreal](/creation/unreal-development/getting-started/differences-in-unreal-development-workflow)
{% endcontent-ref %}

{% content-ref url="/pages/zvKsKEABUy4UhFgkvOpt" %}
[Morpheus Networking](/creation/unreal-development/getting-started/networking)
{% endcontent-ref %}

{% content-ref url="/pages/PpOiDcBSuY7MQ6JuXHv7" %}
[Creating a New Map](/creation/unreal-development/getting-started/creating-your-own-map)
{% endcontent-ref %}

{% content-ref url="/pages/VsOboXCnSeURlG7xXt92" %}
[Creating a new character](/creation/unreal-development/getting-started/creating-your-own-character)
{% endcontent-ref %}

{% content-ref url="/pages/CYQR17HqDkTSAM3hkVCw" %}
[Upload Content](/creation/unreal-development/getting-started/uploading-content)
{% endcontent-ref %}


# Download the Editor

Download our editor to start building Morpheus Platform experiences

## System Requirements <a href="#system-requirements" id="system-requirements"></a>

Currently, the Morpheus Platform editor only supports Windows 10 and 11.

## Hardware Requirements

Our editor is built on Unreal Editor, and has the same [hardware and software requirements](https://dev.epicgames.com/documentation/en-us/unreal-engine/hardware-and-software-specifications-for-unreal-engine).

{% hint style="info" %}
The exact hardware necessary will depend on the scale of your project.
{% endhint %}

## Prerequisites

* If you haven't installed Unreal before, you might need Microsoft's [Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe).
* You need to have been given `Developer` access to your metaverse - see [Access Control](/admins/access-control).

## Steps

From your [dashboard](/morpheus-platform/glossary#dashboard), click the **`⬇ Download the editor`** button.

In the modal dialog that appears, first click the **`⬇ Install the Launcher`** button.

<figure><img src="/files/dA4o2DDGzmEfRvse8bRQ" alt=""><figcaption><p>Note: Your <a href="/pages/rlOPBWzdQ0L5EtzpgpUy#projects">project</a> probably won't be called Staging. If you're not sure which project's editor to download, speak to your colleagues.</p></figcaption></figure>

{% hint style="info" %}
M² Launcher is our thin desktop app for Unreal editor & client downloading. It caches downloads so that subsequent launches happen fast.

i.e. The second time you click ⬇ **`Download`** for the same editor or client version, it should run immediately.
{% endhint %}

{% hint style="warning" %}
To change the editor download location (e.g. drive) - see the [M2 Launcher](/apis-and-tooling/launcher) page.
{% endhint %}

After installing the launcher, click the bigger ⬇ **`Download`** button to get the editor.

The launcher should automatically appear and start the editor download.

<figure><img src="/files/NQsjmYSccDhRdyo9XGr5" alt=""><figcaption><p>Downloading an editor</p></figcaption></figure>

Once the download finishes, it should automatically open the Unreal Engine project modal.

If it doesn't, you can click the ⬇ **`Download editor`** button in the dashboard again, and now the launcher will immediately open Unreal.

To create a new project:

* Click the `MSquared` tab
* Configure the Project Location and Project Name as you like
* Click the `Create` button

{% hint style="info" %}
For further details on how to use the template project, see [Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project)
{% endhint %}

<figure><img src="/files/Qx3EhoXk8HLxQRK67EzP" alt=""><figcaption><p>Creating a project</p></figcaption></figure>

Alternatively, you may want to [open an existing project with this editor](/creation/unreal-development/tutorials/upgrade-the-editor).

{% hint style="info" %}
In future, you can open your project just by clicking the `uproject` file in your project folder. You should only need to use the download path when if you need to update the editor version you're using. [More on that later](/creation/unreal-development/tutorials/upgrade-the-editor).
{% endhint %}

## Wait for the Editor to Open

Lastly, wait for the Unreal Editor to open your project.

<figure><img src="/files/0gH2fBETa6RCYLo13X7F" alt=""><figcaption><p>The editor opening a project</p></figcaption></figure>

<figure><img src="/files/ucuTBnBVjp8BtrxuMWyw" alt=""><figcaption><p>Your first MSquared project</p></figcaption></figure>

## Known Issues

#### Editor downloads but errors when trying to open

You may need to install the Unreal Engine prerequisites. You can do this by:

1. Navigating to`%LocalAppdata%/M2Launcher/Editors`
2. Sort this directory by Date modified and open the most recently modified directory (this is the Editor that you most recently downloaded).
3. From here, navigate to`Windows/Engine/Extras/Redist/en-us`
4. and run the `UEPrereqSetup_x64.exe` file.


# Morpheus Base Project

{% hint style="success" %}
verified: 2025-11-18 version: v39
{% endhint %}

<figure><img src="/files/aPfXh3EVgFP5wG0vhkFU" alt=""><figcaption></figcaption></figure>

## Summary

The `M² Base Project` contains starting assets. They have sensible default values but you're free to modify and experiment with them.

<figure><img src="/files/M69SRiOYKItDUkY8HqYQ" alt=""><figcaption></figcaption></figure>

The `M² Base Project` also contains [Live Config](/creation/unreal-development/features-and-tutorials/live-config) files, which act as the starting point for making changes to MSquared's default values.

<figure><img src="/files/PZ1waiTjPnp0SsdzvzEi" alt=""><figcaption></figcaption></figure>

## Important Assets

* `BP_Example_PlayerController` and `BP_Example_PlayerCharacter` are your player controller and pawn respectively. These behave the same as the native Unreal equivalents, except that they perform no replication.
* `BPM_Example_PlayerCharacter` is your character's Morpheus Actor. This is tied to your pawn, and handles all the replication. For more details on this, see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking).
* `WBP_Example_HUD` is your HUD widget. This is the recommended location to place any UI elements you want to add.
* `[Your project path]/Config/LiveConfig/Overrides/game.override.json` is where you can override "game" live config values, which will encompass most live config values you will likely make changes to. Some starting overrides have been made here already, such as configuring the quickbar, but you can change these or add other overrides if you want changes to MSquared's default behavior here.

The template project is built off of the [Example Plugin](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin)'s content, including extending from its base classes (e.g. [The Example Character](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/the-example-character)). If you want to make a start on modifying and customizing your character, see [Creating a new character](/creation/unreal-development/getting-started/creating-your-own-character)

Kickstart your project by importing and creating assets in your project's content folder, transforming it into a truly unique experience.

## The Welcome Message

When you first create a project using the template, you will be presented with a welcome message.

<figure><img src="/files/fNbrG79vXvU6D0hmfx2O" alt=""><figcaption></figcaption></figure>

The message will be shown every time the project is opened, until dismissed with "Don't show this again". However, note that the checkbox only applies to you locally, not for all users of your project. If you don't want collaborators to see the message, or want to customize its contents, you can do so in \`Project Settings -> Editor -> M2 Template Creation Settings

<figure><img src="/files/qN0IQCAORcCQYYyw0nod" alt=""><figcaption></figcaption></figure>


# Differences from Unreal

{% hint style="success" %}
verified: 2025-11-18 version: v39
{% endhint %}

Morpheus Platform uses a customized version of the Unreal Engine that involves changes to standard Unreal workflows.

## Why is Development Different from Standard "Vanilla" Unreal? <a href="#how-and-why-is-development-different-from-vanilla-unreal" id="how-and-why-is-development-different-from-vanilla-unreal"></a>

* We replace the Unreal implementation of a few systems to drastically increase the number of people you can have in your experiences (i.e. the max CCU). These systems include:
  * Networking - our [Morpheus Networking ](/creation/unreal-development/getting-started/networking/networking)stack allows thousands of players to be networked together in real time
  * Rendering - Morpheus Rendering allows for thousands of individually animated, fully customised 3D avatars to be rendered on-screen at the same time
  * Audio - [Morpheus Crowd Audio](/creation/unreal-development/features-and-tutorials/crowd-audio) provides a realistic spatial audio experience for all players
* Our game client dynamically loads world content when starting up, which carries benefits for creator velocity
* Our base platform is consistent, so we can allow objects such as avatars and more to work across worlds (interoperability)

## Key Differences <a href="#what-are-the-implications-of-the-changed-development-flow" id="what-are-the-implications-of-the-changed-development-flow"></a>

* Developers are restricted to only changing Unreal assets: blueprints, materials, meshes and other binary data
  * This means you can't add or modify C++ code. However, visual scripting in blueprints provides essentially the same feature set.
  * This also means that we don't support bespoke precompiled plugins, as we'd need to distribute them to all users
* Networking works significantly differently (see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking))
  * As a result, not all Unreal actors can be networked, and some of the core Unreal classes behave differently (see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking#changes-to-core-unreal-classes))
* Not all local changes are reflected in launched worlds
  * Some configuration files are not supported. Neither is changing engine content directly. This is because your uploaded plugin content is dynamically loaded into a prebuilt client. For this reason, we hide a lot of the contents of Project Settings and make engine content read-only to prevent users tripping themselves up on this expectation.
  * For more details, see [Editing Project Settings](/creation/unreal-development/tutorials/adding-project-settings-config-overrides)
* Size of content will affect load times
  * The content in your plugin is loaded into the client at runtime. This means the larger the size of the content in your plugin, the longer client will initially have to wait before it becomes playable.
* We have made some changes to the player character, and how it is configured. For more details, see [Character Configuration](/creation/unreal-development/getting-started/differences-in-unreal-development-workflow/msquared-character-configuration).


# Character Configuration

There are a few differences from native unreal in how we set up the character that the player uses.

## How we Define the Character

### The Main Classes

We use a `Pawn` and `PlayerController`, same as native Unreal, but also define a `MorpheusPawnActor`, which handles the replication. For more details on this, see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking).

Like in native Unreal, these can be controlled via the `GameMode`.

The core Unreal classes, like `Pawn` and `PlayerController` do behave slightly differently when using Morpheus networking. For more details, see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking#changes-to-core-unreal-classes).

### Your Avatar

Instead of using regular static meshes for your character, we use an interoperable avatar system. For details of how this is used, see [Creating a new character](/creation/unreal-development/getting-started/creating-your-own-character#updating-your-character-avatar)

### Your "Render Target"

To handle large scale, we don't use "full actors" (i.e. `Pawn`s) per Morpheus Actor in the world. Instead, we dynamically switch between full actors, and "the crowd" (a high performance way of representing distant actors - see [Crowd Rendering](/creation/unreal-development/features-and-tutorials/the-animated-crowd)) based on the distance the character is away from you. For more details, see [Creating a new character](/creation/unreal-development/getting-started/creating-your-own-character).

By default, the "full actor" used, both for yourself and for nearby other players, is the `DefaultPawnClass` defined in your `GameMode`. In release v40 onwards, your "crowd" is configured automatically for you. These can be controlled in your Morpheus Actor class. For more details on how to do this, see [Creating a new character](/creation/unreal-development/getting-started/creating-your-own-character#updating-your-character-avatar)

<figure><img src="/files/RbEHwed99ylROMqyqCwu" alt=""><figcaption><p>From your Morpheus Actor class, you are able to configure your default avatar Url, and your render target. For most player characters, all you will need to set is "Use Default Pawn as Render Target Actor", and "Crowd Enabled", and it will configure things as expected.</p></figcaption></figure>

### Pawn Sets

{% hint style="info" %}
NOTE: From release v40 onwards, using Pawn Sets to configure your render targets is no longer needed - you can instead configure your character for most use cases directly from the Morpheus Actor. For more details on how to do this, see [Creating a new character](/creation/unreal-development/getting-started/creating-your-own-character)
{% endhint %}

In basic cases, you will only need to modify your `Pawn` in the `GameMode` to control which class is used to represent player characters. However, there are some cases where you will need further configuration, which is controlled in the "Pawn Set". This controls all possible render targets used for the Morpheus Actor, including in the animated crowd, and what class is used on other clients.

The main fields to consider:

* `OverrideAuthPawnClass` - if one is provided, this will change the pawn used when using the given pawn set, when you are the auth client. Otherwise the `DefaultPawnClass` in the game mode will be used.
* `LodGroup` `Bucket` - explained in more detail in [Morpheus Render Targets](/creation/unreal-development/getting-started/networking/morpheus-render-targets#lod-group-buckets), this allows you to specify that the given MorpheusActor is "higher priority" than others, and so should e.g. use the LOD0 Actor over other "lower priority" clients, even if they are closer.

  <figure><img src="/files/6kNMhnNc18UiHzM8uMW1" alt=""><figcaption></figcaption></figure>
* `LOD Levels` - this ties in to MSquared's rendering system, and how it supports >1000 player events. A limited number of nearby characters are represented as complete characters (Actor render targets), and ones in the distance are represented by the animated crowd. (For more details, see [Crowd Rendering](/creation/unreal-development/features-and-tutorials/the-animated-crowd))
  * For now, the only recommended class to change would be the LOD 0 `Override Actor Class` - this will control what actor is used to represent the nearby other players (if left as `None`, it will also use the `DefaultPawnClass` from the game mode).

<figure><img src="/files/KPZiac153k0025Y8hJNJ" alt=""><figcaption></figcaption></figure>

#### How to specify the Pawn Set

The pawn set can be controlled in the following places:

* The default pawn set can be controlled via `Project Settings - Engine - M2 Engine Default Pawn Set - Default Pawn Set`
  * By default, the pawn set used is `DA_Pawns`, which has no overrides present, meaning that the LOD0 character used will be that defined in your game mode.\\
  * From Release v36 onwards, the default pawn set can be obtained via the `GetDefaultPawnSet` helper function
  * NOTE: This requires that your character implementation applies the pawn set somewhere. This will be done for you in the example assets, but would not be the case if you started from the `M2M_CharacterBase` code class
* Manually setting the pawn set, via the `ApplyPawnSet` helper.

  * NOTE: This is done for the local machine. If you want the pawn set to be updated on all clients, you will need to call this on all clients.

  <figure><img src="/files/zrv03zqsfXarDnoUyBMe" alt=""><figcaption><p>The example character sets the pawn set to be the default pawn set on begin play.</p></figcaption></figure>

## Gameplay Changes/Additional Functionality (Deprecated)

{% hint style="warning" %}
NOTE: The following gameplay related divergences are only present in our deprecated content. From release v39 onwards, you can ignore this section entirely.
{% endhint %}

Our default character and controller have some gameplay related additions:

### Gait Speed

Instead of defining a single `MaxWalkSpeed` which controls the grounded move speed, we split the speed into three modes: `Walk`, `Jog` and `Sprint`. This gives us easy out-the-box movement speed control, e.g. starting in `Jog`, but pressing `Shift` to enter `Sprint` mode, or pressing `Ctrl` to enter `Walk` mode.

This is controlled via the `J_CharacterMovementComponent`, on the BP Character.

<figure><img src="/files/fquaXMMPKWKSyTYE56Fz" alt=""><figcaption></figcaption></figure>

If you are using the deprecated roles table, you can customize the speed per role, by adding `Gait Speeds` to the `RoleConfigurationOverrides`. If no override is provided, it will use the default in the `J_CharacterMovementComponent`.

<figure><img src="/files/gnCRAu8waua0iBKm9XoQ" alt=""><figcaption></figcaption></figure>

### Jump Count

Like with native Unreal, the jump count can be controlled via the `Jump Max Count` field on the character (e.g. setting it to 2 will allow you to double-jump, setting it to 0 will disable jumping).

We also add the `Character.JumpMaxCount` live config value. This defaults to `-1`, but if set to a value >= 0, it will override the value in the character, allowing for live enabling/modifying the number of jumps.


# Morpheus Networking

The biggest technical innovation in MSquared is how networking works. We replace Unreal's networking with our own custom implementation, called Morpheus.

You can watch the video below for an introduction, additional information is available in the subpages.

{% embed url="<https://www.youtube.com/watch?v=m2plmKMiEa8>" %}


# Introduction to Morpheus Networking

## What is Morpheus Networking? <a href="#networking-actorreplication" id="networking-actorreplication"></a>

In MSquared, we replace Unreal's standard networking with our own custom implementation, called Morpheus.

Morpheus is the technology that enables thousands of players and objects to be networked together in the same space, in real time, whilst using the bandwidth of a standard battle royale game.

The fundamental concepts of Morpheus networking are the same as [in Unreal](https://dev.epicgames.com/documentation/en-us/unreal-engine/networking-and-multiplayer-in-unreal-engine):

* A single server coordinates multiple clients
* The basic unit of networking is the actor
* Actors are synchronised ("replicated") between server and client using two mechanisms:
  * Variable replication
  * RPCs

This document assumes a rough familiarity with these concepts, and focuses on Morpheus's essential differences from Unreal.

## Morpheus Actors <a href="#networking-actorreplication" id="networking-actorreplication"></a>

In a Morpheus game, only actors that inherit from `AMorpheusActor` are networked. All other actor types are local-only. If you spawn an `AMorpheusActor` on the server, it will be replicated to all clients immediately. `AMorpheusActors` should only be destroyed on the server, and the actor's destruction will also be replicated to all clients immediately.

Each client sees every `AMorpheusActor` in the world; there is no concept of 'net relevancy' or 'checking in and out' an actor.

## Changes to Core Unreal Classes

Since only Morpheus Actors are networked, a number of the core Unreal classes behave slightly differently when using Morpheus networking:

* `GameMode` - Functionally the same as native Unreal, except that it adds a default Morpheus Actor class, similar to the `Default Pawn Class`, and it replaces the normal `GameState` with a `MorpheusGameState`. \*

  ```
  <figure><img src="../../../../.gitbook/assets/image (1426).png" alt=""><figcaption></figcaption></figure>
  ```

  * Note that the `GameMode` is also created on the local client, rather than exclusively existing on the server, since a client using Morpheus networking is configured to be a "standalone" game, rather than a "client", since it does not use native Unreal networking.
* `GameInstance` - same as in native Unreal networking. It exists on all machines, but is not networked.
  * NOTE: This cannot be modified by downstream projects. Due to our [Worlds](/creation/worlds) setup where a base Morpheus Platform build is launched, and user content is loaded in as a Mod, the game instance used will be the MSquared default, not what is provided by the user's content. This is required to support interoperability between different worlds built on the same platform.
* `GameState` - Not used in Morpheus networking. Replaced with a replicated `MorpheusGameState` (a Morpheus Actor that is replicated, and can be used functionally like a `GameState`.)
* `GameSession` - Not used in Morpheus networking. We handle online services and player connection separately.
* `PlayerController` - This is only present on the local client's machine. It is not replicated, and does not exist on the server.
* `PlayerState` - This is not networked. It is largely unused and untested with Morpheus networking - if you want replicated player data, you can use the Morpheus Actor.
* `Pawn`/`Character` - This is not networked. For the local player, this works the same as native local-only games. For other players, their in-game representation is determined by their morpheus actor's render target. (See [Morpheus Render Targets](/creation/unreal-development/getting-started/networking/morpheus-render-targets)).
  * If other players' characters are represented with actors, they are also subject to pooling (see [Actor Pooling](/creation/unreal-development/features-and-tutorials/actor-pooling))

## Replication

### Network Levels <a href="#networking-networklevels" id="networking-networklevels"></a>

Although every client sees every `AMorpheusActor` in the world, it may not hold the full state for all of them. On each client, each `AMorpheusActor` is present at one of three network levels:

* Background
* Midground
* Foreground

Only actors in the foreground are fully replicated.

For a detailed description of how network levels work, see [Network Levels](/creation/unreal-development/getting-started/networking/network-levels).

### Authority

Unlike in standard Unreal, a `AMorpheusActor` may have an **authoritative client**. This is an immutable property assigned when the actor is spawned. An actor's client authority affects both variable replication and RPCs.

(For how to assign a client authority to an actor, see "Spawning and Destroying" below.)

### Variable Replication <a href="#networking-properties" id="networking-properties"></a>

In Morpheus, you can mark blueprint variables for replication the same way you would in Unreal. However, **existing Unreal replication features such as RepNotify behave differently in Morpheus**. For more information on how these features work and how to apply them in your variable definitions, see [Replicated Properties](/creation/unreal-development/getting-started/networking/replicated-properties).

### RPCs <a href="#networking-rpcs" id="networking-rpcs"></a>

Morpheus supports the three main types of Unreal RPC: `Server`, `Client` and `NetMulticast`. However, the semantics of these differ from standard Unreal networking. For further information, see [RPCs](/creation/unreal-development/getting-started/networking/morpheus-rpcs).

## Morpheus Actor Components <a href="#networking-morpheusactorcomponents" id="networking-morpheusactorcomponents"></a>

In order to be networked, a component must:

* Inherit from `UMorpheusActorComponent`
* Belong to an `AMorpheusActor`
* Be created in its owning actor's constructor, using `CreateDefaultSubobject`. **Components added to existing actors won't be replicated.**

Authority and network level are delegated to the component's owning actor.

Variable replication and RPCs work the same way as for `AMorpheusActor`.

## Spawning and Destroying <a href="#networking-spawninganddestroying" id="networking-spawninganddestroying"></a>

### Spawning an `AMorpheusActor` <a href="#networking-spawning" id="networking-spawning"></a>

**Only the server** can spawn replicated `AMorpheusActor`s. You can spawn them from server blueprints, using Unreal's standard `SpawnActor` functions. In addition, Net Startup Actors that are `AMorpheusActors` will be automatically spawned and replicated when their level starts up or their sublevel streams in.

By default, an `AMorpheusActor` has server authority. To spawn an `AMorpheusActor` with client authority, you must call `SpawnMorpheusActorWithClientAuthority` **on the server**. You identify the authoritative client by passing in an `AMorpheusClientConnection`; this is typically obtained by calling the `AMorpheusActor` function `ServerGetRpcCallerConnection` from within the handler for a `Server` RPC.

Morpheus does not support authority transfer. If a client disconnects, the server destroys any `AMorpheusActor`s which that client had authority over.

### Destroying an `AMorpheusActor` <a href="#networking-destroyinganamorpheusactor" id="networking-destroyinganamorpheusactor"></a>

Only the server can destroy replicated `AMorpheusActor`s, using the standard Unreal `Destroy` functions.

### Lifecycle Events <a href="#networking-lifecycleevents" id="networking-lifecycleevents"></a>

For `AMorpheusActor`s and `UMorpheusActorComponent`s, there's a single change to the standard [Unreal actor life cycle](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-actor-lifecycle). Instead of the standard `BeginPlay` event, you need to use `MorpheusBeginPlay`. (`BeginPlay` still exists, but shouldn't be used - it will print warnings in the blueprint compiler if you do use it.)

The call to `MorpheusBeginPlay` marks the point at which networking functionality becomes available. RPCs sent from within `MorpheusBeginPlay` are queued up and sent later, once the actor has completed initialization.


# Net Relevancy Levels

Previously known as: Network Levels

## Overview

Each [replicated property](/creation/unreal-development/getting-started/networking/replicated-properties) on an `AMorpheusActor` belongs to one of three net relevancy levels (Foreground, Midground or Background) as defined by the user.

Seeing an `AMorpheusActor` at a specific net relevancy level means you can **see all replicated properties belonging to that net relevancy level and below**. For example, if a client is seeing an `AMorpheusActor` in the midground, it will see all the actor's background and midground properties. This means that every client will see all background properties for every `AMorpheusActor` in the world at all times.

Each client decides actors' net relevancy levels according to a prioritization algorithm. The net relevancy levels are filled in order, so that the highest priority actors are in the foreground, the next are in the midground, and the remainder are in the background. The number of actors allowed in foreground and midground is customisable: see [#modifying-the-number-in-a-given-network-level](#modifying-the-number-in-a-given-network-level "mention").

By default, the algorithm prioritizes all actors based on their distance from the client's authoritative Morpheus pawn, but there are some exceptions. For these, see [#forcing-prioritizing-an-entity-into-the-foreground](#forcing-prioritizing-an-entity-into-the-foreground "mention") and [#modifying-the-client-origin-for-network-prioritization](#modifying-the-client-origin-for-network-prioritization "mention").

You can specify the `MinimumNetworkLevel` of an `AMorpheusActor` type. The `AMorpheusActor` will be forced into at least this net relevancy level at all times.

Below is a breakdown of each net relevancy level, its behavior, limitations and examples.

### Foreground <a href="#networklevels-background" id="networklevels-background"></a>

All foreground properties are replicated at `60Hz`.

Foreground properties can use most types supported by standard Unreal replication: see [Supported types](/creation/unreal-development/getting-started/networking/replicated-properties#morpheusactorproperties-propertymeta).

Multicast RPCs are **only** received for actors in the foreground net relevancy level.

Depending on the game, each client will likely be able to see on the order of 50-100 actors in the foreground. Foreground properties cost much less bandwidth than midground & background ones. You should only move a property out of foreground if you definitely need it to be more widely visible.

Typical foreground properties include:

* The player's name.
* The player's current chat status.
* A list of the player's teammates.

The server sees every actor in the foreground net relevancy level, but only receives foreground property updates at `30Hz` due to its limited tick rate to `30 FPS`.

### Midground <a href="#networklevels-midground" id="networklevels-midground"></a>

All midground properties are replicated at `30 Hz`.

Background properties can only use a narrow set of types: see [Supported types](/creation/unreal-development/getting-started/networking/replicated-properties#morpheusactorproperties-propertymeta).

Multicast RPCs are **not** received for actors in the midground net relevancy level.

Depending on the game, each client will likely be able to see on the order of 500-1000 actors in the midground.

Typical midground properties include:

* A higher fidelity quantised position of the actor.
* The quantised rotation of the actor.
* The colour index of each player's hat.

### Background

All background properties are replicated at `6 Hz`.

Background properties can only use a narrow set of types: see [Supported types](/creation/unreal-development/getting-started/networking/replicated-properties#morpheusactorproperties-propertymeta).

Multicast RPCs are **not** received for actors in the background net relevancy level.

Because every client sees all background properties in the world, **you have to be careful** what you mark as a background property. Adding background properties which frequently change value can incur a large bandwidth cost to your game. Additionally, processing a large number of OnReps in a single tick in BP can impact client performance. You should only mark a property as being in the background if it is absolutely essential that it is visible on all clients.

Typical background properties include:

* A low fidelity quantised position of the actor.
* An index determining which player character the actor is.
* The current emote index of each player.

## Net Relevancy Groups

{% hint style="warning" %}
Net Relevancy Groups have been introduced in v39
{% endhint %}

Each `Net Relevancy Group` has its own net relevancy prioritization config and identified by a `Group Id`

Each `AMorpheusActor` can be assigned to only one `Net Relevancy Group Id` at a time.

The `AMorpheusActor` will be prioritized according to its current `Net Relevancy Group` config.

We currently have the following `Net Relevancy Groups` to choose from:

1. `AlwaysForeground` : All `AMorpheusActor`s belonging to this group will always be in the `Foreground` net relevancy level regardless of their distance to the player.
2. `ProximityBased` : `AMorpheusActor`s belonging to this group will be prioritized according to their distance to the player and respect the `NumInForeground` and `NumInMidground` configurations specified for that group.
3. `CustomGroup` : Intended for Advanced users only and acts as an auxiliary group for project specific needs.

### Assigning MorpheusActors to Net Relevancy Groups

You can assign `AMorpheusActor` to a net relevancy group from its Blueprint class details panel:

<figure><img src="/files/erAUyj8Jao7minXpivJa" alt="" width="563"><figcaption><p>MorpheusActor Details Panel</p></figcaption></figure>

You can also change the assigned `Group Id` for a `AMorpheusActor` during runtime via blueprints using this blueprint function:

<figure><img src="/files/LmizrqbfbTJnAO89U8kF" alt="" width="375"><figcaption></figcaption></figure>

## Customizing Net Relevancy Groups

### Modifying the number in a given net relevancy level for a given group

The number of entities in a given net relevancy level can be modified in 2 ways:

#### Via [Live Config](/creation/unreal-development/features-and-tutorials/live-config):

* To modify the number of players in the foreground level, use `PlayerClient.Networking.NumInForeground` (in the `game` config)
* To modify the number of players in the midground, use `PlayerClient.Networking.NumInMidground` (in the `game` config)
* The remaining entities will be placed in the background.
* Note that this will only apply to the `ProximityBased` group Id.

<figure><img src="/files/L89odJ7huU5BJhKbgxFe" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
NOTE: Updating the live config will apply to all users.
{% endhint %}

#### Via Blueprints

In the `MorpheusClientConnection` class there is the function `SetConfigForNetRelevancyGroupId` which can be used to change the number of actors in `Foreground` and in `Midground` for the `Proximity Based` net relevancy group during **runtime**.

<figure><img src="/files/e5PhWgynSSZqV63y4WZm" alt="" width="563"><figcaption></figcaption></figure>

{% hint style="info" %}
NOTE: Calling this method will only apply locally. If you want to update the number for everyone, you will need to either call the method on all machines, or go via the live config approach.
{% endhint %}

### Modifying the "client origin" for network prioritization

{% hint style="warning" %}
NOTE: This section contains features that were added for release version v28. Some functionality described here won't be present in earlier versions.
{% endhint %}

The client connection uses a "Client Origin Actor" to determine the client's centre for distance related priority calculations. By default this is the authoritative pawn that the client is controlling, but it can be modified.

E.g. if you want to make a "sniper" feature, where you focus in on a distant location, you would want the most high fidelity networked actors to be around your zoomed in location, not your actor's current position.

This client origin actor can be live-updated, by calling the `PushClientOriginActor` method, providing a new actor to use as the origin location. This makes the new actor trump the default as the origin for the prioritization logic. Once you are done, and want to go back to the default prioritization, call `RemoveClientOriginActor`, to stop considering your new actor, and return to using the previously set one.

<figure><img src="/files/aq4IOXAyvihsMjM9VfFQ" alt=""><figcaption></figcaption></figure>

(If you want the client origin to be at a fixed or relative location, the simplest approach would be to spawn an invisible actor, and use it as the Client Origin Actor).

### Forcing/prioritizing an entity into the foreground

{% hint style="warning" %}
NOTE: This section contains features that were added for release version v28. Some functionality described here won't be present in earlier versions.
{% endhint %}

If you want a particular entity to be preferred by the prioritization system regardless of position

This is used e.g. by our "presenters": if you have a VIP player in your game that you want everyone to see at the highest fidelity, you can set it to be prioritized.

There are two ways of achieving this:

* Via the `SetIsForcedIntoForeground` method on a morpheus actor:
  * (This will mean that the actor is prioritized on the local machine, and so will trump non-prioritized actors, regardless of position)

    <figure><img src="/files/bFSbznB2VrOHqetEhxxE" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
NOTE: The forced prioritization here does not override the cap of entities in the foreground level. If you have e.g. max 30 entities in your foreground, and have 50 prioritized, it won't put all 50 in your foreground. 30 is still the max.
{% endhint %}


# Replicated Properties

In Morpheus as in Unreal, the basic unit of replication is the [property](https://docs.unrealengine.com/5.3/en-US/unreal-engine-uproperties/). Properties are marked for replication the same way as in Unreal, but Morpheus can only replicate properties belonging to classes based on `AMorpheusActor` and `AMorpheusActorComponent`.

This page will detail the concepts introduced with replicated Morpheus properties, before demonstrating how to implement them in the [How to define properties](#how-to-define-properties) section below.

### Replication semantics <a href="#morpheusactorproperties-propertyreplicationsemantics" id="morpheusactorproperties-propertyreplicationsemantics"></a>

The following semantics apply for **all** properties in **any** [network level](/creation/unreal-development/getting-started/networking/network-levels):

* Replicated properties are **registered** once the `MorpheusActor` has spawned at the Server (specifically after `PreInitializeComponents` has been called).
  * This means that any `AMorpheusActorComponent` added to the `MorpheusActor` afterwards will not be registered and hence its properties will **NOT be replicated**.
* Other than that, property replication in Morpheus follows [Unreal semantics:](https://dev.epicgames.com/documentation/en-us/unreal-engine/property-replication-in-unreal-engine?application_version=5.4)

> Property replication is reliable. This means that the property of the client version of the Actor will eventually reflect the value on the authority, but the client will not necessarily receive notification of every individual change that happens to a property at the authority. For example, if an integer property rapidly changes its value from 100 to 200, and then to 300, the client will eventually receive an update with the value of 300, but there is no guarantee that the client will know about the change to 200.

### Features

#### Network Relevancy level <a href="#morpheusactorproperties-clientauthority" id="morpheusactorproperties-clientauthority"></a>

In Morpheus, every replicated property belongs to one of three network levels (Foreground, Midground or Background). See [Network Levels](/creation/unreal-development/getting-started/networking/network-levels) for details.

#### Client authority <a href="#morpheusactorproperties-clientauthority" id="morpheusactorproperties-clientauthority"></a>

In standard Unreal networking, only the server can update replicated properties. If a client wants to change a replicated property, it must send an RPC to the server instructing it to do so.

In Morpheus, however, you can define **client authoritative properties**. This means that the client which is authoritative over the entity can *directly change* the replicated property, and the new value will be sent to the server and other clients.

This allows you to avoid the server becoming the bottleneck for certain systems where it is appropriate. Properties belonging to any network level can be marked as client authoritative.

The server still receives a 4Hz view of all client authoritative properties, which it can use to validate that the client is behaving appropriately. It would be up to the user to perform validation of client authoritative properties on the server, and one potential response to a client behaving inappropriately is kicking the client.

**NOTE:** For Client Authoritative properties to work, the actor must be spawned with Client Authority. For information on how to do this, see [Spawning](/creation/unreal-development/getting-started/networking/networking#networking-spawninganddestroying).\
**NOTE**: Once a property is defined as client authoritative, the server no longer has authority over the property and modifications made by the server will not be replicated.

#### RepNotify <a href="#morpheusactorproperties-repnotify" id="morpheusactorproperties-repnotify"></a>

Morpheus supports `RepNotify` functions with the same behaviour as native Unreal. That is, when a property update is received and if the received value is different to the local value, then the `RepNotify` function will be called. If the received value is equal to the local value, then the function is **not** called.

Note that `RepNotify` execution is ordered across sub-objects; an Actor's `RepNotify` function will always be executed before those of its components.

#### Owner Only <a href="#morpheusactorproperties-owneronly" id="morpheusactorproperties-owneronly"></a>

You can mark a foreground server-authoritative property as **Owner only**, which means it will only be replicated to the authoritative client.

#### Authority Only <a href="#morpheusactorproperties-owneronly" id="morpheusactorproperties-owneronly"></a>

You can mark a `UMorpheusActorComponent` with the `AuthorityOnly` meta tag, which means this component will be **only** available at the authoritative client. Other non-authoritative clients will just destroy this **AuthorityOnly** component.\
\
However, this won't prevent the component properties from being replicated to the non-authoritative clients by default and hence you would need to also add `OwnerOnly` tag to the server-authoritative properties of that component to save networking replication costs.

#### Update Fast in Midground

You can mark a background property as **Update Fast in Midground**. This is a performance trade-off. Normally, a background property will be updated at 2Hz, regardless of whether the property's owning actor is in background, midground or foreground. If you enable this feature, then when the property's actor is in midground or foreground, the client will receive updates at 10Hz (the same rate as for a midground or foreground property).

In other words, you get the best of both worlds: the property is available for every actor in the scene, yet is highly responsive for higher-priority actors. The downside is increased server load: it's equivalent to adding another midground property to your actor.

#### **Value on Relevancy Lost**

A replicated property can lose relevancy when its owner MorpheusActor moves to a lower Network Relevancy Level.\
E.g. A MorpheusActor moves from Foreground to Midground while it has a replicated property that's defined with a `Foreground` Network Relevancy Level will cause that property to become irrelevant.\
\
When this happens, you can specify which value this property will take. The available options are:

1. `Last Value Received` (Default): When actor's relevancy level drops below this property's level and the property stops receiving updates, leave its value unchanged.
2. `Default Value`: When actor's relevancy level drops below this property's level and the property stops receiving updates, reset it to its default value.

#### RepNotify Condition

In Morpheus, you can control when should the `OnRep` of a property be fired. The available options are:

1. `OnChanged` (Default) : Call the OnRep function whenever the property changes regardless of relevancy.
   * Default option and that's how native Unreal `OnReps` are fired.
2. `OnChangedWhileRelevant`: Call the OnRep function when the property changes, but only while the property is relevant. Network Relevancy changes will not trigger the OnRep function.
   * A use case for this new option is when you only want the `OnRep` to only be triggered for live updates to your property. Initial values and value changes that occured while the property wasn't relevant will not trigger the `OnRep`.
3. `Always`: Call the OnRep function whenever the value is received from the network or updated on relevancy lost. Reagardless of whether the value has changed. (Only available in Foreground)
   * A use case for this is if the property represents an action that the actor has done and you want to call the `OnRep` each time that action has been performed regardless if it's the same action.

{% hint style="info" %}
`OnReps` would also be triggered as a result of the `Default Value` option in `Value on Relevancy Lost` depending on the `RepNotify Condition`
{% endhint %}

### Supported types <a href="#morpheusactorproperties-propertymeta" id="morpheusactorproperties-propertymeta"></a>

#### Foreground

Foreground properties can use the same types as standard Unreal networking, with one exception. Object references must be references to:

* Morpheus actors
* Morpheus actor components
* [Stably named objects](https://dev.epicgames.com/documentation/en-us/unreal-engine/replicate-actor-properties-in-unreal-engine#stablynamedobjects)

#### Midground and background

Midground and background properties are more limited. They can only use the following types:

* Bools
* Integers
* References to Morpheus actors and Morpheus actor components
* Structs comprising any of the above
  * They can be nested
* Floats & doubles

Floats and doubles are a special case: Morpheus compresses them lossily on replication. You need to specify your required level of precision in the property's Details panel. (For instance, a property with a `Precision When Replicated` of 0.01 will only replicate to an accuracy of two decimal places.) This requirement means that non-foreground structs can't contain floats or doubles.

{% hint style="info" %}
Morpheus compression works best when your properties' deltas are between 0 - 255 hence it's **recommended** to quantize your values such they occupy that range if possible **specially** if these properties are expected to change frequently and you don't care about precision.
{% endhint %}

### How to define properties

Properties are marked for replication through the Details panel in the Blueprint Editor. This is also how you turn on all of the above features.

By default, properties aren't replicated. Mark them for replication using the `Replication` dropdown. The default replicated property is **foreground** and **server authoritative**.

<figure><img src="/files/evDEBmfGb5QAqkuOB5MB" alt=""><figcaption></figcaption></figure>

Note that:

* Morpheus replication settings are only available within classes based on `AMorpheusActor` and `AMorpheusActorComponent`.
* If the `Network Level` option only shows `Foreground`, the property you are attempting to replicate is only compatible with the Foreground network level (see [Supported types](#morpheusactorproperties-propertymeta) above).
* Create a `RepNotify` function for a property by setting the `Replication` drop-down to `RepNotify`.


# RPCs

In Morpheus, Remote Procedure Calls (RPCs) are defined the same way as in vanilla Unreal, but have some important differences in behaviour.

As with all Morpheus networking, Morpheus RPCs are restricted to classes that inherit from `AMorpheusActor` or `UMorpheusActorComponent`. RPCs on other classes won't work.

### Arguments

RPCs can take any number of arguments.

RPC arguments can use the same types as standard Unreal networking, with one exception. Object references must be references to:

* Morpheus actors
* Morpheus actor components
* [Stably named objects](https://dev.epicgames.com/documentation/en-us/unreal-engine/replicate-actor-properties-in-unreal-engine#stablynamedobjects)

### Server RPCs <a href="#morpheusrpcs-serverrpcs" id="morpheusrpcs-serverrpcs"></a>

In Morpheus, **any client can invoke any** `Server` **RPC on any** `AMorpheusActor`. The RPC is executed on the server. The server can also invoke a `Server` RPC itself, in which case it will be executed locally.

#### Helper functions

There are four special `AMorpheusActor` functions you can call from within the handler for a `Server` RPC:

1. `AuthoritativeClientCalledServerRpc` checks whether the RPC was invoked by the client which has authority over the actor. (You can use this to emulate the standard Unreal semantics, where only the authoritative client can call a `Server` RPC.)
2. `ServerCalledRpc` checks whether the RPC was invoked locally, i.e. by the server.
3. `ServerRPCCallerOwnsActor` accepts an `AMorpheusActor`. It checks whether the RPC was invoked by the connection which has authority over the given actor. This is useful for Singleton type actors that need an auth actor passed in to do their work.
4. `ServerGetRpcCallerConnection` returns the `AMorpheusConnection`which invoked the RPC - either a client or the server. (This becomes complicated when working with bots - see [here](/creation/unreal-development/features-and-tutorials/bots#calling-server-rpcs).)

There are also corresponding functions with the same names on `UMorpheusActorComponent`. Please note that if an RPC is called on the component, you should check these functions on the component directly, not the owning actor.

### Client RPCs <a href="#morpheusrpcs-clientrpcs" id="morpheusrpcs-clientrpcs"></a>

In Morpheus, **the server or any client can invoke any** `Client` **RPC on any** `AMorpheusActor`. The RPC is executed only on the **authoritative** client.

From within the handler of a `Client` RPC, you can use the `AMorpheusActor` function `ServerCalledRpc` to determine whether the RPC was invoked by the server. (You can use this to emulate the standard Unreal semantics, where only the server can call a `Client` RPC.)

### NetMulticast RPCs <a href="#morpheusrpcs-netmulticastrpcs" id="morpheusrpcs-netmulticastrpcs"></a>

In Morpheus, both server and client can call `NetMulticast` RPCs. A `NetMulticast` RPC will be executed locally when called and then, if invoked from...

* the authoritative server: it will also be executed on all clients with this `AMorpheusActor` in the foreground network level.
* the authoritative client: it will also be executed on the server *and* all clients with this `AMorpheusActor` in the foreground network level.
* a non-authoritative client: it won't be executed anywhere else.

From within the handler of a `NetMulticast` RPC, you can use the `AMorpheusActor` function `ServerCalledRpc` to determine if the server invoked the RPC. This can be used on the client to determine that the RPC was called by the server as opposed to another client, or on the server to handle the local execution of the RPC. Use the `AMorpheusActor` function `IsOnClient` to handle these cases separately.

### RPC Guarantees <a href="#morpheusrpcs-rpcguarantees" id="morpheusrpcs-rpcguarantees"></a>

*The Morpheus system has semantics and behaviour that may not be immediately obvious. This is a non-exhaustive list of semantics we offer for external developers to use as a reference, and for internal developers to refer to when making changes.*

Morpheus offers some ordering guarantees in order to try and match some Unreal semantics. See [this doc](https://github.com/improbable/morpheus-core/blob/master/morpheus/docs/guarantees.md) in the `morpheus-core` repository for more information on what these are and how we offer them. Because this repository is available to Improbable developers only, a subset of the doc relevant to Unreal development is exposed here:

#### Salient Ordered Channels <a href="#morpheusrpcs-salientorderedchannels" id="morpheusrpcs-salientorderedchannels"></a>

**Multicast RPCs from clients** and **Client Authoritative Entity Data** offers ordering when sent from the same client.

**Server to Client RPCs** and **Authoritative Client Entity Deletions** offers ordering as both will be sent from the server.

**Multicast RPCs from servers**, **Server Authoritative Entity Data** and **Server Authoritative Owner Only Entity Data** offers ordering as all will be sent from the server.

In other words, in Morpheus, RPCs of the same type on the same actor are **guaranteed** to be executed in the same order they were called. For example:

1. The server invokes two RPCs on `MorpheusActor_A`: first `NetMulticastRPC_1`, then `NetMulticastRPC_2`.
2. The client executes `NetMulticastRPC_1` first, then executes `NetMulticastRPC_2`.

#### Non-Ordered Channels <a href="#morpheusrpcs-non-orderedchannels" id="morpheusrpcs-non-orderedchannels"></a>

An example of a pair of channels that you might think would be ordered but are not is **Server Authoritative Entity Data** and **Authoritative Client Entity Deletions**.

In Morpheus, different types of RPCs are **NOT guaranteed** to be executed in the same order. For example:

1. The server invokes two RPCs on `MorpheusActor_A`: first `ClientRPC_1`, then `NetMulticastRPC_1`.
2. The client will **NOT** necessarily execute `ClientRPC_1` first.

#### Reliability <a href="#morpheusrpcs-reliability" id="morpheusrpcs-reliability"></a>

Morpheus RPCs are always **reliable** even if you marked them as **unreliable**.

As long as your client is **connected**, it will receive all RPCs sent to it.


# Morpheus Render Targets

### What is a Render Target?

In Morpheus, every client sees every `AMorpheusActor` in the world, no matter how far away that `AMorpheusActor` is. If your game has 10000 players, each client will have 10000 player `AMorpheusActor`s in their scene.

This means that, for high-scale types of `AMorpheusActor`, you cannot have very expensive components on that `AMorpheusActor`. For example, 10000 skeletal mesh components, or 10000 character movement components, would significantly slow down the client and server.

Morpheus has a feature called **render targets** which addresses this. A render target is a way of rendering an `AMorpheusActor`, which can change dynamically.

### Available Render Targets

Currently, a render target can be either:

* Nothing.
* A non-`AMorpheusActor` actor of a given class.
* A member of an animated crowd.

An `AMorpheusActor` can have only one render target active at any given point, and you can configure automatic handling of which render target to apply, when.

By default, an `AMorpheusActor` will never load any render targets.

### Setting up Render Targets

In your `AMorpheusActor` derived Blueprint, you will find the `MorpheusRenderTargetComponent`

<figure><img src="/files/nruZYRsGkHsjQt9MmITC" alt=""><figcaption><p>MorpheusRenderTargetComponent in a MorpheusActor Blueprint</p></figcaption></figure>

In the details panel of the component you can control its render targets:\\

#### **Server Render Target**

This is the render target always applied on the server. Although the server doesn't render anything, it can sometimes be convenient to have a server-side actor associated with an `AMorpheusActor`.

#### Authoritative Client Render Target

This is the render target which is always applied on the client which has authority over this `AMorpheusActor`.

*Actors with authoritative render targets will not have their LOD switched and calculated.*

#### LOD Group Id

In order for an actor to be rendered, it must be assigned to a `FMorpheusLODGroup`

By default, we have the `PlayerClient` LOD group ID but you can add as many as you want from the project settings when clicking `Create LOD Group`

<figure><img src="/files/7qjsgLG7CiTLw5vax2rv" alt=""><figcaption></figcaption></figure>

If the LOD group ID is not assigned we fallback to the `DefaultLODGroup` in the following setting.

#### Default LOD Group

Each LOD Group has a list of `FMorpheusLODGroupLevel` and `FMorpheusLODGroupBucket`.

* A LOD Group Level defines the `NumEntities` that can be rendered in that level.
* A LOD Group Bucket is used to prioritize some actors over others within the same LOD Group. It defines a `MaxDistance` within which the actors belonging to that bucket will be prioritized.

Each non-authoritative client will render the closest `NumEntities` entities (within the same `FMorpheusLODGroup`) starting from LOD 0.

For example, an actor with the following three LOD levels:

* 0: Actor render target with actor class `ACharacter`.
* 1: Animated crowd render target with high quality vertex animated meshes.
* 2: None

and belonging to the LOD Group `CharacterLODGroup` defined with:

* LOD Level 0: (NumEntities=`30`)
* LOD Level 1: (NumEntities=`500`)

Will render the closest 30 entities as the `ACharacter` class, the next 500 closest entities as Animated Crowd memers, the remaining actors as imposters, and have no render targets.

The render targets will be automatically swapped when the `AMorpheusActor`s move closer or further away.

#### LOD Group Buckets

A LOD Group can define buckets, and actors can register to the buckets to be prioritized. This can be done from the `MorpheusRenderTargetComponent`\\

For example, using the previously described LOD Group `CharacterLODGroup` , let's say it also defines these buckets:

* Bucket 0: (Name=`HighPriority`, MaxDistance=`10000`)
* Bucket 1: (Name=`LowPriority`, MaxDistance=`5000`)

Notice that buckets at lower indices will always have higher priority than buckets at higher indices.

`UMorpheusRenderTargetManager` will prioritize the actors belonging to bucket `HighPriority` (if their distance from the camera is below 10000) over the actors in the `LowPriority` group:

* Actor 0: Belonging to `HighPriority` bucket and with Distance=7000
* Actor 1: Belonging to `LowPriority` bucket and with Distance=1000
* Actor 2: Doesn't have a bucket assigned (i.e `None` ) and with Distance=400

In the above situation, the actors will occupy the available slots (`NumEntities`) in the `CharacterLodGroup` in the same order they were listed respecting the bucketing order.\
\
So actors belonging to the `HighPriority` bucket will get assigned first followed by `LowPriority` bucket then the unassigned bucket actors.

### Setting the Render Targets during runtime

If you want to update your Render Target setup during runtime, there are some blueprint functions that can be used to achieve this:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/cf149ed5-29a5-4526-baa3-91bab1ddf6ef>" %}

These options should be used sparingly as they may cause multiple render target reloads depending on the new `NumEntities` capacity - for example, when calling `SetClientLODLevels` it will attempt to reload the render target to a sensible default option based on the previous LOD level index.

{% hint style="info" %}
In release v40 onwards, we have some additional helpers, which we recommend using instead of setting the Client LOD levels directly:

<img src="/files/f3IaSzc8a6Yp6ukw9Ft1" alt="" data-size="original">
{% endhint %}

### Checking which Render Target is currently in use

In order to identify which render target is currently in use you can use the following nodes in Blueprints:\\

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/0ceab40d-16bb-46c2-8030-046755ba8426>" %}

If an `AMorpheusActor` currently has an actor render target enabled, `MorpheusActorRenderTargetComponent->CurrentActor` is set to the actor. `MorpheusActorRenderTargetComponent->CurrentActor` is `nullptr` otherwise.

If an `AMorpheusActor` currently has an animated crowd render target enabled, `MorpheusActorRenderTargetComponent->CurrentAnimatedCrowd` is set to the animated crowd actor. `MorpheusActorRenderTargetComponent->CurrentAnimatedCrowd` is `nullptr` otherwise.

`MorpheusActorRenderTargetComponent->GetClientLODIndex()` can be used to determine which client LOD level index is currently active, if any.

### Render Target State

The `MorpheusActorRenderTargetComponent` has a generic state that is stored locally (NOT replicated). This state will be known as the `Render Target State` and can be used to maintain the rendering state of the `MorpheusActor`

The `Render Target State` is of a type called `FMorpheusPackedStruct` which is a special type that can store any type of a struct.

Before using the `Render Target State` you will need to create or specify the struct that will represent your rendering state.

Here is a BP example that shows it in action:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/5bdded46-ddd3-4b42-b287-227004050983>" %}

You can also respond to updates that occur to your `Render Target State` via the delegate `OnRenderTargetStateUpdated` which will fire as a result of any of these triggers:

* An update to the `Render Target State`
  * i.e. a call to `SetPackedRenderTargetState` .
* A render target transition
  * e.g. Actor to Animated Crowd or vise versa.
* A render target is first loaded
  * e.g. as a result of a newly spawned `MorpheusActor`.

Here is an example of how to use this event in Blueprints:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/14541d54-686a-48a5-bd64-1ca00fa77d0c>" %}

{% hint style="info" %}
It's recommended to use the delegate `OnRenderTargetStateUpdated` delegate for updating your render target compared to the `Additional Render Target Events` below as it's more inclusive.
{% endhint %}

### Additional Render Target Events

The `MorpheusActor` provides some events to listen for when its render target is updated.

* `OnRenderTargetUpdated` : This is triggered when the render target is updated (e.g. switching from Actor to AnimatedCrowd)
* `OnRenderTargetSpawnedEvent` : Triggered when the Render Target has been switched to an Actor that has just finished spawning.


# Morpheus Array

{% hint style="warning" %}
This feature is currently in Beta.
{% endhint %}

### Introduction <a href="#howto-morpheusarray-introduction" id="howto-morpheusarray-introduction"></a>

This document covers when and how to use a `UMorpheusArray` in Blueprints and the current limitations it has.

### Morpheus Array <a href="#howto-morpheusarray-morpheusarray" id="howto-morpheusarray-morpheusarray"></a>

A `MorpheusArray` is a generic replicated container that can be used to efficiently **replicate** array updates.

`MorpheusArray` is only replicated in **Foreground** and supports **any type that a replicated TArray supports**.

### When to use a Morpheus Array vs normal Arrays? <a href="#howto-morpheusarray-morpheusarrayvstarray" id="howto-morpheusarray-morpheusarrayvstarray"></a>

A `Morpheus Array` is preferred to be used when:

* You expect your array to contain 1000s of elements with frequent changes.
* You need to know when a specific index has been updated in the array.

An example use case can be when you want to keep track of some data for each actor in the game and that data can change during runtime. (e.g Player scores)

### Garbage Collection

Similar to Unreal's `TArray` , any `UObject` reference stored inside the `MorpheusArray` will **NOT** be garbage collected.

These `UObject` references will be collected from each element in the `MorpheusArray`, however deep in the hierarchy (e.g. a struct containing a struct containing a UObject).

This is to guarantee `UObject` liveness as long as it remains inside the `MorpheusArray`

### Using a Morpheus Array in Blueprints <a href="#howto-morpheusarray-definingumorpheusarray" id="howto-morpheusarray-definingumorpheusarray"></a>

In order to start using a `Morpheus Array` in Blueprints you do the following:

* Open your Blueprint that derives from either a `MorpheusActor` or a `MorpheusActorComponent`
* Add a variable to your Blueprint and give it the type `Morpheus Array`

<div align="center" data-full-width="false"><figure><img src="/files/XjWzxwMtKcbGLcMbTJ6w" alt="" width="375"><figcaption></figcaption></figure></div>

* In the variable Details Panel on the right, select the `Morpheus Array Inner Type` to be the desired type that the `Morpheus Array` will hold.

<div data-full-width="false"><figure><img src="/files/ChUekf2kHjuGh1F5fipn" alt="" width="375"><figcaption></figcaption></figure></div>

* Don't forget to set the `Morpheus Array` variable to be `Replicated`
* Now drag and drop the variable into the BP graph to start using your `Morpheus Array` using the `Morpheus Array` specific nodes shown under the `Morpheus Array` category.

<figure><img src="/files/MoOWk4ZWYDPB5sRQPyP8" alt="" width="375"><figcaption></figcaption></figure>

### Example Blueprint Usages <a href="#howto-morpheusarray-onrepumorpheusarray" id="howto-morpheusarray-onrepumorpheusarray"></a>

<figure><img src="/files/6Rbm3htxZd1zfm2L4Rzz" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/J4uu1pjlXnf3okl3394K" alt=""><figcaption></figcaption></figure>

Since `UMorpheusArray` is a replicated type it also supports rep notifies and they do fire even if a single element was updated.

But additionally `UMorpheusArray` has a couple of helper functions that you can use in the OnRep to know the exact replication changes that we received.

* `UMorpheusArray::OnRepUpdatedIndices()` which returns an array of the indices that have been updated by the last replication event.
* `UMorpheusArray::OnRepDeletedIndices()` which returns an array of the indices that have been deleted by the last replication event.

With these functions, users can be aware of the changes that happened to the array, rather than having to figure out any changes manually

Example usage:

<figure><img src="/files/Z1f02HMxBrj0YG6h5pAS" alt=""><figcaption></figcaption></figure>

### On About to Apply Update Delegate <a href="#howto-morpheusarray-limitations" id="howto-morpheusarray-limitations"></a>

Morpheus Arrays has a delegate `OnAboutToApplyUpdate` that is fired before the `OnRep` . This delegate can be used to react to incoming element updates/deletions before they are applied to the `Morpheus Array` itself and losing the old values.\
\
See example below:

{% @blueprintue-embed/embed url="<https://nextjs-boilerplate-jl63.vercel.app/ca081f39-81e6-4d44-b022-22f8956dfb1b>" %}

Notice that the delegate gets called with `Keys` instead of `Indices` so you will need to use `GetIndexFromKey` to retrieve the about to be updated/deleted index in the Morpheus Array.

There is also another helper function `GetKeyOfIndex` that retrieves the Key of a given index.

#### Keys vs Indices

A `Key` in a Morpheus Array is a unique identifier for a Morpheus Array element.

Since elements in the Morpheus Array can get added or removed the `Index` becomes insufficient to represent the element as it could now be pointing to a different element.

Every `Key` is mapped to an `Index` in the array and whenever an `Index` is removed, its `Key` will also get removed but the remaining keys will still point to the same elements despite having their indices changed.

An update to an element doesn't affect the `Key` nor the `Index` of that element.

### Limitations <a href="#howto-morpheusarray-limitations" id="howto-morpheusarray-limitations"></a>

1. `AMorpheusActors` that own a `UMorpheusArray` and aren’t in **Foreground** will still need to checkout the whole array once they enter **Foreground**. In which case, a `UMorpheusArray` will **not** be replicated efficiently.
2. Using the `Get` node and the `ToArray` nodes in Blueprints will currently return **copies** of the values inside the `UMorpheusArray` so bear in that in mind if performance is a concern.
3. Debugging a `UMorpheusArray` may not be trivial as the data is stored internally as a raw byte buffer so you might need to write extra code to view the contents of the `UMorpheusArray` while debugging it.


# Networking FAQ

### How should I avoid overloading the Unreal server? <a href="#networkingfaq-howdoesservercomputationworkatscalewithasingleunrealserver" id="networkingfaq-howdoesservercomputationworkatscalewithasingleunrealserver"></a>

Although the server does have authority over all `AMorpheusActor`s in the game, you are able to mark a replicated property as client authoritative. This means that the client which owns that `AMorpheusActor` can write *directly* to that property, and that value will be sent to other clients without needing to go via the server. Clients are also able to send RPCs directly to each other, meaning a lot of communication never needs to go via the server.

This ability to have client authority allows you to run *cloud hosted*, trusted clients which can log in and directly simulate certain 'server' computation. For example, you can log in a client which can simulate 100 AI, or 50 destructible buildings. This client can directly write to the AI or building properties, and talk to player clients directly using client RPCs, never needing to go via the server.

This allows you to put the heavy server side computation on cloud hosted 'clients', and reserve the server's capacity for higher level logic or transactions across multiple `AMorpheusActor`s.

### Will this work out of the box with Unreal system X <a href="#networkingfaq-willthisworkoutoftheboxwithunrealsystemx" id="networkingfaq-willthisworkoutoftheboxwithunrealsystemx"></a>

Not directly. Morpheus only replicates `AMorpheusActor`s and `AMorpheusActorComponent`s and classes inheriting from them, so a project will always require some work to inherit from these classes.

Morpheus does, however, provide out of the box tools to make it easier to integrate with some Unreal systems. For example, Morpheus provides the `AMorpheusPawnActor` type which provides simple and scalable replication of `APawn`s and their movement. This class also contains a `UMorpheusCharacterActorComponent` which extends `AMorpheusPawnActor` to work with `ACharacter` classes.

Morpheus also has the 'render target' system which makes it simple to associate an `AMorpheusActor` with any type of actor, and automatically replicate the base movement of any actor type in a scalable fashion.

### My client authoritative property is not working? <a href="#networkingfaq-myclientauthoritativepropertyisnotworking" id="networkingfaq-myclientauthoritativepropertyisnotworking"></a>

Ensure you are spawning your actor on the server with client authority, see [Spawning and Destroying](/creation/unreal-development/getting-started/networking/networking#networking-spawning) section for more info.

### Running integration tests in the editor seems really flaky? <a href="#networkingfaq-runningintegrationtestsintheeditorseemsreallyflaky" id="networkingfaq-runningintegrationtestsintheeditorseemsreallyflaky"></a>

Tests can fail if they time out, and there is a setting that makes the editor run slowly if it's not in focus. Check this setting: Editor --> Editor Preferences --> "Use Less CPU when in Background" --> Set to False


# Replicating Sublevels

## Sublevels

Morpheus Actors in sublevels can be replicated by ensuring that the sublevel is **loaded at both the Server and the Clients**.

If you only loaded the sublevel at the server and forgot to do it at the client (or vice versa) the actors will not be replicated. This can be verified by checking if the `MorpheusBeginPlay` event has been called on those actors.

You would also need to synchronize the state of the sublevels across your server and clients such that late joining clients would be able to restore the sublevel state (whether it's loaded or unloaded). Otherwise, the clients will be desynced on the state of those actors.

This synchronization can be done via a *Replicated Sublevel Manager Singleton Morpheus Actor* for example.

## Level Instancing

Unreal Engine 5 introduced [Level instancing](https://dev.epicgames.com/documentation/en-us/unreal-engine/level-instancing-in-unreal-engine) that we support in Morpheus.

> Use the Level Instancing workflow with one or more Actors to create Level Instances that can be placed down and repeated across your world.

Morpheus supports replication of actors on level instances placed in the level just like the Sublevels we discussed above.

### Runtime Level Instances

As of **v37,** Morpheus supports replication of Morpheus Actors inside Level Instances that are loaded during runtime with some caveats.

{% hint style="info" %}
Native Unreal currently doesn't support replication of runtime level instance actors.
{% endhint %}

When loading a level instance during runtime you need to ensure the following:

1. Both Server and Clients are loading the same instance at the same location, this can be done via a *Replicated Level Instance Manager Singleton Morpheus Actor* for example.
2. Both Server and Clients are using the same `Optional Level Name Override` to load this level instance. This is because Morpheus links actors for replication via their `PathName` and if this is different at the client than the server, the linking would fail and actors will be detached.

{% hint style="info" %}
NOTE: The `Optional Level Name Override` must not be empty, and must be a unique name (i.e. there should not be any other levels loaded with the same as this new level instance). The former would mean that the actors will not be replicated, and the latter results in the level failing to load.
{% endhint %}

3. This can be done via the Unreal function `Load Level Instance By Soft Object Ptr`&#x20;


# Creating a New Map

{% hint style="success" %}
verified: 2025-11-18 version: v39
{% endhint %}

Like in native Unreal there's many ways you can create a new map. In order for your map to work with our various systems, the quickest way to get up and running is to modify the version of ExampleMap provided by the [Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project) or to duplicate our minimalist template map. The steps below cover the template map approach:

1. Create Your Map
   1. Open `NewMapTemplate`
   2. File > Save Current Level As and rename it to make it your own
2. Make Your Map Available for Upload
   1. Open Edit > Project Settings > Morpheus Platform> M2 World Builder
   2. Open section Upload > Maps
   3. Either replace Example Map or add an additional Map to the array
      1. All maps listed in this array will be uploaded and available in your mod if "Include Map in Upload" is checked. See [Upload Content](/creation/unreal-development/getting-started/uploading-content) for more info

<figure><img src="/files/EeVFMib93jVErWHwJCTr" alt=""><figcaption><p>This section in Project Settings dictates what maps are visible in the web UI for any given version of a mod.</p></figcaption></figure>

{% hint style="danger" %}
Map names, including the path, must be no more than 63 characters. If they are longer then you'll get an error when launching a deployment.
{% endhint %}


# Creating a new character

This page outlines the steps involved in setting up your character in a way that is compatible with the Morpheus Platform. Note that there are some steps here that are different to native Unreal, so it is worth even experienced Unreal users looking through this page.

## Setting up your Morpheus Actor

The `Morpheus Actor` is the class that will be responsible for networking your character. For more details on this, see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking).

If you are using the [Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project), `BPM_Example_PlayerCharacter` has been made for you.

{% hint style="info" %}
We require that the Morpheus actor for your main character extends from `M2M_CharacterBase` at the minimum. This is a child of `MorpheusPawnActor` (a specialized form of `MorpheusActor`), that includes implementation of some of our core functionality, such as [Crowd Animation](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation), and [Avatars](/creation/unreal-development/features-and-tutorials/avatars). For other Morpheus actors in-game, you can go directly from `MorpheusActor` or below.

<img src="/files/9icxs2woPgJsQORG5lR9" alt="" data-size="original">
{% endhint %}

Your Morpheus Actor is responsible for spawning its "render target" (the avatar model) and tracking any replicated state. For how these are done, see the following steps:

* [#configuring-your-render-target](#configuring-your-render-target "mention")
* [#updating-your-character-avatar](#updating-your-character-avatar "mention")

## Configuring your Render Target

### What is a Render Target?

Your render target is the "physical representation" of your character. We have different "render targets", at different rendering "LOD Levels". For most casts, LOD 0 is the `Actor` that is used when the player is nearby, and LOD 1 is the "crowd" (see [Crowd Rendering](/creation/unreal-development/features-and-tutorials/the-animated-crowd)) used for distant actors.

More details on these "Render Targets" in [Morpheus Render Targets](/creation/unreal-development/getting-started/networking/morpheus-render-targets)

<figure><img src="/files/GEx4ACRm3o6pQltm4m9F" alt=""><figcaption><p>A demonstration of the difference between render targets. In this example, there are 3 characters in the world (so 3 <code>BPM_M2Example_PlayerCharacter</code>s), but only 2 render target actors (<code>BP_M2Example_PlayerCharacter</code>). This because we have set the "NumInLOD0" to 1, meaning that other than yourself, only one other character will be a render target actor, and any past that point will be represented in the crowd.</p></figcaption></figure>

### The Pawn Class

Like in traditional Unreal projects, we use the `Pawn` class to represent most players. As mentioned above, the main difference is that for remote characters, we switch between these Render Target Actors, and a "crowd" representation.

We use the pawn class for handling game logic that requires a physical in-game body, e.g. collision or moving the actor through the game world (any networked state needs to be sent through the Morpheus Actor).

If you are using the [Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project), `BP_Example_PlayerCharacter` has been made for you.

{% hint style="info" %}
We require your main character to extend from `M2_CharacterBase` at the minimum (a child of `Character`). This is to handle some of our core functionality, such as [Actor Pooling](/creation/unreal-development/features-and-tutorials/actor-pooling)and handling custom avatars' [Capsules and Mesh Transforms](/creation/unreal-development/features-and-tutorials/avatars/capsules). If you are using making other Morpheus Actor render targets, you can go directly from `Actor` or below.
{% endhint %}

{% hint style="warning" %}
**Some important things to note regarding using pawns on the Morpheus Platform**

* We do not advise modifying your `SkeletalMeshAsset` to set your character's visuals. Instead, we use an interoperable avatar system (See [Avatars](/creation/unreal-development/features-and-tutorials/avatars)). To configure your character's model, see [#updating-your-character-avatar](#updating-your-character-avatar "mention")
* The `Anim Class` can be modified, but has some caveats:
  * Animations require some specialized techniques to be compliant with the Animated Crowd. See [Crowd Animation](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation)
  * Our custom avatar setup requires a specific skeleton to be used (`SKEL_UE5Mannequin`), so this should not be changed if you want to be compatible with our custom avatars.
  * For these reasons, if you do want to change your animations, we recommend duplicating `ABP_M2_Human`, and using it as a starting point.
    {% endhint %}

<figure><img src="/files/eIwG6f97WMXGlamIuoA9" alt=""><figcaption></figcaption></figure>

#### Supporting montages

If you want to play montages on the animated crowd, you need to inform the crowd what montages it needs to know about ahead of time, along with the `Anim Class`. To do this, we have a `CrowdAnimationProviderInterface` on our pawn classes, which provides a `GetAnimNameToSequenceMap` function. This is called to inform the crowd of any animations the crowd needs to know about.

If you want to add montages, you can extend/implement this function.

For more details, see [Crowd Animation](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation)

### How to define your Render Targets

{% hint style="info" %}
NOTE: The following section applies to release v40 onwards. Prior to that, you will need to configure your render targets via a pawn set. For more details, see [Configuring your pawn set](/creation/unreal-development/getting-started/creating-your-own-character/configuring-your-pawn-set)
{% endhint %}

In your Morpheus Actor, the `MorpheusRenderTargetSettings` are exposed to your `Details` panel:

* If `UseDefaultPawnAsRenderTargetActor` is true, the Morpheus Actor will use the `DefaultPawnClass` in your `GameMode` as the LOD0 actor class
  * If it is false, the `RenderTargetActorClass` will be used. If this is `None`, no render target class will be used.
* If `CrowdEnabled` is true, a crowd will be used for LOD1
  * If `RaycastableCrowdEnabled` is true, then the crowd will support raycasting. For details, see [Raycastable Crowd](/creation/unreal-development/features-and-tutorials/enabling-raytracing-for-crowd-members)

<figure><img src="/files/AE3fjnLtHgsQu7oXx6fI" alt=""><figcaption></figcaption></figure>

#### Advanced render target settings

* `CrowdDetails` - this is the details object provided to define how the LOD1 crowd looks:
  * `CrowdData` - this can be left null, but if you want to override any of the default values, you can create your own asset, and provide it here.

    * `Skeleton`: If one is provided, it will change the skeleton used by the crowd. If left null, it will use the one from your LOD0 actor
    * `CrowdAnimInstance`: If one is provided, it will change the `Anim Instance Class` used by the crowd to animate the character. If left null, it will use the one from your LOD0 actor. It doesn't have to match, but generally makes the most sense to match, to ensure animations are consistent.
    * `AnimNameToSequence`: This is a mapping of animation montages that can run on the animated crowd. They can be triggered via e.g. `JM_MontageComponent::PlayMontageByName(MontageName)`. If you want to add montages that you expect to play on the crowd, they will need to be added either here, or on the pawn itself (in their `GetAnimaNameToSequenceMap`). For more details, see [Crowd Animation](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation)
    * `NumCustomDataFloats`/`NumCustomDataFloatsPerMesh`: Intended only for specialist use. We advise leaving these unchanged.

    <figure><img src="/files/lVbCdWcIAI2htM4Aglpa" alt=""><figcaption></figcaption></figure>
  * `IsmActorType` - we generally don't advise overriding this. By default (if left as `None`) it uses the `DefaultInstancedMeshActorClass` in `Project Settings -> Morpheus Platform -> Animated Crowd Settings`.
  * `RaycastableCrowdClass` - If left `None`, it will use the `DefaultRaycastableCrowdClass` in the above project settings, if `RaycastableCrowdEnabled` is true. If you want to use a custom raycastable crowd class, you can set it here. For more details, see [Raycastable Crowd](/creation/unreal-development/features-and-tutorials/enabling-raytracing-for-crowd-members)
* `ServerRenderTarget` - you can specify a render target to use on the server. Typically this can be left as "No Target", to improve performance on the server, since it doesn't need to deal with actors/crowd members.
* `UseDistinctRenderTargetActorClassForNonAuthClient` - if true, then the non-auth client at LOD0 will use a different render target actor to the auth client (`NonAuthClientRenderTargetActorClass`)
* `LODGroupId` can be set if you want your actor to be in a different group (e.g. rendered in priority over other actors in its group, or handled in a separate group to others). For more details, see [Morpheus Render Targets](/creation/unreal-development/getting-started/networking/morpheus-render-targets)
  * If you don't specify a `LODGroupId`, it will default to the `DefaultLODGroupId` defined in `Project Settings -> Morpheus Platform -> Morpheus LODs`
  * If you specify a `DefaultLODGroup`, it will instead use that, as a custom LOD group, instead of joining the existing group with that Id.

<figure><img src="/files/RIv9oP44lMM6SLfMptsu" alt=""><figcaption></figcaption></figure>

## The Player Controller

Player Controllers work basically the same in the Morpheus Platform as they do in native Unreal, on the local client. When your authoritative Render Target Actor is spawned, it will be possessed by your Player Controller.

In the [Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project), `BP_Example_PlayerController` has been made for you.

## Setting up your Game Mode

### What's in the Game Mode?

The game mode allows use to configure some default classes for your project or map. Important ones to consider here:

* `PlayerMorpheusActorClass`: sets the Morpheus Actor that will be used for your character in the level. If you made your own class in [#setting-up-your-morpheus-actor](#setting-up-your-morpheus-actor "mention"), you will need to make sure it is defined in your active game mode for it to be used.
* `DefaultPawnClass`: sets the pawn class used for player characters. If your Morpheus Actor is configured to `UseDefaultPawnAsRenderTargetActor`, this is what it will use.

{% hint style="info" %}
Remember: If you are on an earlier release than v40, your `DefaultPawnClass` will not be used until you call `ApplyPawnSet`. Your `PlayerMorpheusActorClass` will be created, but it will not have an associated Render Target Actor.
{% endhint %}

<figure><img src="/files/8LfX1j5HeixMPkyfMv6q" alt=""><figcaption></figcaption></figure>

### How do I set my Game Mode?

The Game Mode used by your project can be configured either by:

* Setting the default game mode via the project settings:

  <figure><img src="/files/vhckaThwtwQ7UoeiiXwB" alt=""><figcaption></figcaption></figure>
* Overriding the game mode for your specific map, in your `World Settings`:

  <figure><img src="/files/uaXrbX5HhXMCB09CaLd4" alt=""><figcaption><p>An example of overriding the default game mode: here to <code>BP_CombatExample_GameMode</code></p></figcaption></figure>

In the [Morpheus Base Project](/creation/unreal-development/getting-started/using-the-template-project), `BP_Example_GameMode` is set as our default game mode, and no override is added to the `ExampleMap` level, meaning that the default will be what is used. It has already been configured to use the `_Example_` classes outlined in the steps above.

## Updating your character avatar

Instead of using regular meshes directly from Unreal, we use an interoperable avatar system, where character models are downloaded via URLs. (See [Avatars](/creation/unreal-development/features-and-tutorials/avatars)). The following is some guidance on how that flow works

### Creating an MML Avatar

We have documentation that outlines the process to go from a 3D model to an MML avatar that can be used in-game, and across Morpheus Platform experiences: [Creating an Avatar](/creation/unreal-development/features-and-tutorials/avatars/creating-mml-avatars-with-blender-and-free-rigging-tools)

### Setting your character in-game

Once you have created an MML character URL, or have one you want to use from elsewhere, you can set it via your `CharacterAssetComponent`. For details on how this works, see: [Using an Avatar in-game](/creation/unreal-development/features-and-tutorials/avatars/using-an-avatar-in-game)

The `BPM_M2Example_PlayerCharacter` has some default behavior that sets some MML avatars for you:

* If a player has a character URL already defined in their profile, that will be used.
* If not, they will default to using a fallback avatar from a pool of example avatars.

<figure><img src="/files/0OLzCa1DUAxnJ1tHOMpS" alt=""><figcaption><p>The example logic in <code>BPM_M2Example_PlayerCharacter</code> waits for your profile to be loaded. Once it is loaded, it obtains the profile's <code>Url</code> field, and loads it. The example also includes some fallback behavior, to load some fallback avatars if there is no avatar tied to their profile.</p></figcaption></figure>

* This pool of example avatars is defined via live config (`DefaultAvatar.FormatAvatarUrl`), with the default of `https://casual-filtered-v1.msquaredavatars.com/{0}.mml` - it will select a random URL replacing `{0}` with a number between `DefaultAvatar.MinEntry` and `DefaultAvatar.MaxEntry`.
  * These are some of our publicly available "default avatars" - see [Avatars](/creation/unreal-development/features-and-tutorials/avatars#some-default-characters)

    <figure><img src="/files/9eED2V4exgcIZIZf52Kg" alt=""><figcaption></figcaption></figure>


# Upload Content

Upload your Unreal levels from the editor

## Uploading the Example Map <a href="#uploadingcontent-uploadingbyplugin" id="uploadingcontent-uploadingbyplugin"></a>

After [Downloading the editor](/creation/unreal-development/getting-started/downloading-the-tooling) and creating a project, you can test the upload flow by uploading the example maps.

Click the **Upload Content** button in the toolbar.

<figure><img src="/files/AYPLlPN86IxGSG5EjCg2" alt=""><figcaption><p>Upload Content button</p></figcaption></figure>

This button will open the upload window as shown below:

Here you can configure:

* An optional upload description, which is displayed in the dashboard.
* The levels you want uploaded. Selecting fewer levels will take less time.

Once you're done, click the **Upload** button.

For your first upload, this will open a browser for authentication - make sure to use the account you used to login to the website.

![](/files/OUjpwbCPWiexJEKRYB2i)

After login the upload will begin, with progress tracked in the top-right of the modal.

<figure><img src="/files/ZDMqTfH9KKxN7a7xUhHC" alt=""><figcaption><p>The upload window for an in-progress upload.</p></figcaption></figure>

Once the upload completes, click the **View upload in dashboard** button:

<figure><img src="/files/jZfcZegC9h2KPoXp3Rfz" alt=""><figcaption><p>The upload window for a complete upload.</p></figcaption></figure>

This button will open the dashboard page for your uploaded content, which we call a Mod.

<figure><img src="/files/ZMYHEzJjlwZjSY1lwGPm" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
A **Mod** is a representation of your cooked Unreal content in our web platform.

When you first upload, we'll automatically create a new mod for you. Your uploaded content represents the first version of your mod. The next time you iterate and upload, that content will be listed as a new version of your existing mod.\
\
\&#xNAN;***Note** - We only store the cooked version of your assets, not the raw versions, so this is not a replacement for source code version control (i.e. you can't download your project from the uploaded assets).*
{% endhint %}

Click the 🚀 **`Launch`** button (below your mod title) to launch a world using your content.

## Troubleshooting <a href="#uploadingcontent-uploadingbyplugin" id="uploadingcontent-uploadingbyplugin"></a>

### Access to the pakchunklayers.txt is denied

This can happen if the `Build\WindowsClient\ChunkLayerInfo\pakchunklayers.txt` file is not marked as writable on your machine which in turn can happen if the `Build/` folder is wrongly checked into Perforce.

To fix this, ensure the relevant marked is **not** marked as read-only.

### **Multiple Plugins**

`LogWorldBuilderEditorUtils: Error: Multiple plugins found to upload.`

This error occurs when you have more than one project plugin *without* `M2Library: true` in the plugin descriptor.

A legacy restriction on the platform is that only one plugin is designated to be cooked and uploaded. This is no longer the case as dependencies are built from the maps selected for upload however the restriction of only one 'primary' plugin existing is still in place.

By default, all libraries created using the above flow will have this tag and *do not need to be modified* however, if you manually copy a new plugin into your project, you are likely to see this error.

To solve this error:

* Open each .uplugin file within `<your-project-dir>/plugins/` in a text editor
* Ensure that all-but-one of your project plugins have the tag `M2Library: true`


# Editor Versions

Our release announcements include:

* Release Notes
* Breaking changes (make sure you check when updating)
* Known issues

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.


# Morpheus Platform Release v40.0

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 18/05/2026

#### Morpheus Pawn Actor no longer auto-destroys old pawn on possess <a href="#morpheus-pawn-actor-no-longer-auto-destroys-old-pawn-on-possess" id="morpheus-pawn-actor-no-longer-auto-destroys-old-pawn-on-possess"></a>

**Date of change:** 06/01/2026

**Affected Projects:** all/ODK

**Affected Features:** Pawn

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

Previously, possessing a new pawn via a `MorpheusPawnActor`, either using `PossessOwnedPawn`, or via the `AutoPossessPlayerOnClientAuthority` variable on the class would default to destroying the previously possessed pawn. This was due to an old setup that depended on this, but this assumption can cause confusion now, with actors being removed without explanation.

As a result of this change:

* `PossessOwnedPawn`'s `DestroyPreviousPawn` field now defaults to false (previously it defaulted to true)
* If `AutoPossessPlayerOnClientAuthority` is set to a value other than `Disabled`, it will still possess the player, but will not remove the old pawn.

**How to fix it?**

If you explicitly wanted to delete the old pawn upon possessing the new pawn, you will need to do the following:

* If calling `PossessOwnedPawn`, you can simply tick the `DestroyPreviousPawn` field
* If you were expecting the pawn to be destroyed automatically via `AutoPossessPlayerOnClientAuthority`, you will now instead need to destroy the pawn manually.

**How to test it?**

Check if your logic has any switching of morpheus pawn actors. If not, no work is required. If you are switching between morpheus pawn actors, review the behavior, and make sure that the posessed pawns are still handled as expected.

#### Minor API changes to MontageComponent <a href="#minor-api-changes-to-montagecomponent" id="minor-api-changes-to-montagecomponent"></a>

**Date of change:** 15/12/2025

**Affected Projects:** all/ODK (the only one now, lol)

**Affected Features:** Montages

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

We have made some changes to the montage component, to make it more user-friendly. This includes enabling the montages in your montage data asset to define the crowd anim sequences without needing them to be provided elsewhere. We have also made some changes that are slightly breaking and worth calling out:

* `PlayMontageByName` and `StopMontage` were called out as “authoritative client only”, but didn’t actually block you from calling them on non-authoritative clients. It now prevents you from doing so, and gives a warning. This means that if you were calling them on other clients (which is not advised), they will no longer play animations. You should instead only control the montage on the authoritative client
* The `OnPlayMontage` event previously also was triggered when stopping a montage, “playing” a null montage. We have instead removed this behavior, so `OnPlayMontage` is only triggered when playing a new montage. We have instead introduced a separate `OnStopMontage` that is triggered when a montage is stopped, providing details of the stopped montage.

**How to test it?**

Play your game. If you see the following, you should investigate the breaking changes:

* Looping montages - likely due to not listening to `OnStopMontage`
* Montages not playing on non-auth clients - likely due to incorrectly triggering `PlayMontageByName` on the non-auth client

#### Move custom packed struct from Action Gameplay Helper API into HitInfo Structs <a href="#move-custom-packed-struct-from-action-gameplay-helper-api-into-hitinfo-structs" id="move-custom-packed-struct-from-action-gameplay-helper-api-into-hitinfo-structs"></a>

**Date of change:** 12/12/2025

**Affected Projects:** All

**Affected Features:** Action Gameplay Helper API

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

APIs in the Shootable and Combat component that passed in a Morpheus packed struct as custom data have been changed. The custom data param has been removed, and moved into the HitInfo struct.

**How to fix it?**

Change Blueprint logic to pass the custom data into the struct instead.

#### Removed legacy capability gameplay tags (not committed yet) <a href="#removed-legacy-capability-gameplay-tags-not-committed-yet" id="removed-legacy-capability-gameplay-tags-not-committed-yet"></a>

**Date of change:** 03/12/2025

**Affected Projects:** All

**Affected Features:** Capability gameplay tags

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The default `DT_M2_GameplayTags` asset contained many legacy gameplay tags which are no longer used in the Morpheus platform, and have now been removed. If your project uses any content from the `M2Deprecated` plugin, or uses any of the Capability tags directly, you may need to re-add the removed tags.

**How to fix it?**

Download the standalone M2Deprecated plugin and add the `DT_M2_DeprecatedGameplayTags` asset to your project. This is a copy of the previous version of `DT_M2_GameplayTags` containing all the legacy tags.

In the `GameplayTags` section of the project settings, replace the DT\_M2\_GameplayTags entry with DT\_M2\_DeprecatedGameplayTags to restore the previous tags. Alternatively you can manually add the ones your require as a new asset, as detailed here: [Adding Gameplay Tags | MSquared Docs](https://docs.msquared.io/creation/unreal-development/tutorials/reference/adding-gameplay-tags)

**How to test it?**

All previous gameplay tags will be available in the gameplay tag UI.

#### Removed input configs <a href="#removed-input-configs" id="removed-input-configs"></a>

**Date of change:** 03/12/2025

**Affected Projects:** All

**Affected Features:** Input

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The input mappings in the base engine are entirely unused now by the Morpheus Platform, so have been removed. If you have not made changes to the input mappings in your own project, but depend on them (e.g. if you’re referring to `M2Deprecated` content), the actions will stop working, and you will see warnings about the input actions being missing.

**How to fix it?**

If you depend on these old input actions, you can add them manually to your project.

* In your project’s `Config` folder, find or create a `DefaultInput.ini`
* In your ini file’s `[/Script/Engine.InputSettings]` section (add one if it is not present), add the removed config values:

  Private & Shared/Engine/Internal Workflows/MSquared breaking changes/input\_mappings.txt

  * Feel free to review and/or remove any you no longer need
  * (If you already have values in this section, best to paste these values above the existing ones, to avoid your changes being stomped)

  &#x20;
* Close your editor and reopen it
* The input mappings should now be visible in your `Project Settings -> Input`

**How to test it?**

Play your game - it should respond to inputs as expected, and not give warnings about missing inputs

#### Removed MetricsManager default singleton and code class <a href="#removed-metricsmanager-default-singleton-and-code-class" id="removed-metricsmanager-default-singleton-and-code-class"></a>

**Date of change:** 01/12/2025

**Affected Projects:** All

**Affected Features:** Default singletons

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

`BPM_MetricsManager` and the base code class `JM_MetricsManager` have been removed. The `J_MetricsSubsystem:: GetMetricsManager` function has also been removed. `MetricsManagerClass` has been removed from the list in the World Settings.

The metrics manager class didn’t add any functionality, but it was possible to subclass it in a project and use the default singletons entry to spawn it.

**How to fix it?**

If you have subclassed `JM_MetricsManager` then simply reparent it to `MorpheusActor`. If your subclass was spawned by being set as the `MetricsManagerClass` in the singletons list, you can explicitly add it in the `Additional Singletons` array in the singletons settings. Calls to `GetMetricsManager` can be replaced with `GetActorOfClass`.

**How to test it?**

You blueprint should be spawned and function as before.

#### M2Extras\_PubnubChat example integration moved to M2Deprecated <a href="#m2extras_pubnubchat-example-integration-moved-to-m2deprecated" id="m2extras_pubnubchat-example-integration-moved-to-m2deprecated"></a>

**Date of change:** 25/11/2025

**Affected Projects:** All

**Affected Features:** PubNub chat

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The `M2Extras_PubnubChat` plugin contained a blueprint example of integrating Pubnub chat into a project. As this is no longer being actively tested or maintained, the existing example content has been moved into the M2Deprecated plugin which is available to download separately.

**How to fix it?**

If your project is directly using any of the content in the M2Extras\_PubnubChat plugin, the simplest solution is to copy those assets into your project before upgrading.

Alternatively, download the separate M2Deprecated plugin and copy it into your project’s Plugins directory - you blueprints should automatically reference the deprecated assets in the M2Deprecated plugin.

See the Morpheus Platform v39 documentation for details on integrating this example content. However, note that this documentation is no longer officially supported and may be out of date.

**How to test it?**

Pubnub chat continues to work in your project.

#### ‘Soft’ deprecation of legacy systems <a href="#soft-deprecation-of-legacy-systems" id="soft-deprecation-of-legacy-systems"></a>

**Date of change:** Ongoing

**Affected Projects:** All

**Affected Features:** Various

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The Morpheus platform contains legacy features that may be in use by projects, but which are overly opinionated and could be implemented more flexibly directly in the project. Deprecating them in Unreal itself causes warnings in the Blueprints which is not desirable for projects, so instead they are being ‘soft’ deprecated. The approach is to add a display name for the class or function with a `_DEPRECATED` suffix. This doesn’t affect the functionality in any way and the system will continue to work.

There is no timeline for fully deprecating the functionality, these systems will not be prioritised for further support and should be avoided. If you are using any, consider moving towards a project-side implementation.

The affected systems are:

* `J_CharacterBase` and `JM_CharacterBase`. Use `M2_CharacterBase` and `M2M_CharacterBase` directly instead.
* `JunoCoreUI`: `J_BaseHUD`, `M2_CoreWidget`, `M2_StandardButton` , `J_UISkinsSubsystem` and related. Use the vanilla Unreal HUD and standard widgets.
* Morpheus Chat system: `JM_ChatServer`, `MorpheusChatSenderComponent`, `MorpheusChatReceiverComponent` and related. See `BPMC_M2Example_TextChatComponent` for an example of a blueprint replacement.
* `JM_PlayerProfileComponent`: use `M2M_PlayerProfileComponent` directly
* `J_PlayerController`: use the vanilla `PlayerController` directly
* `M2_EnhancedInputSubsystem` and `M2_InputPrioritizationSubsystem` : use the vanilla Unreal input systems
* `JM_WorldTravelPortal`: use `M2_WorldTravelService` directly
* `M2M_HealthComponent`: see `BMPC_CombatExample_Health` for an example blueprint implementation
* Tutorials (`M2_TutorialManagerActorComponent` and related)
* Effect applicator (`JM_EffectManager` and related)
* Inventory and Equipment (`JM_InventoryComponent`, `JM_EquipmentComponent` and related)
* `J_NameplateComponent`
* `M2_NavigationPoolingSubsystem`
* `M2M_WeatherControl`
* Interaction and FocusCam (`M2_FocusCameraComponent`, `M2_InteractableComponent` and related)
* Legacy Roles system (`JM_RolesComponent`)

**How to fix it?**

Nothing needs fixing as a result of this change, however it is recommended to migrate away from any soft-deprecated systems.

**How to test it?**

Systems work as previously.

#### Removed some default singletons <a href="#removed-some-default-singletons" id="removed-some-default-singletons"></a>

**Date of change:** 02/12/2025

**Affected Projects:** All

**Affected Features:** Default singletons

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The `Morpheus Platform - Singletons` section of the World Settings contained many non-critical singletons, and singletons used by deprecated systems, that have now been removed from the list. These optional singletons can now be added as required, instead of being added to all maps.

The removed default singletons are:

* `AbilitySingletonClass` : default was `JM_AbilitySingleton` (used by deprecated ability system)
* `NotificationsSingletonClass` : default was `M2M_NotificationsSingleton` (required if using the Notifications system)
* `ConsoleCommandSingletonClass` : default was `JM_ConsoleCommandsSingleton` (adds a debug command)
* `LatencyInspectorSingletonClass` : default was `BPM_LatencyInspectorSingleton` (adds a rebug command for measuring latency)
* `MetricsManagerClass` : no longer required
* `CapabilitiesManagerClass` : default was `BPM_CapabilitiesManager`. This will need re-adding if you:

  * Selectively enable emotes per-role in `JM_PlayerEmotesComponent` with a role capability
  * Use `JM_CharacterBase` to enable voice chat functionality, or to force specific players into the foreground
  * Use `JM_ObserverCameraManager` to enable load/save camera functionality with the `ObserverSaveLoadCapability` on the role
  * Use `J_PlayerCameraManager` to enable observer mode with the `ObserverAccessCapability` on the role
  * Access the manager directly with `J_CapabilitiesSubsystem::GetCapabilitiesManager`

  &#x20;

**How to fix it?**

If you still want to spawn any of these singletons, add them to the `Additional Singletons` array in the `Morpheus Platform - Singletons` section of the world settings.

**How to test it?**

Verify the required singletons are still spawned.

#### **JunoGameData references replaced by LiveConfig** <a href="#junogamedata-references-replaced-by-liveconfig" id="junogamedata-references-replaced-by-liveconfig"></a>

**Date of change:** 25/11/2025

**Affected Projects:** All

**Affected Features:** LiveConfig

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The legacy `JunoGameData.*` console commands have been removed in favour of the equivalent `M2.LiveConfig.*` commands. The new commands behave identically, only the prefix has changed.

Also in the Blueprint editor you can no longer use the keywords `Game Data Attribute` to search for live config nodes. Search directly for `Live Config` instead.

**How to fix it?**

Use the `M2.LiveConfig.*` console commands instead of `JunoGameData.*`, and use `Live Config` to find nodes in editor.

**How to test it?**

Console commands work as before.

#### Moved JunoGenericLighting and JunoCore maps to M2Deprecated <a href="#moved-junogenericlighting-and-junocore-maps-to-m2deprecated" id="moved-junogenericlighting-and-junocore-maps-to-m2deprecated"></a>

**Date of change:** 24/11/2025

**Affected Projects:** All

**Affected Features:** Maps

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The JunoGenericLighting and JunoCore maps have been moved into the M2Deprecated plugin, which is available to download separately. These maps just contained a default lighting setup, and some bot config. These actors have been copied directly in the affected maps in the platform for simplicity.

**How to fix it?**

If you’re using either of these maps, the simplest solution is to copy the actors from these maps directly into your own maps before upgrading. Alternatively, download the separate M2Deprecated plugin and copy it into your project’s Plugins directory - you maps should automatically reference the deprecated maps in the M2Deprecated plugin.

**How to test it?**

All actors are present in your maps.

#### Renamed Mac device Profiles <a href="#renamed-mac-device-profiles" id="renamed-mac-device-profiles"></a>

**Date of change: 21/11/2025**

**Affected Projects:** Projects who have custom device profile overrides defined in ConsoleVariables.ini.

**Affected Features:** Graphics Settings / Device Profiles

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

Renamed profile `MacClient_Macbook` to `MacClient_LowSpec`

Renamed profile `MacClient_StudioUltra` to `MacClient_HighSpec`

**How to fix it?**

Replace any instances of `MacClient_Macbook` or `MacClient_StudioUltra` defined in ConsoleVariables.ini with the either `MacClient_LowSpec` or `MacClient_HighSpec`, respectively.

**How to test it?**

Load game on a mac device and verify any profile overrides have been set correctly.

#### Removal of M2M\_PartyComponent and M2M\_PartyManager <a href="#removal-of-m2m_partycomponent-and-m2m_partymanager" id="removal-of-m2m_partycomponent-and-m2m_partymanager"></a>

**Date of change:** 24/11/2025

**Affected Projects:** All

**Affected Features:** Activities

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The Party system has been marked as deprecated since v38, so has now been fully removed.

**How to fix it?**

If your project uses Parties, please remove or replace the use of the code classes before updating to this version. Projects will then need to implement their own functionality in project space if required.

**How to test it?**

Blueprints compile without error.

#### Removal of Activities system <a href="#removal-of-activities-system" id="removal-of-activities-system"></a>

**Date of change:** 24/11/2025

**Affected Projects:** All

**Affected Features:** Activities

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The Activities system has been marked as deprecated since v36, so has now been fully removed.

**How to fix it?**

If your project uses Activites, please remove or replace the use of the code classes before updating to this version. Projects will then need to implement their own functionality in project space if required.

**How to test it?**

Blueprints compile without error.

#### RaycastableCrowd has been replaced with DynamicColliderProxySystem <a href="#raycastablecrowd-has-been-replaced-with-dynamiccolliderproxysystem" id="raycastablecrowd-has-been-replaced-with-dynamiccolliderproxysystem"></a>

**Date of change: 14/11/2025**

**Affected Projects:** All

**Affected Features:** Raycastable Crowd

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The RaycastableCrowd has been replaced with a system with similar functionality, the DynamicColliderProxySystem. The crowd collider implementation of this is the MorpheusActorColliderProxySystem.

All raycastable crowd related classes and settings have been removed.

**How to fix it?**

You will need to set up the MorpheusActorColliderProxySystem in your game to match the functionality. Please see the full docs, but for a quick conversion to the new system:

* There’s no longer a RaycastableCrowd class that you need to specify with the settings of the raycastable crowd. Instead, you configure these settings in the WorldSettings.
* `BP_M2_AvatarColliderProxyActor` is the replacement for `BP_M2_AvatarRaycastableCrowdActor` .
* To configure the prioritization settings that used to be in the RaycastableActor class, you now need to create a PrioritizationSettings class with your settings in, and specify it in *Prioritization Settings Class* in WorldSettings.

**How to test it?**

Go into a level with crowd members (using the live config `game.PlayerClient.Rendering.NumInLOD0` to decrease the number of non-crowd members if necessary) and see if the correct crowd members have colliders, matching what your project was previously set up with. You can enable `bDebugVisibility` on the BP\_M2\_AvatarColliderProxyActor to help with this, or use the Unreal command `show COLLISION` .

&#x20;

#### Remove JM\_StateSequenceComponent <a href="#remove-jm_statesequencecomponent" id="remove-jm_statesequencecomponent"></a>

**Date of change:** 13/11/2025

**Affected Projects:** All

**Affected Features:** JM\_StateSequenceComponent

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

`JM_StateSequenceComponent` has been removed as it’s not a core part of the platform, and can easily be built in a project Blueprint.

**How to fix it?**

Functionality will need to be rebuilt a project blueprint. It’s an array of {FromStateName, ToStateName, ULevelSequence}, and a replicated ToStateName. When receiving a new ToStateName, the corresponding level sequence between the old and new state is played.

**How to test it?**

The project behaves as previously.

#### WebUI respects the URL allow list <a href="#webui-respects-the-url-allow-list" id="webui-respects-the-url-allow-list"></a>

**Date of change:** 06/11/2025

**Affected Projects:** All

**Affected Features:** WebUI

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The M2 platform allows configuring external URL access policies, to enable projects to restrict access to unauthorised domains. This policy now also applies to the WebUI in-game browser.

Loading local files now requires the Allow All policy, to avoid exploits that bypass loading from a URL.

**How to fix it?**

Check the External URLs section of the your project’s admin dashboard. If you have filtering enabled, add any required domains to the allow list. If you’re using WebUI to show local files, you must change the policy to Allow All.

**How to test it?**

The web browser will still be able to open the page. If a request is blocked you will see a log message `LoadURL: Requested URL is denied by policy`.

#### M2Deprecated, JunoSkypark and JunoVoxelWorld plugins removed <a href="#m2deprecated-junoskypark-and-junovoxelworld-plugins-removed" id="m2deprecated-junoskypark-and-junovoxelworld-plugins-removed"></a>

**Date of change:** 06/11/2025

**Affected Projects:** All

**Affected Features:** All deprecated content

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The M2Deprecated plugin has now been removed from the platform by default, but is available to download as a separate plugin that can be re-added to your project. The deprecated content is no longer maintained, so has been removed to simplify the platform for new users.

Some of the blueprints in the separate M2Deprecated plugin relied on code that has also been removed. These blueprints have been fixed up to remove compile errors, but may not function as before. You can refer to the blueprints in the v39 editor release to see the original implementations.

JunoSkypark content has also been removed. These were mostly redirectors, and replacement core redirects are included in the downloadable M2Deprecated plugin. Follow the steps below if you encounter and issues with JunoSkypark references.

JunoSkypark has also contained a handful of code classes that have been removed. J\_GraffitiWallFunctionLibrary for the removed graffiti wall functionality, J\_Skypark\_LightSource which updated intensity based on an MPC and can be re-implemented in blueprint, and JM\_RepulsorArea which was used by the deprecated activity system.

JunoVoxelWorld was an unsupported experimental plugin and has been removed entirely.

**How to fix it?**

Access the M2Deprecated plugin via the plugins tab within the ODK Launcher. Drop the M2Deprecated plugin into your project, in `<ProjectRoot>/Plugins/`. It is now part of your own project, and you have full control over it.

The M2Deprecated plugin also contains core redirects for all of the redirector assets removed in the platform, so all existing asset references should continue to work. It’s recommended to resave every asset in your project, which will fix up the references.

**How to test it?**

Your project should compile and run as before, with no errors caused by missing assets.

#### Changes to the `BPC_M2Example_NameplateComponent` <a href="#changes-to-the-bpc_m2example_nameplatecomponent" id="changes-to-the-bpc_m2example_nameplatecomponent"></a>

**Date of change: 06**/11/2025

**Affected Projects:** All

**Affected Features:** Nameplates

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

We have extended the functionality in `BPC_M2Example_NameplateComponent` to support globally disabling nameplates, as well as each individual nameplate hiding due to distance etc. (Details in [Nameplates | MSquared Docs](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/nameplates))

For this reason, there are two changes to the component’s functionality to note:

* `SetWidgetEnabled` has been renamed to `SetIndividualWidgetEnaabled`, to reflect that this only refers to the distance etc. checks, and not whether it is actually enabled, which could be due to nameplates being disabled globally
* `IsEnabled` checks whether the nameplate should ultimately be visible or not, handling both the individual check, and the new global check

**How to fix it?**

No changes needed - the function rename should apply globally

#### DefaultIconMap setup in deprecated UI skinning system <a href="#defaulticonmap-setup-in-deprecated-ui-skinning-system" id="defaulticonmap-setup-in-deprecated-ui-skinning-system"></a>

**Date of change:** 05/11/2025

**Affected Projects:** All

**Affected Features:** UI skinning icons

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The default value for `J_InputIconConfig::DefaultIconMap` was an asset in the M2Deprecated plugin, which has now been removed (but can be downloaded separately). Because of this, the default value has been removed from the platform. If your project relied on the default `/M2Deprecated/M2Content/UI/Input/DA_InputIconMap` asset you will need to manually re-add this in a config file.

If you don’t use the skinning system, or the icon map, then no action is necessary.

**How to fix it?**

Add the `DefaultIconMap` to the `[/Script/JunoCoreUI.J_InputIconConfig]` section in your `<ProjectRoot>/Config/DefaultGame.ini` file, or add the section if it doesn’t exist:

`[/Script/JunoCoreUI.J_InputIconConfig] DefaultIconMap=/M2Deprecated/M2Content/UI/Input/DA_InputIconMap.DA_InputIconMap`

(This assumes you’ve downloaded the legacy M2Deprecated plugin and copied it directly into your project - the asset may be at a different the path if not.)

**How to test it?**

The UI skinning and icons will behave the same as before.

#### Client origin API changes <a href="#client-origin-api-changes" id="client-origin-api-changes"></a>

**Date of change:** 20/10/2025

**Affected Projects:** All

**Affected Features:** Client Origin

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The methods to change the client origin, used for net prioritisation, have changed. This includes:

* `PushClientOriginActor`
* `RemoveClientOriginActor`
* `ClientOriginMovement`

Net prioritisation now takes into account all client origin actors that are in the ClientOriginLocations set (see below). This no longer operates as a queue that you can push/remove from; you’ll need to directly clear the set if you want to change which actor is used as the client origin.

**How to fix it?**

Use:

* `AddClientOriginActor`
* `RemoveClientOriginActor`
* `SetClientOriginActors`
* `SetClientOriginActor`
* `GetClientOriginActors`

To directly set which actors you want to be used for net prioritisation at any given time.

**How to test it?**

Check that the correct actors are in your foreground, midground and background after you’ve made the changes above.

#### UserCollections, Wallets, Currency, Transactions and Purchaseables systems removed <a href="#usercollections-wallets-currency-transactions-and-purchaseables-systems-removed" id="usercollections-wallets-currency-transactions-and-purchaseables-systems-removed"></a>

**Date of change:** 20/10/2025

**Affected Projects:**

**Affected Features:** UserCollections, Wallets, Currency, Transactions and Purchaseables systems

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

These systems have been deprecated in M2 for several releases, and relied on the User Collections web platform system which has been removed. As these systems are now non-functional they have been removed entirely.

**How to fix it?**

Projects should already have migrated away from these systems. Currency and transactions should be implemented in project space.

**How to test it?**

Blueprints compile without error.

#### Removal of StorePlayerProfile async task <a href="#removal-of-storeplayerprofile-async-task" id="removal-of-storeplayerprofile-async-task"></a>

**Date of change:** 17/10/2025

**Affected Projects:** All

**Affected Features:** Player Profile system

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The `StorePlayerProfile` async task node has been removed. This didn’t support saving the player avatar, and you can just call the underlying functions directly.

**How to fix it?**

Replace with calls to the Save functions on the `M2_WebServivesDataProvider` (see `BP_M2_ProfileDataProvider` for examples). It’s also possible to use the `M2_PlayerProfileSubsystem`.

**How to test it?**

The project should compile and profile name/avatar data should save correctly.

#### Removal of profile pictures and legacy content from M2 player profiles <a href="#removal-of-profile-pictures-and-legacy-content-from-m2-player-profiles" id="removal-of-profile-pictures-and-legacy-content-from-m2-player-profiles"></a>

**Date of change:** 17/10/2025

**Affected Projects:** All

**Affected Features:** Player Profile system

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

`M2_PlayerProfile` now only contains a `Name` and `AvatarUrl`. It no longer contains legacy properties for Profile Images, Wallet, and User Collection items associated with your avatar. These have been previously deprecated, and it wasn’t possible to save new values to a user’s profile for these.

`JM_PlayerEmoteComponent` no longer supports `J_ProfileAsEmotePrimaryAsset` as profile images are no longer a core part of the M2 player profile. Profile picture emotes can be implemented in the project instead.

Functions and delegates related to profile images and user collections have been removed from `M2_PlayerProfileSubsystem`, `M2_WebPlatformUserProfileService` and `M2M_CharacterAssetComponent`. It was already impossible to update these values, so the API has now been removed.

`M2M_PlayerProfileComponent` no longer replicates a profile image. This can be implemented in the project instead.

**How to fix it?**

Use the `M2_PlayerProfile::AvatarUrl` property directly to retrieve the avatar, instead of using the `Url` property in the `Avatar` structure:

Remove any live config overrides for `Profile.DefaultProfileUrl` and `Profile.ProfileAsEmoteEnabled`

Profile pictures can be implemented in the project if required, by storing them in the KV Store with your own key. See `BP_M2_ProfileDataProvider` for an example - it would work the same as storing and loading the avatar URL:

Profile picture emotes will need implementing in the project. One method would be add a replicated image URL to each player, and showing a custom widget above a player when they trigger an emote.

**How to test it?**

The project compiles without errors, and no live config errors are present when playing in editor.

#### Player Profile changes <a href="#player-profile-changes" id="player-profile-changes"></a>

**Date of change:** 15/10/2025

**Affected Projects:** All

**Affected Features:** Player Profile system

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The default player profile implementation in `BP_M2_ProfileDataProvider` has been migrated to storing date in the M2 KVStore, and requires the `MP_M2_KVStoreService` to exist. This replaces the legacy profile API.

**How to fix it?**

The service should be enabled by default. If you’ve changed the `KV Store Service Class` in your world settings then you will need to also use your own `Profile Data Provider Class`. You can take a copy of `BP_M2_ProfileDataProvider` and update its uses of `MP_M2_KVStoreService` to use your own service.

**How to test it?**

Profile data (display name and avatar URL) should be retrieved correctly when loading into a world.

#### KVStore Store delegate signature has changed <a href="#kvstore-store-delegate-signature-has-changed" id="kvstore-store-delegate-signature-has-changed"></a>

**Date of change:** 15/10/2025

**Affected Projects:** All

**Affected Features:** KVStore

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The completion delegate passed into `M2_KVStoreService::Store` has a different signature. Previously it took a single Success bool, but now it takes a struct containing the same Success value plus the ID of the request triggered it (which is now passed back from Store function). This enables you to associate a response with a specific request.

**How to fix it?**

For delegate events, you should just need to break the new Result pin to get Success.

For delegate functions, update the signature to to take a `FM2_KVStoreServiceStoreResponse` instead of a bool, and split that to get Success.

**How to test it?**

Blueprints should compile and behave the same.

#### Removal of M2 AvatarEditor code and assets <a href="#removal-of-m2-avatareditor-code-and-assets" id="removal-of-m2-avatareditor-code-and-assets"></a>

**Date of change:** 13/10/2025

**Affected Projects:** All

**Affected Features:** Avatar Editor

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The deprecated M2 Avatar Editor C++ classes and blueprints have been removed, as they relied on legacy Web Platform features that are no longer available.

**How to fix it?**

Remove any references to `M2_AvatarEditorActor`, `M2_AvatarEditorComponent` and any of the `/M2Deprecated/AvatarEditor` assets from your project.

Remove any live config overrides for `AvatarEditor.*` values from your project’s `game.override.json` file, otherwise live config setup will fail with an error.

**How to test it?**

The project compiles and runs without errors.

#### Removed the BA Welcome Screen by default <a href="#removed-the-ba-welcome-screen-by-default" id="removed-the-ba-welcome-screen-by-default"></a>

**Date of change: 14/10/2025**

**Affected Projects:** All

**Affected Features:** BlueprintAssist

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

We have now hidden the “BA Welcome Screen” popup from new projects, created via our starter project template.

**How to fix it?**

If you want information on how to use the Blueprint Assist plugin, please look into it independently.

If you want the the popup to display for your project, you can add the following section to your `DefaultEditorPerProjectUserSettings.ini`:

`[/Script/BlueprintAssist.BASettings_EditorFeatures] bShowWelcomeScreenOnLaunch=False`

#### Removed the `EUW_RolesHierarchyViewer` utility widget <a href="#removed-the-euw_roleshierarchyviewer-utility-widget" id="removed-the-euw_roleshierarchyviewer-utility-widget"></a>

**Date of change: 26/09/2025**

**Affected Projects:** All

**Affected Features:** Roles

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

We have removed the `EUW_RolesHierarchyViewer` utility widget, and its dependent widgets, since it was noticed that this has been broken for about a year, and was only ever used for now-deprecated content. Since it has gone unnoticed for a year, we have chosen to remove it rather than fix it and keep it in deprecated content.

**How to fix it?**

N/A

**How to test it?**

N/A

&#x20;

#### CrowdScale functionality removed from M2M CharacterBase <a href="#crowdscale-functionality-removed-from-m2m-characterbase" id="crowdscale-functionality-removed-from-m2m-characterbase"></a>

**Date of change: 23**/09/2025

**Affected Projects:** All

**Affected Features:** Character

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

Set/GetCrowdScale have been removed from M2M CharacterBase. This functionality is superceded by MorpheusAnimatedSkeletonComponent’s relative transform functionality.

The EnableResizingOfAnimatedCrowd LiveConfig has also been removed.

Resizing functionality in the deprecated AJM\_CharacterBase (with JM\_ReiszeableActorComponent) class is now broken.

**How to fix it?**

In any case where you would have set the crowd scale to match the lod0 actor’s scale, you can use Character.MorpheusAnimatedSkeletonComponent.SetSkeletalMeshRelativeTransform and set the scale property of the transform. This will affect the lod0 and crowd transform, so you don’t need to branch.

If you want to intentionally set the crowd scale of an actor to be different to the lod0 scale of an actor, then you’ll need to implement your own IMorpheusAnimatedSkeleton::ApplySkeletalMeshTransform in your character class. See the MorpheusAnimatedSkeletonComponent in the docs for details.

If you were using the deprecated AJM\_CharacterBase class, you should swap to using AM2\_CharacterBase and the BPMC\_M2Example\_ResizingComponent to continue using resizing functionality in the crowd.

**How to test it?**

Check your characters and resizing correctly in the crowd.

&#x20;

#### Graphics Settings reduce maximum visible Carnival Meshes (MML) <a href="#graphics-settings-reduce-maximum-visible-carnival-meshes-mml" id="graphics-settings-reduce-maximum-visible-carnival-meshes-mml"></a>

**Date of change: 22/09/2025**

**Affected Projects:** All

**Affected Features:** Carnival Rendering

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

To aid in client performance, the maximum visible Carnival meshes have been limited based on the graphics settings used. No change is required by the Project. Can be overridden by project settings if desired.

| Graphics Settings | Max Carnival Meshes |
| ----------------- | ------------------- |
| Low               | 2500                |
| Medium            | 8750                |
| High              | 15000               |
| Epic              | 15000               |

**How to fix it?**

Override `r.Carnival.MaxVisibleModels` in projects settings following this documentation [Editing Project Settings | MSquared Docs](https://docs.msquared.io/creation/unreal-development/tutorials/adding-project-settings-config-overrides#adddingprojectsettingsconfigoverrides-howtooverridecvars)

&#x20;

#### Replicated animations and capsule moved into components <a href="#replicated-animations-and-capsule-moved-into-components" id="replicated-animations-and-capsule-moved-into-components"></a>

**Date of change: 15/09/2025**

**Affected Projects:** All

**Affected Features:** Characters

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

Functionality related to the replicated animated skeleton now exists in M2\_AnimatedModularCharacterComponent (e.g. the skeletal mesh transform applied to the crowd).

Functionality related to the replicated capsule now exists in M2\_ReplicatedCapsuleComponent.

Additionally, all actors that implement IMorpheusPooledActor will automatically be hidden, collision disabled, and tick disabled when they enter the pool, and the inverse when they return from the pool, so long as the parent MorpheusPooledActor implementation is called. There is no need to perform these actions manually now.

**How to fix it?**

Instead of the skeletal mesh transform and capsule component data existing in your character class directly, these now exist in Character.AnimatedModularCharacterComponent and Character.ReplicatedCapsuleComponent. You’ll need to update these references.

**How to test it?**

Project should build and characters should function as normal.

#### Deprecate M2\_WebSocketConnection <a href="#deprecate-m2_websocketconnection" id="deprecate-m2_websocketconnection"></a>

**Date of change: 15/09/2025**

**Affected Projects:** All

**Affected Features:** WebSockets

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

We have deprecated `M2_WebSocketConnection` in favour of two alternatives: `M2_JsonWebSocketConnection` and `M2_StringWebSocketConnection`. The class had previously been deprecated, but not in a way that was communicated to downstream users.

As a result of this, the `Connect` node of the old `M2_WebSocketConnection` class will now result in warnings, and you will not be able to add further calls.

**How to fix it?**

Switch to using whichever out of `M2_JsonWebSocketConnection` and `M2_StringWebSocketConnection` is more appropriate for your use case. For instruction on how to use them, see [WebSockets | MSquared Docs](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/web-services/web-socket-connections)

**How to test it?**

Your logic compiles as normal with no warnings. If you needed to modify your logic, check your websockets still connect and send messages as expected.

#### Deprecated the use of Pawn Sets <a href="#deprecated-the-use-of-pawn-sets" id="deprecated-the-use-of-pawn-sets"></a>

**Date of change: 09/09/2025**

**Affected Projects:** all

**Affected Features:** Animated Crowd

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

**#1:**

Pawn sets are no longer required to define a morpheus actor’s render target actor or crowd. Instead, if you have a render target actor defined in the details panel, it will be used, and if crowd is enabled, its details will be inferred automatically from the render target actor.

(Documentation on this process will be written soon)

There are two breaking changes that will need to be noted as a result of this:

* `BPM_M2Example_PlayerCharacter` no longer calls `ApplyPawnSet`. If your character extends this class and relies on a specific pawn set, this logic will need to be re-added, or handled without using pawn sets
* Instead of defining the montages known by the crowd in the pawn set’s Crowd Data Asset, we can provide the list in our actor class (see `GetAnimNameToSequenceMap`). This has been done already in `BP_M2Example_PlayerCharacter`.

  * If your morpheus actor extends `BPM_M2Example_PlayerCharacter`, but your character does not extend `BP_M2Example_PlayerCharacter`, or you have added additional montages than the list existing in `DA_SkeletalCrowdData_LoD1`, you will need to override this function and provide the mappings you need (or the character will be unable to emote in the crowd)

  &#x20;

**#2:**

Since pawn sets are no longer required, we have now deprecated all the pawn sets except for `DA_Pawns` (which is still our default pawn set), moving them into `M2Deprecated`. If you reference any of these assets in your project, you will need to enable the `M2Deprecated` plugin to access them, and move them into your project.

* `DA_Origin_Pawns_Approachability`
* `DA_Pawns_AudioMixer`
* `DA_Pawns_Observer`
* `DA_Pawns_ObserverDirector`
* `DA_Presenter`

**#3:**

Since we no longer call `ApplyPawnSet` to initialize your character (for classes extending `BPM_M2Example_PlayerCharacter`), it it possible for the render target actor to be spawned earlier in the process. If you e.g. listened to `OnRenderTargetUpdated`, and didn’t also check the current render target, the callback may not trigger, if bound after the initial render target was already set.

**How to test it?**

Easiest way to verify that it is working as expected would be:

* PIE with 2 clients, and `PlayerClient.Rendering.NumInLOD0` set to 0. That way the other client you are looking at will be a crowd member
* Walk around - both characters should appear and animate as expected
* Emote - the crowd member should animate when emoting.

If you have a presenter or observer role in your project, check that you can still switch to it correctly.

#### Remove M2\_ExampleAudioProcessor and its LiveConfig value `VoiceChat.ExampleProcessorEnabled`  <a href="#remove-m2_exampleaudioprocessor-and-its-liveconfig-value-voicechat.exampleprocessorenabled" id="remove-m2_exampleaudioprocessor-and-its-liveconfig-value-voicechat.exampleprocessorenabled"></a>

**Date of change: 02/09/2025**

**Affected Projects:** All

**Affected Features:** Crowd Audio

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

Removed the M2\_ExampleAudioProcessor as it was always disabled and even if it was enabled it was doing nothing. It was also causing a crash as a result of accessing live config (not thread-safe) from the crowd audio thread.

This also resulted in removing the already deprecated live config value `VoiceChat.ExampleProcessorEnabled` from the `game` config

**How to fix it?**

Ensure that you aren’t relying on the live config value `VoiceChat.ExampleProcessorEnabled` and if so, you can add a new live config value for your specific usage.

**How to test it?**

Crowd audio is working as expected.

#### Undefined anim vars now default to 0/false <a href="#undefined-anim-vars-now-default-to-0-false" id="undefined-anim-vars-now-default-to-0-false"></a>

**Date of change: 01/09/2025**

**Affected Projects:** All

**Affected Features:** Animation

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

We have now provided explicit behavior to an edge case that previously resulted in undefined behavior:

If you define a variable in your animation blueprint which is not actually registered in your anim vars component - previously this would result in an undefined result (i.e. if you use a `IsDead` bool, but don’t register it in your anim vars component, the result could either be true or false). Now, it will always fall back to 0 (false for bools).

If you had unregistered variables previously, it could be that they were defaulting to the right value accidentally, in which case this change may result in their behavior changing. If so, you would see errors along the lines of:

`LogAnimatedCrowd: Warning: UAnimatedCrowdComponent::ValidateAnimVars: Crowd expected to support anim var with name IsSprinting, but this could not be found. Please check your anim var names. LogAnimatedCrowd: Warning: UAnimatedCrowdComponent::ValidateAnimVars: Crowd expected to support anim var with name InCombatMode, but this could not be found. Please check your anim var names.`

**How to fix it?**

If you are seeing the above warnings, you should address them. See [Custom Animation Variables | MSquared Docs](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/avatars/bespoke-character-animations) for details on how to register custom anim variables.

**How to test it?**

When you play the game with crowd members (easiest way would be to set the `PlayerClient.Rendering.NumInLOD0` override to 0 and test with a second client), you shouldn’t see any warnings along the lines of:

`LogAnimatedCrowd: Warning: UAnimatedCrowdComponent::ValidateAnimVars: Crowd expected to support anim var with name IsSprinting, but this could not be found. Please check your anim var names. LogAnimatedCrowd: Warning: UAnimatedCrowdComponent::ValidateAnimVars: Crowd expected to support anim var with name InCombatMode, but this could not be found. Please check your anim var names.`

If you do, please verify whether these variables are needed in your ABP, or need to be registered in your anim vars component.

#### Introduced min LOD checks for projects targeting mobile platforms <a href="#introduced-min-lod-checks-for-projects-targeting-mobile-platforms" id="introduced-min-lod-checks-for-projects-targeting-mobile-platforms"></a>

**Date of change: 25/08/2025**

**Affected Projects:** Only projects targeting mobile devices, e.g. IOS/Android

**Affected Features:** Cooking

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

To help avoid performance issues on projects targeting mobile platforms, we have added some automated checks and logic to enforce that skeletal meshes and static meshes have sufficient LODs.

If you attempt to cook for a project that targets Android or IOS, and has fewer LODs than the configured minimum (in `Project Settings | M2 World Builder` - 7 for skeletal meshes, 4 for static meshes), it will be flagged as an error. If you are cooking from the editor, a popup will show for each flagged asset.

For more details on this, see [Automatic Mesh Validation | MSquared Docs](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/helpers-and-extras/automatic-mesh-validation)

**How to fix it?**

* The ideal solution would be that if you have any such meshes that need fixing up, that you address them. Any meshes that were flagged when you attempt to cook should be looked at. You can either manually add LOD levels, or alternatively, if you save the asset, it will automatically generate the required number of LODs for you.

  &#x20;
* If you aren’t intending to build for mobile platforms, you can modify your “supported platforms” list. This can be done in your `.uproject` file. Any `IOS` or `Android` ones can be removed.

  &#x20;
* If you don’t want the checks to be applied, you can turn them off by going to `Project Settings | M2 World Builder | Mesh Validation`, and un-checking `ValidateMeshes`.

  &#x20;

**How to test it?**

Attempt to cook your project. Cooks should succeed for your target platform.

#### Removed MorpheusConnection OnMorpheusActorCheckedOutBP Implementable Event <a href="#removed-morpheusconnection-onmorpheusactorcheckedoutbp-implementable-event" id="removed-morpheusconnection-onmorpheusactorcheckedoutbp-implementable-event"></a>

**Date of change: 21/08/2025**

**Affected Projects:** All, although unlikely to could’ve been used by downstream projects

**Affected Features:** MorpheusConnection delegates

**Does this breaking change need publishing for external users?** Yes

**What’s broken and why?**

The BP implementable event `OnMorpheusActorCheckedOutBP` on the `MorpheusConnection` has been replaced with a Blueprint Assignable Delegate `OnMorpheusActorAdded` and `OnMorpheusActorRemoved`

**How to fix it?**

Instead of using `OnMorpheusActorChecekdOutBP` you can now assign to the delegate `OnMorpheusActorAdded`

**How to test it?**

Ensure that the `OnMorpheusActorAdded` delegate is being called when MorpheusActors spawn in the world.

## Deprecating J\_CharacterMovementComponent and JM\_AnimVarsComponent

{% hint style="info" %}
The following is a significant breaking change in upgrading to release v39. If you are using the simplified base classes (i.e. not the deprecated classes with e.g. the `Origin` or `J_` prefixes), you will be affected, and will need to take action.

If you have extended the deprecated classes, and are using your own anim instance (ABP), you will likely also be affected (see [#modified-abp\_m2\_human](#modified-abp_m2_human "mention")). In that case, you will need to make sure your ABP is correctly reflected in your crowd, explained in the [#if-you-want-to-keep-using-the-deprecated-classes-only-recommended-as-a-temporary-solution](#if-you-want-to-keep-using-the-deprecated-classes-only-recommended-as-a-temporary-solution "mention") section
{% endhint %}

## Does this affect me?

Have a look through the [#whats-changed-and-why](#whats-changed-and-why "mention") section. Some sections may not be relevant to your project; if so, feel free to skip them.

If your character extends e.g. `M2_CharacterBase`, `BP_M2_PlayerCharacter` or `BP_M2Example_PlayerCharacter`, you will be affected at least by the change to the character movement component, even if you are not using any of the deprecated functionality. You will see the following popup when you open your character class. More details on this in [#resolving-the-corrupted-charactermovementcomponent](#resolving-the-corrupted-charactermovementcomponent "mention").

<figure><img src="/files/AkJ3UlX5EkeUfvP1Q2K9" alt=""><figcaption></figcaption></figure>

If any of these parts are relevant to your project, see [#how-to-fix](#how-to-fix "mention").

## What's changed, and why?

The following changes have been made to the `M2` character and morpheus actor (`M2_CharacterBase` and `M2M_CharacterBase`), meaning that if you are using blueprints based off of those classes, you will be impacted. If you are still using the deprecated character (extending e.g. `J_` classes or `Origin` classes), you will not be affected by this.

### Deprecated Anim Vars Component

The existing `JM_AnimVarsComponent` has now been deprecated, in favour of a stripped back `M2M_AnimVarsComponent`.

* The following anim vars have been removed:
  * `IsWalking`
  * `IsDoubleJumping`
  * `HasBeenLaunched`
  * `HasLowGravity`
  * `HasZeroGravity`
  * `IsMovingInLowGravity`
  * `IsThrustingUp`
  * `IsThrustingDown`
  * `IsBouncing`
  * `IsSliding`
  * `IsAiming`
* The following anim vars have been modified:\
  (These have been moved into being custom anim vars. For more details, see [#changes-to-gait-speeds](#changes-to-gait-speeds "mention")& [#changes-to-combat-mode](#changes-to-combat-mode "mention"))
  * `IsJogging`
  * `IsSprinting`
  * `IsInCombatMode`
  * `IsDead`

{% hint style="info" %}
In the deprecated `J_AnimInstance`, these are still accessible via the `DeprecatedAnimVars` variable
{% endhint %}

#### Modified ABP\_M2\_Human

`ABP_M2_Human`, our default anim instance, has been reparented from `J_AnimInstance` to `M2_AnimInstance`, and so no longer uses the deprecated anim vars. The old anim vars are still in use in the deprecated `ABP_M2_Human_OId`.

### Deprecated Character Movement Component

The existing `J_CharacterMovementComponent` has now been deprecated, in favour of using the native default `CharacterMovementComponent`.

* The following features have been removed:
  * The “Custom Movement Mode Primary Asset” system (see [#changes-to-custom-movement](#changes-to-custom-movement "mention"))
  * Some minor helper functions, like `AddGravityMultiplier` and `AddGaitSpeedMultiplier`
    * These could easily be added in the blueprint level in downstream projects if desired.
* The following features have been modified:
  * “Gait speeds” (see [#changes-to-gait-speeds](#changes-to-gait-speeds "mention"))
  * “Combat mode” (see [#changes-to-combat-mode](#changes-to-combat-mode "mention"))
* Due to `M2_CharacterBase`'s `Character Movement` class being changed (from `J_CharacterMovementComponent` to `CharacterMovementComponent`), unfortunately assets extending `M2_CharacterBase` will have their component corrupted. If this affects your character, you will see the following popup when attempting to play or open your asset.
  * For resolving this, see [#resolving-the-corrupted-charactermovementcomponent](#resolving-the-corrupted-charactermovementcomponent "mention")

<figure><img src="/files/HOqz1gHaIf5Kuz5OVOFK" alt=""><figcaption></figcaption></figure>

### Changes to gait speeds

Gait speeds” are now no longer used as a core concept, and the `BPC_CharacterMoveSpeedComponent` has been deprecated. If you want to change your character’s walk speed, you can do so directly by calling your character movement component. We have an example of this in `BP_M2_PlayerCharacter` (for more details, see [The Example Character](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/the-example-character))

<figure><img src="/files/Nzm8Eu6dua5knNPhm3Cr" alt=""><figcaption></figcaption></figure>

### Changes to "combat mode"

Similar to above, `IsInCombatMode` and `IsDead` have been converted to BP custom anim vars, and are used in our `M2Extras: CombatExample` plugin

<figure><img src="/files/fNQj7OvpxI9QtthtGADT" alt=""><figcaption></figcaption></figure>

### **Changes to "custom movement"**

The deprecated “Custom Movement Mode Primary Asset” system is no longer used. It has not been documented, and has not been actively maintained by MSquared for years.

Note that Unreal’s custom movement modes are still available. Custom physics will need to be provided if so, in the `UpdateCustomMovement` event on your pawn

<figure><img src="/files/jWeHeIbfpUJduLAKAidX" alt=""><figcaption><p>For reference - the node on the left is exclusive to the <code>J_CharacterMovementComponent</code>, and so has been deprecated and removed from our base class. The node on the right is native Unreal's way of handling custom movement, and will still be available</p></figcaption></figure>

<figure><img src="/files/oK4YjTkDkigLpujnoQSN" alt=""><figcaption><p>A basic representative example of applying phyics to your custom movement mode in the native Unreal way</p></figcaption></figure>

### A diagram of the relevant classes

{% hint style="info" %}
Knowing the interaction of these classes is not essential, but this information has been provided if you want to know more about how the classes interact.
{% endhint %}

This diagram shows the changes to the assorted classes, and how they are related:

* `JM_AnimVarsComponent` has had a new base class introduced: `M2M_AnimVarsComponent`, which `M2M_CharacterBase` now points to
* `J_AnimInstance` has had a new base class introduced: `M2_AnimInstance`, which `ABP_M2_Human` now points to.
* `BPM_M2Example_PlayerCharacter` now uses a BP-level `BPMC_M2_AnimVarsComponent`, based off of the simplified base class, instead of using the deprecated anim vars.
* The deprecated BP classes (e.g. the `_Origin_` ones) will still point to the `J_` classes)

<figure><img src="/files/mEj91JtgkQNlYzSp0Inj" alt=""><figcaption><p>A diagram outlining the various movement and animation components, and how they interact</p></figcaption></figure>

## How to fix

### **Resolving the corrupted CharacterMovementComponent**

{% hint style="warning" %}
NOTE: This breaking change is best fixed with knowledge of the project prior to upgrading. Please either check this flow before starting the upgrade, so you can make appropriate notes, or have access to a version of the project prior to the upgrade to hand, to easily compare between them.
{% endhint %}

The most significant action required is resolving the corrupted character movement component in classes extending `M2_CharacterBase`. You can fix it by doing the following:

* Open your actor class.
* If you see the following popup, that means your movement component was corrupted, and has been regenerated automatically.
  * (This is due to the parent class changing its default `CharacterMovementComponent` to be the base component rather than previously setting it to `J_CharacterMovementComponent`).

<figure><img src="/files/5YG9Yfie8vKHoa2VOzoO" alt=""><figcaption></figcaption></figure>

Review your auto-generated character movement component class. Since the movement component had to be regenerated, any manual changes to your previous movement component will have been reset.

* Unfortunately, you won’t be able to compare changes via the diff, since the diffed version will have also been corrupted. Therefore, the best approach to get your changes to your character movement component class would be to either:
  * Make note of your changes to the movement component prior to the upgrade. You will be able to see any changes from the defaults since they will have the “undo arrow” by the property. Some edge cases to be aware of: `FaceLastAccelerationDirection` may be off, due to the `J_CharacterMovementComponent` making changes to this automatically. This should probably be set to true once moving off the `J_CharacterMovementComponent`. Also, make note of the `GaitSpeeds` values. `Jog` would be the default walk speed used, and you may want to re-add sprint to your project.
    \*

    ```
    <figure><img src="/files/gWH1alu8I5XLMn8slA3i" alt=""><figcaption></figcaption></figure>

    * Open a version of the project prior to the upgrade, to compare side-by-side, and add any changes back to the upgraded version of your class.
    ```

    * **Save your asset** once you have reviewed your character. Even if you did not need to modify your movement component, the regenerated asset will need to be saved.

### If you accept the simplified base classes (recommended)

Our recommended approach would be to use the simplified components. Most of the deprecated anim variables, movement component additions and the like are not widely used, and could be re-added in downstream projects if desired.

If you accept the new base classes, and are using the `M2_CharacterBase`, `M2M_CharacterBase` and `ABP_M2_Human` already, all you will need to resolve would be the corrupted movement component (see [#resolving-the-corrupted-charactermovementcomponent](#resolving-the-corrupted-charactermovementcomponent "mention")).

If there are parts of the old functionality that you want to reintroduce into your project, this can be done at the blueprint level. A potential example would be if you want an equivalent to "gait speeds". We have an example flow of handling this in our `M2Example` plugin - including setting the movement speed on the native Unreal `CharacterMovementComponent`, and introducing a custom anim var to replicate the state and animate it for both regular and crowd characters. See [#changes-to-gait-speeds](#changes-to-gait-speeds "mention")

### If you want to keep using the deprecated classes (only recommended as a temporary solution)

If you want to use the deprecated anim vars, there are a number of places you will need to check:

{% hint style="info" %}
These components are tightly interlinked, so we strongly recommend switching wholesale, or moving all the componets wholesale back to the deprecated classes. (e.g. if you use the deprecated character movement component, but don't update the anim instance or anim vars, some animations may be missing, or other issues will be encountered)
{% endhint %}

* In your BPM, check the `AnimVarsComponentClass`. Make sure that it extends `JM_AnimVarsComponent`, or some child of that.

<figure><img src="/files/O2sArdJNLJRM6zs7O6Fk" alt=""><figcaption></figcaption></figure>

* In your pawn, check your `Character Movement`'s details panel. Set it back to `J_CharacterMovementComponent`.\
  (If you want to keep values from before the breaking change, you will need to copy them across as outlined in [#resolving-the-corrupted-charactermovementcomponent](#resolving-the-corrupted-charactermovementcomponent "mention"), since this step will recreate the component)

  <figure><img src="/files/E6yoIsMjL6FZdjm6VyaE" alt=""><figcaption></figcaption></figure>

* In your pawn, check the mesh’s `AnimClass`. It will need to be set to an animation blueprint that extends `J_AnimInstance` instead of `M2_AnimInstance`<br>

  <figure><img src="/files/pAIVIbxDilTMD06L8iLc" alt=""><figcaption></figcaption></figure>

* Check your pawn set. In its crowd entry, it will need to point to the a `SkeletalAnimatedCrowdData` that has the right anim instance<br>

  <figure><img src="/files/SLHB8mCzSCwPiAoqeoO9" alt=""><figcaption></figcaption></figure>

## How to test it?

Open your character asset. Then PIE to verify that your character begins play, and moves as expected. If you see the `Asset had a corrupted CharacterMovementComponent` popup in either of the above steps, you will need to go through the [#how-to-fix](#how-to-fix "mention") process.

We recommend also checking the animated crowd (e.g. by testing with multiple clients and setting the`PlayerClient.Rendering.NumInLOD0` live config override to 0), to ensure that it is also animating as expected.

If you previously used the `J_CharacterMovementComponent`, and are not using it any more, you may have compile errors if calling methods that are not present in `CharacterMovementComponent`. You should also search for attempts to cast to `J_CharacterMovementComponent` in your project. If there were any, they will fail.


# Morpheus Platform Release v39.1

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 21/10/2025

{% hint style="info" %}
Please note v39.1.0 removes support for any build on v35.0.1 on Pixel Streaming
{% endhint %}

## Release notes

This release includes a number of bug fixes to release v39, alongside core bug fixes/functionality required to enable iOS support. (Further documentation can be found here: [Native iOS](/creation/running-events/player-entry/native-ios))

If you are looking to enable iOS on your project, please reach out to support.

An outline of the changes:

* iOS-specific changes:
  * Voice chat support
  * Carnival support
  * iOS 26 support
  * Add a "min spec" warning when using below 6GB RAM devices
  * Fix `M2_FileMediaSource` cook failures
  * Improve mobile boot flow & sign-in
* Apply workarounds for Nanite GPU crashes in-editor
* Fix carnival characters occasionally using an incorrect skeleton, or mounting multiple avatars.

## Known Issues

### Spurious nanite-related linter warnings

Due to the workarounds for the GPU crashes discussed in the release notes, we temporarily disable some features during map startup, and re-enable them later, following the advice in: <https://dev.epicgames.com/community/learning/knowledge-base/j2yV/unreal-engine-ue-5-5-x-most-common-rendering-issues>

This can cause warnings along the lines of:

`InstancedFoliageActor_0 Static mesh '[X]' uses Nanite but Virtual Shadow Maps are not enabled in the project settings. Nanite geometry does not support stationary light shadows, and may yield poor visual quality and reduced performance. Nanite geometry works best with virtual shadow maps enabled. See release notes.`

to be logged if a "map check" is run too soon after loading the map in editor. These warnings can be ignored, since the virtual shadow maps are re-enabled automatically, and so there will be no issues when in-game, or in-editor.

These warnings have been noticed so far only when attempting to run the Linter on maps with nanite enabled meshes, and not through normal editor use.

This issue is being tracked, and will be fixed in an upcoming release.


# Morpheus Platform Release v39

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 29/08/2025

{% hint style="info" %}
Please note v39.0.0 removes support for any build on v35.0.0 on Pixel Streaming
{% endhint %}

## Release notes

### NPC crowds

<figure><img src="/files/xVGqrSkM31DT2zNZFG9z" alt=""><figcaption></figcaption></figure>

It is now possible for your project to have crowds of NPCs which can be customised with your own models and animation. See the documentation here: [Crowds of NPCs](/creation/unreal-development/features-and-tutorials/how-to-create-a-npc-crowd).

### New default avatars

<figure><img src="/files/hs2Nj9bOp3y9ltWVljXj" alt=""><figcaption></figcaption></figure>

The default avatars have been changed to use [MSquared Avatars](https://msquared.io/products/avatars). These avatars are highly optimised for our crowd system and guaranteed to work at scale.

### Testing reconnection flow

You can now simulate players disconnecting and reconnecting, or connecting as late joiners through the `/disconnect` and `/reconnect` commands. See our [Testing Reconnection and Disconnection](/creation/unreal-development/tutorials/reference/connecting-clients-to-different-deployment-types) page for more information.

### Replicated vehicles

{% hint style="warning" %}
**Experimental:** This feature is experimental. It has not been widely tested, may be incomplete, and is subject to change at any time.
{% endhint %}

<figure><img src="/files/nifGwIYbRTbgJs0XzAYN" alt=""><figcaption></figcaption></figure>

We've added support for [replicated vehicles](/creation/unreal-development/features-and-tutorials/replicated-vehicles-experimental) within the Morpheus Platform, causing them to look physically simulated in LOD 0.

### iOS support

{% hint style="warning" %}
**Experimental:** This feature is experimental. It has not been widely tested, may be incomplete, and is subject to change at any time.
{% endhint %}

MSquared has been making steady progress towards an iOS native client, and v39 is the first version which allows deploying to iPhone. This is currently highly experimental and requires an iPhone 15 Pro or iPhone 16. If you are interested in the iOS native client, please reach out to one of your support engineers.

### Crash reports dashboard

<figure><img src="/files/jbOqune7QOLfniUiScvg" alt=""><figcaption></figcaption></figure>

We've created a dashboard which allows an organisation to see reports for any crashes that players experience. The full documentation can be found in [Crash Reporting](/creation/unreal-development/features-and-tutorials/crash-reporting).

## Known issues

### Settings menu (WBP\_M2Example\_SettingsMenu) causes PIE windows to be fullscreened

This is due to a known issue in Unreal Engine, where `ApplySettings` causes the "resolution settings" to apply, which sets the window's dimensions to your system's resolution settings. Context here: <https://epicprosupport.epicgames.com/s/question/0D5QP00001SwDgz0AF/calling-ugameusersettingsapplysettings-forces-the-dimensions-of-a-pie-window>

In Morpheus Platform v40, we have worked around this with the following: Instead of calling `ApplySettings`, in editor, you can call `ApplyNonResolutionSettings`, followed by `SaveSettings`, to apply and save all the settings *except* the resolution ones.

<figure><img src="/files/Euv7MzaPyJ9IglIeMaC5" alt=""><figcaption></figcaption></figure>

### "Welcome to the MSquared platform!" popup cannot be dismissed

The welcome popup should be dismissable, but currently comes back every time you reopen the editor, ignoring your "Don't show this again" checkbox.

<figure><img src="/files/LCcoM5FzIgnTXO2msbTq" alt=""><figcaption></figcaption></figure>

This has been fixed in the next release, but if you want to hide it before then, you can manually change the `[Your Project]/Config/DefaultEditor.ini`'s `bShowWelcomeMessage` value:

```
[/Script/M2ContentEditor.M2_TemplateCreationSettings]
bShowWelcomeMessage=False
```

NOTE: If you submit the above, it will apply to all users of your project, and so the popup won't appear for new users eithre

### Cannot remove SubscriptionUpdateListener within ListenToSubscriptionUpdares callback (KVStore)

Doing this can trigger the following ensure:

```
LogOutputDevice: Error: Ensure condition failed: CurrentNum == InitialNum  [File:C:\b\Game\Engine\Source\Runtime\Core\Public\Containers\Array.h] [Line: 256] 
LogOutputDevice: Error: Array has changed during ranged-for iteration!
```

This is being looked into. For the meantime, please avoid calling `RemoveSubscriptionUpdateListener` from within the `HandleSubscriptionUpdate` event. If you need to do this, please add at least a delay tick.

### DefaultPawnSet isn't guaranteed to be cooked

We received a report that if you set your `DefaultPawnSet` to an asset that is not referenced elsewhere in your codebase, it is not guaranteed to be cooked.

### Missing Audio Component Events

We have identified an issue with Unreal Engine 5.5 when it comes to playing audio components. After the world has initialized, the component's `OnAudioPlaybackPercent` and `OnAudioFinished` events stop playing (due to some internal failing when passing work between the audio thread and the game thread). So far we have not seen any other issues with the playing of audio, and the lack of these events can be worked around with tick behavior and delays based on the audio source's duration.

### Millicast screens

If a Millicast Screen is in a BP loaded sublevel, it's possible for the controls not to detect this screen as an option to stream to. We have updated our [documentation](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/video-players/millicast-video-streaming#known-issues) to address this.

### Graphics Settings overwritten on startup

Due to changes in how Unreal 5.5 stores changes to ini files, we've noticed that if graphical settings are changed in a project's graphics settings menu, these values are overwritten the next time the game client is launched.

This is due to the benchmarking check that should only happen on first launch. Thankfully this means the override value should be a reasonable setting for your machine, but we understand this is not ideal. A fix has been submitted and will be released in v40

## Breaking changes

### Removed OWLMediaProductionToolkit plugin

**What’s broken and why?**

The third party plugin **OWLMediaProductionToolkit** has been in the Morpheus Platform, but unused. As it is a licensed plugin, keeping it would incur significant costs and it increases our maintenance area without providing a tangible benefit.

As such, the plugin has been deleted and is no longer available.

**How to fix it?**

As the plugin has been removed, there is no workaround. If this removal causes you issues, please contact MSquared.

**How to test it?**

Check if your project loads successfully using the latest version of the Morpheus Platform.

### Removed Example Purchaseables

**What’s broken and why?**

The following classes and structs were removed:

* FAnotherPurchaseableTableRow
* UAnotherPurchaseable
* AExamplePlayer
* FExamplePurchaseableTableRow
* UExamplePurchaseable
* AExampleSingleton

These were used in C++ only internally to validate the purchasing system. No content was added that referenced these, but there is a *very* small chance someone has created a class that inherits from these test classes accidentally.

**How to fix it?**

If you have never used M2’s Currency, Transaction or User Collections it is highly unlikely you will have used these.

If you have, it is still unlikely you will have used these but check your purchaseables to ensure they don’t inherit from or reference these classes.

It is important to note that support for Transactions/Currency has been previously dropped, with large areas of it deprecated in C++. If this change does affect you, please speak to your support contact for advice on this.

**How to test it?**

Content using this should not be fixed, it needs to be migrated to use another system such as the KV Store. Support will be able to outline alternatives for you.

### Morpheus Arrays working with redirectors

**What’s broken and why?**

Morpheus Arrays in BPs will no longer have their correct inner type defaulting to integers.

This is due to a refactor in the Morpheus Arrays inner type to integrate with Unreals redirectors preventing crashes when redirected types are used as an Inner type to the MorpheusArray.

**How to fix it?**

* Find the broken BPs containing a Morpheus Array
* Re-pick their correct Inner Type.
* Re-compile the blueprint and save it.

**How to test it?**

Make sure Morpheus Arrays are working as expected and all blueprints are compiling fine.

### Replaced the example character’s footsteps logic with a simplified equivalent

**What’s broken and why?**

`BPC_Audio_MovementSystem` has been deprecated, in favor of a simplified component (outlined in <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/footsteps-audio>), along with some dependent assets. The old component and assets will still be accessible from the `M2Deprecated` plugin, but will not be actively maintained.

**How to fix it?**

If your project relies on the old `BPC_Audio_MovementSystem`, we recommend migrating across, or making a copy of the required assets in your own project.

For more details of the changes, see <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/footsteps-audio#i-was-using-the-now-deprecated-bpc_audio_movementsystem.-anything-to-be-aware-of>

**How to test it?**

Walk around in PIE. Footsteps should sound as expected.

### Moved misc assets to M2Deprecated

**What’s broken and why?**

The following folders have been moved into M2Deprecated, since they are not part of the core Morpheus Platform offering:

* `M2Content/Audio/Ambience`
* `M2Content/Audio/System/UnifiedAmbience/`
* `M2Content/Audio/System/CrowdSimulation`
* `M2Content/Geometry`
* `M2Content/InputActions`
* `M2Content/Environment`
* `M2Content/MaterialLibrary/SmartSurfaces`
* `M2Content/Props`

If you reference assets in these folders, you may get errors due to them being missing.

**How to fix it?**

If you enable the `M2Deprecated` plugin, the assets will redirect. Any assets that you depend on, we advise making local copies of and referencing in your own content, since we do not intend to support the assets long-term

**How to test it?**

Check for any errors or compilation failures - if there’s anything related to missing `Audio` assets from these folders, they can be fixed as outlined above.

### J\_CharacterMovementComponent and J\_AnimVarsComponent have been deprecated, simplifying to CharacterMovementComponent and M2\_AnimVarsComponent

**What’s broken and why?**

The following changes have been made to the `M2` character and morpheus actor, meaning that if you are using blueprints based off of those classes, you will be impacted. If you are still using the deprecated character (extending e.g. `J_` classes or `Origin` classes), you will not be affected by this:

* The existing `JM_AnimVarsComponent` has now been deprecated, in favour of a stripped back `M2M_AnimVarsComponent`.
  * The following anim vars have been removed:
    * `IsWalking`
    * `IsDoubleJumping`
    * `HasBeenLaunched`
    * `HasLowGravity`
    * `HasZeroGravity`
    * `IsMovingInLowGravity`
    * `IsThrustingUp`
    * `IsThrustingDown`
    * `IsBouncing`
    * `IsSliding`
    * `IsAiming`
  * The following anim vars have been modified:
    * `IsJogging`
    * `IsSprinting`
    * `IsInCombatMode`
    * `IsDead`
* The existing `J_CharacterMovementComponent` has now been deprecated, in favour of using the native default `CharacterMovementComponent`.
  * The following features have been removed:
    * The “Custom Movement Mode Primary Asset” system
    * Some minor helper functions, like `AddGravityMultiplier` and `AddGaitSpeedMultiplier`
  * The following features have been modified:
    * “Gait speeds”
    * “Combat mode”
  * Due to `M2_CharacterBase`'s `CharacterMovementComponent` class being changed, unfortunately assets extending it will have their component corrupted. If this affects your character, you will see the following popup when attempting to play or open your asset.

    ![image.png](attachment:e9029630-4f15-4885-adbe-1760b91553ae:image.png)

For more details on this change, see <https://docs.msquared.io/creation/unreal-development/release-notes/breaking-changes-further-details/breaking-change-details-deprecating-j_charactermovementcomponent>

**How to fix it?**

{% hint style="warning" %}
NOTE: This breaking change is best fixed with knowledge of the project prior to upgrading. If you think you may be affected by this change (if you are not certain that you are using the deprecated classes), please either check this flow before starting the upgrade, so you can make appropriate notes, or have access to a version of the project prior to the upgrade to hand, to easily compare between them.
{% endhint %}

If you are using the example plugin content as a base, or building off of the core `M2` classes, you will have one of two options:

* Use the simplified components (Recommended)
  * Using the logic in the Morpheus Plugin as reference you will be able to achieve the same functionality as was achieved via the deprecated code classes entirely in blueprints.
* Switch back to the deprecated components (only recommended as a temporary solution)

For details on these, see <https://docs.msquared.io/creation/unreal-development/release-notes/breaking-changes-further-details/breaking-change-details-deprecating-j_charactermovementcomponent>

**How to test it?**

Open your character asset. Then PIE to verify that your character begins play, and moves as expected. If you see the `Asset had a corrupted CharacterMovementComponent` popup in either of the above steps, you will need to go through the [**How to fix it?**](https://www.notion.so/How-to-fix-it-22d7560da1e38046955dcf64159738e8?pvs=21) process.

We recommend also checking the animated crowd (e.g. by testing with multiple clients and setting the`PlayerClient.Rendering.NumInLOD0` live config override to 0), to ensure that it is also animating as expected.

### AActor.bReplicateMovement replaced with MorpheusActorMovementComponent.bMorpheusReplicateMovement

**What’s broken and why?**

Morpheus no longer uses the AActor.bReplicateMovement property to determine whether movement is replicated. This field is now hidden and you should use MorpheusActorMovementComponent.bMorpheusReplicateMovement.

**How to fix it?**

For any classes that have changed the bReplicateMovement property from the default, the movement will continue to replicate as per your custom setting for this release, but you will get an error log at runtime asking you to resave your asset. This error and auto-fix will be removed in future version.

Resave all your assets that have changed the bReplicateMovement value from the default. This will fix up the bMorpheusReplicateMovement property to its previous value.

**How to test it?**

Ensure that movement is replicating property for all objects in your game.

### **Removed r.SkylightIntensityMultiplier override on low/medium graphics settings**

**What’s broken and why?**

We previously made a change to the Unreal defaults to set the `r.SkylightIntensityMultiplier` to `0.05` on Low and Medium graphics settings, which can improve visual fidelity on indoor scenes. However it can lead to very black shadows on outdoor scenes, which can look bad.

The change is to remove the override and restore the Unreal default value of `1`. Projects are free to make their own tweaks to this value based on their own lighting setups, and the default is now the same as in a vanilla Unreal project.

**How to fix it?**

To restore the previous behaviour, edit or create a file called `DefaultScalability.ini` in `<ProjectDirectory>/Config`, which will override the defaults. Add this to the file to apply the old settings (or change the values as you like):

```jsx
[GlobalIlluminationQuality@0]
r.SkylightIntensityMultiplier=0.05

[GlobalIlluminationQuality@1]
r.SkylightIntensityMultiplier=0.05
```

**How to test it?**

Test your level on Low and Medium graphics settings to ensure the lighting looks correct.

### Hidden Assets upload button behind setting

**What’s broken and why?**

There is no change unless you were already using the Assets and Releases system. If you are not aware what this system is then you can ignore this breaking change.

The assets upload button has been hidden behind a new setting that is default set to off. For projects using this functionality they will need to toggle this setting and commit the changes.

**How to fix it?**

Navigate to and enable `Project Settings` > `Morpheus Platform` > `M2 World Builder` > `Assets` > `Enable Assets Upload (Experimental)`.

**How to test it?**

You should see the assets button in the top right of your editor again.

You can also verify the change was successful by looking for the setting `bEnableAssetsUpload=True` in `DefaultGame.ini` for your project. If the setting is set here, it can be source controlled so other developers do not need to make this change too.

### Removed several unused maps

**What’s broken and why?**

The following maps have been fully removed from the platform:

* /M2Core/Content/JunoAssetLoader/Maps/ - These maps were for internal testing and no longer used
  * LevelInstanceLoader\_TestWorld
  * LevelStreamer\_TestSublevel
  * LevelStreamerUnload\_TestWorld
  * LevelStreamer\_TestWorld
* /M2Content/Maps/TestGyms/Video/M2VideoTestGym
  * The VideoPlayer asset has been deprecated and an alternative is being provided in the ExampleMap
* /M2Core/JunoActivities/Maps/TestLevel
  * Activities are already deprecated and due for removal in v39

**How to fix it?**

If you need these maps you can copy them into you project locally, but there is no good reason to given the reasons listed above.

### Deprecated BPM\_VideoPlayer

**What’s broken and why?**

The old `BPM_VideoPlayer` has now been deprecated, due to being temperamental, and very C++ driven (making it difficult for downstream users to dig into). It has now been replaced by some completely BP example content: `BPM_M2Example_SyncedVideoPlayer` and `BP_M2Example_VideoPlayerMirror`.

Since `M2Deprecated` has now been turned off by default, this means that if you were using the old video player, it will be missing until you manually enable the plugin.

**How to fix it?**

If you need the old video player, you can re-enable `M2Deprecated` as a stop-gap, but best approach would be to migrate to using the BP-only examples, or making your own.

**How to test it?**

Check for any uses of video players in your map. They should still work.

### Disabled M2 Deprecated plugin by default

**What’s broken and why?**

The M2 Deprecated plugin that contains things like the Legacy Origin and Approachability characters has been disabled by default. This content is still available in the latest release, but will need enabling to use. This has been done because MSquared no longer tests, maintains or supports this content as part of our initiative to reduce the surface area of the platform to deliver higher quality content and API’s we intend to support going forwards. Disabling this by default reduces the risk of customers using content they are unaware has been deprecated.

**How to fix it?**

If you are concerned that your project will not load correctly as there is M2 Deprecated content in your default map, you can add the following to your projects `.uproject` file to ensure it is enabled on launch.

```
		{
			"Name": "M2Deprecated",
			"Enabled": true
		}
```

Alternatively you can enable the plugin by launching the editor and ticking M2 Deprecated in **Edit > Plugins**

![image.png](attachment:090d006c-d03a-4bf7-ad63-ad3f391b854b:image.png)

We advise that you start working out a migration plan for breaking your dependency on content within M2 Deprecated. There are a number of ways of doing this:

1. Build your own base classes to replace the legacy M2 ones
2. Reparent your content to non-deprecated content in the platform
3. Migrate the desired legacy content from the M2 Deprecated plugin into your own project

Option 1 gives you the greatest long term stability and control. You will be building using our API’s directly and should be far less impacted by breaking changes by reducing dependence on shipped content.

Option 2 is a great way to get a similar level of stability but at the potential sacrifice of control, given there is a Blueprint layer between your content and underlying code. This may be a worthwhile trade-off as it does mean there could be less that you need to implement yourself if we have already provided base/example functionality.

Option 3 may well be the fastest way to keep your project functioning as expected. **This route does pose a degree of risk** as there may be BP API within the content that has also been deprecated, that you will need to replace or risk losing all related functionality. You will want to ensure all content needed (the desired content and any dependencies) has been migrated, so make sure you test by turning M2 Deprecated off from time to time.

**How to test it?**

If you are not using any content from the M2 Deprecated plugin, there is nothing to do.

If you are using M2 Deprecated content, check your content functions as expected after re-enabling.


# Morpheus Platform Release v38.1.3

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 22/08/2025

{% hint style="info" %}
Please note v38.1.3 removes support for any build on v38.1.0 on Pixel Streaming
{% endhint %}

## Release notes

This hotfix addresses an issue which was identified with **v38.1.2**.

* When using Fast Play, Mac Native clients were unable to load the pre-packaged PAK files.


# Morpheus Platform Release v38.1.2

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 08/08/2025

{% hint style="info" %}
Please note v38.1.2 removes support for any build on v34.1.1 on Pixel Streaming
{% endhint %}

## Release notes

This hotfix addresses a few issues which were identified with **v38.1.1**.

* Fixed screenshot command not working in Shipping builds.
* Made the roles list provide be an instanced object rather than a class, to avoid accidentally modifying CDOs.
* Exposed a getter for roles to enable developers to handle which provided is being used.
* Fixed a crash for Mac with WebUI due to incorrect handling of DPI scaling.


# Morpheus Platform Release v38.1.1

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 31/07/2025

{% hint style="info" %}
Please note v38.1.1 removes support for any build on v34.1.0 on Pixel Streaming
{% endhint %}

## Release notes

This hotfix addresses a few issues which were identified with **v38.1**.

* Fixed MoviePlayer causing a crash on Mac.
* Fixed the editor not correctly uploading content for Mac.
* Fixed base characters not ticking in blueprints.
* Fixed Easy Anti Cheat not being available with Shipping builds.
* Fixed mouse positions not being correct withing WebUI windows.
* Added settings to disable emote and montage cancellation on character falling.


# Morpheus Platform Release v38.1

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 01/07/2025

{% hint style="info" %}
Please note v38.1 removes support for any build on v34.0.0 on Pixel Streaming
{% endhint %}

{% tabs %}
{% tab title="Release notes" %}
**Unreal Engine 5.5.4**

The underlying version of Unreal Engine used by the Morpheus platform has been upgraded from 5.3.1 to 5.5.4.

This is a very significant upgrade, and we do recommend that users read the release notes for both 5.4 and 5.5, which are available here:

* [Unreal 5.4 release notes](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-5.4-release-notes?application_version=5.4)
* [Unreal 5.5 release notes](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-5-5-release-notes?application_version=5.5)

Not only does this upgrade provide a significant number of features and bug fixes, but it is also provides foundational improvements which will be necessary as we continue adding support for mobile.

**Improved documentation for crowd animation**

We've added documentation for the crowd animation system, including a full list of which nodes are supported in the crowd animation blueprint:

* [Crowd animation](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation)
* [User Guide - Crowd Anim Blueprint](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/user-guide-crowd-anim-blueprint)
* [Reference Guide - ABP Nodes](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes)

**Live config per plugin**

In addition to setting Live Config in your project, you can also do so on a per-plugin basis.

To do so, you could add e.g. `game.schema.json` to your `Config/LiveConfig/Schemas` folder in the plugin and it will be handled correctly.

**HUD can now be hidden**

You can now hide the HUD in the Example project by pressing `Ctrl+Alt+H`
{% endtab %}

{% tab title="Breaking changes" %}
**Separated out the pubnub text chat integration into the M2Extra**

**What’s broken and why?**

The pubnub chat system has been moved fully into `M2Extras_PubnubChat`, and is not being used in the Morpheus Platform classes. This is because the pubnub authentication is being dropped by the web platform. The authentication flow we are moving into `M2Deprecated`, and removing references to them in our example content.

The outline of the changes done is as follows:

* `BMPC_TextChatComponent` - moved to `M2Deprecated`
* A similar component: `BPMC_Pubnub_TextChatComponent` has been added to the `M2Extras_PubnubChat` plugin. This has all the “send messages through `BP_M2_PubnubConnection` logic, but has a stub for users to add their own pubnub auth.
* The `WebPlatform` logic in the `M2Extras_PubnubChat` has been moved into `M2Deprecated` (e.g. `BP_M2_SocialWorldService`)
* `BPMC_M2Example_TextChatComponent` - removed the `UsingPubnubChat` - now it will only use the local flow, and not refer to the `BPMC_TextChatComponent`

The main noticeable effect of this would be that if you were using `BPMC_M2Example_TextChatComponent`, but had `UsingPubnubChat` checked, that flow will now not work - you will default to the Unreal chat flow.

**How to fix it?**

Please switch to using the Unreal-based text chat <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat>. This should handle most in-game text chat requirements. If you need an external chat system like pubnub, please reach out to a support engineer. We have some docs on how to use the M2Extra as a starting point here: <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/communication/text-chat>

**How to test it?**

Try using text chat as intended by your experience. If you have a web based text chat, things may have been affected.

**Deprecated the `(JM)` bootflow subsystem functions (plus some others)**

**What’s broken and why?**

We have marked the following bootflow functions as deprecated:

* `HandleAuthActorSpawned (JM)`
* `HandleAuthPawnSpawned (JM)`
* `GetAuthActor (JM)`

We have also deprecated some other helpers:

* `GetM2HUD`
* `Download Image (With Cache)`

Therefore, any usage in your code will result in compiler warnings.

**How to fix it?**

Please use the advised alternative functions instead. These use the more generic base class `MorpheusPawnActor`. If you truly need the logic to use the deprecated `JM_CharacterBase`, you can cast the result.

<figure><img src="/files/6VY94MyhGBqhqZVty21n" alt=""><figcaption></figcaption></figure>

**Made Legacy UI Skinning "opt-in"**

**What’s broken and why?**

We have removed some references to our legacy UI Skinning system in our `BaseGame.ini` file, as the feature is due for deprecation and removal, and the default skin has already been deprecated. In order to eliminate spammed warnings about missing skins, we made the legacy Skinning system "opt-in".

**How to fix it?**

*If you built your project from our example content or are not using the legacy HUD or skins, there is likely nothing for you to fix.*

Launch the editor and go to **Project Settings** > **M2 UI Skins** and enable the Legacy Skinning System. Ensure your default skin is set, this will either be PDA\_Skin\_Origin (the previous M2 default) or something you have created project-side.

<figure><img src="/files/4cHW19FNrpF4EOyucH5Q" alt=""><figcaption></figcaption></figure>

This will only continue to work while we still ship the `M2 Deprecated` plugin which we plan to eventually retire. We also plan to officially deprecate the functionality of the Legacy in the near future, so it is advised customers that require UI Skinning migrate onto the [M2 Extras Skinning System](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/helpers-and-extras/m2extras-skins-system).

**How to test it?**

Check you’re able to boot into your world in PIE and see your UI.

**Removed game mode override in ControlPanelsGym**

**What’s broken and why?**

The game mode override for control panels test gym was a deprecated game mode that used the old “Origin” content. This has been removed.

**How to fix it?**

Copy the map into your project folder, then set the game mode override to BP\_GameMode (in M2 Deprecated).

Long term we plan to drop all support of control panels and the BP\_GameMode uses a character with a soon to be deprecated Roles component, so our advice is to not use this and to build your own Control Panel test content if needed, as this can no longer be relied on long term.

**How to test it?**

Check that the roles related content works in the test gym.

**Deprecated User Collections and Purchaseable systems**

**What’s broken and why?**

The following systems have been deprecated, along with any of their functionality:

* User Collections
* Purchasing/Transactions/Wallets
* Avatar Editor

This is in line with the upcoming removal of the User Collections system from the web platform, at which point these Unreal APIs will stop functioning.

**How to fix it?**

If you need these systems, or encounter any compilation warnings as a result of these systems being deprecated, please reach out to your support engineer. Our intention is to not support these systems going forwards, so you will need to migrate off of these, onto other equivalents

**How to test it?**

Your game should build fine, with no additional compiler warnings.

**Simplified `BPMC_M2Example_CrowdAudioComponent`**

**What’s broken and why?**

We have cleaned up the example crowd audio implementation (`BPMC_M2Example_CrowdAudioComponent`) so that it no longer copies across all the functions from the deprecated `BPMC_CrowdAudio`. These functions were not used by example content, so would only break if the functionality was used in a downstream project that is attempting to use the deprecated functionality.

The main changes of note:

* The old functions to enable/disable voice e.g. `InformMicrophoneButtonPressed/Released`, `SetPushToTalkMode`, `StartLoudspeakerRequest` etc. have been removed. Instead we use the base `CrowdAudioComponent`'s functions directly, e.g. `SetVoiceInputEnabled`. We no longer support both push to talk and toggle. We only have push to talk in our default UI, but toggle could be implemented in downstream logic via the `SetVoiceInputEnabled` function
* The “manually muted” logic has been removed, since it is unused
* The “choppiness detection” logic has been removed, since it is unused
* The `GetCanUseVoice` logic based on capabilities and moderation has been removed, but could be reimplemented downstream in the simplified `CanUseVoice` function.

**How to fix it?**

Any deprecated logic that is depended on should be fixed up, either by writing equivalents in project code, or switching the functions used.

If the deprecated functions are definitely needed in the downstream project, the deprecated `BPMC_CrowdAudio` is still present, and can be used as an off-ramp.

**How to test it?**

PIE - if there are any compile errors relating to usage of `BPMC_M2Example_CrowdAudioComponent`, they will need to be cleaned up.

**Deprecated functions in M2M\_PartyComponent**

**What’s broken and why?**

Previously we had messaged that we were dropping support for parties in Unreal, but had not actively deprecated the functions used by `BPMC_PartyComponent` . That has been handled now, meaning `BPMC_PartyComponent` or any other class using functions from `M2M_PartyComponent` will give a compiler warning in Blueprints. The Unreal-to-web party functionality was deprecated and removed several versions ago leaving only basic party management which is implementable by anyone with Unreal experience.

**How to fix it?**

Firstly you need to remove `BPMC_PartyComponent` from any characters you wish to continue using. Then you will need to create a new party system to use in it’s place if this functionality is desired.

If you are unsure of how to build a party system, please reach out to your support engineer for guidance. We also have documentation on how to use broadcasting channels to allow users to voice chat with specific users, which can help build a “party chat” system <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/spatial-audio#broadcast-channels>

**Live config functions and console commands renamed (no longer JunoGameData)**

**What’s broken and why?**

Nothing broken, just a callout: The live config helpers and console commands have been renamed, to get rid of the out of date `Juno Game Data` name. The following renames have happened:

* Console commands: `JunoGameData.GetValue`/`SetValue`,`ClearOverride` → `M2.LiveConfig.GetValue`/`SetValue`,`ClearOverride`
* `GetGameDataAttributeValueAsString`/`Integer`/etc. → `GetLiveConfigValueAsString`/`Integer`/etc.

**How to fix it?**

No changes necessary! The functions and console commands will all redirect, just be aware of the new names going forwards.

**Launch Context removal from Live Config and Domain Configuration Subsystem**

**What’s broken and why?**

Launch Contexts are not a user-facing concept and have been removed from the editor. The final change in this initiative is to remove LC from the domain configuration subsystem. This means content responding to the following live config variables will need to be changed:

* (deployment.json) `Client.OverrideLaunchContextId`.

Existing systems and APIs have already been updated to use World so in most cases, LC can be replaced with World usage.

Additionally, the following UProperties have been removed:

* (M2\_UserDataStore) `LaunchContextId`.
* (M2\_WorldConnectionApi) `LaunchContextId`.
* (M2\_DomainConfigurationSubystem) `LaunchContextId`.
* (M2\_DomainSettings) `LaunchContextId`.

**How to fix it?**

* Replace usages of `Client.OverrideLaunchContextId` with `Client.OverrideWorldId`
* Replace `LaunchContextId` UProperties with `WorldId`

Reach out to support if this does not resolve the issue.

**How to test it?**

* Check that the BPs recompile.
* Test that the system works as expected.

**The boot-flow no longer blocks on having a player profile**

**What’s broken and why?**

We are changing how user profiles work in MSquared. One part of this is that we are making the current user profiles system (the Profile Data Profiler class) optional, and so we no longer block in the boot-flow on the profile system loading a profile.

All existing MSquared logic is unaffected by this change, but there is a small chance that downstream project logic could encounter a race condition, if they attempt to get the profile early on in the bootflow (immediately after HandleBootflowStarted is satisfied), where they expect the profile to be ready, but it is not yet.

**How to fix it?**

If you have such logic, that expects the profile be ready early in the bootflow without checking (e.g. startup logic that happens before your character is spawned), it would be best to check that the profile is ready before attempting to use it. We have one such example implementation in `BPMC_M2Example_PlayerNameComponent`

<figure><img src="/files/rrgOR0XUewqSmNUij0Sa" alt=""><figcaption></figcaption></figure>

**How to test it?**

Begin Play - all your custom logic that depends on the local player’s profile (e.g. find references to “profile data provider” in your codebase) should successfully get the profile when expected to.

**Moved Carnival GetFromAssetId functions into UCarnivalWorldSubsystem**

**What’s broken and why?**

Two static functions have been moved into a subsystem, to fix an issue with tracking meshes:

`CarnivalSkeletalMesh::GetFromAssetId` → `CarnivalWorldSubsystem:: GetSkeletalMeshFromAssetId`

`UCarnivalStaticMesh::GetFromAssetId` → `CarnivalWorldSubsystem::GetStaticMeshFromAssetId`

**How to fix it?**

Replace any calls to the `GetFromAssetId` functions with the corresponding on the CarnivalWorldSubsystem.

<figure><img src="/files/x5ZjIHax8If1ocytY9cy" alt=""><figcaption></figcaption></figure>

**How to test it?**

Blueprints will compile and function as before.

**Removed LC from web platform utilities**

**What’s broken and why?**

Requests made to the web platform now all use world context. Launch contexts have been phased out and launch context utilities have been removed.

Additionally, the enum value `EM2_HttpRequestScope::LaunchContext` has been removed.

**How to fix it?**

Replace the utilities and values that no longer exist:

* `Get M2 Web Platform Launch Context ID` > `Get M2 Web Platform World ID`
* `EM2_HttpRequestScope::LaunchContext` > `EM2_HttpRequestScope::World`

**How to test it?**

After making the replacements above, re-test your feature. If it still does not work, reach out to support.

**Removed unused singletons from singletons list**

**What’s broken and why?**

The following deprecated singleton classes have been removed from the named singletons list in the world settings:

* `ActivityManagerClass` (A deprecated system for tracking participants in “activities”, and loading appropriate sublevels)
* `DataProviderSingletonClass` (A system for providing data to UI that was never used)
* `EffectManagerClass` (A deprecated system for spawning gameplay effects, see uses of `FAS_[X]` assets or `BP_[X]ApplicatorSettings`)
* `UserTagManagerClass`
* `PartyManagerClass`

Before:

<figure><img src="/files/cMfh6ZKpsLlK0Fnun2TO" alt=""><figcaption></figcaption></figure>

After:

<figure><img src="/files/DjKX1zj0AlNdPmWITBUY" alt=""><figcaption></figcaption></figure>

In deprecating the user tags content, we have also removed the DT\_M2\_UserTags reference from the GameplayTagTableList, but this can easily be re-added downstream if needed:

<figure><img src="/files/z3G62W0Jjj94kXVNKDth" alt=""><figcaption></figcaption></figure>

**How to fix it?**

If you need any of the removed singleton classes, they can be re-added in your level using the `AdditionalSingletons` list:

<figure><img src="/files/l1US4hfOvPj5lbqXfk5Z" alt=""><figcaption></figcaption></figure>

**How to test it?**

Your gameplay systems should behave as before, with no additional warnings related to missing singletons/systems

**Modified the GetJsonObjectAtLocation function**

**What’s broken and why?**

The `GetJsonObjectAtLocation` function has had its nodes changed, so that instead of logging warnings and outputting a bool, it uses different execution pins for the assorted outcomes. This enables users to more clearly see the various failure cases and handle accordingly (instead of e.g. always warning if the object doesn’t exist, where it may actually be optional)

<figure><img src="/files/GETN83j2yLjqeEWBUC0P" alt=""><figcaption></figcaption></figure>

**How to fix it?**

Any nodes that fail to compile should be updated as in the screenshot above

**How to test it?**

Your logic should compile successfully.

**Removed deprecated behaviors from `BT_BotBehaviour`**

**What’s broken and why?**

The bot “roles” and “interact” behaviors have been removed from the `BT_BotBehavior`, since the functionality they were testing has been deprecated.

<figure><img src="/files/GwdbOa0CshMlNbNuY6m5" alt=""><figcaption></figcaption></figure>

**How to fix it?**

If you referred to `BT_BotBehavior` and specifically want to test these two behaviors in your “full” behavior, you will need to add them manually to your Behavior Tree.

**How to test it?**

PIE - your BT should perform the behaviors you want it to.

**Removed Launch Context from world travel structs**

**What’s broken and why?**

Users will be unable to perform local PIE world travel when using deprecated world travel content (BPs and WBPs)

World travel structs no longer have a launch context field. As a result, the previous logic of attempting to use the launch context and falling back on the world or map has been replaced with logic where the world or map names are used directly.

This will have no effect for deployments and everything should work as expected even if using deprecated world travel content

**How to fix it?**

Use non-deprecated world travel engine content

**How to test it?**

Perform PIE world travel

**Changed Carnival memory usage live config into a CVAR**

**What’s broken and why?**

The `Carnival.StreamClientTargetMaxInMemoryBytes` live config value was used to specify how much crowd model data should be cached in memory. This has been changed to a scalability CVar `r.CarnivalStreamClientMaxInMemoryMB` so it can be set independently for different client hardware. The default value of 512 is the same as previously.

**How to fix it?**

If you’ve modified the `Carnival.StreamClientTargetMaxInMemoryBytes` live config default for your project you should instead add the CVar into your project’s `<project>/Config/DefaultConsoleVariables.ini` file with the same value. Example file contents:

```jsx
[WorldBuilder]
r.CarnivalStreamClientMaxInMemoryMB=512
```

**How to test it?**

Crowd rendering should behave as before with the same memory usage.
{% endtab %}

{% tab title="Known issues" %}
**M2M\_CharacterBase not receiving tick**

We have identified a bug with our `M2M_CharacterBase` which means that children of the class will not receive the tick event in BP. This has been fixed now, and will be in the next release.

In the meantime, we recommend working around the issue by e.g. using a looping timer

<figure><img src="/files/yoifrYJhZgEewnfXiV27" alt=""><figcaption></figcaption></figure>

**DefaultPawnSet isn't guaranteed to be cooked**

We received a report that if you set your `DefaultPawnSet` to an asset that is not referenced elsewhere in your codebase, it is not guaranteed to be cooked. If this affects you, you will get errors along the lines of:

`LogStreaming: Warning: LoadPackage: SkipPackage: /VaultCore/Core/Base/[Your DA_PawnSet] (0xF739E326EC32E612) - The package to load does not exist on disk or in the loader`

We are investigating this, and will work on a fix. In the meantime, if you encounter this issue, you can resolve it by adding a reference to your pawn set in your cooked content, e.g. by adding a variable that is set to your pawn set

<figure><img src="/files/RK7MFVBGz8SsgqF0Wspx" alt=""><figcaption></figcaption></figure>

**Control Panels don't work on native mobile**

We have identified that control panels don't work on native mobile. They still work fine on streaming mobile, and on PC/Mac. We don't expect this to have significant impact, given control panels are intended for specialist use, and not for general participants. If you expect this to impact your project, please reach out to support.

**Crash when using Movie Player on Mac native**

We have identified a crash with Unreal Engine 5.5 when using movie playback on Mac native. The client will immediately crash when attempting to play a video.

We are currently investigating the issue and will provide a hotfix as soon as possible.

**Missing Audio Component events**

We have identified an issue with Unreal Engine 5.5 when it comes to playing audio components. After the world has initialized, the component's `OnAudioPlaybackPercent` and `OnAudioFinished` events stop playing (due to some internal failing when passing work between the audio thread and the game thread). So far we have not seen any other issues with the playing of audio, and the lack of these events can be worked around with tick behavior and delays based on the audio source's duration.

<figure><img src="/files/4LQR9TnqvLS7b2MtcHhP" alt=""><figcaption></figcaption></figure>

**Graphics Settings overwritten on startup**

Due to changes in how Unreal 5.5 stores changes to ini files, we've noticed that if graphical settings are changed in a project's graphics settings menu, these values are overwritten the next time the game client is launched.

This is due to the benchmarking check that should only happen on first launch. Thankfully this means the override value should be a reasonable setting for your machine, but we understand this is not ideal. A fix has been submitted and will be released in v40
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v37

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 23/05/2025

{% hint style="info" %}
Please note v37 removes support for any build on v33.0.3 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Release notes" %}
{% hint style="warning" %}
**IMPORTANT NOTICE**

We currently expect **v37 to be the final major release before MSquared transitions to Unreal 5.5**, which is anticipated to bring significant improvements.

To minimize disruption, we strongly recommend **upgrading your project to v37** in preparation for this change.
{% endhint %}

**Performance guarantees**

Our platform undergoes regular scale tests, and we are now publishing our [Performance Guarantees](https://docs.msquared.io/creation/unreal-development/tutorials/upgrade-the-editor/release-notes).

**New Unreal-based text chat**

A new, less complex text chat solution which works at scale and does not require PubNub is now available: <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat>

**Embedded browser now works on Mac**

Support for WebUI on native clients has been expanded and it will now work on Mac, rather than just Windows.

**Embedded browser logs to UE stdout**

Debugging issues with the embedded web browser was challenging as it was not displaying any logging information when an issue occurred inside the browser process. These logs have been redirected and will display in Unreal's console / log files as expected.

**UserID Tracker Subsystem**

Regularly MSquared users needed to keep lists of clients who are involved in some gameplay functionality and needs to account for players reconnecting to the deployment. Maintaining a list of MAs wasn't sufficient as the client would be allocated a new MorpheusActor when they rejoined. To remove the need of each project having to roll out its own map between user IDs and MorpheusActors, we have a new subsytem which will do this for you: <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/helpers-and-extras/the-user-id-replication-component#userid-tracker-subsystem>

**Quality of life improvements**

There's a large number of quality of life tasks which have been done for this release, which should lead to a more streamlined experience inside Unreal. Among them are:

* Unreal Editor will now only require a single login.
* The new map modal has been cleaned up.
* Bot behaviors are now easier to set up.
  {% endtab %}

{% tab title="Breaking changes" %}
**UX Subsystem delegates rename and function signature changes**

**What’s broken and why?**

We have removed references to launch context from the World Builder UX Subsystem in favour of using world Id.

The following blueprint exposed functions, delegates and variables have been renamed:

* `OnLaunchContextQueryHandled` > `OnWorldQueryHandled`
* `OnBeginLaunchContextImageDownload` > `OnBeginWorldImageDownload`
* `OnLaunchContextInfoUpdated` > `OnWorldInfoUpdated`
* `LaunchContextDescription` > `WorldDescription`
* `LaunchContextName` > `WorldName`
* `UpdateLaunchContextInfo` > `UpdateWorldInfo`

The following function signatures have also been changed:

* `UpdateWorldInfo`
  * ➖ OrganizationId (FString)
  * ➖ ProjectId (FString)
  * ➖ LaunchContextId (FString)
  * ➕ WorldId (FString)

**How to fix it?**

Users should search for all occurrances of the old named functios, variables and delegates usage and resolve any blueprint compilation errors by making replacements according to the mapping above

**How to test it?**

You will know when your blueprints are compiling again

**Removing SetAnimatedCrowdIsHidden function**

**What’s broken and why?**

`SetAnimatedCrowdIsHidden(...)` blueprint callable function to locally check hidden status for crowd on a morpheus actor has been removed.

**How to fix it?**

Use the blueprint callable function `SetHiddenLocally(...)` of `UMorpheusActorRenderTargetComponent`

**How to test it?**

Calling `SetHiddenLocally(...)` and `IsHiddenLocally()` instead of `UMorpheusActorRenderTargetComponent` will change the local visibility of the morpheus actor, regardless of the render target.

**Deleted Unused Loudspeaker Prop “BP\_LoudspeakerVolume\_VisualFeedback”**

**What’s broken and why?**

The asset `BP_LoudspeakerVolume_VisualFeedback.uasset` has been removed from the M2 Example plugin as it contained multiple references to deprecated content and was overly complex as an example of using the global audio channel.

**How to fix it?**

If you require specific functionality from this prop, copy it into your project or use `BP_LoudspeakerVolume_MicStand_VisualFeedback` in M2 Deprecated.

Otherwise we have `BP_LoudSpeaker_Example` which can be found in the Example Map which is a more up to date and simplified example of how to implement this functionality.

**Changing UserID Tracker Subsystem from a GameInstance subsystem to a World Subsystem**

**What’s broken and why?**

The getter for the UserID Tracker Subsystem as a `GameInstance Subsystem` will no longer work.

**How to fix it?**

Change the getter for the UserID Tracker Subsystem to get it as a `World Subsystem` instead.

**How to test it?**

Ensure that the `Get World Subsystem` node returns the UserID tracker subsystem correctly and that the UserID Tracker Subsystem is tracking users as expected.

**Removed unused Niagra System “NS\_CombatTest\_NDC\_Beam”**

**What’s broken and why?**

The “NS\_CombatTest\_NDC\_Beam” particle system we were not using has been removed from our content.

**How to fix it?**

Duplicate the asset and fix up references if needed. If you have not created your own assets using our particles, it is highly unlikely this will affect you as there were not references to the asset in our codebase.

**Removed unused PlayerController “BP\_M2\_PlayerController”**

**What’s broken and why?**

Created and never used, this has been replaced by `BP_M2Example_PlayerController` in our example content.

**How to fix it?**

It is unlikely you will have referenced this asset, but if you have either duplicate this into project space before taking the update or re-base onto `BP_M2Example_PlayerController` .

**How to test it?**

Ensure functionality remains intact

**Changed Launch Context as the pubnub channel name to World Id**

**What’s broken and why?**

We have renamed the live config variables and default channel naming behaviour in order to use the worldId:

* `Social.Chat.LaunchContextId` → `Social.Chat.World`
* `Social.Chat.LaunchContextSource` → `Social.Chat.WorldSource`
* `Social.Chat.Editor.LaunchContextId` → `Social.Chat.Editor.World`
* `Social.Chat.Editor.LaunchContextSource` → `Social.Chat.Editor.WorldSource`

The pubnub channel will now be named `<world Id>` and will use the value found in the domain settings at runtime by default for both editor and deployments.

*We recommend you use these settings unless you need to specify a specific channel name for use as it gates chat by the world that is being used and allows pubnub chat to be used in editor with no additional configuration.*

The `WorldSource` (previously `LaunchContextSource`) options have been changed to:

* `LiveConfig` - Changeable at runtime for ALL players in a world
* `CommandLine` - Static at runtime and set when the client is launched
* `Domain` - (default) Changeable at runtime for each client

**How to fix it?**

If users have not previously modified the live config variables listed above in the following files then nothing needs to be done.

* `M2LiveConfig/Config/deployment.schema.json` - Check for var modifications
* `<project>/Config/LiveConfig/Overrides/deployment.override.json` - Check for var existence

If you have previously modified the live config variables, you will need to modify the `WorldSource`\
value to one of the below, depending on your usecase

* Empty or `Domain` - this will set the pubnub channel name to your local world ID. To use this, you must have "Use Local World in PIE" enabled in your editor's sign in settings
* `LiveConfig` - will grab the `world` value from live config (e.g. the one set at `Social.Chat.Editor.World`
* `CommandLine` - will grab the CLI launch arg worldId value (least likely to be used)

If any modifications have been made, please tranfer the values set in the old live config variables to each equivalent new variable according to the mapping above.

**How to test it?**

Launch a deployment or PIE and send a message. If the message is successfully sent the sender will see it appear in the chat widget and this has been successful.

**Renamed the web platform world services**

**What’s broken and why?**

We have renamed the MSquared world service classes, to better match our conventions:

* `BP_M2_WPKeyValueStoreService` → `BP_M2_KVStoreService`
* `BP_M2_WPProfileDataProvider` → `BP_M2_ProfileDataProvider`
* `BP_M2_WPRoleDataProvider` → `BP_M2_RoleDataProvider`

The references have been fixed up, and the world settings’ default config has been updated MSquared-side. However, If you modified the world service classes in your project’s own config, referencing the old names, they will need to be updated

**How to fix it?**

If you see missing classes in your world settings, check for the old file names in your project’s config and update them, or alternatively select the right files in the dropdown.

If you modified the world service classes in your project’s own config,

**How to test it?**

Go to your world settings, and search for “services”. The three named world services should still be present.

<figure><img src="/files/arB3N4gyFKc64S9jpTvi" alt=""><figcaption></figcaption></figure>

**Flipped bCheckIfRolesDataTableIsValid to “false” by default**

**What’s broken and why?**

This is unlikely to affect most projects. If you are still using the legacy Roles (now located in the `Morpheus Platform - Deprecated|Roles` section of our World Settings), which we deprecated in a previous release, you will find the default value of `bCheckIfRolesDataTableIsValid` has changed from True to False. This is because we no longer require this check in the currently supported Roles system and leaving this legacy setting enabled could cause confusion when warnings are given to customers using the new system.

**How to fix it?**

Go to `Morpheus Platform - Deprecated|Roles` in the affected map and change `bCheckIfRolesDataTableIsValid` to True.

**How to test it?**

Warning should be given if no Roles table provided

**Disabled email-based fallback sign in**

**What’s broken and why?**

Previously we were able to use multiple methods of signing in, but now the only accepted method of authentication is SSO. We had a widget that would pop up on failed sign in that would give the option to sign in with email or password. Now this option is not provided and if SSO fails, users will not be able to enter via alternative means.

**How to fix it?**

There is no fix for this. If this is required functionality, please reach out.

**Replaced references to BPM\_VideoScreen in BP\_MillicastCapture**

**What’s broken and why?**

Under Scene Capture > Show Only Actors in BP\_MillicastCapture we no longer use BPM\_VideoScreen, having replaced it with the non-deprecated BPM\_VideoPlayer asset.

**How to fix it?**

If you use BPM\_VideoScreen still, you will need to re-add this to your list of actors to be shown. This can be done on instances of your BP\_MillicastCapture or a locally modifiable duplicate of this asset.

**How to test it?**

Confirm functionality remains as before.

**Deprecated old “user data” and Key Value/persistence APIs**

**What’s broken and why?**

The following systems have been deprecated, in favour of our single KV Store system (<https://docs.msquared.io/creation/unreal-development/features-and-tutorials/online-services/kv-store-service>):

* UserDataStore
* WebPlatformKeyValueStoreService (not to be confused with the still present `M2_KeyValueStoreWorldService`, renamed to `M2_KVStoreService`)
* `M2_PersistenceSubsystem`
  * Since we are no longer using this system, the now irrelevant bootflow steps `HandleUserDataReady` and `HandleInitialValuesReceived` have been deprecated too.

**How to fix it?**

Please move to the new system as soon as convenient. Your existing logic won’t break, but you will get compiler warnings, and you won’t be able to use the deprecated nodes past their current usage in your project.

If you were using the persistence subsystem, we have a guide for ease of migration: [My project is using the now-deprecated Persistence Subsystem. How can I migrate across?](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/online-services/kv-store-service#my-project-is-using-the-now-deprecated-persistence-subsystem.-how-can-i-migrate-across)

**How to test it?**

Your logic does not have compiler warnings for using the old systems

**Changes to the KV Store implementation**

**What’s broken and why?**

There have been a few changes to the example KV Store service (`BP_M2_WPKeyValueStoreService`) and its related files, that would require some attention, if it is currently being used:

* `SM2_WP_KvStoreObject` has been removed, and `SM2_WP_KvStoreReadItem` has been updated to treat the `object` as a generic Json Object.

  * This makes the struct more flexible, supporting other json value types, rather than just `JsonObject` for the fields within the `object` field, e.g. `Data`

  <figure><img src="/files/SVw007BLKe1j5IPdxwna" alt=""><figcaption></figcaption></figure>
* We now no longer reject “non-json” string values, instead treating them as “json string values”. e.g. a string `Hello` will now be treated as the json value `"Hello"`, rather than being rejected.
  * This improves the UX for generic KVStore usage, enabling stores more akin to `Store(”KeyName”, “ExampleValue”)`, rather than needing `Store("KeyName", { "Value": "Examplevalue"})`

**How to fix it?**

* If you referenced `SM2_WP_KvStoreObject`, or `SM2_WP_KvStoreReadItem`, please update your logic accordingly, e.g. by following the example in `BP_M2_WPKeyValueStoreService::ParseReadResponseItem`

<figure><img src="/files/cagfMeEGHUPE5DPeYjhn" alt=""><figcaption></figcaption></figure>

* If your logic depended on non-json strings being rejected, please update the `KVStoreServiceClass` to a custom implementation of your choice, using `BP_M2_WPKeyValueStoreService` as a starting point

<figure><img src="/files/rN68g7WXlevjLHpzkDqO" alt=""><figcaption></figcaption></figure>

**How to test it?**

Everything should compile correctly

**Example Moderation Component now uses Example Crowd Audio Component**

**What’s broken and why?**

Previously `BPMC_M2Example_ModerationComponent` used our legacy Crowd Audio component (`BPMC_CrowdAudio`) when sending transcripts to a moderator. As we are simplifying the CrowdAudio component but want to leave the legacy version intact, we have replaced the reference here to `BPMC_M2Example_CrowdAudioComponent` .

**How to fix it?**

This issue will only affect users that are using `BPMC_M2Example_ModerationComponent` with a legacy character class, or that still use the `BPMC_CrowdAudio` .

If you use `BPMC_CrowdAudio`, you will need to duplicate `BPMC_M2Example_ModerationComponent` replace all references to `BPMC_M2Example_CrowdAudioComponent` with `BPMC_CrowdAudio` and then replace your moderation component with this duplicated and modified version.

It should be noted that we will not be maintaining `BPMC_CrowdAudio` any further, so if you want a higher level of support it is recommended you switch to the example component as the legacy one will be removed when the M2 Deprecated plugin is removed.

**How to test it?**

Ensure moderation functionality is maintained after following the above steps and you are still able to receive transcriptions.

**Removed Interaction widget from Example HUD**

**What’s broken and why?**

The Example HUD created when starting a new project from a template no longer features the deprecated Interaction widget. This will also affect anyone directly using the engine version of `WBP_M2Example_HUD`

**How to fix it?**

We highly recommend you do not use the M2 Interaction system as this is deprecated. If you are dependent on this and relied on it in this HUD, you will need to re-add the `M2Deprecated/M2Core/M2ObjectInteraction/WBP_M2_FullInteractionMenu` widget to your HUD

**How to test it?**

Ensure that desired interaction functionality is still present

**Changed AutoProfiler SessionData Fields**

**What’s broken and why?**

Previously, all `ActorCommandExecutorTasks` in the AutoProfiler SessionData would be called with the same optional parameter. This meant that Carnival would attempt to load avatars with the name of sublevels to load and the world would attempt to load a sublevel with an MML URL. Now the SessionData requires the specific task and parameter for each `ActorCommandExecutorTask`. The original “Optional Parameter” field has been removed in order to improve this.

**How to fix it?**

`ActorCommandExecutorTasks` in any AutoProfiler SessionData assets will need to be reconfigured by filling in the new fields.

<figure><img src="/files/N9mHIi8p9rQxlL4iQrnj" alt=""><figcaption></figcaption></figure>

**How to test it?**

The AutoProfiler should function as expected prior to this change and should not interfere with other `ActorCommandExecutorTasks` .

**Removed the world travel portal from `WorldTravelDestination_P`**

**What’s broken and why?**

The `WorldTravelDestination_P` test map has had its world travel portal removed. This is because it used the now deprecated interaction system, and the map has been updated to use the simplified character, which doesn’t use said system. This means that if you do try and access that world, you will not be able to world travel using the portal

<figure><img src="/files/cx8wxICv4w6ssBn7qvuU" alt=""><figcaption></figcaption></figure>

**How to fix it?**

In the unlikely case that you were using `WorldTravelDestination_P`, you will need to use alternative approaches to world travel out of the map. e.g. instead of interacting with the world travel portal, you can instead use the `WorldTravel.TravelToWorld [WorldId]` console command

**Removed Walk binding from IMC\_CharacterMovement**

**What’s broken and why?**

As we no longer have a walking animation in our default Animation Blueprint, we have removed the corresponding key binding

**How to fix it?**

You will need to use an Input Mapping Context in your project that maps IA\_CharacterWalk to an input (previously the Ctrl keyboard button)

**How to test it?**

Implement the above and ensure character moves as expected when button is used

**Get BPCharacter removed from ABP\_M2\_Human.uasset**

**What’s broken and why?**

The function “Get BPCharacter” in ABP\_M2\_Human is no longer available. It has been removed as there are no references to it within the Morpheus Platform and it’s presence creates a dependency on deprecated content.

**How to fix it?**

If you rely on this within the default ABP you can either duplicate the asset to preserve your current version, or duplicate the new version and add the following:

<figure><img src="/files/R5ENxUMDl9vbEuHNvnIN" alt=""><figcaption></figcaption></figure>

Please not that due to the lack of Child ABP’s, duplicating this asset means you will have to repeat this any time you wish to take further ABP updates from our default class.

**How to test it?**

Follow the steps above if applicable and ensure functionality is consistent.

**Analytics BP API Removed**

**What’s broken and why?**

Analytics API that was deprecated in v34 has now been removed in full. Please see the [release notes on v34](https://docs.msquared.io/creation/unreal-development/tutorials/upgrade-the-editor/release-notes#m-platform-release-v34.1.1) for further information.

**How to fix it?**

Customers are expected to replace any usage of this API with their own analytics integration. See <https://docs.msquared.io/integrations/3rd-party-analytics#setting-up-mixpanel-analytics> for an example integration.

**M2 Human ABP simplified and multiple states removed**

**What’s broken and why?**

The base ABP for M2 projects, ABP\_M2\_Human, has been reworked, resulting in a more streamlined ABP with improved combat animations using assets from Lyra and less custom M2 behaviour overall.

The following functionality has been removed from the ABP:

* Double jump
* Walking
* Launch
* Low gravity
* Bounce
* Zero G
* Non-combat head turning
* Multiple random idle animations

The old ABP is now ABP\_M2\_Human\_Old in the Deprecated plugin.

**How to fix it?**

If your project relied on the above removed animation behaviour, you can temporarily set your characters to use the ABP\_M2\_Human\_Old ABP (in the Deprecated plugin) instead. This will be removed in a future release, so if you rely on this behaviour, we recommend copying the logic you rely on from this old ABP to your own ABP class.

**How to test it?**

Test all your gameplay and observe whether the animations are behaving as expected.

**Check replicability of blueprint properties at compile time**

**What’s broken and why?**

In the blueprint editor, it’s possible but erroneous to mark an Event Dispatcher as “Replicated”. That causes an Ensure to fire in PIE, and maybe in standalone.

This change makes that mistake visible by introducing a blueprint compile error.

**How to fix it?**

Disable replication for Event Dispatchers in blueprints.

**How to test it?**

Only affects blueprint compilation - if everything cooks then all is well.

**Removed AudioControls and AudioMixManager from default Singletons**

**What’s broken and why?**

The Audio Controls Class and Audio Mix Manager Class is no longer present in the default Singletons list in World Settings. This is because we are deprecating the BP content used for these.

<figure><img src="/files/lbcWDpxd4AKyI5uaoT5C" alt=""><figcaption></figcaption></figure>

**How to fix it?**

You will need to add `BPM_AudioControls` and `BPM_M2_Audio_MixManager` as additional singletons to your World Settings for any map you intend to use these in.

**How to test it?**

Ensure your world still has access to this functionality after adding them manually.

**Crowd audio changes to schema and removal of echo cancellation and dynamic occlusion**

**What’s broken and why?**

* Echo Cancellation has been removed as an option from crowd audio settings.
* Dynamic Occlusion has been removed as an option from crowd audio settings.
* PreprocessorSettings has been split into NoiseSettings and VolumeNormalisationSettings.
* Some ObserverSettings have been separated into OcclusionSettings.
* Some parameters have changed their category in LiveConfig.

**How to fix it?**

Echo cancellation and dynamic occlusion are no longer supported features. It’s unlikely your project was using them in a noticeable way, but if they were, please reach out to @Samuel Silvester.

If your project has any live config overrides to crowd audio settings, check the latest morpheus.schema.json to make sure your live config overrides still match the schema. Make sure that your editor sessions run without any schema warnings or errors, or your live config overrides will not be respected.

If your project has modified any crowd audio settings in BPs, double check to make sure these are still applied correctly.

**How to test it?**

Run editor sessions and ensure no live config errors or warnings are output.

Ensure that the crowd audio in your world is still functioning as intended.
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v36

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version released:** 20/03/2025

{% hint style="info" %}
Please note v36 removes support for any build on v32.1 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Release notes" %}
**Static MML rendering with Carnival**

MML geometry can now be rendered at scale using **Carnival**, unlocking new possibilities such as:

* **Configurable per-model parameters**, including LOD levels, custom depth settings, and more.
* **Trigger volumes** for handling overlapping events.
* **Optional physics interactions** and visibility to raycasts.

**UE basic name and chat moderation**

Basic Unreal chat and nameplate moderation is now included in example assets, and are both turned on by default. Unreal chat moderation is configurable by setting the game live config value "EnableBasicModeration" to true or false. You can also find a list of profanity that is moderated out in live config, and tweak these to your needs.

Nameplate moderation uses the same profanity list, and can be turned on and off via the Settings Menu blueprint (you will need to make your own copy of `WBP_M2Example_SettingsMenu` in the content folder and adapt this).

**Enable Spatial Crowd Audio muting**

Spatial Crowd Audio can now be **globally muted**.

{% hint style="warning" %}
Please note that it is not possible to mute an individual in the crowd.
{% endhint %}

**Visual fixes for scaled characters**

Fixes have been implemented for **incorrect rendering of large-scaled characters**, which previously caused:

* Clipping through the landscape.
* Incorrect normal maps.
  {% endtab %}

{% tab title="Breaking changes" %}
**Observer Control singletons no longer default M2 Singletons**

**What’s broken and why?**

As we move to turning off the M2 Deprecated plugin by default, we are removing dependencies on legacy content. Our Observer role is scheduled to be simplified, but currently it is tied to the legacy classes which means it cannot be a default singleton. Specifically the control panels often used in this mode will not be available and you will see the following logs:

`LogBlueprintUserMessages: [BP_ObserverPawn_C_0] Observer Camera Control Panel isn't present in the level! Keybinding will not work.`

`LogBlueprintUserMessages: [BP_ObserverPawn_C_0] Observer HUD Control Panel isn't present in the level! Keybinding will not work.`

**How to fix it?**

The following needs to be done for any map in which you want to use the Observer role.

1. Navigate to World Settings
2. Search for Additional Singletons
3. Add the required Singletons
   1. BPM\_ObserverCameraControls
   2. BPM\_ObserverHUDControls

<figure><img src="/files/EwGr5UrvOWnQAzXjaVNk" alt=""><figcaption></figcaption></figure>

**How to test it?**

Ensure Observer functions as expected.

**USkeletalCrowdMeshStore removed**

**What’s broken and why?**

`USkeletalCrowdMeshStore` and `UJ_ModularCrowdMeshStore` types have been removed.

These were previously optional but deprecated. This change removes support for them in an effort to clean up and simplify the `USkeletalAnimatedCrowdData`.

`USkeletalAnimatedCrowdData::DefaultMeshIndices` has also been removed. It was generally unused and no longer makes sense in context.

**How to fix it?**

Any existing mesh store assets should now be deleted.

`USkeletalAnimatedCrowdData` data assets will need updating to specify the `USkeleton` used by the crowd, if this hasn’t been done already. See below:

<figure><img src="/files/i6GwESQ0XmJsU1IA1k7W" alt=""><figcaption></figcaption></figure>

**How to test it?**

Test that crowd continues to work as before.

**Network Level callbacks renamed to Net Relevancy**

**What’s broken and why?**

The `OnNetworkLevelChanged` callback has been renamed `OnNetRelevancyLevelChanged`.

The `NetworkLevel` struct has been renamed `NetRelevancyLevel`.

**How to fix it?**

There are core redirectors so these renames will be automatically be applied in your project, but you should use the new names where possible.

**How to test it?**

Project compiles.

**Made the example map use simplified base classes (e.g. `M2M_CharacterBase` instead of `JM_CharacterBase`)**

**What’s broken and why?**

As part of our planned simplification work, we are cleaning up the logic in our Example content, removing deprecated features and providing simplified alternatives to core/example features that we are cleaning up.

We have now reparented the example content to new base classes (e.g. `M2M_CharacterBase`, instead of `JM_CharacterBase`, where the former is a parent of the latter). This means that a bunch of the logic added at the `JM_CharacterBase` level or below has been removed.

This includes:

* Character resizing (awaiting simplification)
* Roles (awaiting simplification)
* Capabilities (can be re-added in downstream projects if desired)
* Out of bounds auto-respawning (awaiting simplification)
* Camera zoom
* Approachability movement (click to move, etc.)
* Sliding & bounce components
* Motion warping
* motion capture
* traversals
* over-the-shoulder/topdown cameras
* "inhibitor component"/Player capture component
* Interaction
* focus cam
* Inventory/equipment
* deprecated chat
* Ability system
* debug command component (looks unused, part of the old live config system?)

If you are using the deprecated character (e.g. basing your character off of `BPM_Origin_PlayerCharacter`, or accessing the `JM_CharacterBase` directly), there should be no changes. If you are basing your character off of e.g. `BPM_M2Example_PlayerCharacter`, some functionality will have been removed.

**How to fix it?**

If you depend on any of the features removed, get in touch - the features will either be re-added in due time, or are not being supported by MSquared. If any are absolutely essential to your project, you can fall back to using the deprecated `Origin` classes for now, but this is not advised in the long run.

**How to test it?**

Review the removed features, check your core functionality is still as expected.

**Deprecation of Juno/M2 Activities and Venue\_Orb Map**

**What’s broken and why?**

The legacy Activities system has been deprecated. This was used extensively in the Venue\_Orb map. The blueprint facing API has been deprecated and all assets referencing these functions have either been deleted or modified to remove the references, depending on complexity of their connection to this system.

Areas of note:

* *Venue\_Orb\_P*
  * Removed entirely
* *BP\_PlayerController*
  * References to Activity widget removed
* *BP\_OrbUtility*
  * Handle teleport logic removed
* *BPM\_FadeToBack*
  * No longer gated behind a capability that was previously removed from the platform (Capabilities.ActivityControls)
* For a full list of affected classes, please refer to ActivityDeprecationCodeChanges.txt
* For a full list of affected assets, please refer to ActivityDeprecationChanges.txt

If you have content that was built on the Activities API, you will find the deprecation warnings will cause a warning at compile time for your blueprints. If you use our asset linter, assets using this API will fail the linting rules due to these warnings.

**How to fix it?**

The general advice here is to remove all references to this system ahead of taking this update. Soon we will remove this functionality altogether, which means anything that is still using it will break entirely.

If you are unsure as to whether or not you have used this, you can do a dry run on taking this update and see if there are any new warnings created when linting your content.

If there are warnings and you are not yet ready to remove the content, you can get the linter to ignore these for the time being. To do this, you’ll need to ensure your linting rules use a modified version of `JLR_BP_Compiles` and you need to add the specific strings to be ignored in the “Allowed Blueprint Warnings Regex” array. This will not work once we fully remove the underlying C++, so please plan accordingly.

<figure><img src="/files/y68w6ZxK5T3jOU9D0iUY" alt=""><figcaption></figcaption></figure>

If your project relies on any content removed as part of this process, you will need to create duplicates of the affected assets and keep them in project-space to avoid unwanted changes. If these assets inherit from Activity related classes, you must anticipate that these classes will also be removed in the near future.

**How to test it?**

Check all affected content works as expected.
{% endtab %}

{% tab title="Known issues" %}
**Performance regression at 18K CCU on Windows native**

We are currently investigating a performance regression which was identified during our scale tests using 18000 bots when using an **AMD Ryzen 9 5900X / NVIDIA GeForce RTX 3080** device.

This results on framerates of **\~20FPS**, rather than our 30FPS target.

**Unreal D3D12 Memory Leak in cooked clients if minimised**

It was observed that if you minimize the game client, it may eventually crash. The resulting callstack may vary, with one observed example being:

```
[2025.03.26-08.26.30:297][400]LogD3D12RHI: OnlineHeap RollOver Detected. Increase the heap size to prevent creation of additional heaps
[2025.03.26-08.26.30:398][406]LogD3D12RHI: Error: Interfaces.CopyCommandList->Close() failed 
 at C:\b\Game\Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandList.cpp:284 
 with error E_OUTOFMEMORY
```

Ahead of such crashes, it is clear that memory is leaking, by observing logs along the lines of `[2025.03.27-09.26.37:982][760]LogJunoMetrics: Process memory high water mark: 17554MB physical, 22196MB virtual`. Until this is fixed, we recommend advising users to not minimize their game window.
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v35

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version Released:** 20/02/2025

{% hint style="info" %}
Please note v35 removes support for any build on v31 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Release notes" %}
**Nameplate simplification**

Nameplates have been simplified, allowing for a Blueprint-only implementation. An example has been provided in M2 Example.

**AI State Tree support for bots**

[AI State Trees](https://dev.epicgames.com/documentation/en-us/unreal-engine/state-tree-in-unreal-engine) can now be used and MSquared-specific documentation is available here: <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/bots#using-state-tree>
{% endtab %}

{% tab title="Breaking changes" %}
**SkeletalCrowd supports dynamic addition of meshes at runtime**

**What’s broken and why?**

* `SkeletalCrowdMeshStore` mesh list is now ignored - meshes are now processed and useable by `SkeletalCrowdComponent` on demand at runtime. This shouldn’t break anything, but may mean processing of meshes is happening at a different time in the fame.
* This change in turn has simplified a lot of setup required to get meshes added during `BeginPlay`, and means we can remove the `ISkeletalCrowdMeshProviderInterface` and all uses of it
* All code related to avatars and attachments has been updated to handle this

**How to fix it?**

`ISkeletalCrowdMeshProviderInterface` is removed. If code/BP was previously using this it can now be removed. When creating an `FAnimatedCrowdMemberInitializer` using one of these (formerly) provided meshes:

* For skeletal meshes there is nothing to do
* For static meshes, previously the crowd got its attachment information from the mesh store data, which in turn was supplied from the mesh provider interface. This no longer exists. Therefore it must be passed in using the new `StaticMeshSocket` and `StaticMeshTransform` members on the `FAnimatedCrowdMemberInitializer` .

Similarly, `CharacterAssetComponent`’s `AddedCrowdStaticMeshesOverride` array has changed type. It is no longer a list of static meshes, but a list of `M2_StaticMeshAttachment` types (including socket, transform and custom data as well). Code / BP usage of this array will need fixing up, or ideally, changing to use the `AddAttachment` function which is the preferred path.

**Carnival Model Component**

**What’s broken and why?**

Blueprint functions to manually add and remove carnival meshes.

**How to fix it?**

To manually add a mesh (e.g. attachment) to a Carnival model, you can use the `UJ_ModularCharacterComponent` as usual.

**How to test it?**

Carnival characters and attachments should work as usual.

**Made the example map use new simplified character classes**

**What’s broken and why?**

The base classes used by the example map, and the example plugin have been reparented, so that they use less of the deprecated content (e.g. the interaction system). The example map’s functionality should remain largely unchanged, but any classes extending off the M2Example bases that depend on features in M2Deprecated may not work.

The changes to the example content are as follows:

* The ExampleMap now uses its own `BP_M2Example_BotBehaviorStore`, instead of the default one
  * This uses a different chat behavior
* `WBP_M2Example_TextChat` has been retargeted to use the `BPMC_M2Example_TextChatComponent` instead of the deprecated text chat component. If you are using this widget without using the other example classes, this may fail.
* `BPM_Example_PlayerCharacter` has been reparented to a simplified base class. This removes some functionality, such as the deprecated interaction system
* `BP_Example_PlayerCharacter` has been reparented to `BP_M2_PlayerCharacter`. This replaces some features, such as nameplates, and removes some deprecated functionality

NOTE: This change does not affect users exclusively using the content in M2Deprecated, e.g. `WBP_Origin_HUD` and `BP_Origin_PlayerCharacter`, only those using content in the `M2Example` plugin.

**How to fix it?**

If you have assets extending example content, but that depends on deprecated content, you will need to either migrate away from using the deprecated content, or reparent your assets onto the deprecated base classes, e.g. `BP_Origin_PlayerCharacter`.

**How to test it?**

Check whether your core classes extend any of the following:

* `BP_M2_PlayerCharacter`
* `BP_Example_PlayerCharacter`
* `BPM_Example_PlayerCharacter`

And check whether your UI includes `WBP_M2Example_TextChat`. If these are true, you may need to update their usage, if there are any compile errors, or deprecated features stop working.

**Made M2\_WorldBuilderUXSubsystem::bUpdateRequired read only**

**What’s broken and why?**

`UpdateRequired` was previously `BlueprintReadWrite`, but is not intended to be modified externally in blueprints. It has therefore now been made `BlueprintReadOnly`. Any downstream uses where it was set should be removed.

**Change to Persistence Subsystem Read Query**

**What’s broken and why?**

The response after reading from the KVStore has been minorly adapted to also return information about whether a key exists within the store. Instead of a map of key and value strings, it’s replaced with a struct that also contains a success boolean that indicates whether that key exists.

This means that the On Persistent Value Query Complete delegate will execute for both successfully found keys and non-successfully found keys.

**How to fix it?**

If you’re relying on the above delegate to execute only for successfully found keys, you will need to use Get Session Value String in your custom event to add an additional check for whether the key exists or not, before continuing with any logic.

**How to test it?**

Persistence systems should operate as normal.
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v34.1.1

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version Released:** 10/02/2025

{% hint style="info" %}
Please note v34.1.1 removes support for any build on v30 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Release notes" %}
**Added experimental WebUI plugin**

Support for the WebUI plugin has been added, allowing users to create web UIs which are embedded into Unreal and can talk back to the main game.

An example has been provided in the Example Map for you to experiment with. Currently this feature only works on Windows and can have a significant performance impact, but it is under active development and will continue improving over the coming releases.

Initial documentation can be found here: <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/web-ui>

**Standardised approach to animations using M² Skeleton**

The bone translation retargeting settings have been changed in the M² Skeleton, which is the skeleton used when loading MML avatars. Most of the bones are now set to use the Skeleton's translations, instead of the animation's translations, which should make M²'s animations more compatible with custom avatars.

**Removed legacy Analytics API**

Given the limitations imposed on our customers by using our platform’s analytics, the decision was made that we should avoid projects implementing analytics with our existing system. We're now providing a viable off-ramp which allows customers to handle their own analytics using JSON. More details can be found here: <https://docs.msquared.io/integrations/3rd-party-analytics>
{% endtab %}

{% tab title="Breaking changes" %}
**BP facing Analytics API removed**

**What’s broken and why?**

The following analytic events have been removed from Blueprints

* **BPC\_ApproachabilityMovement**
  * Removed event control\_interactions\_tracked
    * In function “Process Tap”
* **BP\_WBL\_WaitingPawn**
  * Removed event download\_launch\_context\_image\_finish
    * After event “Download On Url Received”
* **BP\_ItemExecutor\_LoudspeakerDevice**
  * Removed event loudspeaker\_request\_event
    * In functions “Turn Off Loudspeaker” and “Turn On Loudspeaker”
* **BPM\_VideoScreen**
  * Removed event Exit Screen Interaction option
    * In event “On Button Option Requested”
* **BPMC\_CrowdAudio**
  * Removed event loudspeaker\_change\_event
    * In functions “Start Loudspeaker Request” and “Stop Loudspeaker Request”
* **BP\_AvatarEditorActor**
  * Removed event avatar\_editor\_opened
    * In event “OnAvatarInitialized”
  * Removed event avatar\_editor\_closed
    * In event “DoneButton”
* **BP\_LaunchPad**
  * Removed event launchpad\_jump
    * In function "Jump"
* **BP\_ItemExecutor\_Ping\_LocationSelector**
  * Removed event ping\_ability\_used
    * In event "HandleLocationSelected"
* **BP\_ItemExecutor\_Silencer\_PlayerSelector**
  * Removed event silencer\_event
    * In function "Apply to Selected"
* **BP\_LoudspeakerVolume\_MicStand**
  * Removed event loudspeaker\_request\_event
    * In function "Enable Loudspeaker"
    * In function "Disable Loudspeaker"
* **WBP\_EmoteSelector**
  * Removed event menu\_opened
    * In event "Event notify Activated"
  * Removed event menu\_closed
    * In event "Event Notify Deactivated"
* **BPC\_MovementAnalyticsComponent**
  * Deleted entire component, removing several events
    * heartbeat\_location
    * xyz\_movement
    * xy\_movement
  * Component will no longer be present on BP\_M2\_PlayerCharacterBase or it’s children

**How to fix it?**

To implement your own Analytics, please refer to this guide: <https://docs.msquared.io/integrations/3rd-party-analytics#setting-up-mixpanel-analytics>

To preserve the analytics listed above and the associated logic, duplicates of the affected assets need to be made before upgrading to this version, and the analytics called replaced with the appropriate call to the implemented analytics system of your choosing.

**How to test it?**

Ensure that analytics are captured for the events required.

**Change Morpheus terminology to use "split authority" and remove the term “net ownership”**

**What’s broken and why?**

`SpawnMorpheusActorWithClientAuthority` has been deprecated and replaced with `SpawnMorpheusActorWithSplitAuthority`.

`GetOwningClientConnection` has been deprecated and replaced with `GetAuthoritativeClientConnection`.

The `SpawnMorpheusActorWithClientAuthority` function was misleading, since the spawned actor is still largely server authoritative. “Split authority” is being adopted as more accurate terminology.

“Owning client connection” in Morpheus is identical to “authoritative client connection”, so we’re removing this terminology entirely to simplify Morpheus.

**How to fix it?**

Replace all instances in BP code of `SpawnMorpheusActorWithClientAuthority` with `SpawnMorpheusActorWithSplitAuthority` and `GetOwningClientConnection` with `GetAuthoritativeClientConnection`.

**How to test it?**

Ensure your Blueprints all compile.

**Modified M2 Extras: Skins System**

**What’s broken and why?**

* Some functions and classes have been modified in the M2 Extras: Skins System
  * `ListenToSkinUpdates` now takes a delegate called `OnSkinUpdated`, rather than `OnConditionMet`.
  * The `GetSettingByClass` helper takes specifically `M2_InstancedObject` classes, not any `Object` \\
  * These should be fixable by checking for any compile errors in any downstream logic that uses these functions, and reconnecting the pins.

**How to test it?**

If you are using `M2 Extras: Skins System`, there may be compile errors. If there are though, they should be simple to fix.

**Removed Scale Test related Level Instances**

**What’s broken and why?**

All Level Instances used in `ScaleTestMap_Surround_Example` have been broken down into the assets that composed them, with the Level Instances then being deleted.

**How to fix it?**

If these instances have been used elsewhere in your project, please copy the following assets out of the engine and into your project, then fix references to point to the new copies:

M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Gameplay01.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Gameplay02.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Gameplay03.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_PyramidVenue.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Rocks01.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Screens01.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Screens02.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_SetDressing\_Aa.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_StadiumLights01.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Structures\_Aa.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Structures\_Ab.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Structures\_Ba.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Structures\_Ca.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Structures\_Cb.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Aa.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Ab.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Ac.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Ad.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Ae.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Ba.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bb.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bc.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bd.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Be.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bf.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bg.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bh.umap\
M2Unreal/M2Example/Content/Maps/SubLevels/Maps\_LevelInstances/LI\_Nexus\_Walkways\_Bi.umap

**How to test it?**

Ensure the Level Instances you have used still appear as they did previously.

**Parallel delegates for background high frequency events removed from Blueprints**

**What’s broken and why?**

In the combat helper classes, the parallel versions of the background high frequency events (`ShootableComponent::OnHitReceivedBackgroundParallel` and `CombatComponent::OnShotFiredBackgroundParallel`) have been make inaccessible to Blueprints.

The `OnHighFrequencyEventReceivedParallel` parameter in the BP initialiser for background high frequency events `UBackgroundHighFrequencyEventLibrary::InitializeBackgroundHighFrequencyEvent` has been removed, and the `bUseNonParallelDelegates` argument is removed with it.

This is because it’s impractical to write thread-safe code from Blueprints. Using them from BPs often resulted in clients crashing, and faulty BP code should never cause a client crash.

**How to fix it?**

If any functionality is bound to the above events, move the functionality to the non-parallel versions of the delegates instead.

**How to test it?**

Check that your `OnHitReceived`, `OnShotFired`, and any other custom background high frequency event behaviour continues to work as usual.

**M2Extras: Widget Handler moved into M2Example, as “UI Mode Helpers”**

**What’s broken and why?**

The old “M2Extras: Widget Handler” plugin has been removed, in favor of the same functionality in M2Example, now that it is being used in our example UI setup. If you relied on the old helpers, you will need to migrate them over.

**How to fix it?**

Any uses of the old `BPFL_WidgetHandler` methods will need updating to the `BPFL_UIModeHelpers` equivalents:

* `MarkWidgetNeedsUIMode` has been replaced with `RequestUIMode`
* `UnmarkWidgetNeedsUIMode` has been replaced with `ReleaseUIModeRequest`
* `HandleUIModeChangeRequest` has been replaced with `BindToUIModeChangeRequests`

**How to test it?**

If you have no compile errors, you should be good to go!
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v33

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version Released:** 13/01/2025

{% hint style="warning" %}
Note: There is a known issue with the base release (`v33.0.0`), which has been fixed in hotfix version `v33.0.2`: #some-m2-assets-fail-to-package-correctly
{% endhint %}

{% hint style="info" %}
Please note v33 removes support for any build on v28.0.0 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Breaking changes" %}
**Removed 'WebBrowserWidget' and 'WebBrowserNativeProxy' modules**

**Affected Features:** Web Browser

**What’s broken and why?**

Removed the 'WebBrowserWidget' and 'WebBrowserNativeProxy' modules as the the WebUI plugin has replaced this functionality.

**How to fix it?**

If using the Web Browser Widget, replace the instance with a Web Interface from the WebUI plugin. The API should be the same.

**How to test it?**

Play in PIE and see the web browser widget working as before.

**Carnival ViewDistanceQuality Settings Rename**

**Affected Features:** Carnival

**What’s broken and why?**

Carnival scalability settings for quality of meshes have been renamed in favour of model-driven new approach. This means that if any project overridden the Carnival scalability settings, they will not apply anymore, and need to be removed or renamed in favour of the new ones, which are found in BaseScalability.ini file, under ViewDistanceQuality sections.

**How to fix it?**

If ViewDistanceQuality scalability settings are overridden in a project, they need to match new namings found in BaseScalability.ini file, under ViewDistanceQuality sections.

**How to test it?**

Only the new cvars present in ViewDistanceQuality sections will have an impact on Carnival visual quality.

**Removed ChatGPT node functionality**

**Affected Features:** ChatGPT

**What’s broken and why?**

Removed the ChatGPT nodes as they are no longer supported.

**How to fix it?**

Remove the references to all now-invalid ChatGPT nodes.

**How to test it?**

Ensure project runs as expected.

**Removed Remote Viewer related Live Config schema**

**Affected Features:** Remote Viewers

**What’s broken and why?**

As Remote Viewers has been non-functional for several versions, we are now taking the time to clean up our live config schema as well. This means there are a number of values no longer present by default in game schema:

* PlayerSpawn.InitialRemoteViewerSpawnArea
* RemoteViewers.MasterRole
* RemoteViewers.VisualizerRole
* RemoteViewers.TimeUntilRVDespawn
* RemoteViewers.MasterActorTickInterval
* RemoteViewers.AllowRemoteViewerDespawn
* RemoteViewers.AllowVisualizerAndPlayerInDeployment

**How to fix it?**

These were not functional in M2. If you are using these values elsewhere in your own project, please add them to your own Game override Live Config Schema. The recommendation is you copy these values from the old schema before updating, if you find you need these.

**How to test it?**

Ensure project functions as before.

**Removed Legacy Live Config settings from Editor Preferences**

**Affected Features:** Legacy Live Config (Live Config v1)

**What’s broken and why?**

The Legacy Live Config settings are no longer visible in Editor Preferences. We have a new version of Live Config (see [Release Notes for v19.1.1](https://docs.msquared.io/creation/unreal-development/upgrade-the-editor/release-notes#m-platform-release)). This change was only removing the exposed options of a defunct system.

**How to fix it?**

If you are still keeping values in this area of the Editor Preferences, please look over the [Live Config docs](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/live-config) and ensure you have configured your values correctly in the currently supported system before taking this update.

**How to test it?**

Ensure project behaves as expected once migrating any old values to the current version of Live Config.

**Removed failover hook**

**Affected Features:** Networking

**What’s broken and why?**

I’ve removed the event FailoverBeginPlay from Morpheus Actor. It was part of server failover, a half-implemented feature left over from 2022, and now deleted. It’s very unlikely to be used in any customer projects.

**How to fix it?**

Remove FailoverBeginPlay event nodes from blueprints that inherit from Morpheus Actor.

**How to test it?**

Ensure project builds and runs as expected. Errors will report:

```
Could not find a function named "ReceiveFailoverBeginPlay" in 'MorpheusActor'.
```

**Removed references and assets for Remote Viewers**

**Affected Features:** Remote Viewers

**What’s broken and why?**

Following assets removed:

* DA\_RemoteViewerVisualizerPawnSet
* DA\_Skypark\_Pawns\_RemoteViewerVisualizer
* BP\_M2\_RemoteViewerConnection
* BP\_M2\_RemoteViewerLifecycleManager\_Example
* BP\_M2\_RemoteViewerVisualizer
* BP\_M2\_ViewerConnectionSpawner
* BPM\_M2\_RemoteViewerMasterActor
* BPM\_M2\_RemoteViewerVisualizer
* BPM\_M2\_RemoteViewerVisualizerControlComponent
* DA\_M2\_Pawns\_RemoteViewerVisualizer

References to these have been removed from BP\_Origin\_GameMode and the following maps:

* ApproachabilityGym
* ExampleMap
* ScaleTestMap

Remote Viewer roles were removed from DT\_Origin\_Roles

**How to fix it?**

The feature has been non-functional for several versions, there is no way to fix “Remote Viewers” but you may have to replace references to classes listed above if they have been used elsewhere for non-Remote Viewer related things.

Reach out to Solutions if there is need for “Remote Viewer” functionality going forward.

**How to test it?**

Ensure project builds and runs as expected.

**Removed SkipSignInConfirmationScreen from Game Live Config**

**Affected Features:** Boot flow / sign in

**What’s broken and why?**

Default Live Config schema no longer has Game value EntryFlow\.SkipSignInConfirmationScreen because it was no longer functional or needed by core M2 platform

**How to fix it?**

Add the following to you Game schema under EntryFlow

```
"SkipSignInConfirmationScreen": {
	"type": "boolean",
	"default": true,
	"description": "Bypasses the sign-in confirmation screen, streamlining entry for users who are already logged in or in scenarios where authentication is handled differently."
},
```

**How to test it?**

This isn’t used in M2 so we cannot say how it *should* work for you, but you can check it works as expected in the context of your project by restoring the value and checking that WBP\_SignInScreen works as expected, or any other project specific locations you have also used this value for.

**Deprecated legacy M2 GameModes**

**Affected Features:** Unreal maps/modes

**What’s broken and why?**

We have deprecated BP\_GameMode and BP\_Origin\_GameMode. All functionality running on these game modes are implementable in project space now, so for greater transparency and ease of use, we've moved both into deprecated.

**How to fix it?**

If you have either selected as your global project game mode, open "ProjectSettings > Maps & Modes" and reselect your GameMode from the Default Game Mode dropdown.

**How to test it?**

Cook your project successfully. If you have a bad game mode selected you'll see the following error:

```
LogWorldBuilderEditor: Display: LogCook: Error: GlobalDefaultGameMode contains a redirected reference '/M2Content/Core/BP_GameMode'. The intended asset will fail to load in a packaged build. Select the intended asset again in Project Settings to fix this issue.
```

{% endtab %}

{% tab title="Known Issues" %}
**You cannot World Travel to the same map**

If you attempt to world travel between worlds that use the same map, it will currently fail, giving `LogWorldTravel: Error: Cannot use world builder world travel to travel between the same map '/Game/ExampleMap'.`

We are looking into enabling this flow, and will update this in an upcoming release

**"Mesh Reproduction Sprite" Niagara systems unsupported on Carnival**

Making particle systems that track the character's mesh (e.g. following the tutorial outlined here: <https://youtu.be/5yI6FU-6Jzo?t=499>) will not currently work with carnival actors. This means that non-auth characters using MML avatars (including LOD0) will not be able to display such particle effects.

**Some M2 assets fail to package correctly**

NOTE: This has been fixed in hotfix v33.0.2 - if this change impacts you, please upgrade to the hotfix!

A small number of assets currently fail to package within WB projects due to some failing Unreal redirector logic. Assets that fail to resolve will log within the Unreal process:

```
LogStreaming: Error: CreateExport: <path> - Could not find class object for <classname>
LogStreaming: Warning: Missing Dependency, missing package import 0x110000000C for package <path>
```

You can workaround this temporarily by copying the M2 asset to your project locally, and referencing that version instead. **This will affect functionality such as control panels**
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v32

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version Released:** 06/12/2024

Latest Binary Version `32.0.0`

{% hint style="info" %}
Please note v32 removes support for any build on v27.0.0 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Highlights" %}
**Improved API for interest level changes for replicated properties**

Users previously encountered challenges when attempting to apply net-foreground-only or net-midground-only status effects, such as displaying a specific attachment exclusively in the midground. These effects were inherently implemented using foreground or midground variables and OnReps. However, when a player transitioned to a lower network level, the status effect persisted unintentionally.

To address this, we delivered an API designed for this use case, promoting a design pattern that ensures status effects are properly canceled and re-enabled in response to changes in the network level. While the Morpheus Actor already included a `NetworkLevelChangedEvent` event, we enhanced functionality by introducing more granular, property-specific handlers to provide finer control.
{% endtab %}

{% tab title="Breaking Changes" %}
**Cancelled value added to EM2\_HttpResponseStatus**

**Affected Features:** Http

**What’s broken and why?**

We have added a new “Cancelled” status to the EM2\_HttpResponseStatus enum. Whilst this in itself is not breaking, users me be using the “Switch” block in blueprint to handle the http results.

If this is the case, the addition of the new Cancelled status will result in an unmapped pin, which may cause your blueprint to not handle the case of cancelled requests. This would only happen if you explicitly cancel a request.

**How to fix it?**

You have two options:

1. If you are using the enum and mapping all but the “OK” pin to a failure state, you should swap to using an Equals “OK” and branch node.\\
2. If you still wish to use the switch, you must map this to your cancellation handler (or failure case)

**How to test it?**

Check your http requests are handling the responses you expect.

**World Builder settings migration**

**Affected Features:** World Builder

**What’s broken and why?**

We’ve migrated some settings from DefaultEditorPerProjectUserSettings.ini to DefaultGame.ini. Nothing will break, but some steps are provided to avoid this causing issues with version control.

**How to fix it?**

We migrate the settings automatically.

If you’re using a version control system, you’ll need to submit the modified Config/DefaultGame.ini as part of the upgrade.

**How to test it?**

Navigate to Project Settings -> M2 World Builder and ensure your old settings e.g. Mod Id and Maps are still present:

**Crowd Animation blend support**

**Affected Features:** CrowdAnimBlueprint, SkeletalCrowd

**What’s broken and why?**

Nothing *should* be broken. In order to support blend nodes within crowd ABP, this change contains some very fundamental modifications to how crowd animations are running, and as such projects should double check crowd animations are working as expected.

**How to test it?**

Crowd members should be animating as they used to before the change, precisely what this means will depend on the project.

**Pubnub-based Chat simplification**

**Affected Features:** Social (Chat)

**What’s broken and why?**

As part of the Pubnub-based text chat simplification process, we have ported the chat from C++ to Blueprint to allow customers to take control of the implementation. As a result of this, there is one change that must be addressed when taking this version of MSquared.

In order to continue using the current version of text chat you must add the ps.pndsn.com domain to your Developer Dashboard url allow list settings for the **Client**. See the next section for details.

Secondly, we have removed the “announcements” support. This feature was not used by any projects as so there should be no project impact.

Additionally, the “Fetch Channel History” function on the UM2\_TextChatComponent has changed signature from having a delegate passed in, to using a broadcast delegate for all history messages. This is due to the function implementation being moved from C++ to Blueprint. This should only be impactful if you have implemented a custom chat UI.

**How to fix it?**

To add the ps.pndsn.comas an allowed domain, you must:

1. Navigate to your developer dashboard
2. Select the Admin tab
3. Select External Urls
4. Expand the **Client** section
5. Set "**External Url Access**" section to "**Allow content to access only URLs with specified domains**"
6. Click “+ Add Domain”
7. Add "**ps.pndsn.com**" to the new entry
8. Click **Update** to save the setting

If your chat UI is using the announcement messages feature of the M2\_TextChatComponent; then it is recommended you begin removing the use of it, as in the future the functions will be removed.

When binding Fetch Channel History, you should now bind to the broadcast delegate “On Chat History Message Received” delegate to continue receiving the historical responses.

**How to test it?**

General chat should function as normal; minus the ability to receive announcement messages.

* Check your history messages still appear
* Check you can still send and receive normal chat messages

**Cleaned up/consolidated excess DT Roles tables**

**Affected Features:** Roles

**What’s broken and why?**

The following data tables have been removed:

* DT\_ApproachabilityGym\_Roles
* DT\_FeatureTestGym\_Roles
* DT\_NexusRoles
* DT\_QARoles
* DT\_RolesExampleMap
* DT\_RolesScaleTestMap

Any uses of them internally have been replaced with our default DT\_RolesExample.

The example roles table has also had some changes to it:

* The “starting inventory assets” have been removed, since this is a feature that is being deprecated.
* The Director role has been granted 4 “sizes” that it can switch between using + and -.\\

**How to fix it?**

If you want the default roles setup, please use DT\_RolesExample. If you want custom roles behavior, it is best to use your own roles table. (See <https://docs.msquared.io/creation/unreal-development/features-and-tutorials/game-roles#example-setup> )

**How to test it?**

In your level(s), go to the world settings, and filter by “role” - if the default role or data tables arrays have missing values, it may be that you were using one of the removed data tables. This will need to be replaced.

Similarly, if you try to change roles, and see that the roles are missing, or that your startup character isn’t as expected, that could be a sign that the role data table needs updating.

You will also see warnings along these lines:

```
LogLinker: Warning: [AssetLog] [X]: Failed to load '[Y]': Can't find file.
LogLinker: Warning: [AssetLog] [X]: VerifyImport: Failed to load package for import object '[Y]'
```

If so, that will highlight the removed data tables that are being referenced.
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v31

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version Released:**

### Morpheus Platform Release v31

15/11/2024

Latest Binary Version `31.0.0`

{% hint style="info" %}
Please note v31 removes support for any build on v26.0.0 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Highlights" %}
**Background character inspection**

* We've exposed the Raycastable System configurations to be in blueprints, specifically the raycastable prioritization config.
* We demonstrated this by adding more functionality to the Morpheus Inspector:
  1. Allow the users to force Morpheus Actors into Foreground
  2. Allow users to select Crowd Members via mouse clicks utilizing the Raycastable system.

Documentation is available in the [Raycastables system page](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/action-gameplay/enabling-raytracing-for-crowd-members).
{% endtab %}

{% tab title="Breaking Changes" %}
**Party Functionality Permanently Disabled**

**Affected Features:** Parties

**What’s broken and why?**

As part of the M2 Platform simplication process, we have permanently disabled parties and related functionality. As such, it is no longer possible to:

* Enable party support
* Create a party
* Join a party
* Leave a party
* Send a party message
* Receive party messages
* Use party voice chat

The *Party Component* is still present but is no longer functional. It will be removed in a future version of the M2 Platform.

**How to fix it?**

If parties are required in your project, you will need to create or integrate a third party solution. Contact your support representative if you require assistance.

**Removed UM2\_WebPlatformRealtimeNFTWebsocket**

**Affected Features:** Collections

**What’s broken and why?**

As part of M2 platform simplification, the UM2\_WebPlatformRealtimeNFTWebsocket class has been removed.

**How to fix it?**

If you require this funtionality, you can implement it in your own project by using the [Web Socket Connection](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/web-services/web-socket-connections) and [M2 Web Platform API documentation](https://docs.msquared.io/apis-and-tooling/api-reference/realtime)

**Interface Change: UM2\_WebServicesRoleDataProvider / UM2\_WebServicesProfileDataProvider**

**Affected Features:** Web Platform Integration

**What’s broken and why?**

The interfaces to UM2\_WebServicesRoleDataProvider / UM2\_WebServicesProfileDataProvider have changed. Instead of taking FM2\_AuthUserContext as a parameter, they now take int LocalUserIndex. This is to simplify / remove assumptions about users for custom web platform integrations.

This change should not impact anyone yet unless they have implemented their own data providers.

**How to fix it?**

Instead passing FM2\_AuthUserContext to any of the functions (which was hard to determine in Blueprint), you can pass LocalUserIndex. In 99% of cases, this will be 0, except for bots, which would be the index of the current bot.

**How to test it?**

Profile and role fetching should function as normal.

**Deleted UserRolesSubsystem / UserRolesService**

**Affected Features:** Services

**What’s broken and why?**

As part of MSquared platform simplification; the C++ querying of user roles has been removed to allow users to perform their own queries to either the web platform, or a service of their own choosing.

As a result of this, existing C++ Web Platform roles integration code has been removed.

This change should not impact users as it extremely unlikely that you’ll be manually querying role data.

**How to fix it?**

If previously you queried roles via either the UserRolesSubsystem or the UserRolesService (Web Platform), then you need to replace those calls with a Get World Service query, passing M2 Web Platform Roles Data Provider or an explicit derivative.

**How to test it?**

Role querying should work as normal.

**CorrelationId added to Response of SendHttpRequest**

**Affected Features:** Http

**What’s broken and why?**

CorrelationId has been added to the Response event used by SendHttpRequest. This is to allow users to correlate a response event with the request that initiates it; which is useful for storing state between the sending and response handling.

However, if you are using a bound function to handle the responses, you will experience a blueprint compile error due to the signature of the event changing.

**How to fix it?**

For every function you have bound to the completion delegate of SendHttpRequest, you must add an extra parameter to the Signature:

**Name**: CorrelationId, **Type**: Guid

Once you have done this, try compling the blueprint again and saving it.

**How to test it?**

If the blueprint compiles correctly, then no further action is required (once you’ve saved it).

**Skin PDAs need a resave**

**What’s broken and why?**

The underlying skins logic has been moved, but PDAs don’t handle redirectors nicely. As a result, without a resave of the active skin, PIE will be blocked in the “waiting for HUD” step.

**How to fix it?**

If you have a custom skin for your project, find it, and resave it. Easiest way to check what skin is being used is by going to the project settings → M2 UI Skins, and checking the Default Skin

**How to test it?**

If you can PIE and successfully enter the world, it has been fixed!

**Disabled Remote Viewers Web Platform Connectivity**

**Affected Features:** Remote Viewers

**What’s broken and why?**

The Remote Viewers feature is being removed as part of platform simplification. This step disables the connectivity of the Remote Viewers system to the M2 Web Platform services, effectively disabling the feature.
{% endtab %}
{% endtabs %}


# Morpheus Platform Release v30

See [this guide](/creation/unreal-development/tutorials/upgrade-the-editor) on how to update your existing project to a new editor release.

***

**Version Released:**

### Morpheus Platform Release v30

05/11/2024

Latest Binary Version `30.0.0`

{% hint style="info" %}
Please note v30 removes support for any build on v25.0.0 on Pixel Streaming.
{% endhint %}

{% tabs %}
{% tab title="Highlights" %}
**Support for multiple unique video streams with Millicast**

Although users have been able to create multiple Millicast streams, this feature was experimental and could lead to crashes and low performance due to consuming significant amounts of RAM and VRAM. We've improved this significantly and two simultaneous Millicast streams are fully supported on scales of up to 15000 CCU.

Using more than two Millicast screens is possible and is unlikely to cause out of memory issues, but it is unsupported by MSquared and downstream projects need to test their use case and target hardware.

**Support for microphone on Mac**

Crowd audio is now fully supported on Mac. The user can now listen to other players, talk with them and configure the input audio device.

This required considerable changes and we are keen to receive feedback on your experience, particularly on audio quality.

**Improved Mac performance**

We have been focusing on improving Mac performance across the board, focusing on the Mac Studio M2 Ultra (at 5000 CCU) and MacBook Air M2 (at 1000 CCU).
{% endtab %}

{% tab title="Breaking Changes" %}
**Removed `JLR_Plugin_NoFPDependencies`**

**Affected Features:** Linting

**What’s broken and why?**

The firepit linting rule does not do anything, so has now been removed. That means the classes `JunoLintRule_Plugin_NoFPDependencies` and `JLR_Plugin_NoFPDependencies` are no longer present. If you have any custom lint rules, the file will be missing.

**How to fix it?**

There will be a “none” in place of the removed linting rule in any of your custom rule set assets. Remove these. (Or a resave would also be sufficient to stop things complaining)

**How to test it?**

If your preflights run fine, all is well!

***

**Health in HealthComponent no longer replicated in background**

**Affected Features:** Health Component

**What’s broken and why?**

The Health variable as part of the HealthComponent is no longer replicated in the background. This is because it was very expensive and could limit the scale of deployments.

**How to fix it?**

If your project is relying on background health, or the health increased / damage taken callbacks in the background, the game design will need to be adjusted to avoid this.

**How to test it?**

Check that any health based functionality in your project still works.

***

**Improved Raycastable Crowd Prioritization**

**Affected Features:** Shooting

**What’s broken and why?**

Raycastable Crowd prioritization is now more configurable from Blueprints.

**How to fix it?**

Open the `RaycastableCrowd` asset used by your project’s Animated crowd. This will most likely be in the `DA_Pawns` asset linked in your Roles Data table.

In the `RaycastableCrowd` asset, there is a new `PriorityCalculation` property that exposes multiple prioritization strategies and their configurations.

The default strategies that were in-use before this change were the `View Frustum` and the `Area Of Influence` so you will need to enable and configure (based on your project needs) both of these strategies like the following:

Refer to [Enabling Raytracing for Crowd Members](https://docs.msquared.io/creation/unreal-development/features-and-tutorials/action-gameplay/enabling-raytracing-for-crowd-members#integration-4) for more guidance.

**How to test it?**

1. Start a PIE session with bots/other players.
2. Force everyone into LOD1 so they will be using RaycastableCrowd
3. Shoot at other players and verify they are still receiving damage/interacting.

***

**Removed JM\_ModularCharacterComponent and AddedCrowdStaticMeshesOverride**

**Affected Features:** Avatars

**What’s broken and why?**

In v29 the `JM_ModularCharacterComponent` was deprecated with the removal of modular characters, and its functions merged into `M2M_CharacterAssetComponent`. In v30 `JM_ModularCharacterComponent` has been removed entirely.

`JM_CharacterBase::AddedCrowdStaticMeshesOverride` and `JM_CharacterBase::UpdateDefaultCrowdMemberInitializer` have also been removed in favour of the equivalent functions on `M2M_CharacterAssetComponent` as they’ve been deprecated for several version.

**How to fix it?**

Anywhere you call a function on `JM_ModularCharacterComponent`, you should instead call the equivalent function on `M2M_CharacterAssetComponent` instead. The `JM_CharacterBase` class has both of these components, so you can get the `M2M_CharacterAssetComponent` directly from the same actor. v29 had deprecation messages on each function to tell you the equivalent - they are nearly all named exactly the same, except for functions with `Interop` in the name where this word has been removed.

If you’ve set an asset in `JM_ModularCharacterComponent::PostProcessAnimBlueprint` you should instead set it in `M2M_CharacterAssetComponent::PostProcessAnimBlueprint` as this can’t be automatically migrated.

Anywhere you set `JM_CharacterBase::AddedCrowdStaticMeshesOverride` you should instead set `M2M_CharacterAssetComponent::AddedCrowdStaticMeshesOverride`. Any call to `JM_CharacterBase::UpdateDefaultCrowdMemberInitializer` should be replaced by `M2M_CharacterAssetComponent::ReloadCharacter`.

**How to test it?**

Blueprints will compile and avatars will behave the same as before.
{% endtab %}
{% endtabs %}


# Performance Guarantees

The **Morpheus Platform** is tested weekly, using deployments with a set up designed to simulate large scale multiplayer events.

## World Sizes

Current guarantees are published for our worlds of size:

* 30 CCU
* 100 CCU
* 500 CCU
* 1500 CCU
* 5000 CCU

Guarantees for larger worlds will be added in future.

## Environment

The [**Example Map**](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin) (with the **ScaleTestSublevel** enabled) is our profiling test environment; it's a large map with mixed characteristics, including foliage, a stadium and an elaborate city background. Nanite is used throughout, and Lumen is enabled in supported hardware. Standard post-processing (anti-aliasing, bloom, tone-mapping, etc.) is used. Screens are used to stream two different [Millicast](/creation/unreal-development/features-and-tutorials/video-players/millicast-video-streaming) sources.

<figure><img src="/files/K4VrVjWcmChVDPH7I0m5" alt=""><figcaption></figcaption></figure>

## Avatar setup

Each avatar uses multi-part MML to customize different parts of the character. Each character has 7 parts, totalling an average of 35.000 triangles. Morplheus Platform runs using the Carnival renderer.

<figure><img src="/files/79vNZdJXrdBf1BYxbwpi" alt=""><figcaption><p>One of the ten thousand avatars used in the scale test.</p></figcaption></figure>

## Authenticated Bot behaviour

Authenticated Bots are configured to mimic a real players gameplay actions via the `BT_M2Example_BotFullBehavior` which includes:

* Running around the whole map (and jumping)
* [Using emotes](/creation/unreal-development/features-and-tutorials/emotes)
* [Testing crowd audio](/creation/unreal-development/features-and-tutorials/crowd-audio)
* [Sending messages through the text chat](/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat)
* [Switching roles](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/in-game-roles)
* [Changing avatar size](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/resizing)

<figure><img src="/files/IbakN1QCMQN2sp5uQTo0" alt=""><figcaption><p><code>BT_M2Example_BotFullBehavior</code></p></figcaption></figure>

Additionally, as authenticated bots have user accounts, they are able to mimic a real players account actions via the following behaviours:

### [KV Store](/creation/unreal-development/features-and-tutorials/online-services/kv-store-service#api-and-usage)

* `BT_AuthBot_KVStore_Read`
* `BT_AuthBot_KVStore_Store`
* `BT_AuthBot_KVStore_Subscribe`

### [LiveConfig](/creation/unreal-development/features-and-tutorials/live-config/using-live-config-settings-in-unreal)

* `BT_AuthBot_LiveConfig_Subscribe`

### Concurrent request guarantees

This table shows the maximum request concurrency and maximum throughput that we currently test.

* Max concurrency is the maximum number of a single request that we trigger at one time across all players on the server.
* Max throughput is the maximum number of a single request that we trigger over a given window.

<table><thead><tr><th width="201">Request</th><th width="228">Max Concurrency (requests)</th><th>Max Throughput (requests per minute)</th></tr></thead><tbody><tr><td>KV Store Read</td><td>18,000</td><td>72,000</td></tr><tr><td>KV Store Store</td><td>18,000</td><td>108,000</td></tr><tr><td>KV Store Subscribe</td><td>18,000</td><td>18,000</td></tr><tr><td>Live Config Subscribe</td><td>18,000</td><td>18,000</td></tr></tbody></table>

{% hint style="info" %}
Subscribe behaviours only send the subscribe request once and therefore have equal throughput and concurrency.
{% endhint %}

## Client performance

We guarantee a **minimum of 30FPS** with this setup in the following configurations:

| Hardware                                | Concurrent players |
| --------------------------------------- | ------------------ |
| Intel i7-9700K / AMD Radeon RX 480      | 1000               |
| Intel i7-8700 / NVIDIA GeForce GTX 1080 | 5000               |
| Mac Studio (M2 Ultra)                   | 5000               |


# Features & Guides

Expand this section to see a list of features accessible in the [Editor](/creation/unreal-development/getting-started/downloading-the-tooling).


# Actor Pooling

## **Intro** <a href="#intro" id="intro"></a>

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](/creation/unreal-development/features-and-tutorials/the-animated-crowd)), 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.

{% hint style="info" %}
NOTE: This only applies to other clients' characters. The authoritative client's render target actor is not pooled, and cannot go into the crowd.
{% endhint %}

<figure><img src="/files/PcamVJYBzdpWCQnH5HMY" alt=""><figcaption><p>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 <code>BP_Origin_PlayerCharacter</code>. Therefore, there will only ever be 2 actors, your one, and whichever other client is in LOD0.</p></figcaption></figure>

{% hint style="warning" %}
**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.
{% endhint %}

## **Technical Usage** <a href="#technical-usage" id="technical-usage"></a>

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

<figure><img src="/files/n6Rt2oSGWLcRygoBwkJj" alt=""><figcaption></figcaption></figure>

* 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.\
  \&#xNAN;*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)

<figure><img src="/files/Hah1k5RFpbPW1MjWbvte" alt=""><figcaption></figcaption></figure>

## **How to Test** <a href="#how-to-test" id="how-to-test"></a>

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.

Characters changing LOD levels can be easily triggered via the Morpheus Inspector - see [Morpheus Inspector](/creation/unreal-development/features-and-tutorials/inspector#rendering-related-options)

{% hint style="warning" %}
The following sections refer to functionality added in release v29
{% endhint %}

### "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!)

<figure><img src="/files/jkHj83vQyzf84LgDnjd6" alt=""><figcaption><p>An example warning if there is a delegate that hasn't been cleaned up. In this example, we automatically unbind it.</p></figcaption></figure>

### 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.

<figure><img src="/files/Zw6tprfEE3NncktQjeLl" alt=""><figcaption></figcaption></figure>


# Asset Loader

{% hint style="success" %}
verified: 2025-12-04 version: v39
{% endhint %}

For larger maps, loading times and memory usage can be an issue if every asset is hard referenced. This can be reduced by loading assets asynchronously on demand from Soft Object References.

The Morpheus platform provides a set of asset loading functions which wrap some of the boilerplate of the vanilla Unreal loading functions. They also cache recently loaded assets, which can reduce micro-stalls when rapidly loading and unloading assets, and provide consistent execution flow behaviour by ensuring that all latent nodes are executed later in the frame after the function has exited (instead of potentially executing instantly if the asset is already available).

## Blueprint nodes

These are latent asynchronous nodes, so can only be used in the Event graph (not in functions).

### Standard assets

Use the `JunoAsyncLoadAsset` or `JunoAsyncLoadAssets` nodes to load one or more Soft Object references. The `Completed` pin is executed once the load completes, and the result can be checked. For `JunoAsyncLoadAssets` the loaded `Objects` array is guaranteed to be in the same order as the input `Assets` array - the indexes will match, even if some assets fail to load.

You will need to cast the loaded object to the expected type on completion.

Assets don't need explicitly unloading. Once the last reference to the returned object has been cleared, the asset can be garbage collected once the cache timeout has expired.

<figure><img src="/files/dMj20LoYhIfmmNTW0nS0" alt=""><figcaption></figcaption></figure>

### Load results

* Success - All assets loaded successfully
* Partial Success - When loading an array of assets, at least one of them loaded successfully
* Fail - None of the assets loaded successfully
* Asset Limit Hit - By default there are no limits, so this won't occur
* Canceled - Asset loads cannot be cancelled from Blueprint, so this should only occur during e.g. a level transition

### Classes

Equivalent functions exist for loading classes from Soft Class References.

<figure><img src="/files/zY9xBKMLAtE3tHVENsm9" alt=""><figcaption></figcaption></figure>

### Primary assets

Primary assets can be loaded in a similar way, but also return a `Keep Loaded Handle`. This is to simplify the vanilla load functions, and remove the need to explicitly call an Unload function.

To keep the Primary Assets loaded you keep a reference to the loaded objects themselves as normal, or you can keep a copy of the returned handle. Clear the handle again to enable the objects to be garbage collected. When using `JunoLoadPrimaryAssetList` the single handle will keep all assets loaded.

You can also ignore the `Keep Loaded Handle`, and just rely on holding onto references to the loaded objects.

<figure><img src="/files/W2Amzam7anbBn2LNKHDe" alt=""><figcaption></figcaption></figure>

Alternatively you can call `JunoLoadPrimaryAssetTemporary` which behaves exactly like `JunoAsyncLoadAsset`:

<figure><img src="/files/xXxGtzfdOKWs4W5sVyE4" alt=""><figcaption></figcaption></figure>


# Audio

{% hint style="info" %}
For docs on Morpheus Crowd Audio see [Voice Chat](/creation/unreal-development/features-and-tutorials/crowd-audio)
{% endhint %}

## Unreal Engine Documentation

This page will only provide a brief overview of audio content, and how it works within an MSquared project. As we are working with the Unreal Engine native audio solution, it is advised to read the Unreal Engine Documentation on [Working With Audio](https://dev.epicgames.com/documentation/en-us/unreal-engine/working-with-audio-in-unreal-engine).

## Volume Settings

We have a number of different "volume channels" in our project, that can be used to control the volume of different channels per client:

* `master_volume` (Will control all volume)
* `sfx_volume`
* `voice_volume`
* `music_volume`

### Controlling the volume settings

These can be controlled in-game via the user's settings, using the `GetVolumeLevel` and `SetVolumeLevel` helper functions on the `J_GameUserSettings` (the settings class used in MSquared projects)

<figure><img src="/files/ppYuXdjrHCnUMjaFlHCe" alt=""><figcaption></figcaption></figure>

The `WBP_M2Example_SettingsMenu` provides a simple example of how you can add settings to your project to control these volume levels. We have only implemented the `master_volume` value here, but you could use this same approach to set the levels of sfx, voice or music if desired.

<figure><img src="/files/AMhZtkFoCsXEQ0VrHIjE" alt=""><figcaption><p>Image depicts the Audio settings in the example settings menu (WBP_M2Example_SettingsMenu)</p></figcaption></figure>

### Making new Audio Respond to the Volume Settings

In order to have your game sounds affected by the audio volume sliders, you need to ensure that you have correctly set their `SoundClass`.

This can be accomplished in two ways:

* Setting the SoundClass on the asset itself (strongly recommended, see below).
* Setting a `Sound Class Override` on an actor.

For example, if you have an `AmbientSound` actor, you can make it respect the `Music Volume` slider by adding the following SoundClass override:

<figure><img src="/files/vdBzR2OIB5OnAzCL9sYD" alt=""><figcaption></figcaption></figure>

To set up the appropriate sound classes, you can either use the existing ones, or make your own. To make sure that they map to the appropriate volume setting, you will need to link them to the appropriate `SoundControlBus`: (either directly through its list of VolumeModulators, or through a submix class):

* `master_volume` - No sound class needed, will be applied to all sounds
* `sfx_volume` - any SoundClass with `CB_M2_ClientVolumeControl_SFX` added to its list of VolumeModulators (or using a submix that has this)

  * e.g. `SCL_M2_NonWorld_UI` or `SCL_M2_World_Ambience`

  <figure><img src="/files/jVnMW75qGeGeK5a1fNgU" alt=""><figcaption></figcaption></figure>
* `voice_volume` - any SoundClass with `CB_M2_ClientVolumeControl_Voice` added to its list of VolumeModulators

  * e.g. `SCL_M2_World_Dialogue` or `SCL_M2_NonWorld_Dialogue`

  <figure><img src="/files/ewj81fK8Qi2Nrcdp3tRb" alt=""><figcaption></figcaption></figure>
* `music_volume` - any SoundClass with `CB_M2_ClientVolumeControl_Music` added to its list of VolumeModulators (or using a submix that has this
  * e.g. `SSM_M2_World_Music`) e.g. `SCL_M2_World_Music` or `SCL_M2_NonWorld_Music`

(World/NonWorld in this case denote Diegetic (typically 3D, in the world)/Non-Diegetic (typically 2D))

## Important Audio Asset Properties

MSquared has some example audio added, such as footsteps, which rely on correctly setting parameters on imported content. It is also important to be aware of the hierarchy of properties - i.e. some properties (such as Attenuation) on a SoundWave are ignored if the SoundWave is used in a MetaSoundSource.

The hierarchy is as follows:

* `AudioComponent`: This component is required to play any sound, and any properties set on the component will override those on any assets being played through it.
* `SoundCue / MetaSoundSource`: These assets contain and combine SoundWaves, and will override the properties defined on any SoundWave they contain.
* `SoundWave`: This is the "lowest-level" and most simplistic audio .uasset.

As a consequence of this, if an Attenuation property is set on a SoundWave, but the SoundWave is played inside of a MetaSoundSource with no Attenuation setting, then the outputted audio will be in 2D (i.e. with no attenuation or spatialisation).

Important properties to be aware of:

* SoundClass: This property defines the "category" of a sound and to which channel of the mixer system the audio will be routed. For example, this system is used by volume sliders in the pause menu. Adjusting the UI slider will only change the volume of sounds that are being sent to the UI channel, which can be accomplished by setting the SCL\_M2\_NonWorld\_UI SoundClass.\\
* Attenuation: This property defines the spatial behaviour of a sound - i.e. how it behaves in 3D space. The default null value will play a sound in 2D (i.e. it will sound the same regardless of your position, orientation, etc.) Using an Attenuation asset with spatialisation will make the sound play from a world location (i.e. the location of the AudioComponent that is playing it).

{% hint style="info" %}
Note that is it not possible for a non-spatialised sound to have attenuation, but it IS possible for a spatialised sound to NOT have attenuation (i.e. a sound that plays from a point in the world, but never gets quieter, regardless of how far away you are.)
{% endhint %}

<figure><img src="/files/kKGtTWvjJZ1UGjC8Xkx2" alt=""><figcaption></figcaption></figure>

* Looping: This property (when true) will set a sound to repeatedly play in a continuous loop. This is useful for ambient sounds, like running water in a river. If there is a noticeable gap where a sound stops and starts, it will ruin the immersion, so a continually looping sound will better simulate the sound of a flowing river.

Note: volume multipliers in Unreal are **multiplicative**, so setting the volume of a SoundWave to 0.5, then adding that SoundWave to a MetaSoundSource, and setting its volume to 0.5, will result in the sound playing at a volume of 0.5 multiplied 0.5, or 0.25. This also means that a sound can be muted by setting its volume to zero at any stage.


# Avatars

You in the Metaverse!

## Summary

Our goal is to support as broad a range of avatars as possible, so that people can use their avatars and associated items across our whole metaverse network. Player freedom may be limited by the experiences themselves, but not by the underlying technology.

Currently we have a few formats we support natively, but our aim is to provide tools to convert as many as possible into the [glTF format](https://en.wikipedia.org/wiki/GlTF), which can be used anywhere that [MML](https://mml.io/docs/reference/elements/m-character) is supported.

* [Web3 / NFT Avatar Collections](/creation/unreal-development/features-and-tutorials/avatars/supporting-an-nft-avatar-collection) - support for NFT collections with MML definitions

## Further Details

* For context behind our avatar setup, see: [Interoperability](/morpheus-platform/interoperability)
* For details on creating your own interoperable avatar, see: [Creating an Avatar](/creation/unreal-development/features-and-tutorials/avatars/creating-mml-avatars-with-blender-and-free-rigging-tools)
* For details on an MML Viewer tool, see: [The MML Viewer](/creation/unreal-development/features-and-tutorials/avatars/the-mml-viewer)
* For details on using your created avatar in-game, see: [Using an Avatar in-game](/creation/unreal-development/features-and-tutorials/avatars/using-an-avatar-in-game)

## Some Default Characters

For projects to get started, we have some pools of created avatars, ready to use:

* `https://casual-filtered-v1.msquaredavatars.com/[X].mml` - where `[X]` can be a number anywhere between 0 and 15000.
  * This is a list of randomly generated characters, with more conservative dress.

    <figure><img src="/files/oerMXeaM4uJ44KUdIvc4" alt=""><figcaption></figcaption></figure>
* `https://casual-v1.msquaredavatars.com/[X].mml` - where `[X]` can be a number anywhere between 0 and 15000.
  * This is a list of randomly generated characters with a wider range of clothing options

    <figure><img src="/files/Raj2e8BhE0f1idkrG3Jv" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you want to generate your own pools of custom avatars, please reach out!
{% endhint %}


# Creating an Avatar

You can turn any humanoid mesh into an MSquared avatar with Blender and free rigging tools. Here is a full video run-through of the process:

{% embed url="<https://www.youtube.com/watch?v=0m5xAzhoGkQ>" %}

## **Software you will need:**

* Blender 4.0+: <https://www.blender.org/download/>
  * (tested on 4.0.2, but should work on newer versions)
* Download these three Blender add-on files:

{% file src="/files/nlgQjWsETq2szsuduXNy" %}
The repo is private, so this file is the latest one
{% endfile %}

{% file src="/files/f5N4bQjktPtNRbZOBOJC" %}
Surface Heat Skinning Tool
{% endfile %}

{% file src="/files/YeLgfi1eObDQxrheTKaN" %}
Game Rig Tools (Support the creators if possible)
{% endfile %}

(These files are the Improbable Blender add-on for the geometry utilities from [this private repo](https://github.com/improbable/BlenderGeometryUtilities/tree/feature/geometry_process_addon), the Game Rig Tools from <https://toshicg.gumroad.com/l/game_rig_tools> and the Surface Heat Skinning tool <http://www.mesh-online.net/shd-blender-addon.zip> from [this ](https://github.com/meshonline/Surface-Heat-Diffuse-Skinning)repo)

### Plugin installation in Blender

In Blender, go to Edit -> Preferences -> Add-ons and press the `Install` button

<figure><img src="/files/Bh703sXTvl75FY3qFHcw" alt=""><figcaption></figcaption></figure>

Install both of the .zip files and the .py file in turn. When each one has been installed, you must enable it by checking the box:

If the python file is updated you can re-download, replace it and it will be updated in Blender. For the other addons (zip files), you'll need to download the file, remove the old one from Blender and re-add the newest zip file. Game Rig Tools is in active development and it has updates in a regular basis.

## Importing your character

First you will need a character model file. This can either be a character you've authored yourself, or one you have downloaded. There are many free character meshes available online, for example at <https://sketchfab.com/>.

For best results your mesh should be humanoid and in an A-pose or T-pose. Meshes with lots of accessories or sticking out parts don't tend to work well, as the auto-skinning step can get confused and attach parts of them to the wrong joints.

Once you've found a character mesh, you're ready to start converting it into a file that's compatible with the MSquared avatar system. For a detailed explanation see the video above, but here you will find a summary of the most important steps. If you're completely new to Blender you can also see a [basic introduction to the controls](#appendix-basic-blender-controls).

* Create a new empty scene in Blending. If there are default Camera, Cube and Light objects in the overview you can click them and press Delete to remove them.
* Use File -> Import to import your character file. If you see an Icosphere object in the overview, delete it:<br>
* Tip: If your character doesn't import nicely or looks wrong, you can try re-exporting it from a different tool. If your source file is a glTF/GLB file you can go to <https://www.gltfeditor.com/> and import your avatar, and then Save again. Import this re-saved file into Blender instead and it make work better.
* You need to remove any existing skeleton on the character, and for ease we can merge all meshes together. Press N to bring up the tools menu and select `Improbable geometry process`. Click `Remove Armature`, `Remove Transform Groups` and then `Merge Vertices` to perform all the clean-up steps. This will also erase any non-geometry elements in your scene and remove all parent transform groups.
* Select the Game Rig Tool tool and press `Initiate Mannequin` to add the skeletons.
* Ensure your mesh is the right scale and rotation to match the skeleton. Ensure you are in Object mode, select your mesh and press S to scale, and R to rotate it. You are now ready to set up the skeleton.\
  ![](/files/fqF7eXxRc6wccyehlqvs)

### Setting up the skeleton

You can now fine tune the joint positions to match your character geometry.

* In the `Game Rig Tool` isolate the `Tweak` skeleton by pressing the white circle next to it. Go into `Pose` mode to edit the joints.
* Enable the `Body Parts` and/or `Joint Tweak` options, and move the joints into the right place to match you mesh. Select the wireframe squares (body parts) and circles (joints) and move them by pressing `G` and rotate by pressing `R`.
* See the video for advanced methods of matching the fingers.
* When you're happy, press `Apply Rig`.\
  ![](/files/ZQaPTO1wPxJplg4QfBPy)

Now the joints are set up, the geometry needs skinning to the skeleton.

* In the `Game Rig Tool` isolate the `Deform` skeleton by pressing the white circle next to it. Go into `Object` mode to use the skinning tool.
* Click the `Mesh Online` tool and set the `Influence Bones` to `4`.
* Select the Deform skeleton and then `Ctrl + Click` the mesh itself so that both are selected.\
  ![](/files/IUVNTK8e2MvCi1udnWpl)
* Press the `Surface Heat Diffuse Skinning` button to calculate this skinning. This will take a few seconds.
* Go back into `Pose` mode to test the skinning, by selecting joints and pressing `R` to rotate them. Press `Esc` to cancel each rotation after testing.
* Go back into the `Game Rig Tool` and press `Switch Parent Armature` to apply the changes to the Unreal skeleton.
* Isolate the `Unreal` skeleton in the `Game Rig Tool` with the circle button, where you can test the skinning again in `Pose` mode.
* Go back to the `Improbable geometry process` tool and select an Export location and a filename.\
  \
  ![](/files/3QbmO1RsnTWOp3McMpXw)
* Go back into Object mode, isolate the `Unreal` skeleton again and `Ctrl + Click` the mesh to ensure both the skeleton and the mesh are selected. Now you can press `Export GLB`.\
  \
  ![](/files/FAYESrMLAl3tpCQ1Liu2)
* Finally press the `Open Web Avatar Exporter` button to open the web page where we carry out the final stage.

### Fixing the rotations

We're now done in Blender, but we need to use the GLTF Avatar Exporter web tool to fix up the skeleton rotations.

* Go to <https://mml-io.github.io/avatar-tools/main/tools/gltf-avatar-exporter/>\
  (this is where the `Open Web Avatar Exporter` button should take you).
* Drag the GLB file you exported in the previous step into the top left window. If everything exported correctly you should see your character.
* Press the `Use Sample Animation` button, and if everything is set up correctly you will see your character performing an animation.\
  ![](/files/duNgNwOscTM6an04Sj9d)
* Assuming this all works, press the `Export` button at the top right to save your final GLB file!

## Turning your GLB file into an MML character

You now have a compatible GLB avatar file. But to use it you need to create an MML avatar using the file.

{% hint style="info" %}
From v21 of the platform, we also support [DRACO](https://google.github.io/draco/) compressed glTFs and GLBs
{% endhint %}

* Go to <https://mmleditor.com/projects> and `Create a Project`
* Upload the .glb file you previously exported by going to the `Assets` tab and dragging your file in.

<figure><img src="/files/RmMgEEwLgIJ52gsZnI09" alt=""><figcaption><p>Upload your Asset to IPFS</p></figcaption></figure>

* Now drag the asset to the Code window, and rename the `m-model` tag to `m-character` at the start and end of the code. This is all you need in your MML file.

```xml
<m-character src="https://mmlstorage.com/[ASSET_CODE]"></m-character>
```

* Now you need to permanently store the MML. Click the `Static Versions` button at the top right and press `Publish`. The click `Copy` to copy the URL of your MML avatar.

<figure><img src="/files/bLcpijDqJicmI6FNq6Tn" alt=""><figcaption><p>Getting the static URL</p></figcaption></figure>

* The MML avatar link should now be ready to use! Try one of the following:
  * View your Url online: [The MML Viewer](/creation/unreal-development/features-and-tutorials/avatars/the-mml-viewer)
  * Add your Avatar to your game: [Using an Avatar in-game](/creation/unreal-development/features-and-tutorials/avatars/using-an-avatar-in-game)

## Further demo

Here is another quick demo using a different character.

{% embed url="<https://youtu.be/O8mpzWHAtsg?feature=shared>" %}

### Generative AI Character Demo

You can also use generative AI to create your avatar. Here is another quick demo of this process.

{% embed url="<https://youtu.be/rReyMIdxQVc?feature=shared>" %}

## Appendix: Basic Blender controls

If you're new to Blender it can be confusing to use. Here are some basic controls to get you started. The extra controls are covered in the tutorial video at the top of the page.

Camera controls:

* Spin the camera by holding the middle mouse button.
* Move the camera by holding `Shift` and the middle mouse button
* Zoom with the mouse wheel, or by holding `Ctrl` and the middle mouse button

Change the 'edit mode' in the top left corner (the actual menu depends on what you have selected). In this tutorial you'll dealing with skeletons, and will need to use `Object Mode` (for selecting entire objects) and `Pose Mode` (for manipulating individual joints).

<figure><img src="/files/pRVNcnf0UWz5b12p8HfA" alt=""><figcaption></figcaption></figure>

Press `N` to show the tools the you will be using, on the right hand side.

Click the axis letters to enter an orthographic view. This is useful for moving joints about in a single plane - for example click the X axis to move spine joints around without the risk of them moving off the centre line.

<figure><img src="/files/pAeyNQHxT70yr5cLkD3V" alt=""><figcaption></figcaption></figure>

Some steps require multiple objects to be selected at once. In the top right tree view, you can select a second object by holding `Ctrl` and clicking. For example, some steps require you to use the white circle icon to select a specific skeleton, and then also select your mesh. You can hold Ctrl and click the mesh either in the main viewport, or in the tree view.

<figure><img src="/files/8QAiXUizS3I0Td0vyW9k" alt=""><figcaption></figcaption></figure>


# Using an Avatar in-game

This page outlines details on how to use these avatar Urls in-game, via the `CharacterAssetComponent`.

The `CharacterAssetComponent` is found on your morpheus actor (added by default for children of `M2M_CharacterBase`)

## How To Set Your Url

To apply your avatar Url, you can use one of the following:

### Directly Setting your Url

The `CharacterAssetComponent` has a `LoadCharacterFromUrl` function, which allows you to apply your Url.

{% hint style="info" %}
This function must be called on the *authoritative client*, so that it gets replicated to other users.
{% endhint %}

<figure><img src="/files/ihuEVzl8LyHf3VZ30xy6" alt=""><figcaption></figcaption></figure>

### The Default MML Url

If you want all characters to default to a specific Url, paste the Url into the `DefaultMmlCharacterUrl` field of your Morpheus Actor's `CharacterAssetComponent`:

<figure><img src="/files/mM3hlrXx45N1HH32aP6l" alt=""><figcaption></figcaption></figure>

### Multi-mesh avatar considerations

The main avatar GLB will be loaded onto the default Mesh component of your pawn actor. If your MML contains multiple GLB meshes (using child `<m-model>` nodes) then an additional `SkeletalMeshComponent` will be created for each sub-mesh.

If you want to make any tweaks to the player mesh after loading (for example disabling shadows) then you may need to iterate the child mesh components and make the change to each of them. Trigger this with the `M2M_CharacterAssetComponent::OnCharacterLoaded` delegate, which is called once all the components have been created.


# Custom Animation Variables

Using animation variables outside of the default M2UP animation variables to control your Animation Blueprint.

M2UP has a default set of AnimVars (animation variables) that are used to define how the ABP (Animation Blueprint) logic operates. These variables are either replicated or filled locally in code every tick to determine what the animation state should be based on the current state of the character. For example, if the player's gait isn't replicated, the animation component code can calculate the gait AnimVar from the speed of the player.

The variables used are in the `M2_AnimVars` struct and cover things like walking, running, basic combat poses, which you can see being used in `ABP_M2_Human`. Your project may want to use a different ABP which requires different AnimVars. M2UP provides a couple of different ways to do this.

## Custom Booleans

The quickest solution for basic cases is to use the M2UP provided custom bools. M2UP provides eight generic bool AnimVars within the `M2_AnimVars` struct that are never used by M2UP blueprints. These bools are client-authoritative background replicated variables, so will be replicated to all players, and work on Crowd members too.

There are functions on the `JM_AnimVarsComponent` to set and get the values from the authoritative client. This example will toggle the first bool:

<figure><img src="/files/CljASJmITbezzzXQypIm" alt=""><figcaption></figcaption></figure>

The bools will be replicated and set on the `M2_AnimVars` struct that’s available in the ABP (see the existing AnimVars macros). They will look like this:

<figure><img src="/files/FQ7sZgvagdJBhahzb7Y3" alt=""><figcaption></figcaption></figure>

You can use these to drive your new animation state changes as usual in your custom ABP.

## Define your own variables

{% hint style="info" %}
The tools in this section are available from MSquared v27.
{% endhint %}

For more advanced use cases, you can also directly use AnimVars that you've defined in your own ABP. To ensure that these function correctly with Crowd members and with M2UP's actor pooling system, you'll need to register these variables in a custom AnimVarsComponent and use appropriate callbacks to set the variable.

### Defining and registering the variable

You can create an AnimVar as usual, by creating a variable inside your ABP.

<figure><img src="/files/jrWFrK5eU3z8GXWDsnwc" alt=""><figcaption><p>I've created "TestCustomAnimVar" that defines a test transition in my ABP.</p></figcaption></figure>

To register my variable, I need to create a custom anim vars component. This is a component that extends `JM Anim Vars Component`, but to use the base M2UP anim var settings, you can extend from `BPMC M2 Anim Vars Base`.

In this component, you need to register your custom anim var by calling `RegisterCustomAnimVar` from the `InitializeAnimVarsComponent` event. In `RegisterCustomAnimVar`, you need to provide:

* CrowdAnimVarName: a string that matches the name of the anim var. This is only if you want your variable to function in the Crowd; you can leave it blank otherwise. In the above example, this would be "TestCustomAnimVar".
* UpdateAnimVarValue: an event that accepts an Anim Instance (which is your ABP) and a float input. This event should perform the action of setting the anim var on your ABP to the input value. This event will be called whenever the anim var needs changing.
* AnimInstanceClass: the class of the ABP that this variable is on.

This function returns a handle that you need to store to make updates to the anim var later on.

Note that your project can be set up to use multiple different ABPs at once for different user configurations, and not all the ABPs will necessarily have every custom anim var. This register function only registers the anim var for the given AnimInstanceClass, so you'll need to register for each separate class that has the variable.

<figure><img src="/files/tNwphoqeV4xCgSAA49pt" alt=""><figcaption><p>Here, I'm registering my TestCustomAnimVar. My UpdateAnim function needs to cast the AnimInstance to my ABP that actually has the anim var in order to set it. Because the input can only be a float, I'm also converting the float to a bool before setting it in my ABP.</p></figcaption></figure>

Finally, we need to tell our MorpheusActor character class to actually use this new anim vars component that we've created. This is done by setting the `Anim Vars Component Class` in your player MorpheusActor class to the class of your new anim vars component.

<figure><img src="/files/TsIsiYc2Hci10oXWtNZw" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you attempt to use a variable inside your ABP that has not been registered, you will see warnings along the lines of:

```
LogAnimatedCrowd: Warning: UAnimatedCrowdComponent::ValidateAnimVars: Crowd expected to support anim var with name [YourVarName], but this could not be found. Please check your anim var names.
```

From release v40 onwards, these will default to 0/false. (earlier releases will have these variables with undefined values)
{% endhint %}

### Updating your custom variable

To update the variable, we can't just update the anim var that's in the ABP instance, because the ABP instances are pooled and not available on Crowd members. Instead, we just need to call `UpdateCustomAnimVar` in our anim vars component and pass in the handle we saved from registration, and the (float) value that the anim var should be set to.

{% hint style="info" %}
Never set the value of the anim var on the ABP instance directly; always call `UpdateCustomAnimVar`.
{% endhint %}

Anim vars are not replicated by default. To replicate them, you can simply create your own replicated variable and update the anim var as above to match your replicated variable.

<figure><img src="/files/iiqQTyuio3lc51fplxrF" alt=""><figcaption><p>I've created a client-auth, midground replicated "TestCustomAnimVar" in my anim vars component, with a RepNotify that updates the anim var. Note I'm casting back to a float here.</p></figcaption></figure>

<figure><img src="/files/CumfzjNLXP1JbnFqnMgS" alt=""><figcaption><p>This is an example implementation of how you'd update an anim var from the authoritative client. My auth client is updating my replicated bool every 5 seconds; the OnRep shown earlier handles this replicated bool applying the update to the anim var.</p></figcaption></figure>

## Performance

Lots of AnimVars in traditional games are calculated and set every frame. For example, values like turning angle that depend on your current velocity. Due to the scale of M2UP experiences, *you cannot create anim vars in projects that need to be updated every tick,* since that would involve calling into a BP function every frame for all (potentially 15k+) players in the game.

Variables that need to be updated every frame are kept in code. Custom anim vars should instead only be used for states that don't need changing that frequently.


# Attachments

{% hint style="success" %}
verified: 2025-12-08 version: v39
{% endhint %}

Static mesh attachments can be socketed to player characters, for example weapons, glow sticks, or other accessories.

This page describes the process for attaching Unreal `StaticMesh` assets. You can also use attachments defined in MML - for details see [MML Attachments](/creation/unreal-development/features-and-tutorials/avatars/avatar-attachments/mml-attachments).

## Adding attachments to characters

Use the `AddAttachment` and `RemoveAttachment` functions on the Morpheus Actor's `M2M_CharacterAssetComponent` to add and remove attachments. The attachment will then automatically be applied to the character, whether it's in the crowd or a full actor, and regardless of the avatar type (MML or a static mesh).

Note that attachments are **NOT REPLICATED**. Automatic replication of all possible attachment states would add significant overhead, and would be unnecessary in most projects. Therefore it is up to projects to replicate their own state. This may be as simple as a single background integer specifying which item is equipped - in the `OnRep`, simply call `RemoveAttachment` with the previously equipped item and `AddAttachment` with the new one.

The Add and Remove functions have a `Reload Character` option. If you're making multiple calls to add and/or remove attachments to a character, it's more efficient to only reload the character on the final call. The character visuals won't be updated until it's reloaded.

The crowd system is limited to 16 total meshes per character including attachments, however up to 32 attachments will work for full actor (non-crowd) players.

<figure><img src="/files/RLoSknEbX6trFVSCObm9" alt=""><figcaption></figcaption></figure>

Adding an attachment to a character returns a `FM2_StaticMeshAttachmentHandle` which can be cached to later retrieve this attachment, or the attached Mesh. Note that passing in a null mesh, or a mesh which has already been attached, will return an invalid handle, so be careful not to overwrite any previously saved handle.

<figure><img src="/files/v2gSbPgqtQp8zl8Mi8EL" alt=""><figcaption><p>Example of using an <code>FM2_StaticMeshAttachmentHandle</code> to retrieve an attached mesh</p></figcaption></figure>

## Customising colors

It is possible to dynamically set material colors for attachments, but it requires some additional setup.

#### Crowd pipeline setup

Materials are customised by passing in additional color data with each mesh in the crowd. This additional data has a small memory and performance cost to the crowd rendering, so is disabled by default. To enabled it, on the `MorpheusActorRenderTargetComponent` on your player Morpheus Actor blueprint, look for the `Crowd Data` property (under Advanced -> Crowd Details).

<figure><img src="/files/WVV15DVdMdj45QarRc9t" alt=""><figcaption></figcaption></figure>

Either edit the data asset, or create a new data asset of type `SkeletalAnimatedCrowdData` and set it as the `Crowd Data`. In the data asset, set `NumCustomDataFloatsPerMesh` to 4 to enable the color to be passed correctly:

<figure><img src="/files/08m9TPqNilMj1Kn3rrvJ" alt=""><figcaption></figcaption></figure>

#### Setting the attachment color

A custom color can be passed into `AddAttachment` as part of the `M2_StaticMeshAttachment` struct, or the color can be updated on an existing attachment with `M2M_CharacterAssetComponent::SetCustomColorForAttachment`. As with adding/removing attachments, these changes will not be visible until the character has been reloaded and **the changes are not replicated automatically**.

<figure><img src="/files/ImvCzFeTTddrKHK78uGA" alt=""><figcaption><p>Example of how one might update the colour of an attachment</p></figcaption></figure>

#### Material setup

To access the custom color in the mesh material you must use a specific custom node setup.

The material must have the `MF_SkeletalCrowdPerMeshCustomDataRGB` node followed by a `VertexInterpolator` node. This node handles reading the crowd data if it's in the crowd, or the standard custom parameter if it's an actor.  The material must also have a Vector Param named `CustomValue`, which will receive the data.

A typical setup should look like this:

<figure><img src="/files/tIpqpFGPBvi9UCUa3XW4" alt=""><figcaption></figcaption></figure>

The Index input allows you to swizzle the custom data input channels. Typically this should be left as `0, 1, 2` which will pass the color through unchanged.


# MML Attachments

{% hint style="success" %}
verified: 2025-12-08 version: v39
{% endhint %}

MML can be used to define static mesh attachments that are stored online, and can be socketed to player characters during gameplay. This is an alternative to creating attachment meshes directly as Unreal assets - they can be easier to use as replication is handled automatically, but they can't have custom colors or materials.

### MML Attachment format

The attachment MML files must be in a specific format, consisting of a single `<m-model>` node with a `socket` attribute. The simplest MML attachment will look like this:

```
<m-model socket="hand_r" src="https://my_url/model.glb"></m-model>
```

The socket must be the name of a bone or socket on the UE5 skeleton. When attached, the model's origin will be attached to the specified bone or socket.

You can also optionally specify an extra transform to apply, to translate/rotate/scale the model relative to the socket. This is the full set of attributes to define translation, rotation and scale:

```
<m-model socket="hand_r" src="https://my_url/model.glb"
  x="0.1" y="0.0" z="0.06"
  rx="90" ry="180" rz="0"
  sx="0.25" sy="0.25"sz="0.25">
</m-model>
```

### Adding and removing attachments

You use the `M2M_CharacterAssetComponent` on a player's Morpheus actor to add and remove MML attachments. Calling `Auth_AddMMLAttachment` will add the attachment and return a handle. Pass this handle into `RemoveAttachment` to remove it again (note that the same `RemoveAttachment` function is used for both MML and static mesh attachments).

These functions can only be called on the authoritative client. The attachment is automatically replicated to remote clients, so no manual replication is required (unlike with static mesh attachments).

<figure><img src="/files/v8flXHF25FW2EBE88eN3" alt=""><figcaption></figcaption></figure>

### Live config

Each player character can use and replicate a maximum of 12 Carnival meshes. Because MML attachments are rendered using Carnival, each added attachment comes out of this budget. By default attachments are lower priority that normal character meshes, so if a player's avatar has too many individual meshes then attachments won't render.

You can use the `Carnival.NumMeshesReservedForAttachments` live config to control this. Setting this will ensure at least this many attachments are visible, and limit normal character meshes to the remaining slots.


# The MML Viewer

There is an open-source MML Viewer that can be used to view any MML avatar created:

<figure><img src="/files/1HSzRuspg0xbC2qAEPWC" alt=""><figcaption></figcaption></figure>

## Links

* MML Viewer: <https://viewer.mml.io/main/v1/>
* Github Repo: <https://github.com/mml-io/mml/tree/main/packages/mml-viewer>

## How to view MML avatars

* The following link takes you to a pre-configured version of the MML viewer with good conditions for viewing MML avatars: <https://viewer.mml.io/main/v1/?url=https%3A%2F%2Fcasual-filtered-v1.msquaredavatars.com%2F0.mml&environmentMap=cloudysky&cameraMode=orbit&cameraOrbitSpeed=0&cameraFitContents=true&charAnim=https%3A%2F%2Fpublic.mml.io%2Fcharacter-idle-animation.glb>
* By default it is showing one of our example avatars from [Avatars](/creation/unreal-development/features-and-tutorials/avatars#some-default-characters)
* To view an avatar of your choice:
  * Click the button in the top-right to open the settings

    <figure><img src="/files/Yc3RzicxC8f5bgbK5731" alt=""><figcaption></figcaption></figure>
  * Paste the Url of the MML Avatar you want to view. Click Submit or press the `Enter` key to apply

    <figure><img src="/files/CTXEo2df21sNayxPrFWk" alt=""><figcaption></figcaption></figure>
  * Click and drag the screen to rotate to view your avatar from other angles


# Importing an NFT Collection

Using MML Avatars with your Web3 NFT Collections

In order to setup your NFT collection to work in experience, you will need to do the following steps:

1. Make the Avatar Assets for each NFT in MML
2. Host the MML and any GLBs needed in a public bucket
3. Reference the MML from the NFT

{% hint style="info" %}
**Note:** The ideal implementation will need access to change the NFT collections metadata, please reach out if this is not possible as we maybe able to setup a referral service.
{% endhint %}

## Making MML Avatars

All assets need to be in the GLB format and match our Skeleton, using the import pipeline we have setup. See [Creating MML Avatars with Blender and Free Rigging Tools](/creation/unreal-development/features-and-tutorials/avatars/creating-mml-avatars-with-blender-and-free-rigging-tools) for the correct skeleton and format.

{% hint style="info" %}
From v21 of the platform, we also support [DRACO](https://google.github.io/draco/) compressed glTFs and GLBs
{% endhint %}

To make a collection made up of individual traits, you can either "bake" the GLB, or you can rig the parts of the NFT to use the same skeleton, and use MML to compose them into a unique Avatar.

```json
<m-character src="https://cylinderfolk.xyz/glb/body4.glb">
	<m-model type="Head" src="https://cylinderfolk.xyz/glb/head2.glb"></m-model>
	<m-model type="Hat" src="https://cylinderfolk.xyz/glb/hat5.glb"></m-model>
</m-character>
```

## Reference the MML from the NFT

{% hint style="danger" %}
**Note:** We will need to add your collection to an allow-list so let us know if you plan to add it
{% endhint %}

When we have user Web3 Wallet Connection enabled, we scan the NFTs owned by the Wallet and look for an MML link, and use this to add an Avatar to your collection. Include this by adding the relevant MML URL to the NFT definition, using the `mml` tag.

```json
{
  "attributes": [
    {
      "trait_type": "Head",
      "value": "Round"
    },
    {
      "trait_type": "Hat",
      "value": "Crown"
    }
  ],
  "image": "https://cylinderfolk.xyz/image/210.png",
  "mml": "https://cylinderfolk.xyz/mml/210.mml"
}
```


# Capsules and Mesh Transforms

M2UP's handling of the capsule component and mesh transforms when using MML avatars.

{% hint style="info" %}
The information in this page only applies to versions **before v40**. If you're on v40 or later, this has been replaced with the [Replicated Capsule Component](/creation/unreal-development/features-and-tutorials/replicated-capsule-component) and [Morpheus Animated Skeleton Component](/creation/unreal-development/features-and-tutorials/morpheus-animated-skeleton-component).
{% endhint %}

M2UP provides tooling and automatic handling of capsule components and the mesh transforms on avatars to help deal with MML avatars of different sizes, and how these changes can be applied to avatars in the crowd.

## Skeletal Mesh Transform

### Setting the transform

Render target actors (non-crowd) have a parent capsule component with a skeletal mesh inside. You should generally **not set the transform of your skeletal mesh directly**, since this won't apply to the avatar when they move in and out of the crowd.

Instead, use `SetSkeletalMeshLocalTransform` on the render target's MorpheusActor. This will apply the transform for the render target while it's an actor or in the crowd. You can use `GetSkeletalMeshLocalTransform`on a MorpheusActor to retrieve this transform on a render target even when it's in the crowd.

This mesh transform data is not replicated.

### Automatic handling of translation

By default, M2UP automatically sets the translation of the MeshLocalTransform property whenever the capsule size of the MorpheusActor changes. The translation will be set to place the render target in the centre of the capsule, ensuring the avatar sits squarely on the floor.

You can configure this behaviour on a per-actor basis with `SetCalculateSkeletalMeshTranslationFromCapsule`or globally (including at runtime) with the LiveConfig `game.Capsule.CalculateSkeletalMeshTranslationFromCapsule`.

## Capsule Size

### Setting the capsule size

Render target actors (non-crowd) have a parent capsule component. You should generally **not set the size of your capsule component directly,** since this won't apply when they move in and out of the crowd.

Instead, the render target's MorpheusActor has a replicated CapsuleData property. You can set on the authoritative characters only with `SetCapsuleData` and retrieve the value on all characters with `GetCapsuleData`, using the `UJM_CharacterCapsule` helper functions to use the FCapsuleData struct.

This property is replicated in the background, so all users will see the change to the capsule size.

`OnCapsuleChanged` is a delegate that's fired when the capsule component changes size as a result of locally changing the size on the auth player or receiving a changed size over the network.

### Automatic capsule resizing

Each character loads in with the capsule component specified in the defaults for the pawn class that is spawned (specified in your [character configuration](/creation/unreal-development/getting-started/differences-in-unreal-development-workflow/msquared-character-configuration)). By default, when a player loads in a new MML avatar, the capsule component will resize to include the bounds of that avatar.

`UpdateCapsuleSizeFromAvatar` is the function that's called when characters load in a new avatar, and you can call manually.

If you'd rather keep the capsules all the same size or handle this logic yourself, you can disable this with the `game.Capsule.MatchCustomMesh` LiveConfig.

<figure><img src="/files/NLfEHguDKkvZYnnQSYyX" alt=""><figcaption><p>Viewing capsule colliders with <code>show COLLISION</code> shows the resizes capsules for the different avatars.</p></figcaption></figure>


# Avatar Physics Assets

Assigning and replicating physics assets used on characters with an MML avatar.

## Overview

The Morpheus Platform primarily uses [MML ](/creation/unreal-development/features-and-tutorials/mml#mml-avatars)[avatars](/creation/unreal-development/features-and-tutorials/mml#mml-avatars) for its characters, which allows players to bring in their own custom avatar. The mesh data for this avatar is streamed in to every observing client for rendering, but this does not include physics data, which means that each player will not see a physics asset on any remote player's character.

The Avatar Physics Asset component allows you to configure which physics asset should be assigned to remote characters based on their avatar. You can assign a global physics asset to be used for all characters, configure your game to only use capsule components, or assign different physics assets depending on the shape of the character's avatar.

## Quickstart

### Configuring the AvatarPhysicsAssetComponent

Create an `AvatarPhysicsAssetComponent` by creating a child class of `M2M_AvatarPhysicsAssetComponent` .

<figure><img src="/files/imUAXfMhJ19gFeu2rUoV" alt=""><figcaption></figcaption></figure>

The important fields are:

* **Avatar Physics Asset Data:** This configures which physics asset the character should use on remote clients. This is covered in the next section.
* **Interaction Query/Collision Channel:** These are the channels that are dynamically enabled/disabled (by being set to ignore or block) by this component according to your configuration, to be used for your gameplay line tracing and collision. For example, these channels will be enabled and disabled on your character's Capsule according the configurations in this component.

Add this component to your Morpheus Character.

<figure><img src="/files/DriG4OHnJvceVrhvEOrp" alt=""><figcaption></figcaption></figure>

### Configuring the Avatar Physics Asset Data

The Avatar Physics Asset Data controls which physics asset each character should be assigned on remote clients according to the avatar that character is currently using. Create an `AvatarPhysicsAssetData` (a Data Asset) by creating a child Data Asset of `M2_AvatarPhysicsAssetData`.

{% hint style="info" %}
M2UP comes with some example `AvatarPhysicsAssetData` assets for you to get started with right away, instead of creating your own:

* `DA_M2_HumanoidIfApplicable_PhysicsAssetData` : Assigns the character a humanoid physics asset if and only if the character's avatar is roughly humanoid shaped.
* `DA_M2_AlwaysHumanoid_PhysicsAssetData` : Always assigns the character a humanoid physics asset.
* `DA_M2_EmptyPhysicsAssetData` : Never assign a physics asset to the character. By default, this will enable the Interactable channels for your character's Capsule component.
  {% endhint %}

Add an element into the `Avatar Physics Asset Infos` array.

<figure><img src="/files/RV0YgV22cz0eQ9hIvYaO" alt=""><figcaption></figcaption></figure>

* **Ingame Physics Asset**: The physics asset to assign this character if the character's avatar matches the *Avatar Shape Rule*.
* **Avatar Shape Rule**: An asset representing a function that takes an avatar mesh as input and returns true or false, depending on whether the avatar matches this rule. Information on creating your own custom rule from scratch, or from customising M2UP's *skeleton bounds rule* is covered below. You can also use the example rules contained in M2UP: `BP_M2_AlwaysValidAvatarShapeRule` and `BP_M2_IsHumanoidAvatarShapeRule` . The latter should only match avatars which are approximately humanoid in shape.
* **Approximate Skeletal Mesh** (Used only in the [Crowd](/creation/unreal-development/features-and-tutorials/the-animated-crowd)). The Skeletal Mesh asset that the [Raycastable Crowd](/creation/unreal-development/features-and-tutorials/enabling-raytracing-for-crowd-members) actor will use to represent this character, when this character is part of the crowd and its avatar matches this entry's rule. This should be a Skeletal Mesh asset that appropriately matches the *Ingame Physics Asset.*

As an example, if I want my character to be assigned *PHYS\_UE5Mannequin* whenever their avatar matches the *BP\_M2\_IsHumanoidAvatarShapeRule* (i.e. when the avatar is approximately humanoid shaped and sized), the Physics Asset Info should look like this.

<figure><img src="/files/RgodNFcfOriNzIRSOsU2" alt=""><figcaption><p>I expect characters matching this rule to be approximately the same shape and size as SK_UE5Mannequin, so that's what I've specified for the Approximate Skeletal Mesh to be used by my Raycastable Crowd.</p></figcaption></figure>

{% hint style="info" %}
You can add multiple entries to the Avatar Physics Asset Infos array to match different physics assets to different characters depending on their avatar. In the case that multiple rules match an avatar, the first entry in the array that matches will be used.

However, using multiple avatar physics assets will limit the scale of your game, as there is currently a performance cost associated with swapping physics assets in [pooled character actors.](/creation/unreal-development/features-and-tutorials/actor-pooling)

To get the best performance out of high scale games, use a maximum of one entry in this array.
{% endhint %}

If a character uses an avatar that doesn't match any of the Avatar Physics Asset Infos, the function `M2M_AvatarPhysicsAssetComponent.HandleInvalidPhysicsAsset` is invoked. By default, this enables the Capsule component to block the Interactable channels, but can be overridden.

{% hint style="info" %}
The capsule component on M2 characters automatically resizes to match the mesh by default. More info on this can be found [here](/creation/unreal-development/features-and-tutorials/avatars/capsules).
{% endhint %}

### Testing the Avatar Physics Asset Component

You can use the Unreal `show collision` command to view the physics assets in use. Your local player uses your mesh's generated physics asset, so to see the effects of the Avatar Physics Asset Component, start a PIE session with 2 clients. You should see that for each client, the remote character has been assigned a physics asset according to the rules.

## Customising your Avatar Shape Rules

M2 has a pre-configured *SkelBoundsAvatarShapeRule* that determines if an avatar fits between bounds which you can configure. Alternatively, you can write your own rule that derives from `UM2_AvatarShapeRuleBase` .

### Skeleton Bounds Avatar Shape Rule

The `UM2_SkelBoundsAvatarShapeRule` is a rule that determines whether an avatar is between the bounds of two assets, with certain tolerances. This can be used to determine if an avatar is appropriate for a given physics asset.

For example, this is the the `BP_M2_IsHumanoidAvatarShapeRule` that extends `UM2_SkelBoundsAvatarShapeRule` .

<figure><img src="/files/0sZ2954MLjHXIpkNSbXd" alt=""><figcaption></figcaption></figure>

* **Max/Min Physics Asset:** The auto-generated physics asset for the user's mesh should be mostly within these bounds.
* **Reference Anim**: This is the animation that will be used on the user's mesh to determine if the mesh is within bounds. This should be a neutral animation pose, like a T pose.
* **Voxel Edge Length:** The comparison works by dividing the volume of the player's mesh into voxels and counting the number of voxels that are in or out of the bounds. This field determines how big these voxels are. Small voxels gives more accuracy but worse performance.
* **Required Min Coverage:** The fraction of the minimum physics asset that must be covered by the user's mesh. Set to a higher value to be less tolerant of user mesh being smaller or not covering certain parts of the min physics asset.
* **Max Allowed Out Of Bounds:** The fraction of the user's mesh that is allowed to be outside the max physics asset bounds. Set this to a lower number to be less tolerant of a user mesh being too large in parts compared to the max physics asset.
* **Debug Draw Voxels:** Draw the voxels used for comparison, with voxels coloured according to if they are in or outside the bounds.
* **Debug Draw Collision Elements**: Draw the comparison physics assets alongside the mesh's auto generated physics assets.

Alongside the **Debug Draw** settings, this rule will output in the `LogM2AvatarPhysicsAsset` category to give additional information about why the rule did or did not match an avatar.

<figure><img src="/files/zNbs1QxsAJQ5aCVIughv" alt=""><figcaption><p>Red voxels indicate areas where the user mesh exceed the max bounds, which according to the output log is 83% of the input match, so this does not match the rule that only has a 23% tolerance for Max Allowed Out Of Bounds.</p></figcaption></figure>

You can also access metadata about the result of the avatar rule matching on the local client (whether the avatars were too big, small, or a different error) in the `UM2M_AvatarPhysicsAssetComponent.LocalAvatarShapeRuleResults` property.

### Creating a custom rule

You can also create your own custom Avatar Shape Rule. Create a child class that extends `M2 Avatar Shape Rule Base` and override `Does Avatar Shape Meet Rule` .

<figure><img src="/files/nEwiKP6rInu2S8pdhv0u" alt=""><figcaption></figcaption></figure>

Here, you can write custom logic to determine if the input avatar skeleton should match the rule. The struct that is returned should contain `IsValid=true` if this avatar did match the rule; the other properties are for observability purposes only.


# Bots

Bots (also known as "simplayers") are fake players that help creators representatively test game performance, rendering and networking by simulating high player counts.

## **Adding bots to a world** <a href="#part-1-spawning-bots" id="part-1-spawning-bots"></a>

You can add bots directly to a launched world by navigating to the "Operations" tab on your project Dashboard.

<figure><img src="/files/uSo2jjGnE4ubZDmRClQM" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/hL1CvKwxTY114Zj7grty" alt=""><figcaption></figcaption></figure>

After a few minutes, you should see bots start to appear in your world

<figure><img src="/files/PgcSDqAMADakWY56DGsQ" alt=""><figcaption></figcaption></figure>

## **Adding bots locally** <a href="#part-1-spawning-bots" id="part-1-spawning-bots"></a>

In the Play dropdown, set the `Number of Players` to `2` (or more) players.

<figure><img src="/files/sYNMd5M8FA6AFPLIKZnB" alt=""><figcaption></figcaption></figure>

Open `Editor Preferences`, search for `Editor Client Connection Types`

First, add `Player` connection type, then a `Bot` connection type. If you added more than 2 players in the previous step, add more `Bot` connection types. If you want multiple bots per bot client, you can specify this in the `NumOfBots` field.

<figure><img src="/files/u6scpZeqU7jxbzub59Aa" alt=""><figcaption></figcaption></figure>

Pressing `Play` will now spawn an additional window for each bot connection

<figure><img src="/files/HJnQrKDn3PeThkb4t3Fq" alt=""><figcaption></figcaption></figure>

## **Bot behaviors** <a href="#part-2-performing-behaviours" id="part-2-performing-behaviours"></a>

### **Overview**

Bot behaviours describe what actions the bot takes after spawning.

In the `Outliner` panel, ensure your level has a `BotBehaviorStore` (if not, add one).

The bot behavior store controls what behavior is run on the bots, based on what command you give them.

<figure><img src="/files/rWRe4kc6GixHiOunwIa7" alt=""><figcaption><p>In this example, the <code>emote</code> command will run the <code>BT_BotEmote</code> behavior tree, and so on.</p></figcaption></figure>

In a PiE session, press `` ` `` to open the console.

Type `Morpheus.Bots.List` to list available bot behaviours in the Output Log.

<figure><img src="/files/QtTAlcPd2O6hEBPidbz1" alt=""><figcaption></figcaption></figure>

Enter `Morpheus.Bots.Run emote` (or another entry), and all running bots should change their behaviour accordingly.

<figure><img src="/files/86ZNAws1oTP4Pdj0XTEj" alt=""><figcaption></figcaption></figure>

### **Setting a "default behavior"**

The "default bot behavior" is controlled via live config: `Bots.BotDefaultBehaviour` (in the `Game` config). Whatever value this is set to, bots will start up running that behavior.

(If this value is set to be empty, then the bots will not run any behavior until you explicitly tell them to)

### **Adding new behaviors**

Bot behaviors are implemented using Unreal behaviour trees. To implement behavior trees, you can reference the existing behaviors or consult the Unreal docs:

* [![](https://docs.unrealengine.com/4.27/Include/Images/site_icon.png)Behavior Tree Overview](https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreesOverview/)
* [![](https://docs.unrealengine.com/4.27/Include/Images/site_icon.png)Behavior Tree Quick Start Guide](https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeQuickStart/)
* [![](https://docs.unrealengine.com/4.27/Include/Images/site_icon.png)Behavior Tree User Guide](https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeUserGuide/)

Once created, add your behavior tree to the list of behaviors on the bot behaviour store in your level (giving it a unique name).

<figure><img src="/files/W9xfDoDFViHw9k2Eb09d" alt=""><figcaption></figcaption></figure>

In a PiE session, type `Morpheus.Bots.List` and you should see your new behavior name.

Type `Morpheus.Bots.Run <behaviour_name>` and all bots should start to execute your behaviour tree

#### Teardown behaviors

Since behaviors can be stopped at any point during their behavior tree (e.g. if you call `Morpheus.Bots.Run [Some other behavior]` whilst one is running, we can get into bad states if any logic was set for the duration of the test that should not be present when running other behaviors.

Our solution to this was adding `TearDownBehaviors` to the behavior store. This behavior is run once you switch away from a given behavior, so can be used to clean up any state the behavior used.

* If you have a behavior `[behavior_name]` in your behavior store's `Behaviors` map, that requires teardown logic, add an entry to the `TearDownBehaviors` map, with a matching `[behavior_name]`
* Do your cleanup logic in that teardown behavior tree. Once you are done, call `BTT_MarkTearDownComplete` to inform the bot manager system that the teardown of the previous behavior has finished.
* The bot will then move on to running the next behavior.

{% hint style="info" %}
NOTE: Any teardown behaviors must include the `BTT_MarkTearDownComplete` at the end of their behavior trees. This marks that the teardown is complete, and so we can move on to the next behavior. Otherwise, the bots will be stuck in their "tearing down" state forever.
{% endhint %}

<figure><img src="/files/3DatXnn0fp3aXuNWpPKX" alt=""><figcaption><p>The <code>roles</code> teardown behavior (<code>BT_BotSwitchRolesTeardown</code>) is run when you stop running the <code>roles</code> behavior, and makes sure that the bots return to the default role, rather than being stuck in whatever role the running behavior had previously set them to.</p></figcaption></figure>

## Using State Tree

{% hint style="info" %}
NOTE: The StateTree plugins have been enabled for MSquared as of release v35.
{% endhint %}

[![](https://docs.unrealengine.com/4.27/Include/Images/site_icon.png) StateTree Unreal Documentation](https://dev.epicgames.com/documentation/en-us/unreal-engine/state-tree-in-unreal-engine)

Unreal's StateTree system can also be used to run bot behaviors, in a different setup to our existing setup. If you want to use this, you can, but we would recommend you disabling the existing bots system (turn off the default behavior in [#setting-a-default-behavior](#setting-a-default-behavior "mention") to make sure the two systems are not conflicting). Otherwise, this system should largely work in MSquared in the same way as native Unreal.

Some things to take care with:

* Any replication will still need to be handled through Morpheus Actors
* If the state tree is set to start automatically, the logic may run before the bots have set up correctly. The bots are given their appropriate bot controller via the morpheus actor, and this may not be set up when the character starts running its behavior tree. This can be handled by waiting for the appropriate controller, e.g. by using the bootflow\\

  <figure><img src="/files/JdWPxBuvKcOKhBTFllsw" alt=""><figcaption></figcaption></figure>
* Make sure that the state tree is only run on bot clients!

## Calling server RPCs

In test deployments, multiple bots can run on the same cloud instance, each pretending to be a player with their own client connection. That means that multiple client connections share an Unreal client.

This introduces a complication: when client code invokes an [RPC](/creation/unreal-development/getting-started/networking/morpheus-rpcs) on the server, it's not always obvious which of these client connections the RPC should go via.

For example, suppose you have a [singleton](/creation/unreal-development/features-and-tutorials/singletons) `AMorpheusActor` with a server RPC, let's say `KillCallingPlayer`. The RPC's handler function will rely on `ServerGetRpcCallerConnection` to securely identify which player to kill. By default, the RPC will be sent via the client connection which created the singleton. However, when multiple bots share an Unreal client, they also share the client's singletons, so by default it's probably the wrong bot who'll get killed.

To get round this problem, you can use the `AMorpheusActor` function `PushRpcSenderConnection` to specify which client connection to use, before calling your RPC. Make sure to either set its `PopAfterNextRpc` flag or else clean up manually by calling `PopRpcSenderConnection` after calling the RPC. For example:

<figure><img src="/files/n0OntUyJr4BD7YkpaNm4" alt=""><figcaption><p>PushRpcServerConnection on client, ServerGetRpcCallerConnection on server</p></figcaption></figure>

N.B. The default client connection used for an RPC is the one which was used to created the `AMorpheusActor` which the RPC belongs to. That means that you don't need to bother with this step if the RPC belongs to a `PlayerCharacter` actor - each bot's own character gets created by its own client connection.


# Capabilities

{% hint style="success" %}
verified: 2025-12-04 version: v39
{% endhint %}

'Capabilities' are the concept of certain players, or groups of players, having sets of permissions. This is often tied into the [Roles](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/in-game-roles) system to give special abilities to 'admin' players in a world (for example presenters in a live experience, moderators or QA), or could be used to enable certain player features at the right time (for example the ability to fire a weapon once a round has started).

Capabilities are a set of server-authoritative Gameplay Tags for each player, replicated and queried with the `JM_CapabilitiesComponent`. Capabilities are only replicated to the owning Morpheus Actor, so are not visible to other players.

## Usage

### Granting and removing

Ensure the player's Morpheus Actor contains a `JM_CapabilitiesComponent`. On the server, grant capabilities either individually or as a set:

<figure><img src="/files/pVYHKdx32kE2wfQmNZ1Z" alt=""><figcaption></figcaption></figure>

Capabilities are reference counted, or 'stacked', meaning that if the same capability is granted twice (e.g. by two different systems) then the player will still have that capability until it has been removed twice. Use the equivalent `RemoveCapability` or `RemoveCapabilities` nodes to remove.

Once granted or removed, capabilities are replicated to the controlling client. Gameplay actions can be gated on capabilities by using any of the these functions:

<figure><img src="/files/slB00oZos5Y44xG2I1hU" alt=""><figcaption></figcaption></figure>

### Suppression

Capabilities can be 'suppressed' on the server, using the same capability stack concept. If a capability is suppressed then it will be removed from the player, regardless of how many stacks of that capability the player may have. This can be used for temporarily disabling a capability while not interfering with other systems, for example muting all players while a custscene occurs in a live event.

<figure><img src="/files/0LtRZKv8K3gqmiROwax2" alt=""><figcaption></figcaption></figure>

### Responding to Capability changes

Bind to the `OnCapabilityAdded`, `OnCapabilityRemoved` and `OnCapabilitiesUpdated` events to respond to changes. `OnCapabilitiesUpdated` will be called both when capabilities are added or removed.

<figure><img src="/files/V221QwtOFIsOBweqiuMm" alt=""><figcaption></figcaption></figure>


# Chat

Ways for Users to Communicate

MSquared has built-in support for text and voice chat.

* For voice chat, see [Crowd Audio](/creation/unreal-development/features-and-tutorials/crowd-audio)
* For text chat, see [Unreal Text Chat](/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat)
  * If you are using the deprecated PubNub chat system, see[Broken mention](broken://pages/RLs1TRNHQYPFeQOzDr56)


# Community Sift

Moderation Technology

{% hint style="danger" %}
Due for **Removal**, please speak to support for further info.

**07/11/2024:** As we simplify the platform, we will create a chat option entirely contained within Unreal. This will not include a moderation system, but will be implemented in such a way that projects should be able to implement their own moderation services themselves.

It has yet to be determined at what point MSquared will stop using Community Sift, but it will be messaged out to customers ahead of time so they can begin setting up their own solution in its place.

Please reach out to your Support Team with any questions.
{% endhint %}

<figure><img src="/files/weB085PGINO8DOQWoHcp" alt="" width="375"><figcaption></figcaption></figure>

### Overview <a href="#moderation-overview" id="moderation-overview"></a>

MSquared platform currently has an available integration with CommunitySift which allows for manual moderation of text and voice logs in real time, as well as automatic moderation.

This is separate from the profanity filter present in the [default text chat](https://docs.msquared.io/tutorials-and-features/communication/text-chat).

***

### **CommunitySift provides the ability to:**

Follow text and voice messaging in real time to identify bad actors

<figure><img src="/files/NSVT9vzqhByTFj3HzLGk" alt=""><figcaption><p>Moderation Log</p></figcaption></figure>

Set bespoke policy guidelines, linking words or phrases with moderation topics

<figure><img src="/files/2g9IwMonEVBGY6Q9T42V" alt=""><figcaption><p>Policy Guide</p></figcaption></figure>

Bundle these phrases into easy to navigate content queues

<figure><img src="/files/NruBoWsAjZZwun6a6wom" alt=""><figcaption><p>Content Queue</p></figcaption></figure>

Text and voice messages can then be moderated within these content queues

<figure><img src="/files/UibrXL8KVJy9QlYlwB7J" alt=""><figcaption><p>Identified phrases</p></figcaption></figure>

Options are then provided on how to manage the user to Mute, Suspend (for a defined period of time) or to Ban them

<figure><img src="/files/mnkIFWT8aqs2KQKq7Ur5" alt=""><figcaption><p>Moderation option</p></figcaption></figure>

***

### Requesting CommunitySift access

Currently the license and access to CommunitySift is managed by MSquared, so if you would like to utilise this, or have MSquared provide moderation for your event please get in touch.


# Unreal Text Chat

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

In [Example Plugin](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin), we have a simple example chat system that can be used for small/medium sized experiences. It doesn't use an external web service (e.g. PubNub), instead handling the messaging through the Unreal machines, via Morpheus networking.

<figure><img src="/files/PbjjmEDp4QYrq7xwCm9g" alt=""><figcaption></figcaption></figure>

## The main classes

### The singleton (BPM\_M2Example\_TextChatSingleton)

This is the morpheus actor that handles the networking involved in sending these Unreal text chat messages. Clients call `SendChatMessage`, which sends an RPC to the server. The server then reviews the message, and broadcasts it to the clients via a multicast RPC.

<figure><img src="/files/QMtH7fRwNQzQBdziEmHF" alt=""><figcaption></figcaption></figure>

#### A note on moderation

We add a `ProcessMessage` step at the point of receiving a `Server_SendChatMessage` RPC, which acts as an entry point for adding moderation/chat filtering. The example is just a simple check that rejects messages that are too long, but more complex moderation could be added here, such as rejecting certain words, or interacting with an external service like CommunitySift.

(Note that adding complex logic to this `ProcessMessage` method may slow the server down at scale, since the computation is being run on the server for each message that gets processed in this example)

<figure><img src="/files/05o7iHZ7EEOkHTT6pRHa" alt=""><figcaption></figcaption></figure>

#### Rate Limiting

{% hint style="warning" %}
Rate Limiting is entirely optional, but highly recommended. We scale test our content with the settings detailed below and cannot guarantee a performant experience if lower limits are used or this logic is removed.
{% endhint %}

If you look at `BPMC_M2Example_TextChatComponent` you will find an example of how we rate limit on clients. The intent here is to limit the number of messages processed by the server to reduce impact on performance. Rate limiting here scales so that as the user count increases, a delay is added to the message being sent making it harder for a single user to spam the server's Text Chat Singleton. Default values will add up to 1 second of delay per 1000 users in the experience.

Change variable `Rate Limit Length Per Divisor` to alter max delay that can be applied per user increment.

Change variable `Rate Limit Player Divisor` to alter the threshold at which delay is increased.

<figure><img src="/files/gTQ3skpA3KqVtMeV0S0n" alt=""><figcaption><p>Client-side rate limiting as seen in BPMC_M2Example_TextChatComponent</p></figcaption></figure>

Additionally, we have functionality on `BPM_M2Example_TextChatSingleton` which also rate limits messages sent to clients, reducing the amount of widgets added per tick.

<figure><img src="/files/BTAEUci1qEP9G85ASgUz" alt=""><figcaption><p>Server-side rate limiting as seen in BPM_M2Example_TextChatSingleton</p></figcaption></figure>

### The text chat component (BPMC\_M2Example\_TextChatComponent)

This component is added to the character's MorpheusActor, and is responsible for communicating with the singleton, sending messages through it, and listening to messages received by it.

### The UI (WBP\_M2Example\_TextChat)

This is the widget added to the example HUD that listens to the text chat component, adding any received messages to the "message history", and sending any messages typed in to the input box (`WBP_M2Example_TextChatInputField`).

`WBP_M2Example_TextChatMessage` and `WBP_M2Example_TextChatInputField` have some added logic to handle adding emojisto the messages.

<figure><img src="/files/YE7hUJc1ehVHmc57K5kY" alt=""><figcaption></figcaption></figure>

#### A note on performance

Adding widgets is a nontrivial operation for the client, so adding a large number of messages in a single tick is going to slow down the client. In this example we have mitigated this with the rate limiting done by the singleton, limiting it so that just a few messages are received per tick.


# PubNub Text Chat

Text chat between the web and in event experience

{% hint style="danger" %}
Due for Simplification, please speak to support for further info.

**31/01/2025:** MSquared is not maintaining the text chat that uses PubNub and Community Sift. We do provide a simple example of text chat that does not use these features (see [Unreal Text Chat](/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat)). If customers wish to continue using these services, they need to speak to the Solutions Engineering team for guidance on how to implement this within their project outside of what MSquared provides off the shelf.

When MSquared drops support for PubNub, we will no longer support Web-to-Unreal text chat. Chat will be limited to Unreal Worlds within MSquared.

This legacy text chat is used in the deprecated UI elements (`WBP_Origin_HUD` still uses the deprecated `WBP_M2_TextChat`, however the M2 Example plugin does not use this, instead using a different `WBP_M2Example_TextChat`, which points to the new Unreal chat component.

Until MSquared completely drops support of PubNub and Community sift, they will remain functional. When the new simplified chat lands, the old chat widget will remain within the platform for customer use.

MSquared will not be addressing non-critical and cosmetic issues relating to Text Chat during this process of simplification. Please reach out to your Support Engineers with concerns.
{% endhint %}

{% hint style="warning" %}
If your project is running on V37 or older, you may have to use alternative settings. Please reach our to your Support Engineer to assist you.
{% endhint %}

{% hint style="info" %}
**Beta Quality** - Customers are encouraged to test and use Beta features in their experiences, but may still require some support
{% endhint %}

### Overview <a href="#in-and-out-experiencechat-overview" id="in-and-out-experiencechat-overview"></a>

The ability to chat on web and in game, including:

* Chat from Web to Unreal and back
* Works on Desktop and Mobile\*
* Text appears in game above the head
* Ability to hide and show the widget, and custom sizing
* User name and profile image appending to the message

The in-and-out-experience chat is backed by [PubNub](https://www.pubnub.com/). For battle-tested, in-experience only chat, see [Experience Only Chat](/creation/unreal-development/features-and-tutorials/communication/text-chat/in-experience-chat/experience-only-chat).

{% hint style="danger" %}
\* Mobile is currently only supported via the old chat UI ([Cloud Chat](https://app.gitbook.com/o/N6rN2gq2jZJWtEY3WRk3/s/oWTlPaoHd1McSakqMigu/~/changes/496/tutorials-and-features/communication/in-and-out-experience-chat/in-experience-chat/cloud-chat)). See [Adding Mobile support](#adding-mobile-support) to continue use of this version of the text chat for desktop
{% endhint %}

## Integration <a href="#integration" id="integration"></a>

1. Make sure you have a safe internal world id set up for your editor users.
2. Configure the variable `Social.Chat.Editor.World` in `deployment.json` with this value (see below)

## How to enable <a href="#how-to-enable" id="how-to-enable"></a>

1. Enable `TextChat.UseCloudChat` in `game.json`.
2. Make sure your in-game HUD is set up to use the new chat system

The following settings in `game.json` influence the Text Chat feature:

<table data-header-hidden><thead><tr><th width="290.3333333333333">Setting</th><th width="306">Description</th><th>Default Value</th></tr></thead><tbody><tr><td><strong>Setting</strong></td><td><strong>Description</strong></td><td><strong>Default Value</strong></td></tr><tr><td><code>TextChat.UseCloudChat</code></td><td>Enables the cloud chat functionality</td><td>true</td></tr><tr><td><code>TextChat.ForceMobileView</code></td><td>Forces mobile view regardless of detected platform</td><td>false</td></tr></tbody></table>

## How to enable Text chat in Editor

The steps taken will depend on your sign-in settings. Navigate to `Editor Preferences` > `General` > `Sign in Settings`. If `Use Local World For PIE` is enabled then follow the instructions for using a local world below. By default, this setting should be true.

{% tabs %}
{% tab title="Using local world" %}
If you are using local world sign in then nothing needs to be done. You will automatically be configured a chat channel named after your users unique local world Id.
{% endtab %}

{% tab title="Not using local world" %}
Create a `deployment.override.json` in your project live config directory (Config/LiveConfig/Overrides) and add the following, replacing the `World` value with any unique name for your chat channel.\\

<pre><code><strong>{    
</strong><strong>    "Social": { 
</strong>        "Chat": { 
<strong>            "Editor": { 
</strong>                "WorldSource": "LiveConfig", 
                "World": [REPLACE WITH WORLD ID] 
<strong>            }
</strong>        }
    }
}
</code></pre>

{% endtab %}
{% endtabs %}

## Live Config configuration

The following `deployment.json` live config fields influence the Text Chat feature:

| Setting                                                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | Default Value                             |
| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `Social.Chat.WorldSource`                                 | <p>Determines how the client should determine the world id to use for chat.<br></p><p>The values are as follows:</p><ul><li><mark style="color:blue;"><code>Domain</code></mark> - Uses the current <code>WorldId</code> value of the Domain Configuration Subsystem. This can change per-player at runtime. Therefore a single users chat channel can change during the game. For example if the player world travels.</li><li><mark style="color:blue;"><code>LiveConfig</code></mark> - Uses the <code>Social.Chat.World</code> value. As a live config value this can be changed for all players by modifying the live config settings via the dashboard.</li><li><mark style="color:blue;"><code>CommandLine</code></mark> - Uses the client cli launch arguments. These are static throughout gameplay for each client and therefore even if you world travel, clients will continue to use the same chat channel</li></ul> | <mark style="color:blue;">`Domain`</mark> |
| `Social.Chat.World`                                       | <p>This is a generic, hard coded chat channel name.</p><p>It is named "World" because the other sources will use the world Id however any unique name could be used as the chat channel</p><p><strong>Only used when <code>Social.Chat.WorldSource</code> is set to <code>LiveConfig.</code></strong></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | *Empty*                                   |
| `Social.Chat.Editor.WorldSource`                          | <p>Exactly the same as <code>Social.Chat.WorldSource</code> but used when in the Editor. For example in Play-in-Editor (PIE) scenarios.<br><br><strong>The default value will only work if you are signing in with a local world. If you are not using a local world, you should change this value.</strong></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | <mark style="color:blue;">`Domain`</mark> |
| Social.Chat.Editor.World                                  | <p>Exactly the same as Social.Chat.World but used when in the Editor. For example in Play-in-Editor (PIE) scenarios.<br><br><strong>Only used when <code>Social.Chat.Editor.WorldSource</code> is set to <code>LiveConfig.</code></strong></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | *Empty*                                   |
| <p>M2.Domains.WorldId</p><p><strong>(LEGACY)</strong></p> | <p>The world id in the web to scope the chat to.</p><p>This must match the web portals if you want cross-experience chat.</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |                                           |

## Adding Chat to your HUD

Add `WBP_M2_TextChat` to your HUD and ensure it is stretched across the whole screen.

### Adding Mobile Support

`WBP_M2_TextChat` does not yet support mobile platforms. If your HUD is or derives from `WBP_TH_HUD` then your good to go. Otherwise follow the below steps:

Use a widget switcher to switch between `WBP_M2_TextChat` and `WBP_TextChatWindow_Mobile` with the following code to allow it to automatically revert to the old UI for mobile devices.

1. On Bootflow finished, add a handle to get live config updates.

<figure><img src="/files/k15Nxe6bz8iZJZ7ZG5am" alt=""><figcaption><p>Add a Handle to Config Updated to get Live config event updates</p></figcaption></figure>

2. Create a function called Update Live Config and add the following:

<figure><img src="/files/4PcrpEI5JeEFFG5Db1KB" alt=""><figcaption><p>Create a function which determines which chat UI version to use</p></figcaption></figure>

## Full Live Config Setting List

Settings marked (LEGACY) may be removed in a future update

| Setting                                                             | Description                                                                                                                         | Default Value |
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `TextChat.GlobalChatEnabled`                                        | Enables the Global Chat channel                                                                                                     | true          |
| `TextChat.UseCloudChat`                                             | Enables use of the cloud based chat system, linking the in game chat with web chat                                                  | true          |
| `TextChat.ForceMobileView`                                          | Forces the old Chat UI (`WBP_TextChatWindow_Mobile`) to a full screen mobile view, regardless of platform or device used            | false         |
| `TextChat.ForceMobileUI`                                            | Force the old Chat UI (`WBP_TextChatWindow_Mobile`) to be used over the new `WBP_M2_TextChat` regardless of platform or device used | false         |
| `TextChat.StartMinimized`                                           | Sets the chat interfaces to start in a minimized state                                                                              | true          |
| `TextChat.EmojiMenuEnabled`                                         | Enables the in game emoji menu to be used. Only supported in `WBP_M2_TextChat`                                                      | true          |
| `TextChat.ReactionsEnabled`                                         | Enables message reactions. Still WIP, not yet supported in Origin                                                                   | false         |
| `TextChat.MaxHistoryMessages`                                       | Max messages to be displayed in the chat interface                                                                                  | 100           |
|                                                                     |                                                                                                                                     |               |
| <p><code>TextChat.LocalChatEnabled</code></p><p>(LEGACY)</p>        | Enables Local chat functionality for Experience only chat                                                                           | true          |
| <p><code>TextChat.LocalRateLimitPerSecond</code></p><p>(LEGACY)</p> | Maximum number of messages a player can send per second                                                                             | 10            |
| <p><code>TextChat.LocalRateLimitQueueSize</code></p><p>(LEGACY)</p> | Defines the message queue size for the local chat server                                                                            | 100           |
| <p><code>TextChat.AllowQuestions</code></p><p>(LEGACY)</p>          | Allows questions to be sent in chat                                                                                                 | false         |


# Moderation

MSquared platform currently has internal tooling for moderation of text and voice logs in real time, as well as automatic moderation. This includes basic features like muting, timing out, and banning.

This is separate from the profanity filter present in the [default text chat](https://docs.msquared.io/tutorials-and-features/communication/text-chat).


# Legacy Text Chat

Options for legacy text chat systems

***

{% hint style="info" %}
**Stable -** Can be used with minimal support by referencing documentation and examples
{% endhint %}

[Experience Only Chat](/creation/unreal-development/features-and-tutorials/communication/text-chat/in-experience-chat/experience-only-chat) - Text chat only in experience


# Experience Only Chat

Only Experience Chat

<figure><img src="/files/5SDPuaoeVIvaFFEinm3A" alt=""><figcaption><p>Legacy Text chat does not support Web</p></figcaption></figure>

{% hint style="info" %}
**Stable -** Can be used with minimal support by referencing documentation and examples
{% endhint %}

## Overview <a href="#in-experiencechat-overview" id="in-experiencechat-overview"></a>

This plugin provides support for sending and receiving chat messages in a Morpheus project while offering flexible moderation options and custom data per message. Features include:

* Broadcast chat messages to all `MorpheusChatReceiverComponents` via an authoritative `MorpheusChatSenderComponent`
* Install arbitrary message filters into the chat server to accept or reject messages based upon custom rules
* Have arbitrary actors act as moderators by giving them a `MorpheusChatModeratorComponent`
* Assign custom data to each message which can be changed by moderators and filters

The plugin is based around a few main parts:

* `FMorpheusChatMessage`

  This is the struct containing all relevant information about a chat message:

  ```
  USTRUCT(BlueprintType)
  struct FMorpheusChatMessage
  {
      GENERATED_BODY()

      // Unique ID used to identify this message in the MorpheusChat plugin
      UPROPERTY(BlueprintReadOnly)
      int32 MessageId;

      // The actor who sent this message via its MorpheusChatSenderComponent
      UPROPERTY(BlueprintReadOnly)
      class AMorpheusActor* Sender;

      // The message content
      UPROPERTY(BlueprintReadOnly)
      FString Message;

      // The server time when this message was initially received
      UPROPERTY(BlueprintReadOnly)
      float ServerTime;

      // Project-specific data associated with this message
      UPROPERTY(BlueprintReadOnly)
      int32 CustomData;
  };
  ```
* `AMorpheusChatServer`

  The chat server provides the backend for sending and receiving messages. It keeps track of all messages and broadcasts them via multicast to all clients. You should only have a single chat server in your world.
* The three chat component types
  * `AMorpheusChatSenderComponent`

    Any actor with this component can attempt to broadcast a chat message to all receivers. Derived classes can override `CanSendMessage` to put restrictions on when to allow message broadcasting according to project rules.
  * `AMorpheusChatReceiverComponent`

    Each client actor with this component receives all chat messages multicast by the chat server. It's up to the project to decide what to do with each message, whether to cache a number of recent messages etc.
  * `AMorpheusChatModeratorComponent`

    An actor with a moderator component can act as a message filter and accept or reject messages based on project rules. They can also update custom data for already sent messages.
* Message filters

  By default all messages received by the chat server are multicast to all receivers. However, projects can define custom rules to decide which messages are accepted and which should be rejected. This functionality is exposed via the `IMorpheusChatFilter` interface. Projects can implement arbitrary filters and install them into the chat server or into other filters that accept children.

## Integration <a href="#in-experiencechat-integrationintoyourproject" id="in-experiencechat-integrationintoyourproject"></a>

To integrate the Chat plugin, follow these steps:

1. Spawn an instance of `AMorpheusChatServer` into your server world
2. Derive a class from `AMorpheusChatReceiverComponent` and override `HandleMessageReceived`. In your override, decide what to do with each message, e.g. expose it to UI, cache an array of the last messages etc. Put this component on each client-authoritative actor that needs to receive chat messages
3. *(optional)* Override `HandleUpdateCustomData` on your receiver component if you want to support updating custom data for messages that were already sent. One use case would be where a moderator can decide later to highlight a message that was already sent by setting a flag in the custom data. Since you only receive the `MessageId`, you need to cache a reasonable number of received messages on the client and look it up yourself to get any benefit out of this feature
4. Put a `UMorpheusChatSenderComponent` on all client-authoritative actors that should be able to broadcast messages
5. *(optional, recommended)* Derive your own sender component and override `CanSendMessage` to control the conditions when a message is allowed to be sent. This function is called on both client and server.
6. *(optional, recommended)* Write any number of message filters and install them into your chat server
7. *(optional)* Derive a `UMorpheusChatModeratorComponent` and put it onto actors that should moderate messages before they are multicast to everyone. Register the component as a message filter in your chat server. Implement client-side UI to show pending messages to moderators so that they can accept or reject each message. Make sure you remove your moderator components from their parent filter before they are are destroyed so that their pending messages are correctly retried
8. *(optional)* Associate custom data with your messages in your own filters or via the moderator component

#### Bandwidth considerations <a href="#in-experiencechat-bandwidthconsiderations" id="in-experiencechat-bandwidthconsiderations"></a>

This plugin multicasts messages to all client-side chat servers (and hence all receiver components) whenever the message passes all message filters. Due to the large scale nature of Morpheus projects, this could quickly lead to network congestion if you have no other means of throttling messages. It is therefore strongly recommended to implement a way to limit the amount of messages that can be sent per sender component in a given time frame. That limit depends on the number of senders you want to support inside the network stack you've set up for your project.

The plugin already offers a variety of filters that can be used for this purpose. See the list of common filters further below.

#### Filtering messages <a href="#in-experiencechat-filteringmessages" id="in-experiencechat-filteringmessages"></a>

A large part of the plugin revolves around the concept of filtering messages before they are broadcast to everyone. This is handled via the `IMorpheusChatFilter` interface:

```
// Interface to implement a chat filter. A chat filter can decide whether to accept or reject a message. Accepted messages are
// passed on to the next filter in the parent (if one exists). Rejected messages are discarded immediately. If the filter returns
// Pending, the filter now owns this message and must use the PendingMessageHandler to resolve it later
class IMorpheusChatFilter
{
    GENERATED_BODY()

public:
    // Called initially if the parent filter supports pending messages. Should be stored by this implementation if it wants to
    // return Pending as a filter result. Upon returning Pending, it must use the stored Handler to accept or reject the message
    // at a later time
    virtual void SetPendingMessageHandler(TScriptInterface<IMorpheusChatPendingMessageHandler> Handler) = 0;

    // Process the message according to this filter's specification. DO NOT store the MessageCustomData reference. Changes to
    // MessageCustomData are applied independent of the filter result. For pending results, you can also change custom data when
    // accepting a message via the IMorpheusChatPendingMessageHandler interface later
    virtual EMorpheusChatFilterResult ProcessMessage(const FMorpheusChatMessage& Message, IN OUT int32& MessageCustomData) = 0;

    // Must be called by the parent filter after this filter was removed. If this filter contains any pending messages, it is
    // expected to call RetryMessage for all of them so that the messages aren't lost. In your implementation, also call this for
    // all owned child filters
    virtual void HandleFilterRemoved() = 0;
};
```

The main part of a filter is the `ProcessMessage` function which is called by the parent filter. In your implementation, decide what to do with the message that was passed in. There are three possible results:

```
enum class EMorpheusChatFilterResult
{
    // The message passed the filter successfully
    Accepted,
    // The message was rejected and will be discarded
    Rejected,
    // Message approval is pending. The filter will call back later
    Pending,
};
```

The chat server has a single filter slot which is initially empty. If no filter is installed, all messages are broadcast automatically. To install a filter, call `InstallMessageFilter`. In order to have more than one filter for your messages, you need to compose them from multiple filters. The plugin already comes with a number of default filters you can use:

* `UMorpheusChatRoundRobinFilter`

  The round robin filter accepts an arbitrary number of child filters. Whenever it receives a message for processing, it forwards that message to the next child filter, wrapping around automatically. If no child filters are installed, messages are always accepted.
* `UMorpheusChatChainFilter`

  The chain filter accepts an arbitrary number of child filters. Whenever it receives a message for processing, the message is passed through all of the filters until one of them returns `Rejected` or all of them eventually return `Accepted`. If a filter returns `Pending`, the chain is continued with the next filter in line once the pending message is resolved. If no child filters are installed, messages are always accepted.
* `UMorpheusChatAcceptIfModeratorFilter`

  Automatically accepts all messages if the sender has a `UMorpheusChatModeratorComponent`. Otherwise processing is forwarded to the next filter. If no next filter is installed, messages are always accepted.
* `UMorpheusChatRateLimitFilter`

  Accepts all messages but applies a rate limit to them. Messages are queued up and accepted according to the rate limit on each tick
* `UMorpheusChatOptionalFilter`

  Helper class for an optional filter. If no child filter is registered, it accepts all messages, otherwise the child filter decides. This is useful for installing optional filters into a chain filter and keeping a reference to it without having to extract it from the chain filter.
* `UMorpheusChatQueueFilter`

  Acts as a rate limiting filter by enforcing a maximum number of pending messages in flight in its child filter. This is useful as part of a load balancing strategy involving filters with user input.
* `UMorpheusChatLoadBalancingFilter`

  This filter attempts to keep an equal load on child filters with pending messages. The child filter with the least number of pending messages always gets the next message. In case of ties, the filter picks the oldest filter that was registered.
* `UMorpheusChatPhraseFilter`

  This filter searches for pre-configured phrases in a message and accepts or rejects the message depending on its mode and whether any of those phrases was found. This can be used as a profanity filter, for example.

There are also `UMorpheusChatSingleChildFilterBase` and `UMorpheusChatChildFiltersBase` for deriving your own filters that support child filters.

#### Pending messages <a href="#in-experiencechat-pendingmessages" id="in-experiencechat-pendingmessages"></a>

If a filter can't decide immediately whether to accept or reject a message, it can return `EMorpheusChatFilterResult::Pending` to indicate that the message will be resolved later. A common example would be the `UMorpheusChatModeratorComponent`. Chat moderation usually requires user input so the message has to be displayed to a moderator for consideration before it can be resolved.

To resolve a pending message, a second interface is used: `IMorpheusChatPendingMessageHandler`. If the parent filter supports pending messages, it should call `SetPendingMessageHandler` on its child filters and pass through a handler. Once a filter has decided what to do with a pending message, it can call `AcceptPendingMessage` or `RejectPendingMessage` on that interface. The chat server itself is a pending message handler and always calls `SetPendingMessageHandler` on its single filter.

If all filters eventually return `Accepted`, the message is broadcast to all receivers. If any filter returns `Rejected`, the message will be immediately discarded.

#### Retrying messages <a href="#in-experiencechat-retryingmessages" id="in-experiencechat-retryingmessages"></a>

If a filter has pending messages to resolve and it has to be removed from the game (e.g. a moderator actor leaving the game with unresolved messages), those messages need to be returned into the installed filter chain to ensure they are not lost. To facilitate this, filters can call `RetryMessage` on the `IMorpheusChatPendingMessageHandler` for all owned, pending messages. It depends on the message handler how retries are resolved. Generally, it should attempt to continue with the next filter in line.

Retrying messages should happen inside your override of `HandleFilterRemoved`. This function is called by the parent filter after your filter has been removed (and you need to ensure this happens when writing your own filters with child filters).

#### Composition example <a href="#in-experiencechat-compositionexample" id="in-experiencechat-compositionexample"></a>

Here's an example for how to compose filters:

```
void InstallFilters(AMorpheusChatServer* ChatServer, const TArray<UMorpheusChatModeratorComponent*>& Moderators)
{
    UMorpheusChatAcceptIfModeratorFilter* ModeratorPassthrough = NewObject<UMorpheusChatAcceptIfModeratorFilter>();

    UMorpheusChatRoundRobinFilter* RoundRobinFilter = NewObject<UMorpheusChatRoundRobinFilter>();
    ModeratorPassthrough->InstallNextFilter(RoundRobinFilter);

    for (const UMorpheusChatModeratorComponent* Moderator : Moderators)
    {
        RoundRobinFilter->InstallChildFilter(Moderator);
    }

    ChatServer->InstallMessageFilter(ModeratorPassthrough);
}
```

This filter setup first checks if the message was sent by a moderator and auto-accepts it. If it wasn't sent by a moderator, it's passed on to the round robin filter which in turn contains all of the moderator components. So each moderator will get a message to resolve in a round robin fashion.

The moderator component always returns `Pending`, so only when the project-specific implementation has decided what to do with the message, it will pass and be fed back into the chat server.

#### Filter gotchas <a href="#in-experiencechat-filtergotchas" id="in-experiencechat-filtergotchas"></a>

* It's your responsibility to ensure that filters are removed from their parent filter before they are destroyed (and hence retry their pending messages if necessary). The plugin assumes that all filters remain valid as long as they are installed.
* Do not install the same filter instance twice. This could assign different PendingMessageHandlers depending on where they are added which would likely break the filter in either location

### Custom data <a href="#in-experiencechat-customdata" id="in-experiencechat-customdata"></a>

`FMorpheusChatMessage` contains a `CustomData` property which is not used by the plugin or any of its common filters. Projects can use this field to associate arbitrary data with each message, e.g. to set flags whether to highlight a message, make it sticky etc. Custom data can be set in three ways:

* `UMorpheusChatSenderComponent`

  When the sender component initially sends a message, it calls its protected `GetInitialCustomData` virtual function to determine the initial custom data to associate with that message. This only happens on the server.
* Filters

  Each filter can change a message's custom data via the supplied `MessageCustomData` reference parameter. Changed custom data is always applied, regardless of which result the filter returns (although it won't have any effect if the filter returns `Rejected` since the message will be dropped!).

  `IMorpheusChatPendingMessageHandler::AcceptPendingMessage` also has a `MessageCustomData` parameter which is applied to the message. You need to ensure you cache the custom data value the message had when it entered your filter yourself if required.

  Common filters supplied by the plugin always pass through custom data unchanged.
* Moderators

  Moderators can also change custom data for messages that were already broadcast in the past via `UMorpheusChatModeratorComponent::ServerUpdateCustomData`. This function calls `HandleUpdateCustomData` on all client receiver components. You have to ensure that you cache a reasonable number of sent messages to do anything with this call since you only receive the message ID, not the whole message.

### Moderation with Community Sift <a href="#in-experiencechat-moderationwithcommunitysift" id="in-experiencechat-moderationwithcommunitysift"></a>

1. Make sure the following is set up in the Live Config **game.json**. Get the exact URL paths from the Community Sift admin site, depending on exactly which ones your project is using. DefaultCategory is what will appear in the Server field in the chat logs and should be set to your project name.\\

   ```
   "Moderation": {
           "UseSimpleProfanityFilter": false,
           "UseWebChatFilter": true,
           "UseUrlFilter": true,
           "IgnoreCommunitySiftResponse": false,
           "UseSpeechToText": true,
           "CheckPlayerNames": true,
           "AllowBotsToSendChat": false,
           "CheckUsernameUrlPath": "/v1/workflow/call/fp_SOMEPROJECT_check_username",
           "CheckTextUrlPath": "/v1/workflow/call/fp_SOMEPROJECT_check_short_text",
           "CheckVoiceTranscriptUrlPath": "/v1/workflow/call/fp_SOMEPROJECT_check_short_or_long_text",
           "DefaultCategory": "SOME_PROJECT_ID"
       },
   ```
2. When setting up an allocation in GSS make sure the following fields are active\\

Reach out to [Andrew Fenwick](https://improbableio.atlassian.net/wiki/people/5f731ce4e0e85a006e43d664?ref=confluence) [Alexander Landen](https://improbableio.atlassian.net/wiki/people/5f7af9424d09f7007613af08?ref=confluence) or Content QA for URL and Password

#### Live Config settings <a href="#in-experiencechat-liveconfigsettings" id="in-experiencechat-liveconfigsettings"></a>

There are quite a few live config settings (see above) that affect moderation.

* `UseSimpleProfanityFilter` This enables the old “banned word list” filter, which rejects any message that contains any of the banned phrases. This is what was used for ScabLab but has been replaced by CommunitySift. The phrase list is also in live config, in `profanity.json`, but requires a server restart to take effect. The default is **false**.
* `UseWebChatFilter` This causes chat (and voice transcriptions if enabled) to be sent to CommunitySift, so they show up in the chat logs and the senders can moderated.
* `UseUrlFilter` This will block any text chat that looks like a URL from being broadcast, regardless of the response from CommunitySift.
* `UseAnsiFilter` This will block any message that contains non-ANSI characters (that might be designed to circumvent other filters).
* `ClientUseUrlFilter` and `ClientUseAnsiFilter` These are equivalent to the above, but run on the client. These filters can be expensive for the server to run, so if you’re using trusted clients you can run them on the client and disabled them on the server.
* `IgnoreCommunitySiftResponse` If enabled, all text chat will still be sent to CommunitySift, but the game won’t reject any messages based on the response. Enable this if you want to test data collection in CommunitySift but don’t want to actually block any text chat.
* `UseSpeechToText` This enables speech transcription, and sends the transcriptions to CommunitySift.
* `CheckPlayerNames` This sends a player’s chosen name to CommunitySift for moderation before changing it.
* `AllowBotsToSendChat` If disabled, bot chat won’t be sent to CommunitySift. This means it’ll never get broadcast if `UseWebChatFilter` is enabled. Don’t enable this with large numbers of bots unless you’re performing a scheduled scale test and CommunitySift have been notified. Alternatively disable `UseWebChatFilter` to see the text in game as normal with no moderation.
* `CheckUsernameUrlPath` / `CheckTextUrlPath` / `CheckVoiceTranscriptUrlPath` These specify the exact endpoints to send each of the requests to. Find them in the API docs page on the Community Sift website or talk to [Andrew Fenwick](https://improbableio.atlassian.net/wiki/people/5f731ce4e0e85a006e43d664?ref=confluence) or [Thomas Wilkinson](https://improbableio.atlassian.net/wiki/people/617f498216119e006979a04b?ref=confluence).
* `DefaultCategory` This will appear in the Server field in the Community Sift chat logs, for differentiating between projects. Set it to your project name.
* `DefaultSubcategory` This will appear in the Room field in the Community Sift chat logs. You could use this to differentiate between dev and production environments, or between different events etc.


# Control Panels


# Control Panel Configuration

{% hint style="danger" %}
15/07/2025: Long term support of this feature is not guaranteed. Deprecation of this content is in discussion.

Existing users should not be affected by this, but our recommendation is that new customers that are not using this feature **should not** use it.
{% endhint %}

{% hint style="warning" %}
**Experimental -** Customers are encouraged to test and use this feature in their experiences, but it may still require some additional support
{% endhint %}

<figure><img src="/files/aRT2MiWfFMYqPxqZNstr" alt=""><figcaption><p>Control Panels configured to suit user needs</p></figcaption></figure>

## Overview <a href="#overview" id="overview"></a>

To help Directors during live events and the QA team while testing features, we are looking at having options for control panels which can be used to setup the control panel environment in a particular way:

* A control panel handler that directors can use to open and close relevant panels.
* Save and load control panels so directors can keep their control panel customisations.
* High level vs. low level control panels architecture.

{% hint style="warning" %}
**Capabilities.ControlPanels.Enabled** is used to allow access to control panels. Please add this to any roles that require the ability to click control panels to open them.
{% endhint %}

## Integration <a href="#integration" id="integration"></a>

{% hint style="warning" %}
Please **do not** use this system if you open control panels by clicking them. This is only meant for control panels which open up automatically for Directors.
{% endhint %}

* The actor `BPM_ControlPanelsHandler` must be placed in a level or spawned on the server at runtime.
* Any control panel actors that you wish to use as a Director (other than this one) must have a **DirectorPanel** actor tag.
* Add the **Capabilities.ControlPanels.CanUseControlPanelHandler** gameplay tag to any Role which you would like to handle this system.

{% hint style="danger" %}
Outdated reference: **Capabilities.ControlPanels.CanUseControlPanelHandler** is no longer used in MSquared after v22. If you still use this you may need to re-add the capability to relevant roles or consider a different gating mechanism
{% endhint %}

### Initial Spawning <a href="#initial-spawning" id="initial-spawning"></a>

Spawning the control panel widget itself can be done in many ways. The quickest way is by following **Option 1** below. If you have a specific way of spawning control panels, e.g. via the Director’s pawn once `EventPossessed` is called, you can handle the spawning for this control panel there by ensuring it only spawns this one, and then allowing you to handle the rest of the control panels via this system.

#### **\[Option 1] Automatic Spawning**

You will need to enable the "AutoOpen" property on the ControlPanelProvider component on your actor. You will also need to ensure you have completed the initial setup conditions above.

<figure><img src="/files/YjLcIFtgkg3xbbEFBfXU" alt=""><figcaption><p>Setting Auto Open to true on a millicast control panel</p></figcaption></figure>

#### **\[Option 2] Example of Manual Spawning**

Whichever blueprint that holds the logic for spawning control panels for Directors will need to now only spawn this control panel and not others. You will also need to ensure you have completed the initial setup conditions above.

The example below only spawns this control panel if the live config value is *true*, otherwise it spawns the usual control panels for Directors. This is a made up live config value where a new one will need to be added to the relevant project’s live config JSON file. You can also do a check against whether the player character has the relevant Capability Tag **Capabilities.Director.UseControlPanelHandler**.

<figure><img src="/files/RW1yQt2ntxDirwb1IwxG" alt=""><figcaption><p>An example of how to setup this system depending using a live config value.</p></figcaption></figure>

### Setting Up Control Panel Sets <a href="#setting-up-control-panel-sets" id="setting-up-control-panel-sets"></a>

In the Details panel under the Config section for this actor, you can set up different Sets of control panels for Directors to easily open up without needing to select each one individually in the drop down menu. Sets are only used for **spawning**, **de-spawning** and changing the **colour** of the control panels.

Each Set should include a set name and an array of what control panels you want to spawn. The array of control panels takes in Morpheus Actors as not all control panels derive from `BPM_ControlPanelBase`. There is also an editor function called `CheckSetsHaveDirectorPanelTagExternal()` to check whether the control panels added to the array have the correct tag **DirectorPanel**. If you forget to do this check, it will automatically ignore that control panel.

<figure><img src="/files/RKEjcZSmlNhwD27aDTUb" alt=""><figcaption><p>Screenshot showing a control panel without the correct actor tag.</p></figcaption></figure>

<figure><img src="/files/dlPFRLkFOy1uoyet2yvU" alt=""><figcaption><p>An output log message indicating which actor was failing the check.</p></figcaption></figure>

<figure><img src="/files/2oWtgRXE94NremgVXi7i" alt=""><figcaption><p>How Sets appear on the control panel.</p></figcaption></figure>

## Available Features <a href="#available-features" id="available-features"></a>

### Spawn/De-spawn All <a href="#spawn-de-spawn-all" id="spawn-de-spawn-all"></a>

This feature allows Directors to spawn and de-spawn all available control panels at once.

### Control Panel Sets <a href="#control-panel-sets" id="control-panel-sets"></a>

Once you have set up Sets of control panels, where you can learn how to from this document: [Setting Up Sets](#control-panel-sets), your sets will be available where you can spawn, de-spawn and choose the colours for all the control panels in a set.

### Individual Sets <a href="#individual-sets" id="individual-sets"></a>

This part of the control panel, holds all the available settings for for each control panel.

* Spawn/De-spawn
* Collapse/Open-up
* Dock Left/Right
* Colours
* Slot Position

{% embed url="<https://youtu.be/-KRAQA9S5Xs>" %}

### Save and Load Pre-set <a href="#save-and-load-pre-set" id="save-and-load-pre-set"></a>

Directors also have the option to save their control panel settings to their M2\_Connect Account, where they will be able to load up their control panel environment between game sessions/live events.

To ensure these settings are correctly saved, the Director must use the same M2\_Connect Account and have all control panel names properly set up via the Control Panel Register Component..


# Crash Reporting

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

{% hint style="warning" %}
To use this dashboard, you'll need an API key generated for you. Please reach out to your support engineer to get an API key.
{% endhint %}

With publishing games to the public, it is inevitable that your users will run into crashes.

We provide a dashboard where you can see all recent crashes in your organisation and project: <https://crash-reports.preview.msquared.io/>

<figure><img src="/files/udVN9fyL987g0eR48ttG" alt=""><figcaption></figcaption></figure>

You can get additional details for each crash, including the user's hardware and callstack:

<figure><img src="/files/TcS7OOYKGO4bt1FQbIES" alt=""><figcaption></figcaption></figure>

There are also various crash-specific attachments which might be of value to you. Of particular relevance:

* `M2Development.log` contains the user's log with timestamps, which provides signifcant context about the state of the application and how the user got there.
* `CrashContext.runtime-xml` is a XML file with information about the user's hardware and World Builder information.

## Common crashes

### GPU Crash dump Triggered

A GPU crash is always fatal, and it can be caused by a very large number of reasons. However, by far the most common one is that the user is using a device which is below the minimum spec listed in [Hardware Requirements](/creation/running-events/player-entry/minimum-hardware-requirements). The majority of these crashes are from users trying to run the game using an integrated GPU, which is wholly incapable of handling Unreal 5.

### Unhandled Exception: EXCEPTION\_STACK\_OVERFLOW

This normally indicates an infinite loop within your blueprints.


# Crowd Audio

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

## Overview <a href="#spatialaudio-overview" id="spatialaudio-overview"></a>

MSquared provides large-scale, spatialised voice chat between players, alongside broadcast channels which allow for channel-based non spatialised (2D) audio.

The audio system consists of three parts:

* The spatial audio **Unreal plugin**. This integrates the system with Unreal and provides an API to game code.
* The **audio client**. This is a DLL that provides engine-agnostic processing functionality, and provides an interface to the connection between the client and the audio server.
* The **audio server**. The server receives audio from each client, performs processing and aggregation, and then sends the mixed audio back to each client.

## Example Audio Component

The character used in the example map, `BPM_M2Example_PlayerCharacter`, uses an example BP crowd audio component `BPMC_CrowdAudio` which enables the player to be able to use voice chat in game. Take a look at the BP logic inside this component to see how BP logic and interact with the audio API in the Unreal plugin to use voice chat.

### Usage / Controls

Voice chat can be enabled either by pressing the button in the UI, or using the corresponding shortcut

* C for regular spatial voice chat
  * This is "push to talk", not a toggle.
* To use the loudspeaker you can stand on the pedestal in the Example map and speak. Loudspeaker is an example of broadcast audio.

![](/files/W67sfLvp8l4R517NzxZa)

## Audio customisation

Crowd Audio has a large number of settings that allow you to control parts of the preprocessor, replication, aggregation, and other parts of the audio flow. Some features that you can configure include:

* Broadcast channels
* Reverb
* Occlusion
* Volume normalisation
* Muting specific players
* Disabling spatial audio for specific clients

### Broadcast channels

Voice Chat is powered by the Crowd Audio system. Typically this is intended for spatial voice. However, it also handles 2D voice chat, using broadcast channels:

This is the way that the Crowd Audio system handles different "channels" for communication.

It is controlled via the following (on the `CrowdAudioComponent`):

* `Add/RemoveSubscribedBroadcastChannels` - controls which broadcast channels you are listening to
* `Add/RemoveAvailableBroadcastChannels` - controls which broadcast channels you are allowed to talk in.
* `SetSelectedBroadcastChannel` - sets the channel that you are talking in (must be available)
* `SetVoiceInputEnabled(bEnabled, bBroadcast)` - controls whether you are talking or not. If `bBroadcast`is true, you will use your selected broadcast channel. If not, you will use spatial voice.

When someone talks on "loudspeaker", they are using the global broadcast channel (0), which everyone is subscribed to.

Broadcast channels will allow you to implement things like team-specific voice chat or direct voice comms between specific individuals.

### Muting individual players

Clients can be configured to locally mute individual other clients' spatial audio. You can do this via the following API on the `CrowdAudioComponent` :

* `AddMutedSourceId`
* `RemoveMutedSourceId`

You can obtain the speech source id to mute with `GetSpeechSourceId` on the target's CrowdAudioComponent.

Note that each additional muted user requires the audio server to do additional computation per tick. This isn't noticeable with low numbers of muted users or at low scale, but you should keep the number of muted sources per player to below 10 in high scale (>5,000) deployments to ensure good audio server performance.

### Adjusting crowd audio settings

All other settings can be adjusted via the `FCrowdAudioSettings` struct or via LiveConfig.

#### Adjusting in BP logic

To adjust crowd audio settings in BPs, you need to set the `Settings` struct in the CrowdAudioComponent. Note that this will set *all* of the values to the defaults, so if you want to keep any changes that have been made, you need to make sure to reapply those.

Settings here are generally not applied globally, and will only affect what the local client outputs and receives.

<figure><img src="/files/CTg92n8jxsH5gLzcTcDZ" alt=""><figcaption><p>Here, I want to keep all the settings the same but disable audio occlusion. I get the Settings struct and forward all the fields onto the <code>Set Settings</code> node on the right except for audio occlusion, where I pass in my own audio occlusion settings struct.</p></figcaption></figure>

#### Adjusting in LiveConfig

You can also adjust settings via LiveConfig, which will be applied globally. To do this, find the CrowdAudioSettings in LiveConfig and enable `UpdateSettingsInTick`, which will enable live config updates for crowd audio.

Note that this will override any custom settings you have applied.


# CrowdAudioComponent advanced configuration

This page includes some extra functionality present in the crowd audio component, which could be useful for users exploring deeper into crowd audio:

## Choppiness Detection

The crowd audio component has a `PollConnectionHealth` function, that checks whether there have been any dropped audio packets in the time since the last time `PollConnectionHealth` was called. It calls `OnConnectionHealthResult` with the result of the poll. This can be used to track whether there are any issues with audio, e.g. notifying users if they have a spotty connection.

<figure><img src="/files/VdptFyAEHVXAWRAi4XX0" alt=""><figcaption><p>Some example logic in the deprecated <code>BPMC_CrowdAudio</code> for tracking connection health. It has been removed from our current example content since it is not currently being used/hooked up to UI, but could be added to a downstream project if desired.</p></figcaption></figure>

## Disabling using voice

`SetVoiceInputEnabled` is the function used to turn voice chat on or off. We call this directly in our example voice chat functionality. The function is overridable, so if you want to inject checks that reject calls to this function, that can be done.

<figure><img src="/files/tS1OdhZjvN34dYlkZLYd" alt=""><figcaption><p><code>BPMC_M2Example_CrowdAudioComponent</code> overrides <code>SetVoiceInputEnabled</code>, blocking requests to enable voice if <code>CanUseVoice</code> is false. This function is blank by default, but can be extended if desired</p></figcaption></figure>

## Voice transcription

If the `game` `Moderation.UseSpeechToText` live config flag is true, then (the local player's) voice chat will be run through a local speech recognition application, to obtain transcripts. This is then broadcast via the `CrowdAudioComponent`'s `OnCrowdAudioSpeechTranscriptionAvailable` event. (Sections of speech are transcribed and broadcast as strings).

These voice transcripts are sent automatically to our moderation system, where we use [Community Sift](/creation/unreal-development/features-and-tutorials/communication/moderation) to observe voice transcriptions, and optionally e.g. ban or mute players.

If you want to implement your own moderation, you can independently bind to `OnCrowdAudioSpeechTranscriptionAvailable`, and handle the transcriptions how you like. Unfortunately, we are not able to expose the raw voice data to downstream projects.

{% hint style="info" %}
NOTE: This logic is only present if the crowd audio component used by your project extends `JM_CrowdAudioComponent` (this is the case for our default `BPMC_M2Example_CrowdAudioComponent`)
{% endhint %}


# Crowd Rendering

## Overview

The animated crowd is our solution to handle rendering massive scales of players in an experience in a performant way. Instead of using a full "Unreal Actor" per player in the world, we replace distant actors with a highly optimized "animated crowd member", and swap out players between real actors (LoD 0) and the crowd as they move closer or further away.

## Limitations of the crowd

Crowd members do not have a real skeletal mesh in the world like a full actor would. This means you cannot add things to the Skeletal Mesh such as collisions, attached UI, sound emitters etc. This means if your project is configured to use 30 full actors and 10k crowd members, things like collision checks, raycasts etc. would only be possible on the closest 30 players. This should be considered whenever designing gameplay features that rely on players having a full actor representation.

Configuration of these settings can be found in the [Animated Crowd](/creation/unreal-development/features-and-tutorials/the-animated-crowd/legacy-animated-crowd) details.

## Constituent parts

The crowd system has two main parts to it; animation and rendering.

Animation is taken care of by the Animated Crowd system and supports basic animation blueprint (ABP) functionality as well as more simply the ability to assign specific animations to specific characters. Full details on configuring the animation system and features / constraints can be found [here](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation). Irrespective of crowd rendering technique, the system used to drive animations is shared by both.

Rendering on the other hand, taking the animations and getting triangles on screen, can be one of two systems (or both, concurrently).

#### Non-MML rendering system

The original crowd rendering system worked with Unreal skeletal meshes directly, rather than MML. This system is still in place for rendering non-MML avatars and can also be used for rendering things like gameplay character attachments that use Unreal static meshes. The non-MML rendering system handles many standard Unreal rendering features such as different materials per mesh\*, custom per-instance and per-mesh material data and custom depth/stencil passes, however in contrast to the MML rendering path, mesh streaming and automatic mesh levels of detail are not available.

(\*up to 128 unique materials per crowd)

#### MML rendering system

More recently a second rendering system has also been developed to support MML rendering. This MML rendering system can be used to render crowd avatars, as well as non-crowd MML objects in the world. This system is designed for avatar interoperability across different worlds, and therefore adopts a standardized material setup that all avatars must use.

The MML Crowd Rendering system supports rendering thousands of unique MML player avatars at once. It uses automatic level of details to render arbitrary numbers of player avatars with a fixed triangle and texture budget, changing the level of detail of each avatar to best use the available budget.

{% hint style="info" %}
*Carnival* is the original codename of the MML Rendering system, and you may see this used in Blueprints and console variables.
{% endhint %}

For further details on how to use and configure the system, see these sections:

* [Crowd Rendering Materials (MML)](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-materials)
* [Configuring Performance Parameters (MML)](/creation/unreal-development/features-and-tutorials/the-animated-crowd/performance-parameters)
* [Live Config Settings (MML)](/creation/unreal-development/features-and-tutorials/the-animated-crowd/live-config-settings)


# Animated Crowd

## Configuration <a href="#configuration" id="configuration"></a>

### Via the Morpheus Actor

{% hint style="warning" %}
NOTE: This section is available from release v40 onwards.
{% endhint %}

In your Morpheus Actor's details panel, you are able to configure its render targets using our simplified configuration - see `Morpheus Render Target Settings`

{% hint style="info" %}
NOTE: The animated crowd currently assumes you are using the [Avatars](/creation/unreal-development/features-and-tutorials/avatars)system, which handles informing the crowd which mesh to use.
{% endhint %}

* If you tick `Crowd Enabled`, then your morpheus actor will use the animated crowd.
  * By default, the crowd will be configured automatically for you, deriving its fields from the render target actor used. If you want more specialist configuration, you can configure it in the [#advanced-configuration](#advanced-configuration "mention").
  * NOTE: For regular player characters using our [Avatars](/creation/unreal-development/features-and-tutorials/avatars) system,
* You can toggle this live using `MorpheusActorRenderTargetComponent::SetUsingCrowd` (will need to be called on every client)

<figure><img src="/files/kKlv47ASzosJwO5zv54m" alt=""><figcaption><p>In this example, we are using the default pawn as your LOD0 render target actor, and have the animated crowd enabled, with a raycastable crowd (see <a data-mention href="/pages/J6bEd9Xhw7GdF31kGugf">/pages/J6bEd9Xhw7GdF31kGugf</a>). Without specifying any advanced Crowd Details, the raycastable crowd will be obtained from your settings, and your crowd details will be obtained from your LOD0 render target actor.</p></figcaption></figure>

#### Advanced configuration

In the `Advanced` section, you can provide overrides to the `Crowd Details`:

<figure><img src="/files/2XVkS6VEc7VJWxiIuqvN" alt=""><figcaption></figcaption></figure>

* `IsmActorType` defaults to the `DefaultInstancedMeshActorClass` defined in `Project Settings -> Morpheus Platform -> Animated Crowd Settings`. We do not advise changing this in most use cases.
* `Raycastable Crowd Class` defaults to the `DefaultRaycastableCrowdClass` in the same project settings. This can freely be configured to suit your project.
  * You can also modify the class using `SetRaycastableCrowdClass` or `ResetRaycastableCrowdClass`.
  * For more details, see [Raycastable Crowd](/creation/unreal-development/features-and-tutorials/enabling-raytracing-for-crowd-members)

For details on the other settings, see [Morpheus Render Targets](/creation/unreal-development/getting-started/networking/morpheus-render-targets).

### Via the Pawn Set Asset

The "Pawn set asset" (see [Character Configuration](/creation/unreal-development/getting-started/differences-in-unreal-development-workflow/msquared-character-configuration#pawn-sets)) defines the LOD levels for the character, including what render targets they use for each. Typically, we have the first LOD level be an actor target type, and the second be the animated crowd.

<figure><img src="/files/dRHHoMWDV90NFnqgBJdx" alt=""><figcaption></figcaption></figure>

You can configure the crowd data from here, e.g. using a different type of crowd, or modify the configuration/data associated with it. This flow can be very complex to modify - if you do think that you need to do so, please get in touch!

### At Runtime

You can configure some settings regarding e.g. how many entities are rendered at which fidelity level, at runtime, using the following approaches:

#### Via [Live Config](/creation/unreal-development/features-and-tutorials/live-config)

The max number of characters that can be represented with real non-crowd actors is controlled by the `PlayerClient.Rendering.NumInLOD0` live config flag (in the `game` config).

<figure><img src="/files/wqBkwGrm8iaX0lkdO3fy" alt=""><figcaption><p>By default there are 35 entities in the first LOD Level for the <code>PlayerClient</code> lod group (the non-crowd level)</p></figcaption></figure>

{% hint style="info" %}
NOTE: By default, we assume that players are in the `PlayerClient` LOD Group. This can be configured if you want further flexibility.
{% endhint %}

#### Via BP

{% hint style="warning" %}
NOTE: This section contains features that were added for release version v29. Some functionality described here won't be present in earlier versions.
{% endhint %}

* Via the `RenderTargetManager` (obtained from the authoritative Morpheus Actor via `GetRenderTargetManagerFromAuthMorpheusActor`), you can modify at runtime the max number of entities in a given LOD Level. e.g. to modify the number of non-crowd actors representing players, you can modify the max in `LODGroupName = PlayerClient`, `LODLevel = 0`.
* For any MorpheusActor, you can modify its LOD Group live using `UpdateClientLODGroup`. If you want it to be rendered at a higher priority (e.g. for presenters that you want all players to be able to see at the highest fidelity at all times), you can set it to e.g. the `Priority` bucket within the `PlayerClient` group.

<figure><img src="/files/HHX0OmbYYNKrbN4O1Z7m" alt=""><figcaption></figcaption></figure>


# Animated Crowd Console Commands

### Live Config <a href="#live-config" id="live-config"></a>

`M2.LiveConfig.SetValue game PlayerClient.Rendering.NumInLoD0 0`: Forces all players apart from your local player into the crowd.

`M2.LiveConfig.SetValue game PlayerClient.Rendering.ForceSkeletalCrowdFrustumCulling <0/1>`: Forces skeletal crowd GPU frustum culling on or off locally.

### Animated Crowd <a href="#animated-crowd" id="animated-crowd"></a>

`AnimatedCrowd.Debug.DrawBoxes 1`: Draws debug bounding boxes on each instance in the animated crowd. Due to performance, boxes will be drawn for a subset of the crowd at once.

`AnimatedCrowd.Debug.MaxBoxes n`: Configures the number of debug boxes to be drawn.

`AnimatedCrowd.Debug.ScanSpeed n`: Configures the speed for drawing each subset of the crowd.

### Skeletal Crowd <a href="#skeletal-crowd" id="skeletal-crowd"></a>

`SkeletalCrowd.Debug.VisualizeLoDs 1`: Enables a debug view of each LoD. Each LoD will have its material be overridden to use a material from `DebugLodMaterials` as a visualization. `DebugLodMaterials` must be non empty for this to work.

`SkeletalCrowd.Debug.ExclusiveLoD n`: If n is a valid LoD index, then only that LoD will be rendered and all other LoDs will be culled.

`SkeletalCrowd.Debug.DumpMemoryUsage`: Dump memory usage for all `USkeletalCrowdComponents`.

* `--verbose` will enable more verbose memory usage dumps

`SkeletalCrowd.Debug.DrawFrustum 1`: Draws the view frustum that is used for frustum culling.

`SkeletalCrowd.Debug.DrawBoundingSpheres 1`: Draws the bounding sphere used for frustum culling around each instance. This is very expensive on a large crowd!

### Crowd Anim Blueprint <a href="#crowd-anim-blueprint" id="crowd-anim-blueprint"></a>

`CrowdAnimBlueprint.VerboseCompilerWarnings 1`: Enables verbose compiler warning for Crowd Anim Blueprint.

`CrowdAnimBlueprint.DumpCompilerOutput 1`: Dumps the output (AST, IL, Bytecode) from Crowd Anim Blueprint compiler to the logs.

`CrowdAnimBlueprint.OptimizeConditions <0/1>`: Enables or disables optimizations to logic performed by transition conditions when Crowd Anim Blueprint compiler is running. Defaults to enabled.


# Crowd Materials (MML)

MML avatars use the GLB format for their meshes. GLB materials use a physically based rendering setup, and are translated into one of three Unreal materials that are used in Crowd Rendering based on how they are configured:

* **Opaque** - for basic opaque materials
* **Masked** - for alpha-masked materials that are rendering in the opaque pass, but mask out pixels
* **Translucent** - for any non-opaque material

These three materials are the only ones used by Crowd Rendering, but with different parameters (textures, base colour, roughness etc).

The materials are exposed in the settings in **Project Settings** → **M2 Carnival**, so you can replace them with your own materials if required:

<figure><img src="/files/OfIobdWVA5s68zPJahnm" alt=""><figcaption></figcaption></figure>

Changes to these settings are stored in `DefaultGame.ini`. At the moment it's not possible to pass in any custom per-character data to the material - all material parameters come from the GLB model file.

{% hint style="info" %}
Known issue: If you specify your own materials they may not be automatically cooked, so may not work in a packaged deployment. As a workaround you can add a reference to your materials on any object anywhere in your map to ensure they are referenced and cooked.
{% endhint %}


# Performance Parameters (MML)

You can tweak Crowd Rendering parameters to balance performance and quality. The parameters are defined in CVars, and some can be tweaked from the console at runtime (in a non-shipping build with console access) to find appropriate values for your project. The most useful ones are listed here.

To set custom values for each quality settings see: [Override CVars Per Scalability Group](/creation/unreal-development/tutorials/adding-project-settings-config-overrides#adddingprojectsettingsconfigoverrides-addingyourownprojectsettingsconfigoverrides-1)

The default values can be found in `<EditorLocation>/Config/BaseScalability.ini`

## Mesh prioritisation <a href="#mesh-fidelity" id="mesh-fidelity"></a>

Triangles are allocated to characters using these steps:

* Cull all characters outside of the camera frustum
* Allocate a minimum number of triangles to each character inside the frustum, and calculate the remaining number of 'spare' triangles from the total budget
* Sort all characters into priority order, based on their screen-space size
* Allocate the spare triangles to the highest priority `n` characters using an exponential dropoff

## Mesh prioritisation settings

**r.CarnivalTargetNumTriangles**

The maximum number of triangles that will be rendered across all meshes. This is the main bottleneck for performance, more triangles = better quality and worse performance.

**r.Carnival.Fidelity.MinNumTrianglesPerModel**

The minimum number of triangles that each character will have. Lower value = worse looking meshes in the distance, but leaves more triangles available to be allocated to nearby meshes.

Ensure to set the value low enough that `(minimum per character * maximum number of characters) < total triangles` to avoid any rendering issues.

**r.Carnival.Fidelity.NumModelsToPrioritize**

The number of characters that are eligible to receive extra triangles.

**r.CarnivalExtraTrianglesExponent**

The rate of exponential drop-off when allocating spare triangles. A higher number means that the closest few characters will get most of the triangles (and therefore look better), while a lower number will give a more even distribution across the prioritised models.

## Other settings

**r.CarnivalTargetTextureMegaPixels**

Set the total texture budget. Reducing this will result is less memory usage, but model textures will be lower resolution.

**r.Carnival.CharacterBoundRadius**

The base radius to radius to use for frustum culling. The default value is 90 which should be appropriate for most human-sized characters.

**r.CarnivalEnableShadows**

Whether Carnival characters cast shadows. Shadows can be disabled to improve performance somewhat.

**r.Carnival.Fidelity.MaxNumOpsModelPerTick**

The higher this value the quicker models will be updated to their correct fidelity level. Reducing this can improve CPU performance.

**r.Carnival.Fidelity.MaxNumOpsTexturePerTick**

The higher this value the quicker textures will be updated to their correct resolution. Reducing this can improve CPU performance.

**r.Carnival.FrustumCull.LookaheadFrames**

Number of frames ahead to predict the view frustum for frustum culling, based on the delta from the last view matrix. Higher values reduce the instances of characters popping in, but result in overall move characters being rendered, when spinning the camera.

**r.Carnival.FrustumCull.FOVExpansion**

Angle in degrees by which the cull frustum is larger than the view frustum. This reduces characters popping in when the camera is suddenly moved. Higher values can reduce performance, as more culled characters will be rendered at all times.


# Live Config Settings (MML)

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

There are a few Live Config settings that can be used to configure and debug the Crowd Rendering system. These are all found in the `Game` live config section.

## Settings

**Carnival.DontUseCarnivalForForcedForeground**

Certain player roles can be set to always be in the network foreground, for example important 'presenter' characters in events. If set, these characters won't render with Carnival and will instead use the default Unreal renderer (only applied if they're using an MML avatar).

**Carnival.MaxConcurrentEncodes**

The number of GLB meshes that will be encoded concurrently. A high number can impact client performance when players use an MML character made up of multiple GLBs, but a lower number will delay when the avatar is visible to other clients.

**Carnival.NumMeshesReservedForAttachments**

Each player can use a total of 12 MML meshes. If you use MML attachments in your projects, set this to the maximum number of attachments that a player can equip at once - this will ensure that the attachment meshes are rendered instead of character meshes (if the player is using an MML with many meshes).

**Carnival.UseCarnivalForAuthClient** (experimental)

The local player character is currently not rendered using Carnival by default. It can be enabled with the setting which may give some performance benefits.


# Crowd Animation

## Overview

Crowd members can be animated in two ways

* By setting animation sequences directly on the crowd member themselves
* By using an Animation Blueprint (ABP)

These techniques can be used either together or in isolation.

{% hint style="info" %}
If an animation sequence is specified directly on a crowd member it will take precedence over the ABP animation until the override is removed. The ABP will continue to update in the background however.
{% endhint %}

## Animation Data Setup

In order to use an Animation Blueprint with the crowd it must first be configured to be compatible. More details on ABP setup can be found [here](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint).

Both animation inputs methods are configured via setting the `AnimNameToSequence` map.

This can be done in one of two ways:

### Via the render target pawn

{% hint style="info" %}
This option is only available in v40 onwards
{% endhint %}

Where possible, the animated crowd obtains data from the LOD0 render target actor class, e.g. the skeleton and the anim instance. We also enable it to provide the `AnimNameToSequence` map, so it can specify what anim sequences it needs to support.

If your LOD0 class implements the `CrowdAnimationProviderInterface` (this is done automatically for children of the `M2_CharacterBase`), then it will expose a `GetAnimNameToSequenceMap` function, which can provide the list of anim sequences.

### Via the Crowd Data

If your animated crowd provides a `Skeletal Animated Crowd Data` data asset, you can fill in the `AnimNameToSequence` map there.

<figure><img src="/files/Sckr7ETf6YLRwTejnIYl" alt=""><figcaption><p>Example Skeletal Animated Crowd Data specifying ABP driven animations as well as named sequences</p></figcaption></figure>

In the above example, an ABP is connected via the `Crowd Anim Instance` parameter and additionally a list of named sequences are supplied in the `Anim Name to Sequence` list.

## Selecting An Animation Source On A Crowd Member

Animation setup for each crowd member is specified by configuring properties within its `FAnimatedCrowdMemberState` .

Animation selection is performed as follows

1. If a crowd member has `FAnimatedCrowdMemberState::AnimState` specified
   * The named animation will be play back on that crowd member
   * If a name isn't specified (`NAME_None`) or it isn't found in the `Anim Name to Sequence list`, then we go to the next step and check the ABP
2. If a crowd has an ABP specified
   * `FAnimatedCrowdMemberState::AnimFloatParameters` will be updated for the crowd member - these contain the anim vars used to drive things like ABP state logic
   * Crowd member will play back ABP driven animation
3. If there was no animation sequence set directly and ABP wasn't present
   * Crowd member will be set to ref pose and will render, but not animate


# Crowd Anim Blueprint

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

Crowd Anim Blueprint was designed as solution for driving the animation states of a crowd with high enough performance to animate thousands of crowd members while still maintaining a familiar workflow.

<figure><img src="/files/HwMSfHerAAveXSr2Rwpb" alt=""><figcaption><p>High level overview of how Crowd Anim Blueprint goes from a familiar ABP setup to efficient execution for the crowd</p></figcaption></figure>

Crowd Anim Blueprint makes use of the existing Animation Blueprint (ABP) system in Unreal to author the animation setups for crowd members. This allows animators familiar with ABPs to customize their own animation logic with no programmer intervention required.

There is then a custom compiler that generates an efficient custom bytecode representing the ABP created by the animator. The bytecode generated is optimized for execution on the GPU with efficient encoding to minimize the complexity of the data processed by the compute shader.

Finally, this bytecode is executed on the GPU to evaluate and update the animation setup for every crowd member. By running on the GPU instead of the CPU, it’s able to process all instances in parallel and reduce the time spent on the game thread.


# User Guide - Crowd Anim Blueprint

## Setting up the Animation Blueprint (ABP) <a href="#setting-up-the-animation-blueprint-abp" id="setting-up-the-animation-blueprint-abp"></a>

To enable Crowd Anim Blueprint for your ABP, you must add the `Crowd Animation Output` node at the *end* of your ABP, typically before the `Output Pose` node, as shown below. Everything before this node will be compiled by Crowd Anim Blueprint automatically when the ABP is compiled. If there are no errors, this is all that is required and you’ll be ready to use your ABP with Crowd Anim Blueprint.

<figure><img src="/files/otZCuWVDE9ODEuaFCUGR" alt=""><figcaption><p>Typical usage of the Crowd Animation Output node to enable Crowd Anim Blueprint for an ABP</p></figcaption></figure>

In some cases, you may have ABP nodes that apply unsupported logic to the final ABP pose, as shown below. In this case, make sure to put the `Crowd Animation Output` node before the chain of unsupported pose nodes, and Crowd Anim Blueprint will ignore them

<figure><img src="/files/pEeCvIr2tWBkrdlrT4Np" alt=""><figcaption><p>The Crowd Animation Output node placed before the chain of unsupported nodes</p></figcaption></figure>

{% hint style="warning" %}
In all cases, you should **never** have more than one `Crowd Animation Output` node in a single ABP
{% endhint %}

## Supported ABP Nodes <a href="#supported-abp-nodes" id="supported-abp-nodes"></a>

Not all ABP nodes are supported by the Crowd Anim Blueprint compiler. The reference page [here](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes) lists nodes and features that are currently supported by Crowd Anim Blueprint. It also details any subtle behaviour differences there might be between an Unreal Actor's use of an ABP node and the crowd version of the same ABP node.

## Resolving errors in the ABP <a href="#resolving-errors-in-the-abp" id="resolving-errors-in-the-abp"></a>

In some cases, your ABP may not compile anymore with Crowd Anim Blueprint enabled. When this occurs, you will get an error in the ABP compiler window with details on why. This will most likely be because you use a node or some configuration that is not supported by Crowd Anim Blueprint, as shown in the image below.

<figure><img src="/files/EpyPIHxvu3ORNyBwQddh" alt=""><figcaption><p>Example of an ABP that no longer compiles under Crowd Anim Blueprint due to the usage of an unsupported node</p></figcaption></figure>

To work around the issue, you can of course simply stop using the offending node in your ABP. If however you'd still like to use the functionality on your Unreal Actors, but do something different for crowd members, there are a pair of nodes available for this purpose.

Using a `Crowd Animation Switch` (for AnimGraph errors) or `Crowd Animation Value Switch` (for transition logic errors) allows you to create two paths, one for the crowd and one for runtime.

* You can then use the offending node as normal for the runtime route, which normal actors will use
* In the Crowd Anim Blueprint route, you can then provide alternative ABP nodes that do not utilize offending nodes
* The image below has an example of using this node to remedy the error

<figure><img src="/files/xXnLUJDMkLFe7lSIHUHB" alt=""><figcaption><p>The ABP now compiles again under Crowd Anim Blueprint, thanks to the Crowd Animation Switch node</p></figcaption></figure>

There may be cases where Crowd Anim Blueprint will compile your ABP correctly, but will ignore specific settings that it does not support, such as a custom crossfade duration on a transition. Since it would be annoying for Crowd Anim Blueprint to report these as warnings when there is nothing you can do to resolve them, they are instead reported as “verbose warnings” instead, which are hidden by default.

<figure><img src="/files/EM9ssGk9zY7uKATUGCfh" alt=""><figcaption><p>A verbose warning output by Crowd Anim Blueprint about the unsupported crossfade duration in the transition</p></figcaption></figure>

Verbose warnings can be enabled with the command below

`CrowdAnimBlueprint.VerboseCompilerWarnings 1`

## Optimizing the ABP for Crowd Anim Blueprint <a href="#optimizing-the-abp-for-crowd-anim-blueprint" id="optimizing-the-abp-for-crowd-anim-blueprint"></a>

While Crowd Anim Blueprint runs on the GPU and can execute at a much larger scale than a traditional ABP does, there is still a non trivial amount of work the system has to do. In some cases you may want to optimize your ABP to be more efficient for Crowd Anim Blueprint if you need to squeeze out some more performance.

These things will generally make your ABP slower to process by the system

* Lots of outgoing transitions from a single state
* Complex conditions in state transitions
* Lots of unique parameters
* Complex chains of pose blend operations
* Frequent use of "Use Cached Pose" node


# Reference Guide - ABP Nodes

## Overview

This guide lists all ABP nodes supported by the crowd animation system and details what level of functionality each node has compared to the full Unreal ABP implementation.

Before listing details, it’s worth noting there are some fundamental differences in the way the crowd animation system works on the GPU. Some properties (for example anything relating to blueprint events) will be ignored and won’t do anything. This caveat applies to all nodes, so to keep the guide short these limitations aren’t listed per-node with details - if a property involves blueprint functionality, you can assume this functionality is not supported. An example of this would be the `On Initial Update` / `On Become Relevant` / `On Update` functionality.

<figure><img src="/files/dwR1CeFysGin31R3HOqh" alt=""><figcaption><p>Unsupported blueprint functionality</p></figcaption></figure>

## Supported Nodes At A Glance

Below is a list of nodes and whether they support most common functionality. If a node is supported here the node will generally do something “reasonable”. It may not match the full Unreal ABP solution 1:1, but it will typically give a good approximation in the crowd for common use-cases.

If a node is not listed below it generally means the node is unsupported. There are a lot of nodes and this list only covers the common cases. Additional information and notes about each node can be found on the linked pages.

<img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> - Most features supported in a way that would be expected\ <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> - Supported, but features missing or important differences to be aware of\ <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> - Unsupported

* [Animation Playback](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/animation-playback)
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Sequence Player
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Blendspace Player
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> AimOffset Player
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Random Sequence Player
* [States and State Machines](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/states-and-state-machines)
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> State
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> State Alias
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> State Machine
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Conduit
* [Variables](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/variables)
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Anim Vars
* [Transitions](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/transitions)
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Transition Properties
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Transition Rules
* [Special](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/special)
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Crowd Animation Output
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Crowd Animation Switch
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Crowd Animation Value Switch
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Save Cached Pose
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Use Cached Pose
* [Blends](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/blends)
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Blend
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Blend Multi
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Layered Blend Per Bone
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Apply Additive
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Apply Mesh Space Additive
* Common unsupported nodes
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Blend by enum
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Blend poses by bool / int


# Animation Playback

## Sequence player <a href="#sequence-player" id="sequence-player"></a>

<figure><img src="/files/d1kHadpK1SjIWXRNVHZm" alt=""><figcaption><p>Sequence Player Properties</p></figcaption></figure>

#### Supported properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Sync
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Relevancy
  * Fully supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Settings
  * Fully supported, with the exception of `PlayRateScaleBiasClamp`, which is ignored
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Pose Matching

## Blendspace Player <a href="#blendspace-player" id="blendspace-player"></a>

<figure><img src="/files/SWJEiJcY746SwVxO573A" alt=""><figcaption><p>Blendspace Player Properties</p></figcaption></figure>

#### Supported properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Sync
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Relevancy
  * Fully supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Coordinates
  * One or two inputs supported
  * Inputs can be constant or anim vars
  * Complex expressions on inputs are generally **not** supported at present (e.g. mathematical operations / type conversion)
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Settings
  * Fully supported, with the exception of `Reset Play Time when Blend Space Changes`, which is ignored

## AimOffset Player <a href="#aimoffset-player" id="aimoffset-player"></a>

#### Supported properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Performance
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Alpha
  * `Alpha input type`
    * `Float Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Bool Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Anim curve` is unsupported
  * `Alpha Scale Bias` is unsupported (settings ignored)
  * `Alpha Scale Bias Clamp` is unsupported (settings ignored)
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Sync
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Relevancy
  * Fully supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Coordinates
  * One or two inputs supported
  * Inputs can be constant or anim vars
  * Complex expressions on inputs are generally **not** supported at present (e.g. mathematical operations / type conversion)
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Settings
  * Fully supported, with the exception of `Reset Play Time when Blend Space Changes`, which is ignored
  * Additionally, see notes [here](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/additional-notes#mesh-space-additive-support) on mesh space additive support within crowd, since there are important differences here from full Unreal ABP solution

## Random Sequence player <a href="#random-sequence-player" id="random-sequence-player"></a>

<figure><img src="/files/PakRWAxPKqJJvqZpyOBd" alt=""><figcaption><p>Random Sequence Player Properties</p></figcaption></figure>

#### Supported properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Settings
  * Full support for `Sequence` and `Chance to Play`
  * `Min Loop Count` and `Max Loop Count` will be evaluated and a fixed loop count will be chosen by crowd ABP compiler (within ranges specified), but will *not* be selected dynamically when sequence is chosen
  * Similar to loop count, `Min / Max Play Rate` are read and a value is fixed at compile time within the bounds
  * `Blend In` and `Shuffle Mode` are **not** supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Relevancy
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag

{% hint style="danger" %}
**Behavior Divergence**

The crowd animation system is not guaranteed to select the same random sequence as its non-crowd counterpart. Random number generation for both systems is different and sequences chosen between the two may diverge.
{% endhint %}


# States and State Machines

## State <a href="#state" id="state"></a>

<figure><img src="/files/wNDzbdxFvOPiwGnXbOJ1" alt=""><figcaption><p>State Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Graph Node
  * Fully supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Animation State
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Events

## State Alias <a href="#state-alias" id="state-alias"></a>

<figure><img src="/files/1FnljspvsAJaHnQFSgS4" alt=""><figcaption><p>State Alias Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Graph Node
  * Fully supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> State Alias
  * Fully supported

## State Machine <a href="#state-machine" id="state-machine"></a>

<figure><img src="/files/9BmRSInfwpa0HVHszsw1" alt=""><figcaption><p>State Machine Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Graph Node
  * Fully supported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Settings
  * No settings here are directly supported, all of these settings are ignored.
  * In terms of transitions per frame and max transition requests, crowd differs from regular ABP execution since it doesn't enforce limits. *However*, these transitions aren’t quite the same as Unreal’s transitions.
    * With Unreal, if a transition is passed through, it gets played. If we execute 3 transitions in a frame for example, these will all typically get played back, blending from one to the next
    * With crowd, if a transition is passed through, it’ll do nothing.
  * Example: If we transitioned Idle → Walk → Run states in a single frame
    * Unreal would keep these transitions and blends playing back over multiple frames (i.e. idle would be playing, blended with walk. The result of this would be blended with run)
    * Crowd will just skip out walk in the middle, and blend idle with run
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag

## Conduit <a href="#conduit" id="conduit"></a>

<figure><img src="/files/uvwyoheFXc8cAbw27Uf5" alt=""><figcaption><p>Conduit Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Graph Node
  * Fully supported


# Variables

#### Anim Vars <a href="#anim-vars" id="anim-vars"></a>

Generally for anim vars there isn’t much to configure from a properties points of view. They are commonly used via a macro such as the following which is supported by crowd animation.

<figure><img src="/files/CIreRM1kv6UFpoimp9tw" alt=""><figcaption><p>Macro Example</p></figcaption></figure>

In terms of limitations it’s worth noting that the current implementation of the Anim Vars encodes all data as float. Internally Boolean properties (e.g. Is Moving above) will be converted on the CPU before being sent to the GPU crowd animation system as a floating point type. If these flags are used for transition logic between states there may be floating point inaccuracies and imprecision in comparisons.


# Transitions

## Transition Properties <a href="#transition-properties" id="transition-properties"></a>

Not a node as such, but this covers the properties on transitions:

<figure><img src="/files/52pMCt4wPAGDbleZs7kt" alt=""><figcaption><p>A Transition</p></figcaption></figure>

#### Supported properties

<figure><img src="/files/TsxQnf4g4dn4tfTBoU7l" alt=""><figcaption><p>Transition Properties</p></figcaption></figure>

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Transition
  * `Priority Order` is supported
  * `Bidirectional` is unsupported
  * `Blend Logic` is unsupported (always assumes a Standard Blend)
  * `Transition Rule Sharing` is unsupported
  * Transition rules themselves are [covered below](#transition-rules)
  * `Automatic Rule Based On Sequence Player In State` is supported
  * `Automatic Rule Trigger Time` is supported (both nonnegative and negative configurations)
  * `Sync Group Name to Require Valid Markers Rule` is unsupported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Blend Settings
  * <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/ef8b0642-7523-4e13-9fd3-01b65648acf6/64x64/26a0.png" alt="warning" data-size="line"> Note: Blend settings are always assumed to be a linear transition over 0.2s whenever a state change occurs within the crowd (see `CrowdAnimBlueprintCommon::CrossfadeDuration` constant)
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Events
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Notifications

## Transition Rules <a href="#transition-rules" id="transition-rules"></a>

Simple transition rules can be achieved through comparisons on one or more inputs combined with logical operations.

For example, the following kinds of expressions would be supported

* `AnimVar.IsMoving == 1`
* `AnimVar.HasLowGravity != 0`
* `(Get Relevant Anim Time > 0.4) & (AnimVar.IsJogging == 1)`

where the expressions are all of the form `[Input] [Comparison] [Constant]`. The last case is simply a logical combination of two of these, which also fine.

<figure><img src="/files/lzmd3srlPDGb7WmOhEw3" alt=""><figcaption><p>A simple transition rule just reading a single Anim Var property via a macro</p></figcaption></figure>

<figure><img src="/files/rv43iDIPIU5uJ2Rosiij" alt=""><figcaption><p>A more complex transition rule reading two properties with some logic</p></figcaption></figure>

#### Variables Supported

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Anim Var inputs
  * Anim Var inputs generally supported
  * As noted [here](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/variables#anim-vars), Boolean variables are all internally represented as float, so care around precision may be needed in comparisons
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Timestamp tests on state machine
  * Get Relevant Anim Time
  * Get Relevant Anim Time Fraction
  * Get Relevant Anim Time Remaining
  * Get Relevant Anim Time Remaining Fraction
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Timestamp tests on asset player
  * Current Time
  * Current Time (ratio)
  * Time Remaining
  * Time Remaining (ratio)

#### Comparisons

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Floating point comparisons: `<`, `<=`, `=`, `!=`, `>=`, `>`
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Non-floating point comparisons (e.g. enums), unsupported
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> `In Range` node supported on float and integer types

#### Logical Ops Supported

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> And
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Or
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Xor
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Not

#### Misc

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Macros
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> Struct breaking (e.g. extracting a component from a vector)


# Special

## Crowd Animation Output <a href="#crowd-animation-output" id="crowd-animation-output"></a>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> This node doesn’t have any relevant properties to configure
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag

## Crowd Animation Switch <a href="#crowd-animation-switch" id="crowd-animation-switch"></a>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> This node doesn’t have any relevant properties to configure
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag

## Crowd Animation Value Switch <a href="#crowd-animation-value-switch" id="crowd-animation-value-switch"></a>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> This node doesn’t have any properties to configure

## Save Cached Pose and Use Cached Pose <a href="#save-cached-pose-and-use-cached-pose" id="save-cached-pose-and-use-cached-pose"></a>

#### Supported Properties

* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/check-64px.png" alt="Check Mark" data-size="line"> These nodes don’t have any relevant properties to configure
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Functions
* <img src="https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/atlassian/productivityEmojis/cross-64px.png" alt="Cross Mark" data-size="line"> Tag

{% hint style="danger" %}
**Performance Warning**

When using cached poses it is worth noting that these nodes effectively copy-and-paste the graph that’s input into the `save cached pose` node for each instance of `use cached pose`. This can lead to increased Crowd Anim Blueprint program complexity in the output program. The advice therefore is to use these nodes sparingly as needed.
{% endhint %}


# Blends

## Blend <a href="#blend" id="blend"></a>

<figure><img src="/files/heKNFUbKrJ1loJFKN34v" alt=""><figcaption><p>Blend Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/26a0/path?scale=MDPI" alt="warning" data-size="line"> Settings
  * `Alpha input type`
    * `Float Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Bool Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Anim curve` is unsupported
  * `Alpha Scale Bias` is unsupported (settings ignored)
  * `Alpha Scale Bias Clamp` is unsupported (settings ignored)
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Functions
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Option
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Tag

## Blend Multi <a href="#blend-multi" id="blend-multi"></a>

<figure><img src="/files/COOtncyZXCK6KnUXMqw6" alt=""><figcaption><p>Blend Multi Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/26a0/path?scale=MDPI" alt="warning" data-size="line"> Settings
  * `Desired Alphas` is supported, but input must be constant (no anim vars)
  * `Alpha Scale Bias` is unsupported
  * `Additive Node` is unsupported
  * `Normalize Alpha` is supported
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Functions
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Tag

## Layered Blend Per Bone <a href="#layered-blend-per-bone" id="layered-blend-per-bone"></a>

<figure><img src="/files/SJTK7HQYLNoF2VBROKWU" alt=""><figcaption><p>Layered Blend Per Bone Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/26a0/path?scale=MDPI" alt="warning" data-size="line"> Settings
  * `Blend Mode` is supported (both branch filter and blend mask supported)
  * `Layer Setup` (branch filter mode) supported, including multiple branch filters per layer
  * `Blend Masks` (blend mask mode) supported
  * `Mesh Space Rotation Blend` is unsupported
  * `Mesh Space Scale Blend` is unsupported
  * `Curve Blend Options` are unsupported (ignored)
  * `Blend Root Motion Based On Root Bone` is unsupported (ignored)
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/26a0/path?scale=MDPI" alt="warning" data-size="line"> Runtime
  * `Blend Weights` are supported, but input must be constant (no anim vars)
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Functions
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Tag
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Performance

## Apply Additive <a href="#apply-additive" id="apply-additive"></a>

<figure><img src="/files/1PBoKqJfkzUdar8CgNFI" alt=""><figcaption><p>Apply Additive Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/26a0/path?scale=MDPI" alt="warning" data-size="line"> Settings
  * `Alpha input type`
    * `Float Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Bool Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Anim curve` is unsupported
  * `Alpha Scale Bias` is unsupported (ignored)
  * `Alpha Scale Bias Clamp` is unsupported (ignored)
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Functions
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Performance
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Tag

## Apply Mesh Space Additive <a href="#apply-mesh-space-additive" id="apply-mesh-space-additive"></a>

<figure><img src="/files/jky2xtCpYF8n6mHcs9fL" alt=""><figcaption><p>Apply Mesh Space Additive Properties</p></figcaption></figure>

#### Supported Properties

* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/26a0/path?scale=MDPI" alt="warning" data-size="line"> Settings
  * `Alpha input type`
    * `Float Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Bool Value` is supported, but `Alpha` input must be constant (no anim vars)
    * `Anim curve` is unsupported
  * `Alpha Scale Bias` is unsupported (ignored)
  * `Alpha Scale Bias Clamp` is unsupported (ignored)
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Functions
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Performance
* <img src="https://improbableio.atlassian.net/gateway/api/emoji/63273493-9579-4b44-9957-e8bef39a56a7/atlassian-cross_mark/path?scale=MDPI" alt="Cross Mark" data-size="line"> Tag

{% hint style="danger" %}
**Mesh Space Additive**

See [notes](/creation/unreal-development/features-and-tutorials/the-animated-crowd/crowd-animation/crowd-anim-blueprint/reference-guide-abp-nodes/additional-notes#mesh-space-additive-support) on mesh space additive support within crowd, since there are blending differences here from full ABP solution.
{% endhint %}


# Additional Notes

## Mesh Space Additive Support

Nodes making use of mesh space additive deserve a special mention (e.g. Apply mesh space additive, AimOffset blendspace).

These nodes are implemented and will generally do something reasonable, but they do *not* implement mesh space additive blending of poses in crowd directly, doing so would incur too much of a performance cost. Instead, when a blend / blend space is encountered that uses mesh space additive the animations used by crowd are converted behind the scenes to a regular additive blend and the node using it is converted as well.

The results are typically plausible for the crowd and this avoids needing a second set of assets for crowd vs non-crowd ABP setups. There will however be differences in blend results, so something to be aware of. If the results of this automatic conversion aren’t good enough, it may be necessary to generate a second crowd-only set of animations and switch to it using a Crowd Animation Switch.


# Crowds of NPCs

## Overview <a href="#overview" id="overview"></a>

NPC crowds provide a way to populate your world with large numbers of animated characters, bringing your world to life even in areas where players might not naturally congregate.

<figure><img src="/files/I0qTliMPWm8o1hsvr9Di" alt=""><figcaption></figcaption></figure>

These NPCs have no networking or physics cost and exist solely client side. They are purely for visual flair and not must not be used for gameplay purposes, nor do they offer a guarantee of being synchronised (in appearance or animation) between two or more clients.

## Placing an NPC crowd <a href="#placing-a-npc-crowd" id="placing-a-npc-crowd"></a>

### Placing the crowd members <a href="#placing-the-crowd-members" id="placing-the-crowd-members"></a>

Crowd members can added via blueprint. The initializer, transform and anim name can be set when adding a new crowd member with `Add Crowd Member`

Crowd members can be preloaded via `Preload Instances` If you know how many crowd members will be added, calling this will make the adding process quicker.

See \``BP_NpcCrowdExample` for an example as to how this can be done.

### Defining a crowd <a href="#defining-a-crowd" id="defining-a-crowd"></a>

Start by placing an `AM2_NpcCrowd`your level. `BP_NpcCrowdExample` is an example of an NPC crowd actor. Either duplicate and modify this asset or create a new one for your project.

This actor is an example BP for configuring the crowd, it allows you to configure the meshes it uses and other properties.

#### Initializers

In your NPC crowd blueprint, the crowd meshes can be configured like below.

<figure><img src="/files/xmZDCoIFnvB1AVTA2oLC" alt="" width="526"><figcaption><p>BP_NpcCrowdExample Initializers detail panel</p></figcaption></figure>

#### Animations

The list of animations can be configured like below.

<figure><img src="/files/mufmErVg4hYVAiutrESY" alt="" width="526"><figcaption><p>BP_NpcCrowdExample AnimList details panel</p></figcaption></figure>

In your `AM2_NpcCrowd`, set the following properties:

* Crowd Data: `M2Content/Content/AnimatedCrowd/DA_SkeletalCrowdData_LoD1`
* Ism Actor Type: `M2Content/Maps/TestGyms/CrowdTestGyms/BP_SkeletalCrowdIsm_LoD1`

If your project has its own crowd assets, you can use those instead.

### Move crowd with actor

<figure><img src="/files/b9iUklvJmoA2enGrSMaz" alt=""><figcaption></figcaption></figure>

Enabling `Move Crowd with Actor` in the NPC Crowd details panel ensures that crowd member transforms are updated whenever the `AM2_NpcCrowd` actor's transform changes. When this occurs, each crowd member's location is recalculated relative to their position in relation to the actor's transform.

When the actor's rotation is updated, the entire crowd rotates as a unified block relative to the actor's transform.

Similarly, when the actor's scale changes, the crowd members spread out or compress collectively, maintaining their relative positions, rather than altering the individual scale of each member.


# Example Plugin

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

The `M2 Example` plugin acts as an slightly more fleshed out starting point for Morpheus Platform projects, adding some example/reference features, which users can then learn from or build upon in their own projects. Features/functionality added in this plugin are not considered core Morpheus Platform functionality, but have been added to show how such features could be added in downstream projects, using a combination of core Morpheus Platform functionality, and native Unreal.

<figure><img src="/files/eAjv7LQHZWKKSYCxI7if" alt=""><figcaption><p>The Example Map acts as the starting point for new projects, showing examples of Morpheus Platform functionality in action</p></figcaption></figure>

## Outline of the content

Some of the features added in the M2 Example plugin:

* The `ExampleMap` - a simple map designed to be the entry point for new projects, showcasing core Morpheus Platform features with simple examples.
* Some example core classes, e.g. the `BP_M2Example_GameMode`, and `BP_M2Example_PlayerCharacter`.
  * Some further details on the core character classes can be found in [The Example Character](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/the-example-character)
* A basic example UI setup (see [UI](/creation/unreal-development/features-and-tutorials/ui))
  * Includes an example settings menu (`WBP_M2Example_SettingsMenu`), showing how to modify things like your profile name, your avatar URL, and audio & graphics settings

    <figure><img src="/files/TqMQHujmXPeBOEiJ0Fus" alt=""><figcaption></figcaption></figure>
  * We include an example ["UI Mode"](/creation/unreal-development/features-and-tutorials/ui/ui-mode) toggling system, to enable users to switch between a "game mode" (where the mouse is captured and used as camera rotation), and a "UI mode", where the mouse is released, and users are allowed to click on things.
  * We have enabled a key binding to disable the main game HUD. This does not disable all visual elements such as Nameplates or any project-added widgets that are not attached to the player's HUD. See `BP_M2Example_PlayerCharacter` for implementation details.
    * Press `Ctrl+Alt+H` to toggle visibility
* Its own bot behavior store (`BP_M2Example_BotBehaviorStore`), and custom bot behaviors (e.g. `BT_M2Example_BotTextChat`), to test out the example plugin-specific functionality. (For more details on how bots work and are configured, see [Bots](/creation/unreal-development/features-and-tutorials/bots))
* An example Unreal text chat system (see [Unreal Text Chat](/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat))
* An example Nameplate component, that displays their profile names, and their recent text chat messages (see [Nameplates](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/nameplates))

  <figure><img src="/files/cQm0Uq5BJ5YegVUv2akX" alt="" width="356"><figcaption></figcaption></figure>
* Example "resizing" functionality (see [Resizing](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/resizing))
* Example usage of the [KV Store Service](/creation/unreal-development/features-and-tutorials/online-services/kv-store-service)
* Example video player (see [Example Synced Video Player](/creation/unreal-development/features-and-tutorials/video-players/streaming-video-player/example-synced-video-player))
* Example "footsteps audio" (see [Footsteps Audio](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/footsteps-audio))
* Example "observer cam" pawn (see @ObserverCam)

Any functionality that you are interested in using in your project, please have a look, and copy whatever is useful for you!

### A note on the example classes:

The example classes, e.g. `BP_M2Example_PlayerController`, have been set up based on a minimal base class, adding some example functionality. We believe these to be a reasonable starting-off point, but they are not the base-most classes that can be used, if you want to start from scratch. Please consider the following:

<table><thead><tr><th width="124">Class</th><th width="250">Minimum supported base class</th><th>Context</th></tr></thead><tbody><tr><td>Game Mode</td><td><code>M2_GameMode</code> (C++)</td><td>The M2 base class adds essential functionality for operation with MSquared, such as the <code>PlayerMorpheusActorClass</code>.</td></tr><tr><td>Player Controller</td><td><code>PlayerController</code> (C++)</td><td>All additions to the base player controller class are optional</td></tr><tr><td>Pawn / Character</td><td><code>M2_CharacterBase</code> (C++)</td><td><p>The M2 base class adds essential functionality for operation with MSquared, such as overriding the out-of-bounds behavior, which can only be done in C++.<br></p><p><em>As well as the C++ base class, we have added a barebones <code>BP_M2_PlayerCharacter</code>, which adds some minimal input and the like to get started.</em></p></td></tr><tr><td>Morpheus Actor</td><td><code>M2M_CharacterBase</code> (C++)</td><td>The M2 base class adds essential functionality for operation with MSquared, such as enabling MML avatars, and supporting animations in the crowd.<br><br><em>The class above the M2M character is <code>MorpheusPawn</code>, which is the true base class for any player controllable Morpheus Actor, but this does not support the above core MSquared functionality, which must be configured in C++.</em></td></tr></tbody></table>

### Respawning/Out-of-bounds logic

{% hint style="warning" %}
The following documentation is for release v36 onwards
{% endhint %}

One limitation of MSquared only supporting modifying Unreal assets, and not code (see [Differences from Unreal](/creation/unreal-development/getting-started/differences-in-unreal-development-workflow)), is that the character's "out of bounds" behavior is hidden away, and cannot typically be overridden. The default behavior of an actor when out of bounds (e.g. hitting a kill plane) is to destroy the actor. This is not compatible with typical MSquared experiences, since we pool and reuse the characters (see [Actor Pooling](/creation/unreal-development/features-and-tutorials/actor-pooling)).

Therefore, we have surfaced `Event Notify Outside World Bounds`, which is triggered when the character ends up out of bounds. This behavior can be overridden to implement whatever death/respawn logic etc. you want in your experience.

<figure><img src="/files/h3LcfKaz5o6zeWZkErhA" alt=""><figcaption><p>The default behavior in our base class <code>BP_M2_PlayerCharacter</code> is currently to just log a warning. We will write a fuller example behavior in future.</p></figcaption></figure>


# The Example Character

This page outlines some of the opinionated decisions made in the example character classes.

## BP\_M2Example\_PlayerCharacter

This is our example Pawn - the physical actor in the world. This is what the player controls on the local client. On other clients, this is the physical representation of your character that they will see when at LOD0 (for more details on this, see [Morpheus Render Targets](/creation/unreal-development/getting-started/networking/morpheus-render-targets)).

It adds a number of example components, such as:

* `BPC_SoftPawnHandling` - a "soft collision component", enabling users to walk through each other, but still act as if other characters have a physical presence in the world
* `BPC_M2Example_FootstepsAudioComponent` - enabling [Footsteps Audio](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/footsteps-audio)

### BP\_M2\_PlayerCharacter

The example functionality in our pawn is split into two levels. The more opinionated logic is in `BP_M2Example_PlayerCharacter` (i.e. the example components above), whereas some more "core" functionality is present in `BP_M2_PlayerCharacter`.

This core functionality includes some basic input handling - adding a mapping context (`IMC_CharacterMovement`), and listening to some basic inputs, like movement, jumping and sprinting.

Sprinting is an example of a custom anim variable (see [Custom Animation Variables](/creation/unreal-development/features-and-tutorials/avatars/bespoke-character-animations)). As well as modifying our movement speed (via the `CharacterMovementComponent`'s `MaxWalkSpeed` variable), we need to inform our anim instance (`ABP_M2_Human`) that we are sprinting. We do this via `BPMC_M2_AnimVarsComponent`, which registers a custom anim var for sprinting, and applies it whenever the value updates

<figure><img src="/files/lCy6JK7jMNfnerhDYhWo" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/q4BQjOWJ0QnNPVM4KXhk" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QaNBK3MI1G5jww9dCvW6" alt=""><figcaption></figcaption></figure>

## BPM\_M2Example\_PlayerCharacter

This is our example Morpheus Actor (the actor responsible for handling any networked state for your character. For more details, see [Introduction to Morpheus Networking](/creation/unreal-development/getting-started/networking/networking))

This extends from `M2M_CharacterBase` - the minimal class we require for your Morpheus Player Character.

It adds a number of example components, such as:

* `BPMC_M2Example_ResizingComponent` - enabling [Resizing](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/resizing)
* `BPMC_M2Example_TextChatComponent` - enabling [Unreal Text Chat](/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat)
* `BPMC_M2Example_RolesComponent` - enabling [In-Game Roles](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/in-game-roles)

### Applying a Pawn Set

`BPM_M2Example_PlayerCharacter` applies a Pawn Set (see [Character Configuration](/creation/unreal-development/getting-started/differences-in-unreal-development-workflow/msquared-character-configuration#pawn-sets)) on begin-play for all machines. This is required to connect your Morpheus Actor to your Render Target Actor.

<figure><img src="/files/lItlLEVlLEZUTr4C6VLc" alt=""><figcaption></figcaption></figure>

### Setting an MML Avatar

We have some example logic that applies an MML Avatar for your character (for details on this, see [Avatars](/creation/unreal-development/features-and-tutorials/avatars)). Our example logic first checks if there was an avatar provided by your profile, and if not, loads a random one from a bucket of known MML Avatar Urls.

<figure><img src="/files/i1Kc2zCABekaZm8PZyJj" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/VXJ38WG8moGScSwabCco" alt=""><figcaption></figcaption></figure>

## BP\_M2Example\_PlayerController

This is our example Player Controller. It extends directly from native Unreal's `PlayerController`.

The main thing it adds is example handling of a "UI Mode" (see ["UI Mode"](/creation/unreal-development/features-and-tutorials/ui/ui-mode)). It adds an example input for switching between "UI mode" and "game mode", and handling external requests for entering/leaving UI mode.

<figure><img src="/files/CiNTz10jjP9bqcgOZNG1" alt=""><figcaption></figcaption></figure>

## ABP\_M2\_Human

This is our example Anim Instance. This handles all our core animations, such as running, jumping, combat mode, and looking up and down. It includes some examples of [Custom Animation Variables](/creation/unreal-development/features-and-tutorials/avatars/bespoke-character-animations)(e.g. `CustomAnimVars:IsSprinting`), and supports animations on the [Animated Crowd](/creation/unreal-development/features-and-tutorials/the-animated-crowd/legacy-animated-crowd).

In general, making changes to the anim instance is a more complicated affair, so we advise reaching out to support if you feel you may need this for your project.

<figure><img src="/files/zCyYG5FwEbQb7j1ZQsB0" alt=""><figcaption></figcaption></figure>


# Nameplates

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

In [Example Plugin](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin), we have an example component, `BPC_M2Example_NameplateComponent`, which displays players' usernames over their heads, along with their recent chat messages.

<figure><img src="/files/DZ5J8DS2ENDlEcHXqlCB" alt=""><figcaption></figcaption></figure>

## Features (and limitations)

* Players in the rendering LOD 0 will have nameplates over their heads
* Visibility checks are used to hide the nameplates of players that are blocked by scenery
  * The visibility checks run on a 1 second timer, so will not apply instantaneously as characters move e.g. behind scenery
  * The example's visibility checks are pretty simplistic, running a single line trace to the center of the character, so partially visible characters may or may not have nameplates visible
* If players with nameplates move closer/further away, their nameplate will get larger/smaller
* If players with nameplates send chat messages, they should appear over their heads.
* You can globally disable nameplates, if you want them (temporarily) hidden - see [#globally-disabling-nameplates](#globally-disabling-nameplates "mention")

## Implementation Details

### The nameplate component logic

`BPC_M2Example_NameplateComponent` is a `WidgetComponent`, attached to the `BP_M2Example_PlayerCharacter`'s head, the which displays a `WBP_M2Example_Nameplate` widget.

<figure><img src="/files/HPtjnsToa7KGfk4pY3Cp" alt=""><figcaption></figcaption></figure>

* The widget "distance" calculations are done in the component's tick, to update the scale of the widget based on how far away the player is from the camera.
  * If `DistanceCullingEnabled` is true, this will also hide the widgets if their square distance is outside of `VisibilityDistanceSqrd`.
* The "visibility checking" is run in a separate timer at a lower interval (`LOSTimerIntervalSeconds`)

  <figure><img src="/files/4fd0xE4PZlFXqqVDRreu" alt=""><figcaption></figcaption></figure>
* The component needs to listen to the pooling events (see [Actor Pooling](/creation/unreal-development/features-and-tutorials/actor-pooling)), to make sure that the nameplate of the current actor reflects the correct corresponding Morpheus Actor.![](/files/lcL2dtUK79EcasQAhnIa)

### The player name

To determine the local player's name, we need to use the "Profile data provider" world service (see [World Services](/creation/unreal-development/features-and-tutorials/helpers-and-extras/world-services)). This service is responsible for getting your player name from the web platform, and applying any name changes back to the web platform.

For other players to see your player name, we need to replicate that within Unreal. This is done in the `BPMC_M2Example_PlayerNameComponent`.

<figure><img src="/files/KDTmiBKO980Xi7UHsW0b" alt=""><figcaption></figcaption></figure>

The `WBP_M2Example_NameplatePlayerName` widget (a widget within `WBP_M2Example_Nameplate`) then listens to this replicated player name updating, to update the nameplate.

### Chat on the nameplate

The nameplate listens to the unreal chat system outlined in [Unreal Text Chat](/creation/unreal-development/features-and-tutorials/communication/unreal-text-chat).

This is done in `WBP_M2Example_NameplateMessagesContainer` - another widget within `WBP_M2Example_Nameplate`.

<figure><img src="/files/4rjQ4WiTBYbjrJnFd9eD" alt=""><figcaption></figcaption></figure>

### Globally Disabling nameplates <a href="#globally-disabling-nameplates" id="globally-disabling-nameplates"></a>

If you want to hide all nameplates, you can do so using the `BP_M2Example_NameplateManagerService`. This lets you set nameplates as a whole as "disabled". This will ensure that all nameplates are not visible (but won't actually affect the underlying logic).

If you re-enable nameplates using this service, the default behavior will be restored - nearby nameplates will be visible, but we will still use the other nameplate visibility checks, e.g. whether they are blocked by scenery.

<figure><img src="/files/Pozn10Aga9jmTdHcdeJf" alt=""><figcaption><p>The following logic toggles the visibility of nameplates</p></figcaption></figure>


# In-Game Roles

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

The web platform provides an interface to control what "roles" a user has access to, which we can then use in-game to limit or enable particular functionality. For more details on this, see [Setting Role Groups](/creation/worlds/invite-players/role-groups)

<figure><img src="/files/5qniSNXnqAtB5Z6UytXY" alt=""><figcaption></figcaption></figure>

`BPMC_M2Example_RolesComponent` is our example usage of this, demonstrating how you can read this information from the web platform and use it to affect gameplay.

<figure><img src="/files/Hd2hyImN6DBCedHNaxom" alt=""><figcaption></figcaption></figure>

## How to set up

### How to inform the web platform

To make sure the web platform knows what the in-game roles are, you need to provide them when you upload content.

* In your level's `World Settings`, there is a `Role List Provider` field, which takes a `M2_WorldRoleListProvider` class.

  <figure><img src="/files/53TBnyGmMXaAHOkvf27G" alt=""><figcaption></figcaption></figure>
* The CDO of the provided class has its `GetWorldRoleNames` function called. This is expected to return a list of names, which will be used as the list of possible in-game roles by the web platform.

  <figure><img src="/files/Mjw67SzIk42gvi8yK8tF" alt=""><figcaption><p>In the M2 example, we use an enum to define the possible roles</p></figcaption></figure>

### How to listen to the web platform

The `M2_WebServicesRoleDataProvider` world service (see [World Services](/creation/unreal-development/features-and-tutorials/helpers-and-extras/world-services)) can be used to fetch the roles granted to a given user. If the character does not have access to a given role (e.g. the role was not ticked), it will not show up in the resulting list.

<figure><img src="/files/HZLfe2eHy7T35oLOEbc2" alt=""><figcaption><p>The logic in the <code>BPMC_M2Example_RolesComponent</code> where we look up the roles list for the authoritative client.</p></figcaption></figure>

This can either be done on the client or the server (the client will be able to fetch its own roles, the server will be able to fetch any user's roles). To obtain the UserId on the server, you can use [Morpheus UserID](/creation/unreal-development/features-and-tutorials/helpers-and-extras/the-user-id-replication-component).

{% hint style="info" %}
NOTE: There is a trade-off between doing the roles logic on the server or the authoritative client. If roles management is run on the server, it adds extra security against cheating (clients can only request roles, but the server is responsible for validating and approving the requests), but it adds extra load on the server (the server needing to handle all requests, and validate which roles different players can switch to, instead of the client controlling their own state)
{% endhint %}

## How the example works

* In the example plugin, we have a `E_M2Example_Roles` enum, which we use as the list of roles.

  <figure><img src="/files/AepnWQV0EONNMWA0OwfT" alt=""><figcaption></figcaption></figure>
* The `BP_M2Example_RoleListProvider` converts this enum to a list of names, to inform the web platform

  <figure><img src="/files/JxTUslmNDBTxOhTyu20m" alt=""><figcaption></figcaption></figure>
* The `BPMC_M2Example_RolesComponent`, we communicate withthe `M2_WebServicesRoleDataProvider` to determine which roles we have access to. (On the Authoritative Client)
  * In the editor, since we won't have an associated world to grant us roles (and for bots, which don't have web platform profiles), we skip the lookup step and give everyone access to every role.
* The client replicates the role to all other connections using a background replicated integer property.
* If the client has access to no roles, we give them a default role
* We then use this replicated role to drive gameplay effects (by triggering a `OnRoleUpdated` event, and adding handlers). In our example, we have two:
  * The "elevated" role forces the character into the network and rendering foregrounds, so the character is prioritized over other regular participants (this can be used to make a "presenter"/VIP client)
  * The "fancy" role is a simple example of how the role can affect visuals. In this case, it attaches a prop to the character. (For more details on this, see [Attachments](/creation/unreal-development/features-and-tutorials/avatars/avatar-attachments))
    * We could also swap out the render target actor completely, using `ApplyPawnSet`

      <figure><img src="/files/Yf5aYQiiQSgRDTeta37q" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**A note on performance:**

Since the role in this example is replicated on the background, it runs on every client. For small scale events this is no problem, but when scaling to 18k+, any such property needs to be handled with care, especially when writing logic in BPs. If thousands of OnReps are triggered on the same frame, there will likely be a small hitch, even if each isn't doing all that much.

We are happy with this consideration for the example roles system; since it is not intended to be used frequently, we are happy that it won't cause performance issues.

TL;DR: Users shouldn't be changing roles frequently. That should just be for high level capabilities gated by the web platform. For pure gameplay features (e.g. which "character" a player is playing as), the roles system shouldn't be needed.
{% endhint %}

## I'm still using the deprecated roles system. How can I migrate across?

Since the old roles system has been deprecated, and is not usable with the example character, we advise any users of said system to migrate over when appropriate. However, the example roles system is much lighter than the original roles table, so doesn't do everything that the old system did. However, equivalents should be possible in your own project:

* Using a data table:
  * If you use a custom `M2_RoleListProvider`, you could make it take a data table's row names to provide to the web platform:

    <figure><img src="/files/a1YnKPoRdV3CAsoq87ot" alt=""><figcaption></figcaption></figure>
  * In your `OnRoleUpdated` handler, you could convert the replicated `RoleIndex` back to a data table row, and then apply the details to your character

    <figure><img src="/files/kwWJ8YtHB3voQPASfmfv" alt=""><figcaption></figcaption></figure>
* LOD level set:
  * This can be modified using the `ApplyPawnSet` helper function

    <figure><img src="/files/GzjzBe0l8bMNzOgsrxET" alt=""><figcaption></figcaption></figure>
* Capabilities:
  * Capabilities aren't currently used by the example character, but the capabilities component could be added, and then the capabilities can be granted or removed as a result of the role change, same as before. For more details see [Capabilities](/creation/unreal-development/features-and-tutorials/capabilities).

    <figure><img src="/files/G8SR6cEkQqzYtG8TWc9v" alt=""><figcaption></figcaption></figure>
* Gait speeds:
  * Similar story: this could be overridden in your project as a result of the role change.
  * However, in v39, we no longer use the `J_CharacterMovementComponent` in our example character, instead using Unreal's `CharacterMovementComponent` directly. We advise doing the same.
    * This means that "gait speeds" are no longer an in-built concept in the movement component. An equivalent could easily be achieved in a downstream project though by setting the `MaxWalkSpeed` directly. We have an example of doing this in our example base class: `BP_M2_PlayerCharacter`

      <figure><img src="/files/ASNwR3jw284J59j7bzri" alt=""><figcaption></figcaption></figure>
* Resizing:
  * Switch to using the example component described in [Resizing](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/resizing) (`BPMC_M2Example_ResizingComponent`), or use it as a reference point for your own implementation
  * (Character resizing in the deprecated character is tied to the `JM_ResizeableActorComponent`, which is not compatible with the simplified base character.)


# Resizing

{% hint style="success" %}
verified: 2025-11-19 version: v39
{% endhint %}

We have an example `BPMC_M2Example_ResizingComponent`, which demonstrates how to resize the character in a way that translates to the animated crowd

<figure><img src="/files/6PxgB1dOrfKGto0bRPbD" alt=""><figcaption><p>The example map has some "resize zones", which can grow or shrink player characters that enter<br>The character in the blue volume has been doubled in size, and the character in the green volume has halved.</p></figcaption></figure>

## Features (and limitations)

* Players in LOD0 or the crowd will be able to visually change size
* Players in the rendering LOD 0 will smoothly change size to their target size
* Players in the crowd will instead snap to their target size.
* The `ScaleFactor` variable is a background replicated variable, so is synced to all players, even those far away.

{% hint style="warning" %}
**A note on performance:**

This resizing implementation is not intended for, and should not be used at high frequency in large scale events.

Since the scale factor in this example is replicated on the background, it runs on every client. For small scale events this is no problem, but when scaling to 18k+, any such property needs to be handled with care, especially when writing logic in BPs. If thousands of OnReps are triggered on the same frame, there will likely be a small hitch, even if each isn't doing all that much.
{% endhint %}

* The example map has a `BP_ResizingZone`, which demonstrates how the resizing functionality can be triggered
  * It resizes users to the the target `ScaleMultiplier` when entering the zone, and reverts the change when leaving.
  * There are a few more complex implementation details here, explained in the asset's event graph (e.g. why we don't just use the "overlap" event to trigger scaling up/down)

    <figure><img src="/files/kf2QTRslALS12zHSLLRJ" alt=""><figcaption></figcaption></figure>

## Implementation details

* In our example `BPMC_M2Example_ResizingComponent`, we update a client auth, background replicated `ScaleFactor` float.

  <figure><img src="/files/HmGSlhm7FDHBdjyjrwJ0" alt=""><figcaption></figcaption></figure>
* We apply that scale factor in the OnRep, applying it either immediately, or smoothly on tick.

  Each flow ultimately calls \`ApplyScaleMultiplier to update the character's scale:

  <figure><img src="/files/Roghj5EGoneQrENIkjHP" alt=""><figcaption></figcaption></figure>

  * For LOD0 actors, scale is set using `SetActorScale3D` on the render target actor
    * NOTE: Since the render target actor can change when switching LOD level, we need to also remember to apply the scale multiplier, otherwise characters entering LOD0 will use whatever the last pooled scale was.

      <figure><img src="/files/pAbe2cQIaDNNH2txGQcn" alt=""><figcaption></figcaption></figure>
  * For crowd actors, there is a `SetCrowdScale` function, that applies the scale factor.
  * For the local character, we also modify their spring arm, so the camera zooms in/out appropriately


# Footsteps Audio

{% hint style="info" %}
This doc page is for release v39 onwards
{% endhint %}

The `BPC_M2Example_FootstepsAudioComponent` is our example implementation of adding sound effects when characters take footsteps, or land after being airborne.

## Summary of the implementation

### Linking footstep audio to our animations

Each of our animations with footsteps triggers a notify: `AnimNotify_Audio_MovementSystem`

<figure><img src="/files/aGuY95IppAqNhoOGY6hc" alt=""><figcaption></figcaption></figure>

The bone associated with the footstep (used to determine left vs right foot), and the "audio movement state" (i.e. whether the footstep is a regular step vs landing after a jump etc.) are passed in to the notify.

These notifies are then passed to any components on the animated actor that implement `BPI_Footstep_Listener`, triggering `NotifyFootstep` - both the `BPC_M2Example_FootstepsAudioComponent` and the deprecated `BPC_Audio_MovementSystem` implement this. These components then determine what sound effect to play (see the section below)

### Handling different audio based on terrain

Responding to the `NotifyFootstep` event, the `BPC_M2Example_FootstepsAudioComponent` uses a line trace to determine what physics material is underfoot.

<figure><img src="/files/sscNRwa3SdanuWBoowcH" alt=""><figcaption></figcaption></figure>

We use this physics material to map to a footsteps sound asset, via the `FootstepSoundsDataAsset` property in the component. This maps to a data asset which contains a map, along with a default sound for when we are using an unknown physics material.

<figure><img src="/files/nngA8xfp2SCpoob413po" alt=""><figcaption></figcaption></figure>

If you want to add more physics materials to the list, or swap out the sounds used, you can replace the `FootstepSoundsDataAsset` with your own `BP_M2Example_FootstepSounds` Data Asset. We recommend copying one of the existing `A_M2Example_Foley_Footsteps_[X]` assets as a starting point, and swapping out the `Sounds_[Y]` arrays inside

#### "Land" sounds vs "Moving" sounds

For each material, we want the sound played when landing after a jump to be different to regular footsteps. Therefore, we pass in whether the `NotifyFootstep` was from a "Land" notify or not into the sound. Our sound sources use this to determine what sound to play.

See `A_M2Example_Foley_Footsteps_Grass` for an example.

<figure><img src="/files/DANS65adpAbul6cPL60h" alt=""><figcaption><p>Each sound source has a list of sounds for "movement" footsteps and "landing" footsteps, and it picks one at random, adding some slight pitch shifting, to add variation between each footstep.</p></figcaption></figure>

In our basic example, the only different "movement states" we care about are "Land" vs the rest (movement related states, i.e. walk, jog, sprint)

<figure><img src="/files/VzgvQsYyD7E8DCOgyGBS" alt=""><figcaption><p>The "Jump" state is effectively ignored, since we don't trigger any notifies in our animations for it.</p></figcaption></figure>

## I was using the now deprecated BPC\_Audio\_MovementSystem. Anything to be aware of?

The new stripped down example `BPC_M2Example_FootstepsAudioComponent` is similar to the now-deprecated `BPC_Audio_MovementSystem`, but has some changes to be aware of:

* The "wind audio" has been separated out into `BPC_M2Example_InAirWindAudioComponent`. If you want the wind noise playing while airborne, you can add this component too.
* The physics material-to-audio source mapping, and the audio sources themselves have been modified - see [#handling-different-audio-based-on-terrain](#handling-different-audio-based-on-terrain "mention"). The old data table approach (i.e. `DT_M2_Audio_FootstepSounds`), and the old audio cues with integer `MovementState` will not be compatible. If you want to use the old system, we recommend making local copies of the deprecated assets, and using those.
* Our example footsteps component doesn't pitch shift footsteps based on the actor's size. The old logic from `BPC_Audio_MovementSystem::BindMorpheusEvents` could be copied across to your own implementation if desired, but we recommend using the new resizing component, outlined in [Resizing](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/resizing).
* Our example has a more limited physics material-to-sound source mapping. If your project has materials that you need audio for, you can add them as outlined above in [#handling-different-audio-based-on-terrain](#handling-different-audio-based-on-terrain "mention")


# Observer Cam

How to use the observer controls to make videos for broadcast

The "observer cam" is a cinematic camera, for use in recording footage, or for a "spectator mode". We have example functionality for switching from a regular player to an "observer pawn", that can instead control a flycam, or switch between set cameras, for taking cinematic shots.&#x20;

<figure><img src="/files/ZaPh3DrF2FgHiBdli8yw" alt=""><figcaption></figcaption></figure>

## Switching to Observer Mode <a href="#switching-to-observer-mode" id="switching-to-observer-mode"></a>

We have the `BPM_M2Example_ObserverActivator` in our Example Map, which demonstrates a way of switching to the observer cam, in a way that is reflected on all clients.

Click on the cube to switch to the observer cam!

<figure><img src="/files/PO0PsmQiBNND6MxG2qNg" alt=""><figcaption></figcaption></figure>

### A bit on the implementation

If you want to make your own observer cam equivalent, the main steps here are to switch your render target actor class to your "observer pawn" (in our case, it's `BP_M2Example_ObserverPawn`). You will need to make sure to also replicate this to other clients, to make sure they don't use the default render target actor class, e.g. setting it to null on other clients

<figure><img src="/files/FRaZAPrWXllUVm8QTVBT" alt=""><figcaption><p>In <code>BPM_M2Example_ObserverActivator</code>, we call <code>SetRenderTargetActorClass</code> on all observer actors, tracked in a replicated array, so that we ensure the observer actors are set appropriately on all clients (including late joiners), rather than just the local client.</p></figcaption></figure>

{% hint style="info" %}

## A note on the scalability of the implementation

The example implementation in `BPM_M2Exxample_ObserverActivator` drives all "observer" requests through the server. This was done to enable all "switch to observer" logic to be self-contained in a drag-and-drop actor in the world, and avoid needing any additional components on the `MorpheusPawnActor`.

However, if the observer mode were a highly used feature, this would present scalability risks. (If the server needed to manage 10k players' requests, which is especially slow in blueprints).&#x20;

Since we typically expect only a few observers at most in a world, this approach is fine for our example, but if you want observers, or some equivalent, to be used more frequently, we would recommend making this be client authoritative, e.g. using the [#switching-to-observer-mode-in-other-ways](#switching-to-observer-mode-in-other-ways "mention")approach below.
{% endhint %}

### Switching to observer mode in other ways

The `BPM_M2Example_ObserverActivator` is just a basic example approach for switching to the observer pawn. The main thing to ensure in whatever implementation you use is that you set the `RenderTargetActor` on all clients - the authoritative client should use the observer pawn, and other clients can be set to not have any `RenderTargetActor` class.

For example, if you wanted the observer to be gated/controlled via [In-Game Roles](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/in-game-roles), that could be done, by making modifications to the roles logic to set the `RenderTargetActor` based on an "Observer role".

<figure><img src="/files/Kmrao6RLgGAsvYsIKlCG" alt=""><figcaption></figcaption></figure>

## The shortcut help menu <a href="#bringing-up-the-shortcut-help-menu" id="bringing-up-the-shortcut-help-menu"></a>

When you switch to the observer cam, a help menu will be brought up. This will show the list of observer cam controls. You can toggle it with `H`.

* This includes controls on how to move the camera, or change its speed (while in flycam mode)
* One of the controls is for the [#setting-up-and-choosing-cameras](#setting-up-and-choosing-cameras "mention") menu (`Z`)
  * This includes controls for switching between the managed cameras, either by cycling forwards (`L`) or backwards (`K`), or by selecting a specific managed camera (num-keys `1`-`9`), or toggling between the last selected managed camera and the normal flycam (`C`).
* There are controls to change the "smoothing" of the camera, making the camera rotation more gradual, and less "snappy".
  * The camera rotation is smoothed by default.
* You can disable nameplates using `N`, if you want more "cinematic", less UI-heavy visuals.
  * This is done using: [Nameplates](/creation/unreal-development/features-and-tutorials/the-m2-example-plugin/nameplates#globally-disabling-nameplates)
* You can control the camera's "focus settings", i.e. setting its focus distance. Objects at the focus distance will be clearer, while objects outside of the focus distance will appear more blurry.
  * `T` lets you track a target actor (they must be a `Pawn`, e.g. a player character). This means that as they move, they will automatically adjust the focus distance to track them.
  * `Insert` lets you set the focus distance to the object in the centre of the camera (uses a line trace to determine the distance based on what it hits). This does not track, so the focus distance will remain at that value until it is modified.

<figure><img src="/files/35Uh2iRalyvfyd9Xd9xL" alt=""><figcaption></figcaption></figure>

## Managed Cameras <a href="#setting-up-and-choosing-cameras" id="setting-up-and-choosing-cameras"></a>

As well as using the default "flycam", you can create "managed cameras", that either stay in place, or perform some fixed movement pattern. Once created, you can switch between these and the flycam freely. These can be useful for getting consistent shots, or quickly switching between views.

Cameras are created through the "Camera Management menu". All cameras in a level are replicated and shared between the observers in real time. To open up the menu in observer mode, use `Z`.

<figure><img src="/files/ofEJyUHii6mltf1nn5os" alt=""><figcaption><p>The camera management menu. This shows the currently selected managed camera (Camera 4)</p></figcaption></figure>

### Configuring cameras <a href="#configuring-cameras" id="configuring-cameras"></a>

* Click "Add camera". New cameras will be automatically selected. If you wish to edit a different camera, select it from the dropdown.
* Each camera has a key binding of the num key matching the camera number. Press this to switch to that camera
* You can update the canera's position (and focus settings) to the flycam's current values with the button.
* To create a moving camera, tick `Camera Movement`.&#x20;
  * You can update the target destination of the movement to the flycam's current values using the `Set Movement (& Focus) Destination` button. The camera will move smoothly between the two values (rotation, position and focus settings),
  * `Movement Duration (sec)` can be used to control how long it takes for the camera to move between the `Position` and `Destination` values.
  * If the camera is set to `Continue in background`, then once you stop using the camera, it will remain active, so when you switch back to it, it will be at whatever position it would have been if you had been using it the whole time, instead of resetting back to the starting position.
    * You can reset a `Continue in background` camera by reselecting it using the num key.
  * To switch the camera back to a fixed camera, untick `Camera movement`.
* Actions such as adding/removing cameras, or updating their positions, are tracked, and can be undone or redone.
* We also support saving the selection of cameras per level, per user, using our [KV Store Service](/creation/unreal-development/features-and-tutorials/online-services/kv-store-service). This allows people to configure the cameras ahead of time, and then load them when needed.

{% hint style="info" %}
NOTE: Remember that the managed cameras are replicated and shared across all observers. This means that if multiple users are modifying the managed camera list at the same time, there is the risk of users overriding each others' changes!
{% endhint %}

### Swapping from Cameras to Flycam (and vice versa) <a href="#swapping-from-cameras-to-flycam-and-vice-versa" id="swapping-from-cameras-to-flycam-and-vice-versa"></a>

By default, you’ll start off as a flycam. After switching to a managed camera (eg. with a hotkey), press `C` to switch back to your flycam. It will  be in the position it was in prior to switching to the managed camera. One known quirk is that, while in fixed camera view, you can still move the flycam (but any movement will not be reflected on your screen until you swap back to flycam).


# Emotes

{% hint style="danger" %}
Due for Simplification, please speak to support for further info.

**31/10/2024:** Our Emotes system is a layer built on top of other functionality that enables anim montages to be played in Foreground and Crowd rendering levels. We are planning to simplify this approach and better expose the underlying API.

Support for the Emote system will decrease as we are treating it as an example of functionality rather than a feature in itself.

As part of the simplification, we will be removing Super Emotes from the platform.

MSquared will not be addressing cosmetic issues (such as those in the Emote wheel itself) going forward, but will be ensuring the emotes themselves still function correctly.
{% endhint %}

Emotes are enabled by default and are accessed by players pressing `B` and clicking an icon.

<figure><img src="/files/elAJLilBNucWrV8mwNG0" alt=""><figcaption><p>Emotes in use in a test gym</p></figcaption></figure>

## Implementation

The main implementationof emotes is in `JM_PlayerEmoteComponent`

Other key classes include:

* Emote Selection - The set of emotes that appear in the Emote Wheel UI (`WBP_EmoteSelector`) are configured via the (DEPRECATED) Roles table using the Emote Selection property.
* Emote Selection can be overridden at runtime via Blueprint on the `JM_PlayerEmoteComponent`

## Creating new emotes

Emotes are configured by creating a Primary Data Asset of the type `J_EmotePrimaryAsset`.

These emotes can then be added to the default selection set on the role component or set as overrides at runtime.

<figure><img src="/files/3tJ6XnJrvgTtSHAVDPzE" alt=""><figcaption><p>Clap Emote settings example</p></figcaption></figure>

## Configuration

### Enabling/Disabling Emotes for a role

Emotes can be disabled per game role in your project's (DEPRECATED) roles data table by:

1. In your editor, enable `Emotes Enabled` in the `Role Configuration Overrides` section of the `Role Configuration` section of the roles data table to expose it.

   <figure><img src="/files/UnD7dM1fLdQgqTHISIiZ" alt=""><figcaption></figcaption></figure>
2. Change the `Emotes Enabled` setting to `true` or `false` to enable or disable emotes for this role

<figure><img src="/files/4j96BZl2sjCm7jiIPjni" alt=""><figcaption></figcaption></figure>

#### Configuring Default Emote Selection

You can configure which emotes are available in your experience in your project's roles data table (DEPRECATED) Roles data table by:

1. In your editor, enable `Emote Selection` in the Role Configuration Overrides section of the `Role Configuration` section of the roles data table to expose it.
2.

```
<figure><img src="../../../../.gitbook/assets/EmoteSelectionSettings.PNG" alt=""><figcaption></figcaption></figure>
```

3. Assign a `J_EmoteSelectionData` asset to the Emote Selection setting.

<figure><img src="/files/1UwkwYWrhFEPEunkiUe8" alt=""><figcaption><p>Emote Selection Setting on the Role</p></figcaption></figure>

By default these emotes are available:

<figure><img src="/files/7bzfj1jbg4qyxSyeJa9B" alt=""><figcaption><p>Emote Selection settings</p></figcaption></figure>

| Field            | Description                                                                                                                                            |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Profile as Emote | Emote used to show the Player's profile picture                                                                                                        |
| Pick Me Emote    | This emote is used in place of the Player's profile picture when Profile as Emote is disabled via the live config flag `Profile.ProfileAsEmoteEnabled` |
| Emotes           | This is an array containing all other emotes. To use the default `WBP_EmoteSelector` UI, this **must** be 7 elements long.                             |

## Changing settings at runtime

### Blueprint functions

Emote Selection can be changed at runtime by calling the following functions on the `JM_PlayerEmoteComponent`:

* `OverrideEmotesEnabled`
* `OverrideEmoteSelectionSlotAtIndex`
* `OverrideEmoteSelectionSetFromAsset`
* `OverrideProfileAsEmote`
* `OverridePickMeEmote`

Overrides can be cleared with the following functions:

* `ClearEmotesEnabledOverride`
* `ClearAllEmoteSelectionOverrides`
* `ClearEmoteSelectionOverrideAtIndex`
* `ClearProfileAsEmoteOverride`
* `ClearPickMeEmoteOverride`

### Live Config Settings <a href="#emotes-emotewithplayersprofilepicture" id="emotes-emotewithplayersprofilepicture"></a>

All emote settings live in game.json

<table><thead><tr><th width="278">Key</th><th width="144">Default Value</th><th>Description</th></tr></thead><tbody><tr><td>Emotes.Enabled</td><td>true</td><td>Project wide setting to enable/disable emotes</td></tr><tr><td>Emotes.EmoteWheelEnabled</td><td>true</td><td>Project wide setting to enable/disable the emote wheel UI</td></tr><tr><td>Emotes.ClearEmoteSelectionOverridesOnRoleChanged</td><td>false</td><td>Setting to optionally clear all override settings on role changes.</td></tr><tr><td>Emotes.MaxObjectPoolSize</td><td>20</td><td>Max number of Emote objects to pool.</td></tr><tr><td>Emotes.MaxSoundDistance</td><td>5000.0</td><td>Max distance for emote sounds to be heard</td></tr></tbody></table>

### Debugging in Editor

Console commands are available for all of the above functions to test functionality:

* `M2.Emotes.OverrideEmotesEnabled [bool Enabled]` - Overrides Emotes enabled
* `M2.Emotes.OverrideEmoteSelectionSlotAtIndex [Index Emote Name]` - Overrides an emote slot at Index with the given Emote Primary Asset name e.g. `M2.Emotes.OverrideEmoteSelectionSlotAtIndex 5 PDA_Emote_Icon_ThumbsUp`
* `M2.Emotes.OverrideEmoteSelectionSetFromAsset [Emote Selection Asset Name]` - Overrides all emotes with the given Emote selection asset name e.g. `DA_EmoteSelection_Default`
* `M2.Emotes.OverrideProfileAsEmote [Emote Name]` - Overrides the Profile As Emote slot with the given Emote Primary Asset name e.g. `PDA_Emote_Icon_ThumbsUp`
* `M2.Emotes.OverridePickMeEmote [Emote Name]` - Overrides the Pick Me Emote slot with the given Emote Primary Asset name e.g. `PDA_Emote_Icon_ThumbsUp`
* `M2.Emotes.ClearAllEmoteSelectionOverrides` - Clears all emote selection overrides
* `M2.Emotes.ClearEmoteSelectionOverrideAtIndex [Index]` - Clears emote selection override in slot with the given Index
* `M2.Emotes.ClearProfileAsEmoteOverride` - Clears the Profile As Emote override
* `M2.Emotes.ClearPickMeEmoteOverride` - Clears the Pick Me Emote override


# Emotes as Possessions (items)

This page outlines how emotes can be represented as useable items that can be placed in a user's collection.

Emotes are now additionally represented as useable items. These items are linked to user collection objects. Ownership of the user collection object will provide a user with the an emote item in game. Removal of that user collection object from a users collection will result in the removal of the in game item. These user collection items can be gifted to people using the PDA\_Item\_ItemGranter.

<figure><img src="/files/qvJ0IA2A3e32zdF7uAlX" alt=""><figcaption><p>Example emote item PDA</p></figcaption></figure>


# Helpers & Extras


# Advanced Graphics Settings

## Console commands

The following are some console commands that can be used to modify assorted graphical settings, e.g. to test out performance:

* `scalability [0-3]` - sets all the below `sg.*` settings (except `sg.ResolutionQuality`) to the specified quality level (0: low, 1: medium, 2: high, 3: epic)

{% hint style="info" %}
NOTE: There is a fifth quality level: `4: cinematic`, but this is not suitable for real-time game rendering, and can lead to issues. We advise never setting these settings to 4, even though it exists.
{% endhint %}

* `sg.ViewDistanceQuality [0-3]`
* `sg.AntiAliasingQuality [0-3]`
* `sg.PostProcessQuality [0-3]`
* `sg.ShadowQuality [0-3]`
* `sg.GlobalIlluminationQuality [0-3]`
* `sg.ReflectionQuality [0-3]`
* `sg.TextureQuality [0-3]`
* `sg.EffectsQuality [0-3]`
* `sg.FoliageQuality [0-3]`
* `sg.ShadingQuality [0-3]`
* `sg.ResolutionQuality [X]` - sets the resolution quality to `X`%. (100 being the max. If you go near to 0, it will look very extreme)
* `r.Vsync [0/1]` - turns vsync on/off.
* `t.MaxFPS [X]` - sets the maximum FPS to `X`. <= 0 will set it to uncapped

## User Settings

If you want to modify them per user, and have them saved in their user settings, this can be achieved with the following helper functions in the `J_GameUserSettings`:

* `Get/SetOverallScalabilityLevel` - same as the equibalent `scalability` command line: gets/sets the value of all the scalability settings at once, to one of the set scalability levels: 0: low, 1: medium, 2: high, 3: epic. (If the settings have been individually modified, the getter will return -1: custom)
* `IsVsyncEnabled/SetVsyncAndDefaultFrameLimiter` - the helper combines "vsync on/off" with the default frame limiter - when on , we use a capped frame rate controlled by the `J_GameUserSettings::DefaultFrameLimit` config value. Otherwise, it uses an uncapped framerate.
* `Set/GetViewDistanceQuality` - same as the command line
* `Set/GetAntiAliasingQuality`
* `Set/GetPostProcessingQuality`
* `Set/GetShadowQuality`
* `Set/GetGlobalIlluminationQuality`
* `Set/GetReflectionQuality`
* `Set/GetTextureQuality`
* `Set/GetVisualEffectsQuality`
* `Set/GetFoliageQuality`
* `Set/GetShadingQuality`
* `Set/GetResolutionScaleNormalize` - same as the equivalent command line, but uses a normalized value of `[0-1]` to be equivalent to `[MinScaleValue-MaxScaleValue]`

Each of these settings can be obtained using `GetGameUserSettings`, and saved using `ApplySettings`:

<figure><img src="/files/fpfEBxAq2Qsb1Th70Krt" alt=""><figcaption><p>An example of setting the "vsync and default frame limiter" setting value via a checkbox</p></figcaption></figure>


# Automatic Mesh Validation

{% hint style="info" %}
The following feature was added in release v40
{% endhint %}

## Summary

We have added a mesh validation step to cooks, and upon saving `StaticMesh` and `SkeletalMesh` assets. If you are building for mobile (i.e. your `.uproject` has a `IOS` or `Android` related target platform), these checks will be run, to make sure your meshes will be performant to use.

At the point that you save when in-editor, it will check that enough `LOD` levels have been generated. If there are too few, some will be made automatically.

<figure><img src="/files/VaVjwY0fLN8Cdhpz5IUc" alt=""><figcaption></figcaption></figure>

The checks will also be run when you cook your project (either in-editor, or externally, e.g. via CI). If assets exist that fail the mesh validation checks (i.e. they have too few `LOD` levels), the assets will be flagged. These assets will need to be fixed (they aren't fixed up automatically here, but can be fixed in-editor afterwards, e.g. by re-saving them)

<figure><img src="/files/iq8AJeexw1Kw9nqsZf2h" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
NOTE: If your project is not targeting mobile platforms, this feature won't affect you by default. If you want the checks (and automatic fixes) to apply to your project, you can uncheck the `Only Validate on Mobile` flag.

For more details, see [#configuring-the-mesh-validation](#configuring-the-mesh-validation "mention")below.
{% endhint %}

## Configuring the mesh validation

The mesh validation settings can be found in `Project Settings | M2 World Builder | Mesh Validation`. These can be freely configured to fit your project:

<figure><img src="/files/b1Br72YTLQwEtw9B2qzy" alt=""><figcaption></figcaption></figure>

* `Validate Meshes` - controls whether the validation steps will be run at all. If this is false, all the settings below it are ignored.
* `Only Validate on Mobile` - true by default. If set, the validation steps will only be run if you have a mobile platform in your "Target Platforms" list in your `.uproject` file. If the value is false, then we won't check platforms, and will run the checks on all of them.
  * E.g. this example contains `IOSClient`, so we will validate even if `Only Validate on Mobile` is true.\
    ![](/files/9gPwR3CB523R0K24vCjj)
  * The reasoning here is that projects that aren't intending to run on mobile may not need these LOD checks - the performance requirements on PC are not as severe, and nanite exists to handle performant meshes at different distances without LODs.
* `Auto-LOD Meshes` - if this is true, then when you save meshes in-editor, if they fail the validation check, the required number of LODs will automatically be created for you.
* `Max Vertices Before Needing LODs` - if a mesh has fewer vertices than this, then we don't bother enforcing a minimum number of LODs (e.g. if we have a model that is already very low-poly, it won't need multiple LODs)
* `Min Static Mesh LODs` - how many LODs to require a large static mesh has.
* `Min Skeletal Mesh LODs` - how many LODs to require a large skeletal mesh has.




---

[Next Page](/llms-full.txt/1)

