import type { ServerWebSocket } from "bun"; import { Participiant } from "./Participiant"; import { Client } from "./Client"; import { proto } from "pianoverse"; import { addRoomBan, getRoomBans } from "./Database"; import { Server } from "./Server"; import { writeFileSync, existsSync, readFileSync } from "fs"; import { join } from "path"; interface Ban { banTime: number; minutes: number; } export class Room { particpiants = new Map(); name: string; private: boolean = false; owner: string; chats: proto.ServerMessage_Chat[] = []; constructor(name: string, owner: string) { this.name = name; if (Server.specialRooms.includes(this.name)) { this.owner = ""; } else { this.owner = owner; } if (existsSync("chats/" + this.name)) { const welcome = proto.ServerMessage.fromBinary( readFileSync("chats/" + this.name) ).welcome; if (!welcome) return; this.chats = welcome.chat; this.owner = welcome.owner; } else { this.systemMessage( "This is a development server. Instability may occur. Written by @fucksophie" ); } } private addToChatArray(chat: proto.ServerMessage_Chat) { this.chats.push(chat); if (this.chats.length > 150) this.chats.shift(); writeFileSync( join("chats", this.name), new proto.ServerMessage({ event: proto.ServerMessage_EventType.WELCOME, welcome: { chat: this!.chats, owner: this.owner, }, }).toBinary() ); } systemMessage(message: string) { const system = Server.systemMessage(message); this.addToChatArray(system.chat!); this.particpiants.forEach((z) => { z.clients.forEach((g) => { g.send(system); }); }); } chat(ws: ServerWebSocket, message: string) { const profile = Server.profiles.get(ws.data.id); if (!profile) return; const chatPacket = new proto.ServerMessage({ event: proto.ServerMessage_EventType.CHAT, chat: { id: ws.data.id, content: message, name: profile.name, color: profile.color, }, }); this.particpiants.forEach((z) => { z.send(chatPacket); }); this.addToChatArray(chatPacket.chat!); } ban(ws: ServerWebSocket, minutes: number) { if (this.name == "Backrooms") return; addRoomBan(ws.data.id, this.name, minutes, Date.now()); ws.data.backrooms(); } checkBan(ws: ServerWebSocket) { const ban = getRoomBans(this.name)?.find((z) => z.id == ws.data.id); if (!ban) return false; const time = ban.banTime - (Date.now() - ban.minutes * 60 * 1000); if (time <= 0) { return false; // Database.ts automatically removes the ban } else { return time; } } addClient(ws: ServerWebSocket) { ws.data.room = this; let particpiant = this.particpiants.get(ws.data.id); if (!particpiant) { particpiant = new Participiant(ws.data.id, this); particpiant.addClient(ws.data); this.particpiants.set(ws.data.id, particpiant); } else { particpiant.addClient(ws.data); } ws.data.send( new proto.ServerMessage({ event: proto.ServerMessage_EventType.WELCOME, welcome: { id: ws.data.id, name: particpiant.profile.name, color: particpiant.profile.color, room: ws.data.room!.name, owner: ws.data.room!.owner, chat: ws.data.room!.chats, role: particpiant.profile.role, }, }) ); if (particpiant.clients.length <= 1) { //#region Annouce to everyone that the user has joined const joinMessage = new proto.ServerMessage({ event: proto.ServerMessage_EventType.JOIN, join: { id: ws.data.id, name: particpiant.profile.name, color: particpiant.profile.color, role: particpiant.profile.role, }, }); [...this.particpiants.values()] .filter((z) => z.cid != ws.data.id) .forEach((z) => { z.send(joinMessage); }); } //#endregion //#region Annouce to player that everybody has joined [...this.particpiants.values()] .filter((z) => z.cid != ws.data.id) .forEach((z) => { const joinMessage = new proto.ServerMessage({ event: proto.ServerMessage_EventType.JOIN, join: { id: z.cid, name: z.profile.name, color: z.profile.color, role: z.profile.role, }, }); ws.data.send(joinMessage); }); //#endregion } }