Implementing entities. (#15)
* player: allowing player to send packet outside of packet handlers entity: simple entity implementation, spawning doesnt work currently * fix: conflict * fix: faulty request data * fix: oopsie * again... * requested: file name & fixes for latest commit * fix: memetrolls on drugs * [CodeFactor] Apply fixes [ci skip] [skip ci] * Minor changes * Formatting * Rename actor.ts to Actor.ts * Rename entity.ts to Entity.ts * Rename monster.ts to Monster.ts * Rename npc.ts to NPC.ts * Rename prop.ts to Prop.ts * Rename scene.ts to Scene.ts Co-authored-by: labalityowo <56186498+labalityowo@users.noreply.github.com> Co-authored-by: codefactor-io <support@codefactor.io> Co-authored-by: memetrollsXD <memetrollsxd@gmail.com>
This commit is contained in:
parent
0098da757c
commit
83d81487df
@ -10,7 +10,7 @@ export default class Avatar {
|
||||
|
||||
}
|
||||
|
||||
public static async create(uid: UID, baseAvatarId: number = 1001): Promise<Avatar> {
|
||||
public static async create(uid: UID, baseAvatarId: number = 1001, slot: number = -1): Promise<Avatar> {
|
||||
const db = Database.getInstance();
|
||||
// Check if already exists
|
||||
const existing = await Avatar.fromUID(uid, baseAvatarId);
|
||||
@ -29,7 +29,7 @@ export default class Avatar {
|
||||
hp: 10000,
|
||||
id: baseAvatarId,
|
||||
satiety: 100,
|
||||
slot: -1,
|
||||
slot: slot,
|
||||
sp: 10000
|
||||
});
|
||||
db.set("avatars", avatar);
|
||||
|
@ -1,8 +1,10 @@
|
||||
import Session from "../server/kcp/Session";
|
||||
import { ExtraLineupType, HeroBasicType, LineupInfo, Vector } from "../data/proto/StarRail";
|
||||
import Logger from "../util/Logger";
|
||||
import Account from "./Account";
|
||||
import Avatar from "./Avatar";
|
||||
import Database from "./Database";
|
||||
import { Scene } from "../game/Scene";
|
||||
const c = new Logger("Player");
|
||||
|
||||
export interface LineupI {
|
||||
@ -40,30 +42,33 @@ interface PlayerI {
|
||||
posData: {
|
||||
floorID: number;
|
||||
planeID: number;
|
||||
pos?: Vector;
|
||||
pos: Vector;
|
||||
}
|
||||
}
|
||||
|
||||
export default class Player {
|
||||
public readonly uid: number;
|
||||
private constructor(public db: PlayerI) {
|
||||
public readonly uid: number
|
||||
public readonly scene: Scene;
|
||||
|
||||
private constructor(readonly session: Session, public db: PlayerI) {
|
||||
this.uid = db._id;
|
||||
this.scene = new Scene(this);
|
||||
}
|
||||
|
||||
public static async fromUID(uid: number | string): Promise<Player | undefined> {
|
||||
public static async fromUID(session: Session, uid: number | string): Promise<Player | undefined> {
|
||||
if (typeof uid == "string") uid = Number(uid);
|
||||
const db = Database.getInstance();
|
||||
const player = await db.get("players", { _id: uid }) as unknown as PlayerI;
|
||||
if (!player) return Player.create(uid);
|
||||
return new Player(player);
|
||||
if (!player) return Player.create(session, uid);
|
||||
return new Player(session, player);
|
||||
}
|
||||
|
||||
public static async fromToken(token: string): Promise<Player | undefined> {
|
||||
public static async fromToken(session: Session, token: string): Promise<Player | undefined> {
|
||||
const db = Database.getInstance();
|
||||
const plr = await db.get("players", { token }) as unknown as PlayerI;
|
||||
if (!plr) return Player.fromUID((await Account.fromToken(token))?.uid || Math.round(Math.random() * 50000));
|
||||
if (!plr) return Player.fromUID(session, (await Account.fromToken(token))?.uid || Math.round(Math.random() * 50000));
|
||||
|
||||
return new Player(plr);
|
||||
return new Player(session, plr);
|
||||
}
|
||||
|
||||
public async getLineup(lineupIndex?: number): Promise<LineupInfo> {
|
||||
@ -89,7 +94,7 @@ export default class Player {
|
||||
this.db.lineup.curIndex = curIndex;
|
||||
}
|
||||
|
||||
public static async create(uid: number | string): Promise<Player | undefined> {
|
||||
public static async create(session: Session, uid: number | string): Promise<Player | undefined> {
|
||||
if (typeof uid == "string") uid = Number(uid);
|
||||
const acc = await Account.fromUID(uid);
|
||||
if (!acc) {
|
||||
@ -119,7 +124,12 @@ export default class Player {
|
||||
},
|
||||
posData: {
|
||||
floorID: 10001001,
|
||||
planeID: 10001
|
||||
planeID: 10001,
|
||||
pos: {
|
||||
x: 0,
|
||||
y: 439,
|
||||
z: -45507
|
||||
}
|
||||
},
|
||||
banned: false
|
||||
} as PlayerI
|
||||
@ -141,13 +151,16 @@ export default class Player {
|
||||
lineups: {}
|
||||
}
|
||||
for (let i = 0; i <= LINEUPS; i++) {
|
||||
let copy = baseLineup;
|
||||
const copy = baseLineup;
|
||||
copy.index = slot++;
|
||||
dataObj.lineup.lineups[i] = copy;
|
||||
}
|
||||
|
||||
await Avatar.create(uid, 1001, 0);
|
||||
|
||||
|
||||
await db.set("players", dataObj);
|
||||
return new Player(dataObj);
|
||||
return new Player(session, dataObj);
|
||||
}
|
||||
|
||||
public async save() {
|
||||
|
30
src/game/Scene.ts
Normal file
30
src/game/Scene.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { SceneEntityDisappearScNotify, SceneEntityUpdateScNotify } from "../data/proto/StarRail";
|
||||
import Player from "../db/Player";
|
||||
import { Entity } from "./entities/Entity";
|
||||
|
||||
export class Scene {
|
||||
public entryId!: number;
|
||||
public entities: Map<number, Entity> = new Map<number, Entity>();
|
||||
|
||||
constructor(public readonly player: Player) {
|
||||
|
||||
}
|
||||
|
||||
public spawnEntity(entity: Entity, silent: boolean = false) {
|
||||
this.entities.set(entity.entityId, entity);
|
||||
if (!silent) {
|
||||
this.player.session.send("SceneEntityUpdateScNotify", {
|
||||
entityList: [entity.getSceneEntityInfo()]
|
||||
} as SceneEntityUpdateScNotify);
|
||||
}
|
||||
}
|
||||
|
||||
public despawnEntity(entityId: number, silent: boolean = false) {
|
||||
this.entities.delete(entityId);
|
||||
if (!silent) {
|
||||
this.player.session.send("SceneEntityDisappearScNotify", {
|
||||
entityIdList: [entityId]
|
||||
} as SceneEntityDisappearScNotify);
|
||||
}
|
||||
}
|
||||
}
|
28
src/game/entities/Actor.ts
Normal file
28
src/game/entities/Actor.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { AvatarType, EntityType, MotionInfo, SceneActorInfo, SceneEntityInfo, Vector } from "../../data/proto/StarRail";
|
||||
import { Scene } from "../Scene";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
export class ActorEntity extends Entity
|
||||
{
|
||||
public mapLayer: number = 0;
|
||||
|
||||
constructor(readonly scene: Scene, public readonly avatarId: number, public pos: Vector, public rot?: Vector){
|
||||
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 //?
|
||||
};
|
||||
return sceneEntityInfo;
|
||||
}
|
||||
|
||||
public getEntityType(): EntityType {
|
||||
return EntityType.ENTITY_AVATAR;
|
||||
}
|
||||
|
||||
}
|
33
src/game/entities/Entity.ts
Normal file
33
src/game/entities/Entity.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { EntityType, MotionInfo, SceneEntityInfo, Vector } from "../../data/proto/StarRail";
|
||||
import { Scene } from "../Scene";
|
||||
|
||||
export abstract class Entity{
|
||||
static nextEntityId: number = 0;
|
||||
readonly entityId: number;
|
||||
|
||||
constructor(readonly scene: Scene, public pos: Vector, public rot?: Vector){
|
||||
this.entityId = Entity.nextEntityId++;
|
||||
}
|
||||
|
||||
public abstract getEntityType(): EntityType;
|
||||
|
||||
public getSceneEntityInfo(): SceneEntityInfo{
|
||||
return {
|
||||
entityId: this.entityId,
|
||||
groupId: 1,
|
||||
instId: 1,
|
||||
motion: {
|
||||
pos: this.pos,
|
||||
rot: this.rot ?? {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
},
|
||||
} as MotionInfo,
|
||||
actor: {},
|
||||
npc: {},
|
||||
npcMonster: {},
|
||||
prop: {}
|
||||
} as SceneEntityInfo;
|
||||
}
|
||||
}
|
29
src/game/entities/Monster.ts
Normal file
29
src/game/entities/Monster.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { AvatarType, EntityType, MotionInfo, SceneActorInfo, SceneEntityInfo, SceneNpcMonsterInfo, Vector } from "../../data/proto/StarRail";
|
||||
import { Scene } from "../Scene";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
export class MonsterEntity extends Entity
|
||||
{
|
||||
public mapLayer: number = 0;
|
||||
|
||||
constructor(readonly scene: Scene, public readonly monsterId: number, public pos: Vector, public rot?: Vector){
|
||||
super(scene, pos, rot);
|
||||
}
|
||||
|
||||
public getSceneEntityInfo(): SceneEntityInfo {
|
||||
const sceneEntityInfo = super.getSceneEntityInfo();
|
||||
sceneEntityInfo.npcMonster = {
|
||||
eventId: 1,
|
||||
isGenMonster: true,
|
||||
isSetWorldLevel: false,
|
||||
worldLevel: 1,//hardcoded
|
||||
monsterId: this.monsterId,
|
||||
} as SceneNpcMonsterInfo;
|
||||
return sceneEntityInfo;
|
||||
}
|
||||
|
||||
public getEntityType(): EntityType {
|
||||
return EntityType.ENTITY_MONSTER;
|
||||
}
|
||||
|
||||
}
|
26
src/game/entities/NPC.ts
Normal file
26
src/game/entities/NPC.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { EntityType, NpcExtraInfo, PropExtraInfo, SceneEntityInfo, SceneNpcInfo, SceneNpcMonsterInfo, ScenePropInfo, Vector } from "../../data/proto/StarRail";
|
||||
import { Scene } from "../Scene";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
export class NpcEntity extends Entity
|
||||
{
|
||||
public mapLayer: number = 0;
|
||||
|
||||
constructor(readonly scene: Scene, public readonly npcId: number, public pos: Vector, public rot?: Vector){
|
||||
super(scene, pos, rot);
|
||||
}
|
||||
|
||||
public getSceneEntityInfo(): SceneEntityInfo {
|
||||
const sceneEntityInfo = super.getSceneEntityInfo();
|
||||
sceneEntityInfo.npc = {
|
||||
npcId: this.npcId,
|
||||
extraInfo: {} as NpcExtraInfo
|
||||
} as SceneNpcInfo;
|
||||
return sceneEntityInfo;
|
||||
}
|
||||
|
||||
public getEntityType(): EntityType {
|
||||
return EntityType.ENTITY_PROP;
|
||||
}
|
||||
|
||||
}
|
29
src/game/entities/Prop.ts
Normal file
29
src/game/entities/Prop.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { EntityType, PropExtraInfo, SceneEntityInfo, SceneNpcMonsterInfo, ScenePropInfo, Vector } from "../../data/proto/StarRail";
|
||||
import { Scene } from "../Scene";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
export class PropEntity extends Entity
|
||||
{
|
||||
public mapLayer: number = 0;
|
||||
|
||||
constructor(readonly scene: Scene, public readonly propId: number, public pos: Vector, public rot?: Vector){
|
||||
super(scene, pos, rot);
|
||||
}
|
||||
|
||||
public getSceneEntityInfo(): SceneEntityInfo {
|
||||
const sceneEntityInfo = super.getSceneEntityInfo();
|
||||
sceneEntityInfo.prop = {
|
||||
propId: this.propId,
|
||||
createTimeMs: Date.now(),
|
||||
extraInfo: {} as PropExtraInfo,
|
||||
lifeTimeMs: Date.now() + 1000 * 60 * 60,
|
||||
propState: 1,
|
||||
} as ScenePropInfo;
|
||||
return sceneEntityInfo;
|
||||
}
|
||||
|
||||
public getEntityType(): EntityType {
|
||||
return EntityType.ENTITY_PROP;
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,21 @@
|
||||
import { GetCurSceneInfoScRsp } from "../../data/proto/StarRail";
|
||||
import { GetCurSceneInfoScRsp, Vector } from "../../data/proto/StarRail";
|
||||
import { ActorEntity } from "../../game/entities/Actor";
|
||||
import Packet from "../kcp/Packet";
|
||||
import Session from "../kcp/Session";
|
||||
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
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);
|
||||
session.send("GetCurSceneInfoScRsp", {
|
||||
retcode: 0,
|
||||
scene: {
|
||||
planeId: posData.planeID,
|
||||
floorId: posData.floorID,
|
||||
entityList: [],
|
||||
entityList: [
|
||||
curAvatarEntity
|
||||
],
|
||||
entityBuffList: [],
|
||||
entryId: 10001,
|
||||
envBuffList: [],
|
||||
@ -17,4 +23,6 @@ export default async function handle(session: Session, packet: Packet) {
|
||||
lightenSectionList: []
|
||||
},
|
||||
} as unknown as GetCurSceneInfoScRsp);
|
||||
session.player.scene.spawnEntity(curAvatarEntity, true);
|
||||
session.player.scene.entryId = 10001;
|
||||
}
|
@ -27,7 +27,7 @@ export default async function handle(session: Session, packet: Packet) {
|
||||
const account = await Account.fromToken(body.token || "");
|
||||
if (!account) retWarn(`Account not found with token ${body.token}`);
|
||||
|
||||
const player = await Player.fromToken(account?.token || "");
|
||||
const player = await Player.fromToken(session, account?.token || "");
|
||||
if (!player) retWarn(`Player not found with accountToken ${account?.token}`);
|
||||
if (!player || !account) {
|
||||
dataObj.retcode = 6;
|
||||
|
@ -22,7 +22,7 @@ import Session from "../kcp/Session";
|
||||
export default async function handle(session: Session, packet: Packet) {
|
||||
const body = packet.body as PlayerLoginCsReq;
|
||||
|
||||
const plr = await Player.fromUID(session.player.db._id);
|
||||
const plr = await Player.fromUID(session, session.player.db._id);
|
||||
if (!plr) return;
|
||||
|
||||
if (!plr.db.heroBasicType) {
|
||||
@ -45,7 +45,7 @@ export default async function handle(session: Session, packet: Packet) {
|
||||
}
|
||||
|
||||
if (!plr.db.lineup) {
|
||||
Avatar.create(plr.db._id);
|
||||
await Avatar.create(plr.db._id, 1001, 0);
|
||||
const baseLineup = {
|
||||
avatarList: [1001],
|
||||
extraLineupType: ExtraLineupType.LINEUP_NONE,
|
||||
@ -63,7 +63,7 @@ export default async function handle(session: Session, packet: Packet) {
|
||||
lineups: {}
|
||||
}
|
||||
for (let i = 0; i <= LINEUPS; i++) {
|
||||
let copy = baseLineup;
|
||||
const copy = baseLineup;
|
||||
copy.index = slot++;
|
||||
plr.db.lineup.lineups[i] = copy;
|
||||
}
|
||||
@ -73,7 +73,12 @@ export default async function handle(session: Session, packet: Packet) {
|
||||
if (!plr.db.posData) {
|
||||
plr.db.posData = {
|
||||
floorID: 10001001,
|
||||
planeID: 10001
|
||||
planeID: 10001,
|
||||
pos: {
|
||||
x: 0,
|
||||
y: 439,
|
||||
z: -45507
|
||||
}
|
||||
}
|
||||
plr.save();
|
||||
}
|
||||
|
@ -1,9 +1,38 @@
|
||||
import { SceneEntityMoveCsReq, SceneEntityMoveScRsp } from "../../data/proto/StarRail";
|
||||
import { ActorEntity } from "../../game/entities/Actor";
|
||||
import Packet from "../kcp/Packet";
|
||||
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;
|
||||
}
|
||||
for (const entityMotion of body.entityMotionList) {
|
||||
const entity = session.player.scene.entities.get(entityMotion.entityId);
|
||||
if (!entity) { //what??
|
||||
session.player.scene.despawnEntity(entityMotion.entityId);
|
||||
continue;
|
||||
}
|
||||
const motion = entityMotion.motion;
|
||||
if (!motion) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (motion.pos && (Object.keys(motion.pos!).length > 0)) { //preventing motion sending empty pos causing the pos to be reset
|
||||
entity.pos = motion.pos;
|
||||
if (entity instanceof ActorEntity) {
|
||||
entity.mapLayer = entityMotion.mapLayer;
|
||||
session.player.db.posData.pos = motion.pos!;
|
||||
}
|
||||
}
|
||||
|
||||
entity.rot = (Object.keys(motion.rot!).length > 0) ? motion.rot : {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
}
|
||||
}
|
||||
|
||||
session.send("SceneEntityMoveScRsp", {
|
||||
retcode: 0,
|
||||
|
Loading…
Reference in New Issue
Block a user