mirror of
https://github.com/TotalFreedomMC/AMP-Bot.git
synced 2024-12-22 08:15:15 +00:00
circa 2017, doubt it still works
This commit is contained in:
parent
168e007e84
commit
2deb5d6722
9 changed files with 506 additions and 0 deletions
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
#Pycharm.
|
||||
.idea/
|
||||
*.pyc
|
||||
~*/
|
||||
|
||||
## Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# macOS nonsense
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Windows nonsense
|
||||
## Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Ew
|
||||
desktop.ini
|
||||
|
||||
|
214
bot.py
Normal file
214
bot.py
Normal file
|
@ -0,0 +1,214 @@
|
|||
import os
|
||||
import logging
|
||||
|
||||
from discord.ext import commands
|
||||
from utils.config import Config
|
||||
from utils import amp
|
||||
from utils import checks
|
||||
|
||||
config = Config()
|
||||
|
||||
desc = "Server control bot for {}".format(config.name)
|
||||
|
||||
bot = commands.Bot(command_prefix=config.command_prefix, description=desc, pm_help=False)
|
||||
|
||||
def init_console_logger():
|
||||
logger = logging.getLogger("consolelogger")
|
||||
format = logging.Formatter("%(asctime)s %(message)s")
|
||||
fileHandler = logging.FileHandler("commands.log")
|
||||
fileHandler.setFormatter(format)
|
||||
streamHandler = logging.StreamHandler()
|
||||
streamHandler.setFormatter(format)
|
||||
logger.setLevel(logging.INFO)
|
||||
logger.addHandler(fileHandler)
|
||||
logger.addHandler(streamHandler)
|
||||
init_console_logger()
|
||||
|
||||
console_logger = logging.getLogger("consolelogger")
|
||||
|
||||
class Server():
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command()
|
||||
async def state(self):
|
||||
"""Gets the server's current state"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
await self.bot.say("The server is **{}**".format(state))
|
||||
|
||||
@checks.is_senior_admin()
|
||||
@commands.command()
|
||||
async def start(self):
|
||||
"""Starts the server"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
if state == "online":
|
||||
await self.bot.say("The server is already running")
|
||||
return
|
||||
elif state == "starting":
|
||||
await self.bot.say("The server is already starting")
|
||||
return
|
||||
else:
|
||||
amp.control_power(amp.Power.START)
|
||||
await self.bot.say("Starting the server...")
|
||||
|
||||
@checks.is_senior_admin()
|
||||
@commands.command()
|
||||
async def restart(self):
|
||||
"""Restarts the server"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
if state == "starting":
|
||||
await self.bot.say("The server is already starting")
|
||||
return
|
||||
elif state == "shutting down":
|
||||
await self.bot.say("The server is already shutting down")
|
||||
return
|
||||
else:
|
||||
amp.control_power(amp.Power.RESTART)
|
||||
await self.bot.say("Restarting the server...")
|
||||
|
||||
@checks.is_senior_admin()
|
||||
@commands.command()
|
||||
async def stop(self):
|
||||
"""Stops the server"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
if state == "offline":
|
||||
await self.bot.say("The server is already stopped")
|
||||
return
|
||||
elif state == "shutting down":
|
||||
await self.bot.say("The server is already shutting down")
|
||||
return
|
||||
else:
|
||||
amp.control_power(amp.Power.STOP)
|
||||
await self.bot.say("Stopping the server...")
|
||||
|
||||
@checks.is_senior_admin()
|
||||
@commands.command()
|
||||
async def kill(self):
|
||||
"""Kills the server (useful if it isn't responding)"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
if state == "offline":
|
||||
await self.bot.say("The server is already stopped")
|
||||
return
|
||||
else:
|
||||
amp.control_power(amp.Power.KILL)
|
||||
await self.bot.say("Killing the server...")
|
||||
|
||||
@commands.command()
|
||||
async def list(self):
|
||||
"""Gets the list of online players"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
if state == "offline":
|
||||
await self.bot.say("The server is offline")
|
||||
return
|
||||
await self.bot.say(amp.get_player_list())
|
||||
|
||||
@checks.is_senior_admin()
|
||||
@commands.command(pass_context=True)
|
||||
async def sendcommand(self, ctx, *, command:str):
|
||||
"""Send a console command"""
|
||||
try:
|
||||
state = amp.get_server_state()
|
||||
except KeyError:
|
||||
amp.get_session_id()
|
||||
state = amp.get_server_state()
|
||||
if state == "offline":
|
||||
await self.bot.say("The server is offline")
|
||||
return
|
||||
amp.send_console_command(command)
|
||||
console_logger.info("[Console Command] {}: {}".format(ctx.message.author, ctx.message.content.replace("{}{} ".format(config.command_prefix, ctx.command), "")))
|
||||
await self.bot.say("Command sent!")
|
||||
|
||||
bot.add_cog(Server(bot))
|
||||
|
||||
@bot.event
|
||||
async def on_command_error(error, ctx):
|
||||
if isinstance(error, commands.CommandNotFound):
|
||||
return
|
||||
if isinstance(error, commands.DisabledCommand):
|
||||
await bot.send_message(ctx.message.channel, "This command has been disabled")
|
||||
return
|
||||
if isinstance(error, checks.dev_only):
|
||||
await bot.send_message(ctx.message.channel, "This command can only be ran by the server developers")
|
||||
return
|
||||
if isinstance(error, checks.admin_only):
|
||||
await bot.send_message(ctx.message.channel, "This command can only be ran by the discord admins")
|
||||
return
|
||||
if isinstance(error, checks.senior_admin_only):
|
||||
await bot.send_message(ctx.message.channel, "This command can only be ran by the server senior admins")
|
||||
return
|
||||
|
||||
# In case the bot failed to send a message to the channel, the try except pass statement is to prevent another error
|
||||
try:
|
||||
await bot.send_message(ctx.message.channel, error)
|
||||
except:
|
||||
pass
|
||||
print("An error occured while executing the command named {}: {}".format(ctx.command.qualified_name, error))
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print("Connected! Logged in as {}/{}".format(bot.user, bot.user.id))
|
||||
amp.get_session_id()
|
||||
|
||||
@checks.is_dev()
|
||||
@bot.command(hidden=True, pass_context=True)
|
||||
async def debug(ctx, *, shit:str):
|
||||
import asyncio
|
||||
import requests
|
||||
import random
|
||||
py = "```py\n{}```"
|
||||
"""This is the part where I make 20,000 typos before I get it right"""
|
||||
# "what the fuck is with your variable naming" - EJH2
|
||||
# seth seriously what the fuck - Robin
|
||||
try:
|
||||
rebug = eval(shit)
|
||||
if asyncio.iscoroutine(rebug):
|
||||
rebug = await rebug
|
||||
await bot.say(py.format(rebug))
|
||||
except Exception as damnit:
|
||||
await bot.say(py.format("{}: {}".format(type(damnit).__name__, damnit)))
|
||||
|
||||
@checks.is_dev()
|
||||
@bot.command(hidden=True, pass_context=True)
|
||||
async def terminal(ctx, *, command:str):
|
||||
"""Runs terminal commands and shows the output via a message. Oooh spoopy!"""
|
||||
xl = "```xl\n{}```"
|
||||
try:
|
||||
await bot.send_typing(ctx.message.channel)
|
||||
await bot.say(xl.format(os.popen(command).read()))
|
||||
except:
|
||||
await bot.say("Error, couldn't send command")
|
||||
|
||||
@checks.is_dev()
|
||||
@bot.command(hidden=True)
|
||||
async def shutdown():
|
||||
"""Shuts down the bot"""
|
||||
await bot.say("Shutting down...")
|
||||
amp.logout()
|
||||
await bot.logout()
|
||||
|
||||
print("Connecting...")
|
||||
bot.run(config._token)
|
30
config.ini
Normal file
30
config.ini
Normal file
|
@ -0,0 +1,30 @@
|
|||
[Bot]
|
||||
; Your server name
|
||||
Name = a minecraft server
|
||||
|
||||
; The command prefix you would like to use
|
||||
Command_Prefix = srv!
|
||||
|
||||
; The bot account token
|
||||
Token =
|
||||
|
||||
; Developer only ID
|
||||
; In order for a user to use dev-only commands, they need to at least have this role. To get the id of a role, get a bot that can get it for you.
|
||||
Developer_Role_ID =
|
||||
|
||||
; In order for a user to use admin-only commands, they need at least one of these roles or the developer role. To get the id of a role, get a bot that can get it for you.
|
||||
; Ex: Admin_Role_IDs = ID1 ID2 ID3
|
||||
Admin_Role_IDs =
|
||||
|
||||
; In order for a user to use senior-admin+ only commands, they need to atleast have this role, the admin role, or the developer role. To get the id of a role, get a bot that can get it for you.
|
||||
Senior_Admin_Role_ID =
|
||||
|
||||
[AMP]
|
||||
; MAKE SURE YOU ARE USING YOUR MINECRAFT INSTANCE AND NOT THE ADS INSTANCE
|
||||
AMP_Username =
|
||||
|
||||
AMP_Password =
|
||||
|
||||
; DO NOT LEAVE A TRAILING SLASH (Ex: https://example.com:1234/)
|
||||
; Ex: URL = https://example.com:1234
|
||||
URL =
|
8
run.sh
Normal file
8
run.sh
Normal file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
python3.5 -V > /dev/null 2>&1 || {
|
||||
echo >&2 "Python 3.5 doesn't seem to be installed! Do you have a weird installation?"
|
||||
echo >&2 "If you have python 3.5, use it to run bot.py instead of this script."
|
||||
exit 1; }
|
||||
|
||||
python3.5 bot.py
|
38
runbot.bat
Normal file
38
runbot.bat
Normal file
|
@ -0,0 +1,38 @@
|
|||
@ECHO off
|
||||
|
||||
CHCP 65001 > NUL
|
||||
CD /d "%~dp0"
|
||||
|
||||
SETLOCAL ENABLEEXTENSIONS
|
||||
SET KEY_NAME="HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
||||
SET VALUE_NAME=HideFileExt
|
||||
|
||||
FOR /F "usebackq tokens=1-3" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO (
|
||||
SET ValueName=%%A
|
||||
SET ValueType=%%B
|
||||
SET ValueValue=%%C
|
||||
)
|
||||
|
||||
IF x%ValueValue:0x0=%==x%ValueValue% (
|
||||
ECHO Unhiding file extensions...
|
||||
START CMD /c REG ADD HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced /v HideFileExt /t REG_DWORD /d 0 /f
|
||||
)
|
||||
ENDLOCAL
|
||||
|
||||
|
||||
IF EXIST %SYSTEMROOT%\py.exe (
|
||||
CMD /k py.exe -3.6 bot.py
|
||||
EXIT
|
||||
)
|
||||
|
||||
python --version > NUL 2>&1
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO nopython
|
||||
|
||||
CMD /k python bot.py
|
||||
GOTO end
|
||||
|
||||
:nopython
|
||||
ECHO ERROR: Python has either not been installed or not added to your PATH.
|
||||
|
||||
:end
|
||||
PAUSE
|
8
runbot_mac.command
Normal file
8
runbot_mac.command
Normal file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "$BASH_SOURCE")" || {
|
||||
echo "Python 3.5 doesn't seem to be installed!" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
python3.5 bot.py
|
89
utils/amp.py
Normal file
89
utils/amp.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
import requests
|
||||
|
||||
from utils.config import Config
|
||||
|
||||
config = Config()
|
||||
username = config.amp_username
|
||||
password = config.amp_password
|
||||
url = config.amp_panel_url
|
||||
|
||||
headers = {"Accept":"text/javascript"}
|
||||
session_id = None
|
||||
|
||||
class Paths:
|
||||
LOGIN = url + "/API/Core/Login"
|
||||
LOGOUT = url + "/API/Core/Logout"
|
||||
GET_STATUS = url + "/API/Core/GetStatus"
|
||||
class power:
|
||||
START = url + "/API/Core/Start"
|
||||
RESTART = url + "/API/Core/Restart"
|
||||
STOP = url + "/API/Core/Stop"
|
||||
KILL = url + "/API/Core/Kill"
|
||||
PLAYER_LIST = url + "/API/Core/GetUserList"
|
||||
SEND_CONSOLE_COMMAND = url + "/API/Core/SendConsoleMessage"
|
||||
|
||||
class States:
|
||||
OFFLINE = 0
|
||||
STARTING = 10
|
||||
ONLINE = 20
|
||||
SHUTTING_DOWN = 30
|
||||
|
||||
class Power:
|
||||
START = "start"
|
||||
RESTART = "restart"
|
||||
STOP = "stop"
|
||||
KILL = "kill"
|
||||
|
||||
def get_session_id():
|
||||
# The API only accepts json in the form of a string for some odd reason
|
||||
data = str({"username":config.amp_username,"password":config.amp_password,"token":"","rememberMe":"false","SESSIONID":""})
|
||||
response = requests.post(Paths.LOGIN, headers=headers, data=data).json()
|
||||
global session_id
|
||||
session_id = response["sessionID"]
|
||||
|
||||
def logout():
|
||||
data = str({"SESSIONID": session_id})
|
||||
requests.post(Paths.LOGOUT, headers=headers, data=data)
|
||||
|
||||
def get_server_state():
|
||||
data = str({"SESSIONID":session_id})
|
||||
response = requests.post(Paths.GET_STATUS, headers=headers, data=data).json()
|
||||
state = response["State"]
|
||||
if state == States.OFFLINE:
|
||||
return "offline"
|
||||
elif state == States.STARTING:
|
||||
return "starting"
|
||||
elif state == States.ONLINE:
|
||||
return "online"
|
||||
elif state == States.SHUTTING_DOWN:
|
||||
return "shutting down"
|
||||
else:
|
||||
return str(state)
|
||||
|
||||
def control_power(action):
|
||||
path = None
|
||||
if action == Power.START:
|
||||
path = Paths.power.START
|
||||
elif action == Power.RESTART:
|
||||
path = Paths.power.RESTART
|
||||
elif action == Power.STOP:
|
||||
path = Paths.power.STOP
|
||||
elif action == Power.KILL:
|
||||
path = Paths.power.KILL
|
||||
data = str({"SESSIONID":session_id})
|
||||
requests.post(path, headers=headers, data=data)
|
||||
|
||||
def get_player_list():
|
||||
data = str({"SESSIONID":session_id})
|
||||
response = requests.post(Paths.PLAYER_LIST, headers=headers, data=data).json()
|
||||
players = []
|
||||
for p in response["result"].values():
|
||||
players.append(p)
|
||||
if len(players) == 0:
|
||||
return "```There are no players online```"
|
||||
else:
|
||||
return "```{}```".format(", ".join(players))
|
||||
|
||||
def send_console_command(command):
|
||||
data = str({"SESSIONID":session_id, "message":command})
|
||||
requests.post(Paths.SEND_CONSOLE_COMMAND, headers=headers, data=data).json()
|
37
utils/checks.py
Normal file
37
utils/checks.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
from discord.ext import commands
|
||||
from utils.config import Config
|
||||
config = Config()
|
||||
|
||||
class admin_only(commands.CommandError):
|
||||
pass
|
||||
|
||||
class senior_admin_only(commands.CommandError):
|
||||
pass
|
||||
|
||||
class dev_only(commands.CommandError):
|
||||
pass
|
||||
|
||||
def is_dev():
|
||||
def predicate(ctx):
|
||||
for role in ctx.message.author.roles:
|
||||
if role.id == config.dev_role_id:
|
||||
return True
|
||||
else:
|
||||
raise dev_only
|
||||
return commands.check(predicate)
|
||||
|
||||
def is_admin():
|
||||
def predicate(ctx):
|
||||
for role in ctx.message.author.roles:
|
||||
if role.id in config.admin_role_ids or role.id == config.dev_role_id:
|
||||
return True
|
||||
raise admin_only
|
||||
return commands.check(predicate)
|
||||
|
||||
def is_senior_admin():
|
||||
def predicate(ctx):
|
||||
for role in ctx.message.author.roles:
|
||||
if role.id == config.senior_admin_role_id or role.id in config.admin_role_ids or role.id == config.dev_role_id:
|
||||
return True
|
||||
raise senior_admin_only
|
||||
return commands.check(predicate)
|
60
utils/config.py
Normal file
60
utils/config.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
import os
|
||||
import configparser
|
||||
|
||||
class Defaults:
|
||||
name = "a minecraft server"
|
||||
token = None
|
||||
command_prefix = "srv!"
|
||||
dev_role_id = None
|
||||
admin_role_ids = []
|
||||
senior_admin_role_id = None
|
||||
amp_username = None
|
||||
amp_password = None
|
||||
amp_panel_url = None
|
||||
|
||||
class Config:
|
||||
def __init__(self):
|
||||
|
||||
self.config_file = "config.ini"
|
||||
|
||||
config = configparser.ConfigParser(interpolation=None)
|
||||
config.read(self.config_file, encoding="utf-8")
|
||||
|
||||
sections = {"Bot", "AMP"}.difference(config.sections())
|
||||
if sections:
|
||||
print("Could not load a section in the config file, please obtain a new config file from the github repo")
|
||||
os._exit(1)
|
||||
self.name = config.get("Bot", "Name", fallback=Defaults.name)
|
||||
self._token = config.get("Bot", "Token", fallback=Defaults.token)
|
||||
self.command_prefix = config.get("Bot", "Command_Prefix", fallback=Defaults.command_prefix)
|
||||
self.dev_role_id = config.get("Bot", "Developer_Role_ID", fallback=Defaults.dev_role_id)
|
||||
self.admin_role_ids = config.get("Bot", "Admin_Role_IDs", fallback=Defaults.admin_role_ids)
|
||||
self.senior_admin_role_id = config.get("Bot", "Senior_Admin_Role_ID", fallback=Defaults.senior_admin_role_id)
|
||||
self.amp_username = config.get("AMP", "AMP_Username", fallback=Defaults.amp_username)
|
||||
self.amp_password = config.get("AMP", "AMP_Password", fallback=Defaults.amp_password)
|
||||
self.amp_panel_url = config.get("AMP", "URL", fallback=Defaults.amp_panel_url)
|
||||
|
||||
self.check()
|
||||
|
||||
def check(self):
|
||||
if not self._token:
|
||||
print("No token was specified in the config, please put your bot's token in the config.")
|
||||
os._exit(1)
|
||||
|
||||
if len(self.admin_role_ids) is not 0:
|
||||
try:
|
||||
self.admin_role_ids = list(self.admin_role_ids.split())
|
||||
except:
|
||||
self.admin_role_ids = Defaults.admin_role_ids
|
||||
|
||||
if not self.amp_username:
|
||||
print("No AMP username was specified in the config")
|
||||
os._exit(1)
|
||||
|
||||
if not self.amp_password:
|
||||
print("No AMP password was specified in the config")
|
||||
os._exit(1)
|
||||
|
||||
if not self.amp_panel_url:
|
||||
print("No AMP panel url was specified in the config")
|
||||
os._exit(1)
|
Loading…
Reference in a new issue