Helpers for writing and reading lobby metadata keys used to track game runtime revision, staleness, migration targets, grace period end, and source lobby ID. Provides BuildLobbyMetadata to create the metadata dictionary and helpers IsLobbyOnCurrentRevision and IsLobbyStale to interpret those keys.
using System;
using System.Collections.Generic;
namespace Sandbox;
/// <summary>
/// Helpers for writing revision metadata to lobbies.
/// Call <see cref="NetworkStorage.BuildLobbyMetadata"/> when creating
/// a lobby to stamp revision tracking keys that other clients can
/// use to discover lobbies running the latest game version.
///
/// Key schema (short names for efficient network transfer):
/// ns_rev — RuntimeRevisionId (0 for editor/local sessions)
/// ns_stale — 1 if outdated, 0 if current
/// ns_grace_end — Grace period end unix timestamp, or 0
/// ns_mig — 1 if this lobby supports migration, 0 otherwise
/// ns_mig_rev — Migration target revision, or 0
/// ns_src — Source lobby ID (set when created via "Create New Game")
/// </summary>
public static partial class NetworkStorage
{
/// <summary>
/// Build a lobby metadata dictionary with revision tracking keys.
/// Pass the result to your lobby creation API (e.g. lobby.SetMetadata).
/// </summary>
/// <param name="migrationRevision">Target revision for migration, or null.</param>
/// <param name="sourceLobbyId">Previous lobby ID (for "Create New Game" flow), or null.</param>
public static Dictionary<string, string> BuildLobbyMetadata(
long? migrationRevision = null,
string sourceLobbyId = null )
{
var meta = new Dictionary<string, string>
{
["ns_rev"] = (NetworkStoragePackageInfo.RuntimeRevisionId ?? 0).ToString(),
["ns_stale"] = "0",
["ns_grace_end"] = "0",
["ns_mig"] = migrationRevision.HasValue ? "1" : "0",
["ns_mig_rev"] = (migrationRevision ?? 0).ToString(),
["ns_src"] = sourceLobbyId ?? "",
};
// If revision is outdated, set stale flag and grace end
if ( NetworkStoragePackageInfo.IsOutdatedRevision )
{
meta["ns_stale"] = "1";
}
if ( NetworkStoragePackageInfo.PolicyGracePeriodMinutes.HasValue )
{
var graceEnd = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
+ NetworkStoragePackageInfo.PolicyGracePeriodMinutes.Value * 60;
meta["ns_grace_end"] = graceEnd.ToString();
}
return meta;
}
/// <summary>
/// Check whether a lobby's metadata indicates it's running the
/// latest revision. Useful for filtering stale lobbies.
/// </summary>
public static bool IsLobbyOnCurrentRevision( Dictionary<string, string> metadata )
{
if ( metadata == null )
return true;
if ( !metadata.TryGetValue( "ns_rev", out var revStr ) || !long.TryParse( revStr, out var rev ) )
return true;
var current = NetworkStoragePackageInfo.RuntimeRevisionId;
if ( !current.HasValue )
return true;
return rev >= current.Value;
}
/// <summary>
/// Check whether a lobby's metadata says it's stale (outdated revision).
/// </summary>
public static bool IsLobbyStale( Dictionary<string, string> metadata )
{
if ( metadata == null )
return false;
return metadata.TryGetValue( "ns_stale", out var stale ) && stale == "1";
}
}