From 76a1273128a4e819f7b3d625a02585582cf67b4b Mon Sep 17 00:00:00 2001 From: Dang Hoang Phuc <13364457+phuchptty@users.noreply.github.com> Date: Fri, 5 Aug 2022 03:27:30 +0700 Subject: [PATCH 1/6] feat: add gacha banner id (#45) --- src/util/Banner.ts | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/util/Banner.ts b/src/util/Banner.ts index 0cc9e99..98a1b14 100644 --- a/src/util/Banner.ts +++ b/src/util/Banner.ts @@ -1,6 +1,7 @@ import fs from 'fs'; -import { resolve } from 'path'; +import {resolve} from 'path'; import Logger from './Logger'; + const c = new Logger("Banner"); type Banner = { @@ -18,15 +19,21 @@ function r(...args: string[]) { export default class Banners { public static config: Banner[]; - public static init(){ + public static init() { Banners.readConfig(); } - private static readConfig(){ + private static readConfig() { let config: Banner[]; - const defaultConfig: Banner[] = [ - { - gachaId: 1001, + + const defaultConfig: Banner[] = []; + + // TODO: figure where is GachaBasicInfoConfigExcelTable. Temporary hardcode + const bannersID = [1001, 2001, 2002, 3001, 3002, 4001] + + for (let i = 0; i < bannersID.length; i++) { + defaultConfig.push({ + gachaId: bannersID[i], detailWebview: "", rateUpItems4: [ 1001, 1103 @@ -35,13 +42,13 @@ export default class Banners { 1102 ], costItemId: 101 // Star Rail Pass - } as Banner - ]; + } as Banner) + } try { config = JSON.parse(fs.readFileSync(r('../../banners.json')).toString()); - - for(const [index, gachaBanner] of Object.entries(config)){ + + for (const [index, gachaBanner] of Object.entries(config)) { const missing = Object.keys(defaultConfig[0]).filter(key => !gachaBanner.hasOwnProperty(key)); if (missing.length > 0) { c.log(`Missing ${missing.join(', ')}, using default values.`); @@ -54,7 +61,7 @@ export default class Banners { Banners.updateConfig(defaultConfig); } } - + private static updateConfig(config: Banner[]) { this.config = config; fs.writeFileSync(r('../../banners.json'), JSON.stringify(config, null, 2)); From 50c51738aaaf2b803834cf962590cdbe9bab8e05 Mon Sep 17 00:00:00 2001 From: GanyusLeftHorn <1244229+GanyusLeftHorn@users.noreply.github.com> Date: Thu, 4 Aug 2022 22:54:35 +0200 Subject: [PATCH 2/6] Fix Cyclic Dependency Error (#43) --- src/commands/scene.ts | 8 ++--- src/db/Player.ts | 37 ++++++++++------------ src/server/packets/JoinLineupCsReq.ts | 25 --------------- src/server/packets/SceneEntityMoveCsReq.ts | 6 +++- 4 files changed, 24 insertions(+), 52 deletions(-) diff --git a/src/commands/scene.ts b/src/commands/scene.ts index ed42395..8f95087 100644 --- a/src/commands/scene.ts +++ b/src/commands/scene.ts @@ -20,11 +20,9 @@ export default async function handle(command: Command) { if (!planeID) return c.log("Usage: /scene "); - Interface.target.player.db.posData = { - floorID: planeID.StartFloorID, - planeID: planeID.PlaneID, - pos: Interface.target.player.db.posData.pos - }; + // Update scene information on player. + Interface.target.player.db.posData.planeID = planeID!.PlaneID; + Interface.target.player.db.posData.floorID = planeID!.StartFloorID; await Interface.target.player.save() //ty for tamilpp25 scene diff --git a/src/db/Player.ts b/src/db/Player.ts index 7b054e3..1d1c560 100644 --- a/src/db/Player.ts +++ b/src/db/Player.ts @@ -43,7 +43,11 @@ interface PlayerI { posData: { floorID: number; planeID: number; - pos: Vector; + pos: { + x: number, + y: number, + z: number + }; } } @@ -52,7 +56,7 @@ export default class Player { public readonly scene: Scene; private inventory!: Inventory; - private constructor(readonly session: Session, public db: PlayerI) { + private constructor(readonly session: Session, public readonly db: PlayerI) { this.uid = db._id; this.scene = new Scene(this); } @@ -155,34 +159,25 @@ export default class Player { } }, banned: false - } as PlayerI - - const baseLineup = { - avatarList: [1001], - extraLineupType: ExtraLineupType.LINEUP_NONE, - index: 0, - isVirtual: false, - leaderSlot: 0, - mp: 100, // ?? Not sure what this is - name: "", - planeId: 10001 - } + } as PlayerI; const LINEUPS = 6; for (let i = 0; i < LINEUPS; i++) { - const copy = { - ...baseLineup, + const l : LineupI = { + avatarList: [1001], + extraLineupType: ExtraLineupType.LINEUP_NONE, index: i, - name: `Team ${i}` + isVirtual: false, + leaderSlot: 0, + mp: 100, + name: `Team ${i}`, + planeId: 10001 }; - dataObj.lineup.lineups[i] = copy; + dataObj.lineup.lineups[i] = l; } const player = new Player(session, dataObj); - await Avatar.addAvatarToPlayer(player, 1001); - // await Avatar.create(uid, 1001, 0); - // Save to database and return. await db.set("players", dataObj); diff --git a/src/server/packets/JoinLineupCsReq.ts b/src/server/packets/JoinLineupCsReq.ts index 0c72416..c394b50 100644 --- a/src/server/packets/JoinLineupCsReq.ts +++ b/src/server/packets/JoinLineupCsReq.ts @@ -11,31 +11,6 @@ export default async function handle(session: Session, packet: Packet) { // Replace avatar in the player's lineup. const slot = body.slot ?? 0; session.player.db.lineup.lineups[session.player.db.lineup.curIndex].avatarList[slot] = body.baseAvatarId; - - /* - - let lineup = await session.player.getLineup(); - const avatarList = []; - - // What in the fuck is the purpose of this loop supposed to be?! - for (const avatarId in lineup) { - const avatar = await Avatar.fromUID(session.player.db._id, Number(avatarId)); - if (avatar.length === 0) return session.c.warn(`Avatar ${body.baseAvatarId} not found`); - if (avatar) avatarList.push(avatar[0]); - } - - lineup.avatarList[slot] = { - avatarType: AvatarType.AVATAR_FORMAL_TYPE, - hp: 10000, - id: body.baseAvatarId, - satiety: 100, - slot, - sp: 10000 - }; - if (body.extraLineupType) lineup.extraLineupType = body.extraLineupType; - session.player.setLineup(lineup); - */ - await session.player.save(); session.send(SyncLineupNotify, { diff --git a/src/server/packets/SceneEntityMoveCsReq.ts b/src/server/packets/SceneEntityMoveCsReq.ts index dfbe65e..c222884 100644 --- a/src/server/packets/SceneEntityMoveCsReq.ts +++ b/src/server/packets/SceneEntityMoveCsReq.ts @@ -23,7 +23,11 @@ export default async function handle(session: Session, packet: Packet) { entity.pos = motion.pos; if (entity instanceof ActorEntity) { entity.mapLayer = entityMotion.mapLayer; - session.player.db.posData.pos = motion.pos!; + session.player.db.posData.pos = { + x: motion.pos.x, + y: motion.pos.y, + z: motion.pos.z + }; } } From 118df5656d0dcaad9680d263145d568aa3f5c3b6 Mon Sep 17 00:00:00 2001 From: tamilpp25 Date: Fri, 5 Aug 2022 08:49:27 +0530 Subject: [PATCH 3/6] improve scene command (#42) Co-authored-by: TheLostTree <65834918+TheLostTree@users.noreply.github.com> --- src/commands/scene.ts | 42 +++++++++++++++++++++++++------- src/util/excel/MazePlaneExcel.ts | 4 +++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/commands/scene.ts b/src/commands/scene.ts index 8f95087..a869542 100644 --- a/src/commands/scene.ts +++ b/src/commands/scene.ts @@ -11,26 +11,50 @@ export default async function handle(command: Command) { return; } - const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0])) - const uid = Interface.target.player.db._id; + if(command.args.length == 0){ + c.log("Usage: /scene "); + return; + } + + const plane = MazePlaneExcel.fromFloorId(parseInt(command.args[0])) || MazePlaneExcel.fromPlaneId(parseInt(command.args[0])) //Get plane data + let floorId = 10001001 // Default floor data + + if(plane!){ + if(command.args[0].length === 5){//PLANE ID LOGIC + floorId = plane.StartFloorID; + }else if(command.args[0].length === 8){//FLOOR ID LOGIC + if(plane! && plane.FloorIDList.includes(parseInt(command.args[0]))){ + floorId = parseInt(command.args[0]); + }else{ + c.error("cannot find Scene data!"); + return; + } + }else{ + c.error("Invalid FloorID / PlaneID length!"); + return; + } + }else{ + c.error("cannot find Scene data!"); + return; + } + const posData = Interface.target.player.db.posData; - const lineup2 = await Interface.target.player.getLineup(); - const curAvatarEntity = new ActorEntity(Interface.target.player.scene, lineup2.avatarList[0].id, posData.pos); + const lineup = await Interface.target.player.getLineup(); + const curAvatarEntity = new ActorEntity(Interface.target.player.scene, lineup.leaderSlot, posData.pos); - if (!planeID) return c.log("Usage: /scene "); + const planeId = parseInt(floorId.toString().slice(0,5)); // Update scene information on player. Interface.target.player.db.posData.planeID = planeID!.PlaneID; Interface.target.player.db.posData.floorID = planeID!.StartFloorID; await Interface.target.player.save() - //ty for tamilpp25 scene Interface.target.send(GetCurSceneInfoScRsp, { retcode: 0, scene: { - planeId: planeID.PlaneID, - floorId: planeID.StartFloorID, + planeId: planeId, + floorId: floorId, entityList: [ curAvatarEntity ], @@ -45,5 +69,5 @@ export default async function handle(command: Command) { Interface.target.sync(); - c.log(`Scene set to PlaneID: ${planeID.PlaneID}`); + c.log(`Scene set to floorId: ${floorId}`); } diff --git a/src/util/excel/MazePlaneExcel.ts b/src/util/excel/MazePlaneExcel.ts index 03d3bd6..be8ecaf 100644 --- a/src/util/excel/MazePlaneExcel.ts +++ b/src/util/excel/MazePlaneExcel.ts @@ -55,6 +55,10 @@ export default class MazePlaneExcel { public static fromPlaneId(planeId: number): MazePlaneExcelTableEntry { return MazePlaneExcelTable[planeId.toString()]; } + + public static fromFloorId(floorId: number): MazePlaneExcelTableEntry { + return MazePlaneExcelTable[floorId.toString().slice(0,5)]; + } public static getEntry(entryId: number): MapEntryExcelTableEntry { return MapEntryExcelTable[entryId.toString()]; From 2fe4f6a2ea989f73e0d783fde3e2a7d1f5dc566d Mon Sep 17 00:00:00 2001 From: GanyusLeftHorn <1244229+GanyusLeftHorn@users.noreply.github.com> Date: Fri, 5 Aug 2022 05:28:46 +0200 Subject: [PATCH 4/6] Implement Character Level-up and Ascension (#48) --- src/commands/item.ts | 14 ++-- src/db/Avatar.ts | 17 +++-- src/db/Inventory.ts | 21 +++++- src/db/Player.ts | 6 +- src/server/packets/AvatarExpUpCsReq.ts | 88 ++++++++++++++++++++++++ src/server/packets/PromoteAvatarCsReq.ts | 40 +++++++++++ src/util/excel/AvatarExpItemExcel.ts | 20 ++++++ src/util/excel/AvatarPromotionExcel.ts | 20 ++++++ src/util/excel/ExpTypeExcel.ts | 20 ++++++ 9 files changed, 232 insertions(+), 14 deletions(-) create mode 100644 src/server/packets/AvatarExpUpCsReq.ts create mode 100644 src/server/packets/PromoteAvatarCsReq.ts create mode 100644 src/util/excel/AvatarExpItemExcel.ts create mode 100644 src/util/excel/AvatarPromotionExcel.ts create mode 100644 src/util/excel/ExpTypeExcel.ts diff --git a/src/commands/item.ts b/src/commands/item.ts index 39fcd14..7d41bd5 100644 --- a/src/commands/item.ts +++ b/src/commands/item.ts @@ -17,8 +17,8 @@ export default async function handle(command: Command) { let count: number = 1; let level: number = 1; - let rank: number = 1; - let promotion: number = 1; + let rank: number = 0; + let promotion: number = 0; for (let i = 2; i < command.args.length; i++) { const arg = command.args[i]; @@ -52,6 +52,9 @@ export default async function handle(command: Command) { break; } } + + // Sync session. + await player.session.sync(); } async function handleGive(player: Player, itemId: number, count:number, level: number, rank: number, promotion: number) { @@ -96,9 +99,12 @@ async function handleGiveAll(player: Player) { const inventory = await player.getInventory(); for (const entry of ItemExcel.all()) { - const count = entry.ItemType == "Material" ? 100 : 1; + const count = + (entry.ItemType == "Material") ? 1000 : + (entry.ItemType == "Virtual") ? 10_000_000 : + 1; await inventory.addItem(entry.ID, count); } - + c.log(`All materials added to ${player.uid}`); } \ No newline at end of file diff --git a/src/db/Avatar.ts b/src/db/Avatar.ts index 363ebe0..d6dddfc 100644 --- a/src/db/Avatar.ts +++ b/src/db/Avatar.ts @@ -49,9 +49,9 @@ export default class Avatar { baseAvatarId: 1001, avatarType: AvatarType.AVATAR_FORMAL_TYPE, level: 1, - exp: 1, - promotion: 1, - rank: 1, + exp: 0, + promotion: 0, + rank: 0, equipmentUniqueId: 20003, equipRelicList: [], skilltreeList: [], @@ -111,9 +111,9 @@ export default class Avatar { baseAvatarId: baseAvatarId, avatarType: AvatarType.AVATAR_FORMAL_TYPE, level: 1, - exp: 1, - promotion: 1, - rank: 1, + exp: 0, + promotion: 0, + rank: 0, equipmentUniqueId: 20003, equipRelicList: [], skilltreeList: [], @@ -144,6 +144,11 @@ export default class Avatar { return res; } + public async save() { + const db = Database.getInstance(); + await db.update("avatars", { ownerUid: this.player.uid, baseAvatarId: this.db.baseAvatarId }, this.db); + } + /******************************************************************************** Get avatar info. ********************************************************************************/ diff --git a/src/db/Inventory.ts b/src/db/Inventory.ts index 696de14..3aa3787 100644 --- a/src/db/Inventory.ts +++ b/src/db/Inventory.ts @@ -101,13 +101,24 @@ export default class Inventory { } switch (itemData.ItemType) { - case "Virtual": return 0; // ToDo: Handle virtual items. + case "Virtual": return this.getVirtualItemCount(id); case "Material": return this.db.materials[id] ?? 0; } return 0; } + private getVirtualItemCount(id: number) : number { + // ToDo: Figure out which virtual item ID is what. + switch (id) { + case 2: + return this.player.db.basicInfo.scoin; + break; + } + + return 0; + } + /******************************************************************************** Add items to the inventory. ********************************************************************************/ @@ -151,6 +162,14 @@ export default class Inventory { */ public async addVirtualItem(id: number, count: number) { // ToDo: Figure out which virtual item ID is what. + switch (id) { + case 2: + this.player.db.basicInfo.scoin += count; + break; + } + + // Save. + this.player.save(); } /** diff --git a/src/db/Player.ts b/src/db/Player.ts index 1d1c560..62f6efc 100644 --- a/src/db/Player.ts +++ b/src/db/Player.ts @@ -137,13 +137,13 @@ export default class Player { heroBasicType: HeroBasicType.BoyWarrior, basicInfo: { exp: 0, - level: 1, + level: 70, hcoin: 0, mcoin: 0, nickname: acc.name, scoin: 0, - stamina: 100, - worldLevel: 1, + stamina: 180, + worldLevel: 6, }, lineup: { curIndex: 0, diff --git a/src/server/packets/AvatarExpUpCsReq.ts b/src/server/packets/AvatarExpUpCsReq.ts new file mode 100644 index 0000000..8bac1b3 --- /dev/null +++ b/src/server/packets/AvatarExpUpCsReq.ts @@ -0,0 +1,88 @@ +import { AvatarExpUpCsReq, AvatarExpUpScRsp } from "../../data/proto/StarRail"; +import Avatar from "../../db/Avatar"; +import { PayItemData } from "../../db/Inventory"; +import AvatarExcel from "../../util/excel/AvatarExcel"; +import AvatarExpItemExcel from "../../util/excel/AvatarExpItemExcel"; +import AvatarPromotionExcel from "../../util/excel/AvatarPromotionExcel"; +import ExpTypeExcel from "../../util/excel/ExpTypeExcel"; +import Packet from "../kcp/Packet"; +import Session from "../kcp/Session"; + +export default async function handle(session: Session, packet: Packet) { + const body = packet.body as AvatarExpUpCsReq; + const inventory = await session.player.getInventory(); + + // Get the target avatar. + const avatarId = body.baseAvatarId; + const avatar = await Avatar.loadAvatarForPlayer(session.player, avatarId); + const avatarExcelData = AvatarExcel.fromId(avatarId); + + // Determine the next level cap based on the avatar's current promotion. + const levelCap = AvatarPromotionExcel.fromId(`${avatarId}:${avatar.db.promotion}`).MaxLevel; + + // Determine the EXP we get from the consumed items. + let exp = 0; + const costMaterialList = []; + for (const item of body.itemCost!.itemList) { + // Determine amount of EXP given by that item. + // We know that the cost items given in this Req will be `PileItem`s. + const expPerItem = AvatarExpItemExcel.fromId(item.pileItem!.itemId).Exp; + + // Add EXP for the number of items consumed. + exp += expPerItem * item.pileItem!.itemNum; + + // Add material to cost. + costMaterialList.push({ id: item.pileItem!.itemId, count: item.pileItem!.itemNum } as PayItemData); + } + + // Determine cost, which is always 10% of EXP, and add to the list of cost materials. + const coinCost = exp * 0.1; + costMaterialList.push({ id: 2, count: coinCost } as PayItemData); + + // Try consuming materials. + const success = await inventory.payItems(costMaterialList); + if (!success) { + // ToDo: Correct retcode. + session.send(AvatarExpUpScRsp, { retcode: 1, returnItemList: [] } as AvatarExpUpScRsp); + return; + } + + await inventory.save(); + + // Cost has been paid - now level up. + let currentAvatarExp = avatar.db.exp + exp; + let nextRequiredExp = ExpTypeExcel.fromId(`${avatarExcelData.ExpGroup}:${avatar.db.level}`).Exp; + while (currentAvatarExp >= nextRequiredExp && avatar.db.level < levelCap) { + // Increase level. + avatar.db.level++; + + // Deduct EXP necessary for this level. + currentAvatarExp -= nextRequiredExp; + + // Determine EXP necessary for the next level. + nextRequiredExp = ExpTypeExcel.fromId(`${avatarExcelData.ExpGroup}:${avatar.db.level}`).Exp; + } + + // Calculate the character's new EXP and any excess EXP. + let excessExp = 0; + if (avatar.db.level == levelCap && currentAvatarExp >= nextRequiredExp) { + avatar.db.exp = nextRequiredExp; + excessExp = currentAvatarExp - nextRequiredExp; + } + else { + avatar.db.exp = currentAvatarExp; + } + + // Save. + await avatar.save(); + + // ToDo: Handle return items. + + // Done. Sync and send response. + await session.sync(); + + session.send(AvatarExpUpScRsp, { + retcode: 0, + returnItemList: [] + } as AvatarExpUpScRsp); +} \ No newline at end of file diff --git a/src/server/packets/PromoteAvatarCsReq.ts b/src/server/packets/PromoteAvatarCsReq.ts new file mode 100644 index 0000000..dfb8a30 --- /dev/null +++ b/src/server/packets/PromoteAvatarCsReq.ts @@ -0,0 +1,40 @@ +import { PromoteAvatarCsReq, PromoteAvatarScRsp } from "../../data/proto/StarRail"; +import Avatar from "../../db/Avatar"; +import { PayItemData } from "../../db/Inventory"; +import AvatarExcel from "../../util/excel/AvatarExcel"; +import AvatarExpItemExcel from "../../util/excel/AvatarExpItemExcel"; +import AvatarPromotionExcel from "../../util/excel/AvatarPromotionExcel"; +import ExpTypeExcel from "../../util/excel/ExpTypeExcel"; +import Packet from "../kcp/Packet"; +import Session from "../kcp/Session"; + +export default async function handle(session: Session, packet: Packet) { + const body = packet.body as PromoteAvatarCsReq; + const inventory = await session.player.getInventory(); + + // Get the target avatar. + const avatarId = body.baseAvatarId; + const avatar = await Avatar.loadAvatarForPlayer(session.player, avatarId); + const promotionExcelData = AvatarPromotionExcel.fromId(`${avatarId}:${avatar.db.promotion}`); + + // Build list of consumed items. We take this from the excel, instead of the Req. + const costMaterialList = promotionExcelData.PromotionCostList.map(c => { return { id: c.ItemID, count: c.ItemNum } as PayItemData }); + + // Try consuming materials. + const success = await inventory.payItems(costMaterialList); + if (!success) { + // ToDo: Correct retcode. + session.send(PromoteAvatarScRsp, { retcode: 1 } as PromoteAvatarScRsp); + return; + } + + await inventory.save(); + + // Promote the avatar and save. + avatar.db.promotion++; + await avatar.save(); + + // Done. Sync and send response. + await session.sync(); + session.send(PromoteAvatarScRsp, { retcode: 0 } as PromoteAvatarScRsp); +} \ No newline at end of file diff --git a/src/util/excel/AvatarExpItemExcel.ts b/src/util/excel/AvatarExpItemExcel.ts new file mode 100644 index 0000000..27d1036 --- /dev/null +++ b/src/util/excel/AvatarExpItemExcel.ts @@ -0,0 +1,20 @@ +import _AvatarExpItemConfigExcelTable from "../../data/excel/AvatarExpItemConfigExcelTable.json"; +type AvatarExpItemConfigExcelTableEntry = typeof _AvatarExpItemConfigExcelTable[keyof typeof _AvatarExpItemConfigExcelTable] +const AvatarExpItemConfigExcelTable = _AvatarExpItemConfigExcelTable as { [key: string]: AvatarExpItemConfigExcelTableEntry }; + +export default class AvatarExpItemExcel { + private constructor() { + } + + public static all() : AvatarExpItemConfigExcelTableEntry[] { + return Object.values(AvatarExpItemConfigExcelTable); + } + + public static fromId(id: number) : AvatarExpItemConfigExcelTableEntry { + return AvatarExpItemConfigExcelTable[id]; + } + + public static fromIds(ids: number[]): AvatarExpItemConfigExcelTableEntry[] { + return ids.map(id => AvatarExpItemExcel.fromId(id)); + } +} \ No newline at end of file diff --git a/src/util/excel/AvatarPromotionExcel.ts b/src/util/excel/AvatarPromotionExcel.ts new file mode 100644 index 0000000..18c1bf5 --- /dev/null +++ b/src/util/excel/AvatarPromotionExcel.ts @@ -0,0 +1,20 @@ +import _AvatarPromotionExcelTable from "../../data/excel/AvatarPromotionExcelTable.json"; +type AvatarPromotionExcelTableEntry = typeof _AvatarPromotionExcelTable[keyof typeof _AvatarPromotionExcelTable] +const AvatarPromotionExcelTable = _AvatarPromotionExcelTable as { [key: string]: AvatarPromotionExcelTableEntry }; + +export default class AvatarPromotionExcel { + private constructor() { + } + + public static all() : AvatarPromotionExcelTableEntry[] { + return Object.values(AvatarPromotionExcelTable); + } + + public static fromId(id: string) : AvatarPromotionExcelTableEntry { + return AvatarPromotionExcelTable[id]; + } + + public static fromIds(ids: string[]): AvatarPromotionExcelTableEntry[] { + return ids.map(id => AvatarPromotionExcel.fromId(id)); + } +} \ No newline at end of file diff --git a/src/util/excel/ExpTypeExcel.ts b/src/util/excel/ExpTypeExcel.ts new file mode 100644 index 0000000..02591f0 --- /dev/null +++ b/src/util/excel/ExpTypeExcel.ts @@ -0,0 +1,20 @@ +import _ExpTypeExcelTable from "../../data/excel/ExpTypeExcelTable.json"; +type ExpTypeExcelTableEntry = typeof _ExpTypeExcelTable[keyof typeof _ExpTypeExcelTable] +const ExpTypeExcelTable = _ExpTypeExcelTable as { [key: string]: ExpTypeExcelTableEntry }; + +export default class ExpTypeExcel { + private constructor() { + } + + public static all() : ExpTypeExcelTableEntry[] { + return Object.values(ExpTypeExcelTable); + } + + public static fromId(id: string) : ExpTypeExcelTableEntry { + return ExpTypeExcelTable[id]; + } + + public static fromIds(ids: string[]): ExpTypeExcelTableEntry[] { + return ids.map(id => ExpTypeExcel.fromId(id)); + } +} \ No newline at end of file From 016faec86b7dd60fb8c6251edc6e8c9e23326e27 Mon Sep 17 00:00:00 2001 From: GanyusLeftHorn <1244229+GanyusLeftHorn@users.noreply.github.com> Date: Fri, 5 Aug 2022 06:56:28 +0200 Subject: [PATCH 5/6] Revert "improve scene command (#42)" (#49) This reverts commit 118df5656d0dcaad9680d263145d568aa3f5c3b6. --- src/commands/scene.ts | 42 +++++++------------------------- src/util/excel/MazePlaneExcel.ts | 4 --- 2 files changed, 9 insertions(+), 37 deletions(-) diff --git a/src/commands/scene.ts b/src/commands/scene.ts index a869542..8f95087 100644 --- a/src/commands/scene.ts +++ b/src/commands/scene.ts @@ -11,50 +11,26 @@ export default async function handle(command: Command) { return; } - if(command.args.length == 0){ - c.log("Usage: /scene "); - return; - } - - const plane = MazePlaneExcel.fromFloorId(parseInt(command.args[0])) || MazePlaneExcel.fromPlaneId(parseInt(command.args[0])) //Get plane data - let floorId = 10001001 // Default floor data - - if(plane!){ - if(command.args[0].length === 5){//PLANE ID LOGIC - floorId = plane.StartFloorID; - }else if(command.args[0].length === 8){//FLOOR ID LOGIC - if(plane! && plane.FloorIDList.includes(parseInt(command.args[0]))){ - floorId = parseInt(command.args[0]); - }else{ - c.error("cannot find Scene data!"); - return; - } - }else{ - c.error("Invalid FloorID / PlaneID length!"); - return; - } - }else{ - c.error("cannot find Scene data!"); - return; - } - + const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0])) + const uid = Interface.target.player.db._id; const posData = Interface.target.player.db.posData; - const lineup = await Interface.target.player.getLineup(); - const curAvatarEntity = new ActorEntity(Interface.target.player.scene, lineup.leaderSlot, posData.pos); + const lineup2 = await Interface.target.player.getLineup(); + const curAvatarEntity = new ActorEntity(Interface.target.player.scene, lineup2.avatarList[0].id, posData.pos); - const planeId = parseInt(floorId.toString().slice(0,5)); + if (!planeID) return c.log("Usage: /scene "); // Update scene information on player. Interface.target.player.db.posData.planeID = planeID!.PlaneID; Interface.target.player.db.posData.floorID = planeID!.StartFloorID; await Interface.target.player.save() + //ty for tamilpp25 scene Interface.target.send(GetCurSceneInfoScRsp, { retcode: 0, scene: { - planeId: planeId, - floorId: floorId, + planeId: planeID.PlaneID, + floorId: planeID.StartFloorID, entityList: [ curAvatarEntity ], @@ -69,5 +45,5 @@ export default async function handle(command: Command) { Interface.target.sync(); - c.log(`Scene set to floorId: ${floorId}`); + c.log(`Scene set to PlaneID: ${planeID.PlaneID}`); } diff --git a/src/util/excel/MazePlaneExcel.ts b/src/util/excel/MazePlaneExcel.ts index be8ecaf..03d3bd6 100644 --- a/src/util/excel/MazePlaneExcel.ts +++ b/src/util/excel/MazePlaneExcel.ts @@ -55,10 +55,6 @@ export default class MazePlaneExcel { public static fromPlaneId(planeId: number): MazePlaneExcelTableEntry { return MazePlaneExcelTable[planeId.toString()]; } - - public static fromFloorId(floorId: number): MazePlaneExcelTableEntry { - return MazePlaneExcelTable[floorId.toString().slice(0,5)]; - } public static getEntry(entryId: number): MapEntryExcelTableEntry { return MapEntryExcelTable[entryId.toString()]; From 4e0b5a3064411ab1c4c8060cfff4c3a170df3427 Mon Sep 17 00:00:00 2001 From: memetrollsXD Date: Fri, 5 Aug 2022 07:35:10 +0200 Subject: [PATCH 6/6] Implement some packets for character screen (#44) * implement eidolon levelup * implement changing weapons --- src/server/packets/DoGachaCsReq.ts | 2 +- src/server/packets/DressAvatarCsReq.ts | 16 +++++++++ src/server/packets/RankUpAvatarCsReq.ts | 44 +++++++++++++++++++++++ src/server/packets/StartChallengeCsReq.ts | 4 +-- 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/server/packets/DressAvatarCsReq.ts create mode 100644 src/server/packets/RankUpAvatarCsReq.ts diff --git a/src/server/packets/DoGachaCsReq.ts b/src/server/packets/DoGachaCsReq.ts index 2798719..eb0dbb0 100644 --- a/src/server/packets/DoGachaCsReq.ts +++ b/src/server/packets/DoGachaCsReq.ts @@ -16,7 +16,7 @@ export default async function handle(session: Session, packet: Packet) { if (!success) { session.send(DoGachaScRsp, { - retcode: 1 + retcode: 1301 } as DoGachaScRsp); } diff --git a/src/server/packets/DressAvatarCsReq.ts b/src/server/packets/DressAvatarCsReq.ts new file mode 100644 index 0000000..7d72746 --- /dev/null +++ b/src/server/packets/DressAvatarCsReq.ts @@ -0,0 +1,16 @@ +import { DressAvatarCsReq, DressAvatarScRsp } from "../../data/proto/StarRail"; +import Avatar from "../../db/Avatar"; +import Packet from "../kcp/Packet"; +import Session from "../kcp/Session"; + +export default async function handle(session: Session, packet: Packet) { + const body = packet.body as DressAvatarCsReq; + + const avatar = await Avatar.loadAvatarForPlayer(session.player, body.baseAvatarId); + + avatar.db.equipmentUniqueId = body.equipmentUniqueId; + await avatar.save(); + + session.send(DressAvatarScRsp, { retcode: 0 }); + session.sync(); +} \ No newline at end of file diff --git a/src/server/packets/RankUpAvatarCsReq.ts b/src/server/packets/RankUpAvatarCsReq.ts new file mode 100644 index 0000000..d6093c9 --- /dev/null +++ b/src/server/packets/RankUpAvatarCsReq.ts @@ -0,0 +1,44 @@ +import { RankUpAvatarCsReq, RankUpAvatarScRsp } from "../../data/proto/StarRail"; +import Avatar from "../../db/Avatar"; +import { PayItemData } from "../../db/Inventory"; +import Logger from "../../util/Logger"; +import Packet from "../kcp/Packet"; +import Session from "../kcp/Session"; +const c = new Logger("RankUpAvatarCsReq"); + +export default async function handle(session: Session, packet: Packet) { + const body = packet.body as RankUpAvatarCsReq; + const dataObj: RankUpAvatarScRsp = { + retcode: 0 + }; + + try { + const inv = await session.player.getInventory(); + if (!body.costData) return; + const list = body.costData.itemList; + const arr: Array = []; + + for (let i = 0; i < list.length; i++) { + const item = list[i]; + if (!item.pileItem) continue; + arr.push({ + count: item.pileItem.itemNum, + id: item.pileItem.itemId + }); + } + + if (await inv.payItems(arr)) { + const avatar = await Avatar.loadAvatarForPlayer(session.player, body.baseAvatarId); + avatar.db.rank = body.rank // gidra moment: ez hack + await avatar.save(); + } else { + dataObj.retcode = 1301; + } + } catch (e) { + c.error(e as Error); + dataObj.retcode = 2; + } finally { + session.send(RankUpAvatarScRsp, dataObj); + session.sync(); + } +} \ No newline at end of file diff --git a/src/server/packets/StartChallengeCsReq.ts b/src/server/packets/StartChallengeCsReq.ts index 7c8c5d7..5b7bb92 100644 --- a/src/server/packets/StartChallengeCsReq.ts +++ b/src/server/packets/StartChallengeCsReq.ts @@ -17,14 +17,14 @@ export default async function handle(session: Session, packet: Packet) { rounds: 1, status: ChallengeStatus.CHALLENGE_DOING, killMonsterList: [{ - monsterId: 1001010, + monsterId: 8013010, killNum: 1, }] }, maze: { // ? Data from MappingInfoExcelTable id: 30101, - mapEntryId: 1000, + mapEntryId: 10001, floor: { floorId: 20121001, scene: {