Get Started - Learn How To Make Your Bot!
List of all currently Free Items
Here we will implement a Command Handler, this will help us to organize better our bot’s code.
The Command Handler will receive a message and check if it’s a valid function within our files, to do that we will use the 🛄 Teleporter code snippet as an example and we will modify it a little bit to fit in our Command Handler.
Here’s a quick video showing the Teleporter function working through this Command Handler:
Highrise 2023-07-24 23-11-39.mp4
Here’s what we will need to import into our bot’s main file:
from highrise import *
from highrise.models import *
import os
import importlib.util
Now we will make a new folder called “functions” where we will store our functions, see that inside of our new folder I created a file called “teleporter.py”:
Files in the workspace.
Now let’s make some changes on our “teleporter function” to make sure it works from outside of the “Bot class” (outside of the main file):
from highrise import *
from highrise.models import *
async def teleport(self: BaseBot, user: User, message: str)-> None:
"""
Teleports the user to the specified user or coordinate
Usage: /teleport <username> <x,y,z>
"""
#separates the message into parts
#part 1 is the command "/teleport"
#part 2 is the name of the user to teleport to (if it exists)
#part 3 is the coordinates to teleport to (if it exists)
try:
command, username, coordinate = message.split(" ")
except:
await self.highrise.chat("Incorrect format, please use /teleport <username> <x,y,z>")
return
#checks if the user is in the room
room_users = (await self.highrise.get_room_users()).content
for user, _ in room_users:
if user.username.lower() == username.lower():
user_id = user.id
break
#if the user_id isn't defined, the user isn't in the room
if "user_id" not in locals():
await self.highrise.chat("User not found, please specify a valid user and coordinate")
return
#checks if the coordinate is in the correct format (x,y,z)
try:
x, y, z = coordinate.split(",")
except:
await self.highrise.chat("Coordinate not found or incorrect format, please use x,y,z")
return
#teleports the user to the specified coordinate
await self.highrise.teleport(user_id = user_id, dest = Position(float(x), float(y), float(z)))
Perfect! Now we can start making our handler, to do that we will first going to create a new function called “command_handler” inside of our main file that will be triggered if the user says a message that starts with “/”:
from highrise import *
from highrise.models import *
import os
import importlib.util
class Bot(BaseBot):
async def on_start(self, SessionMetadata: SessionMetadata)-> None:
print (f"Starting: {SessionMetadata}")
async def on_chat(self, user: User, message: str)-> None:
print (f"Received: {message} from {user.username}")
if message.startswith("/"):
await self.command_handler(user, message)
async def command_handler(self, user: User, message: str):
pass
Ok, now we will implement the operation of the command_handler in the main file:
async def command_handler(self, user: User, message: str):
parts = message.split(" ")
command = parts[0][1:]
functions_folder = "functions"
# Check if the function exists in the module
for file_name in os.listdir(functions_folder):
if file_name.endswith(".py"):
module_name = file_name[:-3] # Remove the '.py' extension
module_path = os.path.join(functions_folder, file_name)
# Load the module
spec = importlib.util.spec_from_file_location(module_name, module_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Check if the function exists in the module
if hasattr(module, command) and callable(getattr(module, command)):
function = getattr(module, command)
await function(self, user, message)
return
# If no matching function is found
return
The command handler will perform any functions that take an User and a Message as a parameter, the function has to be in the functions folder and to use it the user only has to say “/<name of the function”.
Our code is done, now let’s summarize how this code works!
command_handler
and takes two arguments: self
, user
,and message
. The self
parameter implies that this function is defined within a class.message
parameter is a string containing a command that the code needs to handle.parts = message.split(" ")
: The input message
is split into parts using space (" ") as the delimiter. It assumes that the command is prefixed with a character, like "!command". So, this line separates the prefix from the actual command and any additional arguments.command = parts[0][1:]
: After splitting, the first part of the message will be the command with the prefix. The command
variable is then assigned the value of the command without the prefix, removing the first character.functions_folder = "functions"
: A variable functions_folder
is assigned the value "functions", which is the name of the folder where the command functions are stored.functions
folder to find a module that contains the appropriate command function.for file_name in os.listdir(functions_folder):
: This loop iterates over the list of files in the functions
folder.if file_name.endswith(".py"):
: The code checks if the file is a Python file (ends with ".py").module_name = file_name[:-3]
: It removes the last 3 characters (".py") from the file name to get the module name.module_path = os.path.join(functions_folder, file_name)
: The full path of the module is obtained by joining the functions_folder
and file_name
.spec = importlib.util.spec_from_file_location(module_name, module_path)
: A module specification is created using the module name and the path of the module.module = importlib.util.module_from_spec(spec)
: A new module is created using the module specification.spec.loader.exec_module(module)
: The module is executed, which means the code in the module is run, and it becomes available for use.module
) has the specified command (command
) as an attribute and if that attribute is callable (meaning it's a function).if hasattr(module, command) and callable(getattr(module, command)):
: If the command function is found in the module, the code proceeds to the next step.function = getattr(module, command)
: The command function is obtained from the module using the getattr
function.await function(self, user, message)
: The command function is called with self
user
, and message
as arguments. The await
keyword indicates that this function is an asynchronous function, and it will wait for the command function to complete its execution.This code is designed to dynamically load and execute command functions from separate Python files located in the "functions" folder based on the input command passed to the command_handler
function. The assumption is that each command function has a corresponding Python file with the same name as the command in the "functions" folder.