refactoring and stuff

This commit is contained in:
Tabby 2025-11-02 14:55:36 +11:00
parent 03e0f0d5a8
commit 9dc18b86a2
16 changed files with 260 additions and 115 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
# Godot 4+ specific ignores
.godot/
/android/
environment.env

View file

@ -1,17 +1,73 @@
# FabsocBot
# Fabcat!
meow meow! welcome to fabcat! a discord bot for Fabsoc made by Tabby
`Version 0.1`
## Basic Commands
This commands can be used by anyone!
- `/help`
displays this help screen
- `/printer-status`
displays the currently loaded spools and nozzle for each printer
- `/spool-list`
displays a list of both loaded and available spools
## Todo
- [x] want to redo spool management so when a spool is in a printer it leaves leaves the library - only exists in one place at a time
- [x] spool list should show loaded spools in printer, then unloaded and available spools
- [X] unloading a spool returns it to the library
- [ ] job management?
- [x] shoot some of the printers can hold multiple fillaments: endermixer 2, ams: 4
- [x] handling of spools when printer is deleted
- [x] command permissions
- [ ] refactoring
- [ ] documentation
- [ ] readme
- [ ] fabsoc docs
- [ ] help command -> points to fabsoc docs?
- [x] offer to delete /unloaded spools
- [ ] bugtesting / fixing
## Technician Only Commands
Since these commands edit data, only users with the `technician` role may use them
### Printer Management
- `/printer-create <name>`
Creates a new printer with the provided name
- `/printer-delete <name>`
Deletes the printer with the matching name
- `/printer-slots <name> <slots>`
Changes the amount of spool slots a printer has (for example: if an AMS is attached)
- `/printer-nozzle <name> <new_nozzle>`
Changes the nozzle attached to the printer
- `/printer-load <printer-name> <spool-name>`
Loads a spool into a printer, If the printer only has one spool slot and it is filled then this command will replace it and return the old spool to the library (offers option to delete old spool)
- `/printer-unload <printer-name>`
Unloads the spool from the printer, If there are multiple a dropdown asks which to unload. The unloaded spool can then be kept in the library or deleted
### Spool Management
- `/spool-create <name> [link]`
Creates a new spool with the given name and optionally a link to it
- `/spool-delete <name>`
Deletes the spool with the matching name, can only delete a spool if it is in the library (not loaded into a printer)
- `/spool-edit <old-name> <new-name> [new-link]`
Changes the name and/or link of a spool, only works if the spool is in the library (not loaded into a printer)
## Contributing to fabcat
> [!Warning] Work in progress
fabcat is made in Godot v4.5 with the discord.gd plugin. To edit the project follow these steps:
1. Download Godot v4.5
2. Clone the fabcat repo to your computer
3. Open the project folder with Godot
### Project Structure
- `main.gd` - main script which manages everything at the top level, you shouldn't need to touch this
- `Tools.gd` - global script that contains helper functions usable from anywhere, currently just has a function to check if the user has the right permissions
- `AutocompleteTools.gd` - global script that contains helper functions for command autocomplete
- `library.gd` - global script that manages the printer and spool library
- `datatypes`
- `librarySave` - class used by `library.gd` to save data to storage
- `printer` - class used to represent a printer
- `spool` - class used to represent a spool
- `application_cmds` - folder that holds all the commands for Fabcat, do not rename or place commands elsewhere as they will not be picked up
### Application Command Structure
Each application command file is made up of up to 5 key parts, only `execute()` and `data` are required for a minimal command:
- `on_ready()` - this function runs once when the bot starts up, useful for connecting signals
- `on_autocomplete()` - this function is run every time the bot receives a new partially typed argument and can return a list of entries for the user to pick from
- `execute()` - function that is run when the user runs the command
- `on_interaction_create()` - gets run whenever the user interacts with components in a message such as buttons or a dropdown, requires a signal connection to be made in `ready()`
- `data` - defines the structure and arguments of the application command
### Useful Resources
- [Godot Documentation](https://docs.godotengine.org/en/4.5/)
- [discord.gd Documentation](https://3ddelano.github.io/discord.gd/#quick-tips-to-browse-through-the-documentation)
- [discord.gd Youtube Tutorial](https://www.youtube.com/playlist?list=PL5t0hR7ADzuk4M_GDeGcW7cDjG_xp710p)
- [Example discord.gd Project](https://github.com/3ddelano/discord-bot-v2-godot/tree/main)
### Running an instance of fabcat
1. export to linux x86_64
2. move to your server
3. give it executable permissions
4. run with the --headless argument
5. then do something else to keep it running in background, restarting as needed

23
TODO.md Normal file
View file

@ -0,0 +1,23 @@
# FabsocBot
## Todo
- [x] want to redo spool management so when a spool is in a printer it leaves leaves the library - only exists in one place at a time
- [x] spool list should show loaded spools in printer, then unloaded and available spools
- [X] unloading a spool returns it to the library
- [x] shoot some of the printers can hold multiple fillaments: endermixer 2, ams: 4
- [x] handling of spools when printer is deleted
- [x] command permissions
- [x] refactoring
- [x] documentation
- [x] readme
- [x] fabsoc docs
- [x] contributing guide
- [x] help command -> points to fabsoc docs?
- [x] offer to delete /unloaded spools
- [?] bugtesting / fixing
- [x] spool editing
- [ ] seperate place to store bot access key
- [x] update test command
### Possible furture development
- job management

62
application_cmds/help.gd Normal file
View file

@ -0,0 +1,62 @@
extends RefCounted
var help : String = (
"meow meow! welcome to fabcat! a discord bot for Fabsoc made by Tabby <:tabby:1434381576694665378>
`Version 0.1`
## Basic Commands
This commands can be used by anyone!
- `/help`
displays this help screen
- `/printer-status`
displays the currently loaded spools and nozzle for each printer
- `/spool-list`
displays a list of both loaded and available spools
## Technician Only Commands
Since these commands edit data, only users with the `technician` role may use them
### Printer Management
- `/printer-create <name>`
Creates a new printer with the provided name
- `/printer-delete <name>`
Deletes the printer with the matching name
- `/printer-slots <name> <slots>`
Changes the amount of spool slots a printer has (for example: if an AMS is attached)
- `/printer-nozzle <name> <new_nozzle>`
Changes the nozzle attached to the printer
- `/printer-load <printer-name> <spool-name>`
Loads a spool into a printer, If the printer only has one spool slot and it is filled then this command will replace it and return the old spool to the library (offers option to delete old spool)
- `/printer-unload <printer-name>`
Unloads the spool from the printer, If there are multiple a dropdown asks which to unload. The unloaded spool can then be kept in the library or deleted
### Spool Management
- `/spool-create <name> [link]`
Creates a new spool with the given name and optionally a link to it
- `/spool-delete <name>`
Deletes the spool with the matching name, can only delete a spool if it is in the library (not loaded into a printer)
- `/spool-edit <old-name> <new-name> [new-link]`
Changes the name and/or link of a spool, only works if the spool is in the library (not loaded into a printer)"
)
var link : String = "\n\nInterested in improving fabcat? more information is available in the [Fabsoc docs](https://utsfabsoc.github.io/Docs/Technician-Zone/Fabcat-Discord-Bot)"
#func on_ready(main, bot: DiscordBot) -> void:
# pass
#
#func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
# pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
var response : String = "displaying help..."
var embed = Embed.new().set_description(help + link)
embed.set_color("#CB5DFF")
interaction.reply({
"content": response,
"embeds":[embed],
"ephemeral" : true,
})
pass
var data = ApplicationCommand.new()\
.set_name("help")\
.set_description("read the manual")\

View file

@ -0,0 +1 @@
uid://cvrvkvt45ugls

View file

@ -7,7 +7,7 @@ extends RefCounted
# pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)

View file

@ -12,30 +12,11 @@ func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, opt
# The part of string which the user is typing
var part = options[0].value
#print("received autocomplete: ", part)
# The final Array of choices for the autocomplete response
var result = []
for hint in Library.printer_choices_string():
# If the user hasn't typed anything, add all the hints
if part == "":
result.append(ApplicationCommand.choice(hint, hint))
else:
# If the user has typed some part of string,
# add only those hints which have the part as a substring
if hint.findn(part) > -1:
result.append(ApplicationCommand.choice(hint, hint))
# Limit the number of results to 25 (Discord's limit is 25)
if result.size() > 25:
result = result.slice(0, 24)
# Respond with the results
interaction.respond_autocomplete(result)
AutocompleteTools.printer_autocomplete(part, interaction)
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)
@ -84,7 +65,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
print(interaction.data.custom_id)
if(interaction.data.custom_id == "delete-printer"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
#print("deleting: " + endangered_printer)
for printer in Library.save.printers:
@ -105,7 +86,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
})
elif(interaction.data.custom_id == "keep-printer"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
endangered_printer = ""
var embed = Embed.new().set_description("cancelled deletion")

View file

@ -19,7 +19,7 @@ func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, opt
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)
@ -117,7 +117,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
print(interaction.data.custom_id)
if(interaction.data.custom_id == "delete-oldspool"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
#print("deleting: " + endangered_printer)
@ -135,7 +135,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
})
elif(interaction.data.custom_id == "keep-oldspool"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
endangered_spool = null

View file

@ -10,30 +10,11 @@ func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, opt
# The part of string which the user is typing
var part = options[0].value
#print("received autocomplete: ", part)
# The final Array of choices for the autocomplete response
var result = []
for hint in Library.printer_choices_string():
# If the user hasn't typed anything, add all the hints
if part == "":
result.append(ApplicationCommand.choice(hint, hint))
else:
# If the user has typed some part of string,
# add only those hints which have the part as a substring
if hint.findn(part) > -1:
result.append(ApplicationCommand.choice(hint, hint))
# Limit the number of results to 25 (Discord's limit is 25)
if result.size() > 25:
result = result.slice(0, 24)
# Respond with the results
interaction.respond_autocomplete(result)
AutocompleteTools.printer_autocomplete(part, interaction)
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)

View file

@ -10,30 +10,11 @@ func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, opt
# The part of string which the user is typing
var part = options[0].value
#print("received autocomplete: ", part)
# The final Array of choices for the autocomplete response
var result = []
for hint in Library.printer_choices_string():
# If the user hasn't typed anything, add all the hints
if part == "":
result.append(ApplicationCommand.choice(hint, hint))
else:
# If the user has typed some part of string,
# add only those hints which have the part as a substring
if hint.findn(part) > -1:
result.append(ApplicationCommand.choice(hint, hint))
# Limit the number of results to 25 (Discord's limit is 25)
if result.size() > 25:
result = result.slice(0, 24)
# Respond with the results
interaction.respond_autocomplete(result)
AutocompleteTools.printer_autocomplete(part, interaction)
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)

View file

@ -16,7 +16,7 @@ func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, opt
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)
@ -104,7 +104,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
return
if(interaction.data.custom_id == "spool-select"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(interaction.data.values[0])
@ -135,7 +135,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
break
if(interaction.data.custom_id == "delete-unloadspool"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
#print("deleting: " + endangered_printer)
@ -153,7 +153,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
})
elif(interaction.data.custom_id == "keep-unloadspool"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
endangered_spool = null

View file

@ -7,7 +7,7 @@ extends RefCounted
# pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)

View file

@ -12,30 +12,11 @@ func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, opt
# The part of string which the user is typing
var part = options[0].value
#print("received autocomplete: ", part)
# The final Array of choices for the autocomplete response
var result = []
for hint in Library.spool_choices_string():
# If the user hasn't typed anything, add all the hints
if part == "":
result.append(ApplicationCommand.choice(hint, hint))
else:
# If the user has typed some part of string,
# add only those hints which have the part as a substring
if hint.findn(part) > -1:
result.append(ApplicationCommand.choice(hint, hint))
# Limit the number of results to 25 (Discord's limit is 25)
if result.size() > 25:
result = result.slice(0, 24)
# Respond with the results
interaction.respond_autocomplete(result)
AutocompleteTools.spool_autocomplete(part, interaction)
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)
@ -84,7 +65,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
print(interaction.data.custom_id)
if(interaction.data.custom_id == "delete-spool"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
#print("deleting: " + endangered_printer)
for spool in Library.save.spools:
@ -101,7 +82,7 @@ func on_interaction_create(bot: DiscordBot, interaction : DiscordInteraction):
})
elif(interaction.data.custom_id == "keep-spool"):
if not Tools.check_perms(interaction):
if not Tools.check_perms(interaction): #limit access to technicians only
return
endangered_spool = ""
var embed = Embed.new().set_description("cancelled deletion")

View file

@ -0,0 +1,77 @@
extends RefCounted
#func on_ready(main, bot: DiscordBot) -> void:
#pass
#
func on_autocomplete(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
#print(options)
#interaction.respond_autocomplete(Library.printer_choies())
# The part of string which the user is typing
var part = options[0].value
AutocompleteTools.spool_autocomplete(part, interaction)
pass
func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Array) -> void:
if not Tools.check_perms(interaction): #limit access to technicians only
return
print(options)
var spool_name : String = options[0].value
var new_name : String = options[1].value
var new_link : String
if options.size() > 2:
new_link = options[2].value
var spool_exists : bool = false
for spool : Spool in Library.save.spools:
if spool.name == spool_name:
spool_exists = true
if new_name != "0":
spool.name = new_name
if new_link:
spool.link = new_link
#Library.save.printers.erase(printer)
Library.save_data()
if not spool_exists:
interaction.reply({
"content" : "unable to find " + spool_name
})
return
var response : String = "finished editing `" + new_name + "`\n"
var embed = Embed.new().set_description(Library.list_spools(new_name))
interaction.reply({
"content": response,
"embeds":[embed],
})
pass
var data = ApplicationCommand.new()\
.set_name("spool-edit")\
.set_description("edit a spool (IN THE LIBRARY)")\
.add_option(ApplicationCommand.string_option("spool_name", "the spools name (MUST BE UNLOADED)",
{
"required":true,
"autocomplete":true,
#"choices" : Library.printer_choies()
}))\
.add_option(ApplicationCommand.string_option("new_name","new name for the spool (type '0' to keep as is)",
{
"required" : true,
}))\
.add_option(ApplicationCommand.string_option("new_link","new link for the spool",
{
"required" : false,
}))\
## lesson learnt: option name must not have spaces

View file

@ -0,0 +1 @@
uid://bp5ameady5mdn

View file

@ -10,9 +10,9 @@ func execute(main, bot: DiscordBot, interaction: DiscordInteraction, options: Ar
print("hiya!")
interaction.reply(
{
"content" : "meow meow! hearing you loud and clear tabby!"
"content" : "meow meow!"
}
)
pass
var data = ApplicationCommand.new().set_name("meow_test").set_description("meow_desc")
var data = ApplicationCommand.new().set_name("meow_test").set_description("meow meow meow!")