Appearance
Release 34
September 10th, 2025
Appearance
September 10th, 2025
Hotfix release
Release 34.2 is the latest hotfix release for Release 34.
It contains a critical fix for WebGL, and IL2CPP builds running into an out of memory error. If you are using WebGL, please update to this release as soon as possible.
Game Config diffing has been revamped, the implementation is now server driven for better performance, and the UI has been rewritten for better clarity and usability.

The LiveOps Timeline, previously introduced for LiveOps Events, is now able to show scheduled Leagues, In-Game Offers, Config-Driven Game Events, and other custom Activables that you have implemented. See Configuring Offer Groups for the Timeline and Configuring Config-Driven Events for the Timeline for more information.

The CLI has received a lot of quality of life improvements to make your life easier:
metaplay test integration.metaplay database reset.metaplay database export-snapshot and metaplay database import-snapshot.metaplay get server-info.metaplay get environment-info.metaplay debug database.metaplay debug collect-cpu-profile and metaplay debug collect-heap-dump.dotnet-dump using: metaplay debug collect-heap-dump --mode=dump.metaplay build dashboard --output-prebuilt.metaplay debug database --from-file <query_file> --output <output_file>.See the CLI releases history for a full list of changes.
OrderedSet<T> now implements ISet<T>.IGameEngineIntegration interface to reduce Unity-specific code in the SDK core.SecretUtil.ResolveSecretAsync(log, secretPath) now supports loading secrets from a cloud environment while running in a local development environment.PlayerActor.OnSessionStartAsync(), in sessionParams.IPAddress. Please keep in mind the relevant privacy aspects when handling this personally identifiable information.-ipv6.ClientConnection.MaxCompressedPacketPayloadSize to control the size limit where we start failing to send network messages.ClientConnection.MaxDecompressedPacketPayloadSize to control the maximum size of the decompressed data received from the client.game_player_uncompressed_size to track the player's uncompressed model size.METAPLAY_CLIENT and METAPLAY_CLOUD and use them instead of abusing NETCOREAPP which was used for the same purpose earlier.UnityLogger class has been renamed to MetaClientLogger and made more generic.UnityLogHistoryTracker class has been renamed to LogHistoryTracker and made more generic.MetaHttpClient (instead of HttpWebRequest) to improve platform compatibility.MetaplaySDK.{StreamingAssetsPath, PersistentDataPath} are now deprecated and will be removed in the future. Use Unity's UnityEngine.Application.{streamingAssetsPath, persistentDataPath} instead.BotClientBase.GenerateRandomPlayerName() and other name generation methods no longer accept caller-supplied Random.serverStatusHint.json.MetaTask.MainScheduler as a generic way to access the main thread scheduler. Works outside of Unity as well. Defaults to the thread pool on platforms where there is no special main thread, e.g., on the server.MetaplaySDK.RunOnUnityThreadAsync() has been renamed to more general MetaplaySDK.RunOnMainThreadAsync().ConnectionStates.Connected.LatestReceivedMessageTimestamp. For assessing network quality, Connected.IsHealthy should be used instead.IMetaplayLifecycleDelegate.OnSessionLost() is called with an event with TechnicalErrorCode=1210 TechnicalErrorString=cluster_node_lost instead of TechnicalErrorCode=1000 TechnicalErrorString=closed_session_init_done.Metaplay/Clear menu item now has been redesigned, now features a sub menu with more options. Clear All option to clear credentials, offline state, language, and the game config cache.Clear Credentials menu item now clears all credential slots, including Unity's Multiplayer Play Mode credentials.EnableCompanyAccountClientIntegrations feature flag has been removed. Browser-based login plugins for Android and iOS are now included by default.ServerInitialGameConfigProvider.InitialArchiveBlob constructor no longer takes in the Archive version.SchemaMigrationRegistry, GameConfigRepository, LiveOpsEventTypeRegistry, ModelActionRepository, IAPSharedDelegateRegistry.entrypoint binary.DynamicEnum constructor no longer accepts isValid parameter and all values are considered to be valid.DynamicEnum value fields must now be public and readonly.Player.DebugConfig.ChecksumGranularity runtime option, controlling the checksumming rate of PlayerModel has been reduced. The default mode for non-local environments is now ChecksumGranularity.PerBatch, which roughly corresponds to 5 seconds worth of ticks or one action. For local environment, tick checksums are computed at most once per frame.CommitIdCheckRule from Environment Configs has been moved to server's Runtime Options, under ClientConnection:CommitIdCheckRule and set Disabled by default in all environments. See Commit ID Check for details.MetaSerializerTypeScanner no longer scans through all assemblies in runtime but uses only assemblies that are part of the IntegrationAssembly set that is resolved during the build using source generation.MetaplayFeatureEnabledConditionAttribute used for toggling various Metaplay features no longer works on the assembly level.DoNotBuildForDevices Environment Config flag has been removed. Instead, device builds targeting localhost host will be disallowed by default.DatabaseOptions.MaxConnectionsPerShard, is now automatically adjusted downwards on server startup to not exceed the maximum number of connections accepted by the database.AdminApiUseOpenIdConnectIdToken). Access tokens are now always used.GameConfigBuildUtil has been renamed to BackendAdminApi, and within it, the methods PublishGameConfigArchiveToServerAsync() and PublishLocalizationArchiveToServerAsync() to UploadGameConfigArchiveToServerAsync() and UploadLocalizationArchiveToServerAsync().GameConfigPublishPolicy has been removed from Unity project and Environment Configs. The values are now controlled on server Runtime Options UnityEditor:Allow{GameConfig,Localization}{Upload,Publish} flags.game_player_persisted_size and game_guild_persisted_size are now using more sensible bucket sizes.UseCustomLeagueSchedule has been changed to ScheduleType. Default value is RuntimeOptions, and Custom means the same as the old UseCustomLeagueSchedule option being true.DefaultEnvironmentConfigProvider are now non-virtual. If you want to customize the behavior, please reach out to us so we can figure out how to best cover your use case.Player:ModelSizeWarningThreshold to ClientConnection:PlayerModelSizeWarningThreshold.ClientConnection:PlayerModelSizeWarningThreshold is now initialized to 90% of ClientConnection.MaxCompressedPacketPayloadSize.MetaplayCoreOptions.ProjectId to separate the display name and ID from each other. See migration guide for details.TerminalError.ProjectNameMismatchError has been renamed to ProjectIdMismatchError, as it is now based on ProjectId and not ProjectName.FileUtil.Read to read files in StreamingAssets (i.e. from inside the APK file) now works from non-Unity threads too. This makes the behavior similar to other platforms.MonoBehaviour.OnApplicationPause(true) has been received or not.[BigQueryAnalyticsFormat(Ignore)] attribute can now be set on a subtype of a formatted type to ignore that particular subtype in formatting.PlayerModel.Language is now set for new players before experiments are evaluated.TypeScanner assembly scanning is now more accurate and no longer matches assemblies whose name starts with the name of an intentionally ignored assembly.MetaDatabase.InsertAsync() now throws ItemAlreadyExistsException if item already exists, instead of MySqlException or SqliteException.long, sbyte, byte, short, ushort, and uint fields not being written in BigQuery Analytics when AnalyticsSinkBigQuery.UseV2 Runtime Option was set.PlayerSetIsOnline if an earlier pending enqueued Server Action threw an exception.[PlayerDashboardAction] attribute layoutTargetId and layoutPosition parameters now work.EnvironmentConfig.Id is now an ID.Removing non-existent entity watch ... (no watchSet found for source) on server shutdown.__EFMigrationsHistory) uses the utf8mb4_bin collation, instead of database default collation. This improves compatibility of database snapshots between MySQL and MariaDB.UnityEngine.EntityId type have been resolved by using a file scope type alias for Metaplay.Core.EntityId.MModal now has a closeButtonDisabledTooltip prop to disable the modal close button and show a tooltip when hovered.MHorizontalDictionary component that displays key/value pairs in a horizontal grid layout.MetaAbbreviateNumber component has been removed and replaced with the MAbbreviateNumber component.MetaOrdinalNumber component has been removed. Use the toOrdinalString() utility function from the @metaplay/meta-utilities package instead.MetaBarChart component has been removed. Use the MPlot component instead.DefaultDashboard/public folder is now opted-out from Git LFS storage to avoid broken images due to LFS pointer files.MInputDurationOrEndDateTime durationTitle and dateTimeTitle props have been removed in favor of a single label prop that accepts both a duration and an end date/time label.MInputDurationOrEndDateTime for improved clarity and consistency.MInputSingleSelectDropdown component now correctly displays its placeholder text when no value is selected.MIconButtons danger variant now shows correctly as a muted red color when the component is disabled.MInputSingleSelectDropdown and MInputSingleSelectAsyncDropdown components was positioned too far below the input box, making it appear disconnected.MInputSingleSelectSwitch component now correctly updates its value when the modelValue prop changes.MInputSingleSelectSwitch component now behaves correctly when the disabledTooltip prop changes.GeneratedUiFormConfigLibraryKeyField.PurchaseHistoryCard loading time for players with a high volume of in-app purchases.MetricCard now avoids unnecessary data fetches when a user lacks permission.input component code samples have been re-written in pug for improved readability and copy/pasteability.There are no known issues in this release.
Please apply the following changes to your project to ensure compatibility with the latest Metaplay SDK.
Backward-Incompatible Changes
Bump your game's MetaplayCoreOptions.supportedLogicVersions to force a synchronized update of your game client and server.
The Metaplay SDK now requires Helm chart v0.9.0 or later for cloud deployments.
Migration Steps:
Update your metaplay-project.yaml to the latest Helm chart version.
serverChartVersion: 0.x.y
serverChartVersion: 0.9.0Roll out the change to each environment by running the CI job to build and deploy a new version.
You can do this for each environment separately, whenever is a good time for you.
Premium SDK Update Support
If your support contract includes Metaplay-provided SDK updates, all the following steps have already been applied to your project. You can skip this migration guide!
This guide offers step-by-step instructions for migrating your project to the latest version of the Metaplay SDK. You can skip the migrations steps for features you are not using in your project.
It's a good idea to run the Metaplay integration test suite on your project before and after upgrading to the latest SDK version.
MyProject$ metaplay test integrationYou should get a clean test run before starting the upgrade process to know that your project is in a good state, and know that any test failures after the upgrade are related to the upgrade itself.
The following core SDK changes affect all Metaplay projects:
A new property MetaplayCoreOptions.ProjectId was added. The ProjectId is used to uniquely identify the project in the Metaplay SDK and avoid accidentally having clients connect to the server from a different project. Previously, the MetaplayCoreOptions.ProjectName was used for this purpose, but was also used as a display name. You should set your ProjectId to be the same value as projectName used to have to avoid connection issues with your next game update!
From now on, MetaplayCoreOptions.ProjectName is used for display purposes only, mainly on the LiveOps Dashboard. You may freely give it any value you like.
Migration Steps:
Update your initialization of MetaplayCoreOptions to include projectId. Use the same value as projectName used to have!
public MetaplayCoreOptions Options { get; } = new MetaplayCoreOptions(
// ... Old comment no longer applies...
projectName: "MyProjectId",
// Unique project ID. DO NOT CHANGE!
projectId: "MyProjectId",
// Display name of project. You can now change this.
projectName: "MyProjectId",
...
);The following LiveOps Dashboard changes affect all Metaplay projects:
The MetaplaySDK/Frontend/DefaultDashboard/public is now opted-out from Git LFS (Large File Storage) to avoid the folder contents becoming LFS pointer files when pulled with the default git settings, as is common in CI systems.
Git LFS does not detect these changes automatically. If the files are tracked by Git LFS, the files need to be manually normalized to ensure LFS detects the change, and avoids converting them to the pointer files.
Migration Steps:
git add --renormalize MetaplaySDK/Frontend/DefaultDashboard/public/The following changes affect projects updating to Unity 6.2:
Unity 6.2 introduces type EntityId in the UnityEngine namespace in the Unity core assembly. This new type will conflict with the existing Metaplay SDK type Metaplay.Core.EntityId in any source files that have using statements both for UnityEngine and Metaplay.Core and that refers to the type EntityId without further namespace qualification, as the compiler will not be able to deduce which type is meant.
The options for resolving the ambiguous reference are:
Update references to the type to be fully qualified, i.e. change EntityId to Metaplay.Core.EntityId in source code files that are using both namespaces.
Add a file scope type alias for Metaplay.Core.EntityId in source code files that are using both namespaces. This option will not work if your code is also referring to UnityEngine.EntityId, in that case you will have to choose option 1 or invent another name for the type alias of one of the EntityId types.
using Metaplay.Core; // Metaplay.Core.EntityId
using UnityEngine; // UnityEngine.EntityId
using EntityId = Metaplay.Core.EntityId; The following LiveOps Dashboard changes affect projects that have a game-specific dashboard project:
As usual, we have updated the underlying dependencies and configurations of the LiveOps Dashboard. This causes changes to several configuration files, which you will need to update in your dashboard project. We use the MetaplaySDK/Frontend/DefaultDashboard folder as the source of truth for these files.
Migration Steps:
Update the package.json to update your project's dependencies.
package.json file directly from the MetaplaySDK/Frontend/DefaultDashboard directory. Next, restore the name property inside the file to that of your project. This is typically of the form "name": "<projectName>-dashboard".Copy and overwrite the following files:
vite.config.ts.gitattributesTo ensure that your dashboard project has the correct dependencies, you will need to clear the existing cached files and recreate them.
You should ensure that you have Node version 22.14.0 (the latest 22.x version at the time of writing) installed. To check the current version, run node --version. If you are using nvm, you can update Node with:
# Install Node 22.14.0 with Node Version Manager (nvm).
nvm install 22.14.0
# Use the new version.
nvm use 22.14.0Migration Steps:
git clean -fdx ':(glob)**/node_modules/*' from the root of your repository. This clears any currently installed dependencies.git clean -fdx ':(glob)**/dist/*' from the root of your repository. This clears any previously built files.pnpm-lock.yaml file from the root of your repository. This clears the cached dependency versions.pnpm install in your 'Dashboard' folder. This recreates all of the above files and folders with the correct dependencies.The Dashboard/public is now opted-out from Git LFS (Large File Storage) to avoid the folder contents becoming LFS pointer files when pulled with the default git settings, as is common in CI systems.
If your custom public folder is currently tracked by Git LFS, the files need to be manually normalized to ensure LFS detects the change and avoids converting them to pointer files.
Migration Steps:
git add --renormalize Dashboard/public/As a part of continued code review and polish of the dashboard codebase, we have done a few breaking changes to internal APIs that you may be using in your custom components.
MetaAbbreviateNumber to MAbbreviateNumberMetaAbbreviateNumber component has been removed and replaced with the MAbbreviateNumber component.Migration Steps:
Find all instances of the MetaAbbreviateNumber component and meta-abbreviate-number in your dashboard project.
Import the new MAbbreviateNumber component from the @metaplay/meta-ui-next.
import { MAbbreviateNumber } from '@metaplay/meta-ui-next'Replace all instances of MetaAbbreviateNumber and meta-abbreviate-number with MAbbreviateNumber in your code.
meta-abbreviate-number(:value="1234567890")
MAbbreviateNumber(:number="1234567890")MetaOrdinalNumber to toOrdinalString()The MetaOrdinalNumber component has been removed in favor of the toOrdinalString() utility function from the @metaplay/meta-utilities package.
Migration Steps:
Find all instances of the MetaOrdinalNumber component and meta-ordinal-number in your dashboard project.
Import the toOrdinalString utility function from the @metaplay/meta-utilities package.
import { toOrdinalString } from '@metaplay/meta-utilities'Replace the MetaOrdinalNumber and meta-ordinal-number with the toOrdinalString() function:
meta-ordinal-number(:value="1")
span {{ toOrdinalString(1) }} MInputDurationOrEndDateTime Props and SlotsThe MInputDurationOrEndDateTime durationTitle and dateTimeTitle props have been removed and replaced by a single label prop. The new label prop requires both duration and endDateTime labels to be provided.
Migration Steps:
MInputDurationOrEndDateTime in your project that include the label, durationTitle and/or dateTimeTitle props.label prop as follows:MInputDurationOrEndDateTime(
:model-value="duration"
:update:model-value="duration"
label="Example Duration"
duration-title="Example Duration"
dateTime-title="Example End Date Time"
:label="{ duration: 'Example Duration', endDateTime: 'Example End Date Time' }"
...
)The duration-hint-message slot has been renamed to duration-input-hint. The end-time-hint-message slot has been renamed to end-time-input-hint. The dateTime slot prop has been renamed to projectedEndDate. The duration slot prop has been renamed to projectedDuration.
Migration Steps:
MInputDurationOrEndDateTime component in your project that include the duration-hint-message and/or end-time-hint-message slots.MInputDurationOrEndDateTime(
:model-value="duration"
:update:model-value="duration"
)
template(#duration-hint-message="durationHintProps") This example will expire on {{ durationHintProps.dateTime }}.
template(#end-time-hint-message="endTimeHintProps") This example is valid until {{ endTimeHintProps.duration }}.
template(#duration-input-hint="{ projectedEndDate }") This example will expire on {{ projectedEndDate }}.
template(#end-time-input-hint="{ projectedDuration }") This example is valid until {{ projectedDuration }}. DefaultEnvironmentConfigProvider The methods and getters on DefaultEnvironmentConfigProvider are now non-virtual. The behavior of the class is so complicated that wholesale exposing of the internals is quite risky as inheriting code could easily break it in unexpected ways. If you want to customize the behavior, please reach out to us and describe your use case and we'll help you find a safe way to do so.
As a hot-fix, you can add the necessary virtuals back to the getters or methods that you need to be virtual. This way, you can proceed with upgrading Metaplay SDK while we work on a more permanent solution.
These changes affect you in case you happen to use any of the APIs changed. You can build your project to get a list of any incompatibilities instead of going through the list one item at a time.
BotClientBase.GenerateRandomPlayerName() and Other Name Generation Methods.To simplify BotClientBase.GenerateRandomPlayerName(), GenerateRandomGuildName(), and GenerateRandomGuildDescription(), they no longer take Random parameter.
Migration Steps:
Remove Random parameter from call-sites:
string playerName = GenerateRandomPlayerName(new Random());
string playerName = GenerateRandomPlayerName();
string guildDisplayName = GenerateRandomGuildName(random);
string guildDescription = GenerateRandomGuildDescription(random);
string guildDisplayName = GenerateRandomGuildName();
string guildDescription = GenerateRandomGuildDescription(); If BotClient overrides the default implementations, update the signatures:
protected override string GenerateRandomPlayerName(Random random)
protected override string GenerateRandomPlayerName()
{
}
protected override string GenerateRandomGuildName(Random random)
protected override string GenerateRandomGuildName()
{
}
protected override string GenerateRandomGuildDescription(Random random)
protected override string GenerateRandomGuildDescription()
{
}EnableCompanyAccountClientIntegrations Feature Flag.The feature flag for EnableCompanyAccountClientIntegrations has been removed and the login dependencies are now included in SDK by default.
Migration Steps:
Remove feature flag from MetaplayCoreOptions:
public class GlobalOptions : IMetaplayCoreOptionsProvider
{
public MetaplayCoreOptions Options { get; } = new MetaplayCoreOptions(
...
featureFlags: new MetaplayFeatureFlags
{
...
EnableCompanyAccountClientIntegrations = true
});
}Remove io.metaplay.unitysdk.androidcustomtabs package from Unity:
{
"dependencies": {
...
"io.metaplay.unitysdk.androidcustomtabs": "...",
}
}InitialArchiveBlob Constructor.ServerInitialGameConfigProvider.InitialArchiveBlob constructor no longer accepts the archive version. The version is deduced from the archive bytes.
Migration Steps:
Remove argument from new InitialArchiveBlob call sites:
new InitialArchiveBlob(
archiveVersion,
archiveBytes,
dataSource
...
);GameConfigEntryInfo Property Accesses.GameConfigEntryInfo's properties have been rearranged to avoid confusion and also due to changes in how the data is populated.
GameConfigEntryInfo's Name property has been renamed to the more explicit EntryName.MemberInfo is no longer readily available, but most of the useful information is now available directly, in members Type, DeclaringType, MemberName, GetEntry(), and SetEntry(). If you still need MemberInfo to access some other information, you can get it using ResolveMemberInfo(), but be aware that it involves reflection and can have significant cost if used a lot.Migration Steps:
If you get an obsoleted error about GameConfigEntryInfo.Name, access EntryName instead.
GameConfigEntryInfo entryInfo = ...;
string entryName = entryInfo.Name; // error CS0619: 'GameConfigEntryInfo.Name' is obsolete
string entryName = entryInfo.EntryName; If you get an obsoleted error about GameConfigEntryInfo.MemberInfo, instead access one of the other properties depending on what information you need, or call ResolveMemberInfo().
GameConfigEntryInfo entryInfo = ...;
// Member name is now directly available.
string memberName = entryInfo.MemberInfo.Name;
string memberName = entryInfo.MemberName;
// Less common data, like attributes, still need to come from the MemberInfo.
MyConfigAttribute attribute = entryInfo.MemberInfo.GetCustomAttribute<MyConfigAttribute>();
MyConfigAttribute attribute = entryInfo.ResolveMemberInfo().GetCustomAttribute<MyConfigAttribute>(); isValid Argument from DynamicEnum Constructors.Creation of DynamicEnums that are Invalid or Hidden are no longer supported. All enum values are now valid, and it is no longer necessary to mark the values as valid.
Migration Steps:
For each class inheriting DynamicEnum, remove isValid argument from constructor.
public class ExampleDynamicEnum : DynamicEnum<ExampleDynamicEnum>
{
public static readonly ExampleDynamicEnum Value0 = new ExampleDynamicEnum(0, "TestValue0");
public static readonly ExampleDynamicEnum Value1 = new ExampleDynamicEnum(1, "TestValue1");
protected ExampleDynamicEnum(int id, string name) : base(id, name, isValid: true)
protected ExampleDynamicEnum(int id, string name) : base(id, name)
{
}
}DynamicEnum Value Fields readonly.Value fields in a DynamicEnum are now required to be public, static and readonly. If a static field is found that is not public or readonly, compilation will fail.
Migration Steps:
Fix field declarations with compilation errors:
public class MyDynamicEnum : DynamicEnum<MyDynamicEnum>
{
static readonly MyDynamicEnum Value1 = new MyDynamicEnum(1, nameof(Value1)); // error MP_DEA_002: Invalid DynamicEnum field declaration
public static readonly MyDynamicEnum Value1 = new MyDynamicEnum(1, nameof(Value1));
public static MyDynamicEnum Value2 = new MyDynamicEnum(2, nameof(Value2)); // error MP_DEA_002: Invalid DynamicEnum field declaration
public static readonly MyDynamicEnum Value2 = new MyDynamicEnum(2, nameof(Value2));
public MyDynamicEnum(int id, string name) { ... }
}If a field is not intended to be an enum value, annotate it with [IgnoreDataMember] attribute:
public class MyDynamicEnum : DynamicEnum<MyDynamicEnum>
{
[IgnoreDataMember]
MyDynamicEnum _alternativeValue;
public MyDynamicEnum(int id, string name) { ... }
}CommitIdCheckRule into Runtime Options.CommitIdCheckRule has been removed from Client's Environment Configs and moved into server-side Runtime Options. If you have customized the rule, you must port the customizations to the Runtime Options.
The default value of CommitIdCheckRule is now Disabled on all environments. Note that in some development environments, CommitIdCheckRule defaulted to OnlyIfDefined. If you want to keep this value, you need to migrate the value manually. For more information on CommitIdCheckRule, see Commit ID Check.
Migration Steps:
ClientConnection:
# For CommitIdCheckRule.Disabled
CommitIdCheckRule: Disabled
# For CommitIdCheckRule.OnlyIfDefined
CommitIdCheckRule: OnlyIfDefined
# For CommitIdCheckRule.Strict
CommitIdCheckRule: StrictGameConfigPublishPolicy into Runtime Options.GameConfigPublishPolicy has been removed from Client's Environment Configs and moved into server-side Runtime Options. If you have customized the policy values, you must port the customizations to the Runtime Options.
The default values remain the same:
If Unity requires knowing whether it is allowed to publish, the policy can be fetched using the BackendAdminApi.FetchPublishPolicyAsync() API.
Migration Steps:
UnityEditor:
# For GameConfigPublishPolicy.NotAllowed
AllowGameConfigUpload: false
AllowLocalizationUpload: false
# For GameConfigPublishPolicy.UploadOnly
AllowGameConfigUpload: true
AllowGameConfigPublish: false
AllowLocalizationUpload: true
AllowLocalizationPublish: false
# For GameConfigPublishPolicy.AskForConfirmation
AllowGameConfigUpload: true
AllowGameConfigPublish: true
GameConfigPublishPrompt: "Are you sure you want to publish game config into <env>?"
AllowLocalizationUpload: true
AllowLocalizationPublish: true
LocalizationPublishPrompt: "Are you sure you want to publish game config into <env>?"
# For GameConfigPublishPolicy.Allowed
AllowGameConfigUpload: true
AllowGameConfigPublish: true
GameConfigPublishPrompt: ""
AllowLocalizationUpload: true
AllowLocalizationPublish: true
LocalizationPublishPrompt: ""GameConfigBuildUtil into BackendAdminApi.GameConfigBuildUtil has been renamed to BackendAdminApi in order to match the actual contents of the helper. BackendAdminApi provides API binding for the Backend Server's HTTP AdminAPI.
Additionally, the functions for publishing game configs and localizations have been changed. The confirmDialog boolean has been removed altogether, as the policy of requiring confirmation is now declared in server options (see the above migration note for GameConfigPublishPolicy).
Migration Steps:
Update references from GameConfigBuildUtil into BackendAdminApi:
... = await GameConfigBuildUtil.DownloadGameConfigAsync(...);
... = await BackendAdminApi.DownloadGameConfigAsync(...); Update calls to PublishGameConfigArchiveToServerAsync() to use UploadGameConfigArchiveToServerAsync() instead:
await GameConfigBuildUtil.PublishGameConfigArchiveToServerAsync(
await BackendAdminApi.UploadGameConfigArchiveToServerAsync(
adminApiBaseUrl,
configArchive,
authorizationToken,
confirmDialog,
setAsActive,
name,
description
new BackendAdminApi.GameConfigUploadOptions()
{
Name = name,
Description = description,
SetAsActive = setAsActive,
}
);Update calls to PublishLocalizationArchiveToServerAsync() to use UploadLocalizationArchiveToServerAsync() instead:
await GameConfigBuildUtil.PublishLocalizationArchiveToServerAsync(
await BackendAdminApi.UploadLocalizationArchiveToServerAsync(
adminApiBaseUrl,
configArchive,
authorizationToken,
confirmDialog,
name,
description
new BackendAdminApi.LocalizationUploadOptions()
{
Name = name,
Description = description,
SetAsActive = true
}
);UseCustomLeagueSchedule: true RuntimeOption to ScheduleType: Custom.If any of the league runtime options defines UseCustomLeagueSchedule: true, it should be changed to ScheduleType: Custom.
Migration Steps:
Change UseCustomLeagueSchedule: true to ScheduleType: Custom in Options.base.yaml:
MyLeague:
UseCustomLeagueSchedule: true
ScheduleType: CustomPlayer:ModelSizeWarningThreshold to ClientConnection:PlayerModelSizeWarningThresholdPlayer:ModelSizeWarningThreshold has been moved to ClientConnection:PlayerModelSizeWarningThreshold and is now initialized to be 90% of ClientConnection.MaxCompressedPacketPayloadSize.
Migration Steps:
Update runtime option usages of Player:ModelSizeWarningThreshold
Player:
ModelSizeWarningThreshold: ...
ClientConnection:
PlayerModelSizeWarningThreshold: ...Update C# usages of PlayerOptions.ModelSizeWarningThreshold
RuntimeOptionsRegistry.Instance.GetCurrent<PlayerOptions>().ModelSizeWarningThreshold;
RuntimeOptionsRegistry.Instance.GetCurrent<ClientConnectionOptions>().PlayerModelSizeWarningThreshold; ProjectNameMismatchError to ProjectIdMismatchErrorTerminalError.ProjectNameMismatchError has been renamed to ProjectIdMismatchError, because the detection is now based on ProjectId (in MetaplayCoreOptions) instead of ProjectName. If you have custom network error handling that refers to this error, it needs to be updated.
Migration Steps:
ProjectNameMismatchError references to ProjectIdMismatchError.ClientProjectName and ServerProjectName member references to ClientProjectId and ServerProjectId.MetaplayClientConnectionErrors.ProjectNameMismatch references to MetaplayClientConnectionErrors.ProjectIdMismatch.You should run the Metaplay integration test suite on your project after the SDK upgrade to make sure everything is still working as expected:
MyProject$ metaplay test integrationReleased on: September 18th, 2025
StreamingAssets resources to fail on WebGL. Most notably, accessing the builtin localization files fails, which prevents session start when the remembered initial language doesn't match the language stored in the player model.ProjectId in telemetry.FileUtil.ReadAllBytesAsync() returning null instead of throwing the expected IOException when accessing a missing file on the persisted IndexedDB filesystem.Released on: October 24th, 2025
Changed: Update Akka and Kubernetes to non-vulnerable versions.
Fixed: Fixed OOM failure in Unity IL2CPP release builds when SharedGameConfig or ServerGameConfig contained hundreds of libraries.
Fixed: Fixed the DailyCohortChart component showing empty data even when there was non-empty data.