Jump/JumpScores.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
/// <summary>
/// 成绩记录:本地排行榜(FileSystem.Data 持久化,始终可用)
/// + 官方云端排行榜(Sandbox.Services 的 Stats/Leaderboards,尽力而为——
/// 包未发布/离线时后端没有身份,拿不到数据就静默降级为纯本地)。
/// </summary>
public static class JumpScores
{
const string SaveFile = "jump_scores.json";
const int MaxKeep = 30;
/// <summary> 一条本地成绩 </summary>
public class ScoreEntry
{
public int Score { get; set; }
public int Difficulty { get; set; } // 0 简单 1 容易 2 困难
public string Date { get; set; } = "";
}
static List<ScoreEntry> _scores = new();
static bool _loaded;
/// <summary> 云端排行榜条目(RefreshCloud 成功后填充) </summary>
public static List<(long Rank, string Name, int Score)> Cloud { get; } = new();
/// <summary> 云端排行榜是否成功拉取过 </summary>
public static bool CloudLoaded { get; private set; }
static JumpScores()
{
Load();
}
static void Load()
{
if ( _loaded ) return;
try
{
// 编辑器早期(编辑模式/场景加载中)FileSystem.Data 还没就绪会抛 NRE,
// 此时不能把 _loaded 置位,留给游戏运行期间的下次调用重试
if ( FileSystem.Data is null ) return;
if ( FileSystem.Data.FileExists( SaveFile ) )
{
_scores = Json.Deserialize<List<ScoreEntry>>( FileSystem.Data.ReadAllText( SaveFile ) ) ?? new List<ScoreEntry>();
}
_loaded = true;
}
catch ( Exception e )
{
Log.Warning( $"JumpScores load: {e.Message}" );
}
}
/// <summary> 历史最高分 </summary>
public static int Best => _scores.Count > 0 ? _scores[0].Score : 0;
/// <summary> 本地前 N 名(降序,全难度) </summary>
public static List<ScoreEntry> Top( int count )
{
Load();
return _scores.Take( count ).ToList();
}
/// <summary> 指定难度的本地前 N 名(降序) </summary>
public static List<ScoreEntry> Top( int count, JumpDifficulty difficulty )
{
Load();
return _scores.Where( x => x.Difficulty == (int)difficulty ).Take( count ).ToList();
}
/// <summary> 局终记录成绩(云端上报顺带触发) </summary>
public static void Record( int score, JumpDifficulty difficulty )
{
if ( score <= 0 ) return;
Load();
_scores.Add( new ScoreEntry { Score = score, Difficulty = (int)difficulty, Date = DateTime.Now.ToString( "MM-dd" ) } );
_scores = _scores.OrderByDescending( x => x.Score ).Take( MaxKeep ).ToList();
Save();
SubmitCloud( score, difficulty );
}
static void Save()
{
try
{
FileSystem.Data.WriteAllText( SaveFile, Json.Serialize( _scores ) );
}
catch ( Exception e )
{
Log.Warning( $"JumpScores save: {e.Message}" );
}
}
// ---- 云端(官方 Services,尽力而为)----
/// <summary> 上报成绩到官方云端(打包发布后生效;本地开发包可能没有后端身份) </summary>
public static void SubmitCloud( int score, JumpDifficulty difficulty )
{
try
{
Sandbox.Services.Stats.SetValue( "best_score", score, new Dictionary<string, object>
{
{ "difficulty", difficulty.ToString() }
} );
_ = FlushAndReloadCloud();
}
catch ( Exception e )
{
Log.Warning( $"JumpScores cloud submit: {e.Message}" );
}
}
/// <summary> 拉取云端排行榜(聚合 = 每人历史最高分,降序) </summary>
public static async Task RefreshCloud()
{
try
{
var board = Sandbox.Services.Leaderboards.GetFromStat( "best_score" );
board.SetAggregationMax();
board.MaxEntries = 10;
await board.Refresh();
Cloud.Clear();
foreach ( var e in board.Entries )
{
Cloud.Add( ( e.Rank, e.DisplayName ?? "???", (int)e.Value ) );
}
CloudLoaded = true;
}
catch ( Exception )
{
// 本地包 / 离线:云端不可用,静默降级为纯本地排行
}
}
static async Task FlushAndReloadCloud()
{
await Sandbox.Services.Stats.FlushAsync();
await RefreshCloud();
}
}