Merge pull request #2 from Crepe-Inc/login-sequence

This commit is contained in:
memetrollsXD 2022-07-31 21:14:20 +02:00 committed by GitHub
commit fb33fbc41f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 562 additions and 10 deletions

2
.gitignore vendored
View File

@ -106,4 +106,4 @@ dist
# CrepeSR # CrepeSR
config.json config.json
src/data/proto src/data/*

View File

@ -1,6 +1,7 @@
import { createInterface } from 'readline'; import { createInterface } from 'readline';
import _alias from './alias.json'; import _alias from './alias.json';
import Logger from '../util/Logger'; import Logger from '../util/Logger';
import Session from '../server/kcp/Session';
const c = new Logger("Command", "blue"); const c = new Logger("Command", "blue");
const alias: { [key: string]: string } = _alias; const alias: { [key: string]: string } = _alias;
@ -22,6 +23,8 @@ export default class Interface {
output: process.stdout output: process.stdout
}); });
public static target: Session;
private constructor() { } private constructor() { }
public static readonly start = () => { public static readonly start = () => {

View File

@ -14,6 +14,7 @@ export default async function handle(command: Command) {
} }
Config.VERBOSE_LEVEL = level as unknown as VerboseLevel; Config.VERBOSE_LEVEL = level as unknown as VerboseLevel;
Logger.VERBOSE_LEVEL = level as unknown as VerboseLevel;
c.log(`VerboseLevel set to ${Config.VERBOSE_LEVEL} (${VerboseLevel[level]})`); c.log(`VerboseLevel set to ${Config.VERBOSE_LEVEL} (${VerboseLevel[level]})`);
} }
} }

26
src/commands/kick.ts Normal file
View File

@ -0,0 +1,26 @@
import { BlackLimitLevel, PlayerKickOutScNotify, PlayerKickOutScNotify_KickType } from "../data/proto/StarRail";
import SRServer from "../server/kcp/SRServer";
import Logger from "../util/Logger";
import Interface, { Command } from "./Interface";
const c = new Logger("/kick", "blue");
export default async function handle(command: Command) {
if (!Interface.target) {
c.log("No target specified");
return;
}
Interface.target.send("PlayerKickOutScNotify", {
kickType: PlayerKickOutScNotify_KickType.KICK_BLACK,
blackInfo: {
limitLevel: BlackLimitLevel.BLACK_LIMIT_LEVEL_ALL,
beginTime: Math.round(Date.now() / 1000),
endTime: Math.round(Date.now() / 1000),
banType: 2
}
} as PlayerKickOutScNotify);
// SRServer.getInstance().sessions.delete(`${Interface.target.ctx.address}:${Interface.target.ctx.port}`);
c.log(`Kicked ${Interface.target.account.name}`);
}

36
src/commands/target.ts Normal file
View File

@ -0,0 +1,36 @@
import Logger from "../util/Logger";
import Interface, { Command } from "./Interface";
import findBestMatch from "../util/stringSimilarity";
import SRServer from "../server/kcp/SRServer";
import Session from "../server/kcp/Session";
const c = new Logger("/target", "blue");
export default async function handle(command: Command) {
const target = command.args[0];
const possibleTargets: {
id: string;
session: Session;
uid: number;
}[] = [];
SRServer.getInstance().sessions.forEach(client => {
possibleTargets.push({
id: `${client.ctx.address}:${client.ctx.port}`,
uid: Number(client.account.uid),
session: client
});
});
if (!target) {
c.log("No target specified");
c.log("Possible targets: ");
possibleTargets.forEach(x => c.trail(`${x.id} (UID: ${x.uid})`));
return;
}
const autoTarget = findBestMatch(target, possibleTargets.map(x => x.id)).bestMatch.target;
Interface.target = possibleTargets.find(x => x.id === autoTarget)!.session;
c.log(`Target set to ${autoTarget}`);
}

View File

@ -64,6 +64,11 @@ export default class Account {
} }
await db.delete("accounts", { _id: Number(uid) }); await db.delete("accounts", { _id: Number(uid) });
} }
public async save() {
const db = Database.getInstance();
await db.update("accounts", { _id: Number(this.uid) }, this);
}
} }
function generateToken(): string { function generateToken(): string {

View File

@ -22,7 +22,7 @@ export default class Database {
return Database.instance; return Database.instance;
} }
public async get(collection: string, query?: {}) { public async get(collection: string, query?: object) {
try { try {
const db = await Database.client.db(); const db = await Database.client.db();
const _collection = db.collection(collection); const _collection = db.collection(collection);
@ -52,7 +52,7 @@ export default class Database {
} }
} }
public async delete(collection: string, query: {}) { public async delete(collection: string, query: object) {
try { try {
const db = await Database.client.db(); const db = await Database.client.db();
const _collection = db.collection(collection); const _collection = db.collection(collection);
@ -65,4 +65,18 @@ export default class Database {
c.error(e as Error); c.error(e as Error);
} }
} }
public async update(collection: string, query: object, payload: object) {
try {
const db = await Database.client.db();
const _collection = db.collection(collection);
if (!(await db.listCollections({ name: collection }).toArray()).length) {
c.warn(`Collection ${collection} does not exist. Creating...`);
await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
}
return await _collection.updateOne(query, { $set: payload }, { upsert: true });
} catch (e) {
c.error(e as Error);
}
}
} }

View File

@ -63,6 +63,6 @@ export default class Player {
public async save() { public async save() {
const db = Database.getInstance(); const db = Database.getInstance();
await db.set("players", this.db); await db.update("players", { _id: this.db._id } , this.db);
} }
} }

View File

@ -0,0 +1,12 @@
import { FinishTalkMissionCsReq, FinishTalkMissionScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
const body = packet.body as FinishTalkMissionCsReq;
session.send("FinishTalkMissionScRsp", {
retcode: 0,
talkStr: body.talkStr
} as FinishTalkMissionScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetAllLineupDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetAllLineupDataScRsp", {
retcode: 0,
lineupList: []
} as unknown as GetAllLineupDataScRsp);
}

View File

@ -0,0 +1,29 @@
import { GetAvatarDataCsReq, GetAvatarDataScRsp } from "../../data/proto/StarRail";
import AvatarExcelTable from "../../data/excel/AvatarExcelTable.json";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
const body = packet.body as GetAvatarDataCsReq;
const dataObj = {
retcode: 0,
avatarList: [{
baseAvatarId: 1001,
equipmentUniqueId: 13501,
equipRelicList: [],
exp: 0,
level: 1,
promotion: 1,
rank: 1,
skilltreeList: [],
}],
isAll: body.isGetAll
} as GetAvatarDataScRsp;
Object.values(AvatarExcelTable).forEach(avatar => {
// dataObj.avatarList.push()
});
session.send("GetAvatarDataScRsp", dataObj);
}

View File

@ -0,0 +1,14 @@
import { GetBagScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetBagScRsp", {
equipmentList: [],
materialList: [],
relicList: [],
retcode: 0,
rogueItemList: [],
waitDelResourceList: []
} as GetBagScRsp);
}

View File

@ -0,0 +1,13 @@
import { GetBasicInfoScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetBasicInfoScRsp", {
curDay: 1,
exchangeTimes: 0,
retcode: 0,
nextRecoverTime: Math.round(new Date().getTime() / 1000) + 100000,
weekCocoonFinishedCount: 0
} as GetBasicInfoScRsp)
}

View File

@ -0,0 +1,10 @@
import { GetChallengeScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetChallengeScRsp", {
retcode: 0,
challengeList: []
} as GetChallengeScRsp);
}

View File

@ -0,0 +1,11 @@
import { GetChallengeRaidInfoScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetChallengeRaidInfoScRsp", {
retcode: 0,
challengeRaidList: [],
takenRewardIdList: []
} as GetChallengeRaidInfoScRsp);
}

View File

@ -0,0 +1,24 @@
import { AvatarType, BattleEndStatus, GetCurBattleInfoScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetCurBattleInfoScRsp", {
retcode: 0,
avatarList: [{
avatarType: AvatarType.AVATAR_FORMAL_TYPE,
id: 1001,
level: 1,
rank: 1,
index: 1,
hp: 100,
sp: 100,
promotion: 1,
}],
stageId: 10000,
logicRandomSeed: 2503,
battleInfo: {},
lastEndStatus: BattleEndStatus.BATTLE_END_WIN,
lastEventId: 0
} as GetCurBattleInfoScRsp);
}

View File

@ -0,0 +1,25 @@
import { AvatarType, GetCurLineupDataCsReq, GetCurLineupDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetCurLineupDataScRsp", {
retcode: 0,
lineup: {
avatarList: [{
slot: 1,
avatarType: AvatarType.AVATAR_FORMAL_TYPE,
id: 1001,
hp: 100,
sp: 100,
satiety: 100
}],
index: 1,
isVirtual: false,
mp: 100,
name: "lineuprspname",
planeId: 10000,
leaderSlot: 1
}
} as GetCurLineupDataScRsp);
}

View File

@ -0,0 +1,19 @@
import { GetCurSceneInfoScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetCurSceneInfoScRsp", {
retcode: 0,
scene: {
planeId: 10000,
floorId: 10000000,
entityList: [],
entityBuffList: [],
entryId: 10001,
envBuffList: [],
gameModeType: 1,
lightenSectionList: []
},
} as unknown as GetCurSceneInfoScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetDialogueEventDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetDialogueEventDataScRsp", {
dialogueEventList: [],
retcode: 0
} as GetDialogueEventDataScRsp);
}

View File

@ -0,0 +1,12 @@
import { GetExpeditionDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetExpeditionDataScRsp", {
retcode: 0,
expedtionList: [],
unlockedExpeditionIdList: [],
teamCount: 4
} as GetExpeditionDataScRsp);
}

View File

@ -0,0 +1,9 @@
import { GetFirstTalkNpcScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetFirstTalkNpcScRsp", {
retcode: 0,
} as GetFirstTalkNpcScRsp);
}

View File

@ -0,0 +1,19 @@
import { Gender, GetHeroBasicTypeInfoScRsp, HeroBasicType } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetHeroBasicTypeInfoScRsp", {
retcode: 0,
gender: Gender.GenderMan,
basicTypeInfoList: [{
basicType: HeroBasicType.BoyMage,
rank: 1,
skillTreeList: []
}],
curBasicType: HeroBasicType.BoyMage,
heroPathList: [],
isPlayerInfoModified: false,
isGenderModified: false
} as GetHeroBasicTypeInfoScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetHeroPathScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetHeroPathScRsp", {
retcode: 0,
heroPathList: []
} as GetHeroPathScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetLevelRewardTakenListScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetLevelRewardTakenListScRsp", {
retcode: 0,
takenLevelList: []
} as GetLevelRewardTakenListScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetLoginActivityScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetLoginActivityScRsp", {
retcode: 0,
loginActivityList: []
} as GetLoginActivityScRsp);
}

View File

@ -0,0 +1,14 @@
import { GetMailScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetMailScRsp", {
retcode: 0,
mailList: [],
noticeMailList: [],
start: 0,
totalNum: 0,
isEnd: false
} as GetMailScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetMazeTimeOfDayScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetMazeTimeOfDayScRsp", {
retcode: 0,
mazeTimeOfDayMap: {}
} as GetMazeTimeOfDayScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetMissionDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetMissionDataScRsp", {
retcode: 0,
missionList: []
} as unknown as GetMissionDataScRsp);
}

View File

@ -0,0 +1,10 @@
import { GetMissionEventDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetMissionEventDataScRsp", {
retcode: 0,
missionEventList: []
} as unknown as GetMissionEventDataScRsp);
}

View File

@ -0,0 +1,35 @@
import { GetMissionStatusCsReq, GetMissionStatusScRsp, MissionStatus } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
const body = packet.body as GetMissionStatusCsReq;
const dataObj = {
retcode: 0,
finishedMainMissionIdList: [],
missionEventStatusList: [],
subMissionStatusList: [],
unfinishedMainMissionIdList: []
} as GetMissionStatusScRsp;
body.mainMissionIdList.forEach(id => { dataObj.unfinishedMainMissionIdList.push(id); });
body.missionEventIdList.forEach(id => {
dataObj.missionEventStatusList.push({
id: id,
progress: 0,
status: MissionStatus.MISSION_DOING
});
});
body.subMissionIdList.forEach(id => {
dataObj.subMissionStatusList.push({
id: id,
progress: 0,
status: MissionStatus.MISSION_DOING
});
});
session.send("GetMissionStatusScRsp", dataObj);
}

View File

@ -0,0 +1,10 @@
import { GetNpcStatusScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetNpcStatusScRsp", {
retcode: 0,
messageStatusList: []
} as GetNpcStatusScRsp);
}

View File

@ -0,0 +1,12 @@
import { GetQuestDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetQuestDataScRsp", {
questList: [],
retcode: 0,
takenAchievementLevelList: [],
totalAchievementExp: 1,
} as GetQuestDataScRsp);
}

View File

@ -0,0 +1,21 @@
import { GetRogueInfoScRsp, RogueStatus } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetRogueInfoScRsp", {
retcode: 0,
rogueInfo: {
status: RogueStatus.ROGUE_STATUS_DOING,
rogueCoin: 1,
baseAvatarIdList: [1001],
rogueStamina: 100,
reviveCount: 1,
recoverStaminaCount: 1,
isRecordSaved: true,
beginTime: Math.round(Date.now() / 1000),
endTime: Math.round(Date.now() / 1000) + 3600,
isWin: true,
}
} as GetRogueInfoScRsp);
}

View File

@ -0,0 +1,18 @@
import { GetSpringRecoverDataScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
session.send("GetSpringRecoverDataScRsp", {
retcode: 0,
healPoolInfo: {
healPool: 0,
refreshTime: 600,
},
springRecoverConfig: {
autoRecoverHp: true,
defaultHp: 100,
avatarPresetHpList: []
}
} as GetSpringRecoverDataScRsp);
}

View File

@ -0,0 +1,6 @@
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
// We actually don't need to handle this
}

View File

@ -1,4 +1,4 @@
import { PlayerLoginCsReq, PlayerLoginScRsp } from "../../data/proto/StarRail"; import { PlayerBasicInfo, PlayerLoginCsReq, PlayerLoginScRsp } from "../../data/proto/StarRail";
import Player from "../../db/Player"; import Player from "../../db/Player";
import Packet from "../kcp/Packet"; import Packet from "../kcp/Packet";
import Session from "../kcp/Session"; import Session from "../kcp/Session";
@ -37,10 +37,12 @@ export default async function handle(session: Session, packet: Packet) {
} }
session.send("PlayerLoginScRsp", { session.send("PlayerLoginScRsp", {
basicInfo: plr!.db.basicInfo, basicInfo: plr!.db.basicInfo as PlayerBasicInfo,
isNewPlayer: true, isNewPlayer: false,
stamina: 100, stamina: 100,
curTimezone: body.clientTimeZone, retcode: 0,
serverTimestampMs: Math.round(new Date().getTime() / 1000).toString(), isRelay: false,
} as unknown as PlayerLoginScRsp); loginRandom: Number(body.loginRandom),
serverTimestampMs: Math.round(new Date().getTime() / 1000),
} as PlayerLoginScRsp);
} }

View File

@ -0,0 +1,8 @@
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
import SRServer from "../kcp/SRServer";
export default async function handle(session: Session, packet: Packet) {
// Remove from session list
SRServer.getInstance().sessions.delete(`${session.ctx.address}:${session.ctx.port}`);
}

View File

@ -0,0 +1,13 @@
import { SyncTimeCsReq, SyncTimeScRsp } from "../../data/proto/StarRail";
import Packet from "../kcp/Packet";
import Session from "../kcp/Session";
export default async function handle(session: Session, packet: Packet) {
const body = packet.body as SyncTimeCsReq;
session.send("SyncTimeScRsp", {
retcode: 0,
clientTimeMs: body.clientTimeMs,
serverTimeMs: Math.round(new Date().getTime() / 1000)
} as SyncTimeScRsp);
}

View File

@ -0,0 +1,51 @@
export function compareTwoStrings(first: string, second: string) {
first = first.replace(/\s+/g, '')
second = second.replace(/\s+/g, '')
if (first === second) return 1; // identical or empty
if (first.length < 2 || second.length < 2) return 0; // if either is a 0-letter or 1-letter string
const firstBigrams = new Map();
for (let i = 0; i < first.length - 1; i++) {
const bigram = first.substring(i, i + 2);
const count = firstBigrams.has(bigram)
? firstBigrams.get(bigram) + 1
: 1;
firstBigrams.set(bigram, count);
}
let intersectionSize = 0;
for (let i = 0; i < second.length - 1; i++) {
const bigram = second.substring(i, i + 2);
const count = firstBigrams.has(bigram)
? firstBigrams.get(bigram)
: 0;
if (count > 0) {
firstBigrams.set(bigram, count - 1);
intersectionSize++;
}
}
return (2.0 * intersectionSize) / (first.length + second.length - 2);
}
export default function findBestMatch(mainString: string, targetStrings: string[]) {
const ratings = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetStrings.length; i++) {
const currentTargetString = targetStrings[i];
const currentRating = compareTwoStrings(mainString, currentTargetString)
ratings.push({ target: currentTargetString, rating: currentRating })
if (currentRating > ratings[bestMatchIndex].rating) {
bestMatchIndex = i
}
}
const bestMatch = ratings[bestMatchIndex]
return { ratings: ratings, bestMatch: bestMatch, bestMatchIndex: bestMatchIndex };
}