2024-02-29 21:35:09 -05:00
import asyncio
2024-02-27 23:02:03 -05:00
import json
2024-03-15 16:22:10 -04:00
from typing import Mapping , Optional , Tuple , Union
2024-02-29 23:31:30 -05:00
2024-02-28 12:43:26 -05:00
import discord
2024-02-27 23:02:03 -05:00
import websockets
2024-03-14 16:26:31 -04:00
from discord . ext import tasks
2024-02-29 23:31:30 -05:00
from pydactyl import PterodactylClient
2024-03-07 00:56:50 -05:00
from redbot . core import app_commands , commands
from redbot . core . app_commands import Choice
2024-02-27 23:02:03 -05:00
from redbot . core . bot import Red
2024-03-07 00:00:15 -05:00
from redbot . core . utils . chat_formatting import box , error
2024-03-02 19:27:36 -05:00
from redbot . core . utils . views import ConfirmView
2024-02-29 23:26:24 -05:00
2024-03-14 16:26:31 -04:00
from pterodactyl import mcsrvstatus
2024-02-29 23:55:51 -05:00
from pterodactyl . config import config , register_config
2024-02-29 23:26:24 -05:00
from pterodactyl . logger import logger
2024-02-27 23:02:03 -05:00
class Pterodactyl ( commands . Cog ) :
""" Pterodactyl allows you to manage your Pterodactyl Panel from Discord. """
def __init__ ( self , bot : Red ) :
self . bot = bot
2024-02-29 23:31:30 -05:00
self . client : Optional [ PterodactylClient ] = None
self . task : Optional [ asyncio . Task ] = None
self . websocket : Optional [ websockets . WebSocketClientProtocol ] = None
2024-03-01 14:42:45 -05:00
self . retry_counter : int = 0
2024-02-29 23:55:51 -05:00
register_config ( config )
2024-03-01 15:11:57 -05:00
self . task = self . get_task ( )
2024-03-14 16:38:23 -04:00
self . update_topic . start ( )
2024-02-29 16:47:20 -05:00
2024-02-29 23:26:24 -05:00
async def cog_unload ( self ) - > None :
2024-03-14 16:38:23 -04:00
self . update_topic . cancel ( )
2024-02-29 23:26:24 -05:00
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
self . retry_counter = 0
2024-02-29 23:26:24 -05:00
await self . client . _session . close ( ) # pylint: disable=protected-access
2024-02-29 18:50:22 -05:00
2024-03-01 15:11:57 -05:00
def get_task ( self ) - > asyncio . Task :
2024-02-29 23:33:00 -05:00
from pterodactyl . websocket import establish_websocket_connection
2024-02-29 23:26:24 -05:00
task = self . bot . loop . create_task ( establish_websocket_connection ( self ) , name = " Pterodactyl Websocket Connection " )
2024-03-01 15:02:42 -05:00
task . add_done_callback ( self . error_callback )
2024-02-29 21:35:09 -05:00
return task
2024-03-01 15:11:57 -05:00
def error_callback ( self , fut ) - > None : #NOTE - Thanks flame442 and zephyrkul for helping me figure this out
2024-02-29 21:35:09 -05:00
try :
fut . result ( )
except asyncio . CancelledError :
2024-03-01 13:14:55 -05:00
logger . info ( " WebSocket task has been cancelled. " )
2024-02-29 22:15:44 -05:00
except Exception as e : # pylint: disable=broad-exception-caught
2024-02-29 23:26:24 -05:00
logger . error ( " WebSocket task has failed: %s " , e , exc_info = e )
2024-02-29 22:06:59 -05:00
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
if self . retry_counter < 5 :
self . retry_counter + = 1
2024-03-01 14:57:21 -05:00
logger . info ( " Retrying in %s seconds... " , 5 * self . retry_counter )
2024-03-01 15:11:57 -05:00
self . task = self . bot . loop . call_later ( 5 * self . retry_counter , self . get_task )
2024-03-01 14:42:45 -05:00
else :
logger . info ( " Retry limit reached. Stopping task. " )
2024-02-28 08:47:24 -05:00
2024-03-14 16:26:31 -04:00
@tasks.loop ( minutes = 6 )
async def update_topic ( self ) :
topic = await self . get_topic ( )
console = self . bot . get_channel ( await config . console_channel ( ) )
chat = self . bot . get_channel ( await config . chat_channel ( ) )
if console :
await console . edit ( topic = topic )
if chat :
await chat . edit ( topic = topic )
2024-02-28 12:44:54 -05:00
@commands.Cog.listener ( )
2024-02-29 23:26:24 -05:00
async def on_message_without_command ( self , message : discord . Message ) - > None :
if message . channel . id == await config . console_channel ( ) and message . author . bot is False :
2024-03-21 15:27:29 -04:00
if await config . console_commands_enabled ( ) is False :
await message . channel . send ( " Console commands are disabled. " )
logger . debug ( " Received console command from %s , but console commands are disabled: %s " , message . author . id , message . content )
return
2024-02-29 23:26:24 -05:00
logger . debug ( " Received console command from %s : %s " , message . author . id , message . content )
2024-03-13 01:48:17 -04:00
await message . channel . send ( f " Received console command from { message . author . id } : { message . content [ : 1900 ] } " , allowed_mentions = discord . AllowedMentions . none ( ) )
2024-02-29 20:59:47 -05:00
try :
await self . websocket . send ( json . dumps ( { " event " : " send command " , " args " : [ message . content ] } ) )
except websockets . exceptions . ConnectionClosed as e :
2024-02-29 23:26:24 -05:00
logger . error ( " WebSocket connection closed: %s " , e )
2024-02-29 20:59:47 -05:00
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
self . retry_counter = 0
2024-03-01 15:11:57 -05:00
self . task = self . get_task ( )
2024-02-29 23:26:24 -05:00
if message . channel . id == await config . chat_channel ( ) and message . author . bot is False :
logger . debug ( " Received chat message from %s : %s " , message . author . id , message . content )
channel = self . bot . get_channel ( await config . console_channel ( ) )
2024-02-29 17:27:36 -05:00
if channel :
2024-03-13 01:48:17 -04:00
await channel . send ( f " Received chat message from { message . author . id } : { message . content [ : 1900 ] } " , allowed_mentions = discord . AllowedMentions . none ( ) )
2024-03-01 15:27:13 -05:00
msg = json . dumps ( { " event " : " send command " , " args " : [ await self . get_chat_command ( message ) ] } )
2024-02-29 23:26:24 -05:00
logger . debug ( " Sending chat message to server: \n %s " , msg )
2024-02-29 20:59:47 -05:00
try :
await self . websocket . send ( msg )
except websockets . exceptions . ConnectionClosed as e :
2024-02-29 23:26:24 -05:00
logger . error ( " WebSocket connection closed: %s " , e )
2024-02-29 20:59:47 -05:00
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
self . retry_counter = 0
2024-03-01 15:11:57 -05:00
self . task = self . get_task ( )
2024-02-28 12:43:26 -05:00
2024-03-14 16:26:31 -04:00
async def get_topic ( self ) - > str :
topic : str = await config . topic ( )
placeholders = {
" H " : await config . topic_hostname ( ) or " unset " ,
2024-03-14 16:34:41 -04:00
" O " : str ( await config . topic_port ( ) ) ,
2024-03-14 16:26:31 -04:00
}
if await config . api_endpoint ( ) == " minecraft " :
2024-03-14 16:39:15 -04:00
status , response = await mcsrvstatus . get_status ( await config . topic_hostname ( ) , await config . topic_port ( ) )
2024-03-14 16:26:31 -04:00
if status :
2024-03-14 16:34:41 -04:00
placeholders . update ( {
2024-03-14 16:26:31 -04:00
" I " : response [ ' ip ' ] ,
" M " : str ( response [ ' players ' ] [ ' max ' ] ) ,
" P " : str ( response [ ' players ' ] [ ' online ' ] ) ,
" V " : response [ ' version ' ] ,
" D " : response [ ' motd ' ] [ ' clean ' ] [ 0 ] if response [ ' motd ' ] [ ' clean ' ] else " unset " ,
2024-03-14 16:34:41 -04:00
} )
2024-03-14 16:26:31 -04:00
else :
2024-03-14 16:34:41 -04:00
placeholders . update ( {
2024-03-14 16:26:31 -04:00
" I " : response [ ' ip ' ] ,
" M " : " 0 " ,
" P " : " 0 " ,
" V " : " Server Offline " ,
" D " : " Server Offline " ,
2024-03-14 16:34:41 -04:00
} )
2024-03-14 16:26:31 -04:00
for key , value in placeholders . items ( ) :
topic = topic . replace ( ' .$ ' + key , value )
return topic
2024-03-01 15:27:13 -05:00
async def get_chat_command ( self , message : discord . Message ) - > str :
2024-02-29 23:26:24 -05:00
command : str = await config . chat_command ( )
2024-03-01 15:21:44 -05:00
placeholders = {
2024-03-01 15:27:13 -05:00
" C " : str ( message . author . color ) ,
" D " : message . author . discriminator ,
2024-03-01 15:28:14 -05:00
" I " : str ( message . author . id ) ,
2024-03-26 03:04:06 -04:00
" M " : message . content . replace ( ' " ' , ' ' ) . replace ( " \n " , " " ) ,
2024-03-01 15:27:13 -05:00
" N " : message . author . display_name ,
" U " : message . author . name ,
2024-03-04 22:59:43 -05:00
" V " : await config . invite ( ) or " use [p]pterodactyl config invite to change me " ,
2024-03-01 15:21:44 -05:00
}
for key , value in placeholders . items ( ) :
2024-03-01 22:25:21 -05:00
command = command . replace ( ' .$ ' + key , value )
2024-02-29 23:26:24 -05:00
return command
2024-03-15 16:22:10 -04:00
async def get_player_list ( self ) - > Optional [ Tuple [ str , list ] ] :
if await config . api_endpoint ( ) == " minecraft " :
status , response = await mcsrvstatus . get_status ( await config . topic_hostname ( ) , await config . topic_port ( ) )
if status and ' list ' in response [ ' players ' ] :
2024-03-23 11:02:46 -04:00
output_str = ' \n ' . join ( response [ ' players ' ] [ ' list ' ] )
2024-03-15 16:22:10 -04:00
return output_str , response [ ' players ' ] [ ' list ' ]
return None
async def get_player_list_embed ( self , ctx : Union [ commands . Context , discord . Interaction ] ) - > Optional [ discord . Embed ] :
player_list = await self . get_player_list ( )
if player_list :
embed = discord . Embed ( color = await self . bot . get_embed_color ( ctx . channel ) , title = " Players Online " )
embed . description = player_list [ 0 ]
return embed
return None
2024-03-07 00:56:50 -05:00
async def power ( self , ctx : Union [ discord . Interaction , commands . Context ] , action : str , action_ing : str , warning : str = ' ' ) - > None :
if isinstance ( ctx , discord . Interaction ) :
author = ctx . user
else :
author = ctx . author
current_status = await config . current_status ( )
if current_status == action_ing :
if isinstance ( ctx , discord . Interaction ) :
return await ctx . response . send_message ( f " Server is already { action_ing } . " , ephemeral = True )
2024-03-07 02:19:00 -05:00
return await ctx . send ( f " Server is already { action_ing } . " )
2024-03-07 00:56:50 -05:00
2024-03-11 14:20:30 -04:00
if current_status in [ " starting " , " stopping " ] and action != " kill " :
2024-03-07 00:56:50 -05:00
if isinstance ( ctx , discord . Interaction ) :
return await ctx . response . send_message ( " Another power action is already in progress. " , ephemeral = True )
return await ctx . send ( " Another power action is already in progress. " )
view = ConfirmView ( author , disable_buttons = True )
if isinstance ( ctx , discord . Interaction ) :
await ctx . response . send_message ( f " { warning } Are you sure you want to { action } the server? " , view = view )
else :
message = await ctx . send ( f " { warning } Are you sure you want to { action } the server? " , view = view )
await view . wait ( )
if view . result is True :
if isinstance ( ctx , discord . Interaction ) :
2024-03-07 01:03:36 -05:00
await ctx . edit_original_response ( content = f " Sending websocket command to { action } server... " , view = None )
2024-03-07 00:56:50 -05:00
else :
await message . edit ( content = f " Sending websocket command to { action } server... " , view = None )
await self . websocket . send ( json . dumps ( { " event " : " set state " , " args " : [ action ] } ) )
if isinstance ( ctx , discord . Interaction ) :
2024-03-07 01:03:36 -05:00
await ctx . edit_original_response ( content = f " Server { action_ing } " , view = None )
2024-03-07 00:56:50 -05:00
else :
await message . edit ( content = f " Server { action_ing } " , view = None )
else :
if isinstance ( ctx , discord . Interaction ) :
2024-03-07 01:04:27 -05:00
await ctx . edit_original_response ( content = " Cancelled. " , view = None )
2024-03-07 00:56:50 -05:00
else :
await message . edit ( content = " Cancelled. " , view = None )
async def send_command ( self , ctx : Union [ discord . Interaction , commands . Context ] , command : str ) :
channel = self . bot . get_channel ( await config . console_channel ( ) )
if isinstance ( ctx , discord . Interaction ) :
if channel :
2024-03-13 01:48:17 -04:00
await channel . send ( f " Received console command from { ctx . user . id } : { command [ : 1900 ] } " , allowed_mentions = discord . AllowedMentions . none ( ) )
2024-03-07 00:56:50 -05:00
try :
await self . websocket . send ( json . dumps ( { " event " : " send command " , " args " : [ command ] } ) )
await ctx . response . send_message ( f " Command sent to server. { box ( command , ' json ' ) } " , ephemeral = True )
except websockets . exceptions . ConnectionClosed as e :
logger . error ( " WebSocket connection closed: %s " , e )
await ctx . response . send_message ( error ( " WebSocket connection closed. " ) )
self . task . cancel ( )
self . retry_counter = 0
self . task = self . get_task ( )
else :
if channel :
2024-03-13 01:48:17 -04:00
await channel . send ( f " Received console command from { ctx . author . id } : { command [ : 1900 ] } " , allowed_mentions = discord . AllowedMentions . none ( ) )
2024-03-07 00:56:50 -05:00
try :
await self . websocket . send ( json . dumps ( { " event " : " send command " , " args " : [ command ] } ) )
await ctx . send ( f " Command sent to server. { box ( command , ' json ' ) } " )
except websockets . exceptions . ConnectionClosed as e :
logger . error ( " WebSocket connection closed: %s " , e )
await ctx . send ( error ( " WebSocket connection closed. " ) )
self . task . cancel ( )
self . retry_counter = 0
self . task = self . get_task ( )
2024-03-01 01:17:31 -05:00
@commands.Cog.listener ( )
2024-03-01 14:11:11 -05:00
async def on_red_api_tokens_update ( self , service_name : str , api_tokens : Mapping [ str , str ] ) : # pylint: disable=unused-argument
2024-03-01 01:17:31 -05:00
if service_name == " pterodactyl " :
logger . info ( " Configuration value set: api_key \n Restarting task... " )
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
self . retry_counter = 0
2024-03-01 15:11:57 -05:00
self . task = self . get_task ( )
2024-03-01 01:17:31 -05:00
2024-03-07 00:56:50 -05:00
slash_pterodactyl = app_commands . Group ( name = " pterodactyl " , description = " Pterodactyl allows you to manage your Pterodactyl Panel from Discord. " )
@slash_pterodactyl.command ( name = " command " , description = " Send a command to the server console. " )
async def slash_pterodactyl_command ( self , interaction : discord . Interaction , command : str ) - > None :
""" Send a command to the server console.
Parameters :
- - - - - - - - - - -
command : str
The command to send to the server . """
return await self . send_command ( interaction , command )
2024-03-15 16:22:10 -04:00
@slash_pterodactyl.command ( name = " players " , description = " Retrieve a list of players on the server. " )
async def slash_pterodactyl_players ( self , interaction : discord . Interaction ) - > None :
""" Retrieve a list of players on the server. """
e = await self . get_player_list_embed ( interaction )
if e :
await interaction . response . send_message ( embed = e , ephemeral = True )
else :
await interaction . response . send_message ( " No players online. " , ephemeral = True )
2024-03-07 00:56:50 -05:00
@slash_pterodactyl.command ( name = " power " , description = " Send power actions to the server. " )
@app_commands.choices ( action = [
Choice ( name = " Start " , value = " start " ) ,
Choice ( name = " Stop " , value = " stop " ) ,
Choice ( name = " Restart " , value = " restart " ) ,
Choice ( name = " ⚠️ Kill ⚠️ " , value = " kill " )
] )
async def slash_pterodactyl_power ( self , interaction : discord . Interaction , action : app_commands . Choice [ str ] ) - > None :
""" Send power actions to the server.
Parameters :
- - - - - - - - - - -
action : app_commands . Choice [ str ]
The action to perform on the server . """
if action . value == " kill " :
return await self . power ( interaction , action . value , " stopping... (forcefully killed) " , warning = " **⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️** \n " )
2024-03-11 22:19:31 -04:00
if action . value == " stop " :
return await self . power ( interaction , action . value , " stopping... " )
2024-03-07 00:56:50 -05:00
return await self . power ( interaction , action . value , f " { action . value } ing... " )
@commands.group ( autohelp = True , name = " pterodactyl " , aliases = [ " ptero " ] )
2024-02-29 23:26:24 -05:00
async def pterodactyl ( self , ctx : commands . Context ) - > None :
2024-02-28 08:11:23 -05:00
""" Pterodactyl allows you to manage your Pterodactyl Panel from Discord. """
2024-03-15 16:22:10 -04:00
@pterodactyl.command ( name = " players " , aliases = [ " list " , " online " , " playerlist " , " who " ] )
async def pterodactyl_players ( self , ctx : commands . Context ) - > None :
""" Retrieve a list of players on the server. """
e = await self . get_player_list_embed ( ctx )
if e :
await ctx . send ( embed = e )
else :
await ctx . send ( " No players online. " )
2024-03-07 00:13:43 -05:00
@pterodactyl.command ( name = " command " , aliases = [ " cmd " , " execute " , " exec " ] )
2024-03-07 00:00:15 -05:00
@commands.admin ( )
async def pterodactyl_command ( self , ctx : commands . Context , * , command : str ) - > None :
""" Send a command to the server console. """
2024-03-07 00:56:50 -05:00
return await self . send_command ( ctx , command )
2024-03-07 00:00:15 -05:00
2024-03-07 00:13:43 -05:00
@pterodactyl.group ( autohelp = True , name = " power " )
2024-03-01 22:20:50 -05:00
@commands.admin ( )
async def pterodactyl_power ( self , ctx : commands . Context ) - > None :
""" Send power actions to the server. """
@pterodactyl_power.command ( name = " start " )
2024-03-05 02:24:20 -05:00
async def pterodactyl_power_start ( self , ctx : commands . Context ) - > Optional [ discord . Message ] :
2024-03-01 22:20:50 -05:00
""" Start the server. """
2024-03-07 00:56:50 -05:00
return await self . power ( ctx , " start " , " starting... " )
2024-03-01 22:20:50 -05:00
@pterodactyl_power.command ( name = " stop " )
2024-03-05 02:24:20 -05:00
async def pterodactyl_power_stop ( self , ctx : commands . Context ) - > Optional [ discord . Message ] :
2024-03-01 22:20:50 -05:00
""" Stop the server. """
2024-03-07 00:56:50 -05:00
return await self . power ( ctx , " stop " , " stopping... " )
2024-03-01 22:20:50 -05:00
@pterodactyl_power.command ( name = " restart " )
2024-03-05 02:24:20 -05:00
async def pterodactyl_power_restart ( self , ctx : commands . Context ) - > Optional [ discord . Message ] :
2024-03-01 22:20:50 -05:00
""" Restart the server. """
2024-03-07 00:56:50 -05:00
return await self . power ( ctx , " restart " , " restarting... " )
2024-03-01 22:20:50 -05:00
2024-03-05 02:25:58 -05:00
@pterodactyl_power.command ( name = " kill " )
async def pterodactyl_power_kill ( self , ctx : commands . Context ) - > Optional [ discord . Message ] :
""" Kill the server. """
2024-03-07 00:56:50 -05:00
return await self . power ( ctx , " kill " , " stopping... (forcefully killed) " , warning = " **⚠️ Forcefully killing the server process can corrupt data in some cases. ⚠️** \n " )
2024-03-05 02:25:58 -05:00
2024-03-07 00:56:50 -05:00
@pterodactyl.group ( autohelp = True , name = " config " , aliases = [ " settings " , " set " ] )
2024-03-01 00:29:08 -05:00
@commands.is_owner ( )
2024-02-29 23:26:24 -05:00
async def pterodactyl_config ( self , ctx : commands . Context ) - > None :
2024-02-28 08:11:23 -05:00
""" Configure Pterodactyl settings. """
@pterodactyl_config.command ( name = " url " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_base_url ( self , ctx : commands . Context , * , base_url : str ) - > None :
2024-03-01 00:30:38 -05:00
""" Set the base URL of your Pterodactyl Panel.
Please include the protocol ( http / https ) .
Example : ` https : / / panel . example . com ` """
2024-02-29 23:26:24 -05:00
await config . base_url . set ( base_url )
2024-02-28 08:11:23 -05:00
await ctx . send ( f " Base URL set to { base_url } " )
2024-02-29 23:26:24 -05:00
logger . info ( " Configuration value set: base_url = %s \n Restarting task... " , base_url )
2024-02-28 10:46:42 -05:00
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
self . retry_counter = 0
2024-03-01 15:11:57 -05:00
self . task = self . get_task ( )
2024-02-28 08:11:23 -05:00
@pterodactyl_config.command ( name = " serverid " )
2024-02-29 20:28:26 -05:00
async def pterodactyl_config_server_id ( self , ctx : commands . Context , * , server_id : str ) - > None :
2024-03-01 23:04:33 -05:00
""" Set the ID of your server. """
2024-02-29 23:26:24 -05:00
await config . server_id . set ( server_id )
2024-02-28 08:11:23 -05:00
await ctx . send ( f " Server ID set to { server_id } " )
2024-02-29 23:26:24 -05:00
logger . info ( " Configuration value set: server_id = %s \n Restarting task... " , server_id )
2024-02-28 10:46:42 -05:00
self . task . cancel ( )
2024-03-01 14:42:45 -05:00
self . retry_counter = 0
2024-03-01 15:11:57 -05:00
self . task = self . get_task ( )
2024-02-28 12:44:12 -05:00
2024-03-21 15:27:29 -04:00
@pterodactyl_config.group ( name = " console " )
async def pterodactyl_config_console ( self , ctx : commands . Context ) :
""" Configure console settings. """
@pterodactyl_config_console.command ( name = " channel " )
2024-02-29 20:28:26 -05:00
async def pterodactyl_config_console_channel ( self , ctx : commands . Context , channel : discord . TextChannel ) - > None :
2024-02-28 12:44:12 -05:00
""" Set the channel to send console output to. """
2024-02-29 23:26:24 -05:00
await config . console_channel . set ( channel . id )
2024-02-28 12:44:12 -05:00
await ctx . send ( f " Console channel set to { channel . mention } " )
2024-02-29 16:47:20 -05:00
2024-03-21 15:27:29 -04:00
@pterodactyl_config_console.command ( name = " commands " )
async def pterodactyl_config_console_commands ( self , ctx : commands . Context , enabled : bool ) - > None :
""" Enable or disable console commands. """
await config . console_commands_enabled . set ( enabled )
await ctx . send ( f " Console commands set to { enabled } " )
2024-03-04 22:59:43 -05:00
@pterodactyl_config.command ( name = " invite " )
async def pterodactyl_config_invite ( self , ctx : commands . Context , invite : str ) - > None :
""" Set the invite link for your server. """
await config . invite . set ( invite )
await ctx . send ( f " Invite link set to { invite } " )
2024-03-14 16:26:31 -04:00
@pterodactyl_config.group ( name = " topic " )
async def pterodactyl_config_topic ( self , ctx : commands . Context ) :
""" Set the topic for the console and chat channels. """
@pterodactyl_config_topic.command ( name = " host " , aliases = [ " hostname " , " ip " ] )
async def pterodactyl_config_topic_host ( self , ctx : commands . Context , host : str ) - > None :
""" Set the hostname or IP address of your server. """
await config . topic_hostname . set ( host )
2024-03-14 16:49:49 -04:00
await ctx . send ( f " Hostname/IP set to ` { host } ` " )
2024-03-14 16:26:31 -04:00
@pterodactyl_config_topic.command ( name = " port " )
async def pterodactyl_config_topic_port ( self , ctx : commands . Context , port : int ) - > None :
""" Set the port of your server. """
await config . topic_port . set ( port )
2024-03-14 16:49:49 -04:00
await ctx . send ( f " Port set to ` { port } ` " )
2024-03-14 16:26:31 -04:00
@pterodactyl_config_topic.command ( name = " text " )
async def pterodactyl_config_topic_text ( self , ctx : commands . Context , * , text : str ) - > None :
""" Set the text for the console and chat channels.
Available placeholders :
- ` . $ H ` ( hostname )
2024-03-14 16:34:41 -04:00
- ` . $ O ` ( port )
2024-03-14 16:26:31 -04:00
Available for Minecraft servers :
- ` . $ I ` ( ip )
- ` . $ M ` ( max players )
- ` . $ P ` ( players online )
- ` . $ V ` ( version )
- ` . $ D ` ( description / Message of the Day ) """
await config . topic . set ( text )
await ctx . send ( f " Topic set to: \n { box ( text , ' yaml ' ) } " )
2024-03-07 00:56:50 -05:00
@pterodactyl_config.group ( name = " chat " )
2024-02-29 20:31:29 -05:00
async def pterodactyl_config_chat ( self , ctx : commands . Context ) :
""" Configure chat settings. """
@pterodactyl_config_chat.command ( name = " channel " )
2024-02-29 20:28:26 -05:00
async def pterodactyl_config_chat_channel ( self , ctx : commands . Context , channel : discord . TextChannel ) - > None :
2024-02-29 16:47:20 -05:00
""" Set the channel to send chat output to. """
2024-02-29 23:26:24 -05:00
await config . chat_channel . set ( channel . id )
2024-02-29 16:47:20 -05:00
await ctx . send ( f " Chat channel set to { channel . mention } " )
2024-02-29 20:28:26 -05:00
2024-02-29 22:41:06 -05:00
@pterodactyl_config_chat.command ( name = " command " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_chat_command ( self , ctx : commands . Context , * , command : str ) - > None :
2024-02-29 22:41:06 -05:00
""" Set the command that will be used to send messages from Discord.
2024-02-29 20:28:26 -05:00
Required placeholders : ` . $ U ` ( username ) , ` . $ M ` ( message ) , ` . $ C ` ( color )
2024-03-01 14:11:11 -05:00
See [ documentation ] ( https : / / seacogs . coastalcommits . com / pterodactyl / setup / #changing-the-tellraw-command) for more information."""
2024-02-29 23:26:24 -05:00
await config . chat_command . set ( command )
2024-02-29 22:41:06 -05:00
await ctx . send ( f " Chat command set to: \n { box ( command , ' json ' ) } " )
2024-02-29 23:50:54 -05:00
2024-03-07 00:56:50 -05:00
@pterodactyl_config.group ( name = " regex " )
2024-03-01 00:23:00 -05:00
async def pterodactyl_config_regex ( self , ctx : commands . Context ) - > None :
""" Set regex patterns. """
@pterodactyl_config_regex.command ( name = " chat " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_regex_chat ( self , ctx : commands . Context , * , regex : str ) - > None :
2024-03-01 00:23:00 -05:00
""" Set the regex pattern to match chat messages on the server.
2024-03-01 14:11:11 -05:00
See [ documentation ] ( https : / / seacogs . coastalcommits . com / pterodactyl / setup / #my-chat-messages-arent-detected) for more information."""
2024-03-01 00:23:00 -05:00
await config . chat_regex . set ( regex )
await ctx . send ( f " Chat regex set to: \n { box ( regex , ' regex ' ) } " )
@pterodactyl_config_regex.command ( name = " server " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_regex_server ( self , ctx : commands . Context , * , regex : str ) - > None :
2024-02-29 23:50:54 -05:00
""" Set the regex pattern to match server messages on the server.
2024-03-01 14:11:11 -05:00
See [ documentation ] ( https : / / seacogs . coastalcommits . com / pterodactyl / setup / #my-chat-messages-arent-detected) for more information."""
2024-02-29 23:50:54 -05:00
await config . server_regex . set ( regex )
await ctx . send ( f " Server regex set to: \n { box ( regex , ' regex ' ) } " )
2024-03-01 00:05:06 -05:00
2024-03-01 00:46:51 -05:00
@pterodactyl_config_regex.command ( name = " join " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_regex_join ( self , ctx : commands . Context , * , regex : str ) - > None :
2024-03-01 00:46:51 -05:00
""" Set the regex pattern to match join messages on the server.
2024-03-01 14:11:11 -05:00
See [ documentation ] ( https : / / seacogs . coastalcommits . com / pterodactyl / setup / #my-chat-messages-arent-detected) for more information."""
2024-03-01 00:46:51 -05:00
await config . join_regex . set ( regex )
await ctx . send ( f " Join regex set to: \n { box ( regex , ' regex ' ) } " )
@pterodactyl_config_regex.command ( name = " leave " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_regex_leave ( self , ctx : commands . Context , * , regex : str ) - > None :
2024-03-01 00:46:51 -05:00
""" Set the regex pattern to match leave messages on the server.
2024-03-01 14:11:11 -05:00
See [ documentation ] ( https : / / seacogs . coastalcommits . com / pterodactyl / setup / #my-chat-messages-arent-detected) for more information."""
2024-03-01 00:46:51 -05:00
await config . leave_regex . set ( regex )
await ctx . send ( f " Leave regex set to: \n { box ( regex , ' regex ' ) } " )
@pterodactyl_config_regex.command ( name = " achievement " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_regex_achievement ( self , ctx : commands . Context , * , regex : str ) - > None :
2024-03-01 00:46:51 -05:00
""" Set the regex pattern to match achievement messages on the server.
2024-03-01 14:11:11 -05:00
See [ documentation ] ( https : / / seacogs . coastalcommits . com / pterodactyl / setup / #my-chat-messages-arent-detected) for more information."""
2024-03-01 00:46:51 -05:00
await config . achievement_regex . set ( regex )
await ctx . send ( f " Achievement regex set to: \n { box ( regex , ' regex ' ) } " )
2024-03-07 00:56:50 -05:00
@pterodactyl_config.group ( name = " messages " , aliases = [ ' msg ' , ' msgs ' , ' message ' ] )
2024-03-01 00:05:06 -05:00
async def pterodactyl_config_messages ( self , ctx : commands . Context ) :
""" Configure message settings. """
@pterodactyl_config_messages.command ( name = " startup " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_messages_startup ( self , ctx : commands . Context , * , message : str ) - > None :
2024-03-01 00:05:06 -05:00
""" Set the message that will be sent when the server starts. """
await config . startup_msg . set ( message )
await ctx . send ( f " Startup message set to: { message } " )
@pterodactyl_config_messages.command ( name = " shutdown " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_messages_shutdown ( self , ctx : commands . Context , * , message : str ) - > None :
2024-03-01 00:05:06 -05:00
""" Set the message that will be sent when the server stops. """
await config . shutdown_msg . set ( message )
await ctx . send ( f " Shutdown message set to: { message } " )
2024-03-01 00:23:00 -05:00
@pterodactyl_config_messages.command ( name = " join " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_messages_join ( self , ctx : commands . Context , * , message : str ) - > None :
2024-03-01 00:23:00 -05:00
""" Set the message that will be sent when a user joins the server. This is only shown in embeds. """
await config . join_msg . set ( message )
await ctx . send ( f " Join message set to: { message } " )
@pterodactyl_config_messages.command ( name = " leave " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_messages_leave ( self , ctx : commands . Context , * , message : str ) - > None :
2024-03-01 00:23:00 -05:00
""" Set the message that will be sent when a user leaves the server. This is only shown in embeds. """
await config . leave_msg . set ( message )
await ctx . send ( f " Leave message set to: { message } " )
2024-03-01 22:38:49 -05:00
@pterodactyl_config.command ( name = " ip " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_mask_ip ( self , ctx : commands . Context , mask : bool ) - > None :
2024-03-01 22:38:49 -05:00
""" Mask the IP addresses of users in console messages. """
await config . mask_ip . set ( mask )
await ctx . send ( f " IP masking set to { mask } " )
2024-03-01 22:53:08 -05:00
@pterodactyl_config.command ( name = " api " )
2024-03-01 23:01:11 -05:00
async def pterodactyl_config_api ( self , ctx : commands . Context , endpoint : str ) - > None :
2024-03-01 23:03:43 -05:00
""" Set the API endpoint for retrieving user avatars.
2024-03-01 22:53:08 -05:00
2024-03-01 23:03:43 -05:00
This is only used for retrieving user avatars for webhook messages .
See [ PlayerDB ] ( https : / / playerdb . co / ) for valid endpoints . Usually , you should leave this as default . """
2024-03-01 22:53:08 -05:00
await config . api_endpoint . set ( endpoint )
await ctx . send ( f " API endpoint set to { endpoint } " )
2024-03-07 00:56:50 -05:00
@pterodactyl_config_regex.group ( name = " blacklist " , aliases = [ ' block ' , ' blocklist ' ] , )
2024-03-02 19:27:36 -05:00
async def pterodactyl_config_regex_blacklist ( self , ctx : commands . Context ) :
""" Blacklist regex patterns. """
@pterodactyl_config_regex_blacklist.command ( name = " add " )
async def pterodactyl_config_regex_blacklist_add ( self , ctx : commands . Context , name : str , * , regex : str ) - > None :
""" Add a regex pattern to the blacklist. """
async with config . regex_blacklist ( ) as blacklist :
blacklist : dict
if name not in blacklist :
blacklist . update ( { name : regex } )
await ctx . send ( f " Added ` { name } ` to the regex blacklist. \n { box ( regex , ' re ' ) } " )
else :
view = ConfirmView ( ctx . author , disable_buttons = True )
msg = await ctx . send ( f " Name ` { name } ` already exists in the blacklist. Would you like to update it? Current value: \n { box ( blacklist [ name ] , ' re ' ) } " , view = view )
await view . wait ( )
if view . result is True :
blacklist . update ( { name : regex } )
2024-03-22 17:53:19 -04:00
await msg . edit ( content = f " Updated ` { name } ` in the regex blacklist. \n { box ( regex , ' re ' ) } " )
2024-03-02 19:27:36 -05:00
else :
await msg . edit ( content = " Cancelled. " )
@pterodactyl_config_regex_blacklist.command ( name = " remove " )
async def pterodactyl_config_regex_blacklist_remove ( self , ctx : commands . Context , name : str ) - > None :
""" Remove a regex pattern from the blacklist. """
async with config . regex_blacklist ( ) as blacklist :
blacklist : dict
if name in blacklist :
view = ConfirmView ( ctx . author , disable_buttons = True )
msg = await ctx . send ( f " Are you sure you want to remove ` { name } ` from the regex blacklist? \n { box ( blacklist [ name ] , ' re ' ) } " , view = view )
await view . wait ( )
if view . result is True :
del blacklist [ name ]
2024-03-02 19:30:15 -05:00
await msg . edit ( content = " Removed ` {name} ` from the regex blacklist. " )
2024-03-02 19:27:36 -05:00
else :
await msg . edit ( content = " Cancelled. " )
else :
await ctx . send ( f " Name ` { name } ` does not exist in the blacklist. " )
2024-03-01 22:53:08 -05:00
@pterodactyl_config.command ( name = ' view ' , aliases = [ ' show ' ] )
async def pterodactyl_config_view ( self , ctx : commands . Context ) - > None :
""" View the current configuration. """
base_url = await config . base_url ( )
server_id = await config . server_id ( )
console_channel = await config . console_channel ( )
2024-03-21 15:27:29 -04:00
console_commands_enabled = await config . console_commands_enabled ( )
2024-03-01 22:53:08 -05:00
chat_channel = await config . chat_channel ( )
chat_command = await config . chat_command ( )
chat_regex = await config . chat_regex ( )
server_regex = await config . server_regex ( )
join_regex = await config . join_regex ( )
leave_regex = await config . leave_regex ( )
achievement_regex = await config . achievement_regex ( )
startup_msg = await config . startup_msg ( )
shutdown_msg = await config . shutdown_msg ( )
join_msg = await config . join_msg ( )
leave_msg = await config . leave_msg ( )
mask_ip = await config . mask_ip ( )
api_endpoint = await config . api_endpoint ( )
2024-03-04 22:59:43 -05:00
invite = await config . invite ( )
2024-03-02 19:34:30 -05:00
regex_blacklist : dict = await config . regex_blacklist ( )
2024-03-14 16:48:08 -04:00
topic_text = await config . topic ( )
topic_hostname = await config . topic_hostname ( )
topic_port = await config . topic_port ( )
2024-03-01 22:53:08 -05:00
embed = discord . Embed ( color = await ctx . embed_color ( ) , title = " Pterodactyl Configuration " )
embed . description = f """ **Base URL:** { base_url }
* * Server ID : * * ` { server_id } `
2024-03-01 22:55:07 -05:00
* * Console Channel : * * < #{console_channel}>
2024-03-21 15:28:51 -04:00
* * Console Commands : * * { self . get_bool_str ( console_commands_enabled ) }
2024-03-01 22:55:07 -05:00
* * Chat Channel : * * < #{chat_channel}>
2024-03-01 22:53:08 -05:00
* * Startup Message : * * { startup_msg }
* * Shutdown Message : * * { shutdown_msg }
* * Join Message : * * { join_msg }
* * Leave Message : * * { leave_msg }
* * Mask IP : * * { self . get_bool_str ( mask_ip ) }
2024-03-01 22:55:07 -05:00
* * API Endpoint : * * ` { api_endpoint } `
2024-03-04 22:59:43 -05:00
* * Invite : * * { invite }
2024-03-01 22:57:00 -05:00
2024-03-14 16:49:49 -04:00
* * Topic Hostname : * * ` { topic_hostname } `
* * Topic Port : * * ` { topic_port } `
2024-03-14 16:48:54 -04:00
* * Topic Text : * * { box ( topic_text , ' yaml ' ) }
2024-03-14 16:48:08 -04:00
2024-03-01 22:55:07 -05:00
* * Chat Command : * * { box ( chat_command , ' json ' ) }
* * Chat Regex : * * { box ( chat_regex , ' re ' ) }
* * Server Regex : * * { box ( server_regex , ' re ' ) }
* * Join Regex : * * { box ( join_regex , ' re ' ) }
2024-03-01 22:57:00 -05:00
* * Leave Regex : * * { box ( leave_regex , ' re ' ) }
* * Achievement Regex : * * { box ( achievement_regex , ' re ' ) } """
2024-03-02 19:31:26 -05:00
await ctx . send ( embed = embed )
2024-03-02 19:27:36 -05:00
if not len ( regex_blacklist ) == 0 :
regex_blacklist_embed = discord . Embed ( color = await ctx . embed_color ( ) , title = " Regex Blacklist " )
2024-03-02 19:34:30 -05:00
for name , regex in regex_blacklist . items ( ) :
2024-03-02 19:35:42 -05:00
regex_blacklist_embed . add_field ( name = name , value = box ( regex , ' re ' ) , inline = False )
2024-03-02 19:27:36 -05:00
await ctx . send ( embed = regex_blacklist_embed )
2024-03-01 22:53:08 -05:00
2024-03-01 23:43:46 -05:00
def get_bool_str ( self , inp : bool ) - > str :
2024-03-01 22:53:08 -05:00
""" Return a string representation of a boolean. """
2024-03-01 23:43:46 -05:00
return " Enabled " if inp else " Disabled "