Skip to Content
CrossingNet
身份与档案

身份与档案

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队伍号
CrossingRatingElo(可空)
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(持久化游客身份)trueGuest 身份是否持久化

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=100

ApplyBehaviorPenalty(PlayerId, Amount, bLeaver, Reason) 在离队、AFK 判定时扣分; 行为分可作为匹配维度使用。

已知边界

项现状
账号系统不在插件内,由项目登录层提供
排行榜 / 最高段位未做
MatchStats 复制只服务端使用,记分板要项目自建
赛季独立场次未按赛季计数

下一页:局域网开房。

On this page