Merge branch 'main' into patch-2
This commit is contained in:
commit
90c6290cea
@ -1,3 +1,3 @@
|
||||
# CrepeSR
|
||||
|
||||
[Discord](https://discord.gg/sCAC282C)
|
||||
[Discord](https://discord.gg/KA4HqktWYG)
|
||||
|
@ -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,6 +12,7 @@ export default async function handle(command: Command) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(command.args.length == 0){
|
||||
c.log("Usage: /scene <planeID|floorID>");
|
||||
return;
|
||||
@ -33,6 +35,10 @@ export default async function handle(command: Command) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const planeID = MazePlaneExcel.fromPlaneId(parseInt(command.args[0]));
|
||||
const entryId = MapEntryExcel.fromFloorId(planeID.StartFloorID).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);
|
||||
@ -55,9 +61,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);
|
||||
|
@ -119,6 +119,15 @@ export default class Inventory {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the equipment with the given unique ID from the player's inventory.
|
||||
* @param uniqueId The unique ID of the equipment to fetch.
|
||||
* @returns The `Equipment` with the given unique ID, or `undefined` if the player does not have that equipment.
|
||||
*/
|
||||
public getEquipmentByUid(uniqueId: number) {
|
||||
return this.db.equipments.filter(e => e.uniqueId == uniqueId)?.[0];
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
Add items to the inventory.
|
||||
********************************************************************************/
|
||||
@ -376,17 +385,28 @@ export default class Inventory {
|
||||
/********************************************************************************
|
||||
Player updating.
|
||||
********************************************************************************/
|
||||
private sendMaterialUpdate() {
|
||||
/**
|
||||
* Send `PlayerSyncScNotify` for materials.
|
||||
*/
|
||||
public sendMaterialUpdate() {
|
||||
this.player.session.send(PlayerSyncScNotify, PlayerSyncScNotify.fromPartial({
|
||||
materialList: this.getMaterialList()
|
||||
}));
|
||||
}
|
||||
private sendEquipmentUpdate() {
|
||||
|
||||
/**
|
||||
* Send `PlayerSyncScNotify` for equipments.
|
||||
*/
|
||||
public sendEquipmentUpdate() {
|
||||
this.player.session.send(PlayerSyncScNotify, PlayerSyncScNotify.fromPartial({
|
||||
equipmentList: this.getEquipmentList()
|
||||
}));
|
||||
}
|
||||
private sendRelicUpdate() {
|
||||
|
||||
/**
|
||||
* Send `PlayerSyncScNotify` for relics.
|
||||
*/
|
||||
public sendRelicUpdate() {
|
||||
this.player.session.send(PlayerSyncScNotify, PlayerSyncScNotify.fromPartial({
|
||||
relicList: this.getRelicsList()
|
||||
}));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -80,7 +80,6 @@ export default class Session {
|
||||
|
||||
public async sync() {
|
||||
const avatars = await Avatar.loadAvatarsForPlayer(this.player);
|
||||
//const avatars = await Avatar.fromUID(this.player.db._id);
|
||||
const inventory = await this.player.getInventory();
|
||||
|
||||
this.send(PlayerSyncScNotify, PlayerSyncScNotify.fromPartial({
|
||||
@ -92,8 +91,6 @@ export default class Session {
|
||||
relicList: inventory.getRelicsList(),
|
||||
basicInfo: this.player.db.basicInfo
|
||||
}));
|
||||
|
||||
//this.player.save();
|
||||
}
|
||||
|
||||
public async send<Class extends MessageType<any>,>(type: Class, data: UnWrapMessageType<Class>) {
|
||||
|
@ -65,9 +65,9 @@ export default async function handle(session: Session, packet: Packet) {
|
||||
|
||||
// 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;
|
||||
if (avatar.db.level == levelCap) {
|
||||
avatar.db.exp = 0;
|
||||
excessExp = currentAvatarExp;
|
||||
}
|
||||
else {
|
||||
avatar.db.exp = currentAvatarExp;
|
||||
|
@ -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,
|
||||
|
100
src/server/packets/ExpUpEquipmentCsReq.ts
Normal file
100
src/server/packets/ExpUpEquipmentCsReq.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import { ExpUpEquipmentCsReq, ExpUpEquipmentScRsp } from "../../data/proto/StarRail";
|
||||
import { PayItemData } from "../../db/Inventory";
|
||||
import EquipmentExcel from "../../util/excel/EquipmentExcel";
|
||||
import EquipmentExpItemExcel from "../../util/excel/EquipmentExpItemExcel";
|
||||
import EquipmentExpTypeExcel from "../../util/excel/EquipmentExpTypeExcel";
|
||||
import EquipmentPromotionExcel from "../../util/excel/EquipmentPromotionExcel";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as ExpUpEquipmentCsReq;
|
||||
const inventory = await session.player.getInventory();
|
||||
|
||||
// Get the target equipment.
|
||||
const equipmentId = body.equipmentUniqueId;
|
||||
const equipment = inventory.getEquipmentByUid(equipmentId);
|
||||
const equipmentExcelData = EquipmentExcel.fromId(equipment.tid);
|
||||
|
||||
// Determine the next level cap based on the equipment's current promotion.
|
||||
const levelCap = EquipmentPromotionExcel.fromId(`${equipment.tid}:${equipment.promotion}`).MaxLevel;
|
||||
|
||||
// Determine the EXP we get from the consumed items, and the coins it will cost.
|
||||
let exp = 0;
|
||||
let cost = 0;
|
||||
|
||||
const costMaterialList = [];
|
||||
const costEquipmentList = []
|
||||
|
||||
for (const item of body.costData!.itemList) {
|
||||
// Determine amount of EXP given by that item.
|
||||
// If the consumed item is a PileItem, we can fetch the EXP it gives from the excels.
|
||||
if (item.pileItem) {
|
||||
const expItemData = EquipmentExpItemExcel.fromId(item.pileItem.itemId);
|
||||
exp += expItemData.ExpProvide * item.pileItem.itemNum;
|
||||
cost += expItemData.CoinCost;
|
||||
|
||||
costMaterialList.push({ id: item.pileItem.itemId, count: item.pileItem.itemNum } as PayItemData);
|
||||
}
|
||||
else if (item.equipmentUniqueId) {
|
||||
const consumedEquipment = inventory.getEquipmentByUid(item.equipmentUniqueId);
|
||||
const consumedEquipmentExcelData = EquipmentExcel.fromId(consumedEquipment.tid);
|
||||
|
||||
exp += consumedEquipmentExcelData.ExpProvide;
|
||||
cost += consumedEquipmentExcelData.CoinCost;
|
||||
|
||||
costEquipmentList.push(item.equipmentUniqueId);
|
||||
}
|
||||
}
|
||||
|
||||
costMaterialList.push({ id: 2, count: cost } as PayItemData);
|
||||
|
||||
// Try consuming materials.
|
||||
const success = await inventory.payItems(costMaterialList);
|
||||
if (!success) {
|
||||
// ToDo: Correct retcode.
|
||||
session.send(ExpUpEquipmentScRsp, { retcode: 1, returnItemList: [] } as ExpUpEquipmentScRsp);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const id of costEquipmentList) {
|
||||
await inventory.removeEquipment(id);
|
||||
}
|
||||
|
||||
// Cost has been paid - now level up.
|
||||
let currentEquipmentExp = equipment.exp + exp;
|
||||
let nextRequiredExp = EquipmentExpTypeExcel.fromId(`${equipmentExcelData.ExpType}:${equipment.level}`).Exp;
|
||||
while (currentEquipmentExp >= nextRequiredExp && equipment.level < levelCap) {
|
||||
// Increase level.
|
||||
equipment.level++;
|
||||
|
||||
// Deduct EXP necessary for this level.
|
||||
currentEquipmentExp -= nextRequiredExp;
|
||||
|
||||
// Determine EXP necessary for the next level.
|
||||
nextRequiredExp = EquipmentExpTypeExcel.fromId(`${equipmentExcelData.ExpType}:${equipment.level}`).Exp;
|
||||
}
|
||||
|
||||
// Calculate the equipment's new EXP and any excess EXP.
|
||||
let excessExp = 0;
|
||||
if (equipment.level == levelCap) {
|
||||
equipment.exp = 0;
|
||||
excessExp = currentEquipmentExp;
|
||||
}
|
||||
else {
|
||||
equipment.exp = currentEquipmentExp;
|
||||
}
|
||||
|
||||
// Save.
|
||||
await inventory.save();
|
||||
|
||||
// ToDo: Handle return items.
|
||||
|
||||
// Done. Sync and send response.
|
||||
await session.sync();
|
||||
|
||||
session.send(ExpUpEquipmentScRsp, {
|
||||
retcode: 0,
|
||||
returnItemList: []
|
||||
} as ExpUpEquipmentScRsp);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -1,20 +1,26 @@
|
||||
import { AvatarType, JoinLineupCsReq, JoinLineupScRsp, SyncLineupNotify, SyncLineupReason } from "../../data/proto/StarRail";
|
||||
import Avatar from "../../db/Avatar";
|
||||
import {
|
||||
JoinLineupCsReq,
|
||||
JoinLineupScRsp,
|
||||
SyncLineupNotify,
|
||||
SyncLineupReason
|
||||
} from "../../data/proto/StarRail";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
|
||||
// JoinLineupCsReq { baseAvatarId: 1002, slot: 1 }
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as JoinLineupCsReq;
|
||||
session.send(JoinLineupScRsp, { retcode: 0 });
|
||||
session.send(JoinLineupScRsp, {retcode: 0});
|
||||
|
||||
// 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;
|
||||
const index = body.index ?? 1;
|
||||
|
||||
session.player.db.lineup.lineups[index].avatarList[slot] = body.baseAvatarId;
|
||||
await session.player.save();
|
||||
|
||||
session.send(SyncLineupNotify, {
|
||||
lineup: await session.player.getLineup(),
|
||||
lineup: await session.player.getLineup(index),
|
||||
reasonList: [SyncLineupReason.SYNC_REASON_NONE]
|
||||
} as SyncLineupNotify);
|
||||
}
|
70
src/server/packets/LeaveChallengeCsReq.ts
Normal file
70
src/server/packets/LeaveChallengeCsReq.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { GetCurSceneInfoScRsp, LeaveChallengeScRsp } from "../../data/proto/StarRail";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
import MapEntryExcel from "../../util/excel/MapEntryExcel";
|
||||
import MazePlaneExcel from "../../util/excel/MazePlaneExcel";
|
||||
import { ActorEntity } from "../../game/entities/Actor";
|
||||
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const bfArray: number[] = [];
|
||||
for (let i = 0; i < 500; i++) {
|
||||
bfArray.push(i);
|
||||
}
|
||||
|
||||
try {
|
||||
// Challenge maze data doesn't get saved to DB.. We can abuse this and fall back to default
|
||||
const posData = session.player.db.posData;
|
||||
const entry = MapEntryExcel.fromFloorId(posData.floorID);
|
||||
const maze = MazePlaneExcel.fromPlaneId(posData.planeID);
|
||||
if (!entry || !maze) return session.send(LeaveChallengeScRsp, LeaveChallengeScRsp.fromPartial({ retcode: 2 }));
|
||||
|
||||
const dataObj = LeaveChallengeScRsp.fromPartial({
|
||||
retcode: 0,
|
||||
maze: {
|
||||
floor: {
|
||||
floorId: posData.floorID,
|
||||
scene: {
|
||||
entityList: [],
|
||||
entryId: entry.ID,
|
||||
floorId: entry.FloorID,
|
||||
planeId: entry.PlaneID,
|
||||
gameModeType: MazePlaneExcel.getGameModeForPlaneType(maze.PlaneType),
|
||||
lightenSectionList: bfArray,
|
||||
entityBuffList: [],
|
||||
envBuffList: [],
|
||||
}
|
||||
},
|
||||
id: posData.planeID,
|
||||
mapEntryId: entry.ID
|
||||
}
|
||||
});
|
||||
|
||||
session.send(LeaveChallengeScRsp, dataObj);
|
||||
} catch (e) {
|
||||
session.c.error(e as Error);
|
||||
session.send(LeaveChallengeScRsp, LeaveChallengeScRsp.fromPartial({ retcode: 2 }));
|
||||
} finally {
|
||||
// Force us back
|
||||
const posData = session.player.db.posData;
|
||||
const entry = MapEntryExcel.fromFloorId(posData.floorID);
|
||||
const maze = MazePlaneExcel.fromPlaneId(posData.planeID);
|
||||
if (entry && maze) {
|
||||
const actor = new ActorEntity(session.player.scene, session.player.db.lineup.lineups[session.player.db.lineup.curIndex].avatarList[0], posData.pos).getSceneActorInfo();
|
||||
|
||||
session.send(GetCurSceneInfoScRsp, {
|
||||
retcode: 0,
|
||||
scene: {
|
||||
planeId: posData.planeID,
|
||||
floorId: posData.floorID,
|
||||
lightenSectionList: bfArray,
|
||||
gameModeType: MazePlaneExcel.getGameModeForPlaneType(maze.PlaneType),
|
||||
entityBuffList: [],
|
||||
envBuffList: [],
|
||||
entryId: entry.ID,
|
||||
entityList: [actor],
|
||||
leaderEntityId: actor.entityId
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
26
src/server/packets/LockEquipmentCsReq.ts
Normal file
26
src/server/packets/LockEquipmentCsReq.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { LockEquipmentCsReq, LockEquipmentScRsp } 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 LockEquipmentCsReq;
|
||||
|
||||
// Fetch the equipment in question.
|
||||
const inventory = await session.player.getInventory();
|
||||
const equipment = inventory.getEquipmentByUid(body.equipmentUniqueId);
|
||||
|
||||
if (!equipment) {
|
||||
session.send(LockEquipmentScRsp, { retcode: 1 } as LockEquipmentScRsp);
|
||||
}
|
||||
|
||||
// Toggle the equipment's lock.
|
||||
equipment.isProtected = !equipment.isProtected;
|
||||
await inventory.save();
|
||||
|
||||
// Done. Send and sync.
|
||||
inventory.sendEquipmentUpdate();
|
||||
session.send(LockEquipmentScRsp, {
|
||||
retcode: 0,
|
||||
equipmentUniqueId: body.equipmentUniqueId
|
||||
} as LockEquipmentScRsp);
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
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";
|
||||
|
||||
|
36
src/server/packets/PromoteEquipmentCsReq.ts
Normal file
36
src/server/packets/PromoteEquipmentCsReq.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { PromoteEquipmentCsReq, PromoteEquipmentScRsp } from "../../data/proto/StarRail";
|
||||
import { PayItemData } from "../../db/Inventory";
|
||||
import EquipmentPromotionExcel from "../../util/excel/EquipmentPromotionExcel";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as PromoteEquipmentCsReq;
|
||||
const inventory = await session.player.getInventory();
|
||||
|
||||
// Get the target avatar.
|
||||
const equipmentId = body.equipmentUniqueId;
|
||||
const equipment = inventory.getEquipmentByUid(equipmentId);
|
||||
const promotionExcelData = EquipmentPromotionExcel.fromId(`${equipment.tid}:${equipment.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(PromoteEquipmentScRsp, { retcode: 1 } as PromoteEquipmentScRsp);
|
||||
return;
|
||||
}
|
||||
|
||||
await inventory.save();
|
||||
|
||||
// Promote the avatar and save.
|
||||
equipment.promotion++;
|
||||
await inventory.save();
|
||||
|
||||
// Done. Sync and send response.
|
||||
await session.sync();
|
||||
session.send(PromoteEquipmentScRsp, { retcode: 0 } as PromoteEquipmentScRsp);
|
||||
}
|
32
src/server/packets/RankUpEquipmentCsReq.ts
Normal file
32
src/server/packets/RankUpEquipmentCsReq.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { RankUpEquipmentCsReq, RankUpEquipmentScRsp } 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 RankUpEquipmentCsReq;
|
||||
const inventory = await session.player.getInventory();
|
||||
|
||||
// Get equipment.
|
||||
const equipment = inventory.getEquipmentByUid(body.equipmentUniqueId);
|
||||
|
||||
// Check if all sacrificed equipments exist.
|
||||
for (const id of body.equipmentIdList) {
|
||||
if (!inventory.getEquipmentByUid(id)) {
|
||||
session.send(RankUpEquipmentScRsp, { retcode: 1 } as RankUpEquipmentScRsp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove sacrificed equipments.
|
||||
for (const id of body.equipmentIdList) {
|
||||
await inventory.removeEquipment(id);
|
||||
}
|
||||
|
||||
// Increase rank and save.
|
||||
equipment.rank += body.equipmentIdList.length;
|
||||
await inventory.save();
|
||||
|
||||
// Done. Send and sync.
|
||||
await session.sync();
|
||||
session.send(RankUpEquipmentScRsp, { retcode: 0 } as RankUpEquipmentScRsp);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
19
src/server/packets/SwitchLineupIndexCsReq.ts
Normal file
19
src/server/packets/SwitchLineupIndexCsReq.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import Session from "../kcp/Session";
|
||||
import Packet from "../kcp/Packet";
|
||||
import {SwitchLineupIndexCsReq, SwitchLineupIndexScRsp} from "../../data/proto/StarRail";
|
||||
|
||||
// SwitchLineupIndexCsReq { index: 0 }
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as SwitchLineupIndexCsReq
|
||||
const index = body.index ?? 0
|
||||
|
||||
session.send(SwitchLineupIndexScRsp, {
|
||||
retcode: 0,
|
||||
index: index
|
||||
})
|
||||
|
||||
session.player.db.lineup.curIndex = index
|
||||
await session.player.save()
|
||||
|
||||
// Todo: figure need to send SyncLineupNotify again ?
|
||||
}
|
20
src/util/excel/EquipmentExcel.ts
Normal file
20
src/util/excel/EquipmentExcel.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import _EquipmentExcelTable from "../../data/excel/EquipmentExcelTable.json";
|
||||
type EquipmentExcelTableEntry = typeof _EquipmentExcelTable[keyof typeof _EquipmentExcelTable]
|
||||
const EquipmentExcelTable = _EquipmentExcelTable as { [key: string]: EquipmentExcelTableEntry };
|
||||
|
||||
export default class EquipmentExcel {
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
public static all() : EquipmentExcelTableEntry[] {
|
||||
return Object.values(EquipmentExcelTable);
|
||||
}
|
||||
|
||||
public static fromId(id: number) : EquipmentExcelTableEntry {
|
||||
return EquipmentExcelTable[id];
|
||||
}
|
||||
|
||||
public static fromIds(ids: number[]): EquipmentExcelTableEntry[] {
|
||||
return ids.map(id => EquipmentExcel.fromId(id));
|
||||
}
|
||||
}
|
20
src/util/excel/EquipmentExpItemExcel.ts
Normal file
20
src/util/excel/EquipmentExpItemExcel.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import _EquipmentExpItemExcelTable from "../../data/excel/EquipmentExpItemExcelTable.json";
|
||||
type EquipmentExpItemExcelTableEntry = typeof _EquipmentExpItemExcelTable[keyof typeof _EquipmentExpItemExcelTable]
|
||||
const EquipmentExpItemExcelTable = _EquipmentExpItemExcelTable as { [key: string]: EquipmentExpItemExcelTableEntry };
|
||||
|
||||
export default class EquipmentExpItemExcel {
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
public static all() : EquipmentExpItemExcelTableEntry[] {
|
||||
return Object.values(EquipmentExpItemExcelTable);
|
||||
}
|
||||
|
||||
public static fromId(id: number) : EquipmentExpItemExcelTableEntry {
|
||||
return EquipmentExpItemExcelTable[id];
|
||||
}
|
||||
|
||||
public static fromIds(ids: number[]): EquipmentExpItemExcelTableEntry[] {
|
||||
return ids.map(id => EquipmentExpItemExcel.fromId(id));
|
||||
}
|
||||
}
|
20
src/util/excel/EquipmentExpTypeExcel.ts
Normal file
20
src/util/excel/EquipmentExpTypeExcel.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import _EquipmentExpTypeExcelTable from "../../data/excel/EquipmentExpTypeExcelTable.json";
|
||||
type EquipmentExpTypeExcelTableEntry = typeof _EquipmentExpTypeExcelTable[keyof typeof _EquipmentExpTypeExcelTable]
|
||||
const EquipmentExpTypeExcelTable = _EquipmentExpTypeExcelTable as { [key: string]: EquipmentExpTypeExcelTableEntry };
|
||||
|
||||
export default class EquipmentExpTypeExcel {
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
public static all() : EquipmentExpTypeExcelTableEntry[] {
|
||||
return Object.values(EquipmentExpTypeExcelTable);
|
||||
}
|
||||
|
||||
public static fromId(id: string) : EquipmentExpTypeExcelTableEntry {
|
||||
return EquipmentExpTypeExcelTable[id];
|
||||
}
|
||||
|
||||
public static fromIds(ids: string[]): EquipmentExpTypeExcelTableEntry[] {
|
||||
return ids.map(id => EquipmentExpTypeExcel.fromId(id));
|
||||
}
|
||||
}
|
20
src/util/excel/EquipmentPromotionExcel.ts
Normal file
20
src/util/excel/EquipmentPromotionExcel.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import _EquipmentPromotionExcelTable from "../../data/excel/EquipmentPromotionExcelTable.json";
|
||||
type EquipmentPromotionExcelTableEntry = typeof _EquipmentPromotionExcelTable[keyof typeof _EquipmentPromotionExcelTable]
|
||||
const EquipmentPromotionExcelTable = _EquipmentPromotionExcelTable as { [key: string]: EquipmentPromotionExcelTableEntry };
|
||||
|
||||
export default class EquipmentPromotionExcel {
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
public static all() : EquipmentPromotionExcelTableEntry[] {
|
||||
return Object.values(EquipmentPromotionExcelTable);
|
||||
}
|
||||
|
||||
public static fromId(id: string) : EquipmentPromotionExcelTableEntry {
|
||||
return EquipmentPromotionExcelTable[id];
|
||||
}
|
||||
|
||||
public static fromIds(ids: string[]): EquipmentPromotionExcelTableEntry[] {
|
||||
return ids.map(id => EquipmentPromotionExcel.fromId(id));
|
||||
}
|
||||
}
|
24
src/util/excel/MapEntryExcel.ts
Normal file
24
src/util/excel/MapEntryExcel.ts
Normal file
@ -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];
|
||||
}
|
||||
}
|
@ -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,15 +25,25 @@ export default class MazePlaneExcel {
|
||||
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()];
|
||||
}
|
||||
|
||||
public static getAllEntries(): MapEntryExcelTableEntry[] {
|
||||
return Object.values(MapEntryExcelTable);
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
20
src/util/excel/MonsterExcel.ts
Normal file
20
src/util/excel/MonsterExcel.ts
Normal file
@ -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));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user