Early version of multiplayer

This commit is contained in:
Lncvrt committed 2026-03-05 11:36:17 -07:00
1 parent 9600a8ea6b
commit da0a38eec3
2 files changed
+327 -9

No files matched your search

+324 -6
View File
@@ -7,6 +7,7 @@ import swagger from '@elysiajs/swagger'
import { berryDashChats, berryDashUserData, users } from './lib/tables'
import { and, desc, eq } from 'drizzle-orm'
import { checkAuthorization } from './lib/auth'
import { randomBytes } from 'crypto'
import { handler as getVerifyCodeHandler } from './routes/get-verify-code'
@@ -106,19 +107,315 @@ interface ClientInfoData {
ClientPlatform: string
}
interface MultiplayerClient {
Id: string
Key: string
PosX: number
PosY: number
Flipped: boolean
Paused: boolean
FlaggedReason: string | null
Token: string
Username: string
UserID: number
Admin: boolean
Platform: number | null
JoinTimestamp: number
}
interface MultiplayerBerry {
Id: string
Type: string
Timestamp: number
PosX: number
}
const clients = new Set<ElysiaWS>()
const clientInfo: ClientInfoData[] = []
let clientInfo: ClientInfoData[] = []
let multiplayerClients: MultiplayerClient[] = []
let multiplayerBerries: MultiplayerBerry[] = []
setInterval(async () => {
if (multiplayerClients.length == 0) return
let berry = ''
const spawnProbability = Math.random()
const id = randomBytes(16).toString('hex')
if (spawnProbability <= 0.575) {
berry = 'NormalBerry'
} else if (spawnProbability <= 0.75) {
berry = 'PoisonBerry'
} else if (spawnProbability <= 0.85) {
berry = 'SlowBerry'
} else if (spawnProbability <= 0.95) {
berry = 'UltraBerry'
} else {
berry = 'RandomBerry'
}
const time = Date.now()
const posX = Math.random()
const data: MultiplayerBerry = {
Id: id,
Type: berry,
Timestamp: time,
PosX: posX
}
multiplayerBerries.push(data)
for (const multiplayerClientInfo of multiplayerClients) {
const client = Array.from(clients).find(
client => client.id === multiplayerClientInfo.Id
)
if (!client) continue
client.send({
type: 'multiplayer_berry_spawn',
id,
berryType: berry,
posX,
timestamp: time
})
}
}, 1000)
app.ws('/ws', {
maxPayloadLength: 10 * 1024 * 1024,
open (ws) {
clients.add(ws)
console.log(ws.id, 'connected')
// console.log(ws.id, 'connected')
},
async message (ws, message: any) {
// console.log('received:', message, 'from', ws.id)
console.log('received:', message, 'from', ws.id)
if (message == 'ping') ws.send('ping')
if (message.type) {
if (message.type == 'connected_with_current_scene') {
if (
message.type == 'multiplayer_player_move' &&
message.x !== undefined &&
message.y !== undefined &&
message.f !== undefined
) {
const multiplayerInfo = multiplayerClients.find(
client => client.Id == ws.id
)
if (!multiplayerInfo) return
multiplayerInfo.PosX = Number(message.x)
multiplayerInfo.PosY = Number(message.y)
multiplayerInfo.Flipped = Boolean(message.f)
const index = multiplayerClients.findIndex(client => client.Id == ws.id)
if (index === -1) return
multiplayerClients[index] = multiplayerInfo
for (const multiplayerClientInfo of multiplayerClients) {
if (ws.id == multiplayerClientInfo.Id) continue
const client = Array.from(clients).find(
client => client.id === multiplayerClientInfo.Id
)
if (!client) continue
client.send({
type: 'multiplayer_player_move',
id: multiplayerInfo.UserID,
x: Number(message.x),
y: Number(message.y),
f: Boolean(message.f)
})
}
} else if (message.type == 'multiplayer_leave') {
const multiplayerInfo = multiplayerClients.find(
client => client.Id == ws.id
)
if (!multiplayerInfo) return
multiplayerClients = multiplayerClients.filter(
client => client.Id !== ws.id
)
for (const multiplayerClientInfo of multiplayerClients) {
if (ws.id == multiplayerClientInfo.Id) continue
const client = Array.from(clients).find(
client => client.id === multiplayerClientInfo.Id
)
if (!client) continue
client.send({
type: 'multiplayer_player_leave',
id: multiplayerInfo.UserID
})
}
} else if (message.type == 'multiplayer_join_request' && message.auth) {
const dbInfo0 = getDatabaseConnection(0)
const dbInfo1 = getDatabaseConnection(1)
if (!dbInfo0 || !dbInfo1) {
ws.send({
type: 'multiplayer_join_response',
accepted: false,
denyReason: 'Unable to authenticate',
key: null,
players: []
})
return
}
const { connection: connection0, db: db0 } = dbInfo0
const { connection: connection1, db: db1 } = dbInfo1
const ip = ws.remoteAddress
const authResult = await checkAuthorization(
message.auth as string,
db0,
ip
)
if (!authResult.valid) {
connection0.end()
connection1.end()
ws.send({
type: 'multiplayer_join_response',
accepted: false,
denyReason: 'Unable to authenticate',
id: null,
players: []
})
return
}
const userId = authResult.id
const result = await db0
.select({
username: users.username,
admin: users.admin,
token: users.token
})
.from(users)
.where(eq(users.id, userId))
.execute()
if (result.length != 1) {
connection0.end()
connection1.end()
ws.send({
type: 'multiplayer_join_response',
accepted: false,
denyReason: 'Unable to authenticate',
id: null,
players: null
})
return
}
const players: any = []
for (const marketplaceInfo of multiplayerClients) {
const userData = await db1
.select({
saveData: berryDashUserData.saveData
})
.from(berryDashUserData)
.where(and(eq(berryDashUserData.id, marketplaceInfo.UserID)))
.execute()
const savedata = userData[0].saveData
? JSON.parse(userData[0].saveData)
: null
if (!savedata) {
connection0.end()
connection1.end()
return
}
const customIcon = savedata.bird?.customIcon?.selected ?? null
const icon = customIcon ? 0 : savedata?.icon ?? 1
const overlay = customIcon ? 1 : savedata?.overlay ?? 0
const iconColor = customIcon
? [255, 255, 255]
: savedata?.settings?.colors?.icon ?? [255, 255, 255]
const overlayColor = customIcon
? [255, 255, 255]
: savedata?.settings?.colors?.overlay ?? [255, 255, 255]
players.push({
id: marketplaceInfo.UserID,
username: result[0].username,
admin: result[0].admin,
timestamp: marketplaceInfo.JoinTimestamp,
iconData: {
icon,
overlay,
iconColor,
overlayColor,
customIcon: customIcon ?? ''
}
})
}
const key = randomBytes(16).toString('hex')
const time = Date.now()
const data: MultiplayerClient = {
Id: ws.id,
Key: key,
PosX: 0,
PosY: -1,
Flipped: false,
Paused: false,
FlaggedReason: null,
Token: result[0].token, //Just to be safe
Username: result[0].username,
UserID: userId,
Admin: result[0].admin,
Platform: null,
JoinTimestamp: time
}
multiplayerClients.push(data)
ws.send({
type: 'multiplayer_join_response',
accepted: true,
denyReason: null,
players
})
const userData = await db1
.select({
saveData: berryDashUserData.saveData
})
.from(berryDashUserData)
.where(and(eq(berryDashUserData.id, userId)))
.execute()
const savedata = userData[0].saveData
? JSON.parse(userData[0].saveData)
: null
if (!savedata) {
connection0.end()
connection1.end()
return
}
const customIcon = savedata.bird?.customIcon?.selected ?? null
const icon = customIcon ? 0 : savedata?.icon ?? 1
const overlay = customIcon ? 1 : savedata?.overlay ?? 0
const iconColor = customIcon
? [255, 255, 255]
: savedata?.settings?.colors?.icon ?? [255, 255, 255]
const overlayColor = customIcon
? [255, 255, 255]
: savedata?.settings?.colors?.overlay ?? [255, 255, 255]
for (const multiplayerClientInfo of multiplayerClients) {
if (ws.id == multiplayerClientInfo.Id) continue
const client = Array.from(clients).find(
client => client.id === multiplayerClientInfo.Id
)
if (!client) continue
client.send({
type: 'multiplayer_player_join',
id: userId,
username: result[0].username,
admin: result[0].admin,
timestamp: time,
iconData: {
icon,
overlay,
iconColor,
overlayColor,
customIcon: customIcon ?? ''
}
})
}
connection0.end()
connection1.end()
} else if (message.type == 'connected_with_current_scene') {
if (
!message.sceneName ||
!message.Requester ||
@@ -535,12 +832,33 @@ app.ws('/ws', {
}
}
},
close (ws) {
async close (ws) {
clients.forEach(client => {
if (client.id === ws.id) clients.delete(client)
})
clientInfo = clientInfo.filter(client => client.Id !== ws.id)
console.log(ws.id, 'disconnected')
const multiplayerInfo = multiplayerClients.find(
client => client.Id == ws.id
)
if (multiplayerInfo) {
multiplayerClients = multiplayerClients.filter(
client => client.Id !== ws.id
)
for (const multiplayerClientInfo of multiplayerClients) {
if (ws.id == multiplayerClientInfo.Id) continue
const client = Array.from(clients).find(
client => client.id === multiplayerClientInfo.Id
)
if (!client) continue
client.send({
type: 'multiplayer_player_leave',
id: multiplayerInfo.UserID
})
}
}
// console.log(ws.id, 'disconnected')
}
})