reworks (thx dargkkast), more consistent lib functions, total item rework

This commit is contained in:
2025-03-31 21:38:37 +02:00
parent 773187ef20
commit 5df7dd64ed
17 changed files with 122 additions and 175 deletions

View File

@@ -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]}`)
})

View File

@@ -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'] })

View File

@@ -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(' ')}`)
})

View File

@@ -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

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeBlasterCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeClipboardCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeGrenadeCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -1,5 +0,0 @@
interface itemChangeResult {
result: boolean,
count: number
}

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeLootboxCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeSilverbulletCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeTntCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -1,9 +0,0 @@
import { getInventory, updateInventory } from "../lib/userHelper";
export async function changeWatergunCount(username: string, amount = -1): Promise<itemChangeResult> {
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}
}

View File

@@ -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,7 +29,7 @@ async function firstAccess() {
OBTAINMENTTIMESTAMP: tokens.obtainmentTimestamp
}
await pb.collection('ttvauth').create({auth})
await pb.collection('ttvauth').create({ auth })
return auth
}
@@ -54,7 +55,7 @@ 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.")
})

24
src/lib/items.ts Normal file
View File

@@ -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<itemChangeResult> {
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] }
}

View File

@@ -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<statusmessage> {
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<statusmessage> {
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)

View File

@@ -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<balanceGetResult> {
const user = await existanceValidation(username)
export async function getBalance(user: HelixUser): Promise<balanceGetResult> {
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<balanceChangeResult> {
let userBalance = await getBalance(username)
export async function changeBalance(user: HelixUser, amount: number): Promise<balanceChangeResult> {
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<b
interface timeoutsGetResult {
user: HelixUser,
hit: {
blaster: number, // I'm going to combile blaster, grenade and tnt into one. Watergun is irrellevant
blaster: number, // I'm going to combine blaster, grenade and tnt into one. Watergun is irrellevant
silverbullet: number,
},
shot: {
@@ -67,8 +66,8 @@ interface timeoutsGetResult {
const BLASTERS = ['blaster', 'grenade', 'tnt']
export async function getTimeouts(username: string): Promise<timeoutsGetResult> {
const user = await existanceValidation(username)
export async function getTimeouts(user: HelixUser): Promise<timeoutsGetResult> {
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<timeoutsGetResult>
}
}
interface inventory {
export interface inventory {
version: number,
blaster: number,
@@ -104,33 +103,35 @@ interface inventory {
lootbox: number
}
export async function getInventory(username: string): Promise<inventory> {
const user = await existanceValidation(username)
const data = await pb.collection('users').getFirstListItem(`twitchid="${user!.id}"`)
export async function getInventory(user: HelixUser): Promise<inventory> {
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<HelixUser> {
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
}