luanti-network-api-client/miney/helper.py
2024-12-07 01:17:53 +03:00

132 lines
4.8 KiB
Python

import socket
import time
import os
import platform
import subprocess
import webbrowser
import miney
def is_miney_available(ip: str = "127.0.0.1", port: int = 29999, timeout: int = 1.0) -> bool:
"""
Check if there is a running miney game available on an optional given host and/or port.
This functions pings mineysocket and waits **timeout** seconds for a pong.
:param ip: Optional IP or hostname
:param port: Optional port
:param timeout: Optional timeout
:return: True or False
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
s.connect((ip, int(port)))
s.send(b"ping\n")
reply = s.recv(4096).decode()
if reply == "pong\n":
return True
else:
return False
except (socket.timeout, ConnectionResetError, ConnectionRefusedError):
return False
finally:
s.close()
def run_miney_game():
"""
Run minetest with the miney world. Miney will look for the minetest executable in common places for itself,
but it's also possible to provide the path as parameter or as environment variable :envvar:`MINETEST_BIN`.
:return: None
"""
if is_miney_available():
raise miney.MinetestRunError("A miney game is already running")
else:
run_minetest(show_menu=False)
wait = 0
while wait < 12:
time.sleep(1)
available = is_miney_available()
if available:
time.sleep(2) # some extra time to get everything initialized
return True
wait = wait + 1
raise miney.MinetestRunError("Timeout while waiting for minetest with an open mineysocket")
def run_minetest(
minetest_path: str = None,
show_menu: bool = True,
world_path: str = "Miney",
seed: str = "746036489947438842"
) -> None:
"""
Run minetest. Miney will look for the minetest executable in common places for itself,
but it's also possible to provide the path as parameter or as environment variable 'MINETEST_BIN'.
:param minetest_path: Path to the minetest executable
:param show_menu: Start in the world or in the menu
:param world_path: Optional world path
:param seed: Optional world seed
:return: None
"""
if not minetest_path:
if os.environ.get('MINETEST_BIN') and os.path.isfile(os.environ.get('MINETEST_BIN')):
minetest_path = os.environ['MINETEST_BIN']
else:
if platform.system() == 'Windows':
exe_name = "minetest.exe"
else:
exe_name = "minetest"
# we have to guess the path
possible_paths = [
os.path.join(os.getcwd(), "Minetest", "bin"),
]
for p in possible_paths:
path = os.path.join(p, exe_name)
if os.path.isfile(path):
minetest_path = os.path.join(p, exe_name)
break
else:
raise miney.MinetestRunError("Minetest was not found")
if world_path == "Miney":
world_path = os.path.abspath(os.path.join(minetest_path, "..", "..", "worlds", "miney"))
if not os.path.isdir(world_path): # We have to create the default world
if not os.path.isdir(os.path.abspath(os.path.join(world_path, "..", "..", "worlds"))):
os.mkdir(os.path.abspath(os.path.join(world_path, "..", "..", "worlds")))
os.mkdir(world_path)
with open(os.path.join(world_path, "world.mt"), "w") as world_config_file:
world_config_file.write(
"enable_damage = true\ncreative_mode = false\ngameid = minetest\nplayer_backend = sqlite3\n"
"backend = sqlite3\nauth_backend = sqlite3\nload_mod_mineysocket = true\nserver_announce = false\n"
)
with open(os.path.join(world_path, "map_meta.txt"), "w") as world_meta_file:
world_meta_file.write(f"seed = {seed}")
if not os.path.isdir(os.path.abspath(os.path.join(minetest_path, "..", "..", "mods", "mineysocket"))):
raise miney.MinetestRunError("Mineysocket mod is not installed")
# todo: run_minetest - implementation for linux/macos
if show_menu:
subprocess.Popen(
f"{minetest_path} "
f"--world \"{world_path}\" --name {miney.default_playername} --address \"\""
)
else:
subprocess.Popen(
f"{minetest_path} "
f"--go --world \"{world_path}\" --name {miney.default_playername} --address \"\""
)
def doc() -> None:
"""
Open the documention in the webbrower. This is just a shortcut for IDLE or the python interactive console.
:return: None
"""
webbrowser.open("https://miney.readthedocs.io/en/latest/")