FabcatBot/main.gd
2026-01-03 18:06:32 +11:00

215 lines
7.1 KiB
GDScript

extends Node
signal interaction_create(world, bot, interaction, data)
#const prefix = "gd."
var interactions = {}
var application_commands = {}
signal message_created(bot: DiscordBot, message: Message, channel: Dictionary)
func _load_bot_token() -> String:
# read from .env file DISORD_BOT_TOKEN
var lines = FileAccess.get_file_as_string(".env").split("\n")
#print(lines)
for line in lines:
if line.begins_with("DISCORD_BOT_TOKEN="):
return line.split("=")[1]
return ""
func _ready() -> void:
var bot = DiscordBot.new()
add_child(bot)
# Try to read token from global environment variables
var token = OS.get_environment("DISCORD_BOT_TOKEN")
if not token or (token and len(token) < 10):
#Read token from local .env file
token = _load_bot_token()
bot.TOKEN = token
#bot.INTENTS = 4609
bot.bot_ready.connect(_on_bot_ready)
bot.message_create.connect(_on_message_create)
bot.interaction_create.connect(_on_interaction_create)
bot.INTENTS = bot.INTENTS | (1 << 12)
bot.login()
#_load_commands(bot)
_load_application_commands(bot)
func _on_bot_ready(bot: DiscordBot):
print("Logged in as " + bot.user.username + "#" + bot.user.discriminator)
bot.set_presence({
"activity": {
"type": "Watching",
"name": "Watching the printers"
}
})
# Registering commands is not needed on every run,
# only register the command if you change any options
# or if you add/remove commands
# For development use the single server command and
# once you have the commands working you can register
# them as global commands
# -----Single server (updates instantly)
#_register_application_commands(bot, "guild_id_here")
_register_application_commands(bot, "679917161195765822") # personal server
#_register_application_commands(bot, "1038007666032787476") # fabsoc
# -----Global (may take upto 1hr to update)
#_register_application_commands(bot) # everywhere
func _on_message_create(bot: DiscordBot, message: Message, channel: Dictionary) -> void:
#print("meow!")
message_created.emit(bot, message, channel)
#if message.author.bot or not message.content.begins_with(prefix):
#return
#
## Make sure to use trim_prefix() instead of lstrip()
#var raw_content = message.content.trim_prefix(prefix)
#var tokens = []
#var r = RegEx.new()
#r.compile("\\S+") # Negated whitespace character class
#for token in r.search_all(raw_content):
#tokens.append(token.get_string())
#var cmd_or_alias = tokens[0].to_lower()
#tokens.remove(0) # Remove the command name from the tokens
#var args = tokens
#_handle_command(bot, message, channel, cmd_or_alias, args)
#func _load_commands(bot: DiscordBot) -> void:
#var cmd_path = "res://cmds/"
#var dir = DirAccess.open(cmd_path)
#if not dir:
#push_error("An error occurred when trying to open /cmds/ folder.")
#return
#
#dir.list_dir_begin()
#while true:
#var file = dir.get_next()
#if file == "": # End of files
#break
#elif not file.begins_with(".") and (file.ends_with(".gd") or file.ends_with(".gdc")):
#var script = load(cmd_path + file.get_basename() + ".gd").new()
#var data = script.help
#
## Ensure that the commands don't have the default help values
#assert(data.name != "test_name" and data.category != "test_category" and data.description != "test_description" and script.get_usage(prefix) != "test usage", "Must change default values for Command in " + file)
#
#if not data.enabled:
#continue
#
#if script.has_method("on_ready"):
#script.on_ready(self, bot)
#
#commands[data.name] = script
#
#if not data.has("aliases"):
#continue
#
#for alias in data.aliases:
#assert(not command_aliases.has(alias), "Duplicate cmd aliases found in cmd: " + file)
#
#command_aliases[alias] = data.name
#
#print("Loaded " + str(commands.size()) + " cmds")
#dir.list_dir_end()
func _load_application_commands(bot: DiscordBot) -> void:
var app_cmd_path = "res://application_cmds/"
var dir = DirAccess.open(app_cmd_path)
if not dir:
push_error("An error occurred when trying to open /application_cmds/ folder.")
return
dir.list_dir_begin()
while true:
var file = dir.get_next()
if file == "": # End of files
break
elif not file.begins_with(".") and (file.ends_with(".gd") or file.ends_with(".gdc")):
var script = load(app_cmd_path + file.get_basename() + ".gd").new()
var data = script.data
# Ensure that the commands don't have the default help values
assert(data.name != "test_name" and data.description != "test_description", "Must change default values for ApplicationCommand in " + file)
if script.has_method("on_ready"):
script.on_ready(self, bot)
application_commands[data.name] = script
print("Loaded " + str(application_commands.size()) + " application cmds")
dir.list_dir_end()
func _register_application_commands(bot, guild_id: String = "") -> void:
var application_commands_data = []
for app_cmd in application_commands.values():
application_commands_data.append(app_cmd.data)
bot.register_commands(application_commands_data, guild_id)
#func _handle_command(bot: DiscordBot, message: Message, channel: Dictionary, cmd_or_alias: String, args: Array):
#var cmd = null
#if command_aliases.has(cmd_or_alias):
#cmd = commands[command_aliases[cmd_or_alias]]
#elif commands.has(cmd_or_alias):
#cmd = commands[cmd_or_alias]
#
#if cmd == null:
#return
#
#print("CMD: " + cmd.help.name + " by " + message.author.username + "#" + message.author.discriminator + " (" + message.author.id + ")")
#
#cmd.on_message(self, bot, message, channel, args)
func remove_components_from_interaction(interaction: DiscordInteraction, msg = ":robot: Components have timed out!") -> void:
#var embed = Embed.new().set_description(msg)
#var new_embeds = interaction.message.embeds ## + [embed] TODO?
#interaction.update({
#"content": interaction.message.content,
#"embeds": new_embeds,
#"components": []
#})
pass
func _on_interaction_create(bot: DiscordBot, interaction: DiscordInteraction):
print("\ndebug interaction: " + interaction.to_string())
# Handle ApplicationCommand
if interaction.is_command() or interaction.is_autocomplete():
var cmd_name = interaction.data.name
if application_commands.has(cmd_name):
# The application command was found, so execute it
var app_cmd = application_commands[cmd_name]
var options = interaction.data.options if interaction.data.has("options") else []
if interaction.is_autocomplete():
# It is an autocomplete command
app_cmd.on_autocomplete(self, bot, interaction, options)
return
print("APP_CMD: " + app_cmd.data.name + " by " + interaction.member.user.username + "#" + interaction.member.user.discriminator + " (" + interaction.member.user.id + ")")
app_cmd.execute(self, bot, interaction, options)
else:
# The application command was not found
interaction.reply({
"ephemeral": true,
"content": ":electric_plug: The requested command was not found."
})
pass
return
var msg_id = interaction.message.id
# Emit the interaction to the normal (text) commands
if interactions.has(msg_id):
emit_signal("interaction_create", self, bot, interaction, interactions[msg_id])
else:
remove_components_from_interaction(interaction)