Appearance
Release 25
November 14th, 2023
Appearance
November 14th, 2023
New feature: Localizations are now first-class citizens in the LiveOps Dashboard. You can now view localization builds and push them out as OTA updates to clients from the dashboard.

New feature: Environment Configs are a new way to define your client-side environment-specific configurations as a JSON file with full Unity editor support, better CI support and more. See Release 25 Environment Configs Migration Guide for more information.

Major improvement: Game Config Parsing from spreadsheets now supports nested members, vertical collections, and combinations of the two. With these, you can directly parse things like arrays of classes without needing to use source transforms. See Working with Game Config Data for more information.
Major improvement: Game Config Building is now enabled by default in the LiveOps Dashboard. You can see the history of config builds and the results of config validation straight from the dashboard and there's a new form for customizing how the config build is triggered.

Major improvement: Game Config Source Data Fetching Game config building now natively supports multiple data sources as well as adding your own types of data sources. This can be a useful tool for optimizing your config workflows!
INFO
Note: ✨ This release has seen a lot of work in the game configs and localizations pipeline and we are not done yet! We will continue iterating on and polishing these new features in the next release ✨
MetaplayCoreOptions.supportedLogicVersions to force a synchronized update of your game client and server.bootstrap-vue to MetaUiNext we have removed the following dashboard components: b-tooltip - Use MTooltip instead.b-badge - Use MBadge instead.dotnet ef migrations add MetaplayRelease25 in your Backend/Server folder and commit the updated files in 'Migrations/'.INFO
Note: If you have a service contract signed with Metaplay, the breaking changes outside the list above have been fixed already in the SDK upgrade pull request of your project. Otherwise, please see CHANGELOG.md for a full list of changes, along with the HelloWorld and Idler samples for references on how to apply the changes.
We recommend upgrading to the latest versions of the infrastructure and game server Helm chart:
infra-modules v0.2.10. metaplay-gameserver v0.5.0. The minimum required versions are infra-modules v0.2.2 and metaplay-gameserver v0.4.4.

MetaEventStreamCard component has new properties to both set and freeze the filters to easily create cards that show a specific subset of all the events. The filters are also OR instead of AND to make it easier to create very narrow filters. 
MErrorCallout component provides a consistent and user-friendly way to report and share both technical and non-technical errors throughout the LiveOps dashboard. 

MBadge - A colored box/pill to highlight information. Replaces b-badge.MTooltip - A utility to show tooltips. Replaces b-tooltip.MErrorCallout - A specialized callout to display technical errors.add<listName>OverviewListItem and the addUiComponent integration APIs have been extended to support the ability to hide specific list-items and/or UI components on your dashboard based on user permissions. See Customizing the LiveOps Dashboard Frontend for more details.useSubscription function instead of the previous useStaticSubscription/useDynamicSubscription pair. Check the Working with Subscriptions documentation for how to migrate your code.Tuple, ValueTuple, DateTimeOffset, Version, Guid, TimeSpan, ReadOnlyCollection<T>, and ReadOnlyDictionary<Key, Value> in MetaSerialized types.MetaMembers and add the MetaDeserializationConstructor attribute.F32, F64, and the vector variants) ToString() and Parse() now have robust implementations. The conversion from fixed-point to string and back is guaranteed to produce the original fixed-point value. The methods are also deterministic.FileUtil methods uses sharing options that makes it work even if the file is opened in an editor. This is useful for example if importing game configs from .csv files while they are open in Excel for editing.IGameConfigData<>. Reference resolving will look for the item in each library whose item type is compatible with the reference.x64 or ARM64 platforms but use the Any CPU that works well with either target.Hidden and ServerOnly MetaMember flags for stripping data from the client visible config. The "full protocol server hash" does not include these items so that they don't cause spurious hash mismatches between the client and the server.SharedGameConfigBase and ServerGameConfigBase no longer contain entries for the SDK side config libraries (Languages, InAppProducts, PlayerSegments, Offers, OfferGroups, PlayerExperiments) and these entries have been made optional. This removes the need of declaring game config builds (and associated sheets) for features that are not being used.ConfigArchives and ConfigArchiveEntrys, we've refactored ConfigArchive to be read-only and it is now decompressed on load.ExportEntityHandler and ImportEntityHandler are Obsolete. ImportEntityHandler should inherit SimpleImportEntityHandler instead.MultiplayerEntityClientContext constructor now takes ClientMultiplayerEntityContextInitArgs. MultiplayerEntityClientBase.DefaultInitArgs and pass it into the constructor.F32/F64 methods ToString() and Parse() have been rewritten to be deterministic and faster, but the outputs are not identical to the earlier releases. This applies parsing fixed-point values during game config building as well. SharedGameConfigBase and ServerGameConfigBase have been refactored to make SDK side config libraries (Languages, InAppProducts, PlayerSegments, Offers, OfferGroups, PlayerExperiments) optional and to not require specifying custom info classes for the SDK libraries via template parameters. The old base classes have been preserved with Legacy prefix to aid in the migration. SharedGameConfigBase and ServerGameConfigBase derived classes and tag the entries with GameConfigEntryAttribute. Alternatively you can switch the base class to the Legacy variants to retain the old behavior of having the entries declared on the SDK side.PersistedParticipantDivisionAssociation has a new field LeagueStateRevision to help restore the league's state in case of shutdowns and crashes. ConfigArchive has been refactored to be read-only to reduce unnecessary copies of the data, ConfigArchiveEntrys are now decompressed on load. ConfigArchiveEntry.Uncompress() and ConfigArchiveEntry.RawBytes with ConfigArchive.GetEntryBytes() or ConfigArchiveEntry.Bytes.LocalizationStorageFormat and LocalizationStorageFormat.LegacyCsv. The binary format is now always assumed. LocalizationStorageFormat and the legacy format from your code.MetaPlayerReward.Consume now takes the IRewardSource parameter. MetaPlayerReward.InvokeConsume is now sealed and exists only as a helper to call Consume with the concrete PlayerModel type instead of IPlayerModelBase. Consume overrides to take the IRewardSource parameter. Also, change your existing InvokeConsume overrides to be Consume overrides instead.IMetaplayClientSocialAuthenticationDelegate in your client code: Add an implementation of OnSocialAuthenticationConflictWithFailingOtherPlayer. The minimal implementation can be empty (though logging an error is recommended), but ideally the error should be communicated to the user, with the option of contacting customer support. See the comments in IMetaplayClientSocialAuthenticationDelegate for more information.SocialAuthenticateResult directly in your client code: Member ConflictingPlayer has been renamed to ConflictingPlayerIfAvailable, and ConflictingPlayerId has been added. Unlike before, ConflictingPlayerIfAvailable can now deserialize to null even if there was a conflict. The presence of a conflict is now determined by checking if ConflictingPlayerId is available (i.e. is not EntityId.None). Therefore the new case you will need to handle is that where ConflictingPlayerIfAvailable deserializes to null yet ConflictingPlayerId is available. You should handle this case in the same way as described above for IMetaplayClientSocialAuthenticationDelegate.OnSocialAuthenticationConflictWithFailingOtherPlayer.ConfigParser's method TryGetParseFunc() has been replaced with TryParse(). ConfigParser.TryGetParseFunc() should be changed according to the use case: TryGetParseFunc() immediately followed by a call to the returned parse func should be replaced by a call to TryParse() instead.TryGetParseFunc() made for the purpose of checking if a custom parse func has already been registered should be replaced with a call to HasRegisteredParseFunc().TryGetParseFunc() are unlikely to exist, but if they do then they need to be considered case by case.PersistedMultiplayerEntityActorBase, TimeSpan TickUpdateInterval is replaced with TickRateSetting TickRate and has a new default behavior. TickUpdateInterval, convert it into TickRate. See TickRateSetting constructor for details.TickUpdateInterval, the actor now by default uses the Model's tick rate when there is an ongoing Session. This may significantly increase the tick execution rate. To keep the previous tick rate, set TickRate to new TickRateSetting(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)).GameConfigBuilderServices has been removed in favor of the new Game Config build sources system. Integrations need to update to specifying the config build sources using in the GameConfigBuildParameters input parameter and configuring source fetchers with the IGameConfigSourceFetcherConfig input parameter. ConfigArchive.FromBytes(), ConfigArchive.GetEntryBytes(), and ConfigArchiveEntry.Bytes APIs have been updated to use Memory<byte>, please update usages.ReadOnlyConfigArchive with ConfigArchive.ConfigArchive.ToBytes() calls with ConfigArchiveBuildUtility.ToBytes().FolderEncoding is now a child class or ConfigArchiveBuildUtility.ConfigArchive.WriteToFile() with ConfigArchiveBuildUtility.WriteToFile().IConfigArchive and IConfigArchiveEntry interfaces with ConfigArchive and ConfigArchiveEntry.GoogleSheets:GameConfigSheetId has been removed in favor of the new Game Config build sources system. Integrations should now specify the available source spreadsheets by deriving from GameConfigBuildIntegration and overriding its GetAllAvailableBuildSources. GoogleSheets:GameConfigSheetId from your runtime option yaml files. Refer to the Release 25 game configs migration guide to update existing build pipeline configuration.MetaplayClientOptions and MetaplaySDKConfig have been refactored and several options including ServerEndpoint are moved to the new EnvironmentConfig class. METAPLAY_UNITY_DEFINES override file has been removed. METAPLAY_ACTIVE_ENVIRONMENT_ID environment variable, or -MetaplayActiveEnvironmentId env command line parameter.StartSession doesn't need to be called and is removed. StartSession.b-tooltip has been removed in favor the newer MTooltip component. b-tooltip with MTooltip in your Vue components.b-badge has been removed in favor the newer MBadge component. b-badge with MBadge in your Vue components.MetaApiErrorAlert has been removed and replaced with the MErrorCallout component. MetaApiErrorAlert with MErrorCallout in your Vue components.IPlayerModelBase.UpdateTimeZone() method to allow restricting player time zone changes. Sample implementation is included in the Idler sample.MetaRef in a game config item.MetaSerializableFlags.AutomaticConstructorDetection to [MetaSerializable] or by add the [MetaDeserializationConstructor] attribute to your constructor.Tuple and ValueTuple up to 7 elements. MetaSerializableFlags.ImplicitMembers.Tuple and ValueTuple are compatible with a class and a struct respectively, meaning you can change the Tuple/ValueTuple to an instance of a class/struct provided you keep the same TagId order of the members.DateTimeOffset, Version, Guid, TimeSpan, ReadOnlyCollection<T>, and ReadOnlyDictionary<Key, Value>.[BigQueryAnalyticsName("...")] and [FirebaseAnalyticsName("...")] attributes for overriding the name of an analytics event or a parameter in an analytics event, which would by default be determined by the C# class or member name.IGameConfigData<>. Reference resolving will look for the item in each library whose item type is compatible with the reference.LeagueManagerOptions.AllowDivisionBackFill option to turn off division backfilling when removing a participant from a division.LeagueManagerOptions.ConcludeSeasonMaxDelayMilliseconds option to introduce a delay to divisions concluding.GameConfigBuildParameters.IGameConfigSourceFetcher system for implementing fetching of game config source data, and SDK implementations of google sheets and local file fetching.GameConfigBuildIntegration to encapsulate various extension points related to game config building.configBuildSource parameter to GameConfigEntryAttribute for specifying the used game config build source per entry.ServerOptions.EnvironmentConfig system and the DefaultEnvironmentConfigProvider that replaces the Idler sample's DeploymentConfig and similar systems in other samples. Refer to the Release 25 environment configs migration guide for more information on migrating to the new system, or implementing a simpler minimal integration.MErrorCallout component, you can now display both technical and non-technical errors in a consistent and user-friendly way.LeagueDetailView now has a migration progress indicator during preview phase using new MProgressBar component.MetaEventStreamCard component has hew properties to both set and freeze the filters to easily create cards that show a specific subset of all the events.LiveOpsDashboard.DashboardHeaderColorInHex and LiveOpsDashboard.DashboardHeaderLightTextColor runtime options to customize the dashboard header color and text color in your environments.MetaUiNext components. Run pnpm storybook in the MetaplaySDK/NodePackages/MetaUiNext folder to see the components in action. MBadge - A colored box/pill to highlight information. Replaces b-badge.MTooltip - A utility to show tooltips.MInputSingleSelectDropdown - A minimalistic select input for string values.MInputSingleCheckbox - A single checkbox input for boolean values.MInputTextArea - A textarea input for string values.MErrorCallout - A specialized callout to display technical errors.add<listName>OverviewListItem and the addUiComponent have been extened to support hiding of overview list items and UI placement components based a user's permissions.3.3.4 to avoid withDefault boolean type bug with vue bootstrap.PlayerModel or other ISchemaMigratable classes to have extraneous [MigrationFromVersion(fromVersion: x)] methods where fromVersion is outside the range specified in the [SupportedSchemaVersions(...)] attribute. This is intended to guard against mistakes in the specified version range.GameConfigBase.OnConfigEntriesPopulated().GlobalState with game-specific data via introducing a game side implementation of GlobalStateManager.IAPManager to use the IDetailedStoreListener interface added in Unity Purchasing 4.8.0 when available. This fixed a warning about an obsoleted UnityPurchasing method.Hidden and ServerOnly MetaMember flags for stripping data from the client visible config.IMetaActivableConfigData fields are now conditionally compiled for server only, which allows implementations to omit them from client visible config data.MetaMemberFlags.Hidden or MetaMemberFlags.ServerOnly. This allows hidden and server-only flags to be conditionally compiled only in server builds without resulting in compatibility warnings during the login handshake.SharedGameConfig.OnLoaded and is likely only worthwhile during development, not during live operation.sock_diag instead of /proc/net/tcp for reduced overhead.ISharedGameConfig and IServerGameConfig) are no longer required to contain config library entries associated with SDK features. Runtime stub libraries are exposed via the base class implementation when no concrete entry is declared by the game integration config class. Additionally the following uses of SDK config libraries have been updated: SystemStatusController is now augmented with stub data when no config entry exists.ContentHash.None for the ability to refer to an empty archive separately from a missing archive.GameConfigBase.ArchiveVersion. With the introduction of ServerOnly game config data the game config content hash is no longer the same for server and client, and therefore relying on the ArchiveVersion property of the in-memory game config is prone to error.IEnumerable types as collections.metaplay_in_maintenance gauge which has the value of 1 when the game server is in maintenance.game_entity_ask_duration and game_entity_asks_total metrics. This allows identifying which SubscribeToAsync() call is causing elevated metrics.MetaUsername component no longer needs URL or permissions to be passed in.SegmentDetailView, OfferGroupDetailView, OfferDetailView, ActivableDetailView now using single endpoint subscription instead of deconstructing all endpoint data.useStaticSubscription and useDynamicSubscription are now deprecated. Update all callsites to use the new useSubscription API instead. Check the "Working with Subscriptions" documentation for how to do this.MErrorCallout component, you can now display and share both technical and non-technical error information in a consistent and user-friendly way.GameConfigBuildIntegration.GetAvailableBuildSources.dotnet build. Previously, the build could fail with error CS2012: Cannot open ... for writing.model.CurrentTime now has a valid value (instead of epoch) already during model schema migrations. This applies to players, guilds, and multiplayer entities such as divisions. This also fixes the PlayerEventModelSchemaMigrated and GuildEventModelSchemaMigrated analytics events having an invalid timestamp and thus being rejected from BigQuery.ToString() methods now produce deterministic string outputs that can be parsed to the original value losslessly. The output is also the shortest such string for better human readability.Parse() methods now handle rounding properly to achieve lossless fixed->string->fixed conversions.Symlink Sources build setting was enabled.FileUtil methods now allows the file to be open in other applications. This is done by opening the file with the FileAccess.Read and FileShare.ReadWrite flags.ConfigParser can now parse all StringId<>, enum, and Nullable<> types (assuming the Nullable<>'s underlying type is parseable), regardless of whether those types appear as key types in GameConfigLibrary<,>s.fetchSubscriptionDataOnceOnly could hang forever if the requested endpoint returned no data.