fix(framework): player_login.version 改为数字 versionCode(联调登录成功)

真机联调发现:协议 version 字段=数字 versionCode(源码 8 处 data.version=GameData.versionCode),
框架原发字符串 '1.1' 被服务器版本校验拒绝(kick_server 检查到新版本)。改为数字后登录成功
(state:0 playerid:430511)。
- ChannelIdentity/LoginRequestData.version: string→number,去掉冗余 versionCode 与未发送的 '1.1' 串
- query-string version 解析为数字;测试 fixture 同步

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 20:33:53 +08:00
co-authored by Claude Opus 4.8
parent fee5c8b0a0
commit ad661707ec
11 changed files with 12 additions and 15 deletions
@@ -4,8 +4,7 @@ export interface ChannelIdentity {
channelid: string | number;
gameid: string;
marketid: string | number;
version: string; // 旧 GameData.Version
versionCode: number; // 旧 GameData.versionCode
version: number; // 协议 player_login.version 字段 = 数字 versionCode(非 "1.1" 显示串,逐字对齐源码 data.version=GameData.versionCode)
}
/** 身份来源:返回部分字段覆盖。 */
@@ -9,6 +9,5 @@ export const BUILD_IDENTITY: ChannelIdentity = {
channelid: 'FtJf073aa0d6rI1xD8J1Y42fINTm0ziK',
gameid: 'jzWe0kzmN0tAcZ5MLks3rFWcxNecogyu',
marketid: 4,
version: '1.1',
versionCode: 10000,
version: 10000, // 数字 versionCode(联调时改成本地服要求的版本号)
};
@@ -8,7 +8,7 @@ export function queryStringSource(search: string): IdentitySource {
const agentid = q.get('agentid'); if (agentid) out.agentid = agentid;
const channelid = q.get('channelid'); if (channelid) out.channelid = channelid;
const marketid = q.get('marketid'); if (marketid) out.marketid = marketid;
const version = q.get('version'); if (version) out.version = version;
const version = q.get('version'); if (version) out.version = Number(version); // 协议 version 为数字
return out;
};
}
@@ -12,7 +12,7 @@ export interface LoginRequestData {
province: string;
city: string;
unionid: string | number;
version: string;
version: number; // 数字 versionCode(源码 data.version=GameData.versionCode)
channelid: number | string;
marketid: number | string;
[extra: string]: unknown; // location/ip/machineid/telphone 等由 Send_login 注入,见 docs/protocol/01 §6
@@ -8,8 +8,7 @@ test('BUILD_IDENTITY 含全部字段且 gameid 为固定 token', () => {
assert.ok('agentid' in BUILD_IDENTITY);
assert.ok('channelid' in BUILD_IDENTITY);
assert.ok('marketid' in BUILD_IDENTITY);
assert.equal(typeof BUILD_IDENTITY.version, 'string');
assert.equal(typeof BUILD_IDENTITY.versionCode, 'number');
assert.equal(typeof BUILD_IDENTITY.version, 'number'); // 协议 version = 数字 versionCode
});
test('resolveIdentity:后面的 source 覆盖前面的', () => {
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
import { getParam, resolveServers, type RemoteConfig } from '../../YouleNexus/assets/framework/config/remote-config.ts';
import type { ChannelIdentity } from '../../YouleNexus/assets/framework/config/identity.ts';
const ID: ChannelIdentity = { agentid: 'A', channelid: 'C', gameid: 'G', marketid: 2, version: '1', versionCode: 1 };
const ID: ChannelIdentity = { agentid: 'A', channelid: 'C', gameid: 'G', marketid: 2, version: 1 };
const CONFIG: RemoteConfig = {
data: {
@@ -3,8 +3,8 @@ import assert from 'node:assert/strict';
import { queryStringSource } from '../../../YouleNexus/assets/framework/config/sources/query-string.ts';
test('解析 agentid/channelid/marketid/version', () => {
const src = queryStringSource('?agentid=A1&channelid=C1&marketid=2&version=9.9');
assert.deepEqual(src(), { agentid: 'A1', channelid: 'C1', marketid: '2', version: '9.9' });
const src = queryStringSource('?agentid=A1&channelid=C1&marketid=2&version=10001');
assert.deepEqual(src(), { agentid: 'A1', channelid: 'C1', marketid: '2', version: 10001 }); // version 解析为数字
});
test('缺省键不出现在结果里', () => {
@@ -3,7 +3,7 @@ import type { LoginRequestData, LoginResponseData } from '../../YouleNexus/asset
const out: OutboundEnvelope<LoginRequestData> = {
app: 'youle', route: 'agent', rpc: 'player_login',
data: { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 0, province: '', city: '', unionid: 'u', version: '1', channelid: 0, marketid: 0 },
data: { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 0, province: '', city: '', unionid: 'u', version: 1, channelid: 0, marketid: 0 },
};
const inb: InboundMessage<LoginResponseData> = { route: 'agent', rpc: 'player_login', data: { state: 0, playerid: 9 } };
void out; void inb;
@@ -6,7 +6,7 @@ import { parseLoginResponse } from '../../YouleNexus/assets/framework/protocol/l
import type { Clock } from '../../YouleNexus/assets/framework/net/heartbeat.ts';
const realishClock: Clock = { setTimeout: (fn, ms) => setTimeout(fn, ms), clearTimeout: (h: any) => clearTimeout(h) };
const IDENTITY = { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 0, province: '', city: '', unionid: 'u', version: '1', channelid: 0, marketid: 0 };
const IDENTITY = { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 0, province: '', city: '', unionid: 'u', version: 1, channelid: 0, marketid: 0 };
test('login 全流程:握手→登录→业务包,且 parseLoginResponse 识别房间恢复', async () => {
const t = new FakeTransport();
@@ -15,7 +15,7 @@ function fakeClock() {
return { clock, advance };
}
const IDENTITY = { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 0, province: '', city: '', unionid: 'u', version: '1', channelid: 0, marketid: 0 };
const IDENTITY = { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 0, province: '', city: '', unionid: 'u', version: 1, channelid: 0, marketid: 0 };
function makeClient(transports: FakeTransport[], clock: Clock) {
let i = 0;
@@ -2,7 +2,7 @@ import { test } from 'node:test';
import assert from 'node:assert/strict';
import { buildLoginRequest, parseLoginResponse } from '../../YouleNexus/assets/framework/protocol/login.ts';
const IDENTITY = { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 1, province: 'p', city: 'c', unionid: 'u', version: '1.0', channelid: 7, marketid: 9 };
const IDENTITY = { agentid: 1, gameid: 2, openid: 'o', nickname: 'n', avatar: 'a', sex: 1, province: 'p', city: 'c', unionid: 'u', version: 10001, channelid: 7, marketid: 9 };
test('buildLoginRequest 透传必备身份字段', () => {
const d = buildLoginRequest(IDENTITY);