From 5df7dd64edff312bc0806aee1261917c136a9710 Mon Sep 17 00:00:00 2001 From: qwerinope Date: Mon, 31 Mar 2025 21:38:37 +0200 Subject: [PATCH] reworks (thx dargkkast), more consistent lib functions, total item rework --- src/commands/give.ts | 57 ++++++--------------------------------- src/commands/inventory.ts | 54 ++++++++++++++++++++++++++++--------- src/commands/thank.ts | 6 ++--- src/commands/timeout.ts | 6 ++--- src/items/blaster.ts | 9 ------- src/items/clipboard.ts | 9 ------- src/items/grenade.ts | 9 ------- src/items/items.d.ts | 5 ---- src/items/lootbox.ts | 9 ------- src/items/silverbullet.ts | 9 ------- src/items/tnt.ts | 9 ------- src/items/watergun.ts | 9 ------- src/lib/api.ts | 4 +-- src/lib/auth.ts | 15 ++++++----- src/lib/items.ts | 24 +++++++++++++++++ src/lib/timeoutHelper.ts | 18 ++++++------- src/lib/userHelper.ts | 45 ++++++++++++++++--------------- 17 files changed, 122 insertions(+), 175 deletions(-) delete mode 100644 src/items/blaster.ts delete mode 100644 src/items/clipboard.ts delete mode 100644 src/items/grenade.ts delete mode 100644 src/items/items.d.ts delete mode 100644 src/items/lootbox.ts delete mode 100644 src/items/silverbullet.ts delete mode 100644 src/items/tnt.ts delete mode 100644 src/items/watergun.ts create mode 100644 src/lib/items.ts diff --git a/src/commands/give.ts b/src/commands/give.ts index b251baf..a479ed6 100644 --- a/src/commands/give.ts +++ b/src/commands/give.ts @@ -1,13 +1,6 @@ -import { changeBalance } from "../lib/userHelper"; -import { changeBlasterCount } from "../items/blaster" -import { changeTntCount } from "../items/tnt"; -import { changeSilverbulletCount } from "../items/silverbullet" -import { changeWatergunCount } from "../items/watergun" -import { changeLootboxCount } from "../items/lootbox" -import { changeGrenadeCount } from "../items/grenade" - import { createBotCommand } from "@twurple/easy-bot"; import api from "../lib/api"; +import { changeItemCount } from "../lib/items"; export default createBotCommand('give', async (params, { say, broadcasterId, userId }) => { if (userId !== broadcasterId) return @@ -15,46 +8,12 @@ export default createBotCommand('give', async (params, { say, broadcasterId, use const target = await api.users.getUserByName(params[0]) if (!target) { await say(`'${params[0]}' does not exist`); return } - if (Number(params[2]) === 0) {await say(`Specify the amount`)} + if (isNaN(parseInt(params[2]))) { await say(`Specify the amount`); return } - switch (params[1].toLowerCase()) { - case 'mbucks': - const data1 = await changeBalance(target.name, parseInt(params[2])) - if (!data1.result) { await say(`${target.name} only has ${data1.userBalance}. Cannot subtract ${-parseInt(params[2])} mbucks`); return } - await say(`${target.name} now has ${data1.userBalance.balance} mbucks`) - break - case 'blaster': - const data2 = await changeBlasterCount(target.name, parseInt(params[2])) - if (!data2.result) { await say(`${target.name} only has ${data2.count}. Cannot yoink ${-parseInt(params[2])} blaster${data2.count === 1 ? '' : 's'}`); return } - await say(`${target.name} now has ${data2.count} blaster${data2.count === 1 ? '' : 's'}`) - break - case 'tnt': - const data3 = await changeTntCount(target.name, parseInt(params[2])) - if (!data3.result) { await say(`${target.name} only has ${data3.count}. Cannot yoink ${-parseInt(params[2])} tnt`); return } - await say(`${target.name} now has ${data3.count} tnt`) - break - case 'silverbullet': - const data4 = await changeSilverbulletCount(target.name, parseInt(params[2])) - if (!data4.result) { await say(`${target.name} only has ${data4.count}. Cannot yoink ${-parseInt(params[2])} silverbullet${data4.count === 1 ? '' : 's'}`) } - await say(`${target.name} now has ${data4.count} silverbullet${data4.count === 1 ? '' : 's'}`) - break - case 'watergun': - const data5 = await changeWatergunCount(target.name, parseInt(params[2])) - if (!data5.result) { await say(`${target.name} only has ${data5.count}. Cannot yoink ${-parseInt(params[2])} watergun${data5.count === 1 ? '' : 's'}`) } - await say(`${target.name} now has ${data5.count} watergun${data5.count === 1 ? '' : 's'}`) - break - case 'lootbox': - const data6 = await changeLootboxCount(target.name, parseInt(params[2])) - if (!data6.result) { await say(`${target.name} only has ${data6.count}. Cannot yoink ${-parseInt(params[2])} lootbox${data6.count === 1 ? '' : 'es'}`) } - await say(`${target.name} now has ${data6.count} lootbox${data6.count === 1 ? '' : 'es'}`) - break - case 'grenade': - const data7 = await changeGrenadeCount(target.name, parseInt(params[2])) - if (!data7.result) { await say(`${target.name} only has ${data7.count}. Cannot yoink ${-parseInt(params[2])} grenade${data7.count === 1 ? '' : 's'}`) } - await say(`${target.name} now has ${data7.count} grenade${data7.count === 1 ? '' : 's'}`) - break - default: - await say(`Can't find item ${params[1]}`) - break - } + const data = await changeItemCount(target, params[1].toLowerCase(), parseInt(params[2])) + + if (data.reason === 'negative') { await say(`${target.name} only has ${data.count}. Cannot yoink ${-parseInt(params[2])} ${params[1]}`); return } + else if (data.reason === 'noexist') { await say(`Can't find item ${params[1]}`); return } + + await say(`${target.name} now has ${data.count} ${params[1]}`) }) diff --git a/src/commands/inventory.ts b/src/commands/inventory.ts index 2478c74..e8c3ea4 100644 --- a/src/commands/inventory.ts +++ b/src/commands/inventory.ts @@ -1,20 +1,50 @@ import { createBotCommand } from "@twurple/easy-bot"; import { getInventory } from "../lib/userHelper"; import api from "../lib/api"; +import { HelixUser } from "@twurple/api"; export default createBotCommand('inv', async (params, { userName, say }) => { - if (params.length !== 0 && !await api.users.getUserByName(params[0])) { say(`User ${params[0]} not found`); return } + let user: HelixUser | null + if (params.length !== 0) { + user = await api.users.getUserByName(params[0]) + } else user = await api.users.getUserByName(userName) + if (!user) { + say(`User ${params[0]} not found`) + return + } - const data = params.length === 0 ? { me: true, inv: await getInventory(userName) } : { me: false, inv: await getInventory(params[0]) } + const data = params.length === 0 ? { me: true, inv: await getInventory(user!) } : { me: false, inv: await getInventory(user!) } - await say( - `inventory of ${data.me ? userName : params[0]}: - ${data.inv.blaster > 0 ? `blaster${data.inv.blaster === 1 ? '' : 's'}: ${data.inv.blaster}, ` : ''} - ${data.inv.grenade > 0 ? `grenade${data.inv.grenade === 1 ? '' : 's'}: ${data.inv.grenade}, ` : ''} - ${data.inv.tnt > 0 ? `tnt: ${data.inv.tnt}, ` : ''} - ${data.inv.watergun > 0 ? `watergun${data.inv.watergun === 1 ? '' : 's'}: ${data.inv.watergun}, ` : ''} - ${data.inv.silverbullet > 0 ? `silverbullet${data.inv.silverbullet === 1 ? '' : 's'}: ${data.inv.silverbullet}, ` : ''} - ${data.inv.clipboard > 0 ? `clipboard${data.inv.clipboard === 1 ? '' : 's'}: ${data.inv.clipboard}, `:''} - ${data.inv.lootbox > 0 ? `lootbox${data.inv.lootbox === 1 ? '' : 'es'}: ${data.inv.lootbox}`: ''}` - ) + interface parsedData { + amount: number, + name: string, + plural: string + } + + let dataparsed: parsedData[] = [] + for (const key of Object.entries(data.inv)) { + if (key[1] === 0) continue + switch (key[0]) { + case 'lootbox': + dataparsed.push({ amount: key[1], name: key[0], plural: 'es' }) + break + case 'version': + break + default: + dataparsed.push({ amount: key[1], name: key[0], plural: 's' }) + break + } + } + + if (!dataparsed) { await say(`${data.me ? userName : params[0]} has no items!`); return } + + let messagedata: string[] = [] + for (const item of dataparsed) { + messagedata.push(`${item.name + (item.amount === 1 ? '' : item.plural)}: ${item.amount}`) + } + + await say(` + inventory of ${data.me ? userName : params[0]}: + ${messagedata.join(', ')} + `) }, { aliases: ['inventory'] }) diff --git a/src/commands/thank.ts b/src/commands/thank.ts index 983e96e..a0812ae 100644 --- a/src/commands/thank.ts +++ b/src/commands/thank.ts @@ -1,6 +1,6 @@ import { createBotCommand } from "@twurple/easy-bot"; -export default createBotCommand("thank", async (params, {say, msg}) => { - if (params.length === 0) {await say(`chumpi4Heart ${msg.userInfo.userName}`); return} +export default createBotCommand("thank", async (params, { say, msg }) => { + if (params.length === 0) { await say(`chumpi4Heart ${msg.userInfo.userName}`); return } await say(`chumpi4Heart ${params.join(' ')}`) -}) \ No newline at end of file +}) diff --git a/src/commands/timeout.ts b/src/commands/timeout.ts index 03fbe25..78c292a 100644 --- a/src/commands/timeout.ts +++ b/src/commands/timeout.ts @@ -3,16 +3,16 @@ import { addTimeoutToDB, timeout } from "../lib/timeoutHelper"; import api from "../lib/api"; export default createBotCommand('timeout', async (params, { say, broadcasterId, userName }) => { - if (params.length === 0) {await say("nice miss bro"); return} + if (params.length === 0) { await say("nice miss bro"); return } const target = await api.users.getUserByName(params[0]) const status = await timeout(broadcasterId, target!, 60, `You got blasted by ${userName}`) if (status.status) { await say(`${params[0]} got mandoooGun by ${userName}! mandoooGOTTEM`) const attacker = await api.users.getUserByName(userName) - await addTimeoutToDB(attacker! ,target! , 'blaster') + await addTimeoutToDB(attacker!, target!, 'blaster') } else { - switch (status.reason){ + switch (status.reason) { case 'noexist': await say(`${params[0]} doesn't exist!`) break diff --git a/src/items/blaster.ts b/src/items/blaster.ts deleted file mode 100644 index 3ab295e..0000000 --- a/src/items/blaster.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeBlasterCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.blaster + amount < 0) return {result: false, count: inv.blaster} - inv.blaster += amount - await updateInventory(username, inv) - return {result: true, count: inv.blaster} -} diff --git a/src/items/clipboard.ts b/src/items/clipboard.ts deleted file mode 100644 index f7da99f..0000000 --- a/src/items/clipboard.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeClipboardCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.clipboard+ amount < 0) return {result: false, count: inv.clipboard} - inv.clipboard += amount - await updateInventory(username, inv) - return {result: true, count: inv.clipboard} -} diff --git a/src/items/grenade.ts b/src/items/grenade.ts deleted file mode 100644 index d8495f4..0000000 --- a/src/items/grenade.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeGrenadeCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.grenade+ amount < 0) return {result: false, count: inv.grenade} - inv.grenade += amount - await updateInventory(username, inv) - return {result: true, count: inv.grenade} -} diff --git a/src/items/items.d.ts b/src/items/items.d.ts deleted file mode 100644 index 893eadb..0000000 --- a/src/items/items.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface itemChangeResult { - result: boolean, - count: number -} - diff --git a/src/items/lootbox.ts b/src/items/lootbox.ts deleted file mode 100644 index 3cac5bf..0000000 --- a/src/items/lootbox.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeLootboxCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.lootbox+ amount < 0) return {result: false, count: inv.lootbox} - inv.lootbox += amount - await updateInventory(username, inv) - return {result: true, count: inv.lootbox} -} diff --git a/src/items/silverbullet.ts b/src/items/silverbullet.ts deleted file mode 100644 index ccb3054..0000000 --- a/src/items/silverbullet.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeSilverbulletCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.silverbullet+ amount < 0) return {result: false, count: inv.silverbullet} - inv.silverbullet += amount - await updateInventory(username, inv) - return {result: true, count: inv.silverbullet} -} diff --git a/src/items/tnt.ts b/src/items/tnt.ts deleted file mode 100644 index 75e8925..0000000 --- a/src/items/tnt.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeTntCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.tnt+ amount < 0) return {result: false, count: inv.tnt} - inv.tnt += amount - await updateInventory(username, inv) - return {result: true, count: inv.tnt} -} diff --git a/src/items/watergun.ts b/src/items/watergun.ts deleted file mode 100644 index dba1ca9..0000000 --- a/src/items/watergun.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getInventory, updateInventory } from "../lib/userHelper"; - -export async function changeWatergunCount(username: string, amount = -1): Promise { - let inv = await getInventory(username) - if (amount < 0 && inv.watergun+ amount < 0) return {result: false, count: inv.watergun} - inv.watergun += amount - await updateInventory(username, inv) - return {result: true, count: inv.watergun} -} diff --git a/src/lib/api.ts b/src/lib/api.ts index 25bec24..9443f6c 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,4 +1,4 @@ -import authProvider from "../lib/auth"; +import authProvider from "../lib/auth"; import { ApiClient } from "@twurple/api"; const api = new ApiClient({ authProvider }) -export default api \ No newline at end of file +export default api diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 105d6ec..efac1a9 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -12,9 +12,10 @@ async function firstAccess() { const CLIENT_SECRET = process.env.CLIENT_SECRET const OAUTH_CODE = process.env.OAUTH_CODE - if (!CLIENT_ID) {console.error("No 'CLIENT_ID' for OAuth defined in environment variables."); process.exit(1)} - if (!CLIENT_SECRET) {console.error("No 'CLIENT_SECRET' for OAuth defined in environment variables."); process.exit(1)} - if (!OAUTH_CODE) {console.error("No 'OAUTH_CODE' provided. To get the code, please visit this URL, authorize the bot and copy the 'code' from the return URL.") + if (!CLIENT_ID) { console.error("No 'CLIENT_ID' for OAuth defined in environment variables."); process.exit(1) } + if (!CLIENT_SECRET) { console.error("No 'CLIENT_SECRET' for OAuth defined in environment variables."); process.exit(1) } + if (!OAUTH_CODE) { + console.error("No 'OAUTH_CODE' provided. To get the code, please visit this URL, authorize the bot and copy the 'code' from the return URL.") console.error(`https://id.twitch.tv/oauth2/authorize?client_id=${CLIENT_ID}&redirect_uri=http://localhost&response_type=code&scope=chat:read+chat:edit+moderator:manage:banned_users+moderation:read`) process.exit(1) } @@ -28,8 +29,8 @@ async function firstAccess() { OBTAINMENTTIMESTAMP: tokens.obtainmentTimestamp } - await pb.collection('ttvauth').create({auth}) - + await pb.collection('ttvauth').create({ auth }) + return auth } @@ -54,9 +55,9 @@ authProvider.onRefresh(async (_id, newTokenData) => { auth.OBTAINMENTTIMESTAMP = newTokenData.obtainmentTimestamp const ttvauthid = await pb.collection('ttvauth').getFullList() - await pb.collection('ttvauth').update(ttvauthid[0].id, {auth}) + await pb.collection('ttvauth').update(ttvauthid[0].id, { auth }) console.log("Refreshed OAuth tokens.") }) -export default authProvider \ No newline at end of file +export default authProvider diff --git a/src/lib/items.ts b/src/lib/items.ts new file mode 100644 index 0000000..e1e9401 --- /dev/null +++ b/src/lib/items.ts @@ -0,0 +1,24 @@ +import { HelixUser } from "@twurple/api" +import { getInventory, updateInventory } from "../lib/userHelper" + +const ITEMS = ['blaster', 'silverbullet', 'grenade', 'tnt', 'watergun', 'clipboard', 'lootbox'] + +interface itemChangeResult { + result: boolean, + reason: string + count: number, +} + +export async function changeItemCount(user: HelixUser, item: string, amount = -1): Promise { + if (!ITEMS.includes(item)) return { result: false, reason: 'noexist', count: 0 } + let inv = await getInventory(user) + + if (amount < 0 && inv[item] + amount < 0) return { result: false, reason: 'negative', count: inv[item] } + const newcount: number = inv[item] + amount + + Object.defineProperty(inv, item, { + value: newcount, + }) + await updateInventory(user, inv) + return { result: true, reason: '', count: inv[item] } +} diff --git a/src/lib/timeoutHelper.ts b/src/lib/timeoutHelper.ts index 661105d..43714f6 100644 --- a/src/lib/timeoutHelper.ts +++ b/src/lib/timeoutHelper.ts @@ -3,27 +3,27 @@ import api from "./api"; import pb from "./pocketbase"; import { getDBID } from "./userHelper"; -type shooter = 'blaster'|'grenade'|'silverbullet'|'watergun'|'tnt' +type shooter = 'blaster' | 'grenade' | 'silverbullet' | 'watergun' | 'tnt' interface statusmessage { status: boolean, reason?: string } -export async function timeout(broadcasterid:string, target:HelixUser, duration:number, reason:string): Promise { - if (!target) return {status:false, reason: 'noexist'} - if (await api.moderation.checkUserBan(broadcasterid, target)) return {status: false, reason: 'banned'} +export async function timeout(broadcasterid: string, target: HelixUser, duration: number, reason: string): Promise { + if (!target) return { status: false, reason: 'noexist' } + if (await api.moderation.checkUserBan(broadcasterid, target)) return { status: false, reason: 'banned' } try { - await api.moderation.banUser(broadcasterid, {duration, reason, user: target}) - return {status: true} + await api.moderation.banUser(broadcasterid, { duration, reason, user: target }) + return { status: true } } catch (err) { console.error(err) - return {status: false, reason: 'unknown'} + return { status: false, reason: 'unknown' } } } -export async function addTimeoutToDB(attacker: HelixUser, target:HelixUser, source:shooter) { +export async function addTimeoutToDB(attacker: HelixUser, target: HelixUser, source: shooter) { // This has passed the existance check so there's no need to check if the users exist (twitch) const attackerDB = getDBID(attacker) const targetDB = getDBID(target) @@ -36,4 +36,4 @@ export async function addTimeoutToDB(attacker: HelixUser, target:HelixUser, sour targetname: target.name } await pb.collection('timeouts').create(timeoutobj) -} \ No newline at end of file +} diff --git a/src/lib/userHelper.ts b/src/lib/userHelper.ts index e30c320..b231b1e 100644 --- a/src/lib/userHelper.ts +++ b/src/lib/userHelper.ts @@ -1,8 +1,7 @@ import pb from './pocketbase' -import api from './api' import { HelixUser } from '@twurple/api' -const EMPTYINV: inventory = { +export const EMPTYINV: inventory = { version: 1, blaster: 0, @@ -31,8 +30,8 @@ type balanceGetResult = { user: HelixUser } -export async function getBalance(username: string): Promise { - const user = await existanceValidation(username) +export async function getBalance(user: HelixUser): Promise { + await DBValidation(user) const data = await pb.collection('users').getFirstListItem(`twitchid="${user!.id}"`) return { balance: data.balance, user } } @@ -42,8 +41,8 @@ type balanceChangeResult = { userBalance: balanceGetResult } -export async function changeBalance(username: string, amount: number): Promise { - let userBalance = await getBalance(username) +export async function changeBalance(user: HelixUser, amount: number): Promise { + let userBalance = await getBalance(user) if (amount < 0 && userBalance.balance - amount < 0) return { result: false, userBalance } const dbuser = await pb.collection('users').getFirstListItem(`twitchid="${userBalance.user.id}"`) let data = dbuser @@ -56,7 +55,7 @@ export async function changeBalance(username: string, amount: number): Promise { - const user = await existanceValidation(username) +export async function getTimeouts(user: HelixUser): Promise { + await DBValidation(user) const userDBID = await getDBID(user) const hit = await pb.collection('timeouts').getFullList({ filter: `target="${userDBID}"` }) const shot = await pb.collection('timeouts').getFullList({ filter: `attacker="${userDBID}"` }) @@ -91,7 +90,7 @@ export async function getTimeouts(username: string): Promise } } -interface inventory { +export interface inventory { version: number, blaster: number, @@ -104,33 +103,35 @@ interface inventory { lootbox: number } -export async function getInventory(username: string): Promise { - const user = await existanceValidation(username) - const data = await pb.collection('users').getFirstListItem(`twitchid="${user!.id}"`) +export async function getInventory(user: HelixUser): Promise { + await DBValidation(user) + const data = await pb.collection('users').getFirstListItem(`twitchid="${user.id}"`) return data.inventory } -export async function updateInventory(username: string, newinv: inventory) { - const user = await existanceValidation(username) - const data = await pb.collection('users').getFirstListItem(`twitchid="${user!.id}"`) +export async function getStats(user: HelixUser) { + +} + +export async function updateInventory(user: HelixUser, newinv: inventory) { + await DBValidation(user) + const data = await pb.collection('users').getFirstListItem(`twitchid="${user.id}"`) const recordid = data.id await pb.collection('users').update(recordid, { inventory: newinv }) } -async function existanceValidation(username: string): Promise { - const user = await api.users.getUserByName(username) +async function DBValidation(user: HelixUser) { try { - await pb.collection('users').getFirstListItem(`twitchid="${user!.id}"`) + await pb.collection('users').getFirstListItem(`twitchid="${user.id}"`) } catch (error) { await createUser(user!) } - return user! } async function createUser(user: HelixUser) { const data = { - twitchid: user?.id, - firstname: user?.name, + twitchid: user.id, + firstname: user.name, inventory: EMPTYINV, balance: 0 }