diff --git a/Classes/dungeonData.ts b/Classes/dungeonData.ts new file mode 100644 index 0000000..0ff26e1 --- /dev/null +++ b/Classes/dungeonData.ts @@ -0,0 +1,25 @@ +import { game } from "../game" +import { levelState } from "./levelState" + +export class dungeonData{ + entranceId : string + rooms : levelState[] = [] + playerCount : number = 0 + + constructor(id:string) { + this.entranceId = id + } + + getRoom(roomId : string, create : boolean){ + let room = this.rooms.find(r=>r.id == roomId) + + if(room == null && create){ + room = new levelState(roomId, -1) + room.isDungeon = true + this.rooms.push(room) + game.lobbyState.rooms.push(room) + } + + return room + } +} \ No newline at end of file diff --git a/Classes/enemyDamageInfo.ts b/Classes/enemyDamageInfo.ts index 37cd8e3..385b8d6 100644 --- a/Classes/enemyDamageInfo.ts +++ b/Classes/enemyDamageInfo.ts @@ -1,6 +1,7 @@ export class enemyDamageInfo{ - sourceId : number - targetId : number + sourceId : number //player/enemy + targetId : number //player/enemy + targetName : string //physics objects relativePosition : number[] damage : number knockback : number diff --git a/Classes/levelState.ts b/Classes/levelState.ts index 85107a6..870569a 100644 --- a/Classes/levelState.ts +++ b/Classes/levelState.ts @@ -1,11 +1,78 @@ import { enemyData } from "./enemyData"; import { physicsObject } from "./physicsObject"; import { playerData } from "./playerData"; -import { userData } from "./userData"; export class levelState{ id : string + seed : number = -1 hostId : number = -1 - enemies : enemyData[] = []; - objects : physicsObject[] = []; + completed : boolean = false + isDungeon : boolean = false + enemies : enemyData[] = [] + objects : physicsObject[] = [] + players : playerData[] = [] + + getRandomInt(max) { + return Math.floor(Math.random() * max); + } + + constructor(id, hostId){ + this.id = id + this.hostId = hostId + this.seed = this.getRandomInt(1000000) + this.completed = false + } + + copyLight() { + let level : any = {} + level.id = this.id + level.seed = this.seed + level.hostId = this.hostId + level.completed = this.completed + level.enemies = this.enemies + level.objects = this.objects + level.players = this.players.map(pl=>pl.copyLight()) + return level + } + + isHostValid(){ + if(this.hostId == -1) return false + if(this.players.length == 0) return false + + let playerIdx = this.players.findIndex(p=>p.id==this.hostId) + if(playerIdx == -1) return false + + return true + } + + addPlayer(player : playerData) : boolean{ + let playerIdx = this.players.findIndex(p=>p.id==player.id) + if(playerIdx != -1) return false + + this.players.push(player) + + if(this.hostId == -1){ + this.hostId = this.players[0].id + } + + return true + } + + removePlayer(id) : boolean{ + let playerIdx = this.players.findIndex(p=>p.id==id) + if(playerIdx == -1) return false + + this.players.splice(playerIdx,1) + + if(this.hostId == id){ + if(this.players.length > 0){ + this.hostId = this.players[0].id + } + else{ + this.hostId = -1; + } + } + + return true + } } \ No newline at end of file diff --git a/Classes/lobbyState.ts b/Classes/lobbyState.ts index 27a7c65..aec6afa 100644 --- a/Classes/lobbyState.ts +++ b/Classes/lobbyState.ts @@ -1,4 +1,5 @@ import { playerData } from "../Classes/playerData"; +import { dungeonData } from "./dungeonData"; import { levelState } from "./levelState"; import { userData } from "./userData"; @@ -6,6 +7,7 @@ export class lobbyState{ users : userData[] = []; players : playerData[] = []; rooms : levelState[] = [] + dungeons : dungeonData[] = [] copyLight(){ let lobby = Object.assign({}, this); @@ -15,6 +17,7 @@ export class lobbyState{ lobby.players.push(this.players[i].copyLight()); } lobby.rooms = this.rooms + lobby.dungeons = this.dungeons return lobby } @@ -39,11 +42,112 @@ export class lobbyState{ 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){ + let split = name.split("_") + return split[0] + "_" + split[1] + "_0_0" + } + + getDungeon(id : string, create : boolean){ + let dungeon = this.dungeons.find(r=>r.entranceId == id) + if(dungeon == null && create){ + dungeon = new dungeonData(id) + this.dungeons.push(dungeon) + } + return dungeon + } + + getRoom(id: string, create : boolean){ + let room = this.rooms.find(r=>r.id == id) + if(room == null && create){ + room = new levelState(id, -1) + this.rooms.push(room) + } + return room + } + + createRoom(id : string, host : number){ + let room = new levelState(id, host) + this.rooms.push(room) + return room + } + + roomEnter(targetRoom : levelState, player: playerData){ + if(!targetRoom.isDungeon){ + let room = this.getRoom(targetRoom.id, true) + + room.addPlayer(player) + + return room + } + else{ + let dungeon = this.getDungeon(this.getDungeonRoot(targetRoom.id), true); + + let room = dungeon.getRoom(targetRoom.id, true) + + if(room.addPlayer(player)){ + dungeon.playerCount += 1; + } + + return room + } + } + + roomComplete(roomId: string){ + let room = this.getRoom(roomId, false) + if(room != null){ + room.completed = true + return room + } + + return null + } + + roomExit(roomId : string, player: playerData){ + let room = this.getRoom(roomId, false) + if(room != null){ + + if(room.removePlayer(player.id)){ + if(room.isDungeon){ + let dungeon = this.getDungeon(this.getDungeonRoot(roomId), false) + dungeon.playerCount -= 1; + this.tryRemoveDungeon(room.id) + } + else if(room.hostId == -1){ + let roomIdx = this.rooms.indexOf(room) + this.rooms.splice(roomIdx, 1) + } + } + + return room + } + + return null + } + + tryRemoveDungeon(roomId : string){ + let dungeonIdx = this.dungeons.findIndex(r=>r.entranceId == this.getDungeonRoot(roomId)) + + if(dungeonIdx == -1) return false + + let dungeon = this.dungeons[dungeonIdx] + if(dungeon.playerCount == 0){ + this.dungeons.splice(dungeonIdx, 1) + dungeon.rooms.forEach(room=>{ + let roomIdx = this.rooms.findIndex(r=>r.id == room.id) + this.rooms.splice(roomIdx, 1) + }) + } + + return true + } } \ No newline at end of file diff --git a/Classes/physicsObject.ts b/Classes/physicsObject.ts index 230bdf6..586e59b 100644 --- a/Classes/physicsObject.ts +++ b/Classes/physicsObject.ts @@ -1,8 +1,16 @@ export class physicsObject{ name : string + templateId : number //array of floats [3] + kinematic : boolean position : number[] = [0,0,0] rotation : number[] = [0,0,0] velocity : number[] = [0,0,0] angularVelocity : number[] = [0,0,0] + + static copyLight(o: physicsObject) { + let pObject = Object.assign({}, o) + + return pObject + } } \ No newline at end of file diff --git a/Classes/playerData.ts b/Classes/playerData.ts index 7fbd007..207a450 100644 --- a/Classes/playerData.ts +++ b/Classes/playerData.ts @@ -1,4 +1,3 @@ -import { game } from "../game"; import { enemyDamageInfo } from "./enemyDamageInfo"; import { physicsObject } from "./physicsObject"; import { playerInventory } from "./playerInventory"; @@ -15,8 +14,8 @@ export class playerData{ copyLight(){ let player : any = {} player.id = this.id - player.room = this.room - player.rigidbody = this.rigidbody + //player.room = this.room + player.rigidbody = physicsObject.copyLight(this.rigidbody) player.damageInfo = this.damageInfo return player } diff --git a/Classes/roomChangeRequest.ts b/Classes/roomChangeRequest.ts new file mode 100644 index 0000000..99bd023 --- /dev/null +++ b/Classes/roomChangeRequest.ts @@ -0,0 +1,6 @@ +import { levelState } from "./levelState" + +export class roomChangeData{ + previousRoom : string + targetRoom : levelState +} \ No newline at end of file diff --git a/Classes/roomChangeResponse.ts b/Classes/roomChangeResponse.ts new file mode 100644 index 0000000..ef7fa42 --- /dev/null +++ b/Classes/roomChangeResponse.ts @@ -0,0 +1,8 @@ +import { levelState } from "./levelState" +import { playerData } from "./playerData" + +export class roomChangeResponse{ + player : playerData + newRoom : levelState + previousRoom : levelState +} \ No newline at end of file diff --git a/Level/_projectile.ts b/Level/_projectile.ts index c00a6f1..98e4112 100644 --- a/Level/_projectile.ts +++ b/Level/_projectile.ts @@ -1,10 +1,8 @@ -import { game } from "../game"; - export function projectile(socket, data){ if(!socket.hasOwnProperty("user")) return; let buff = Buffer.from(data, 'base64'); //let data1 = JSON.parse(); - game.socketIO.emit('level/projectile', buff.toString('utf-8')) + socket.to(socket.player.room).emit('level/projectile', buff.toString('utf-8')) } \ No newline at end of file diff --git a/Level/_update.ts b/Level/_update.ts index 45e23ab..f59f081 100644 --- a/Level/_update.ts +++ b/Level/_update.ts @@ -10,9 +10,7 @@ export function update(socket, data){ let room = game.lobbyState.rooms.find(l=>l.id == data1.id) if (room == null){ - room = new levelState() - room.id = data1.id - game.lobbyState.rooms.push(room) + return } let player = socket.player diff --git a/Lobby/_clearRoom.ts b/Lobby/_clearRoom.ts new file mode 100644 index 0000000..c992eea --- /dev/null +++ b/Lobby/_clearRoom.ts @@ -0,0 +1,11 @@ +import { game } from "../game"; + +export function clearRoom(socket, data){ + if(!socket.hasOwnProperty("player")) return; + + let buff = Buffer.from(data, 'base64'); + let data1 : string = JSON.parse(buff.toString('utf-8')); + + let room = game.lobbyState.roomComplete(data1) + game.socketIO.emit("lobby/cleared", JSON.stringify(room)) +} \ No newline at end of file diff --git a/Lobby/_enter.ts b/Lobby/_enter.ts new file mode 100644 index 0000000..7e319be --- /dev/null +++ b/Lobby/_enter.ts @@ -0,0 +1,24 @@ +import { roomChangeData as roomChangeRequest } from "../Classes/roomChangeRequest"; +import { roomChangeResponse } from "../Classes/roomChangeResponse"; +import { game } from "../game"; + +export function enter(socket, data){ + if(!socket.hasOwnProperty("player")) return; + + let buff = Buffer.from(data, 'base64'); + let data1 : roomChangeRequest = JSON.parse(buff.toString('utf-8')); + + socket.join(data1.targetRoom.id) + let newRoom = game.lobbyState.roomEnter(data1.targetRoom, socket.player) + socket.player.room = newRoom.id + + socket.leave(data1.previousRoom) + let oldRoom = game.lobbyState.roomExit(data1.previousRoom, socket.player) + + let data2 = new roomChangeResponse() + data2.player = socket.player.copyLight() + data2.newRoom = newRoom.copyLight() + data2.previousRoom = oldRoom.copyLight() + + game.socketIO.emit("lobby/entered", JSON.stringify(data2)) +} \ No newline at end of file diff --git a/Lobby/_playerJoin.ts b/Lobby/_playerJoin.ts index aa0662c..81c5916 100644 --- a/Lobby/_playerJoin.ts +++ b/Lobby/_playerJoin.ts @@ -1,5 +1,5 @@ +import { levelState } from "../Classes/levelState"; import { lobbyMessage } from "../Classes/lobbyMessage"; -import { lobbyState } from "../Classes/lobbyState"; import { playerData } from "../Classes/playerData"; import { userData } from "../Classes/userData"; import { game } from "../game"; @@ -13,9 +13,29 @@ export function playerJoin(socket, data){ socket.player.characterId = data1.characterId game.lobbyState.addUser(socket.user, socket.player) - let newLobbyState : lobbyState = Object.assign({}, game.lobbyState); - newLobbyState.users = newLobbyState.users.map(u=> userData.makeSafe(u)) + let newUser = {users:[userData.makeSafe(socket.user)], players:[socket.player], rooms:[]}; + let existingUsers = {users:game.lobbyState.users.map(u=> userData.makeSafe(u)), players:[], rooms:[]} + + game.lobbyState.players.forEach(player=>{ + if(player.id == socket.player.id){ + existingUsers.players.push(player) + } + else{ + let newPlayer = Object.assign({}, player); + delete(newPlayer.inventory) + existingUsers.players.push(newPlayer) + } + }) + + let room = game.lobbyState.roomEnter(new levelState("0_0", -1), socket.player) + existingUsers.rooms = game.lobbyState.rooms + socket.join("0_0") + + //send only player to all existing players + socket.broadcast.emit("lobby/playerJoin", JSON.stringify(newUser)); + + //send all users to player (including player) + socket.emit("lobby/playerJoin", JSON.stringify(existingUsers)) - game.socketIO.emit("lobby/playerJoin", JSON.stringify(newLobbyState)) game.addMessage(new lobbyMessage(socket.user.login + " joined")) } \ No newline at end of file diff --git a/Lobby/_playerUpdate.ts b/Lobby/_playerUpdate.ts index d392569..296ef3a 100644 --- a/Lobby/_playerUpdate.ts +++ b/Lobby/_playerUpdate.ts @@ -9,10 +9,10 @@ export function playerUpdate(socket, data){ let player : playerData = socket.player if(player == null){ console.log("Error! Player not spawned!") + return } - else{ - player.room = data1.room - player.rigidbody = data1.rigidbody - player.damageInfo = player.damageInfo.concat(data1.damageInfo) - } + + player.room = data1.room + player.rigidbody = data1.rigidbody + player.damageInfo = player.damageInfo.concat(data1.damageInfo) } \ No newline at end of file diff --git a/Lobby/lobbySocket.ts b/Lobby/lobbySocket.ts index 363134f..0113094 100644 --- a/Lobby/lobbySocket.ts +++ b/Lobby/lobbySocket.ts @@ -1,9 +1,19 @@ +import { clearRoom } from "./_clearRoom"; +import { enter } from "./_enter"; import { loadoutChanged } from "./_loadoutChanged"; import { message } from "./_message"; import { playerJoin } from "./_playerJoin"; import { playerUpdate } from "./_playerUpdate"; export function registerLobbyCallbacks(socket){ + socket.on('lobby/enter', (data) => { + enter(socket, data) + }); + + socket.on('lobby/cleared', (data) => { + clearRoom(socket, data) + }); + socket.on('lobby/playerJoin', (data) => { playerJoin(socket, data) }); diff --git a/index.ts b/index.ts index 0ce7cc3..3d0cb44 100644 --- a/index.ts +++ b/index.ts @@ -6,7 +6,8 @@ import { registerItemCallbacks } from "./Items/itemSocket"; import { registerLobbyCallbacks } from "./Lobby/lobbySocket"; import { registerAccountCallbacks } from "./Account/accountSocket"; import { registerLevelCallbacks } from "./Level/levelSocket"; -import { levelState } from "./Classes/levelState"; +import { physicsObject } from "./Classes/physicsObject"; +import { enemyData } from "./Classes/enemyData"; const express = require("express"); const app = express(); @@ -54,50 +55,14 @@ io.on('connection', (socket) => { }); //Send player updates to everyone -setInterval(() => { +setInterval(async () => { let userCount = game.lobbyState.players.length if(userCount > 0){ - game.lobbyState.players.forEach(p=>{ - let room = game.lobbyState.rooms.find(r=>r.id == p.room) - if (room == null){ - room = new levelState() - room.id = p.room - game.lobbyState.rooms.push(room) - console.log("Added room " + room.id) - } - }) - let removeRooms = [] - for (let i = 0; i < game.lobbyState.rooms.length; i++){ - let room = game.lobbyState.rooms[i] + game.lobbyState.rooms.forEach(room=>{ + let roomData = room.copyLight() - //assign host to a room if there isn't one - if(room.hostId == -1){ - let hostPlayer = game.lobbyState.players.find(p=>p.room == room.id) - if(hostPlayer != null){ - room.hostId = hostPlayer.id - continue; - } - } - - //verify if host is still in the room - let hostPlayer = game.lobbyState.players.find(p=>p.id == room.hostId) - if(hostPlayer == null || hostPlayer.room != room.id){ - //if they aren't, find another - hostPlayer = game.lobbyState.players.find(p=>p.room == room.id) - if(hostPlayer != null){ - room.hostId = hostPlayer.id - } - else{ - room.hostId = -1 - removeRooms.push(i) - } - } - } - for(let i = removeRooms.length - 1; i >= 0; i--){ - console.log("no players in room " + game.lobbyState.rooms[removeRooms[i]] + ". removing.") - game.lobbyState.rooms.splice(removeRooms[i],1); - } - io.emit('lobby/update', JSON.stringify(game.lobbyState.copyLight())) + io.in(room.id).emit('lobby/update', JSON.stringify(roomData)) + }) game.playersDB.forEach(p=>{ p.damageInfo = [] }) @@ -105,7 +70,19 @@ setInterval(() => { }, 1000/30) setInterval(() => { - console.log("Players: " + game.lobbyState.players.length + ", users: " + game.lobbyState.users.length + ", rooms: " + game.lobbyState.rooms.length); + let lobbyState = game.lobbyState + console.log("Players:") + for(let i = 0; i < lobbyState.players.length; i++){ + console.log(lobbyState.players[i].id + " " + lobbyState.players[i].room) + } + console.log("Rooms:") + for(let i = 0; i < lobbyState.rooms.length; i++){ + console.log(lobbyState.rooms[i].id + " " + lobbyState.rooms[i].hostId) + } + console.log("Dungeon:") + for(let i = 0; i < lobbyState.dungeons.length; i++){ + console.log(lobbyState.dungeons[i].entranceId + " " + lobbyState.dungeons[i].playerCount) + } }, 60 * 1000) process.on('SIGINT', function () {