Add Discord bot, give command (disabled)

This commit is contained in:
Hri7566 2024-03-08 20:58:15 -05:00
parent f1602461f7
commit 61eee72917
9 changed files with 341 additions and 2 deletions

BIN
bun.lockb

Binary file not shown.

2
config/discord.yml Normal file
View File

@ -0,0 +1,2 @@
serverID: "841331769051578413"
defaultChannelID: "841331769658703954"

View File

@ -17,6 +17,7 @@
"@trpc/client": "next", "@trpc/client": "next",
"@trpc/server": "next", "@trpc/server": "next",
"cli-markdown": "^3.2.2", "cli-markdown": "^3.2.2",
"discord.js": "^14.14.1",
"mpp-client-net": "^1.1.3", "mpp-client-net": "^1.1.3",
"prisma": "^5.9.1", "prisma": "^5.9.1",
"trpc-bun-adapter": "^1.1.0", "trpc-bun-adapter": "^1.1.0",

View File

@ -32,7 +32,7 @@ export const help = new Command(
} }
if (list2.length > 0) if (list2.length > 0)
list.push(`${group.displayName}: ${list2.join(", ")}`); list.push(`**${group.displayName}:** ${list2.join(", ")}`);
} }
return `__Fishing:__\n${list.join("\n")}`; return `__Fishing:__\n${list.join("\n")}`;

View File

@ -21,6 +21,7 @@ import { myid } from "./general/myid";
import { yeet } from "./inventory/yeet"; import { yeet } from "./inventory/yeet";
import { tree } from "./fishing/tree"; import { tree } from "./fishing/tree";
import { pick } from "./fishing/pick"; import { pick } from "./fishing/pick";
// import { give } from "./inventory/give";
interface ICommandGroup { interface ICommandGroup {
id: string; id: string;
@ -49,7 +50,7 @@ commandGroups.push(fishingGroup);
const inventoryGroup: ICommandGroup = { const inventoryGroup: ICommandGroup = {
id: "inventory", id: "inventory",
displayName: "Inventory", displayName: "Inventory",
commands: [inventory, take, eat, sack, pokemon, yeet] commands: [inventory, take, eat, sack, pokemon, yeet /* give */]
}; };
commandGroups.push(inventoryGroup); commandGroups.push(inventoryGroup);

View File

@ -0,0 +1,130 @@
import type { User } from "@prisma/client";
import Command from "@server/commands/Command";
import { getInventory, updateInventory } from "@server/data/inventory";
import prisma from "@server/data/prisma";
import { addItem } from "@server/items";
export const give = new Command(
"give",
["give", "govo", "guvu", "gava", "geve", "givi", "g", "donate", "bestow"],
"Give another user something you have",
"give <user> <item>",
"command.inventory.give",
async ({ id, command, args, prefix, part, user }) => {
const inventory = await getInventory(user.inventoryId);
if (!inventory) return;
let targetFuzzy = args[0];
if (!targetFuzzy) return `To whom will you ${prefix}${command} to?`;
let foundUser: User = user;
foundUser = (await prisma.user.findFirst({
where: {
name: {
contains: targetFuzzy,
mode: "insensitive"
}
}
})) as User;
if (!foundUser) return `Who is ${targetFuzzy}? I don't know them.`;
const foundInventory = await getInventory(foundUser.inventoryId);
if (!foundInventory) return `They have no room, apparently.`;
if (!args[1])
return `What are you going to ${prefix}${command} to ${foundUser.name}?`;
const argcat = args.slice(1).join(" ");
let foundObject: IObject | undefined;
let i = 0;
for (const item of inventory.items as unknown as IItem[]) {
if (!item.name.toLowerCase().includes(argcat.toLowerCase())) {
i++;
continue;
}
foundObject = item;
break;
}
i = 0;
for (const fish of inventory.fishSack as TFishSack) {
if (!fish.name.toLowerCase().includes(argcat.toLowerCase())) {
i++;
continue;
}
foundObject = fish;
break;
}
if (!foundObject) return `You don't have any "${argcat}" to give.`;
let updated = false;
if (foundObject.objtype == "item") {
addItem(foundInventory.items as unknown as IItem[], foundObject);
updated = true;
} else if (foundObject.objtype == "fish") {
addItem(foundInventory.items as unknown as IItem[], foundObject);
updated = true;
}
let shouldRemove = false;
if (updated) {
await updateInventory(foundInventory);
if (foundObject.objtype == "fish") {
i = 0;
for (const fish of inventory.fishSack as TFishSack) {
if (typeof fish.count !== "undefined") {
if (fish.count > 1) {
shouldRemove = false;
((inventory.fishSack as TFishSack)[i]
.count as number)--;
} else {
shouldRemove = true;
}
} else {
shouldRemove = true;
}
if (shouldRemove)
(inventory.fishSack as TFishSack).splice(i, 1);
break;
}
} else if (foundObject.objtype == "item") {
i = 0;
for (const item of inventory.items as unknown as IItem[]) {
if (typeof item.count == "number") {
if (item.count > 1) {
shouldRemove = false;
((inventory.items as TInventoryItems)[i]
.count as number)--;
} else {
shouldRemove = true;
}
} else {
shouldRemove = true;
}
if (shouldRemove)
(inventory.items as TInventoryItems).splice(i, 1);
break;
}
}
return `You ${
command.endsWith("e") ? `${command}d` : `${command}ed`
} your ${foundObject.name} to ${foundUser.name}.`;
} else {
return `You tried to give your ${foundObject.name} away, but I messed up and the transaction was reverted.`;
}
}
);

185
src/discord/bot/Bot.ts Normal file
View File

@ -0,0 +1,185 @@
import { EventEmitter } from "events";
import Discord from "discord.js";
import { Logger } from "@util/Logger";
import { CosmicColor } from "@util/CosmicColor";
import trpc from "@util/api/trpc";
export interface DiscordBotConfig {
serverID: string;
defaultChannelID: string;
token?: string;
}
export class DiscordBot extends EventEmitter {
public client: Discord.Client;
public logger = new Logger("Discord Bot");
public token?: string;
public server?: Discord.Guild;
public defaultChannel?: Discord.TextChannel;
public b = new EventEmitter();
constructor(public conf: DiscordBotConfig) {
super();
this.token = conf.token ?? process.env.DISCORD_TOKEN;
this.client = new Discord.Client({
intents: [
"Guilds",
"GuildMessages",
"MessageContent",
"GuildMembers"
]
});
this.bindEventListeners();
}
public async start() {
await this.client.login(this.token);
}
private bindEventListeners() {
this.client.on("ready", async () => {
this.logger.info("Connected to Discord");
this.server = await this.client.guilds.fetch(this.conf.serverID);
const channel = await this.server.channels.fetch(
this.conf.defaultChannelID
);
if (!channel) throw "Unable to find default Discord channel.";
this.defaultChannel = channel as Discord.TextChannel;
});
this.client.on("guildMemberAdd", async member => {
if (!this.server) return;
const color = new CosmicColor(
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255)
);
const existingRole = this.server.roles.cache.find(
role => role.name === member.id
);
if (existingRole) {
await member.roles.add(existingRole);
return;
}
const role = await this.server.roles.create({
name: member.id,
color: parseInt(color.toHexa().substring(1), 16)
});
await member.roles.add(role);
});
this.client.on("messageCreate", async msg => {
if (!this.server) return;
if (msg.guildId !== this.server.id) return;
const existingRole = this.server.roles.cache.find(
role => role.name === msg.author.id
);
if (!existingRole) return;
let prefixes: string[];
try {
prefixes = await trpc.prefixes.query();
} catch (err) {
this.logger.error(err);
this.logger.warn("Unable to contact server");
return;
}
let usedPrefix: string | undefined = prefixes.find(pr =>
msg.content.startsWith(pr)
);
if (!usedPrefix) return;
const args = msg.content.split(" ");
const command = await trpc.command.query({
args: args.slice(1, args.length),
command: args[0].substring(usedPrefix.length),
prefix: usedPrefix,
user: {
id: msg.author.id,
name: msg.author.displayName,
color: existingRole.hexColor
}
});
if (!command) return;
if (command.response)
msg.reply(
command.response
.split(`@${msg.author.id}`)
.join(`<@${msg.author.id}>`)
);
});
setInterval(async () => {
try {
const backs = (await trpc.backs.query()) as IBack<unknown>[];
if (backs.length > 0) {
// this.logger.debug(backs);
for (const back of backs) {
if (typeof back.m !== "string") return;
this.b.emit(back.m, back);
}
}
} catch (err) {
return;
}
}, 1000 / 20);
this.b.on("color", async msg => {
if (typeof msg.color !== "string" || typeof msg.id !== "string")
return;
if (!this.server) return;
const existingRole = this.server.roles.cache.find(
role => role.name === msg.id
);
if (!existingRole) {
try {
const member = await this.server.members.fetch(msg.id);
if (!member) throw "no member";
const role = await this.server.roles.create({
name: member.id,
color: parseInt(msg.color.substring(1), 16)
});
await member.roles.add(role);
return;
} catch (err) {
return;
}
}
await existingRole.setColor(parseInt(msg.color.substring(1), 16));
});
this.b.on("sendchat", msg => {
// this.logger.debug("sendchat message:", msg);
if (!this.defaultChannel) return;
this.defaultChannel.send(
msg.message
.split(`@${msg.author.id}`)
.join(`<@${msg.author.id}>`)
);
});
}
}

10
src/discord/bot/index.ts Normal file
View File

@ -0,0 +1,10 @@
import { DiscordBot, type DiscordBotConfig } from "./Bot";
export async function initBot(conf: DiscordBotConfig) {
const bot = new DiscordBot(conf);
await bot.start();
}
export { DiscordBot as Bot };
export default DiscordBot;

10
src/discord/index.ts Normal file
View File

@ -0,0 +1,10 @@
import { loadConfig } from "@util/config";
import { initBot } from "./bot";
import type { DiscordBotConfig } from "./bot/Bot";
const config = loadConfig<DiscordBotConfig>("config/discord.yml", {
serverID: "841331769051578413",
defaultChannelID: "841331769658703954"
});
await initBot(config);