Structure change.
cmdids now an enum, protos gitignored, compiled protos for type safety
This commit is contained in:
parent
babc829c44
commit
20d916e30b
3
.gitignore
vendored
3
.gitignore
vendored
@ -105,4 +105,5 @@ dist
|
||||
.tern-port
|
||||
|
||||
# CrepeSR
|
||||
config.json
|
||||
config.json
|
||||
src/data/proto
|
@ -11,7 +11,7 @@ export default async function handle(command: Command) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const acc = await Account.createAccount(command.args[1], command.args[2]);
|
||||
const acc = await Account.create(command.args[1], command.args[2]);
|
||||
c.log(`Account ${acc.name} with UID ${acc.uid} created.`);
|
||||
} catch (e) {
|
||||
c.error(e as Error);
|
||||
@ -22,12 +22,12 @@ export default async function handle(command: Command) {
|
||||
c.log(`Usage: account delete <uid>`);
|
||||
return;
|
||||
}
|
||||
const acc = await Account.getAccountByUID(command.args[1]);
|
||||
const acc = await Account.fromUID(command.args[1]);
|
||||
if (!acc) {
|
||||
c.error(`Account with UID ${command.args[1]} does not exist.`);
|
||||
return;
|
||||
}
|
||||
Account.deleteAccount(command.args[1]);
|
||||
Account.delete(command.args[1]);
|
||||
c.log(`Account ${acc.name} with UID ${acc.uid} deleted successfully.`);
|
||||
break;
|
||||
default:
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"101": "DebugNotify",
|
||||
"5": "PlayerGetTokenCsReq",
|
||||
"48": "PlayerGetTokenScRsp",
|
||||
"22": "PlayerKeepAliveNotify"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message PlayerGetTokenCsReq {
|
||||
uint32 account_type = 1;
|
||||
string account_uid = 2; // Related to v2/login HTTP endpoint
|
||||
string account_token = 3;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message PlayerGetTokenScRsp {
|
||||
uint32 retcode = 1;
|
||||
string msg = 2;
|
||||
uint32 uid = 3;
|
||||
string token = 4;
|
||||
uint32 black_uid_end_time = 5;
|
||||
uint32 account_type = 6;
|
||||
string account_uid = 7;
|
||||
bool is_proficient_player = 8;
|
||||
string secret_key = 9;
|
||||
uint32 gm_uid = 10;
|
||||
uint64 secret_key_seed = 11;
|
||||
bytes security_cmd_buffer = 12;
|
||||
uint32 platform_type = 13;
|
||||
bytes extra_bin_data = 14;
|
||||
bool is_guest = 15;
|
||||
uint32 channel_id = 16;
|
||||
uint32 sub_channel_id = 17;
|
||||
uint32 tag = 18;
|
||||
string country_code = 19;
|
||||
bool is_login_white_list = 20;
|
||||
string psn_id = 21;
|
||||
string client_version_random_key = 22;
|
||||
uint32 reg_platform = 23;
|
||||
string client_ip_str = 24;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
// Copyright (C) 2022 CrepeSR
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
message QueryCurrRegionHttpRsp {
|
||||
uint32 retcode = 1; // Always present
|
||||
string msg = 2; // Always present
|
||||
string region_name = 3; // Always present
|
||||
string gateserver_ip = 4;
|
||||
uint32 gateserver_port = 5;
|
||||
int64 stop_begin_time = 6;
|
||||
int64 stop_end_time = 7;
|
||||
bool unknown_boolean_one = 8;
|
||||
bool unknown_boolean_two = 9;
|
||||
string resource_url = 10;
|
||||
string data_url = 11;
|
||||
string lua_url = 12;
|
||||
uint32 unknown_int_one = 15;
|
||||
string client_secret_key = 17;
|
||||
string region_config = 18;
|
||||
string feedback_url = 20;
|
||||
string beta_text = 24; // "当前版本为测试版本,不代表游戏最终品质"
|
||||
bool unknown_boolean_three = 25;
|
||||
bool unknown_boolean_four = 26;
|
||||
}
|
@ -13,21 +13,28 @@ export default class Account {
|
||||
|
||||
}
|
||||
|
||||
public static async getAccountByUID(uid: string | number): Promise<Account | undefined> {
|
||||
public static async fromUID(uid: string | number): Promise<Account | undefined> {
|
||||
const db = Database.getInstance();
|
||||
const account = await db.get("accounts", { _id: Number(uid) });
|
||||
if (!account) return;
|
||||
return new Account(Number(account._id.toString()), account.name, account.token);
|
||||
}
|
||||
|
||||
public static async getAccountByUsername(name: string): Promise<Account | undefined> {
|
||||
public static async fromToken(token: string): Promise<Account | undefined> {
|
||||
const db = Database.getInstance();
|
||||
const account = await db.get("accounts", { token });
|
||||
if (!account) return;
|
||||
return new Account(Number(account._id.toString()), account.name, account.token);
|
||||
}
|
||||
|
||||
public static async fromUsername(name: string): Promise<Account | undefined> {
|
||||
const db = Database.getInstance();
|
||||
const account = await db.get("accounts", { name });
|
||||
if (!account) return;
|
||||
return new Account(Number(account._id.toString()), account.name, account.token);
|
||||
}
|
||||
|
||||
public static async createAccount(name: string, uid?: string | number): Promise<Account> {
|
||||
public static async create(name: string, uid?: string | number): Promise<Account> {
|
||||
const db = Database.getInstance();
|
||||
let selfAssignedUID = true;
|
||||
if (!uid) {
|
||||
@ -38,7 +45,7 @@ export default class Account {
|
||||
const account = await db.get("accounts", { uid });
|
||||
if (account) {
|
||||
if (!selfAssignedUID) {
|
||||
return await Account.createAccount(name, uid);
|
||||
return await Account.create(name, uid);
|
||||
} else {
|
||||
throw new Error(`Account with uid ${uid} already exists.`);
|
||||
}
|
||||
@ -49,9 +56,9 @@ export default class Account {
|
||||
return new Account(Number(uid), name, token);
|
||||
}
|
||||
|
||||
public static async deleteAccount(uid: string | number): Promise<void> {
|
||||
public static async delete(uid: string | number): Promise<void> {
|
||||
const db = Database.getInstance();
|
||||
const account = await Account.getAccountByUID(uid);
|
||||
const account = await Account.fromUID(uid);
|
||||
if (!account) {
|
||||
throw new Error(`Account with uid ${uid} does not exist.`);
|
||||
}
|
||||
|
68
src/db/Player.ts
Normal file
68
src/db/Player.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import Logger from "../util/Logger";
|
||||
import Account from "./Account";
|
||||
import Database from "./Database";
|
||||
const c = new Logger("Player");
|
||||
|
||||
interface PlayerI {
|
||||
_id: number;
|
||||
name: string;
|
||||
token: string;
|
||||
banned: boolean;
|
||||
basicInfo: {
|
||||
nickname: string;
|
||||
level: number;
|
||||
exp: number;
|
||||
stamina: number;
|
||||
mcoin: number;
|
||||
hcoin: number;
|
||||
scoin: number;
|
||||
worldLevel: number;
|
||||
}
|
||||
}
|
||||
|
||||
export default class Player {
|
||||
private constructor(public db: PlayerI) {
|
||||
|
||||
}
|
||||
|
||||
public static async fromUID(uid: number | string): Promise<Player | undefined> {
|
||||
if (typeof uid == "string") uid = Number(uid);
|
||||
const db = Database.getInstance();
|
||||
const player = await db.get("players", { _id: uid }) as unknown as PlayerI;
|
||||
if (!player) return Player.create(uid);
|
||||
return new Player(player);
|
||||
}
|
||||
|
||||
public static async fromToken(token: string): Promise<Player | undefined> {
|
||||
const db = Database.getInstance();
|
||||
const plr = await db.get("players", { token }) as unknown as PlayerI;
|
||||
if (!plr) return Player.fromUID((await Account.fromToken(token))?.uid || Math.round(Math.random() * 50000));
|
||||
|
||||
return new Player(plr);
|
||||
}
|
||||
|
||||
public static async create(uid: number | string): Promise<Player | undefined> {
|
||||
if (typeof uid == "string") uid = Number(uid);
|
||||
const acc = await Account.fromUID(uid);
|
||||
if (!acc) {
|
||||
c.warn(`Account ${uid} not found`);
|
||||
return;
|
||||
}
|
||||
const db = Database.getInstance();
|
||||
|
||||
const dataObj = {
|
||||
_id: acc.uid,
|
||||
name: acc.name,
|
||||
token: acc.token,
|
||||
banned: false
|
||||
} as PlayerI
|
||||
|
||||
await db.set("players", dataObj);
|
||||
return new Player(dataObj);
|
||||
}
|
||||
|
||||
public async save() {
|
||||
const db = Database.getInstance();
|
||||
await db.set("players", this.db);
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ const c = new Logger("Dispatch");
|
||||
// }
|
||||
|
||||
export default async function handle(req: Request, res: Response) {
|
||||
const acc = await Account.getAccountByUsername(req.body.account);
|
||||
const acc = await Account.fromUsername(req.body.account);
|
||||
const dataObj: any = {
|
||||
retcode: 0,
|
||||
message: "OK",
|
||||
|
@ -6,7 +6,7 @@ const c = new Logger("Dispatch");
|
||||
// {"uid":"63884253","token":"ZQmgMdXA1StL9A3aPBUedr8yoiuoLrmV"}
|
||||
|
||||
export default async function handle(req: Request, res: Response) {
|
||||
const acc = await Account.getAccountByUID(req.body.uid);
|
||||
const acc = await Account.fromUID(req.body.uid);
|
||||
const dataObj: any = {
|
||||
retcode: 0,
|
||||
message: "OK",
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { Request, Response } from "express";
|
||||
import protobuf from 'protobufjs';
|
||||
import protobuf, { Type } from 'protobufjs';
|
||||
import { resolve } from 'path';
|
||||
import Config from "../../util/Config";
|
||||
|
||||
const proto = protobuf.loadSync(resolve(__dirname, '../../data/proto/QueryCurrRegionHttpRsp.proto')).lookup('QueryCurrRegionHttpRsp') as any;
|
||||
import { Gateserver } from "../../data/proto/StarRail";
|
||||
|
||||
export default function handle(req: Request, res: Response) {
|
||||
const dataObj = {
|
||||
const dataObj = Gateserver.fromJSON({
|
||||
retcode: 0,
|
||||
msg: "OK",
|
||||
regionName: "CrepeSR",
|
||||
gateserverIp: Config.GAMESERVER.SERVER_IP,
|
||||
gateserverPort: Config.GAMESERVER.SERVER_PORT,
|
||||
} as any;
|
||||
ip: Config.GAMESERVER.SERVER_IP,
|
||||
port: Config.GAMESERVER.SERVER_PORT,
|
||||
serverDescription: "This is not BingusRail"
|
||||
});
|
||||
|
||||
if (Config.GAMESERVER.MAINTENANCE) {
|
||||
dataObj.retcode = 2;
|
||||
@ -23,14 +23,14 @@ export default function handle(req: Request, res: Response) {
|
||||
|
||||
let rsp;
|
||||
try {
|
||||
rsp = proto!.encode(dataObj).finish();
|
||||
rsp = Gateserver.encode(dataObj).finish();
|
||||
} catch {
|
||||
rsp = proto!.encode({
|
||||
rsp = Gateserver.encode(Gateserver.fromJSON({
|
||||
retcode: 2,
|
||||
msg: "Internal server error",
|
||||
stopBeginTime: Date.now(),
|
||||
stopEndTime: Date.now() * 2,
|
||||
}).finish();
|
||||
})).finish();
|
||||
}
|
||||
res.send(Buffer.from(rsp).toString('base64'));
|
||||
}
|
@ -1,22 +1,11 @@
|
||||
import Logger, { VerboseLevel } from "../../util/Logger";
|
||||
import protobuf from 'protobufjs';
|
||||
import protobuf, { Root } from 'protobufjs';
|
||||
import { resolve } from 'path';
|
||||
import _packetIds from '../../data/packetIds.json';
|
||||
const packetIds = _packetIds as { [key: string]: string };
|
||||
const switchedPacketIds: { [key: string]: number } = (function () {
|
||||
const obj: { [key: string]: number } = {};
|
||||
|
||||
Object.keys(packetIds).forEach((key) => {
|
||||
obj[packetIds[key]] = Number(key);
|
||||
});
|
||||
|
||||
return obj;
|
||||
})();
|
||||
const c = new Logger("Packet")
|
||||
|
||||
export default class Packet {
|
||||
public readonly cmdid: number;
|
||||
public readonly data: Buffer;
|
||||
private static root: Root = Packet.getRoot();
|
||||
public body: {} = {};
|
||||
|
||||
public constructor(public readonly rawData: Buffer, public readonly protoName: string = "") {
|
||||
@ -25,11 +14,10 @@ export default class Packet {
|
||||
this.data = rawData.subarray(12 + metadataLength, 12 + metadataLength + rawData.readUInt32BE(8));
|
||||
this.cmdid = this.rawData.readUInt16BE(4);
|
||||
|
||||
this.protoName = this.protoName || packetIds[this.cmdid.toString()];
|
||||
this.protoName = this.protoName || CmdID[this.cmdid];
|
||||
if (this.protoName) {
|
||||
try {
|
||||
const root = protobuf.loadSync(resolve(__dirname, `../../data/proto/${this.protoName}.proto`));
|
||||
const Message = root.lookupTypeOrEnum(this.protoName);
|
||||
const Message = Packet.root.lookupTypeOrEnum(this.protoName);
|
||||
this.body = Message.decode(this.data);
|
||||
} catch (e) {
|
||||
c.warn(`Failed to decode ${this.protoName}`);
|
||||
@ -51,9 +39,9 @@ export default class Packet {
|
||||
|
||||
public static encode(name: string, body: {}, customCmdId?: number): Packet | null {
|
||||
try {
|
||||
const cmdid = switchedPacketIds[name];
|
||||
const root = protobuf.loadSync(resolve(__dirname, `../../data/proto/${name}.proto`));
|
||||
const Message = root.lookupTypeOrEnum(name);
|
||||
// @ts-ignore - Bullshit. You can just get enums by name
|
||||
const cmdid = CmdID[name];
|
||||
const Message = Packet.root.lookupTypeOrEnum(name);
|
||||
|
||||
const data = Buffer.from(Message.encode(body).finish());
|
||||
const packet = Buffer.allocUnsafe(16 + data.length);
|
||||
@ -70,4 +58,423 @@ export default class Packet {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static getRoot(): Root {
|
||||
try {
|
||||
// Combined proto file with all definitions
|
||||
return protobuf.loadSync(resolve(__dirname, `../../data/proto/StarRail.proto`));
|
||||
} catch (e) {
|
||||
c.error("Failed to load proto root! Server will not be able to function properly. Please check your data/ folder.");
|
||||
c.error(e as Error, false);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type PacketName = keyof typeof CmdID;
|
||||
|
||||
enum CmdID {
|
||||
None = 0,
|
||||
PlayerLoginCsReq = 1,
|
||||
PlayerLoginScRsp = 2,
|
||||
PlayerLogoutCsReq = 3,
|
||||
PlayerLogoutScRsp = 4,
|
||||
PlayerGetTokenCsReq = 5,
|
||||
PlayerGetTokenScRsp = 6,
|
||||
PlayerKeepAliveNotify = 7,
|
||||
GmTalkScNotify = 8,
|
||||
PlayerKickOutScNotify = 9,
|
||||
GmTalkCsReq = 10,
|
||||
GmTalkScRsp = 11,
|
||||
ExchangeStaminaCsReq = 14,
|
||||
ExchangeStaminaScRsp = 15,
|
||||
GetAuthkeyCsReq = 16,
|
||||
GetAuthkeyScRsp = 17,
|
||||
RegionStopScNotify = 18,
|
||||
AntiAddictScNotify = 19,
|
||||
SetNicknameCsReq = 20,
|
||||
SetNicknameScRsp = 21,
|
||||
GetLevelRewardTakenListCsReq = 22,
|
||||
GetLevelRewardTakenListScRsp = 23,
|
||||
GetLevelRewardCsReq = 24,
|
||||
GetLevelRewardScRsp = 25,
|
||||
SyncTimeCsReq = 26,
|
||||
SyncTimeScRsp = 27,
|
||||
SetLanguageCsReq = 28,
|
||||
SetLanguageScRsp = 29,
|
||||
ServerAnnounceNotify = 30,
|
||||
SetHeroBasicTypeCsReq = 31,
|
||||
SetHeroBasicTypeScRsp = 32,
|
||||
GetHeroBasicTypeInfoCsReq = 33,
|
||||
GetHeroBasicTypeInfoScRsp = 34,
|
||||
GetHeroPathCsReq = 35,
|
||||
GetHeroPathScRsp = 36,
|
||||
HeroPathChangedNotify = 37,
|
||||
SetGenderCsReq = 38,
|
||||
SetGenderScRsp = 39,
|
||||
SetPlayerInfoCsReq = 40,
|
||||
SetPlayerInfoScRsp = 41,
|
||||
HeroBasicTypeChangedNotify = 42,
|
||||
QueryProductInfoCsReq = 43,
|
||||
QueryProductInfoScRsp = 44,
|
||||
ClientDownloadDataScNotify = 45,
|
||||
UpdateFeatureSwitchScNotify = 46,
|
||||
GetBasicInfoCsReq = 47,
|
||||
GetBasicInfoScRsp = 48,
|
||||
DailyRefreshNotify = 49,
|
||||
PVEBattleResultCsReq = 101,
|
||||
PVEBattleResultScRsp = 102,
|
||||
QuitBattleCsReq = 103,
|
||||
QuitBattleScRsp = 104,
|
||||
GetCurBattleInfoCsReq = 105,
|
||||
GetCurBattleInfoScRsp = 106,
|
||||
SyncClientResVersionCsReq = 107,
|
||||
SyncClientResVersionScRsp = 108,
|
||||
QuitBattleScNotify = 109,
|
||||
GetStageDataCsReq = 201,
|
||||
GetStageDataScRsp = 202,
|
||||
StageBeginCsReq = 203,
|
||||
StageBeginScRsp = 204,
|
||||
GetAvatarDataCsReq = 301,
|
||||
GetAvatarDataScRsp = 302,
|
||||
AvatarExpUpCsReq = 303,
|
||||
AvatarExpUpScRsp = 304,
|
||||
UnlockSkilltreeCsReq = 305,
|
||||
UnlockSkilltreeScRsp = 306,
|
||||
PromoteAvatarCsReq = 307,
|
||||
PromoteAvatarScRsp = 308,
|
||||
DressAvatarCsReq = 309,
|
||||
DressAvatarScRsp = 310,
|
||||
TakeOffEquipmentCsReq = 311,
|
||||
TakeOffEquipmentScRsp = 312,
|
||||
AddAvatarScNotify = 313,
|
||||
RankUpAvatarCsReq = 314,
|
||||
RankUpAvatarScRsp = 315,
|
||||
DressRelicAvatarCsReq = 316,
|
||||
DressRelicAvatarScRsp = 317,
|
||||
TakeOffRelicCsReq = 318,
|
||||
TakeOffRelicScRsp = 319,
|
||||
GetWaypointCsReq = 401,
|
||||
GetWaypointScRsp = 402,
|
||||
SetCurWaypointCsReq = 403,
|
||||
SetCurWaypointScRsp = 404,
|
||||
GetChapterCsReq = 405,
|
||||
GetChapterScRsp = 406,
|
||||
WaypointShowNewCsNotify = 407,
|
||||
TakeChapterRewardCsReq = 408,
|
||||
TakeChapterRewardScRsp = 409,
|
||||
GetBagCsReq = 501,
|
||||
GetBagScRsp = 502,
|
||||
PromoteEquipmentCsReq = 503,
|
||||
PromoteEquipmentScRsp = 504,
|
||||
LockEquipmentCsReq = 505,
|
||||
LockEquipmentScRsp = 506,
|
||||
UseItemCsReq = 507,
|
||||
UseItemScRsp = 508,
|
||||
RankUpEquipmentCsReq = 509,
|
||||
RankUpEquipmentScRsp = 510,
|
||||
ExpUpEquipmentCsReq = 511,
|
||||
ExpUpEquipmentScRsp = 512,
|
||||
ComposeItemCsReq = 513,
|
||||
ComposeItemScRsp = 514,
|
||||
ExpUpRelicCsReq = 515,
|
||||
ExpUpRelicScRsp = 516,
|
||||
LockRelicCsReq = 517,
|
||||
LockRelicScRsp = 518,
|
||||
SellItemCsReq = 519,
|
||||
SellItemScRsp = 520,
|
||||
RechargeSuccNotify = 521,
|
||||
PlayerSyncScNotify = 601,
|
||||
GetStageLineupCsReq = 701,
|
||||
GetStageLineupScRsp = 702,
|
||||
GetCurLineupDataCsReq = 703,
|
||||
GetCurLineupDataScRsp = 704,
|
||||
JoinLineupCsReq = 705,
|
||||
JoinLineupScRsp = 706,
|
||||
QuitLineupCsReq = 707,
|
||||
QuitLineupScRsp = 708,
|
||||
SwapLineupCsReq = 709,
|
||||
SwapLineupScRsp = 710,
|
||||
SyncLineupNotify = 711,
|
||||
GetLineupAvatarDataCsReq = 712,
|
||||
GetLineupAvatarDataScRsp = 713,
|
||||
ChangeLineupLeaderCsReq = 714,
|
||||
ChangeLineupLeaderScRsp = 715,
|
||||
SwitchLineupIndexCsReq = 716,
|
||||
SwitchLineupIndexScRsp = 717,
|
||||
SetLineupNameCsReq = 718,
|
||||
SetLineupNameScRsp = 719,
|
||||
GetAllLineupDataCsReq = 720,
|
||||
GetAllLineupDataScRsp = 721,
|
||||
VirtualLineupDestroyNotify = 722,
|
||||
GetMailCsReq = 801,
|
||||
GetMailScRsp = 802,
|
||||
MarkReadMailCsReq = 803,
|
||||
MarkReadMailScRsp = 804,
|
||||
DelMailCsReq = 805,
|
||||
DelMailScRsp = 806,
|
||||
TakeMailAttachmentCsReq = 807,
|
||||
TakeMailAttachmentScRsp = 808,
|
||||
NewMailScNotify = 809,
|
||||
GetQuestDataCsReq = 901,
|
||||
GetQuestDataScRsp = 902,
|
||||
TakeQuestRewardCsReq = 903,
|
||||
TakeQuestRewardScRsp = 904,
|
||||
TakeAchievementLevelRewardCsReq = 905,
|
||||
TakeAchievementLevelRewardScRsp = 906,
|
||||
GetMazeCsReq = 1001,
|
||||
GetMazeScRsp = 1002,
|
||||
ChooseMazeSeriesCsReq = 1003,
|
||||
ChooseMazeSeriesScRsp = 1004,
|
||||
ChooseMazeAbilityCsReq = 1005,
|
||||
ChooseMazeAbilityScRsp = 1006,
|
||||
EnterMazeCsReq = 1007,
|
||||
EnterMazeScRsp = 1008,
|
||||
MazeBuffScNotify = 1011,
|
||||
CastMazeSkillCsReq = 1012,
|
||||
CastMazeSkillScRsp = 1013,
|
||||
MazePlaneEventScNotify = 1014,
|
||||
EnterMazeByServerScNotify = 1015,
|
||||
GetMazeMapInfoCsReq = 1016,
|
||||
GetMazeMapInfoScRsp = 1017,
|
||||
GetMazeTimeOfDayCsReq = 1018,
|
||||
GetMazeTimeOfDayScRsp = 1019,
|
||||
SetMazeTimeOfDayCsReq = 1020,
|
||||
SetMazeTimeOfDayScRsp = 1021,
|
||||
DelMazeTimeOfDayCsReq = 1022,
|
||||
DelMazeTimeOfDayScRsp = 1023,
|
||||
ReturnStartAnchorCsReq = 1024,
|
||||
ReturnStartAnchorScRsp = 1025,
|
||||
FinishPlotCsReq = 1101,
|
||||
FinishPlotScRsp = 1102,
|
||||
GetMissionDataCsReq = 1201,
|
||||
GetMissionDataScRsp = 1202,
|
||||
FinishTalkMissionCsReq = 1203,
|
||||
FinishTalkMissionScRsp = 1204,
|
||||
MissionRewardScNotify = 1205,
|
||||
SyncTaskCsReq = 1206,
|
||||
SyncTaskScRsp = 1207,
|
||||
DailyTaskDataScNotify = 1208,
|
||||
TakeDailyTaskExtraRewardCsReq = 1209,
|
||||
TakeDailyTaskExtraRewardScRsp = 1210,
|
||||
DailyTaskRewardScNotify = 1211,
|
||||
MissionGroupWarnScNotify = 1212,
|
||||
FinishCosumeItemMissionCsReq = 1213,
|
||||
FinishCosumeItemMissionScRsp = 1214,
|
||||
GetMissionEventDataCsReq = 1215,
|
||||
GetMissionEventDataScRsp = 1216,
|
||||
MissionEventRewardScNotify = 1217,
|
||||
AcceptMissionEventCsReq = 1218,
|
||||
AcceptMissionEventScRsp = 1219,
|
||||
GetMissionStatusCsReq = 1220,
|
||||
GetMissionStatusScRsp = 1221,
|
||||
InterruptMissionEventCsReq = 1222,
|
||||
InterruptMissionEventScRsp = 1223,
|
||||
SetMissionEventProgressCsReq = 1224,
|
||||
SetMissionEventProgressScRsp = 1225,
|
||||
SubMissionRewardScNotify = 1226,
|
||||
EnterAdventureCsReq = 1301,
|
||||
EnterAdventureScRsp = 1302,
|
||||
SceneEntityMoveCsReq = 1401,
|
||||
SceneEntityMoveScRsp = 1402,
|
||||
InteractPropCsReq = 1403,
|
||||
InteractPropScRsp = 1404,
|
||||
SceneCastSkillCsReq = 1405,
|
||||
SceneCastSkillScRsp = 1406,
|
||||
GetCurSceneInfoCsReq = 1407,
|
||||
GetCurSceneInfoScRsp = 1408,
|
||||
SceneEntityUpdateScNotify = 1409,
|
||||
SceneEntityDisappearScNotify = 1410,
|
||||
SceneEntityMoveScNotify = 1411,
|
||||
SpringTransferCsReq = 1414,
|
||||
SpringTransferScRsp = 1415,
|
||||
UpdateBuffScNotify = 1416,
|
||||
DelBuffScNotify = 1417,
|
||||
SpringRefreshCsReq = 1418,
|
||||
SpringRefreshScRsp = 1419,
|
||||
LastSpringRefreshTimeNotify = 1420,
|
||||
ReturnLastTownCsReq = 1421,
|
||||
ReturnLastTownScRsp = 1422,
|
||||
SceneEnterStageCsReq = 1423,
|
||||
SceneEnterStageScRsp = 1424,
|
||||
EnterSectionCsReq = 1427,
|
||||
EnterSectionScRsp = 1428,
|
||||
SetCurInteractEntityCsReq = 1431,
|
||||
SetCurInteractEntityScRsp = 1432,
|
||||
RecoverAllLineupCsReq = 1433,
|
||||
RecoverAllLineupScRsp = 1434,
|
||||
SavePointsInfoNotify = 1435,
|
||||
StartCocoonStageCsReq = 1436,
|
||||
StartCocoonStageScRsp = 1437,
|
||||
EntityBindPropCsReq = 1438,
|
||||
EntityBindPropScRsp = 1439,
|
||||
SetClientPausedCsReq = 1440,
|
||||
SetClientPausedScRsp = 1441,
|
||||
UpdateBuffGroupStartScNotify = 1442,
|
||||
UpdateBuffGroupEndScNotify = 1443,
|
||||
ActivateFarmElementCsReq = 1445,
|
||||
ActivateFarmElementScRsp = 1446,
|
||||
GetSpringRecoverDataCsReq = 1447,
|
||||
GetSpringRecoverDataScRsp = 1448,
|
||||
SetSpringRecoverConfigCsReq = 1449,
|
||||
SetSpringRecoverConfigScRsp = 1450,
|
||||
SpringRecoverCsReq = 1451,
|
||||
SpringRecoverScRsp = 1452,
|
||||
HealPoolInfoNotify = 1453,
|
||||
SpringRecoverSingleAvatarCsReq = 1454,
|
||||
SpringRecoverSingleAvatarScRsp = 1455,
|
||||
GetShopListCsReq = 1501,
|
||||
GetShopListScRsp = 1502,
|
||||
BuyGoodsCsReq = 1503,
|
||||
BuyGoodsScRsp = 1504,
|
||||
GetTutorialCsReq = 1601,
|
||||
GetTutorialScRsp = 1602,
|
||||
GetTutorialGuideCsReq = 1603,
|
||||
GetTutorialGuideScRsp = 1604,
|
||||
UnlockTutorialCsReq = 1605,
|
||||
UnlockTutorialScRsp = 1606,
|
||||
UnlockTutorialGuideCsReq = 1607,
|
||||
UnlockTutorialGuideScRsp = 1608,
|
||||
FinishTutorialCsReq = 1609,
|
||||
FinishTutorialScRsp = 1610,
|
||||
FinishTutorialGuideCsReq = 1611,
|
||||
FinishTutorialGuideScRsp = 1612,
|
||||
GetChallengeCsReq = 1701,
|
||||
GetChallengeScRsp = 1702,
|
||||
StartChallengeCsReq = 1703,
|
||||
StartChallengeScRsp = 1704,
|
||||
LeaveChallengeCsReq = 1705,
|
||||
LeaveChallengeScRsp = 1706,
|
||||
ChallengeSettleNotify = 1707,
|
||||
FinishChallengeCsReq = 1708,
|
||||
FinishChallengeScRsp = 1709,
|
||||
GetCurChallengeCsReq = 1710,
|
||||
GetCurChallengeScRsp = 1711,
|
||||
ChallengeLineupNotify = 1712,
|
||||
TakeChallengeTargetRewardCsReq = 1713,
|
||||
TakeChallengeTargetRewardScRsp = 1714,
|
||||
GetRogueInfoCsReq = 1801,
|
||||
GetRogueInfoScRsp = 1802,
|
||||
StartRogueCsReq = 1803,
|
||||
StartRogueScRsp = 1804,
|
||||
EnterRogueCsReq = 1805,
|
||||
EnterRogueScRsp = 1806,
|
||||
LeaveRogueCsReq = 1807,
|
||||
LeaveRogueScRsp = 1808,
|
||||
SyncRogueBuffSelectInfoScNotify = 1809,
|
||||
SelectRogueBuffCsReq = 1810,
|
||||
SelectRogueBuffScRsp = 1811,
|
||||
RollRogueBuffCsReq = 1812,
|
||||
RollRogueBuffScRsp = 1813,
|
||||
EnterNextRogueRoomScNotify = 1814,
|
||||
SyncRogueFinishScNotify = 1815,
|
||||
PickRogueAvatarCsReq = 1816,
|
||||
PickRogueAvatarScRsp = 1817,
|
||||
AddRogueBuffScNotify = 1818,
|
||||
ReviveRogueAvatarCsReq = 1819,
|
||||
ReviveRogueAvatarScRsp = 1820,
|
||||
SaveRogueRecordCsReq = 1821,
|
||||
SaveRogueRecordScRsp = 1822,
|
||||
RecoverRogueStaminaCsReq = 1823,
|
||||
RecoverRogueStaminaScRsp = 1824,
|
||||
StartRogueChallengeCsReq = 1827,
|
||||
StartRogueChallengeScRsp = 1828,
|
||||
LeaveRogueChallengeCsReq = 1829,
|
||||
LeaveRogueChallengeScRsp = 1830,
|
||||
SyncRogueChallengeFinishScNotify = 1831,
|
||||
QuitRogueCsReq = 1832,
|
||||
QuitRogueScRsp = 1833,
|
||||
AppraisalRogueStoneCsReq = 1834,
|
||||
AppraisalRogueStoneScRsp = 1835,
|
||||
SyncRogueSeasonFinishScNotify = 1836,
|
||||
SyncRogueInfoChangeScNotify = 1837,
|
||||
AddRogueExtraBuffScNotify = 1838,
|
||||
EnterRogueMapRoomCsReq = 1839,
|
||||
EnterRogueMapRoomScRsp = 1840,
|
||||
EnterRogueNextLevelCsReq = 1841,
|
||||
EnterRogueNextLevelScRsp = 1842,
|
||||
SyncRogueMapRoomScNotify = 1843,
|
||||
SyncRoguePickAvatarScNotify = 1844,
|
||||
SetRogueBlessCsReq = 1845,
|
||||
SetRogueBlessScRsp = 1846,
|
||||
SyncRogueBlessScNotify = 1847,
|
||||
GetRogueShopInfoCsReq = 1848,
|
||||
GetRogueShopInfoScRsp = 1849,
|
||||
BuyRogueShopBuffCsReq = 1850,
|
||||
BuyRogueShopBuffScRsp = 1851,
|
||||
FinishRogueDialogueGroupCsReq = 1852,
|
||||
FinishRogueDialogueGroupScRsp = 1853,
|
||||
UnlockRogueRoomCsReq = 1856,
|
||||
UnlockRogueRoomScRsp = 1857,
|
||||
GetRogueGachaInfoCsReq = 1858,
|
||||
GetRogueGachaInfoScRsp = 1859,
|
||||
SetRogueGachaWishListCsReq = 1860,
|
||||
SetRogueGachaWishListScRsp = 1861,
|
||||
DoRogueGachaCsReq = 1862,
|
||||
DoRogueGachaScRsp = 1863,
|
||||
SyncRogueGachaRefreshScNotify = 1864,
|
||||
BuyRogueShopItemCsReq = 1865,
|
||||
BuyRogueShopItemScRsp = 1866,
|
||||
GetRogueAppraisalItemInfoCsReq = 1867,
|
||||
GetRogueAppraisalItemInfoScRsp = 1868,
|
||||
SyncRogueMiracleGetItemScNotify = 1869,
|
||||
SyncRogueQuestScNotify = 1870,
|
||||
GetRogueQuestRewardCsReq = 1871,
|
||||
GetRogueQuestRewardScRsp = 1872,
|
||||
GetGachaInfoCsReq = 1901,
|
||||
GetGachaInfoScRsp = 1902,
|
||||
DoGachaCsReq = 1903,
|
||||
DoGachaScRsp = 1904,
|
||||
GetPrestigeInfoCsReq = 2001,
|
||||
GetPrestigeInfoScRsp = 2002,
|
||||
PrestigeInfoChangeNotify = 2003,
|
||||
TakePrestigeLevelRewardCsReq = 2004,
|
||||
TakePrestigeLevelRewardScRsp = 2005,
|
||||
GetNpcTakenRewardCsReq = 2101,
|
||||
GetNpcTakenRewardScRsp = 2102,
|
||||
TakeTalkRewardCsReq = 2103,
|
||||
TakeTalkRewardScRsp = 2104,
|
||||
GetFirstTalkNpcCsReq = 2105,
|
||||
GetFirstTalkNpcScRsp = 2106,
|
||||
FinishFirstTalkNpcCsReq = 2107,
|
||||
FinishFirstTalkNpcScRsp = 2108,
|
||||
StartRaidCsReq = 2201,
|
||||
StartRaidScRsp = 2202,
|
||||
LeaveRaidCsReq = 2203,
|
||||
LeaveRaidScRsp = 2204,
|
||||
RaidInfoNotify = 2205,
|
||||
GetChallengeRaidInfoCsReq = 2206,
|
||||
GetChallengeRaidInfoScRsp = 2207,
|
||||
TakeChallengeRaidRewardCsReq = 2208,
|
||||
TakeChallengeRaidRewardScRsp = 2209,
|
||||
ChallengeRaidNotify = 2210,
|
||||
GetArchiveDataCsReq = 2301,
|
||||
GetArchiveDataScRsp = 2302,
|
||||
GetUpdatedArchiveDataCsReq = 2303,
|
||||
GetUpdatedArchiveDataScRsp = 2304,
|
||||
GetDialogueEventDataCsReq = 2401,
|
||||
GetDialogueEventDataScRsp = 2402,
|
||||
SelectDialogueEventCsReq = 2403,
|
||||
SelectDialogueEventScRsp = 2404,
|
||||
SyncDialogueEventDataScNotify = 2405,
|
||||
GetExpeditionDataCsReq = 2501,
|
||||
GetExpeditionDataScRsp = 2502,
|
||||
AcceptExpeditionCsReq = 2503,
|
||||
AcceptExpeditionScRsp = 2504,
|
||||
CancelExpeditionCsReq = 2505,
|
||||
CancelExpeditionScRsp = 2506,
|
||||
TakeExpeditionRewardCsReq = 2507,
|
||||
TakeExpeditionRewardScRsp = 2508,
|
||||
GetLoginActivityCsReq = 2601,
|
||||
GetLoginActivityScRsp = 2602,
|
||||
TakeLoginActivityRewardCsReq = 2603,
|
||||
TakeLoginActivityRewardScRsp = 2604,
|
||||
GetNpcMessageGroupCsReq = 2701,
|
||||
GetNpcMessageGroupScRsp = 2702,
|
||||
GetNpcStatusCsReq = 2703,
|
||||
GetNpcStatusScRsp = 2704,
|
||||
FinishItemIdCsReq = 2705,
|
||||
FinishItemIdScRsp = 2706,
|
||||
FinishSectionIdCsReq = 2707,
|
||||
FinishSectionIdScRsp = 2708,
|
||||
}
|
@ -33,7 +33,6 @@ export default class SRServer {
|
||||
|
||||
private async onMessage(data: Buffer, rinfo: RemoteInfo) {
|
||||
const client = `${rinfo.address}:${rinfo.port}`;
|
||||
c.debug(data.toString("hex"));
|
||||
if (data.byteLength == 20) {
|
||||
// Hamdshanke
|
||||
const handshake = new Handshake(data);
|
||||
|
@ -3,23 +3,21 @@ import { RemoteInfo } from 'dgram';
|
||||
import { resolve } from 'path';
|
||||
import fs from 'fs';
|
||||
import KCP from 'node-kcp-token';
|
||||
import Packet from './Packet';
|
||||
import Packet, { PacketName } from './Packet';
|
||||
import Logger, { VerboseLevel } from '../../util/Logger';
|
||||
import defaultHandler from '../packets/PacketHandler';
|
||||
import Account from '../../db/Account';
|
||||
import Player from '../../db/Player';
|
||||
|
||||
function r(...args: string[]) {
|
||||
return fs.readFileSync(resolve(__dirname, ...args));
|
||||
}
|
||||
|
||||
function xor(data: Buffer, key: Buffer) {
|
||||
const ret: Buffer = Buffer.from(data);
|
||||
for (let i = 0; i < data.length; i++) ret.writeUInt8(data.readUInt8(i) ^ key.readUInt8(i % key.length), i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export default class Session {
|
||||
public key: Buffer = r('./initial.key');
|
||||
public c: Logger;
|
||||
public account!: Account;
|
||||
public player!: Player;
|
||||
public constructor(private readonly kcpobj: KCP.KCP, public readonly ctx: RemoteInfo) {
|
||||
this.kcpobj = kcpobj;
|
||||
this.ctx = ctx;
|
||||
@ -71,7 +69,7 @@ export default class Session {
|
||||
});
|
||||
}
|
||||
|
||||
public send(name: string, body: {}) {
|
||||
public send(name: PacketName, body: {}) {
|
||||
const packet = Packet.encode(name, body);
|
||||
if (!packet) return;
|
||||
if (Logger.VERBOSE_LEVEL >= VerboseLevel.WARNS) this.c.log(packet.protoName);
|
||||
|
@ -2,33 +2,49 @@ import Logger from "../../util/Logger";
|
||||
import Account from "../../db/Account";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
import Player from "../../db/Player";
|
||||
import { PlayerGetTokenScRsp } from "../../data/proto/StarRail";
|
||||
const c = new Logger("Dispatch");
|
||||
|
||||
interface PlayerGetTokenCsReq {
|
||||
accountToken?: string;
|
||||
accountUid?: string;
|
||||
accountType?: number;
|
||||
channel_id?: number;
|
||||
account_uid?: string;
|
||||
token?: string;
|
||||
uid?: number;
|
||||
device?: string;
|
||||
}
|
||||
|
||||
const retWarn = (msg: string) => c.warn(msg);
|
||||
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as PlayerGetTokenCsReq;
|
||||
const account = await Account.getAccountByUID(body.accountUid || 0);
|
||||
if (!account) {
|
||||
c.error(`Account not found: ${body.accountUid}`);
|
||||
|
||||
let dataObj = {
|
||||
retcode: 0,
|
||||
secretKeySeed: 0
|
||||
} as PlayerGetTokenScRsp;
|
||||
|
||||
const account = await Account.fromToken(body.token || "");
|
||||
if (!account) retWarn(`Account not found with token ${body.token}`);
|
||||
|
||||
const player = await Player.fromToken(account?.token || "");
|
||||
if (!player) retWarn(`Player not found with accountToken ${account?.token}`);
|
||||
if (!player || !account) {
|
||||
dataObj.retcode = 6;
|
||||
return;
|
||||
}
|
||||
session.account = account;
|
||||
session.player = player;
|
||||
|
||||
const isTokenValid = account.token === body.accountToken;
|
||||
const isTokenValid = player.db.token === body.token;
|
||||
const isBanned = player.db.banned;
|
||||
if (isBanned) dataObj.retcode = 1013;
|
||||
if (!isTokenValid) {
|
||||
c.error(`Token invalid (${session.ctx.address}:${session.ctx.port})`);
|
||||
retWarn(`Token invalid (${session.ctx.address}:${session.ctx.port})`);
|
||||
dataObj.retcode = 1005;
|
||||
return;
|
||||
}
|
||||
|
||||
session.send("PlayerGetTokenScRsp", {
|
||||
uid: account.uid,
|
||||
token: body.accountToken,
|
||||
secretKey: BigInt(0).toString(),
|
||||
accountUid: account.uid.toString(),
|
||||
accountType: body.accountType,
|
||||
});
|
||||
dataObj.uid = player.db._id;
|
||||
session.send("PlayerGetTokenScRsp", dataObj);
|
||||
}
|
46
src/server/packets/PlayerLoginCsReq.ts
Normal file
46
src/server/packets/PlayerLoginCsReq.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { PlayerLoginCsReq, PlayerLoginScRsp } from "../../data/proto/StarRail";
|
||||
import Player from "../../db/Player";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
|
||||
// { Example body:
|
||||
// platform: 3,
|
||||
// deviceUuid: '406d064a8fa3bcb32f1d88df28e600e5a86bbf751658757874371',
|
||||
// deviceInfo: '{"operatingSystem":"Windows 10 (10.0.19043) 64bit","deviceModel":"B450M DS3H V2 (Gigabyte Technology Co., Ltd.)","graphicsDeviceName":"NVIDIA GeForce GTX 1650","graphicsDeviceType":"Direct3D11","graphicsDeviceVendor":"NVIDIA","graphicsDeviceVersion":"Direct3D 11.0 [level 11.1]","graphicsMemorySize":3962,"processorCount":12,"processorFrequency":3394,"processorType":"AMD Ryzen 5 2600 Six-Core Processor ","systemMemorySize":16335,"DeviceSoC":""}',
|
||||
// systemInfo: 'Windows 10 (10.0.19043) 64bit',
|
||||
// clientVersion: 'OSCBWin0.70.0',
|
||||
// language: 3,
|
||||
// checkSum_1: 'ff07bc743a394e0ff1c163edc663137d',
|
||||
// checkSum_2: 'ca590da88620492b921c9b3b4977f1be10',
|
||||
// resolution: '1920*1080',
|
||||
// systemLanguage: 'Dutch',
|
||||
// resVersion: 611127,
|
||||
// clientTimeZone: '01:00:00'
|
||||
// }
|
||||
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as PlayerLoginCsReq;
|
||||
|
||||
const plr = await Player.fromUID(session.player.db._id)!;
|
||||
if (!plr!.db.basicInfo) {
|
||||
plr!.db.basicInfo = {
|
||||
exp: 0,
|
||||
level: 1,
|
||||
hcoin: 0,
|
||||
mcoin: 0,
|
||||
nickname: plr!.db.name,
|
||||
scoin: 0,
|
||||
stamina: 100,
|
||||
worldLevel: 1,
|
||||
}
|
||||
plr!.save();
|
||||
}
|
||||
|
||||
session.send("PlayerLoginScRsp", {
|
||||
basicInfo: plr!.db.basicInfo,
|
||||
isNewPlayer: true,
|
||||
stamina: 100,
|
||||
curTimezone: body.clientTimeZone,
|
||||
serverTimestampMs: Math.round(new Date().getTime() / 1000).toString(),
|
||||
} as unknown as PlayerLoginScRsp);
|
||||
}
|
Loading…
Reference in New Issue
Block a user