From 22cd1f6ba11e22e702ec380a66068c95b03aa7ba Mon Sep 17 00:00:00 2001 From: GanyusLeftHorn <1244229+GanyusLeftHorn@users.noreply.github.com> Date: Sun, 7 Aug 2022 16:16:40 +0200 Subject: [PATCH] (Only) Enter Forgotten Hall, Set Game Mode, Clean Up Map/Maze Excels (#56) * Implement avatar levelup and promotion. * Clean up maz and map excels, set the correct game mode based on plane type, make forgotten hall enterable. * Remove non-working spawn command. --- src/commands/scene.ts | 9 ++- src/game/Scene.ts | 6 +- src/game/entities/Actor.ts | 17 +++-- src/server/packets/EnterMazeCsReq.ts | 6 +- src/server/packets/GetCurSceneInfoCsReq.ts | 28 ++++--- src/server/packets/GetMazeMapInfoCsReq.ts | 3 +- src/server/packets/SceneEntityMoveCsReq.ts | 1 + src/server/packets/StartChallengeCsReq.ts | 87 +++++++++++++--------- src/util/excel/MapEntryExcel.ts | 24 ++++++ src/util/excel/MazePlaneExcel.ts | 55 +++++--------- src/util/excel/MonsterExcel.ts | 20 +++++ 11 files changed, 157 insertions(+), 99 deletions(-) create mode 100644 src/util/excel/MapEntryExcel.ts create mode 100644 src/util/excel/MonsterExcel.ts diff --git a/src/commands/scene.ts b/src/commands/scene.ts index 8f95087..919c87d 100644 --- a/src/commands/scene.ts +++ b/src/commands/scene.ts @@ -3,6 +3,7 @@ import { ActorEntity } from "../game/entities/Actor"; import Interface, { Command } from "./Interface"; import { GetCurSceneInfoScRsp } from "../data/proto/StarRail"; import MazePlaneExcel from "../util/excel/MazePlaneExcel"; +import MapEntryExcel from "../util/excel/MapEntryExcel"; const c = new Logger("/scene", "blue"); export default async function handle(command: Command) { @@ -11,8 +12,8 @@ export default async function handle(command: Command) { return; } - const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0])) - const uid = Interface.target.player.db._id; + const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0])); + const entryId = MapEntryExcel.fromFloorId(planeID.StartFloorID).ID; const posData = Interface.target.player.db.posData; const lineup2 = await Interface.target.player.getLineup(); @@ -35,9 +36,9 @@ export default async function handle(command: Command) { curAvatarEntity ], entityBuffList: [], - entryId: 10001, + entryId: entryId, envBuffList: [], - gameModeType: 1, + gameModeType: MazePlaneExcel.getGameModeForPlaneType(planeID.PlaneType), lightenSectionList: [] }, } as unknown as GetCurSceneInfoScRsp); diff --git a/src/game/Scene.ts b/src/game/Scene.ts index 2162b90..f04c6e7 100644 --- a/src/game/Scene.ts +++ b/src/game/Scene.ts @@ -13,9 +13,11 @@ export class Scene { public spawnEntity(entity: Entity, silent: boolean = false) { this.entities.set(entity.entityId, entity); if (!silent) { - this.player.session.send(SceneEntityUpdateScNotify, { + const dataObj : SceneEntityUpdateScNotify = { entityList: [entity.getSceneEntityInfo()] - } as SceneEntityUpdateScNotify); + }; + + this.player.session.send(SceneEntityUpdateScNotify, dataObj); } } diff --git a/src/game/entities/Actor.ts b/src/game/entities/Actor.ts index ccd37e5..5c98bc3 100644 --- a/src/game/entities/Actor.ts +++ b/src/game/entities/Actor.ts @@ -10,15 +10,16 @@ export class ActorEntity extends Entity super(scene, pos, rot); } - public getSceneEntityInfo(): SceneEntityInfo { - const sceneEntityInfo = super.getSceneEntityInfo(); - sceneEntityInfo.actor = { - avatarType: AvatarType.AVATAR_FORMAL_TYPE, - baseAvatarId: this.avatarId, - uid: this.scene.player.db._id, - mapLayer: 0 //? + public getSceneActorInfo(): SceneEntityInfo { + return { + ...super.getSceneEntityInfo(), + actor: { + avatarType: AvatarType.AVATAR_FORMAL_TYPE, + baseAvatarId: this.avatarId, + uid: this.scene.player.db._id, + mapLayer: 0 //? + } }; - return sceneEntityInfo; } public getEntityType(): EntityType { diff --git a/src/server/packets/EnterMazeCsReq.ts b/src/server/packets/EnterMazeCsReq.ts index fba4ff6..ebf73d9 100644 --- a/src/server/packets/EnterMazeCsReq.ts +++ b/src/server/packets/EnterMazeCsReq.ts @@ -1,4 +1,5 @@ import { EnterMazeCsReq, EnterMazeScRsp } from "../../data/proto/StarRail"; +import MapEntryExcel from "../../util/excel/MapEntryExcel"; import MazePlaneExcel from "../../util/excel/MazePlaneExcel"; import Packet from "../kcp/Packet"; import Session from "../kcp/Session"; @@ -6,7 +7,8 @@ import Session from "../kcp/Session"; export default async function handle(session: Session, packet: Packet) { const body = packet.body as EnterMazeCsReq; - const mazeEntry = MazePlaneExcel.getEntry(body.entryId); + const mazeEntry = MapEntryExcel.fromId(body.entryId); + const mazePlane = MazePlaneExcel.fromPlaneId(mazeEntry.PlaneID); let curLineup = await session.player.getLineup(); curLineup.planeId = mazeEntry.PlaneID; @@ -23,7 +25,7 @@ export default async function handle(session: Session, packet: Packet) { scene: { planeId: mazeEntry.PlaneID, floorId: mazeEntry.FloorID, - gameModeType: 1, + gameModeType: MazePlaneExcel.getGameModeForPlaneType(mazePlane.PlaneType), } }, id: mazeEntry.PlaneID, diff --git a/src/server/packets/GetCurSceneInfoCsReq.ts b/src/server/packets/GetCurSceneInfoCsReq.ts index 87cf150..1de7db7 100644 --- a/src/server/packets/GetCurSceneInfoCsReq.ts +++ b/src/server/packets/GetCurSceneInfoCsReq.ts @@ -1,28 +1,38 @@ -import { GetCurSceneInfoScRsp, Vector } from "../../data/proto/StarRail"; +import { GetCurSceneInfoScRsp, MotionInfo, SceneEntityInfo, SceneNpcMonsterInfo, Vector } from "../../data/proto/StarRail"; import { ActorEntity } from "../../game/entities/Actor"; +import MapEntryExcel from "../../util/excel/MapEntryExcel"; +import MazePlaneExcel from "../../util/excel/MazePlaneExcel"; import Packet from "../kcp/Packet"; import Session from "../kcp/Session"; export default async function handle(session: Session, packet: Packet) { + // Get data. const posData = session.player.db.posData; const _lineup = session.player.db.lineup; const lineup = _lineup.lineups[_lineup.curIndex]; - const curAvatarEntity = new ActorEntity(session.player.scene, lineup.avatarList[0], posData.pos); + const curAvatarEntity = new ActorEntity(session.player.scene, lineup.avatarList[lineup.leaderSlot], posData.pos); + const entryId = MapEntryExcel.fromFloorId(posData.floorID).ID; + const mazePlane = MazePlaneExcel.fromPlaneId(posData.planeID); + + // Scene management. + session.player.scene.spawnEntity(curAvatarEntity, true); + session.player.scene.entryId = entryId; + + // Send response. session.send(GetCurSceneInfoScRsp, { retcode: 0, scene: { planeId: posData.planeID, floorId: posData.floorID, entityList: [ - curAvatarEntity + curAvatarEntity.getSceneEntityInfo() ], + lightenSectionList: [], + leaderEntityId: curAvatarEntity.entityId, entityBuffList: [], - entryId: 10001, + entryId: entryId, envBuffList: [], - gameModeType: 1, - lightenSectionList: [] + gameModeType: MazePlaneExcel.getGameModeForPlaneType(mazePlane.PlaneType), }, - } as unknown as GetCurSceneInfoScRsp); - session.player.scene.spawnEntity(curAvatarEntity, true); - session.player.scene.entryId = 10001; + } as GetCurSceneInfoScRsp); } \ No newline at end of file diff --git a/src/server/packets/GetMazeMapInfoCsReq.ts b/src/server/packets/GetMazeMapInfoCsReq.ts index c81b883..b97116b 100644 --- a/src/server/packets/GetMazeMapInfoCsReq.ts +++ b/src/server/packets/GetMazeMapInfoCsReq.ts @@ -1,4 +1,5 @@ import { GetMazeMapInfoCsReq, GetMazeMapInfoScRsp } from "../../data/proto/StarRail"; +import MapEntryExcel from "../../util/excel/MapEntryExcel"; import MappingInfoExcel from "../../util/excel/MappingInfoExcel"; import MazePlaneExcel from "../../util/excel/MazePlaneExcel"; import Packet from "../kcp/Packet"; @@ -24,7 +25,7 @@ export default async function handle(session: Session, packet: Packet) { dataObj.lightenSectionList.push(i) } - dataObj.unlockTeleportList = MazePlaneExcel.getAllEntries().map(x => x.ID); + dataObj.unlockTeleportList = MapEntryExcel.all().map(x => x.ID); session.send(GetMazeMapInfoScRsp, dataObj); } \ No newline at end of file diff --git a/src/server/packets/SceneEntityMoveCsReq.ts b/src/server/packets/SceneEntityMoveCsReq.ts index c222884..e229e5a 100644 --- a/src/server/packets/SceneEntityMoveCsReq.ts +++ b/src/server/packets/SceneEntityMoveCsReq.ts @@ -5,6 +5,7 @@ import Session from "../kcp/Session"; export default async function handle(session: Session, packet: Packet) { const body = packet.body as SceneEntityMoveCsReq; + if (session.player.scene.entryId !== body.entryId) { return; } diff --git a/src/server/packets/StartChallengeCsReq.ts b/src/server/packets/StartChallengeCsReq.ts index 5b7bb92..d3f757e 100644 --- a/src/server/packets/StartChallengeCsReq.ts +++ b/src/server/packets/StartChallengeCsReq.ts @@ -1,59 +1,76 @@ -import { ChallengeStatus, ExtraLineupType, StartChallengeCsReq, StartChallengeScRsp } from "../../data/proto/StarRail"; +import { ChallengeStatus, CurChallenge, ExtraLineupType, Maze, SceneActorInfo, SceneEntityInfo, SceneInfo, SceneNpcInfo, SceneNpcMonsterInfo, ScenePropInfo, StartChallengeCsReq, StartChallengeScRsp } from "../../data/proto/StarRail"; +import { ActorEntity } from "../../game/entities/Actor"; import Packet from "../kcp/Packet"; import Session from "../kcp/Session"; // StartChallengeCsReq { challengeId: 101 } export default async function handle(session: Session, packet: Packet) { const body = packet.body as StartChallengeCsReq; + console.log(JSON.stringify(body, undefined, 4)); // TODO: This packet is just a base + const _lineup = session.player.db.lineup; + const lineup = _lineup.lineups[_lineup.curIndex]; + const curAvatarEntity = new ActorEntity(session.player.scene, lineup.avatarList[lineup.leaderSlot], { x: 0, y: 0, z: 0 }); session.send(StartChallengeScRsp, { retcode: 0, curChallenge: { challengeId: body.challengeId, - deadAvatarNum: 0, - extraLineupType: ExtraLineupType.LINEUP_CHALLENGE, rounds: 1, status: ChallengeStatus.CHALLENGE_DOING, - killMonsterList: [{ - monsterId: 8013010, - killNum: 1, - }] - }, + extraLineupType: ExtraLineupType.LINEUP_NONE, + killMonsterList: [], + deadAvatarNum: 0, + } as CurChallenge, maze: { // ? Data from MappingInfoExcelTable - id: 30101, - mapEntryId: 10001, + id: 30104, + mapEntryId: 3000401, floor: { floorId: 20121001, scene: { - planeId: 20121, - entryId: 1000, - floorId: 20121001, - gameModeType: 1, - entityList: [{ - entityId: 10010101, - npcMonster: { - monsterId: 8013010, - worldLevel: 1, - }, - groupId: 11, - motion: { - pos: { - x: 0, - y: 100, - z: 0, + planeId: 30104, + entryId: 3000401, + floorId: 30104001, + lightenSectionList: [], + gameModeType: 4, + entityList: [ + curAvatarEntity.getSceneEntityInfo(), + { + entityId: 10000, + motion: { + pos: { + x: 74719, + y: 2014, + z: -94205, + }, + rot: { + x: 0, + y: 0, + z: 0 + } }, - rot: { - x: 0, - y: 0, - z: 0 - } - }, - }] - } + groupId: 3, + instId: 1, + actor: {} as SceneActorInfo, + npc: {} as SceneNpcInfo, + prop: {} as ScenePropInfo, + npcMonster: { + monsterId: 1003020, + isGenMonster: false, + eventId: 0, + isSetWorldLevel: false, + worldLevel: 6 + } as SceneNpcMonsterInfo + } as SceneEntityInfo, + ], + leaderEntityId: curAvatarEntity.entityId, + entityBuffList: [], + envBuffList: [], + snar: "" + } as SceneInfo } - } + } as Maze } as StartChallengeScRsp); } \ No newline at end of file diff --git a/src/util/excel/MapEntryExcel.ts b/src/util/excel/MapEntryExcel.ts new file mode 100644 index 0000000..3317565 --- /dev/null +++ b/src/util/excel/MapEntryExcel.ts @@ -0,0 +1,24 @@ +import _MapEntryExcelTable from "../../data/excel/MapEntryExcelTable.json"; +type MapEntryExcelTableEntry = typeof _MapEntryExcelTable[keyof typeof _MapEntryExcelTable] +const MapEntryExcelTable = _MapEntryExcelTable as { [key: string]: MapEntryExcelTableEntry }; + +export default class MapEntryExcel { + private constructor() { + } + + public static all() : MapEntryExcelTableEntry[] { + return Object.values(MapEntryExcelTable); + } + + public static fromId(id: number) : MapEntryExcelTableEntry { + return MapEntryExcelTable[id]; + } + + public static fromIds(ids: number[]): MapEntryExcelTableEntry[] { + return ids.map(id => MapEntryExcel.fromId(id)); + } + + public static fromFloorId(id: number) : MapEntryExcelTableEntry { + return Object.values(MapEntryExcelTable).filter(e => e.FloorID == id)?.[0]; + } +} \ No newline at end of file diff --git a/src/util/excel/MazePlaneExcel.ts b/src/util/excel/MazePlaneExcel.ts index 03d3bd6..392c26a 100644 --- a/src/util/excel/MazePlaneExcel.ts +++ b/src/util/excel/MazePlaneExcel.ts @@ -1,5 +1,5 @@ -import _MapEntryExcelTable from "../../data/excel/MapEntryExcelTable.json"; import _MazePlaneExcelTable from "../../data/excel/MazePlaneExcelTable.json"; +import MapEntryExcel from "./MapEntryExcel"; interface MazePlaneExcelTableEntry { PlaneID: number; @@ -11,44 +11,13 @@ interface MazePlaneExcelTableEntry { FloorIDList: number[]; } -interface TextMap { - hash: number; -} - -type EntranceType = "Town" | "Mission" | "Explore"; - -interface MapEntryExcelTableEntry { - ID: number; - IsShowInMapMenu: boolean; - MapMenuSortID: number; - EntranceType: EntranceType | number; // Actually an enum. Town | Mission | Explore - EntranceGroupID: number; - Name: TextMap; - Desc: TextMap; - EntranceListIcon: string; - ImagePath: string; - MiniMapIconHintList: any[]; - ShowReward: number; - PlaneID: number; - FloorID: number; - StartGroupID: number; - StartAnchorID: number; - TargetMission: number; - TargetMainMissionList: number[]; - BeginMainMissionList: number[]; - FinishMainMissionList: number[]; - FinishQuestList: number[]; - UnlockQuest: number; -} - const MazePlaneExcelTable = _MazePlaneExcelTable as { [key: string]: MazePlaneExcelTableEntry }; -const MapEntryExcelTable = _MapEntryExcelTable as { [key: string]: MapEntryExcelTableEntry }; export default class MazePlaneExcel { private constructor() { } public static fromEntryId(entryId: number): MazePlaneExcelTableEntry { - const mapEntry = MapEntryExcelTable[entryId.toString()]; + const mapEntry = MapEntryExcel.fromId(entryId); return MazePlaneExcelTable[mapEntry.PlaneID.toString()]; } @@ -56,11 +25,21 @@ export default class MazePlaneExcel { return MazePlaneExcelTable[planeId.toString()]; } - public static getEntry(entryId: number): MapEntryExcelTableEntry { - return MapEntryExcelTable[entryId.toString()]; - } + public static getGameModeForPlaneType(planeType: string): number { + switch (planeType) { + case "Town": return 1; + case "Maze": return 2; + case "Train": return 3; + case "Challenge": return 4; + case "RogueExplore": return 5; + case "RogueChallenge": return 6; + case "TownRoom": return 7; + case "Raid": return 8; + case "FarmRelic": return 9; + case "Client": return 10; + case "ChallengeActivity": return 11; + } - public static getAllEntries(): MapEntryExcelTableEntry[] { - return Object.values(MapEntryExcelTable); + return 0; } } \ No newline at end of file diff --git a/src/util/excel/MonsterExcel.ts b/src/util/excel/MonsterExcel.ts new file mode 100644 index 0000000..ae33d17 --- /dev/null +++ b/src/util/excel/MonsterExcel.ts @@ -0,0 +1,20 @@ +import _MonsterExcelTable from "../../data/excel/MonsterExcelTable.json"; +type MonsterExcelTableEntry = typeof _MonsterExcelTable[keyof typeof _MonsterExcelTable] +const MonsterExcelTable = _MonsterExcelTable as { [key: string]: MonsterExcelTableEntry }; + +export default class MonsterExcel { + private constructor() { + } + + public static all() : MonsterExcelTableEntry[] { + return Object.values(MonsterExcelTable); + } + + public static fromId(id: number) : MonsterExcelTableEntry { + return MonsterExcelTable[id]; + } + + public static fromIds(ids: number[]): MonsterExcelTableEntry[] { + return ids.map(id => MonsterExcel.fromId(id)); + } +} \ No newline at end of file