further refactor

This commit is contained in:
katboi01 2025-07-12 02:19:48 +02:00
parent 05e254cfcd
commit 473c807461
46 changed files with 637 additions and 475 deletions

1
.gitignore vendored
View File

@ -42,3 +42,4 @@ dist/**/*
# ignore yarn.lock # ignore yarn.lock
yarn.lock yarn.lock
Database/mydb.sqlite3

View File

@ -1,21 +0,0 @@
import { loginResponse } from "../Classes/loginResponse.js";
import { playerData } from "../Classes/playerData.js";
import { userData } from "../Classes/userData.js";
export function emitLogin(socket, user : userData | null, player:playerData, registered:boolean = false){
if(user != null){
socket.emit("account/login", JSON.stringify(new loginResponse(true, user, player)));
socket.user = user
socket.player = player
if(registered){
console.log(`User ${(user as userData).login} registerd and logged in`);
}
else{
console.log(`User ${(user as userData).login} logged in`);
}
}
else{
socket.emit("account/login", JSON.stringify(new loginResponse(false, null, null)));
console.log("Login Failed");
}
}

View File

@ -1,21 +1,33 @@
import { userData } from "../Classes/userData.js"; import { userData } from "../Classes/userData.js";
import { players } from "../Player/players.js"; import { characters } from "../Characters/characters.js";
import { emitLogin } from "./_emitLogin.js";
import { users } from "./users.js"; import { users } from "./users.js";
import { db } from "../index.js"
import { Socket } from "socket.io";
import { loginResponse } from "../Classes/Outgoing/accountResponses.js";
import { Endpoints } from "../endpoints.js";
export function login(socket, data){ export async function login(socket : Socket, data){
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let json : userData = JSON.parse(buff.toString('utf-8')); let json : userData = JSON.parse(buff.toString('utf-8'));
if (!json.login || !json.password) return if (!json.login || !json.password){
console.log("login or password is missing")
let result = users.readUser(json.login, json.password); return
let player = null
if(result != null){
player = players.readPlayer(result.id)
if(player == null){
player = players.createPlayer(result.id)
}
} }
emitLogin(socket, result, player); const user = await users.readUser(db, json.login, json.password);
if(user){
console.log(`User ${user.login} logged in`);
const character = await characters.readCharacter(db, user.id);
const result = new loginResponse(user, character)
socket.user = user
socket.character = character
socket.emit(Endpoints.Login, JSON.stringify(result));
}
else{
console.log(`User ${json.login} did not log in`);
const result = new loginResponse(null, null)
socket.emit(Endpoints.Login, JSON.stringify(result));
}
} }

View File

@ -1,18 +1,32 @@
import { userData } from "../Classes/userData.js"; import { userData } from "../Classes/userData.js";
import { players } from "../Player/players.js";
import { emitLogin } from "./_emitLogin.js";
import { users } from "./users.js"; import { users } from "./users.js";
import { db } from "../index.js"
import { Socket } from "socket.io";
import { loginResponse } from "../Classes/Outgoing/accountResponses.js";
import { Endpoints } from "../endpoints.js";
import { characters } from "../Characters/characters.js";
export function register(socket, data){ export async function register(socket : Socket, data){
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let json : userData = JSON.parse(buff.toString('utf-8')); let json : userData = JSON.parse(buff.toString('utf-8'));
if (!json.login || !json.password) return if (!json.login || !json.password){
console.log("login or password is missing")
let result = users.createUser(json.login, json.password); return
let player = null
if(result != null){
player = players.createPlayer(result.id)
} }
emitLogin(socket, result, player); const user = await users.createUser(db, json.login, json.password);
if(user){
console.log(`User ${user.login} registered`);
const character = await characters.createCharacter(db, user.id);
const result = new loginResponse(user, character)
socket.user = user
socket.character = character
socket.emit(Endpoints.Register, JSON.stringify(result))
}
else{
console.log(`User failed to register`);
const result = new loginResponse(null, null)
socket.emit(Endpoints.Register, JSON.stringify(result))
}
} }

View File

@ -1,12 +1,13 @@
import { register } from "./_register.js"; import { register } from "./_register.js";
import { login } from "./_login.js"; import { login } from "./_login.js";
import { Endpoints } from "../endpoints.js";
export function registerAccountCallbacks(socket){ export function registerAccountCallbacks(socket){
socket.on('account/register', (data) => { socket.on(Endpoints.Register, (data) => {
register(socket, data) register(socket, data)
}); });
socket.on('account/login', (data) => { socket.on(Endpoints.Login, (data) => {
login(socket, data) login(socket, data)
}); });
} }

View File

@ -1,56 +1,25 @@
import { game } from "../game.js";
import { userData } from "../Classes/userData.js"; import { userData } from "../Classes/userData.js";
import { DatabaseController } from "../Database/dbcontroller.js";
export class users{ export class users{
static createUser(login, password){ static async createUser(db: DatabaseController, login : string, password : string){
if (game.accountsDB.find(u=>u.login == login) != null){ await db.run('INSERT INTO users (login, password) VALUES (?, ?)', [login, password]);
console.log(`User ${login} alread exists`); return await this.readUser(db, login, password)
return null;
} }
var user = new userData(game.accountsDB.length, login, password); static async readUser(db: DatabaseController, login : string, password : string): Promise<userData>{
game.accountsDB.push(user); let user = await db.select(`SELECT * FROM users WHERE login = ? AND password = ?`, [login, password])
if (user.length > 0){
let row = user[0]
return new userData({...row})
}
else{
return null
}
}
static async readUserID(db: DatabaseController, id : number){
let user = await db.select(`SELECT * FROM users WHERE id = ?`, [id])
return user; return user;
} }
static readUser(login, password){
let user = game.accountsDB.find(u=>u.login == login && u.password == password)
if(user != null){
return user;
}
return null;
}
static readUserID(id : number){
let user = game.accountsDB.filter(u=>u.id == id)[0];
return user;
}
static updateUser(userNew : userData){
let user = this.readUserID(userNew.id);
let sum = Math.floor(Math.random() * 99999);
while(sum == userNew.checksum){
sum = Math.floor(Math.random() * 99999);
}
userNew.checksum = sum;
game.accountsDB[game.accountsDB.indexOf(user)] = userNew;
}
static saveUsers(fs){
game.accountsDB.forEach(user => {user.save(fs)});
}
static loadUsers(fs){
fs.mkdirSync(`Database/Users/`, { recursive: true })
fs.readdir(`Database/Users/`, (err, files) => {
files.forEach(file => {
fs.readFile(`Database/Users/${file}`, (err, data) => {
if (err) throw err;
let user : userData = Object.assign(new userData(-1,"",""), JSON.parse(data));
game.accountsDB.push(user);
console.log(`Loaded ${user.login}`);
});
});
});
}
} }

29
Characters/characters.ts Normal file
View File

@ -0,0 +1,29 @@
import { characterData } from "../Classes/characterData.js";
import { DatabaseController } from "../Database/dbcontroller.js";
export class characters{
static async createCharacter(db: DatabaseController, userId : number){
await db.run('INSERT INTO characters (user_id) VALUES (?)', [userId]);
return await this.readCharacter(db, userId)
}
static async readCharacter(db: DatabaseController, userId : number): Promise<characterData>{
let player = await db.select(`SELECT * FROM characters WHERE user_id = ? LIMIT 1`, [userId])
if (player.length > 0){
let row = player[0]
return new characterData({
...row,
inventory: row.inventory ? JSON.parse(row.inventory) : undefined,
questBook: row.questBook ? JSON.parse(row.questBook) : undefined,
})
}
else{
return null
}
}
static async savePlayer(db: DatabaseController, data: characterData){
await db.run(`UPDATE characters SET (inventory, questBook) VALUES (?,?) WHERE id = ?`,
[JSON.stringify(data.inventory), JSON.stringify(data.questBook), data.id])
}
}

View File

@ -1,5 +1,5 @@
import { playerData } from "../playerData.js"; import { characterData } from "../characterData.js";
export class levelUpdateClient{ export class levelUpdateClient{
player : playerData player : characterData
} }

View File

@ -1,7 +1,7 @@
import { levelState } from "../levelState.js"; import { levelState } from "../levelState.js";
import { playerData } from "../playerData.js"; import { characterData } from "../characterData.js";
export class levelUpdateHost{ export class levelUpdateHost{
player : playerData player : characterData
room : levelState room : levelState
} }

View File

@ -1,5 +1,5 @@
import { playerData } from "../playerData.js"; import { characterData } from "../characterData.js";
export class lobbyJoin{ export class lobbyJoin{
player : playerData player : characterData
} }

View File

@ -0,0 +1,20 @@
import { characterData } from "../characterData.js";
import { userData } from "../userData.js";
export class loginResponse{
result : boolean
userData : userData
playerData : characterData
constructor(user : userData, player : characterData){
if (!user || !player){
this.result = false;
this.userData = this.playerData = null;
}
else{
this.result = true;
this.userData = user.makeSafe();
this.playerData = player;
}
}
}

View File

@ -0,0 +1,40 @@
import { characterData } from "../characterData.js"
import { enemyDamageInfo } from "../enemyDamageInfo.js"
import { physicsObject } from "../physicsObject.js"
import { playerInventory } from "../playerInventory.js"
export class characterDataStart{
id : number
characterId : number
rigidbody : physicsObject = new physicsObject()
constructor(data : characterData){
this.id = data.id
this.characterId = data.characterId
this.rigidbody = physicsObject.characterOnly(data.rigidbody)
}
}
export class characterDataUpdate{
id : number
rigidbody : physicsObject = new physicsObject()
damageInfo : enemyDamageInfo[] = []
constructor(data : characterData){
this.id = data.id
this.rigidbody = physicsObject.characterOnly(data.rigidbody)
if(data.damageInfo.length > 0){
this.damageInfo = data.damageInfo
}
}
}
export class characterDataInventory{
id : number
inventory : playerInventory = new playerInventory()
constructor(data : characterData){
this.id = data.id
this.inventory = data.inventory
}
}

View File

@ -0,0 +1,17 @@
import { enemyData } from "../enemyData.js";
import { Stat } from "../itemData.js";
import { physicsObject } from "../physicsObject.js";
export class enemyDataUpdate{
id : number
templateId : number
rigidbody : physicsObject
stats : Stat[] = []
constructor(data : enemyData){
this.id = data.id
this.templateId = data.templateId
this.rigidbody = physicsObject.characterOnly(data.rigidbody)
this.stats = data.stats
}
}

View File

@ -0,0 +1,63 @@
import { enemyData } from "../enemyData.js"
import { levelState } from "../levelState.js"
import { propData } from "../propData.js"
import { characterDataStart, characterDataUpdate } from "./characterDataPartial.js"
import { enemyDataUpdate } from "./enemyDataPartial.js"
import { propDataStart, propDataUpdate } from "./propDataPartial.js"
export class levelStateStart{
id : string
seed : number = -1
hostId : number = -1
completed : boolean = false
isDungeon : boolean = false
enemies : enemyDataUpdate[] = []
objects : propDataStart[] = []
players : characterDataStart[] = []
constructor(data : levelState){
this.id = data.id
this.seed = data.seed
this.hostId = data.hostId
this.completed = data.completed
this.isDungeon = data.isDungeon
this.enemies = data.enemies.map(e => e.copyStart())
this.objects = data.objects.map(e => e.copyStart())
this.players = data.players.map(pl=> pl.copyStart())
}
}
export class levelStateUpdate{
id : string
seed : number = -1
hostId : number = -1
completed : boolean = false
isDungeon : boolean = false
enemies : enemyDataUpdate[] = []
objects : propDataUpdate[] = []
players : characterDataUpdate[] = []
constructor(data : levelState){
this.id = data.id
this.seed = data.seed
this.hostId = data.hostId
this.completed = data.completed
this.enemies = data.enemies.map(e => e.copyUpdate())
this.objects = data.objects.map(e => e.copyUpdate())
this.players = data.players.map(pl=> pl.copyUpdate())
}
}
export class levelStateState{
id : string
seed : number = -1
hostId : number = -1
completed : boolean = false
constructor(data : levelState){
this.id = data.id
this.seed = data.seed
this.hostId = data.hostId
this.completed = data.completed
}
}

View File

@ -0,0 +1,16 @@
import { dungeonData } from "../dungeonData.js";
import { levelState } from "../levelState.js";
import { lobbyState } from "../lobbyState.js";
import { characterDataUpdate } from "./characterDataPartial.js";
export class lobbyStateLight{
activeUsers : characterDataUpdate[] = []
rooms : levelState[] = []
dungeons : dungeonData[] = []
constructor(data : lobbyState){
this.activeUsers = data.activeUsers.map(u=>u.character.copyUpdate())
this.rooms = data.rooms
this.dungeons = data.dungeons
}
}

View File

@ -0,0 +1,28 @@
import { physicsObject } from "../physicsObject.js"
import { propData } from "../propData.js"
export class propDataStart{
id : number
templateId : number
rigidbody : physicsObject
components : any
constructor(data : propData) {
this.id = data.id
this.templateId = data.templateId
this.rigidbody = physicsObject.copyStart(data.rigidbody)
this.components = data.components
}
}
export class propDataUpdate{
id : number
rigidbody : physicsObject
components : any
constructor(data : propData) {
this.id = data.id
this.rigidbody = physicsObject.copyUpdate(data.rigidbody)
this.components = data.components
}
}

View File

@ -0,0 +1,8 @@
import { characterDataUpdate } from "./characterDataPartial.js"
import { levelStateStart, levelStateState } from "./levelStatePartial.js"
export class roomChangeResponse{
player : characterDataUpdate
newRoom : levelStateStart
previousRoom : levelStateState
}

View File

@ -0,0 +1,10 @@
import { userData } from "../userData.js";
export class userDataSafe{
id: number;
login: string;
constructor(data : userData){
Object.assign(this, data);
}
}

View File

@ -1,9 +1,10 @@
import { enemyDamageInfo } from "./enemyDamageInfo.js"; import { enemyDamageInfo } from "./enemyDamageInfo.js";
import { characterDataInventory, characterDataStart, characterDataUpdate } from "./Outgoing/characterDataPartial.js";
import { physicsObject } from "./physicsObject.js"; import { physicsObject } from "./physicsObject.js";
import { playerInventory } from "./playerInventory.js"; import { playerInventory } from "./playerInventory.js";
import { questBook } from "./questBook.js"; import { questBook } from "./questBook.js";
export class playerData{ export class characterData{
id : number id : number
level : number = 1 level : number = 1
room : string = "0_0" room : string = "0_0"
@ -13,35 +14,22 @@ export class playerData{
questBook : questBook = new questBook() questBook : questBook = new questBook()
damageInfo : enemyDamageInfo[] = [] damageInfo : enemyDamageInfo[] = []
constructor(init?: Partial<playerData>) { constructor(init?: Partial<characterData>) {
Object.assign(this, init); Object.assign(this, init);
this.questBook = new questBook(this.questBook) this.questBook = new questBook(this.questBook)
this.inventory = new playerInventory(this.inventory)
} }
copyStart(){ copyStart(){
let player : any = {} return new characterDataStart(this)
player.id = this.id
player.characterId = this.characterId
player.rigidbody = physicsObject.characterOnly(this.rigidbody)
return player
} }
copyUpdate(){ copyUpdate(){
let player : any = {} return new characterDataUpdate(this)
player.id = this.id
if(this.rigidbody == null){
console.log(this)
}
player.rigidbody = physicsObject.characterOnly(this.rigidbody)
if(this.damageInfo.length > 0) player.damageInfo = this.damageInfo
return player
} }
copyInventory(){ copyInventory(){
let player : any = {} return new characterDataInventory(this)
player.id = this.id
player.inventory = this.inventory
return player
} }
getItemById(id : number){ getItemById(id : number){
@ -49,14 +37,13 @@ export class playerData{
return item return item
} }
resetDamageInfo(){
this.damageInfo = []
}
validateEquipment(){ validateEquipment(){
if(this.inventory.equipment.length < 3){ if(this.inventory.equipment.length < 3){
this.inventory.equipment = [-1, -1, -1] this.inventory.equipment = [-1, -1, -1]
} }
} }
save(fs){
let data = JSON.stringify(this, null, 2);
fs.writeFileSync(`Database/Players/${this.id}.json`, data);
}
} }

View File

@ -1,4 +1,5 @@
import { Stat } from "./itemData.js" import { Stat } from "./itemData.js"
import { enemyDataUpdate } from "./Outgoing/enemyDataPartial.js"
import { physicsObject } from "./physicsObject.js" import { physicsObject } from "./physicsObject.js"
export class enemyData{ export class enemyData{
@ -7,21 +8,15 @@ export class enemyData{
rigidbody : physicsObject rigidbody : physicsObject
stats : Stat[] = [] stats : Stat[] = []
static copyStart(e: enemyData): any { constructor(init?: Partial<enemyData>){
let enemy : any = {} Object.assign(this, init);
enemy.id = e.id
enemy.templateId = e.templateId
enemy.rigidbody = physicsObject.characterOnly(e.rigidbody)
enemy.stats = e.stats
return enemy
} }
static copyUpdate(e: enemyData): any { copyStart() {
let enemy : any = {} return new enemyDataUpdate(this)
enemy.id = e.id }
enemy.templateId = e.templateId
enemy.rigidbody = physicsObject.characterOnly(e.rigidbody) copyUpdate() {
enemy.stats = e.stats return new enemyDataUpdate(this)
return enemy
} }
} }

View File

@ -1,6 +1,7 @@
import { enemyData } from "./enemyData.js"; import { enemyData } from "./enemyData.js";
import { playerData } from "./playerData.js"; import { characterData } from "./characterData.js";
import { propData } from "./propData.js"; import { propData } from "./propData.js";
import { levelStateStart, levelStateState as levelStateInfo, levelStateUpdate } from "./Outgoing/levelStatePartial.js";
export class levelState{ export class levelState{
id : string id : string
@ -10,7 +11,7 @@ export class levelState{
isDungeon : boolean = false isDungeon : boolean = false
enemies : enemyData[] = [] enemies : enemyData[] = []
objects : propData[] = [] objects : propData[] = []
players : playerData[] = [] players : characterData[] = []
getRandomInt(max) { getRandomInt(max) {
return Math.floor(Math.random() * max); return Math.floor(Math.random() * max);
@ -24,37 +25,15 @@ export class levelState{
} }
copyStart(){ copyStart(){
let level : any = {} return new levelStateStart(this)
level.id = this.id
level.seed = this.seed
level.hostId = this.hostId
level.completed = this.completed
level.isDungeon = this.isDungeon
if(this.enemies.length > 0) level.enemies = this.enemies.map(e => enemyData.copyStart(e))
if(this.objects.length > 0) level.objects = this.objects.map(e => propData.copyPropStart(e))
if(this.players.length > 0) level.players = this.players.map(pl=> pl.copyUpdate())
return level
} }
copyUpdate(){ copyUpdate(){
let level : any = {} return new levelStateUpdate(this)
level.id = this.id
level.seed = this.seed
level.hostId = this.hostId
level.completed = this.completed
if(this.enemies.length > 0) level.enemies = this.enemies.map(e => enemyData.copyUpdate(e))
if(this.objects.length > 0) level.objects = this.objects.map(e => propData.copyPropUpdate(e))
if(this.players.length > 0) level.players = this.players.map(pl=> pl.copyUpdate())
return level
} }
copyState(){ copyState(){
let level : any = {} return new levelStateInfo(this)
level.id = this.id
level.seed = this.seed
level.hostId = this.hostId
level.completed = this.completed
return level
} }
isHostValid(){ isHostValid(){
@ -67,7 +46,7 @@ export class levelState{
return true return true
} }
addPlayer(player : playerData) : boolean{ addPlayer(player : characterData) : boolean{
let playerIdx = this.players.findIndex(p=>p.id==player.id) let playerIdx = this.players.findIndex(p=>p.id==player.id)
if(playerIdx != -1) return false if(playerIdx != -1) return false
@ -80,13 +59,10 @@ export class levelState{
return true return true
} }
removePlayer(id) : boolean{ removePlayer(player : characterData) : boolean{
let playerIdx = this.players.findIndex(p=>p.id==id) this.players = this.players.filter(p=> p !== player)
if(playerIdx == -1) return false
this.players.splice(playerIdx,1) if(this.hostId == player.id){
if(this.hostId == id){
if(this.players.length > 0){ if(this.players.length > 0){
this.hostId = this.players[0].id this.hostId = this.players[0].id
} }

View File

@ -1,55 +1,32 @@
import { playerData } from "../Classes/playerData.js"; import { Socket } from "socket.io";
import { characterData } from "./characterData.js";
import { dungeonData } from "./dungeonData.js"; import { dungeonData } from "./dungeonData.js";
import { levelState } from "./levelState.js"; import { levelState } from "./levelState.js";
import { userData } from "./userData.js"; import { lobbyStateLight } from "./Outgoing/lobbyStatePartial.js";
export class lobbyState{ export class lobbyState{
users : userData[] = []; activeUsers : Socket[] = []
players : playerData[] = [];
rooms : levelState[] = [] rooms : levelState[] = []
dungeons : dungeonData[] = [] dungeons : dungeonData[] = []
copyLight(){ copyLight(){
let lobby = Object.assign({}, this); return new lobbyStateLight(this)
lobby.players = []
lobby.users = []
for (let i = 0; i < this.players.length; i++) {
lobby.players.push(this.players[i].copyUpdate());
}
lobby.rooms = this.rooms
lobby.dungeons = this.dungeons
return lobby
} }
addUser(userData, playerData){ addUser(socket : Socket){
let uIdx = this.users.findIndex(u=>u.id == userData.id) let uIdx = this.activeUsers.findIndex(u=>u === socket)
let pIdx = this.players.findIndex(u=>u.id == playerData.id) if(uIdx != -1){
if(uIdx != -1 || pIdx != -1){ console.log("User " + socket.user.login + " is already in the game!")
console.log("User " + userData.login + " is already in the game!")
return false; return false;
} }
this.users.push(userData) this.activeUsers.push(socket)
this.players.push(playerData)
return true return true
} }
removeUser(id){ removeUser(socket : Socket){
let idx = this.users.findIndex(u=>u.id == id) this.roomExit(socket.character.room, socket.character)
if(idx != -1){ this.activeUsers = this.activeUsers.filter(u=>u !== socket)
this.users.splice(idx, 1)
}
idx = this.players.findIndex(u=>u.id == id)
if(idx != -1){
let player = this.players[idx]
this.players.splice(idx, 1)
this.roomExit(player.room, player)
}
}
findPlayer(id: number){
return this.players.find(p=>p.id == id)
} }
getDungeonRoot(name){ getDungeonRoot(name){
@ -75,13 +52,17 @@ export class lobbyState{
return room return room
} }
removeRoom(room : levelState){
this.rooms = this.rooms.filter(r => r !== room)
}
createRoom(id : string, host : number){ createRoom(id : string, host : number){
let room = new levelState(id, host) let room = new levelState(id, host)
this.rooms.push(room) this.rooms.push(room)
return room return room
} }
roomEnter(targetRoom : levelState, player: playerData){ roomEnter(targetRoom : levelState, player: characterData){
if(!targetRoom.isDungeon){ if(!targetRoom.isDungeon){
let room = this.getRoom(targetRoom.id, true) let room = this.getRoom(targetRoom.id, true)
@ -112,19 +93,17 @@ export class lobbyState{
return null return null
} }
roomExit(roomId : string, player: playerData){ roomExit(roomId : string, player: characterData){
let room = this.getRoom(roomId, false) let room = this.getRoom(roomId, false)
if(room != null){ if(room != null){
if(room.removePlayer(player)){
if(room.removePlayer(player.id)){
if(room.isDungeon){ if(room.isDungeon){
let dungeon = this.getDungeon(this.getDungeonRoot(roomId), false) let dungeon = this.getDungeon(this.getDungeonRoot(roomId), false)
dungeon.playerCount -= 1; dungeon.playerCount -= 1;
this.tryRemoveDungeon(room.id) this.tryRemoveDungeon(room.id)
} }
else if(room.hostId == -1){ else if(room.hostId == -1){
let roomIdx = this.rooms.indexOf(room) this.removeRoom(room)
this.rooms.splice(roomIdx, 1)
} }
} }
@ -143,8 +122,7 @@ export class lobbyState{
if(dungeon.playerCount == 0){ if(dungeon.playerCount == 0){
this.dungeons.splice(dungeonIdx, 1) this.dungeons.splice(dungeonIdx, 1)
dungeon.rooms.forEach(room=>{ dungeon.rooms.forEach(room=>{
let roomIdx = this.rooms.findIndex(r=>r.id == room.id) this.removeRoom(room)
this.rooms.splice(roomIdx, 1)
}) })
} }

View File

@ -1,16 +0,0 @@
import { playerData } from "./playerData.js"
import { userData } from "./userData.js"
export class loginResponse{
result : boolean
userData : userData
playerData : playerData
constructor(result : boolean, user : userData, player : playerData){
this.result = result;
if(result){
this.userData = userData.makeSafe(user);
this.playerData = player;
}
}
}

View File

@ -4,4 +4,8 @@ export class playerInventory{
weapon : number = -1 weapon : number = -1
equipment : number[] = [-1,-1,-1] equipment : number[] = [-1,-1,-1]
items : itemData[] = [] items : itemData[] = []
constructor(init?: Partial<playerInventory>) {
Object.assign(this, init);
}
} }

View File

@ -1,3 +1,4 @@
import { propDataStart, propDataUpdate } from "./Outgoing/propDataPartial.js"
import { physicsObject } from "./physicsObject.js" import { physicsObject } from "./physicsObject.js"
export class propData{ export class propData{
@ -6,21 +7,11 @@ export class propData{
rigidbody : physicsObject rigidbody : physicsObject
components : any components : any
static copyPropStart(o: propData) { copyStart() {
let pObject = Object.assign({}, o) return new propDataStart(this)
pObject.rigidbody = physicsObject.copyStart(o.rigidbody)
return pObject
} }
static copyPropUpdate(o: propData) { copyUpdate() {
let pObject : any = {} return new propDataUpdate(this)
pObject.id = o.id
if(!physicsObject.isKinematic(o.rigidbody)){
pObject.rigidbody = physicsObject.copyUpdate(o.rigidbody)
}
if(o.components != null){
pObject.components = o.components
}
return pObject
} }
} }

View File

@ -1,8 +0,0 @@
import { levelState } from "./levelState.js"
import { playerData } from "./playerData.js"
export class roomChangeResponse{
player : playerData
newRoom : levelState
previousRoom : levelState
}

View File

@ -4,22 +4,14 @@ export class userData{
login: string; login: string;
password: string; password: string;
constructor(id:number, login:string, password:string){ constructor(init?: Partial<userData>){
this.id = id; Object.assign(this, init);
this.login = login;
this.password = password;
this.checksum = 0;
} }
static makeSafe(user : userData){ makeSafe() : userData{
let safeUser : any = Object.assign({}, user); let safeUser : userData = Object.assign({}, this);
delete safeUser.password delete safeUser.password
delete safeUser.checksum delete safeUser.checksum
return safeUser return safeUser
} }
save(fs){
let data = JSON.stringify(this, null, 2);
fs.writeFileSync(`Database/Users/${this.id}_${this.login}.json`, data);
}
} }

View File

@ -1,11 +1,78 @@
import Database from 'better-sqlite3'; import sqlite3 from 'sqlite3'
import { open } from 'sqlite' import { open, Database } from 'sqlite'
// this is a top-level await export class DatabaseController {
(async () => { private db: Database;
// open the database
private constructor(db: Database) {
this.db = db;
}
static async create(filename = ':memory:'): Promise<DatabaseController> {
const db = await open({ const db = await open({
filename: '/tmp/database.db', filename,
driver: Database driver: sqlite3.Database
}) });
})() let dbController = new DatabaseController(db);
dbController.basicSetup()
return dbController;
}
async basicSetup(){
await this.db.run(`CREATE TABLE IF NOT EXISTS characters (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL UNIQUE,
level INTEGER DEFAULT 0,
inventory TEXT,
questBook TEXT
);`)
await this.db.run(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
login TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
);`)
}
async select<T = any>(sql: string, params?: any[]): Promise<T[]> {
const rows: unknown = await this.db.all(sql, params);
return Array.isArray(rows) ? (rows as T[]) : [];
}
async get<T = any>(sql: string, params?: any[]): Promise<T | undefined> {
return this.db.get<T>(sql, params);
}
async run(sql: string, params?: any[]): Promise<void> {
await this.db.run(sql, params);
}
async close(): Promise<void> {
await this.db.close();
}
}
// Usage example (you can put this in another file):
// import { DatabaseController } from './db/DatabaseController';
// (async () => {
// const db = await DatabaseController.create('mydb.sqlite3');
// await db.run(`CREATE TABLE IF NOT EXISTS players (
// id INTEGER PRIMARY KEY,
// level INTEGER NOT NULL,
// inventory TEXT,
// questBook TEXT
// );`)
// await db.run(`CREATE TABLE IF NOT EXISTS users (
// id INTEGER PRIMARY KEY,
// login TEXT NOT NULL,
// password TEXT NOT NULL
// );`)
// await db.run('CREATE TABLE IF NOT EXISTS friends (id INTEGER PRIMARY KEY, name TEXT)');
// await db.run('INSERT INTO friends (name) VALUES (?)', ['Silver Fox']);
// const friends = await db.select('SELECT * FROM friends');
// console.log(friends); // [{ id: 1, name: 'Silver Fox' }]
// await db.close();
// })();

View File

@ -1,14 +1,13 @@
import { inventoryChange } from "../Classes/Incoming/inventoryChange.js"; import { inventoryChange } from "../Classes/Incoming/inventoryChange.js";
import { itemData } from "../Classes/itemData.js"; import { itemData } from "../Classes/itemData.js";
import { playerData } from "../Classes/playerData.js"; import { characterData } from "../Classes/characterData.js";
import { Socket } from "socket.io";
export function updateInventory(socket, data){
if(!socket.hasOwnProperty("player")) return;
export function updateInventory(socket : Socket, data){
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : inventoryChange[] = JSON.parse(buff.toString('utf-8')); let data1 : inventoryChange[] = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let player : characterData = socket.character
let inventory = player.inventory let inventory = player.inventory
data1.forEach(change=>{ data1.forEach(change=>{

View File

@ -1,7 +1,8 @@
import { Endpoints } from "../endpoints.js";
import { updateInventory } from "./_updateInventory.js"; import { updateInventory } from "./_updateInventory.js";
export function registerItemCallbacks(socket){ export function registerItemCallbacks(socket){
socket.on('item/updateInventory', (data) => { socket.on(Endpoints.UpdateInventory, (data) => {
updateInventory(socket, data) updateInventory(socket, data)
}); });
} }

View File

@ -1,11 +1,10 @@
import { Endpoints } from "../endpoints.js";
import { game } from "../game.js"; import { game } from "../game.js";
export function clear(socket, data){ export function clear(socket, data){
if(!socket.hasOwnProperty("player")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : string = JSON.parse(buff.toString('utf-8')); let data1 : string = JSON.parse(buff.toString('utf-8'));
let room = game.lobbyState.roomComplete(data1) let room = game.lobbyState.roomComplete(data1)
game.socketIO.emit("level/cleared", JSON.stringify(room.copyState())) game.socketIO.emit(Endpoints.LevelCleared, JSON.stringify(room.copyState()))
} }

View File

@ -1,30 +1,29 @@
import { game } from "../game.js"; import { game } from "../game.js";
import { playerData } from "../Classes/playerData.js"; import { characterData } from "../Classes/characterData.js";
import { roomChangeResponse } from "../Classes/roomChangeResponse.js"; import { roomChangeResponse } from "../Classes/Outgoing/roomChangeResponse.js";
import { levelEnter } from "../Classes/Incoming/levelEnter.js"; import { levelEnter } from "../Classes/Incoming/levelEnter.js";
import { Socket } from "socket.io";
import { Endpoints } from "../endpoints.js";
export function enter(socket, data){ export function enter(socket : Socket, data){
if(!socket.hasOwnProperty("player")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : levelEnter = JSON.parse(buff.toString('utf-8')); let data1 : levelEnter = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let character : characterData = socket.character
socket.join(data1.targetRoom.id) socket.join(data1.targetRoom.id)
let newRoom = game.lobbyState.roomEnter(data1.targetRoom, player) let newRoom = game.lobbyState.roomEnter(data1.targetRoom, character)
player.room = newRoom.id character.room = newRoom.id
socket.leave(data1.previousRoom.id) socket.leave(data1.previousRoom.id)
let oldRoom = game.lobbyState.roomExit(data1.previousRoom.id, player) let oldRoom = game.lobbyState.roomExit(data1.previousRoom.id, character)
let data2 = new roomChangeResponse() let data2 = new roomChangeResponse()
data2.player = player.copyUpdate() data2.player = character.copyUpdate()
data2.newRoom = newRoom.copyStart() data2.newRoom = newRoom.copyStart()
data2.previousRoom = oldRoom.copyState() data2.previousRoom = oldRoom.copyState()
socket.emit("level/entered", JSON.stringify(data2)) let json = JSON.stringify(data2)
data2.newRoom = newRoom.copyState() socket.emit(Endpoints.LevelEntered, json)
socket.broadcast.emit(Endpoints.LevelEntered, json)
socket.broadcast.emit("level/entered", JSON.stringify(data2))
} }

View File

@ -1,19 +1,20 @@
import { Socket } from "socket.io";
import { levelUpdateClient } from "../Classes/Incoming/levelUpdateClient.js"; import { levelUpdateClient } from "../Classes/Incoming/levelUpdateClient.js";
import { playerData } from "../Classes/playerData.js"; import { characterData } from "../Classes/characterData.js";
export function playerUpdate(socket, data){ export function playerUpdate(socket : Socket, data){
if(!socket.hasOwnProperty("user")) return; if(socket.user != null) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : levelUpdateClient = JSON.parse(buff.toString('utf-8')); let data1 : levelUpdateClient = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let character : characterData = socket.character
if(player == null){ if(character == null){
console.log("Error! Player not spawned!") console.log("Error! Player not spawned!")
return return
} }
player.rigidbody = data1.player.rigidbody character.rigidbody = data1.player.rigidbody
if(data1.player.hasOwnProperty("damageInfo")) if(data1.player.hasOwnProperty("damageInfo"))
player.damageInfo = player.damageInfo.concat(data1.player.damageInfo) character.damageInfo = character.damageInfo.concat(data1.player.damageInfo)
} }

View File

@ -1,10 +1,12 @@
import { playerData } from "../Classes/playerData.js"; import { Socket } from "socket.io";
import { characterData } from "../Classes/characterData.js";
import { Endpoints } from "../endpoints.js";
export function projectile(socket, data){ export function projectile(socket : Socket, data){
if(!socket.hasOwnProperty("user")) return; if(!socket.hasOwnProperty("user")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let player : playerData = socket.player let character : characterData = socket.character
socket.to(player.room).emit('level/projectile', buff.toString('utf-8')) socket.to(character.room).emit(Endpoints.LevelProjectile, buff.toString('utf-8'))
} }

View File

@ -1,16 +1,15 @@
import { Socket } from "socket.io";
import { levelUpdateHost } from "../Classes/Incoming/levelUpdateHost.js"; import { levelUpdateHost } from "../Classes/Incoming/levelUpdateHost.js";
import { playerData } from "../Classes/playerData.js"; import { characterData } from "../Classes/characterData.js";
import { game } from "../game.js"; import { game } from "../game.js";
export function update(socket, data){ export function update(socket : Socket, data){
if(!socket.hasOwnProperty("player")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : levelUpdateHost = JSON.parse(buff.toString('utf-8')); let data1 : levelUpdateHost = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let character : characterData = socket.character
let room = game.lobbyState.rooms.find(l=>l.id == data1.room.id) let room = game.lobbyState.rooms.find(l=>l.id == data1.room.id)
if (room == null || room.hostId != player.id){ if (room == null || room.hostId != character.id){
return return
} }
@ -21,7 +20,7 @@ export function update(socket, data){
data1.room.enemies = [] data1.room.enemies = []
} }
player.rigidbody = data1.player.rigidbody character.rigidbody = data1.player.rigidbody
room.enemies = data1.room.enemies room.enemies = data1.room.enemies
room.objects = data1.room.objects room.objects = data1.room.objects

View File

@ -1,3 +1,4 @@
import { Endpoints } from "../endpoints.js";
import { clear } from "./_clear.js"; import { clear } from "./_clear.js";
import { enter } from "./_enter.js"; import { enter } from "./_enter.js";
import { playerUpdate } from "./_playerUpdate.js"; import { playerUpdate } from "./_playerUpdate.js";
@ -5,23 +6,23 @@ import { projectile } from "./_projectile.js";
import { update } from "./_update.js"; import { update } from "./_update.js";
export function registerLevelCallbacks(socket){ export function registerLevelCallbacks(socket){
socket.on('level/enter', (data) => { socket.on(Endpoints.LevelEnter, (data) => {
enter(socket, data) enter(socket, data)
}); });
socket.on('level/cleared', (data) => { socket.on(Endpoints.LevelCleared, (data) => {
clear(socket, data) clear(socket, data)
}); });
socket.on('level/update', (data) => { socket.on(Endpoints.LevelUpdate, (data) => {
update(socket, data) update(socket, data)
}); });
socket.on('level/playerUpdate', (data) => { socket.on(Endpoints.LevelPlayerUpdate, (data) => {
playerUpdate(socket, data) playerUpdate(socket, data)
}); });
socket.on('level/projectile', (data) => { socket.on(Endpoints.LevelProjectile, (data) => {
projectile(socket, data) projectile(socket, data)
}); });
} }

View File

@ -1,16 +1,16 @@
import { playerData } from "../Classes/playerData.js"; import { Socket } from "socket.io";
import { characterData } from "../Classes/characterData.js";
import { game } from "../game.js"; import { game } from "../game.js";
import { Endpoints } from "../endpoints.js";
export function loadoutChanged(socket, data){ export function loadoutChanged(socket : Socket, data){
if(!socket.hasOwnProperty("player")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : playerData = JSON.parse(buff.toString('utf-8')); let data1 : characterData = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let character : characterData = socket.character
player.inventory.weapon = data1.inventory.weapon character.inventory.weapon = data1.inventory.weapon
player.inventory.equipment = data1.inventory.equipment character.inventory.equipment = data1.inventory.equipment
player.validateEquipment() character.validateEquipment()
socket.emit("lobby/loadoutChanged", JSON.stringify(player.copyInventory())) socket.emit(Endpoints.LoadoutChanged, JSON.stringify(character.copyInventory()))
} }

View File

@ -1,46 +1,50 @@
import { lobbyJoin } from "../Classes/Incoming/lobbyJoin.js"; import { lobbyJoin } from "../Classes/Incoming/lobbyJoin.js";
import { levelState } from "../Classes/levelState.js"; import { levelState } from "../Classes/levelState.js";
import { lobbyMessage } from "../Classes/lobbyMessage.js"; import { lobbyMessage } from "../Classes/lobbyMessage.js";
import { playerData } from "../Classes/playerData.js"; import { characterData } from "../Classes/characterData.js";
import { userData } from "../Classes/userData.js"; import { userData } from "../Classes/userData.js";
import { game } from "../game.js"; import { game } from "../game.js";
import { Socket } from "socket.io";
import { Endpoints } from "../endpoints.js";
export function playerJoin(socket, data){ export function playerJoin(socket : Socket, data){
if(!socket.hasOwnProperty("player")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : lobbyJoin = JSON.parse(buff.toString('utf-8')); let data1 : lobbyJoin = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let character : characterData = socket.character
player.room = "0_0" console.log(character)
player.characterId = data1.player.characterId
game.lobbyState.addUser(socket.user, player) character.room = "0_0"
let spawnRoom = game.lobbyState.roomEnter(new levelState("0_0", -1), player) character.characterId = data1.player.characterId
game.lobbyState.addUser(socket)
let spawnRoom = game.lobbyState.roomEnter(new levelState("0_0", -1), character)
socket.join("0_0") socket.join("0_0")
let newUser = { let newUser = {
users:[userData.makeSafe(socket.user)], users:[socket.user.makeSafe()],
players:[player.copyStart()], players:[character.copyStart()],
rooms:[] rooms:[]
}; };
let existingUsers = { let existingUsers = {
users:game.lobbyState.users.map(u=> userData.makeSafe(u)), users:game.lobbyState.activeUsers.map(u=> u.user.makeSafe()),
players:game.lobbyState.players.map(p=>p.copyStart()), players:game.lobbyState.activeUsers.map(p=>p.character.copyStart()),
rooms:[] rooms:game.lobbyState.rooms.map(room=>{
if(room == spawnRoom)
return spawnRoom.copyStart()
else
return room.copyState()
})
} }
game.lobbyState.rooms.forEach(room=>{ console.log(spawnRoom)
if(room == spawnRoom) console.log(spawnRoom.copyStart())
existingUsers.rooms.push(spawnRoom.copyStart()) console.log(existingUsers)
else
existingUsers.rooms.push(room.copyState())
})
//send only player to all existing players //send only player to all existing players
socket.broadcast.emit("lobby/playerJoin", JSON.stringify(newUser)); socket.broadcast.emit(Endpoints.PlayerJoin, JSON.stringify(newUser));
//send all users to player (including player) //send all users to player (including player)
socket.emit("lobby/playerJoin", JSON.stringify(existingUsers)) socket.emit(Endpoints.PlayerJoin, JSON.stringify(existingUsers))
game.addMessage(new lobbyMessage(socket.user.login + " joined")) game.addMessage(new lobbyMessage(socket.user.login + " joined"))
} }

View File

@ -1,17 +1,18 @@
import { Endpoints } from "../endpoints.js";
import { loadoutChanged } from "./_loadoutChanged.js"; import { loadoutChanged } from "./_loadoutChanged.js";
import { message } from "./_message.js"; import { message } from "./_message.js";
import { playerJoin } from "./_playerJoin.js"; import { playerJoin } from "./_playerJoin.js";
export function registerLobbyCallbacks(socket){ export function registerLobbyCallbacks(socket){
socket.on('lobby/playerJoin', (data) => { socket.on(Endpoints.PlayerJoin, (data) => {
playerJoin(socket, data) playerJoin(socket, data)
}); });
socket.on('lobby/loadoutChanged', (data) => { socket.on(Endpoints.LoadoutChanged, (data) => {
loadoutChanged(socket, data) loadoutChanged(socket, data)
}); });
socket.on('lobby/message', (data) => { socket.on(Endpoints.Message, (data) => {
message(socket, data) message(socket, data)
}); });
} }

View File

@ -1,45 +0,0 @@
import { game } from "../game.js";
import { playerData } from "../Classes/playerData.js";
export class players{
static createPlayer(id){
if (players.readPlayer(id) != null){
console.log(`Player ${id} alread exists`);
return null;
}
var player = new playerData();
player.id = id
game.playersDB.push(player);
return player;
}
static readPlayer(id : number){
let player = game.playersDB.find(u=>u.id == id);
return player;
}
static savePlayers(fs){
game.playersDB.forEach(player => {player.save(fs)});
}
static loadPlayers(fs){
fs.mkdirSync(`Database/Players/`, { recursive: true })
fs.readdir(`Database/Players/`, (err, files) => {
files.forEach(file => {
fs.readFile(`Database/Players/${file}`, (err, data) => {
if (err) throw err;
let player : playerData = new playerData(JSON.parse(data));
game.playersDB.push(player);
player.inventory.items.forEach(i=>{
if(i.id > game.itemCount){
game.itemCount = i.id
}
})
player.validateEquipment()
console.log(`Loaded pl ${player.id}`);
});
});
});
}
}

View File

@ -1,12 +1,11 @@
import { playerData } from "../Classes/playerData.js"; import { Socket } from "socket.io";
import { characterData } from "../Classes/characterData.js";
import { questProgressData } from "../Classes/questProgressData.js"; import { questProgressData } from "../Classes/questProgressData.js";
export function update(socket, data){ export function update(socket : Socket, data){
if(!socket.hasOwnProperty("player")) return;
let buff = Buffer.from(data, 'base64'); let buff = Buffer.from(data, 'base64');
let data1 : questProgressData = JSON.parse(buff.toString('utf-8')); let data1 : questProgressData = JSON.parse(buff.toString('utf-8'));
let player : playerData = socket.player let character : characterData = socket.character
player.questBook.updateQuest(data1) character.questBook.updateQuest(data1)
} }

View File

@ -1,7 +1,8 @@
import { Endpoints } from "../endpoints.js";
import { update } from "./_update.js"; import { update } from "./_update.js";
export function registerQuestCallbacks(socket){ export function registerQuestCallbacks(socket){
socket.on('quest/update', (data) => { socket.on(Endpoints.QuestUpdate, (data) => {
update(socket, data) update(socket, data)
}); });
} }

16
endpoints.ts Normal file
View File

@ -0,0 +1,16 @@
export enum Endpoints{
Login = "account/login",
Register = "account/register",
Message = 'lobby/message',
Messages = "lobby/messages",
PlayerJoin = "lobby/playerJoin",
LoadoutChanged = "lobby/loadoutChanged",
LevelEnter = 'level/enter',
LevelUpdate = 'level/update',
LevelCleared = 'level/cleared',
LevelEntered = "level/entered",
LevelProjectile = 'level/projectile',
LevelPlayerUpdate = 'level/playerUpdate',
UpdateInventory = 'item/updateInventory',
QuestUpdate = 'quest/update',
}

15
game.ts
View File

@ -1,17 +1,12 @@
import fs from 'fs';
import { userData } from "./Classes/userData.js";
import { lobbyMessage } from "./Classes/lobbyMessage.js"; import { lobbyMessage } from "./Classes/lobbyMessage.js";
import { lobbyState } from "./Classes/lobbyState.js"; import { lobbyState } from "./Classes/lobbyState.js";
import { playerData } from "./Classes/playerData.js";
import { persistentItemData } from "./Classes/itemData.js"; import { persistentItemData } from "./Classes/itemData.js";
import { levelState } from "./Classes/levelState.js"; import { Socket } from 'socket.io';
import { Endpoints } from "./endpoints.js";
export class game{ export class game{
static socketIO : any static socketIO : any
static itemCount : number = 0 static itemCount : number = 0
static accountsDB : userData[] = []
static playersDB : playerData[] = []
static itemsDB : persistentItemData[] = [] static itemsDB : persistentItemData[] = []
static lobbyState : lobbyState = new lobbyState() static lobbyState : lobbyState = new lobbyState()
@ -25,7 +20,7 @@ export class game{
} }
game.messages.unshift(message) game.messages.unshift(message)
game.socketIO.emit('lobby/messages', JSON.stringify(game.messages)) game.socketIO.emit(Endpoints.Messages, JSON.stringify(game.messages))
} }
static getItemTemplate(templateId){ static getItemTemplate(templateId){
@ -36,4 +31,8 @@ export class game{
} }
return item return item
} }
static removeUser(socket : Socket) : void {
this.lobbyState.activeUsers = this.lobbyState.activeUsers.filter(u => u !== socket)
}
} }

View File

@ -1,26 +1,28 @@
import fs from 'fs'; import './socketExtended.js';
import express from 'express'; import express from 'express';
import { createServer } from 'http'; import { createServer } from 'http';
import { Server as SocketIOServer } from 'socket.io'; import { Socket, Server as SocketIOServer } from 'socket.io';
import { game } from "./game.js"; import { game } from "./game.js";
import { users } from "./Account/users.js"; import { characters } from "./Characters/characters.js";
import { players } from "./Player/players.js";
import { registerItemCallbacks } from "./Items/itemSocket.js"; import { registerItemCallbacks } from "./Items/itemSocket.js";
import { registerLobbyCallbacks } from "./Lobby/lobbySocket.js"; import { registerLobbyCallbacks } from "./Lobby/lobbySocket.js";
import { registerAccountCallbacks } from "./Account/accountSocket.js"; import { registerAccountCallbacks } from "./Account/accountSocket.js";
import { registerLevelCallbacks } from "./Level/levelSocket.js"; import { registerLevelCallbacks } from "./Level/levelSocket.js";
import { registerQuestCallbacks } from "./Quest/questSocket.js"; import { registerQuestCallbacks } from "./Quest/questSocket.js";
import { DatabaseController } from './Database/dbcontroller.js';
import { SocketExtended } from './socketExtended.js';
import { Endpoints } from './endpoints.js';
const app = express(); const app = express();
const port = 3000; const port = 3000;
const server = createServer(app); const server = createServer(app);
export const db = await DatabaseController.create('./Database/mydb.sqlite3');
server.listen(port, () => { server.listen(port, () => {
console.log(`Server listening at port ${port}`); console.log(`Server listening at port ${port}`);
}); });
const io = new SocketIOServer(server, { const io = game.socketIO = new SocketIOServer(server, {
path: "/webmmo/", path: "/webmmo/",
cors: { cors: {
origin: '\*', origin: '\*',
@ -28,10 +30,7 @@ const io = new SocketIOServer(server, {
} }
}); });
users.loadUsers(fs); io.on('connection', (socket : SocketExtended) => {
players.loadPlayers(fs);
io.on('connection', (socket : any) => {
console.log("Got connection!"); console.log("Got connection!");
socket.emit("connectSuccess", ""); socket.emit("connectSuccess", "");
@ -41,18 +40,14 @@ io.on('connection', (socket : any) => {
registerLevelCallbacks(socket); registerLevelCallbacks(socket);
registerQuestCallbacks(socket); registerQuestCallbacks(socket);
socket.io = game.socketIO = io; socket.io = io;
socket.on("disconnect", () => { socket.on("disconnect", () => {
socket.disconnect() socket.disconnect()
if(socket.hasOwnProperty("player")){ if(socket.character != null){
socket.player.save(fs) characters.savePlayer(db, socket.character)
}
if(socket.hasOwnProperty("user")){
socket.user.save(fs)
game.lobbyState.removeUser(socket.user.id)
delete socket.user
} }
game.removeUser(socket)
console.log(socket.id + " disconnected"); console.log(socket.id + " disconnected");
}); });
@ -63,42 +58,37 @@ io.on('connection', (socket : any) => {
//Send player updates to everyone //Send player updates to everyone
setInterval(async () => { setInterval(async () => {
let userCount = game.lobbyState.players.length let userCount = game.lobbyState.activeUsers.length
if(userCount > 0){ if(userCount > 0){
game.lobbyState.rooms.forEach(room=>{ game.lobbyState.rooms.forEach(room=>{
let roomData = room.copyUpdate() let roomData = room.copyUpdate()
io.in(room.id).emit('level/update', JSON.stringify(roomData)) io.in(room.id).emit(Endpoints.LevelUpdate, JSON.stringify(roomData))
}) })
game.playersDB.forEach(p=>{ game.lobbyState.activeUsers.forEach(u=>{
p.damageInfo = [] u.character.resetDamageInfo()
}) })
} }
}, 1000/30) }, 1000/30)
setInterval(() => { // setInterval(() => {
let lobbyState = game.lobbyState // let lobbyState = game.lobbyState
console.clear() // console.clear()
console.log("Players:") // console.log("Players:")
for(let i = 0; i < lobbyState.players.length; i++){ // for(let i = 0; i < lobbyState.activeUsers.length; i++){
console.log(lobbyState.players[i].id + " " + lobbyState.players[i].room) // console.log(lobbyState.activeUsers[i].user.login + " " + lobbyState.activeUsers[i].character.room)
} // }
console.log("Rooms:") // console.log("Rooms:")
for(let i = 0; i < lobbyState.rooms.length; i++){ // for(let i = 0; i < lobbyState.rooms.length; i++){
console.log(lobbyState.rooms[i].id + " " + lobbyState.rooms[i].hostId) // console.log(lobbyState.rooms[i].id + " " + lobbyState.rooms[i].hostId)
lobbyState.rooms[i].objects.forEach(object => { // lobbyState.rooms[i].objects.forEach(object => {
console.log("\t" + object.id + ": " + JSON.stringify(object.rigidbody)) // console.log("\t" + object.id + ": " + JSON.stringify(object.rigidbody))
}); // });
} // }
console.log("Dungeon:") // console.log("Dungeon:")
for(let i = 0; i < lobbyState.dungeons.length; i++){ // for(let i = 0; i < lobbyState.dungeons.length; i++){
console.log(lobbyState.dungeons[i].entranceId + " " + lobbyState.dungeons[i].playerCount) // console.log(lobbyState.dungeons[i].entranceId + " " + lobbyState.dungeons[i].playerCount)
} // }
}, 5000) // }, 5000)
setInterval(() => {
users.saveUsers(fs);
players.savePlayers(fs);
}, 1000 * 60 * 60 * 12) //twice a day
process.on('uncaughtException', function (err) { process.on('uncaughtException', function (err) {
console.log('Caught exception: ', err); console.log('Caught exception: ', err);
@ -108,8 +98,7 @@ process.on('SIGINT', function () {
console.log('Ctrl-C...'); console.log('Ctrl-C...');
process.exit(2); process.exit(2);
}); });
process.on('exit', function () { process.on('exit', function () {
users.saveUsers(fs);
players.savePlayers(fs);
console.log("exitted"); console.log("exitted");
}); });

24
socketExtended.ts Normal file
View File

@ -0,0 +1,24 @@
import { characterData } from "./Classes/characterData.js"
import { userData } from "./Classes/userData.js"
import { Socket, Server as SocketIOServer } from 'socket.io';
declare module 'socket.io' {
interface Socket {
io: SocketIOServer
user: userData
character: characterData
}
}
export class SocketExtended extends Socket
{
validateUser() : boolean
{
return this.user != null;
}
validateCharacter() : boolean
{
return this.character != null;
}
}