Game/ScoreUploader.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
/// <summary>
/// 成绩上传与全服榜读取(M5)。云端走 Sandbox.Services:
/// 上传 = Stats.SetValue("cr_match_mass", 本局总质量) + Flush;
/// 读取 = Leaderboards.GetFromStat 聚合 Max(全服最高单局)。
/// ⚠️ 未发布的本地包后端没有包身份,Refresh 内部吞 404(Entries 保持空)——
/// 展示层据此自动降级到 LocalBoard 的本地持久化榜。
/// </summary>
public static class ScoreUploader
{
/// <summary> 排行榜统计名(聚合 Max = 单局最高总质量) </summary>
public const string StatName = "cr_match_mass";
/// <summary> 本机成绩上云(按登录用户记账;拿不到本机球就静默跳过) </summary>
public static void SubmitOwn( ScoreWire[] standings, CircleroyaleGame game )
{
try
{
var local = game?.LocalBall;
if ( !local.IsValid() ) return;
var mass = game.TotalMassFor( local );
Sandbox.Services.Stats.SetValue( StatName, mass );
Sandbox.Services.Stats.Flush();
Log.Info( $"[score] uploaded {mass:0} ({StatName})" );
}
catch ( Exception e )
{
Log.Info( $"[score] upload failed: {e.Message}" );
}
}
/// <summary> 拉全服榜 Top10(异步;空/失败回调 null——展示层降级本地榜) </summary>
public static async void FetchGlobal( Action<List<( string Name, float Mass )>> done )
{
try
{
var board = Sandbox.Services.Leaderboards.GetFromStat( StatName );
board.SetAggregationMax();
board.SetSortDescending();
board.FilterByNone();
board.MaxEntries = 10;
await board.Refresh();
var list = new List<( string Name, float Mass )>();
foreach ( var e in board.Entries )
list.Add( ( e.DisplayName, (float)e.Value ) );
done( list.Count > 0 ? list : null );
}
catch ( Exception e )
{
Log.Info( $"[score] global board fetch failed: {e.Message}" );
done( null );
}
}
}