Changed: Final
This commit is contained in:
parent
3e616132d4
commit
8b1b6fdd54
BIN
bot/assets/death.png
Normal file
BIN
bot/assets/death.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
bot/assets/end.png
Normal file
BIN
bot/assets/end.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
bot/assets/fight.png
Normal file
BIN
bot/assets/fight.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
bot/assets/init.png
Normal file
BIN
bot/assets/init.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
BIN
bot/assets/safe.png
Normal file
BIN
bot/assets/safe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
bot/bot.db
Normal file
BIN
bot/bot.db
Normal file
Binary file not shown.
@ -1,9 +1,11 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from mcrcon import MCRcon
|
|
||||||
import enum
|
import enum
|
||||||
from transitions import Machine
|
from transitions import Machine
|
||||||
from cogs.spawner import containers
|
from cogs.spawner import get_server
|
||||||
|
import utils
|
||||||
|
|
||||||
|
color = discord.Color.from_rgb(181, 24, 60)
|
||||||
|
|
||||||
class Whitelist:
|
class Whitelist:
|
||||||
"A workflow machine for managing Whitelist states"
|
"A workflow machine for managing Whitelist states"
|
||||||
@ -11,25 +13,6 @@ class Whitelist:
|
|||||||
Off = None
|
Off = None
|
||||||
toggle = None
|
toggle = None
|
||||||
|
|
||||||
class RCON(MCRcon):
|
|
||||||
def __init__(self, ip: str, secret: str, port: int = 31066):
|
|
||||||
super().__init__(ip, secret, port)
|
|
||||||
self.connect()
|
|
||||||
|
|
||||||
def whitelist(self):
|
|
||||||
self.whitelist.toggle()
|
|
||||||
cmds = "/whitelist {}".format(self.whitelist.current_state.id)
|
|
||||||
print(cmds)
|
|
||||||
|
|
||||||
def sendcmd(self, cmds) -> None:
|
|
||||||
if isinstance(cmds, str):
|
|
||||||
return self.command(str)
|
|
||||||
if isinstance(cmds, list):
|
|
||||||
return [self.command(cmd) for cmd in cmds]
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self.disconnect()
|
|
||||||
|
|
||||||
class States(enum.Enum):
|
class States(enum.Enum):
|
||||||
NOTHING = 0
|
NOTHING = 0
|
||||||
INIT = 1
|
INIT = 1
|
||||||
@ -41,7 +24,6 @@ class States(enum.Enum):
|
|||||||
class Minecraft(commands.Cog):
|
class Minecraft(commands.Cog):
|
||||||
def __init__(self, bot: commands.Bot):
|
def __init__(self, bot: commands.Bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.servers = dict()
|
|
||||||
|
|
||||||
transitions = [
|
transitions = [
|
||||||
['init_game', States.NOTHING, States.INIT],
|
['init_game', States.NOTHING, States.INIT],
|
||||||
@ -68,21 +50,12 @@ class Minecraft(commands.Cog):
|
|||||||
server_name: str
|
server_name: str
|
||||||
Server on which the Session should be initialized
|
Server on which the Session should be initialized
|
||||||
"""
|
"""
|
||||||
server_name = server_name.title()
|
c = get_server(server_name)
|
||||||
|
|
||||||
c = None
|
|
||||||
for container in containers:
|
|
||||||
if server_name == container.name:
|
|
||||||
c = container
|
|
||||||
break
|
|
||||||
|
|
||||||
if not c:
|
if not c:
|
||||||
await ctx.send("---The server doesn't run---")
|
await ctx.send("---The server doesn't run---")
|
||||||
return
|
return
|
||||||
|
|
||||||
conn = RCON(str(c.ip), c.rcon_pass, c.rcon_port)
|
|
||||||
self.servers[server_name] = conn
|
|
||||||
|
|
||||||
cmds = [
|
cmds = [
|
||||||
"/effect give @a minecraft:resistance infinite 255 true",
|
"/effect give @a minecraft:resistance infinite 255 true",
|
||||||
"/effect give @a minecraft:saturation infinite 4 true",
|
"/effect give @a minecraft:saturation infinite 4 true",
|
||||||
@ -92,9 +65,29 @@ class Minecraft(commands.Cog):
|
|||||||
"/worldborder set 5",
|
"/worldborder set 5",
|
||||||
"/whitelist off"
|
"/whitelist off"
|
||||||
]
|
]
|
||||||
|
c.rcon.rconnect()
|
||||||
|
c.rcon.sendcmd(cmds)
|
||||||
|
|
||||||
conn.sendcmd(cmds)
|
embed = discord.Embed(
|
||||||
await ctx.send("init Border Wars Game")
|
title=f"Border Wars @ {server_name.title()}",
|
||||||
|
description='''
|
||||||
|
Session initialized
|
||||||
|
Get ready to get a good armorset.
|
||||||
|
|
||||||
|
**Explanation**
|
||||||
|
This phase last as long as the moderator wants.
|
||||||
|
Every player is immune to damage and can't die by hunger.
|
||||||
|
Look out for a good direction to scout.
|
||||||
|
|
||||||
|
Happy Border Wars!
|
||||||
|
''',
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
file = discord.File("../assets/init.png", filename="init.png")
|
||||||
|
embed.set_thumbnail(url="attachment://init.png")
|
||||||
|
|
||||||
|
await ctx.send(file=file, embed=embed)
|
||||||
|
|
||||||
@commands.hybrid_command(name='safe')
|
@commands.hybrid_command(name='safe')
|
||||||
async def safe(self, ctx: commands.Context, server_name: str):
|
async def safe(self, ctx: commands.Context, server_name: str):
|
||||||
@ -108,25 +101,12 @@ class Minecraft(commands.Cog):
|
|||||||
server_name: str
|
server_name: str
|
||||||
Server on which the Session should be initialized
|
Server on which the Session should be initialized
|
||||||
"""
|
"""
|
||||||
server_name = server_name.title()
|
c = get_server(server_name)
|
||||||
|
|
||||||
c = None
|
|
||||||
for container in containers:
|
|
||||||
if server_name == container.name:
|
|
||||||
c = container
|
|
||||||
break
|
|
||||||
|
|
||||||
if not c:
|
if not c:
|
||||||
await ctx.send("---The server doesn't run---")
|
await ctx.send("---The server doesn't run---")
|
||||||
return
|
return
|
||||||
|
|
||||||
conn = self.servers.get(server_name)
|
|
||||||
|
|
||||||
if not conn:
|
|
||||||
await ctx.send("---Border Wars Session not Initialized---")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
cmds = [
|
cmds = [
|
||||||
'''/title @a subtitle ["",{"text":"bei ","color":"blue"},{"text":"BORDER WARS!","bold":true,"color":"red"}]''',
|
'''/title @a subtitle ["",{"text":"bei ","color":"blue"},{"text":"BORDER WARS!","bold":true,"color":"red"}]''',
|
||||||
'''/title @a title {"text":"Viel Glück!","bold":true,"color":"blue"}''',
|
'''/title @a title {"text":"Viel Glück!","bold":true,"color":"blue"}''',
|
||||||
@ -137,8 +117,28 @@ class Minecraft(commands.Cog):
|
|||||||
"/effect clear @a"
|
"/effect clear @a"
|
||||||
]
|
]
|
||||||
|
|
||||||
conn.sendcmd(cmds)
|
c.rcon.sendcmd(cmds)
|
||||||
await ctx.send("Switched to Safe Phase")
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"Border Wars @ {server_name.title()}",
|
||||||
|
description='''
|
||||||
|
Switched to Safe Phase
|
||||||
|
Hide from other players and scout for resources.
|
||||||
|
|
||||||
|
**Explanation**
|
||||||
|
This phase lasts 30 minutes, after that the fighting phase begins.
|
||||||
|
Every player who dies will keep there inventory.
|
||||||
|
Get a good armorset and be ready to fight.
|
||||||
|
|
||||||
|
Happy Border Wars!
|
||||||
|
''',
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
file = discord.File("../assets/safe.png", filename="safe.png")
|
||||||
|
embed.set_thumbnail(url="attachment://safe.png")
|
||||||
|
|
||||||
|
await ctx.send(file=file, embed=embed)
|
||||||
|
|
||||||
@commands.hybrid_command(name='fight')
|
@commands.hybrid_command(name='fight')
|
||||||
async def fight(self, ctx: commands.Context, server_name: str):
|
async def fight(self, ctx: commands.Context, server_name: str):
|
||||||
@ -152,25 +152,12 @@ class Minecraft(commands.Cog):
|
|||||||
server_name: str
|
server_name: str
|
||||||
Server on which the Session should be initialized
|
Server on which the Session should be initialized
|
||||||
"""
|
"""
|
||||||
server_name = server_name.title()
|
c = get_server(server_name)
|
||||||
|
|
||||||
c = None
|
|
||||||
for container in containers:
|
|
||||||
if server_name == container.name:
|
|
||||||
c = container
|
|
||||||
break
|
|
||||||
|
|
||||||
if not c:
|
if not c:
|
||||||
await ctx.send("---The server doesn't run---")
|
await ctx.send("---The server doesn't run---")
|
||||||
return
|
return
|
||||||
|
|
||||||
conn = self.servers.get(server_name)
|
|
||||||
|
|
||||||
if not conn:
|
|
||||||
await ctx.send("---Border Wars Session not Initialized---")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
cmds = [
|
cmds = [
|
||||||
'''/title @a subtitle {"text":"ÜBERLEBEN!","bold":true,"color":"red"}''',
|
'''/title @a subtitle {"text":"ÜBERLEBEN!","bold":true,"color":"red"}''',
|
||||||
'''/title @a title {"text":"Möge der beste","color":"blue"}''',
|
'''/title @a title {"text":"Möge der beste","color":"blue"}''',
|
||||||
@ -179,8 +166,28 @@ class Minecraft(commands.Cog):
|
|||||||
"/gamerule keepInventory false"
|
"/gamerule keepInventory false"
|
||||||
]
|
]
|
||||||
|
|
||||||
conn.sendcmd(cmds)
|
c.rcon.sendcmd(cmds)
|
||||||
await ctx.send("Switched to Fight Phase")
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"Border Wars @ {server_name.title()}",
|
||||||
|
description='''
|
||||||
|
Switched to Fight Phase
|
||||||
|
Now the real fun begins.
|
||||||
|
|
||||||
|
**Explanation**
|
||||||
|
This phase lasts 60 minutes, after that the game ends.
|
||||||
|
Every player can die now and therefor will lose.
|
||||||
|
Look out for other players.
|
||||||
|
|
||||||
|
Happy Border Wars!
|
||||||
|
''',
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
file = discord.File("../assets/fight.png", filename="fight.png")
|
||||||
|
embed.set_thumbnail(url="attachment://fight.png")
|
||||||
|
|
||||||
|
await ctx.send(file=file, embed=embed)
|
||||||
|
|
||||||
@commands.hybrid_command(name='death')
|
@commands.hybrid_command(name='death')
|
||||||
async def death(self, ctx: commands.Context, server_name: str):
|
async def death(self, ctx: commands.Context, server_name: str):
|
||||||
@ -194,33 +201,40 @@ class Minecraft(commands.Cog):
|
|||||||
server_name: str
|
server_name: str
|
||||||
Server on which the Session should be initialized
|
Server on which the Session should be initialized
|
||||||
"""
|
"""
|
||||||
server_name = server_name.title()
|
c = get_server(server_name)
|
||||||
|
|
||||||
c = None
|
|
||||||
for container in containers:
|
|
||||||
if server_name == container.name:
|
|
||||||
c = container
|
|
||||||
break
|
|
||||||
|
|
||||||
if not c:
|
if not c:
|
||||||
await ctx.send("---The server doesn't run---")
|
await ctx.send("---The server doesn't run---")
|
||||||
return
|
return
|
||||||
|
|
||||||
conn = self.servers.get(server_name)
|
|
||||||
|
|
||||||
if not conn:
|
|
||||||
await ctx.send("---Border Wars Session not Initialized---")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
cmds = [
|
cmds = [
|
||||||
'''/title @a title ["",{"text":"Sudden ","color":"dark_blue"},{"text":"DEATH!","bold":true,"color":"red"}]''',
|
'''/title @a title ["",{"text":"Sudden ","color":"dark_blue"},{"text":"DEATH!","bold":true,"color":"red"}]''',
|
||||||
"/playsound minecraft:entity.ender_dragon.growl ambient @a 0 64 0 80",
|
"/playsound minecraft:entity.ender_dragon.growl ambient @a 0 64 0 80",
|
||||||
"/worldborder set 5 600"
|
"/worldborder set 5 600"
|
||||||
]
|
]
|
||||||
|
|
||||||
conn.sendcmd(cmds)
|
c.rcon.sendcmd(cmds)
|
||||||
await ctx.send("Switched to Sudden Death Phase")
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"Border Wars @ {server_name.title()}",
|
||||||
|
description='''
|
||||||
|
Switched to Sudden Death
|
||||||
|
Only one can be the Winner.
|
||||||
|
|
||||||
|
**Explanation**
|
||||||
|
This phase lasts as long as only one player survives.
|
||||||
|
The worldborder will now shrink 'till zero zero.
|
||||||
|
Good Luck.
|
||||||
|
|
||||||
|
Happy Border Wars!
|
||||||
|
''',
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
file = discord.File("../assets/death.png", filename="death.png")
|
||||||
|
embed.set_thumbnail(url="attachment://death.png")
|
||||||
|
|
||||||
|
await ctx.send(file=file, embed=embed)
|
||||||
|
|
||||||
@commands.hybrid_command(name='end')
|
@commands.hybrid_command(name='end')
|
||||||
async def end(self, ctx: commands.Context, server_name: str, playername: str):
|
async def end(self, ctx: commands.Context, server_name: str, playername: str):
|
||||||
@ -236,25 +250,12 @@ class Minecraft(commands.Cog):
|
|||||||
playername: str
|
playername: str
|
||||||
Player which is announced as the Winner
|
Player which is announced as the Winner
|
||||||
"""
|
"""
|
||||||
server_name = server_name.title()
|
c = get_server(server_name)
|
||||||
|
|
||||||
c = None
|
|
||||||
for container in containers:
|
|
||||||
if server_name == container.name:
|
|
||||||
c = container
|
|
||||||
break
|
|
||||||
|
|
||||||
if not c:
|
if not c:
|
||||||
await ctx.send("---The server doesn't run---")
|
await ctx.send("---The server doesn't run---")
|
||||||
return
|
return
|
||||||
|
|
||||||
conn = self.servers.get(server_name)
|
|
||||||
|
|
||||||
if not conn:
|
|
||||||
await ctx.send("---Border Wars Session not Initialized---")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
cmds = [
|
cmds = [
|
||||||
"/worldborder center 0 0",
|
"/worldborder center 0 0",
|
||||||
"/worldborder set 75",
|
"/worldborder set 75",
|
||||||
@ -264,8 +265,20 @@ class Minecraft(commands.Cog):
|
|||||||
"/playsound minecraft:entity.ender_dragon_death ambient @a 0 64 0 80",
|
"/playsound minecraft:entity.ender_dragon_death ambient @a 0 64 0 80",
|
||||||
]
|
]
|
||||||
|
|
||||||
conn.sendcmd(cmds)
|
c.rcon.sendcmd(cmds)
|
||||||
await ctx.send("Ended Border Wars Session")
|
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"Border Wars @ {server_name.title()}",
|
||||||
|
description=f'''
|
||||||
|
*Game Over*
|
||||||
|
Congratulations **{playername}**.
|
||||||
|
|
||||||
|
Hope you had fun @ **Border Wars!**
|
||||||
|
''',
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
file = discord.File("../assets/end.png", filename="end.png")
|
||||||
|
embed.set_thumbnail(url="attachment://end.png")
|
||||||
|
|
||||||
|
await ctx.send(file=file, embed=embed)
|
||||||
|
@ -4,35 +4,65 @@ import docker
|
|||||||
import random
|
import random
|
||||||
import socket
|
import socket
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from datetime import datetime
|
|
||||||
import pytz
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from ipaddress import IPv4Address
|
from ipaddress import IPv4Address
|
||||||
import secrets
|
import secrets
|
||||||
|
from mcrcon import MCRcon
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from models.users import *
|
||||||
|
import utils
|
||||||
|
|
||||||
|
class RCON(MCRcon):
|
||||||
|
def __init__(self, ip: str, secret: str, port: int):
|
||||||
|
super().__init__(ip, secret, port)
|
||||||
|
|
||||||
|
def rconnect(self):
|
||||||
|
self.connect()
|
||||||
|
|
||||||
|
def whitelist(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def sendcmd(self, cmds) -> None:
|
||||||
|
if isinstance(cmds, str):
|
||||||
|
return self.command(str)
|
||||||
|
if isinstance(cmds, list):
|
||||||
|
return [self.command(cmd) for cmd in cmds]
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Server:
|
class Server:
|
||||||
container: None
|
container: None
|
||||||
name: str
|
name: str
|
||||||
ip: IPv4Address
|
rcon: RCON
|
||||||
port: int
|
port: int
|
||||||
players: int
|
players: int
|
||||||
rcon_pass: str
|
|
||||||
rcon_port: int
|
|
||||||
|
|
||||||
# Global List of all running Containers
|
# Global List of all running Containers
|
||||||
containers = list()
|
containers = list()
|
||||||
|
def get_server(name):
|
||||||
|
name = name.title()
|
||||||
|
for container in containers:
|
||||||
|
if container.name == name:
|
||||||
|
return container
|
||||||
|
return None
|
||||||
|
|
||||||
color = discord.Color.from_rgb(13, 183, 237)
|
color = discord.Color.from_rgb(13, 183, 237)
|
||||||
|
|
||||||
def seed_generator():
|
def seed_generator():
|
||||||
|
'''
|
||||||
|
Generates a random minecraft seed
|
||||||
|
'''
|
||||||
seed = random.randrange(1_000_000_000, 100_000_000_000_000)
|
seed = random.randrange(1_000_000_000, 100_000_000_000_000)
|
||||||
if random.randrange(0,2) == 0:
|
if random.randrange(0,2) == 0:
|
||||||
seed *= -1
|
seed *= -1
|
||||||
return str(seed)
|
return str(seed)
|
||||||
|
|
||||||
def find_free_port():
|
def find_free_port():
|
||||||
|
'''
|
||||||
|
Returns the next available IPv4 Port
|
||||||
|
'''
|
||||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||||
s.bind(('', 0))
|
s.bind(('', 0))
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
@ -75,6 +105,13 @@ class Spawner(commands.Cog):
|
|||||||
enable_hardcore: bool
|
enable_hardcore: bool
|
||||||
Enables Hardcore Minecraft
|
Enables Hardcore Minecraft
|
||||||
'''
|
'''
|
||||||
|
try:
|
||||||
|
User.get(User.username == ctx.author.id)
|
||||||
|
except:
|
||||||
|
await ctx.send(f"{ctx.author.name} isn't registered!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Send user a Waiting screen to avoid confusion
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Starting Server",
|
title="Starting Server",
|
||||||
description=f'''
|
description=f'''
|
||||||
@ -83,17 +120,21 @@ class Spawner(commands.Cog):
|
|||||||
This could take up to **5 minutes**
|
This could take up to **5 minutes**
|
||||||
''',
|
''',
|
||||||
color=color,
|
color=color,
|
||||||
timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
|
timestamp=utils.now()
|
||||||
)
|
)
|
||||||
file = discord.File("../assets/clock.png", filename="clock.png")
|
file = discord.File("../assets/clock.png", filename="clock.png")
|
||||||
embed.set_thumbnail(url="attachment://clock.png")
|
embed.set_thumbnail(url="attachment://clock.png")
|
||||||
start = await ctx.send(file=file, embed=embed)
|
start = await ctx.send(file=file, embed=embed)
|
||||||
|
|
||||||
|
# Set up needed variables
|
||||||
|
# Server Stuff
|
||||||
port = find_free_port()
|
port = find_free_port()
|
||||||
server_name = server_name.title()
|
server_name = server_name.title()
|
||||||
|
# Rcon Stuff
|
||||||
passwd = secrets.token_hex(32)
|
passwd = secrets.token_hex(32)
|
||||||
rcon_port = find_free_port()
|
rcon_port = find_free_port()
|
||||||
|
|
||||||
|
# Image Enviroment
|
||||||
env = {
|
env = {
|
||||||
"EULA": "true",
|
"EULA": "true",
|
||||||
"TYPE": "FABRIC",
|
"TYPE": "FABRIC",
|
||||||
@ -120,7 +161,6 @@ class Spawner(commands.Cog):
|
|||||||
"MAX_MEMORY": "2G",
|
"MAX_MEMORY": "2G",
|
||||||
"USE_AIKAR_FLAGS": "true",
|
"USE_AIKAR_FLAGS": "true",
|
||||||
|
|
||||||
#"MODS_FILE": "/extras/mods.txt",
|
|
||||||
"OPS_FILE": "https://git.cyperpunk.de/Garde-Studios/Uno-MC/raw/branch/main/ops.json",
|
"OPS_FILE": "https://git.cyperpunk.de/Garde-Studios/Uno-MC/raw/branch/main/ops.json",
|
||||||
"SYNC_SKIP_NEWER_IN_DESTINATION": "false",
|
"SYNC_SKIP_NEWER_IN_DESTINATION": "false",
|
||||||
"MAX_PLAYERS": max_players,
|
"MAX_PLAYERS": max_players,
|
||||||
@ -138,6 +178,7 @@ class Spawner(commands.Cog):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Decide between seed or world url if no ones given seed would be randomly generated
|
||||||
if not seed and not world_url:
|
if not seed and not world_url:
|
||||||
seed = seed_generator()
|
seed = seed_generator()
|
||||||
if seed:
|
if seed:
|
||||||
@ -145,6 +186,7 @@ class Spawner(commands.Cog):
|
|||||||
if world_url:
|
if world_url:
|
||||||
env["WORLD"] = world_url
|
env["WORLD"] = world_url
|
||||||
|
|
||||||
|
# setting up the container
|
||||||
container = self.client.containers.run(
|
container = self.client.containers.run(
|
||||||
image='itzg/minecraft-server:latest',
|
image='itzg/minecraft-server:latest',
|
||||||
environment=env,
|
environment=env,
|
||||||
@ -157,14 +199,18 @@ class Spawner(commands.Cog):
|
|||||||
volumes={'mods.txt': {'bind': '/extras/mods.txt', 'mode': 'ro'}}
|
volumes={'mods.txt': {'bind': '/extras/mods.txt', 'mode': 'ro'}}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Connect Container to the appropiate network
|
||||||
net = self.client.networks.get('bot_rcon')
|
net = self.client.networks.get('bot_rcon')
|
||||||
net.connect(container)
|
net.connect(container)
|
||||||
|
|
||||||
|
# save container info
|
||||||
ip = self.client.containers.get(server_name).attrs['NetworkSettings']['Networks']['bot_rcon']['IPAddress']
|
ip = self.client.containers.get(server_name).attrs['NetworkSettings']['Networks']['bot_rcon']['IPAddress']
|
||||||
server = Server(container, server_name, IPv4Address(ip), port, max_players, passwd, rcon_port)
|
rcon = RCON(ip, passwd, rcon_port)
|
||||||
|
server = Server(container, server_name, rcon, port, max_players)
|
||||||
|
|
||||||
containers.append(server)
|
containers.append(server)
|
||||||
|
|
||||||
|
# Send user the confirmation
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Success",
|
title="Success",
|
||||||
description=f'''
|
description=f'''
|
||||||
@ -174,7 +220,7 @@ class Spawner(commands.Cog):
|
|||||||
garde-studios.de:{port}
|
garde-studios.de:{port}
|
||||||
''',
|
''',
|
||||||
color=color,
|
color=color,
|
||||||
timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
|
timestamp=utils.now()
|
||||||
)
|
)
|
||||||
file = discord.File("../assets/docker.png", filename="docker.png")
|
file = discord.File("../assets/docker.png", filename="docker.png")
|
||||||
embed.set_thumbnail(url="attachment://docker.png")
|
embed.set_thumbnail(url="attachment://docker.png")
|
||||||
@ -191,12 +237,17 @@ class Spawner(commands.Cog):
|
|||||||
ctx: commands.Context
|
ctx: commands.Context
|
||||||
The context of the command invocation
|
The context of the command invocation
|
||||||
'''
|
'''
|
||||||
|
try:
|
||||||
|
User.get(User.username == ctx.author.id)
|
||||||
|
except:
|
||||||
|
await ctx.send(f"{ctx.author.name} isn't registered!")
|
||||||
|
return
|
||||||
|
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Currently Running Servers",
|
title="Currently Running Servers",
|
||||||
description="List of all currently running Minecraft Servers",
|
description="List of all currently running Minecraft Servers",
|
||||||
color=color,
|
color=color,
|
||||||
timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
|
timestamp=utils.now()
|
||||||
)
|
)
|
||||||
|
|
||||||
for container in containers:
|
for container in containers:
|
||||||
@ -223,6 +274,11 @@ class Spawner(commands.Cog):
|
|||||||
server_name: str
|
server_name: str
|
||||||
Name of the server that should be removed
|
Name of the server that should be removed
|
||||||
'''
|
'''
|
||||||
|
try:
|
||||||
|
User.get(User.username == ctx.author.id)
|
||||||
|
except:
|
||||||
|
await ctx.send(f"{ctx.author.name} isn't registered!")
|
||||||
|
return
|
||||||
|
|
||||||
server_name = server_name.title()
|
server_name = server_name.title()
|
||||||
|
|
||||||
@ -247,7 +303,7 @@ class Spawner(commands.Cog):
|
|||||||
title="Killed",
|
title="Killed",
|
||||||
description=f"{server_name} killed!",
|
description=f"{server_name} killed!",
|
||||||
color=color,
|
color=color,
|
||||||
timestamp=datetime.now(pytz.timezone('Europe/Berlin'))
|
timestamp=utils.now()
|
||||||
)
|
)
|
||||||
|
|
||||||
file = discord.File("../assets/rip.png", filename="rip.png")
|
file = discord.File("../assets/rip.png", filename="rip.png")
|
||||||
|
@ -1,12 +1,165 @@
|
|||||||
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from sqlalchemy import create_engine
|
from models.users import *
|
||||||
from sqlalchemy.orm import DeclarativeBase
|
from mojang import API
|
||||||
|
import utils
|
||||||
|
|
||||||
#engine = create_engine("sqlite://user.sqlite", echo=True)
|
color = discord.Color.from_rgb(79, 227, 119)
|
||||||
#connection = engine.connect()
|
|
||||||
|
|
||||||
class User(DeclarativeBase):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class UserManager(commands.Cog):
|
class UserManager(commands.Cog):
|
||||||
pass
|
def __init__(self, bot: commands.Bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def gen_user_info(self, user_name: str, user_id: int):
|
||||||
|
'''
|
||||||
|
Generates user output Embed
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
user_name: str
|
||||||
|
given user name
|
||||||
|
user_id: int
|
||||||
|
discord user id to access database info
|
||||||
|
'''
|
||||||
|
user = User.get(User.username == user_id)
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=user_name if not user.is_admin else f'{user_name} (Admin)',
|
||||||
|
description=f'''
|
||||||
|
Name: {user.mc_name}
|
||||||
|
UUID: {user.mc_uuid}
|
||||||
|
Registered since {user.registration_date.strftime("%d.%m.%Y, %H:%M:%S")}
|
||||||
|
''',
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
return embed
|
||||||
|
|
||||||
|
@commands.hybrid_command(name='info')
|
||||||
|
async def info(self, ctx: commands.Context):
|
||||||
|
'''
|
||||||
|
Registers Users to internal Database
|
||||||
|
and links there minecraft username to there discord account.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx: commands.Context
|
||||||
|
The context of the command invocation
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
user = User.get(User.username == ctx.author.id)
|
||||||
|
await ctx.send(embed=self.gen_user_info(ctx.author.name, ctx.author.id))
|
||||||
|
except:
|
||||||
|
await ctx.send(f"{ctx.author.name} isn't registered")
|
||||||
|
|
||||||
|
@commands.hybrid_command(name='register')
|
||||||
|
async def register(self, ctx: commands.Context, minecraft_name: str):
|
||||||
|
'''
|
||||||
|
Registers Users to internal Database
|
||||||
|
and links there minecraft username to there discord account.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx: commands.Context
|
||||||
|
The context of the command invocation
|
||||||
|
minecraft_name: str
|
||||||
|
The minecraft user name to link with
|
||||||
|
'''
|
||||||
|
# Get minecraft uuid
|
||||||
|
api = API()
|
||||||
|
uuid = api.get_uuid(minecraft_name)
|
||||||
|
if not uuid:
|
||||||
|
await ctx.send("Username doesn't exist")
|
||||||
|
return
|
||||||
|
|
||||||
|
# build user
|
||||||
|
try:
|
||||||
|
user = User(
|
||||||
|
username=ctx.author.id,
|
||||||
|
mc_name=minecraft_name,
|
||||||
|
mc_uuid=uuid,
|
||||||
|
is_admin=False if not ctx.author.id == 418848241036165160 else True
|
||||||
|
)
|
||||||
|
user.save()
|
||||||
|
except IntegrityError:
|
||||||
|
await ctx.send("You're already registered")
|
||||||
|
return
|
||||||
|
|
||||||
|
await ctx.send(embed=self.gen_user_info(ctx.author.name, ctx.author.id))
|
||||||
|
|
||||||
|
@commands.hybrid_command(name='delete')
|
||||||
|
async def delete(self, ctx: commands.Context):
|
||||||
|
'''
|
||||||
|
Registers Users to internal Database
|
||||||
|
and links there minecraft username to there discord account.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx: commands.Context
|
||||||
|
The context of the command invocation
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
user = User.get(User.username == ctx.author.id)
|
||||||
|
user.delete_instance()
|
||||||
|
await ctx.send(f"Purged {ctx.author.name} from database!")
|
||||||
|
except:
|
||||||
|
await ctx.send(f"{ctx.author.name} isn't registered!")
|
||||||
|
|
||||||
|
@commands.hybrid_command(name='op')
|
||||||
|
async def op(self, ctx: commands.Context, member: discord.Member):
|
||||||
|
'''
|
||||||
|
Toggels if User is an Admin
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx: commands.Context
|
||||||
|
The context of the command invocation
|
||||||
|
'''
|
||||||
|
user = User.get(User.username == ctx.author.id)
|
||||||
|
if not user.is_admin:
|
||||||
|
await ctx.send("You're not allowed to use this command")
|
||||||
|
return
|
||||||
|
|
||||||
|
if member.id == 418848241036165160:
|
||||||
|
await ctx.send(f"{member.name} is always an admin")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = User.get(User.username == member.id)
|
||||||
|
user.is_admin = not user.is_admin
|
||||||
|
user.save()
|
||||||
|
await ctx.send(embed=self.gen_user_info(member.name, member.id))
|
||||||
|
|
||||||
|
|
||||||
|
@commands.hybrid_command(name='all')
|
||||||
|
async def all(self, ctx: commands.Context):
|
||||||
|
'''
|
||||||
|
Returns User info
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
ctx: commands.Context
|
||||||
|
The context of the command invocation
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
user = User.get(User.username == ctx.author.id)
|
||||||
|
if not user.is_admin:
|
||||||
|
await ctx.send("You're not allowed to use this command")
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
await ctx.send(f"{ctx.author.name} isn't registered")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="All Users",
|
||||||
|
description="Registered Users in Database",
|
||||||
|
color=color,
|
||||||
|
timestamp=utils.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
rows = User.select()
|
||||||
|
for row in rows:
|
||||||
|
member = await ctx.guild.fetch_member(row.username)
|
||||||
|
member = member if not row.is_admin else f'{member} (Admin)'
|
||||||
|
reg_date = row.registration_date.strftime("%d.%m.%Y, %H:%M:%S")
|
||||||
|
embed.add_field(name=member, value="{}\n{}\n{}\n".format(row.mc_name, row.mc_uuid, reg_date))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
10
bot/models/base.py
Normal file
10
bot/models/base.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from peewee import *
|
||||||
|
from playhouse.postgres_ext import *
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
db = SqliteDatabase('bot.db')
|
||||||
|
|
||||||
|
class BaseModel(Model):
|
||||||
|
class Meta:
|
||||||
|
database = db
|
13
bot/models/containers.py
Normal file
13
bot/models/containers.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from peewee import *
|
||||||
|
from models.base import BaseModel
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class Container(BaseModel):
|
||||||
|
# Container
|
||||||
|
name =
|
||||||
|
# players =
|
||||||
|
port =
|
||||||
|
|
||||||
|
# RCON
|
||||||
|
rcon_port =
|
||||||
|
rcon_pwd =
|
12
bot/models/users.py
Normal file
12
bot/models/users.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from peewee import *
|
||||||
|
from models.base import BaseModel
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class User(BaseModel):
|
||||||
|
username = CharField(unique=True)
|
||||||
|
mc_name = CharField(unique=True)
|
||||||
|
mc_uuid = CharField(unique=True)
|
||||||
|
is_admin = BooleanField(default=False)
|
||||||
|
registration_date = DateTimeField(default=datetime.datetime.now())
|
||||||
|
|
||||||
|
User.create_table()
|
@ -11,13 +11,18 @@ docker==7.1.0
|
|||||||
frozenlist==1.4.1
|
frozenlist==1.4.1
|
||||||
greenlet==3.1.1
|
greenlet==3.1.1
|
||||||
idna==3.10
|
idna==3.10
|
||||||
|
Jinja2==3.1.4
|
||||||
|
MarkupSafe==3.0.1
|
||||||
mcrcon==0.7.0
|
mcrcon==0.7.0
|
||||||
|
mojang==1.1.0
|
||||||
multidict==6.1.0
|
multidict==6.1.0
|
||||||
|
peewee==3.17.7
|
||||||
|
psycopg2-binary==2.9.9
|
||||||
|
Pygments==2.18.0
|
||||||
python-dotenv==1.0.1
|
python-dotenv==1.0.1
|
||||||
pytz==2024.2
|
pytz==2024.2
|
||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
SQLAlchemy==2.0.35
|
|
||||||
transitions==0.9.2
|
transitions==0.9.2
|
||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
urllib3==2.2.3
|
urllib3==2.2.3
|
||||||
|
7
bot/utils.py
Normal file
7
bot/utils.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import datetime
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
now = lambda: datetime.datetime.now(pytz.timezone('Europe/Berlin'))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(now())
|
Loading…
Reference in New Issue
Block a user