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

+3 -3
View File
@@ -3,7 +3,7 @@
-- https://www.phpmyadmin.net/ -- https://www.phpmyadmin.net/
-- --
-- Host: localhost -- Host: localhost
-- Generation Time: Feb 21, 2026 at 09:07 PM -- Generation Time: Mar 05, 2026 at 06:35 PM
-- Server version: 11.8.6-MariaDB-log -- Server version: 11.8.6-MariaDB-log
-- PHP Version: 8.5.3 -- PHP Version: 8.5.3
@@ -119,7 +119,7 @@ CREATE TABLE `userposts` (
-- --
ALTER TABLE `chatroom_reports` ALTER TABLE `chatroom_reports`
ADD PRIMARY KEY (`id`), ADD PRIMARY KEY (`id`),
ADD KEY `chatId` (`chatId`); ADD KEY `chatroom_reports?chatId` (`chatId`);
-- --
-- Indexes for table `chats` -- Indexes for table `chats`
@@ -199,7 +199,7 @@ ALTER TABLE `userposts`
-- Constraints for table `chatroom_reports` -- Constraints for table `chatroom_reports`
-- --
ALTER TABLE `chatroom_reports` ALTER TABLE `chatroom_reports`
ADD CONSTRAINT `chatId` FOREIGN KEY (`chatId`) REFERENCES `chats` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; ADD CONSTRAINT `chatroom_reports?chatId` FOREIGN KEY (`chatId`) REFERENCES `chats` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
COMMIT; COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+324 -6
View File
@@ -7,6 +7,7 @@ import swagger from '@elysiajs/swagger'
import { berryDashChats, berryDashUserData, users } from './lib/tables' import { berryDashChats, berryDashUserData, users } from './lib/tables'
import { and, desc, eq } from 'drizzle-orm' import { and, desc, eq } from 'drizzle-orm'
import { checkAuthorization } from './lib/auth' import { checkAuthorization } from './lib/auth'
import { randomBytes } from 'crypto'
import { handler as getVerifyCodeHandler } from './routes/get-verify-code' import { handler as getVerifyCodeHandler } from './routes/get-verify-code'
@@ -106,19 +107,315 @@ interface ClientInfoData {
ClientPlatform: string 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 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', { app.ws('/ws', {
maxPayloadLength: 10 * 1024 * 1024, maxPayloadLength: 10 * 1024 * 1024,
open (ws) { open (ws) {
clients.add(ws) clients.add(ws)
console.log(ws.id, 'connected') // console.log(ws.id, 'connected')
}, },
async message (ws, message: any) { 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) {
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 ( if (
!message.sceneName || !message.sceneName ||
!message.Requester || !message.Requester ||
@@ -535,12 +832,33 @@ app.ws('/ws', {
} }
} }
}, },
close (ws) { async close (ws) {
clients.forEach(client => { clients.forEach(client => {
if (client.id === ws.id) clients.delete(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')
} }
}) })