rework aniv timeouts, fix ghost whisper message, invuln status tweaks

This commit is contained in:
2025-09-15 01:46:39 +02:00
parent 2fb0670765
commit f8fb2c0317
9 changed files with 59 additions and 18 deletions

View File

@@ -4,6 +4,8 @@ import { getUserRecord, updateUserRecord } from "db/dbUser";
import items from "items";
import { buildTimeString } from "lib/dateManager";
import { timeout } from "lib/timeout";
import { isInvuln, removeInvuln } from "lib/invuln";
import { streamerUsers } from "main";
const COOLDOWN = 10 * 60 * 1000; // 10 mins (ms)
@@ -13,6 +15,7 @@ export default new Command({
usertype: 'chatter',
execution: async (msg, user) => {
if (!await redis.exists('streamIsLive')) { await sendMessage(`No loot while stream is offline`, msg.messageId); return; };
if (await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because used a lootbox.`, msg.messageId); await removeInvuln(msg.chatterId); };
if (await user.itemLock()) { await sendMessage(`Cannot get loot (itemlock)`, msg.messageId); return; };
const userData = await getUserRecord(user);
const lastlootbox = Date.parse(userData.lastlootbox);

View File

@@ -1,6 +1,8 @@
import { redis } from "bun";
import { Command, sendMessage } from "commands";
import items from "items";
import { isInvuln, removeInvuln } from "lib/invuln";
import { streamerUsers } from "main";
export default new Command({
name: 'use',
@@ -13,6 +15,7 @@ export default new Command({
const selection = items.get(messagequery[0].toLowerCase());
if (!selection) { await sendMessage(`'${messagequery[0]}' is not an item`, msg.messageId); return; };
if (await redis.sismember('disabledcommands', selection.name)) { await sendMessage(`The ${selection.prettyName} item is disabled`, msg.messageId); return; };
if (await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because you used an item.`, msg.messageId); await removeInvuln(msg.chatterId); };
await selection.execute(msg, user);
}
});

View File

@@ -7,10 +7,11 @@ import { isAdmin } from "lib/admins";
import cheers from "cheers";
import logger from "lib/logger";
import { addMessageToChatWidget } from "web/chatWidget/message";
import { isInvuln, setTemporaryInvuln } from "lib/invuln";
import { isInvuln, removeInvuln, setTemporaryInvuln } from "lib/invuln";
import { getUserRecord } from "db/dbUser";
import { createCheerRecord } from "db/dbCheers";
import handleAnivMessage from "lib/handleAnivMessage";
import { Item } from "items";
eventSub.onChannelChatMessage(streamerId, streamerId, parseChatMessage);
@@ -50,8 +51,9 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use
// Parse commands:
const selected = selectCommand(msg.messageText);
if (!selected) return;
const { cmd: selection, activation } = selected;
const { cmd: selection, activation, isitem } = selected;
if (await redis.sismember('disabledcommands', selection.name)) return;
if (isitem && await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because you used an item.`, msg.messageId); await removeInvuln(msg.chatterId); };
switch (selection.usertype) {
case "admin":
@@ -80,15 +82,16 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use
type selectedCommand = {
cmd: Command;
activation: string;
isitem: boolean;
};
function selectCommand(message: string): selectedCommand | false {
const specialcmdselector = message.trim().toLowerCase().split(' ')[0]!;
const specialcmd = specialAliasCommands.get(specialcmdselector);
if (specialcmd) return { cmd: specialcmd, activation: specialcmdselector };
if (specialcmd) return { cmd: specialcmd, activation: specialcmdselector, isitem: specialcmd instanceof Item };
const commandSelector = message.slice(commandPrefix.length).trim().toLowerCase().split(' ')[0]!;
const normalcmd = commands.get(commandSelector);
if (normalcmd) return { cmd: normalcmd, activation: commandPrefix + commandSelector };
if (normalcmd) return { cmd: normalcmd, activation: commandPrefix + commandSelector, isitem: normalcmd instanceof Item };
return false;
};

View File

@@ -9,10 +9,11 @@ chatterEventSub.onUserWhisperMessage(chatterId, async msg => {
if (await redis.ttl(`user:${msg.senderUserId}:timeout`) < 0) return;
const cooldown = await redis.expiretime(`user:${msg.senderUserId}:whispercooldown`);
if (cooldown < 0) {
if (msg.messageText.length > 200) { await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Message too long. Please send a shorter one.`); return; };
await redis.set(`user:${msg.senderUserId}:whispercooldown`, '1');
await redis.expire(`user:${msg.senderUserId}:whispercooldown`, WHISPERCOOLDOWN);
await sendMessage(`The ghost of ${msg.senderUserDisplayName} whispered: ${msg.messageText}`);
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, "Message sent. You can send another ghost whisper in 10 minutes.");
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Message sent. You can send another ghost whisper in ${Math.floor(WHISPERCOOLDOWN / 60)} minutes.`);
} else {
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Wait another ${buildTimeString(cooldown * 1000, Date.now())} before sending another ghost whisper.`);
};

View File

@@ -30,7 +30,6 @@ export default new Item({
await user.setLock();
await Promise.all([
timeout(target!, `You got hit by ${user.displayName}'s grenade!`, 60),
redis.del(selection),
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s grenade wybuh`),
changeItemCount(user, userObj, ITEMNAME),
createTimeoutRecord(user, target!, ITEMNAME),

View File

@@ -31,7 +31,6 @@ export default new Item({
await getUserRecord(target!); // make sure the user record exist in the database
await Promise.all([
timeout(target!, `You got hit by ${user.displayName}'s TNT!`, 60),
redis.del(`user:${targetid}:vulnerable`),
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
createTimeoutRecord(user, target!, ITEMNAME),
]);

View File

@@ -5,15 +5,45 @@ import { timeout } from "lib/timeout";
import { sendMessage } from "commands";
import { createAnivTimeoutRecord } from "db/dbAnivTimeouts";
const ANIVNAMES = ['a_n_e_e_v', 'a_n_i_v', 'a_c_a_c'];
const ANIVNAMES = ['a_n_e_e_v', 'a_n_i_v'];
type anivMessageStore = {
[key: string]: string;
};
type IsAnivMessage = {
isAnivMessage: true;
message: string;
anivbot: string;
};
type isNotAnivMessage = {
isAnivMessage: false;
};
type anivMessageResult = IsAnivMessage | isNotAnivMessage;
async function isAnivMessage(message: string): Promise<anivMessageResult> {
const data: anivMessageStore = await redis.get('anivmessages').then(a => a === null ? {} : JSON.parse(a));
for (const clanker of ANIVNAMES) {
const anivmessage = data[clanker];
if (!anivmessage) continue;
if (anivmessage === message) return { isAnivMessage: true, message, anivbot: clanker };
};
return { isAnivMessage: false };
};
export default async function handleMessage(msg: EventSubChannelChatMessageEvent, user: User) {
if (ANIVNAMES.includes(user.displayName)) {
await redis.set('lastanivmessage', msg.messageText);
await redis.expire('lastanivmessage', 120); // store for 2 minutes
} else if (msg.messageText === await redis.get('lastanivmessage')) await Promise.all([
timeout(user, 'copied an aniv message', 30),
sendMessage(`${user.displayName} got timed out for copying an a_n_e_e_v message`),
createAnivTimeoutRecord(msg.messageText, user, 30)
]);
const data: anivMessageStore = await redis.get('anivmessages').then(a => a === null ? {} : JSON.parse(a));
data[user.displayName] = msg.messageText;
await redis.set('anivmessages', JSON.stringify(data));
} else {
const data = await isAnivMessage(msg.messageText);
if (data.isAnivMessage) await Promise.all([
timeout(user, 'copied an aniv message', 30),
sendMessage(`${user.displayName} got timed out for copying an ${data.anivbot} message`),
createAnivTimeoutRecord(msg.messageText, user, 30)
]);
};
};

View File

@@ -1,4 +1,5 @@
import { redis } from "bun";
import { streamerUsers } from "main";
export async function getInvulns() {
const data = await redis.keys('user:*:invulnerable');
@@ -13,6 +14,7 @@ export async function addInvuln(userid: string) {
return await redis.set(`user:${userid}:invulnerable`, '1');
};
export async function removeInvuln(userid: string) {
if (streamerUsers.includes(userid)) return;
return await redis.del(`user:${userid}:invulnerable`);
};
export async function setTemporaryInvuln(userid: string, duration = 600) {