Initial commit
This commit is contained in:
commit
f6de717fec
5
.env.example
Normal file
5
.env.example
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export BIND_HOST=0.0.0.0
|
||||||
|
export BIND_PORT=25566
|
||||||
|
export MINECRAFT_RCON_HOST=localhost
|
||||||
|
# export MINECRAFT_RCON_PORT=255
|
||||||
|
export MINECRAFT_RCON_PASSWORD=secret
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__
|
||||||
|
*.env
|
8
makefile
Normal file
8
makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.PHONY: run
|
||||||
|
run: .env ; @./run.sh
|
||||||
|
.PHONY: init
|
||||||
|
init:
|
||||||
|
pip install -r requirements.txt
|
||||||
|
@cp .env.example .env
|
||||||
|
${EDITOR} .env
|
||||||
|
|
7
readme.md
Normal file
7
readme.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# TPUI
|
||||||
|
|
||||||
|
TPUI is a very small app that effectively gives Minecraft players the ability to
|
||||||
|
teleport in your server without needing mods or `/op`. It is currently only
|
||||||
|
suitable for semi-trustworthy situations, since any player can teleport any
|
||||||
|
other player, but is nice when you want to ensure nobody can perform other
|
||||||
|
cheats.
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
flask
|
||||||
|
mcrcon
|
4
run.sh
Executable file
4
run.sh
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
source "./.env"
|
||||||
|
env FLASK_APP=server.py python -m flask run --host="$BIND_HOST" --port="$BIND_PORT"
|
50
server.py
Normal file
50
server.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
from mcrcon import MCRcon
|
||||||
|
from flask import Flask, render_template, redirect, request
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# load from env vars
|
||||||
|
host = os.environ['RCON_HOST']
|
||||||
|
password = os.environ['RCON_PASSWORD']
|
||||||
|
port = int(os.environ.setdefault('RCON_PORT', '25575'))
|
||||||
|
print(f'Connecting to Minecraft Server: {host}:{port} with {password}')
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html', players=current_players_list())
|
||||||
|
|
||||||
|
@app.route('/tp', methods=['POST'])
|
||||||
|
def tp():
|
||||||
|
# TODO: sanitize inputs to avoid possible command injection
|
||||||
|
src = request.form['src']
|
||||||
|
dest = request.form['dest']
|
||||||
|
|
||||||
|
# this echoes a string that contains the src player's coordinates
|
||||||
|
src_coords = rcon_command(f"/tp {src} ~ ~ ~")
|
||||||
|
|
||||||
|
# teleport the player
|
||||||
|
rcon_command(f"/tp {src} {dest}")
|
||||||
|
|
||||||
|
# have the server report the old coordinates in case they need teleporting
|
||||||
|
# back
|
||||||
|
rcon_command(f"/say TP: {src_coords.replace(f'Teleported {src} to', f'{src} just teleported from', 1)} to {dest}".replace("[Rcon] ", ""))
|
||||||
|
|
||||||
|
return redirect('/')
|
||||||
|
|
||||||
|
def rcon_command(cmd):
|
||||||
|
print(f"RCON: Sending \"{cmd}\"...")
|
||||||
|
response = ""
|
||||||
|
with MCRcon(host, password, port) as mcr:
|
||||||
|
response = mcr.command(cmd)
|
||||||
|
print(f"RCON: \"{cmd}\" Response:\n\t{response}")
|
||||||
|
return response
|
||||||
|
|
||||||
|
def current_players_list():
|
||||||
|
# TODO: this breaks if a player has a comma in their name
|
||||||
|
# is that even possible?
|
||||||
|
plist = rcon_command(f"/list")
|
||||||
|
print(f'PLIST: {plist}')
|
||||||
|
print(f'PLIST: {plist.split(":")[1].split(", ")}')
|
||||||
|
return plist.split(":")[1].split(", ")
|
38
templates/index.html
Normal file
38
templates/index.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
Super Simple Minecraft RCON Teleporter
|
||||||
|
|
||||||
|
<form method="POST" action="/tp">
|
||||||
|
Teleport
|
||||||
|
<select name="src">
|
||||||
|
{% for p in players %}
|
||||||
|
<option>{{ p }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
to
|
||||||
|
<select name="dest">
|
||||||
|
{% for p in players %}
|
||||||
|
<option>{{ p }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="Go!"</input>
|
||||||
|
</form>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: #111;
|
||||||
|
color: #fff;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select, input, button {
|
||||||
|
background: #222;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
padding: 0.5em 0.8em;
|
||||||
|
border: solid 1px #888;
|
||||||
|
background:
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in a new issue