Core/NetworkStorageLobbyMetadata.cs
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";
	}
}