mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
"Remove" the global room
I couldn't completely remove the global room in one commit, but this solves basically every problem with it by making it no longer a `Room`. In particular, this means: - It's no longer of type `Room` - It's no longer in the `Rooms.rooms` table - Its class name is now `GlobalRoomState` rather than `GlobalRoom` - It no longer tracks its own user list (online user count is now provided by `Users.onlineCount`) - It's no longer a socket channel (there's new syntax for "send this message to every user")
This commit is contained in:
parent
bf21d8fd0a
commit
702fe9f532
|
|
@ -71,7 +71,7 @@ export const commands: ChatCommands = {
|
|||
html += Utils.html`<div style="float:right;color:#888;font-size:8pt">[${user.name}]</div><div style="clear:both"></div>`;
|
||||
}
|
||||
|
||||
this.room.sendRankedUsers(`|html|<div class="infobox">${html}</div>`, rank as GroupSymbol);
|
||||
room.sendRankedUsers(`|html|<div class="infobox">${html}</div>`, rank as GroupSymbol);
|
||||
},
|
||||
addrankhtmlboxhelp: [
|
||||
`/addrankhtmlbox [rank], [message] - Shows everyone with the specified rank or higher a message, parsing HTML code contained. Requires: * # &`,
|
||||
|
|
@ -121,7 +121,7 @@ export const commands: ChatCommands = {
|
|||
}
|
||||
|
||||
html = `|uhtml${(cmd === 'changerankuhtml' ? 'change' : '')}|${name}|${html}`;
|
||||
this.room.sendRankedUsers(html, rank as GroupSymbol);
|
||||
room.sendRankedUsers(html, rank as GroupSymbol);
|
||||
},
|
||||
addrankuhtmlhelp: [
|
||||
`/addrankuhtml [rank], [name], [message] - Shows everyone with the specified rank or higher a message that can change, parsing HTML code contained. Requires: * # &`,
|
||||
|
|
@ -324,7 +324,7 @@ export const commands: ChatCommands = {
|
|||
// respawn simulator processes
|
||||
void Rooms.PM.respawn();
|
||||
// broadcast the new formats list to clients
|
||||
Rooms.global.send(Rooms.global.formatListText);
|
||||
Rooms.global.sendAll(Rooms.global.formatListText);
|
||||
|
||||
this.sendReply("Formats have been hot-patched.");
|
||||
} else if (target === 'loginserver') {
|
||||
|
|
@ -787,7 +787,7 @@ export const commands: ChatCommands = {
|
|||
|
||||
refreshpage(target, room, user) {
|
||||
if (!this.can('lockdown')) return false;
|
||||
Rooms.global.send('|refresh|');
|
||||
Rooms.global.sendAll('|refresh|');
|
||||
const logRoom = Rooms.get('staff') || room;
|
||||
logRoom.roomlog(`${user.name} used /refreshpage`);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -507,8 +507,8 @@ export const commands: ChatCommands = {
|
|||
target = this.splitTarget(target);
|
||||
const targetUser = this.targetUser;
|
||||
if (this.targetUsername === '~') {
|
||||
this.room = Rooms.global;
|
||||
this.pmTarget = null;
|
||||
this.room = null;
|
||||
} else if (!targetUser) {
|
||||
let error = `User ${this.targetUsername} not found. Did you misspell their name?`;
|
||||
error = `|pm|${this.user.getIdentity()}| ${this.targetUsername}|/error ${error}`;
|
||||
|
|
@ -516,7 +516,7 @@ export const commands: ChatCommands = {
|
|||
return;
|
||||
} else {
|
||||
this.pmTarget = targetUser;
|
||||
this.room = null!;
|
||||
this.room = null;
|
||||
}
|
||||
|
||||
if (targetUser && !targetUser.connected) {
|
||||
|
|
@ -547,7 +547,7 @@ export const commands: ChatCommands = {
|
|||
|
||||
const targetUser = this.pmTarget!; // not room means it's a PM
|
||||
|
||||
if (!targetRoom || targetRoom === Rooms.global) {
|
||||
if (!targetRoom) {
|
||||
return this.errorReply(`The room "${target}" was not found.`);
|
||||
}
|
||||
if (!targetRoom.checkModjoin(targetUser)) {
|
||||
|
|
@ -1393,7 +1393,7 @@ export const commands: ChatCommands = {
|
|||
}
|
||||
|
||||
const targetRoom = Rooms.get(target);
|
||||
if (!targetRoom || targetRoom === Rooms.global || (
|
||||
if (!targetRoom || (
|
||||
targetRoom.settings.isPrivate && !user.inRooms.has(targetRoom.roomid) && !user.games.has(targetRoom.roomid)
|
||||
)) {
|
||||
const roominfo = {id: target, error: 'not found or access denied'};
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@ export const commands: ChatCommands = {
|
|||
alt: 'whois',
|
||||
alts: 'whois',
|
||||
whoare: 'whois',
|
||||
whois(target, room, user, connection, cmd) {
|
||||
let usedRoom: ChatRoom | GameRoom | GlobalRoom = room;
|
||||
if (usedRoom?.roomid === 'staff' && !this.runBroadcast()) return;
|
||||
if (!usedRoom) usedRoom = Rooms.global;
|
||||
whois(target, room: Room | null, user, connection, cmd) {
|
||||
if (room?.roomid === 'staff' && !this.runBroadcast()) return;
|
||||
const targetUser = this.targetUserOrSelf(target, user.group === ' ');
|
||||
const showAll = (cmd === 'ip' || cmd === 'whoare' || cmd === 'alt' || cmd === 'alts');
|
||||
if (!targetUser) {
|
||||
|
|
@ -43,8 +41,8 @@ export const commands: ChatCommands = {
|
|||
buf += ` <small style="color:gray">(trusted${targetUser.id === trusted ? `` : `: <span class="username">${trusted}</span>`})</small>`;
|
||||
}
|
||||
if (!targetUser.connected) buf += ` <em style="color:gray">(offline)</em>`;
|
||||
const roomauth = usedRoom.auth.getDirect(targetUser.id);
|
||||
if (Config.groups[roomauth]?.name) {
|
||||
const roomauth = room?.auth.getDirect(targetUser.id);
|
||||
if (roomauth && Config.groups[roomauth]?.name) {
|
||||
buf += Utils.html`<br />${Config.groups[roomauth].name} (${roomauth})`;
|
||||
}
|
||||
if (Config.groups[targetUser.group]?.name) {
|
||||
|
|
@ -85,7 +83,7 @@ export const commands: ChatCommands = {
|
|||
}
|
||||
const canViewAlts = (user === targetUser || user.can('alts', targetUser));
|
||||
const canViewPunishments = canViewAlts ||
|
||||
(usedRoom.settings.isPrivate !== true && user.can('mute', targetUser, usedRoom) && targetUser.id in usedRoom.users);
|
||||
(room && room.settings.isPrivate !== true && user.can('mute', targetUser, room) && targetUser.id in room.users);
|
||||
const canViewSecretRooms = user === targetUser || (canViewAlts && targetUser.locked) || user.can('makeroom');
|
||||
buf += `<br />`;
|
||||
|
||||
|
|
@ -2631,13 +2629,15 @@ export const commands: ChatCommands = {
|
|||
export const pages: PageTable = {
|
||||
punishments(query, user) {
|
||||
this.title = 'Punishments';
|
||||
const room = this.extractRoom();
|
||||
if (!room) return;
|
||||
|
||||
let buf = "";
|
||||
this.extractRoom();
|
||||
if (!user.named) return Rooms.RETRY_AFTER_LOGIN;
|
||||
if (!this.room.persist) return;
|
||||
if (!this.can('mute', null, this.room)) return;
|
||||
if (!room.persist) return;
|
||||
if (!this.can('mute', null, room)) return;
|
||||
// Ascending order
|
||||
const sortedPunishments = Array.from(Punishments.getPunishments(this.room.roomid))
|
||||
const sortedPunishments = Array.from(Punishments.getPunishments(room.roomid))
|
||||
.sort((a, b) => a[1].expireTime - b[1].expireTime);
|
||||
const sP = new Map();
|
||||
for (const punishment of sortedPunishments) {
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ export const commands: ChatCommands = {
|
|||
let userLookup = '';
|
||||
if (cmd === 'roomauth1') userLookup = `\n\nTo look up auth for a user, use /userauth ${target}`;
|
||||
let targetRoom = room;
|
||||
if (target) targetRoom = Rooms.search(target) as ChatRoom | GameRoom;
|
||||
if (target) targetRoom = Rooms.search(target)!;
|
||||
if (!targetRoom || targetRoom.roomid === 'global' || !targetRoom.checkModjoin(user)) {
|
||||
return this.errorReply(`The room "${target}" does not exist.`);
|
||||
}
|
||||
|
|
@ -262,7 +262,7 @@ export const commands: ChatCommands = {
|
|||
const also = buffer.length === 0 ? `` : ` also`;
|
||||
buffer.push(`${curRoom.title} is a ${roomType}subroom of ${curRoom.parent.title}, so ${curRoom.parent.title} users${inheritedUserType}${also} have authority in this room.`);
|
||||
}
|
||||
curRoom = curRoom.parent as ChatRoom | GameRoom;
|
||||
curRoom = curRoom.parent;
|
||||
}
|
||||
if (!buffer.length) {
|
||||
connection.popup(`The room '${targetRoom.title}' has no auth. ${userLookup}`);
|
||||
|
|
@ -375,7 +375,7 @@ export const commands: ChatCommands = {
|
|||
leave: 'part',
|
||||
part(target, room, user, connection) {
|
||||
const targetRoom = target ? Rooms.search(target) : room;
|
||||
if (!targetRoom || targetRoom === Rooms.global) {
|
||||
if (!targetRoom) {
|
||||
if (target.startsWith('view-')) return;
|
||||
return this.errorReply(`The room '${target}' does not exist.`);
|
||||
}
|
||||
|
|
@ -1829,7 +1829,7 @@ export const commands: ChatCommands = {
|
|||
blacklists: 'showblacklist',
|
||||
showbl: 'showblacklist',
|
||||
showblacklist(target, room, user, connection, cmd) {
|
||||
if (target) room = Rooms.search(target) as ChatRoom | GameRoom;
|
||||
if (target) room = Rooms.search(target)!;
|
||||
if (!room) return this.errorReply(`The room "${target}" was not found.`);
|
||||
if (!this.can('mute', null, room)) return false;
|
||||
const SOON_EXPIRING_TIME = 3 * 30 * 24 * 60 * 60 * 1000; // 3 months
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import {Utils} from '../../lib/utils';
|
|||
export class Announcement {
|
||||
readonly activityId: 'announcement';
|
||||
announcementNumber: number;
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
source: string;
|
||||
timeout: NodeJS.Timer | null;
|
||||
timeoutMins: number;
|
||||
constructor(room: ChatRoom | GameRoom, source: string) {
|
||||
constructor(room: Room, source: string) {
|
||||
this.activityId = 'announcement';
|
||||
this.announcementNumber = room.nextGameNumber();
|
||||
this.room = room;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ type Symbols = '♥' | '♦' | '♣' | '♠';
|
|||
type SymbolName = 'Hearts' | 'Diamonds' | 'Clubs' | 'Spades';
|
||||
|
||||
export class Blackjack extends Rooms.RoomGame {
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
|
||||
blackjack: boolean;
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export class Blackjack extends Rooms.RoomGame {
|
|||
playerTable: {[k: string]: BlackjackPlayer};
|
||||
gameNumber: number;
|
||||
|
||||
constructor(room: ChatRoom | GameRoom, user: User, autostartMinutes = 0) {
|
||||
constructor(room: Room, user: User, autostartMinutes = 0) {
|
||||
super(room);
|
||||
this.gameNumber = room.nextGameNumber();
|
||||
this.room = room;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ type FilterWord = [RegExp, string, string, string | null, number];
|
|||
type MonitorHandler = (
|
||||
this: CommandContext,
|
||||
line: FilterWord,
|
||||
room: ChatRoom | GameRoom | null,
|
||||
room: Room | null,
|
||||
user: User,
|
||||
message: string,
|
||||
lcMessage: string,
|
||||
|
|
|
|||
|
|
@ -52,18 +52,20 @@ export const destroy = () => {
|
|||
export const pages: PageTable = {
|
||||
async spotlights(query, user, connection) {
|
||||
this.title = 'Daily Spotlights';
|
||||
this.extractRoom();
|
||||
const room = this.extractRoom();
|
||||
if (!room) return;
|
||||
|
||||
let buf = `<div class="pad ladder"><h2>Daily Spotlights</h2>`;
|
||||
if (!spotlights[this.room.roomid]) {
|
||||
if (!spotlights[room.roomid]) {
|
||||
buf += `<p>This room has no daily spotlights.</p></div>`;
|
||||
} else {
|
||||
for (const key in spotlights[this.room.roomid]) {
|
||||
for (const key in spotlights[room.roomid]) {
|
||||
buf += `<table style="margin-bottom:30px;"><th colspan="2"><h3>${key}:</h3></th>`;
|
||||
for (const [i, spotlight] of spotlights[this.room.roomid][key].entries()) {
|
||||
for (const [i, spotlight] of spotlights[room.roomid][key].entries()) {
|
||||
const html = await renderSpotlight(spotlight.description, spotlight.image);
|
||||
buf += `<tr><td>${i ? i : 'Current'}</td><td>${html}</td></tr>`;
|
||||
// @ts-ignore room is definitely a proper room here.
|
||||
if (!user.can('announce', null, this.room)) break;
|
||||
if (!user.can('announce', null, room)) break;
|
||||
}
|
||||
buf += '</table>';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export class Hangman extends Rooms.RoomGame {
|
|||
lastGuesser: string;
|
||||
wordSoFar: string[];
|
||||
|
||||
constructor(room: ChatRoom | GameRoom, user: User, word: string, hint = '') {
|
||||
constructor(room: Room, user: User, word: string, hint = '') {
|
||||
super(room);
|
||||
|
||||
this.gameNumber = room.nextGameNumber();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export class Jeopardy extends Rooms.RoomGame {
|
|||
finals: boolean;
|
||||
gameNumber: number;
|
||||
|
||||
constructor(room: ChatRoom | GameRoom, user: User, categoryCount: number, questionCount: number) {
|
||||
constructor(room: Room, user: User, categoryCount: number, questionCount: number) {
|
||||
super(room);
|
||||
this.gameNumber = room.nextGameNumber();
|
||||
this.playerTable = Object.create(null);
|
||||
|
|
|
|||
|
|
@ -264,19 +264,21 @@ export const commands: ChatCommands = {
|
|||
|
||||
export const pages: PageTable = {
|
||||
lottery(query, user) {
|
||||
this.extractRoom();
|
||||
this.title = 'Lottery';
|
||||
const room = this.extractRoom();
|
||||
if (!room) return;
|
||||
|
||||
let buf = '<div class="pad">';
|
||||
const lottery = lotteries[this.room.roomid];
|
||||
const lottery = lotteries[room.roomid];
|
||||
if (!lottery) {
|
||||
buf += `<h2>There is no lottery running in ${this.room.title}</h2></div>`;
|
||||
buf += `<h2>There is no lottery running in ${room.title}</h2></div>`;
|
||||
return buf;
|
||||
}
|
||||
buf += `<h2 style="text-align: center">${lottery.name}</h2>${lottery.markup}<br />`;
|
||||
if (lottery.running) {
|
||||
const userSignedUp = lottery.participants[user.latestIp] ||
|
||||
Object.values(lottery.participants).map(toID).includes(user.id);
|
||||
buf += `<button class="button" name="send" style=" display: block; margin: 0 auto" value="/lottery ${userSignedUp ? 'leave' : 'join'} ${this.room.roomid}">${userSignedUp ? "Leave the " : "Sign up for the"} lottery</button>`;
|
||||
buf += `<button class="button" name="send" style=" display: block; margin: 0 auto" value="/lottery ${userSignedUp ? 'leave' : 'join'} ${room.roomid}">${userSignedUp ? "Leave the " : "Sign up for the"} lottery</button>`;
|
||||
} else {
|
||||
buf += '<p style="text-align: center"><b>This lottery has already ended. The winners are:</b></p>';
|
||||
buf += '<ul style="display: table; margin: 0px auto">';
|
||||
|
|
|
|||
|
|
@ -569,7 +569,7 @@ export const commands: ChatCommands = {
|
|||
pl: 'modlog',
|
||||
timedmodlog: 'modlog',
|
||||
modlog(target, room, user, connection, cmd) {
|
||||
if (!room) room = Rooms.get('global') as ChatRoom | GameRoom;
|
||||
if (!room) (room as Room | undefined) = Rooms.get('global');
|
||||
let roomid: RoomID = (room.roomid === 'staff' ? 'global' : room.roomid);
|
||||
|
||||
if (target.includes(',')) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ interface Option {
|
|||
export class Poll {
|
||||
readonly activityId: 'poll';
|
||||
pollNumber: number;
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
question: string;
|
||||
supportHTML: boolean;
|
||||
multiPoll: boolean;
|
||||
|
|
@ -26,7 +26,7 @@ export class Poll {
|
|||
timeoutMins: number;
|
||||
isQuiz: boolean;
|
||||
options: Map<number, Option>;
|
||||
constructor(room: ChatRoom | GameRoom, questionData: QuestionData, options: string[], multi: boolean) {
|
||||
constructor(room: Room, questionData: QuestionData, options: string[], multi: boolean) {
|
||||
this.activityId = 'poll';
|
||||
this.pollNumber = room.nextGameNumber();
|
||||
this.room = room;
|
||||
|
|
|
|||
|
|
@ -663,12 +663,12 @@ const MODES: {[k: string]: GameMode | string} = {
|
|||
};
|
||||
|
||||
export class ScavengerGameTemplate {
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
playerlist: null | string[];
|
||||
timer: NodeJS.Timer | null;
|
||||
|
||||
[k: string]: any;
|
||||
constructor(room: GameRoom | ChatRoom) {
|
||||
constructor(room: Room) {
|
||||
this.room = room;
|
||||
this.playerlist = null;
|
||||
this.timer = null;
|
||||
|
|
@ -694,7 +694,7 @@ export class ScavengerGameTemplate {
|
|||
}
|
||||
}
|
||||
|
||||
const LoadGame = function (room: ChatRoom | GameRoom, gameid: string) {
|
||||
const LoadGame = function (room: Room, gameid: string) {
|
||||
let game = MODES[gameid];
|
||||
if (!game) return false; // invalid id
|
||||
if (typeof game === 'string') game = MODES[game];
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ if (LeaderboardRoom) {
|
|||
LeaderboardRoom.scavLeaderboard.scavsPlayerLeaderboard = PlayerLeaderboard;
|
||||
}
|
||||
|
||||
function formatQueue(queue: QueuedHunt[] | undefined, viewer: User, room: ChatRoom | GameRoom, broadcasting?: boolean) {
|
||||
function formatQueue(queue: QueuedHunt[] | undefined, viewer: User, room: Room, broadcasting?: boolean) {
|
||||
const showStaff = viewer.can('mute', null, room) && !broadcasting;
|
||||
const queueDisabled = room.settings.scavSettings?.scavQueueDisabled;
|
||||
const timerDuration = room.settings.scavSettings?.defaultScavTimer || DEFAULT_TIMER_DURATION;
|
||||
|
|
@ -353,7 +353,7 @@ export class ScavengerHunt extends Rooms.RoomGame {
|
|||
|
||||
[k: string]: any; // for purposes of adding new temporary properties for the purpose of twists.
|
||||
constructor(
|
||||
room: ChatRoom | GameRoom,
|
||||
room: Room,
|
||||
staffHost: User | FakeUser,
|
||||
hosts: FakeUser[],
|
||||
gameType: GameTypes,
|
||||
|
|
@ -952,7 +952,7 @@ export class ScavengerHunt extends Rooms.RoomGame {
|
|||
return ips.filter((ip, index) => ips.indexOf(ip) === index).length;
|
||||
}
|
||||
|
||||
static parseHosts(hostArray: string[], room: ChatRoom | GameRoom, allowOffline?: boolean) {
|
||||
static parseHosts(hostArray: string[], room: Room, allowOffline?: boolean) {
|
||||
const hosts = [];
|
||||
for (const u of hostArray) {
|
||||
const id = toID(u);
|
||||
|
|
@ -2345,11 +2345,13 @@ const ScavengerCommands: ChatCommands = {
|
|||
export const pages: PageTable = {
|
||||
recycledHunts(query, user, connection) {
|
||||
this.title = 'Recycled Hunts';
|
||||
const room = this.extractRoom();
|
||||
if (!room) return;
|
||||
|
||||
let buf = "";
|
||||
this.extractRoom();
|
||||
if (!user.named) return Rooms.RETRY_AFTER_LOGIN;
|
||||
if (!this.room.persist) return;
|
||||
if (!this.can('mute', null, this.room)) return;
|
||||
if (!room.persist) return;
|
||||
if (!this.can('mute', null, room)) return;
|
||||
buf += `<div class="pad"><h2>List of recycled Scavenger hunts</h2>`;
|
||||
buf += `<ol style="width: 90%;">`;
|
||||
for (const hunt of scavengersData.recycledHunts) {
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ export const otdCommands: ChatCommands = {
|
|||
return handler.generateWinnerDisplay().then(text => {
|
||||
if (!text) return this.errorReply("There is no winner yet.");
|
||||
this.sendReplyBox(text);
|
||||
this.room.update();
|
||||
room.update();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ class Trivia extends Rooms.RoomGame {
|
|||
curAnswers: string[];
|
||||
askedAt: number[];
|
||||
constructor(
|
||||
room: GameRoom | ChatRoom, mode: string, category: string,
|
||||
room: Room, mode: string, category: string,
|
||||
length: string, questions: TriviaQuestion[], isRandomMode = false
|
||||
) {
|
||||
super(room);
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export class UnoGame extends Rooms.RoomGame {
|
|||
isPlusFour: boolean;
|
||||
gameNumber: number;
|
||||
|
||||
constructor(room: ChatRoom | GameRoom, cap: number, suppressMessages: boolean) {
|
||||
constructor(room: Room, cap: number, suppressMessages: boolean) {
|
||||
super(room);
|
||||
|
||||
this.playerTable = Object.create(null);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class Giveaway {
|
|||
gaNumber: number;
|
||||
host: User;
|
||||
giver: User;
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
ot: string;
|
||||
tid: string;
|
||||
prize: string;
|
||||
|
|
@ -45,7 +45,7 @@ class Giveaway {
|
|||
sprite: string;
|
||||
|
||||
constructor(
|
||||
host: User, giver: User, room: ChatRoom | GameRoom,
|
||||
host: User, giver: User, room: Room,
|
||||
ot: string, tid: string, prize: string
|
||||
) {
|
||||
this.gaNumber = room.nextGameNumber();
|
||||
|
|
@ -111,15 +111,15 @@ class Giveaway {
|
|||
return false;
|
||||
}
|
||||
|
||||
static checkBanned(room: ChatRoom | GameRoom, user: User) {
|
||||
static checkBanned(room: Room, user: User) {
|
||||
return Punishments.getRoomPunishType(room, toID(user)) === 'GIVEAWAYBAN';
|
||||
}
|
||||
|
||||
static ban(room: ChatRoom | GameRoom, user: User, reason: string) {
|
||||
static ban(room: Room, user: User, reason: string) {
|
||||
Punishments.roomPunish(room, user, ['GIVEAWAYBAN', toID(user), Date.now() + BAN_DURATION, reason]);
|
||||
}
|
||||
|
||||
static unban(room: ChatRoom | GameRoom, user: User) {
|
||||
static unban(room: Room, user: User) {
|
||||
Punishments.roomUnpunish(room, toID(user), 'GIVEAWAYBAN', false);
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ export class QuestionGiveaway extends Giveaway {
|
|||
winner: User | null;
|
||||
|
||||
constructor(
|
||||
host: User, giver: User, room: ChatRoom | GameRoom, ot: string, tid: string,
|
||||
host: User, giver: User, room: Room, ot: string, tid: string,
|
||||
prize: string, question: string, answers: string[]
|
||||
) {
|
||||
super(host, giver, room, ot, tid, prize);
|
||||
|
|
@ -359,7 +359,7 @@ export class LotteryGiveaway extends Giveaway {
|
|||
maxWinners: number;
|
||||
|
||||
constructor(
|
||||
host: User, giver: User, room: ChatRoom | GameRoom, ot: string,
|
||||
host: User, giver: User, room: Room, ot: string,
|
||||
tid: string, prize: string, winners: number
|
||||
) {
|
||||
super(host, giver, room, ot, tid, prize);
|
||||
|
|
@ -484,7 +484,7 @@ export class LotteryGiveaway extends Giveaway {
|
|||
|
||||
export class GTSGiveaway {
|
||||
gtsNumber: number;
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
giver: User;
|
||||
left: number;
|
||||
summary: string;
|
||||
|
|
@ -497,7 +497,7 @@ export class GTSGiveaway {
|
|||
timer: NodeJS.Timer | null;
|
||||
|
||||
constructor(
|
||||
room: ChatRoom | GameRoom, giver: User, amount: number,
|
||||
room: Room, giver: User, amount: number,
|
||||
summary: string, deposit: string, lookfor: string
|
||||
) {
|
||||
this.gtsNumber = room.nextGameNumber();
|
||||
|
|
|
|||
144
server/chat.ts
144
server/chat.ts
|
|
@ -35,7 +35,7 @@ export interface PageTable {
|
|||
export type ChatHandler = (
|
||||
this: CommandContext,
|
||||
target: string,
|
||||
room: ChatRoom | GameRoom,
|
||||
room: Room,
|
||||
user: User,
|
||||
connection: Connection,
|
||||
cmd: string,
|
||||
|
|
@ -66,7 +66,7 @@ export type ChatFilter = (
|
|||
this: CommandContext,
|
||||
message: string,
|
||||
user: User,
|
||||
room: ChatRoom | GameRoom | null,
|
||||
room: Room | null,
|
||||
connection: Connection,
|
||||
targetUser: User | null,
|
||||
originalMessage: string
|
||||
|
|
@ -203,7 +203,7 @@ class MessageContext {
|
|||
|
||||
export class PageContext extends MessageContext {
|
||||
readonly connection: Connection;
|
||||
room: Room;
|
||||
room: Room | null;
|
||||
pageid: string;
|
||||
initialized: boolean;
|
||||
title: string;
|
||||
|
|
@ -211,7 +211,7 @@ export class PageContext extends MessageContext {
|
|||
super(options.user, options.language);
|
||||
|
||||
this.connection = options.connection;
|
||||
this.room = Rooms.get('global')!;
|
||||
this.room = null;
|
||||
this.pageid = options.pageid;
|
||||
|
||||
this.initialized = false;
|
||||
|
|
@ -237,16 +237,16 @@ export class PageContext extends MessageContext {
|
|||
const room = Rooms.get(parts[2]);
|
||||
if (!room) {
|
||||
this.send(`<h2>Invalid room.</h2>`);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
this.room = room;
|
||||
return room.roomid;
|
||||
return room;
|
||||
}
|
||||
|
||||
send(content: string) {
|
||||
if (!content.startsWith('|deinit')) {
|
||||
const roomid = this.room !== Rooms.global ? `[${this.room.roomid}] ` : '';
|
||||
const roomid = this.room ? `[${this.room.roomid}] ` : '';
|
||||
if (!this.initialized) {
|
||||
content = `|init|html\n|title|${roomid}${this.title}\n|pagehtml|${content}`;
|
||||
this.initialized = true;
|
||||
|
|
@ -295,10 +295,18 @@ export class PageContext extends MessageContext {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a message sent in a PM or to a chat/battle room.
|
||||
*
|
||||
* There are three cases to be aware of:
|
||||
* - PM to user: `context.pmTarget` will exist and `context.room` will be `null`
|
||||
* - message to room: `context.room` will exist and `context.pmTarget` will be `null`
|
||||
* - console command (PM to `~`): `context.pmTarget` and `context.room` will both be `null`
|
||||
*/
|
||||
export class CommandContext extends MessageContext {
|
||||
message: string;
|
||||
pmTarget: User | null;
|
||||
room: Room;
|
||||
room: Room | null;
|
||||
connection: Connection;
|
||||
cmd: string;
|
||||
cmdToken: string;
|
||||
|
|
@ -312,8 +320,8 @@ export class CommandContext extends MessageContext {
|
|||
inputUsername: string;
|
||||
constructor(
|
||||
options:
|
||||
{message: string, room: Room, user: User, connection: Connection} &
|
||||
Partial<{pmTarget: User | null, cmd: string, cmdToken: string, target: string, fullCmd: string}>
|
||||
{message: string, user: User, connection: Connection} &
|
||||
Partial<{room: Room | null, pmTarget: User | null, cmd: string, cmdToken: string, target: string, fullCmd: string}>
|
||||
) {
|
||||
super(
|
||||
options.user, options.room && options.room.settings.language ?
|
||||
|
|
@ -365,7 +373,7 @@ export class CommandContext extends MessageContext {
|
|||
message = this.run(commandHandler);
|
||||
} else {
|
||||
if (commandHandler === '!') {
|
||||
if (this.room === Rooms.global) {
|
||||
if (!this.room) {
|
||||
return this.popupReply(`You tried use "${message}" as a global command, but it is not a global command.`);
|
||||
} else if (this.room) {
|
||||
return this.popupReply(`You tried to send "${message}" to the room "${this.room.roomid}" but it failed because you were not in that room.`);
|
||||
|
|
@ -394,16 +402,14 @@ export class CommandContext extends MessageContext {
|
|||
|
||||
// Output the message
|
||||
if (message && typeof message.then === 'function') {
|
||||
message.then(() => this.update());
|
||||
} else if (message && message !== true) {
|
||||
if (this.pmTarget) {
|
||||
Chat.sendPM(message, this.user, this.pmTarget);
|
||||
} else {
|
||||
this.room.add(`|c|${this.user.getIdentity(this.room.roomid)}|${message}`);
|
||||
if (this.room && this.room.game && this.room.game.onLogMessage) {
|
||||
this.room.game.onLogMessage(message, this.user);
|
||||
void (message as Promise<any>).then(resolvedMessage => {
|
||||
if (resolvedMessage && resolvedMessage !== true) {
|
||||
this.sendChatMessage(resolvedMessage);
|
||||
}
|
||||
}
|
||||
this.update();
|
||||
});
|
||||
} else if (message && message !== true) {
|
||||
this.sendChatMessage(message);
|
||||
}
|
||||
|
||||
this.update();
|
||||
|
|
@ -411,6 +417,19 @@ export class CommandContext extends MessageContext {
|
|||
return message;
|
||||
}
|
||||
|
||||
sendChatMessage(message: string) {
|
||||
if (this.pmTarget) {
|
||||
Chat.sendPM(message, this.user, this.pmTarget);
|
||||
} else if (this.room) {
|
||||
this.room.add(`|c|${this.user.getIdentity(this.room.roomid)}|${message}`);
|
||||
if (this.room.game && this.room.game.onLogMessage) {
|
||||
this.room.game.onLogMessage(message, this.user);
|
||||
}
|
||||
} else {
|
||||
this.connection.popup(`Your message could not be sent:\n\n${message}\n\nIt needs to be sent to a user or room.`);
|
||||
}
|
||||
}
|
||||
|
||||
splitCommand(message = this.message, recursing = false): '!' | undefined | ChatHandler {
|
||||
this.cmd = '';
|
||||
this.cmdToken = '';
|
||||
|
|
@ -510,11 +529,7 @@ export class CommandContext extends MessageContext {
|
|||
this.target = target;
|
||||
this.fullCmd = fullCmd;
|
||||
|
||||
const requireGlobalCommand = (
|
||||
this.pmTarget ||
|
||||
this.room === Rooms.global ||
|
||||
(this.room && !(this.user.id in this.room.users))
|
||||
);
|
||||
const requireGlobalCommand = !(this.room && this.user.id in this.room.users);
|
||||
|
||||
if (typeof commandHandler === 'function' && requireGlobalCommand) {
|
||||
const baseCmd = typeof curCommands[cmd] === 'string' ? curCommands[cmd] : cmd;
|
||||
|
|
@ -604,7 +619,7 @@ export class CommandContext extends MessageContext {
|
|||
return this.room.game.onChatMessage(this.message, this.user);
|
||||
}
|
||||
pmTransform(originalMessage: string) {
|
||||
if (!this.pmTarget && this.room !== Rooms.global) throw new Error(`Not a PM`);
|
||||
if (this.room) throw new Error(`Not a PM`);
|
||||
const targetIdentity = this.pmTarget ? this.pmTarget.getIdentity() : '~';
|
||||
const prefix = `|pm|${this.user.getIdentity()}|${targetIdentity}|`;
|
||||
return originalMessage.split('\n').map(message => {
|
||||
|
|
@ -630,7 +645,7 @@ export class CommandContext extends MessageContext {
|
|||
this.add(data);
|
||||
} else {
|
||||
// not broadcasting
|
||||
if (this.pmTarget || this.room === Rooms.global) {
|
||||
if (!this.room) {
|
||||
data = this.pmTransform(data);
|
||||
this.connection.send(data);
|
||||
} else {
|
||||
|
|
@ -651,36 +666,33 @@ export class CommandContext extends MessageContext {
|
|||
this.connection.popup(message);
|
||||
}
|
||||
add(data: string) {
|
||||
if (this.pmTarget) {
|
||||
if (!this.room) {
|
||||
data = this.pmTransform(data);
|
||||
this.user.send(data);
|
||||
if (this.pmTarget !== this.user) this.pmTarget.send(data);
|
||||
if (this.pmTarget !== this.user) this.pmTarget!.send(data);
|
||||
return;
|
||||
}
|
||||
this.room.add(data);
|
||||
}
|
||||
send(data: string) {
|
||||
if (this.pmTarget) {
|
||||
if (!this.room) {
|
||||
data = this.pmTransform(data);
|
||||
this.user.send(data);
|
||||
if (this.pmTarget !== this.user) this.pmTarget.send(data);
|
||||
if (this.pmTarget !== this.user) this.pmTarget!.send(data);
|
||||
return;
|
||||
}
|
||||
this.room.send(data);
|
||||
}
|
||||
sendModCommand(data: string) {
|
||||
this.room.sendModsByUser(this.user, data);
|
||||
this.room!.sendModsByUser(this.user, data);
|
||||
}
|
||||
|
||||
privateModCommand() {
|
||||
throw new Error(`this.privateModCommand has been renamed to this.privateModAction, which no longer writes to modlog.`);
|
||||
}
|
||||
privateModAction(msg: string) {
|
||||
this.room.sendMods(msg);
|
||||
this.room!.sendMods(msg);
|
||||
this.roomlog(msg);
|
||||
}
|
||||
globalModlog(action: string, user: string | User | null, note: string) {
|
||||
let buf = `(${this.room.roomid}) ${action}: `;
|
||||
let buf = `(${this.room ? this.room.roomid : 'global'}) ${action}: `;
|
||||
if (user) {
|
||||
if (typeof user === 'string') {
|
||||
buf += `[${user}]`;
|
||||
|
|
@ -696,7 +708,7 @@ export class CommandContext extends MessageContext {
|
|||
buf += note.replace(/\n/gm, ' ');
|
||||
|
||||
Rooms.global.modlog(buf);
|
||||
if (this.room !== Rooms.global) this.room.modlog(buf);
|
||||
if (this.room) this.room.modlog(buf);
|
||||
}
|
||||
modlog(
|
||||
action: string,
|
||||
|
|
@ -704,7 +716,7 @@ export class CommandContext extends MessageContext {
|
|||
note: string | null = null,
|
||||
options: Partial<{noalts: any, noip: any}> = {}
|
||||
) {
|
||||
let buf = `(${this.room.roomid}) ${action}: `;
|
||||
let buf = `(${this.room ? this.room.roomid : 'global'}) ${action}: `;
|
||||
if (user) {
|
||||
if (typeof user === 'string') {
|
||||
buf += `[${toID(user)}]`;
|
||||
|
|
@ -722,27 +734,20 @@ export class CommandContext extends MessageContext {
|
|||
buf += ` by ${this.user.id}`;
|
||||
if (note) buf += `: ${note.replace(/\n/gm, ' ')}`;
|
||||
|
||||
this.room.modlog(buf);
|
||||
(this.room || Rooms.global).modlog(buf);
|
||||
}
|
||||
roomlog(data: string) {
|
||||
if (this.pmTarget) return;
|
||||
this.room.roomlog(data);
|
||||
}
|
||||
logEntry() {
|
||||
throw new Error(`this.logEntry has been renamed to this.roomlog.`);
|
||||
}
|
||||
addModCommand() {
|
||||
throw new Error(`this.addModCommand has been renamed to this.addModAction, which no longer writes to modlog.`);
|
||||
if (this.room) this.room.roomlog(data);
|
||||
}
|
||||
addModAction(msg: string) {
|
||||
this.room.addByUser(this.user, msg);
|
||||
this.room!.addByUser(this.user, msg);
|
||||
}
|
||||
update() {
|
||||
if (this.room) this.room.update();
|
||||
}
|
||||
filter(message: string, targetUser: User | null = null) {
|
||||
if (!this.room || this.room.roomid === 'global') return null;
|
||||
return Chat.filter(this, message, this.user, this.room as GameRoom | ChatRoom, this.connection, targetUser);
|
||||
if (!this.room) return null;
|
||||
return Chat.filter(this, message, this.user, this.room, this.connection, targetUser);
|
||||
}
|
||||
statusfilter(status: string) {
|
||||
return Chat.statusfilter(status, this.user);
|
||||
|
|
@ -771,14 +776,14 @@ export class CommandContext extends MessageContext {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (this.room instanceof Rooms.GlobalRoom) {
|
||||
this.errorReply(`You have no one to broadcast this to.`);
|
||||
if (this.room && !this.user.can('broadcast', null, this.room)) {
|
||||
this.errorReply(`You need to be voiced to broadcast this command's information.`);
|
||||
this.errorReply(`To see it for yourself, use: /${this.message.slice(1)}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.pmTarget && !this.user.can('broadcast', null, this.room)) {
|
||||
this.errorReply(`You need to be voiced to broadcast this command's information.`);
|
||||
if (!this.room && !this.pmTarget) {
|
||||
this.errorReply(`Broadcasting a command with "!" in a PM or chatroom will show it that user or room.`);
|
||||
this.errorReply(`To see it for yourself, use: /${this.message.slice(1)}`);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -820,9 +825,9 @@ export class CommandContext extends MessageContext {
|
|||
if (this.pmTarget) {
|
||||
this.sendReply('|c~|' + (suppressMessage || this.message));
|
||||
} else {
|
||||
this.sendReply('|c|' + this.user.getIdentity(this.room.roomid) + '|' + (suppressMessage || this.message));
|
||||
this.sendReply('|c|' + this.user.getIdentity(this.room ? this.room.roomid : '') + '|' + (suppressMessage || this.message));
|
||||
}
|
||||
if (!ignoreCooldown && !this.pmTarget) {
|
||||
if (!ignoreCooldown && this.room) {
|
||||
this.room.lastBroadcast = this.broadcastMessage;
|
||||
this.room.lastBroadcastTime = Date.now();
|
||||
}
|
||||
|
|
@ -831,19 +836,15 @@ export class CommandContext extends MessageContext {
|
|||
}
|
||||
/* The sucrase transformation of optional chaining is too expensive to be used in a hot function like this. */
|
||||
/* eslint-disable @typescript-eslint/prefer-optional-chain */
|
||||
canTalk(message: string, room?: GameRoom | ChatRoom | null, targetUser?: User | null): string | null;
|
||||
canTalk(message?: null, room?: GameRoom | ChatRoom | null, targetUser?: User | null): true | null;
|
||||
canTalk(message: string | null = null, room: GameRoom | ChatRoom | null = null, targetUser: User | null = null) {
|
||||
canTalk(message: string, room?: Room | null, targetUser?: User | null): string | null;
|
||||
canTalk(message?: null, room?: Room | null, targetUser?: User | null): true | null;
|
||||
canTalk(message: string | null = null, room: Room | null = null, targetUser: User | null = null) {
|
||||
if (!targetUser && this.pmTarget) {
|
||||
targetUser = this.pmTarget;
|
||||
}
|
||||
if (targetUser) {
|
||||
room = null;
|
||||
} else if (!room) {
|
||||
if (this.room.roomid === 'global') {
|
||||
this.connection.popup(`Your message could not be sent:\n\n${message}\n\nIt needs to be sent to a user or room.`);
|
||||
return null;
|
||||
}
|
||||
// @ts-ignore excludes GlobalRoom above
|
||||
room = this.room;
|
||||
}
|
||||
|
|
@ -1136,9 +1137,9 @@ export class CommandContext extends MessageContext {
|
|||
}
|
||||
|
||||
if (tagName === 'img') {
|
||||
if (this.room.settings.isPersonal && !this.user.can('lock')) {
|
||||
if (!this.room || (this.room.settings.isPersonal && !this.user.can('lock'))) {
|
||||
this.errorReply(`This tag is not allowed: <${tagContent}>`);
|
||||
this.errorReply(`Images are not allowed in personal rooms.`);
|
||||
this.errorReply(`Images are not allowed outside of chatrooms.`);
|
||||
return null;
|
||||
}
|
||||
if (!/width ?= ?(?:[0-9]+|"[0-9]+")/i.test(tagContent) || !/height ?= ?(?:[0-9]+|"[0-9]+")/i.test(tagContent)) {
|
||||
|
|
@ -1160,12 +1161,13 @@ export class CommandContext extends MessageContext {
|
|||
}
|
||||
}
|
||||
if (tagName === 'button') {
|
||||
if ((this.room.settings.isPersonal || this.room.settings.isPrivate === true) && !this.user.can('lock')) {
|
||||
if ((!this.room || this.room.settings.isPersonal || this.room.settings.isPrivate === true) && !this.user.can('lock')) {
|
||||
const buttonName = / name ?= ?"([^"]*)"/i.exec(tagContent)?.[1];
|
||||
const buttonValue = / value ?= ?"([^"]*)"/i.exec(tagContent)?.[1];
|
||||
if (buttonName === 'send' && buttonValue?.startsWith('/msg ')) {
|
||||
const [pmTarget] = buttonValue.slice(5).split(',');
|
||||
if (this.room.auth.get(toID(pmTarget)) !== '*') {
|
||||
const auth = this.room ? this.room.auth : Users.globalAuth;
|
||||
if (auth.get(toID(pmTarget)) !== '*') {
|
||||
this.errorReply(`This button is not allowed: <${tagContent}>`);
|
||||
this.errorReply(`Your scripted button can't send PMs to ${pmTarget}, because that user is not a Room Bot.`);
|
||||
return null;
|
||||
|
|
@ -1248,7 +1250,7 @@ export const Chat = new class {
|
|||
context: CommandContext,
|
||||
message: string,
|
||||
user: User,
|
||||
room: GameRoom | ChatRoom | null,
|
||||
room: Room | null,
|
||||
connection: Connection,
|
||||
targetUser: User | null = null
|
||||
) {
|
||||
|
|
@ -1469,7 +1471,7 @@ export const Chat = new class {
|
|||
* @param user - the user that sent the message
|
||||
* @param connection - the connection the user sent the message from
|
||||
*/
|
||||
parse(message: string, room: Room, user: User, connection: Connection) {
|
||||
parse(message: string, room: Room | null | undefined, user: User, connection: Connection) {
|
||||
Chat.loadPlugins();
|
||||
const context = new CommandContext({message, room, user, connection});
|
||||
|
||||
|
|
@ -1915,7 +1917,7 @@ export type FilterWord = [RegExp, string, string, string | null, number];
|
|||
export type MonitorHandler = (
|
||||
this: CommandContext,
|
||||
line: FilterWord,
|
||||
room: ChatRoom | GameRoom | null,
|
||||
room: Room | null,
|
||||
user: User,
|
||||
message: string,
|
||||
lcMessage: string,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace Chat {
|
|||
}
|
||||
|
||||
// Rooms
|
||||
type GlobalRoom = Rooms.GlobalRoom;
|
||||
type GlobalRoomState = Rooms.GlobalRoomState;
|
||||
type ChatRoom = Rooms.ChatRoom;
|
||||
type GameRoom = Rooms.GameRoom;
|
||||
type BasicRoom = Rooms.BasicRoom;
|
||||
|
|
@ -40,7 +40,7 @@ type Roomlog = Rooms.Roomlog;
|
|||
type Room = Rooms.Room;
|
||||
type RoomID = "" | "global" | "lobby" | "staff" | "upperstaff" | "development" | "battle" | string & {__isRoomID: true};
|
||||
namespace Rooms {
|
||||
export type GlobalRoom = import('./rooms').GlobalRoom;
|
||||
export type GlobalRoomState = import('./rooms').GlobalRoomState;
|
||||
export type ChatRoom = import('./rooms').ChatRoom;
|
||||
export type GameRoom = import('./rooms').GameRoom;
|
||||
export type BasicRoom = import('./rooms').BasicRoom;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export class RoomGame {
|
|||
* The room this roomgame is in. Rooms can only have one RoomGame at a time,
|
||||
* which are available as `this.room.game === this`.
|
||||
*/
|
||||
room: ChatRoom | GameRoom;
|
||||
room: Room;
|
||||
gameid: ID;
|
||||
title: string;
|
||||
allowRenames: boolean;
|
||||
|
|
@ -100,7 +100,7 @@ export class RoomGame {
|
|||
* to be later. The /timer command is written to be resilient to this.
|
||||
*/
|
||||
timer?: {timerRequesters?: Set<ID>, start: (force?: User) => void, stop: (force?: User) => void} | NodeJS.Timer | null;
|
||||
constructor(room: ChatRoom | GameRoom) {
|
||||
constructor(room: Room) {
|
||||
this.roomid = room.roomid;
|
||||
this.room = room;
|
||||
this.gameid = 'game' as ID;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export interface RoomSettings {
|
|||
noAutoTruncate?: boolean;
|
||||
isMultichannel?: boolean;
|
||||
}
|
||||
export type Room = GlobalRoom | GameRoom | ChatRoom;
|
||||
export type Room = GameRoom | ChatRoom;
|
||||
type Poll = import('./chat-plugins/poll').Poll;
|
||||
type Announcement = import('./chat-plugins/announcements').Announcement;
|
||||
type RoomEvent = import('./chat-plugins/room-events').RoomEvent;
|
||||
|
|
@ -125,7 +125,7 @@ type Tournament = import('./tournaments/index').Tournament;
|
|||
export abstract class BasicRoom {
|
||||
roomid: RoomID;
|
||||
title: string;
|
||||
readonly type: 'chat' | 'battle' | 'global';
|
||||
readonly type: 'chat' | 'battle';
|
||||
readonly users: UserTable;
|
||||
/**
|
||||
* Scrollback log. This is the log that's sent to users when
|
||||
|
|
@ -261,11 +261,9 @@ export abstract class BasicRoom {
|
|||
* for everyone, and appears in the scrollback for new users who
|
||||
* join.
|
||||
*/
|
||||
add(message: string): this { throw new Error(`should be implemented by subclass`); }
|
||||
roomlog(message: string) { throw new Error(`should be implemented by subclass`); }
|
||||
modlog(message: string) { throw new Error(`should be implemented by subclass`); }
|
||||
logEntry() { throw new Error(`room.logEntry has been renamed room.roomlog`); }
|
||||
addLogMessage() { throw new Error(`room.addLogMessage has been renamed room.addByUser`); }
|
||||
abstract add(message: string): this;
|
||||
abstract roomlog(message: string): void;
|
||||
abstract modlog(message: string): void;
|
||||
/**
|
||||
* Inserts (sanitized) HTML into the room log.
|
||||
*/
|
||||
|
|
@ -474,9 +472,7 @@ export abstract class BasicRoom {
|
|||
destroy() {}
|
||||
}
|
||||
|
||||
export class GlobalRoom extends BasicRoom {
|
||||
readonly type: 'global';
|
||||
readonly active: false;
|
||||
export class GlobalRoomState {
|
||||
readonly settingsList: RoomSettings[];
|
||||
readonly chatRooms: ChatRoom[];
|
||||
/**
|
||||
|
|
@ -488,7 +484,6 @@ export class GlobalRoom extends BasicRoom {
|
|||
*/
|
||||
readonly staffAutojoinList: RoomID[];
|
||||
readonly ladderIpLog: WriteStream;
|
||||
readonly users: UserTable;
|
||||
readonly reportUserStatsInterval: NodeJS.Timeout;
|
||||
readonly modlogStream: WriteStream;
|
||||
lockdown: boolean | 'pre' | 'ddos';
|
||||
|
|
@ -496,21 +491,11 @@ export class GlobalRoom extends BasicRoom {
|
|||
lastReportedCrash: number;
|
||||
lastBattle: number;
|
||||
lastWrittenBattle: number;
|
||||
userCount: number;
|
||||
maxUsers: number;
|
||||
maxUsersDate: number;
|
||||
formatList: string;
|
||||
|
||||
readonly game: null;
|
||||
readonly battle: null;
|
||||
readonly tour: null;
|
||||
|
||||
constructor(roomid: RoomID) {
|
||||
if (roomid !== 'global') throw new Error(`The global room's room ID must be 'global'`);
|
||||
super(roomid);
|
||||
|
||||
this.type = 'global';
|
||||
this.active = false;
|
||||
constructor() {
|
||||
this.settingsList = [];
|
||||
try {
|
||||
this.settingsList = require('../config/chatrooms.json');
|
||||
|
|
@ -580,8 +565,6 @@ export class GlobalRoom extends BasicRoom {
|
|||
);
|
||||
|
||||
// init users
|
||||
this.users = Object.create(null);
|
||||
this.userCount = 0; // cache of `size(this.users)`
|
||||
this.maxUsers = 0;
|
||||
this.maxUsersDate = 0;
|
||||
this.lockdown = false;
|
||||
|
|
@ -637,7 +620,7 @@ export class GlobalRoom extends BasicRoom {
|
|||
}
|
||||
void LoginServer.request('updateuserstats', {
|
||||
date: Date.now(),
|
||||
users: this.userCount,
|
||||
users: Users.onlineCount,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -753,7 +736,7 @@ export class GlobalRoom extends BasicRoom {
|
|||
official: [],
|
||||
pspl: [],
|
||||
chat: [],
|
||||
userCount: this.userCount,
|
||||
userCount: Users.onlineCount,
|
||||
battleCount: this.battleCount,
|
||||
};
|
||||
for (const room of this.chatRooms) {
|
||||
|
|
@ -779,18 +762,8 @@ export class GlobalRoom extends BasicRoom {
|
|||
}
|
||||
return roomsData;
|
||||
}
|
||||
checkModjoin(user: User) {
|
||||
return true;
|
||||
}
|
||||
isMuted(user: User) {
|
||||
return undefined;
|
||||
}
|
||||
send(message: string) {
|
||||
Sockets.roomBroadcast(this.roomid, message);
|
||||
}
|
||||
add(message: string) {
|
||||
// TODO: make sure this never happens
|
||||
return this;
|
||||
sendAll(message: string) {
|
||||
Sockets.roomBroadcast('', message);
|
||||
}
|
||||
addChatRoom(title: string) {
|
||||
const id = toID(title) as RoomID;
|
||||
|
|
@ -896,7 +869,7 @@ export class GlobalRoom extends BasicRoom {
|
|||
checkAutojoin(user: User, connection?: Connection) {
|
||||
if (!user.named) return;
|
||||
for (let [i, staffAutojoin] of this.staffAutojoinList.entries()) {
|
||||
const room = Rooms.get(staffAutojoin) as ChatRoom | GameRoom;
|
||||
const room = Rooms.get(staffAutojoin);
|
||||
if (!room) {
|
||||
this.staffAutojoinList.splice(i, 1);
|
||||
i--;
|
||||
|
|
@ -921,34 +894,12 @@ export class GlobalRoom extends BasicRoom {
|
|||
}
|
||||
}
|
||||
}
|
||||
onConnect(user: User, connection: Connection) {
|
||||
handleConnect(user: User, connection: Connection) {
|
||||
connection.send(user.getUpdateuserText() + '\n' + this.configRankList + this.formatListText);
|
||||
}
|
||||
onJoin(user: User, connection: Connection) {
|
||||
if (!user) return false; // ???
|
||||
if (this.users[user.id]) return user;
|
||||
|
||||
this.users[user.id] = user;
|
||||
if (++this.userCount > this.maxUsers) {
|
||||
this.maxUsers = this.userCount;
|
||||
if (Users.users.size > this.maxUsers) {
|
||||
this.maxUsers = Users.users.size;
|
||||
this.maxUsersDate = Date.now();
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
onRename(user: User, oldid: ID, joining: boolean) {
|
||||
delete this.users[oldid];
|
||||
this.users[user.id] = user;
|
||||
return user;
|
||||
}
|
||||
onLeave(user: User) {
|
||||
if (!user) return; // ...
|
||||
if (!(user.id in this.users)) {
|
||||
Monitor.crashlog(new Error(`user ${user.id} already left`));
|
||||
return;
|
||||
}
|
||||
delete this.users[user.id];
|
||||
this.userCount--;
|
||||
}
|
||||
startLockdown(err: Error | null = null, slow = false) {
|
||||
if (this.lockdown && err) return;
|
||||
|
|
@ -1681,8 +1632,8 @@ export class GameRoom extends BasicChatRoom {
|
|||
}
|
||||
|
||||
function getRoom(roomid?: string | Room) {
|
||||
if (roomid && (roomid as Room).roomid) return roomid as Room;
|
||||
return Rooms.rooms.get(roomid as RoomID);
|
||||
if (typeof roomid === 'string') return Rooms.rooms.get(roomid as RoomID);
|
||||
return roomid as Room;
|
||||
}
|
||||
|
||||
export const Rooms = {
|
||||
|
|
@ -1813,11 +1764,11 @@ export const Rooms = {
|
|||
battleModlogStream: FS('logs/modlog/modlog_battle.txt').createAppendStream(),
|
||||
groupchatModlogStream: FS('logs/modlog/modlog_groupchat.txt').createAppendStream(),
|
||||
|
||||
global: null! as GlobalRoom,
|
||||
global: null! as GlobalRoomState,
|
||||
lobby: null as ChatRoom | null,
|
||||
|
||||
BasicRoom,
|
||||
GlobalRoom,
|
||||
GlobalRoomState,
|
||||
GameRoom,
|
||||
ChatRoom: BasicChatRoom,
|
||||
|
||||
|
|
@ -1836,8 +1787,4 @@ export const Rooms = {
|
|||
|
||||
// initialize
|
||||
|
||||
Monitor.notice("NEW GLOBAL: global");
|
||||
|
||||
Rooms.global = new GlobalRoom('global');
|
||||
|
||||
Rooms.rooms.set('global', Rooms.global);
|
||||
Rooms.global = new GlobalRoomState();
|
||||
|
|
|
|||
|
|
@ -458,9 +458,11 @@ export class ServerStream extends Streams.ObjectReadWriteStream<string> {
|
|||
case '#':
|
||||
// #roomid, message
|
||||
// message to all connections in room
|
||||
// #, message
|
||||
// message to all connections
|
||||
nlLoc = data.indexOf('\n');
|
||||
roomid = data.substr(1, nlLoc - 1) as RoomID;
|
||||
room = this.rooms.get(roomid);
|
||||
room = roomid ? this.rooms.get(roomid) : this.sockets;
|
||||
if (!room) return;
|
||||
message = data.substr(nlLoc + 1);
|
||||
for (const curSocket of room.values()) curSocket.write(message);
|
||||
|
|
|
|||
|
|
@ -1121,7 +1121,7 @@ function createTournamentGenerator(
|
|||
return new TourGenerator(modifier || '');
|
||||
}
|
||||
function createTournament(
|
||||
room: ChatRoom | GameRoom, formatId: string | undefined, generator: string | undefined, playerCap: string | undefined,
|
||||
room: Room, formatId: string | undefined, generator: string | undefined, playerCap: string | undefined,
|
||||
isRated: boolean, generatorMod: string | undefined, name: string | undefined, output: CommandContext
|
||||
) {
|
||||
if (room.type !== 'chat') {
|
||||
|
|
@ -1241,10 +1241,10 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
if (Config.tourdefaultplayercap && tournament.playerCap > Config.tourdefaultplayercap) {
|
||||
Monitor.log(`[TourMonitor] Room ${tournament.room.roomid} starting a tour over default cap (${tournament.playerCap})`);
|
||||
}
|
||||
this.room.send(`|tournament|update|{"playerCap": "${playerCap}"}`);
|
||||
this.room!.send(`|tournament|update|{"playerCap": "${playerCap}"}`);
|
||||
} else if (tournament.playerCap && !playerCap) {
|
||||
tournament.playerCap = 0;
|
||||
this.room.send(`|tournament|update|{"playerCap": "${playerCap}"}`);
|
||||
this.room!.send(`|tournament|update|{"playerCap": "${playerCap}"}`);
|
||||
}
|
||||
const capNote = (tournament.playerCap ? ' with a player cap of ' + tournament.playerCap : '');
|
||||
this.privateModAction(`(${user.name} set tournament type to ${generator.name + capNote}.)`);
|
||||
|
|
@ -1292,7 +1292,7 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
this.modlog('TOUR PLAYERCAP', null, tournament.playerCap.toString());
|
||||
this.sendReply(`Tournament cap set to ${tournament.playerCap}.`);
|
||||
}
|
||||
this.room.send(`|tournament|update|{"playerCap": "${tournament.playerCap}"}`);
|
||||
this.room!.send(`|tournament|update|{"playerCap": "${tournament.playerCap}"}`);
|
||||
},
|
||||
end: 'delete',
|
||||
stop: 'delete',
|
||||
|
|
@ -1317,7 +1317,9 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
return this.errorReply("The custom rules cannot be changed once the tournament has started.");
|
||||
}
|
||||
if (tournament.setCustomRules(params, this)) {
|
||||
this.room.addRaw(`<div class='infobox infobox-limited'>This tournament includes:<br />${tournament.getCustomRules()}</div>`);
|
||||
this.room!.addRaw(
|
||||
`<div class='infobox infobox-limited'>This tournament includes:<br />${tournament.getCustomRules()}</div>`
|
||||
);
|
||||
this.privateModAction(`(${user.name} updated the tournament's custom rules.)`);
|
||||
this.modlog('TOUR RULES', null, tournament.customRules.join(', '));
|
||||
}
|
||||
|
|
@ -1336,10 +1338,10 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
tournament.fullFormat = tournament.baseFormat;
|
||||
if (tournament.name === tournament.getDefaultCustomName()) {
|
||||
tournament.name = tournament.baseFormat;
|
||||
this.room.send(`|tournament|update|${JSON.stringify({format: tournament.name})}`);
|
||||
this.room!.send(`|tournament|update|${JSON.stringify({format: tournament.name})}`);
|
||||
tournament.update();
|
||||
}
|
||||
this.room.addRaw(`<b>The tournament's custom rules were cleared.</b>`);
|
||||
this.room!.addRaw(`<b>The tournament's custom rules were cleared.</b>`);
|
||||
this.privateModAction(`(${user.name} cleared the tournament's custom rules.)`);
|
||||
this.modlog('TOUR CLEARRULES');
|
||||
},
|
||||
|
|
@ -1357,7 +1359,7 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
}
|
||||
if (name.includes('|')) return this.errorReply("The tournament's name cannot include the | symbol.");
|
||||
tournament.name = name;
|
||||
this.room.send(`|tournament|update|${JSON.stringify({format: tournament.name})}`);
|
||||
this.room!.send(`|tournament|update|${JSON.stringify({format: tournament.name})}`);
|
||||
this.privateModAction(`(${user.name} set the tournament's name to ${tournament.name}.)`);
|
||||
this.modlog('TOUR NAME', null, tournament.name);
|
||||
tournament.update();
|
||||
|
|
@ -1366,7 +1368,7 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
clearname(tournament, user) {
|
||||
if (tournament.name === tournament.baseFormat) return this.errorReply("The tournament does not have a name.");
|
||||
tournament.name = tournament.baseFormat;
|
||||
this.room.send(`|tournament|update|${JSON.stringify({format: tournament.name})}`);
|
||||
this.room!.send(`|tournament|update|${JSON.stringify({format: tournament.name})}`);
|
||||
this.privateModAction(`(${user.name} cleared the tournament's name.)`);
|
||||
this.modlog('TOUR CLEARNAME');
|
||||
tournament.update();
|
||||
|
|
@ -1376,7 +1378,7 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
begin: 'start',
|
||||
start(tournament, user) {
|
||||
if (tournament.startTournament(this)) {
|
||||
this.room.sendMods(`(${user.name} started the tournament.)`);
|
||||
this.room!.sendMods(`(${user.name} started the tournament.)`);
|
||||
}
|
||||
},
|
||||
dq: 'disqualify',
|
||||
|
|
@ -1423,7 +1425,7 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
return this.errorReply("The tournament is already set to autostart when the player cap is reached.");
|
||||
}
|
||||
tournament.autostartcap = true;
|
||||
this.room.add(`The tournament will start once ${tournament.playerCap} players have joined.`);
|
||||
this.room!.add(`The tournament will start once ${tournament.playerCap} players have joined.`);
|
||||
this.privateModAction(`(The tournament was set to autostart when the player cap is reached by ${user.name})`);
|
||||
this.modlog('TOUR AUTOSTART', null, 'when playercap is reached');
|
||||
}
|
||||
|
|
@ -1485,14 +1487,14 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
if (tournament.scouting) return this.errorReply("Scouting for this tournament is already set to allowed.");
|
||||
tournament.scouting = true;
|
||||
tournament.modjoin = false;
|
||||
this.room.add('|tournament|scouting|allow');
|
||||
this.room!.add('|tournament|scouting|allow');
|
||||
this.privateModAction(`(The tournament was set to allow scouting by ${user.name})`);
|
||||
this.modlog('TOUR SCOUT', null, 'allow');
|
||||
} else if (this.meansNo(option) || option === 'disallow' || option === 'disallowed') {
|
||||
if (!tournament.scouting) return this.errorReply("Scouting for this tournament is already disabled.");
|
||||
tournament.scouting = false;
|
||||
tournament.modjoin = true;
|
||||
this.room.add('|tournament|scouting|disallow');
|
||||
this.room!.add('|tournament|scouting|disallow');
|
||||
this.privateModAction(`(The tournament was set to disallow scouting by ${user.name})`);
|
||||
this.modlog('TOUR SCOUT', null, 'disallow');
|
||||
} else {
|
||||
|
|
@ -1513,13 +1515,13 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
if (this.meansYes(option) || option === 'allow' || option === 'allowed') {
|
||||
if (tournament.modjoin) return this.errorReply("Modjoining is already allowed for this tournament.");
|
||||
tournament.modjoin = true;
|
||||
this.room.add("Modjoining is now allowed (Players can modjoin their tournament battles).");
|
||||
this.room!.add("Modjoining is now allowed (Players can modjoin their tournament battles).");
|
||||
this.privateModAction(`(The tournament was set to allow modjoin by ${user.name})`);
|
||||
this.modlog('TOUR MODJOIN', null, option);
|
||||
} else if (this.meansNo(option) || option === 'disallow' || option === 'disallowed') {
|
||||
if (!tournament.modjoin) return this.errorReply("Modjoining is already not allowed for this tournament.");
|
||||
tournament.modjoin = false;
|
||||
this.room.add("Modjoining is now banned (Players cannot modjoin their tournament battles).");
|
||||
this.room!.add("Modjoining is now banned (Players cannot modjoin their tournament battles).");
|
||||
this.privateModAction(`(The tournament was set to disallow modjoin by ${user.name})`);
|
||||
this.modlog('TOUR MODJOIN', null, option);
|
||||
} else {
|
||||
|
|
@ -1530,12 +1532,12 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
const option = params[0] || 'on';
|
||||
if (this.meansYes(option)) {
|
||||
tournament.forcePublic = true;
|
||||
this.room.add('Tournament battles forced public: ON');
|
||||
this.room!.add('Tournament battles forced public: ON');
|
||||
this.privateModAction(`(Tournament public battles were turned ON by ${user.name})`);
|
||||
this.modlog('TOUR FORCEPUBLIC', null, 'ON');
|
||||
} else if (this.meansNo(option) || option === 'stop') {
|
||||
tournament.forcePublic = false;
|
||||
this.room.add('Tournament battles forced public: OFF');
|
||||
this.room!.add('Tournament battles forced public: OFF');
|
||||
this.privateModAction(`(Tournament public battles were turned OFF by ${user.name})`);
|
||||
this.modlog('TOUR FORCEPUBLIC', null, 'OFF');
|
||||
} else {
|
||||
|
|
@ -1546,12 +1548,12 @@ const tourCommands: {basic: TourCommands, creation: TourCommands, moderation: To
|
|||
const option = params.length ? params[0].toLowerCase() : 'on';
|
||||
if (this.meansYes(option)) {
|
||||
tournament.forceTimer = true;
|
||||
this.room.add('Forcetimer is now on for the tournament.');
|
||||
this.room!.add('Forcetimer is now on for the tournament.');
|
||||
this.privateModAction(`(The timer was turned on for the tournament by ${user.name})`);
|
||||
this.modlog('TOUR FORCETIMER', null, 'ON');
|
||||
} else if (this.meansNo(option) || option === 'stop') {
|
||||
tournament.forceTimer = false;
|
||||
this.room.add('Forcetimer is now off for the tournament.');
|
||||
this.room!.add('Forcetimer is now off for the tournament.');
|
||||
this.privateModAction(`(The timer was turned off for the tournament by ${user.name})`);
|
||||
this.modlog('TOUR FORCETIMER', null, 'OFF');
|
||||
} else {
|
||||
|
|
@ -1714,9 +1716,9 @@ export const commands: ChatCommands = {
|
|||
const punishment: [string, ID, number, string] =
|
||||
['TOURBAN', targetUserid, Date.now() + TOURBAN_DURATION, reason];
|
||||
if (targetUser) {
|
||||
Punishments.roomPunish(this.room, targetUser, punishment);
|
||||
Punishments.roomPunish(this.room!, targetUser, punishment);
|
||||
} else {
|
||||
Punishments.roomPunishName(this.room, targetUserid, punishment);
|
||||
Punishments.roomPunishName(this.room!, targetUserid, punishment);
|
||||
}
|
||||
room.getGame(Tournament)?.removeBannedUser(targetUserid);
|
||||
|
||||
|
|
@ -1734,7 +1736,7 @@ export const commands: ChatCommands = {
|
|||
|
||||
if (!Tournament.checkBanned(room, targetUserid)) return this.errorReply("This user isn't banned from tournaments.");
|
||||
|
||||
if (targetUser) { Punishments.roomUnpunish(this.room, targetUserid, 'TOURBAN', false); }
|
||||
if (targetUser) { Punishments.roomUnpunish(this.room!, targetUserid, 'TOURBAN', false); }
|
||||
this.privateModAction(`${targetUser ? targetUser.name : targetUserid} was unbanned from joining tournaments by ${user.name}.`);
|
||||
this.modlog('TOUR UNBAN', targetUser, null, {noip: 1, noalts: 1});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -391,6 +391,7 @@ export class User extends Chat.MessageContext {
|
|||
this.avatar = DEFAULT_TRAINER_SPRITES[Math.floor(Math.random() * DEFAULT_TRAINER_SPRITES.length)];
|
||||
|
||||
this.connected = true;
|
||||
Users.onlineCount++;
|
||||
|
||||
if (connection.user) connection.user = this;
|
||||
this.connections = [connection];
|
||||
|
|
@ -457,7 +458,7 @@ export class User extends Chat.MessageContext {
|
|||
|
||||
sendTo(roomid: RoomID | BasicRoom | null, data: string) {
|
||||
if (roomid && typeof roomid !== 'string') roomid = (roomid as BasicRoom).roomid;
|
||||
if (roomid && roomid !== 'global' && roomid !== 'lobby') data = `>${roomid}\n${data}`;
|
||||
if (roomid && roomid !== 'lobby') data = `>${roomid}\n${data}`;
|
||||
for (const connection of this.connections) {
|
||||
if (roomid && !connection.inRooms.has(roomid)) continue;
|
||||
connection.send(data);
|
||||
|
|
@ -479,7 +480,7 @@ export class User extends Chat.MessageContext {
|
|||
const lockedSymbol = (punishgroups.locked && punishgroups.locked.symbol || '\u203d');
|
||||
return lockedSymbol + this.name;
|
||||
}
|
||||
if (roomid && roomid !== 'global') {
|
||||
if (roomid) {
|
||||
const room = Rooms.get(roomid);
|
||||
if (!room) {
|
||||
throw new Error(`Room doesn't exist: ${roomid}`);
|
||||
|
|
@ -946,7 +947,10 @@ export class User extends Chat.MessageContext {
|
|||
mergeConnection(connection: Connection) {
|
||||
// the connection has changed name to this user's username, and so is
|
||||
// being merged into this account
|
||||
this.connected = true;
|
||||
if (!this.connected) {
|
||||
this.connected = true;
|
||||
Users.onlineCount++;
|
||||
}
|
||||
if (connection.connectedAt > this.lastConnected) {
|
||||
this.lastConnected = connection.connectedAt;
|
||||
}
|
||||
|
|
@ -1079,7 +1083,9 @@ export class User extends Chat.MessageContext {
|
|||
return removed;
|
||||
}
|
||||
markDisconnected() {
|
||||
if (!this.connected) return;
|
||||
this.connected = false;
|
||||
Users.onlineCount--;
|
||||
this.lastDisconnected = Date.now();
|
||||
if (!this.registered) {
|
||||
// for "safety"
|
||||
|
|
@ -1217,12 +1223,7 @@ export class User extends Chat.MessageContext {
|
|||
if (!room) throw new Error(`Room not found: ${roomid}`);
|
||||
if (!connection) {
|
||||
for (const curConnection of this.connections) {
|
||||
// only join full clients, not pop-out single-room
|
||||
// clients
|
||||
// (...no, pop-out rooms haven't been implemented yet)
|
||||
if (curConnection.inRooms.has('global')) {
|
||||
this.joinRoom(room, curConnection);
|
||||
}
|
||||
this.joinRoom(room, curConnection);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1295,7 +1296,7 @@ export class User extends Chat.MessageContext {
|
|||
* The user says message in room.
|
||||
* Returns false if the rest of the user's messages should be discarded.
|
||||
*/
|
||||
chat(message: string, room: Room, connection: Connection) {
|
||||
chat(message: string, room: Room | null, connection: Connection) {
|
||||
const now = Date.now();
|
||||
|
||||
if (message.startsWith('/cmd userdetails') || message.startsWith('>> ') || this.isSysop) {
|
||||
|
|
@ -1318,10 +1319,10 @@ export class User extends Chat.MessageContext {
|
|||
);
|
||||
return false;
|
||||
} else {
|
||||
this.chatQueue.push([message, room.roomid, connection]);
|
||||
this.chatQueue.push([message, room ? room.roomid : '', connection]);
|
||||
}
|
||||
} else if (now < this.lastChatMessage + throttleDelay) {
|
||||
this.chatQueue = [[message, room.roomid, connection]];
|
||||
this.chatQueue = [[message, room ? room.roomid : '', connection]];
|
||||
this.startChatQueue(throttleDelay - (now - this.lastChatMessage));
|
||||
} else {
|
||||
this.lastChatMessage = now;
|
||||
|
|
@ -1366,12 +1367,12 @@ export class User extends Chat.MessageContext {
|
|||
this.lastChatMessage = new Date().getTime();
|
||||
|
||||
const room = Rooms.get(roomid);
|
||||
if (room) {
|
||||
if (room || !roomid) {
|
||||
Monitor.activeIp = connection.ip;
|
||||
Chat.parse(message, room, this, connection);
|
||||
Monitor.activeIp = null;
|
||||
} else {
|
||||
// room is expired, do nothing
|
||||
// room no longer exists; do nothing
|
||||
}
|
||||
|
||||
const throttleDelay = this.trusted ? THROTTLE_DELAY_TRUSTED : THROTTLE_DELAY;
|
||||
|
|
@ -1516,7 +1517,7 @@ function socketConnect(
|
|||
}
|
||||
});
|
||||
|
||||
user.joinRoom('global', connection);
|
||||
Rooms.global.handleConnect(user, connection);
|
||||
}
|
||||
function socketDisconnect(worker: StreamWorker, workerid: number, socketid: string) {
|
||||
const id = '' + workerid + '-' + socketid;
|
||||
|
|
@ -1558,11 +1559,10 @@ function socketReceive(worker: StreamWorker, workerid: number, socketid: string,
|
|||
if (!user) return;
|
||||
|
||||
// The client obviates the room id when sending messages to Lobby by default
|
||||
const roomId = message.substr(0, pipeIndex) || (Rooms.lobby || Rooms.global).roomid;
|
||||
const roomId = message.slice(0, pipeIndex) || (Rooms.lobby && 'lobby') || '';
|
||||
message = message.slice(pipeIndex + 1);
|
||||
|
||||
const room = Rooms.get(roomId);
|
||||
if (!room) return;
|
||||
const room = Rooms.get(roomId) || null;
|
||||
const multilineMessage = Chat.multiLinePattern.test(message);
|
||||
if (multilineMessage) {
|
||||
user.chat(multilineMessage, room, connection);
|
||||
|
|
@ -1571,7 +1571,8 @@ function socketReceive(worker: StreamWorker, workerid: number, socketid: string,
|
|||
|
||||
const lines = message.split('\n');
|
||||
if (!lines[lines.length - 1]) lines.pop();
|
||||
const maxLineCount = (user.isStaff || room.auth.isStaff(user.id)) ?
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
const maxLineCount = (user.isStaff || (room && room.auth.isStaff(user.id))) ?
|
||||
THROTTLE_MULTILINE_WARN_STAFF : THROTTLE_MULTILINE_WARN;
|
||||
if (lines.length > maxLineCount) {
|
||||
connection.popup(`You're sending too many lines at once. Try using a paste service like [[Pastebin]].`);
|
||||
|
|
@ -1603,6 +1604,7 @@ export const Users = {
|
|||
merge,
|
||||
users,
|
||||
prevUsers,
|
||||
onlineCount: 0,
|
||||
get: getUser,
|
||||
getExact: getExactUser,
|
||||
findUsers,
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ let NumberModeTrivia;
|
|||
function makeUser(name, connection) {
|
||||
const user = new User(connection);
|
||||
user.forceRename(name, true);
|
||||
user.connected = true;
|
||||
Users.users.set(user.id, user);
|
||||
user.joinRoom('global', connection);
|
||||
user.joinRoom('trivia', connection);
|
||||
return user;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ function createUser(connection) {
|
|||
if (!connection) connection = createConnection();
|
||||
|
||||
const user = new Users.User(connection);
|
||||
user.joinRoom('global', connection);
|
||||
connection.user = user;
|
||||
|
||||
return user;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user