身份与档案
身份与档案
CrossingPlayerId 怎么来、Guest 与团队账号怎么切、档案块怎么存与传、Elo 与赛季怎么算。
插件不接管登录。它只做两件事:在服务端给每个连接一个稳定身份,以及把这个身份的数据块存取好。 账号密码、注册、防沉迷这些在项目自己的登录层。
身份
连接 → PostLogin → UCrossingIdentitySubsystem 分配 FGuid CrossingPlayerId
→ 写进 ACrossingPlayerState → 复制到客户端CrossingPlayerId是 GUID,由服务端生成,客户端不能自报- 不依赖 OnlineSubsystem;无 OSS 时
UniqueId无效,插件不碰它 - 身份来源由
ICrossingAuthProvider决定
Guest 与团队账号
; 登录提供者
AuthProviderName=Guest| Provider | 行为 |
|---|---|
Guest | 默认;每个连接分配一个 Guest 身份,不需要登录 |
| 自定义 | 实现 ICrossingAuthProvider 并注册,例如接入团队 SDK |
卫星插件 CrossingNetAuthDemo 是最小示例:注册一个 Demo 身份,并且拒绝非 Guest 自报 ID——
这条是安全边界:如果身份由客户端说,等于没有身份。
// 伪代码:注册一个 provider
Identity->SetAuthProvider(MakeShared<FMyAuthProvider>());PlayerState
ACrossingPlayerState 复制给所有客户端:
| 字段 | 用途 |
|---|---|
CrossingPlayerId | 跨进程稳定的身份 |
CrossingTraceId | 这一局的 trace(房间写入) |
CrossingTeamId | 队伍号 |
CrossingRating | Elo(可空) |
MatchStats | 本局统计(服务端使用) |
档案
UCrossingProfileSubsystem 管「按下标存的数据块」:
Profile
├─ 块(Block):名字 + UScriptStruct + SchemaVersion
│ ├─ Basic 基础资料
│ ├─ Rating Elo
│ ├─ History 战绩
│ └─ Season 赛季
└─ 存储(Store):默认 File,可替换注册块
Profile->RegisterBlock(TEXT("Basic"), FMyBasicBlock::StaticStruct(), /*SchemaVersion=*/1, /*bRequiredAtLogin=*/true);bRequiredAtLogin=true 时,块缺失或版本过旧会让登录流程失败(5005 ProfileVersionMismatch),
避免「带着空档案进对局」。
分块传输
块可能很大,客户端拉取走分块:
; 单块上限 256 KB
ProfileMaxBlockBytes=262144
; 每包字节
ProfileChunkBytes=6000
; 档案分块超时(秒)
ProfileChunkTimeoutSeconds=10.0
; 档案最大重试
ProfileMaxRetries=3对应错误码:5001 MessageTooLarge、5002 DataCorrupt、5003 ChunkFailed、5004 ChunkTimeout。
存储
| 项 | 默认 | 说明 |
|---|---|---|
bPersistProfiles(持久化档案) | true | 是否落盘 |
ProfileStoreName(档案存储) | File | 存储后端;可 RegisterStoreFactory 替换 |
bPersistGuestIdentity(持久化游客身份) | true | Guest 身份是否持久化 |
File 后端写 <Project>/Saved/CrossingNet/ 下,原子替换。
Elo
; 启用定级
bEnableRating=True
; 定级 K
RatingK=32.0
; 定级 K 值
ProvisionalK=40.0
; 定级场次
ProvisionalMatches=10
; 最低 Elo
MinElo=100
; Bot 影响 Elo
bBotsAffectElo=False
; 平局影响定级
bDrawAffectsRating=True
; 逃跑影响定级
bForfeitAffectsRating=True
; 逃跑额外 Elo 惩罚
ForfeitExtraEloPenalty=0.0
; 胜利系数
WinMultiplier=1.0
; 失败系数
LossMultiplier=1.0
; 定级规则
RatingRuleName=Elo- 前
ProvisionalMatches局用ProvisionalK(升/降更快) bBotsAffectElo=false:打 Bot 不计分(常见做法)- 评分规则可换:
CrossingRating::RegisterRule注册自定义ICrossingRatingRule
结算后写回档案(ApplyRating),同时追加一条战绩。
战绩
FCrossingMatchRecord Record;
Record.MatchId = MatchId;
Record.Result = ECrossingPlayerOutcome::Win;
Profile->AppendMatchHistory(PlayerId, Record);
TArray<FCrossingMatchRecord> Recent;
Profile->GetMatchHistory(PlayerId, /*MaxCount=*/10, Recent);事件:OnProfileUpdated。
赛季
; 启用赛季滚动
bEnableSeasonReset=True
; 当前赛季 ID
CurrentSeasonId=1
; 赛季软重置系数
SeasonResetSoftFactor=0.5
; 启用赛季衰减
bEnableSeasonDecay=True
; 赛季衰减起始天数
SeasonDecayAfterDays=14
; 赛季每日衰减
SeasonDecayPointsPerDay=10
; 赛季衰减上限
SeasonDecayMaxElo=200- 赛季滚动时把 Elo 按
SeasonResetSoftFactor软化 - 超过
SeasonDecayAfterDays没打开始衰减,每天SeasonDecayPointsPerDay,上限SeasonDecayMaxElo - 查询:
GetSeasonSummary/GetSeasonHistory;事件OnSeasonChanged
已知限制:定级场次仍用 lifetime Matches,未按赛季独立计数。
行为分
bEnableBehaviorScore=True
BehaviorStartScore=100ApplyBehaviorPenalty(PlayerId, Amount, bLeaver, Reason) 在离队、AFK 判定时扣分;
行为分可作为匹配维度使用。
已知边界
| 项 | 现状 |
|---|---|
| 账号系统 | 不在插件内,由项目登录层提供 |
| 排行榜 / 最高段位 | 未做 |
| MatchStats 复制 | 只服务端使用,记分板要项目自建 |
| 赛季独立场次 | 未按赛季计数 |
下一页:局域网开房。