Appearance
Appearance
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.MetaMember
s 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.ConfigArchive
s and ConfigArchiveEntry
s, 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, ConfigArchiveEntry
s 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.