Communicating with Minetest Server Using APIs
I have been playing Minetest for a while now, mostly in creative mode. Recently I wanted to control it programmatically. So I started looking for ways to do it. I found mineysocket mod, which gives remote access to Minetest server over a network/socket API. There are wrappers available for various languages, including Python.
mineysocket (fork) - A network API mod for minetest. The goal of this mod is to open the minetest for other scripting languages.
For that, this mod opens a TCP network port where it receives lua snippets to execute these inside the minetest. That allows you to write a socket client in your favorite language to wrap API functions over the network/internet.
mineysocket ( fork of it)
To use mineysocket, you must install it as a mod and enable it. So instead of modifying my local server setup. I built a simple (crude, it needs to be optimized) docker image that I can run. It's not secure enough to run on a public network. So I am currently running it on my local network to experiment. Please send me changes to optimize it and secure it.
Table of Contents
Setup Docker
Here is the crude Dockerfile, that you can use to build the image and start the container. Currently, I am not installing the mineysocket module in it, but installing all the dependencies required to run it. You can create the folders locally to map to the container, so it becomes easy to change and experiment.
FROM ubuntu:20.04 as build
ENV TZ="Asia/Kolkata"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update && apt-get install tzdata -y
RUN apt-get install build-essential cmake wget libirrlicht-dev libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev lua-socket lua-cjson -y
RUN wget https://github.com/minetest/minetest/archive/refs/tags/5.6.1.tar.gz && tar xf 5.6.1.tar.gz && mv minetest-5.6.1 ./minetest && rm 5.6.1.tar.gz
RUN wget https://github.com/minetest/irrlicht/archive/master.tar.gz && tar xf master.tar.gz && mv irrlicht-master ./minetest/lib/irrlicht
WORKDIR /minetest
RUN cmake . -DRUN_IN_PLACE=TRUE -DBUILD_SERVER=TRUE -DBUILD_CLIENT=FALSE -DIRRLICHT_INCLUDE_DIR=./lib/irrlicht/include
RUN make -j $(nproc)
VOLUME /minetest/bin/debug.txt
VOLUME /minetest/minetest.conf
VOLUME /minetest/mods
VOLUME /minetest/games
VOLUME /minetest/worlds
EXPOSE 30000/udp
EXPOSE 29999
ENTRYPOINT ["/minetest/bin/minetestserver"]
CMD [""]
Save the above as a file with name Dockerfile
in a folder and build using docker or podman
podman build -t thejeshgn/minetest:latest .
Setup the docker volumes by creating folders inside your main folder called mintest_api_volume
mkdir games
mkdir worlds
mkdir mods
touch debug.txt
touch minetest.conf
Add default game
You need a default game to play. So let's setup a default game inside the games
folder
cd mintest_api_volume/games
wget wget https://github.com/minetest/minetest_game/archive/master.tar.gz
tar xf master.tar.gz
mv minetest_game-master minetest_game
rm master.tar.gz
Add mineysocket
We will need to add mineysocket to mods folder. We will do by cloning the folder directly under it
cd mintest_api_volume/mods
git clone https://github.com/esoadamo/mineysocket
Start Server and Create user
Launch the minetest docker server using the above built image and settings
podman run --name=minetest_api_container \
-p 30000:30000/udp \
-p 29999:29999 \
-e TZ=Asia/Kolkata \
-e CLI_ARGS="--gameid minetest --port 30000" \
-v /home/thej/mintest_api_volume/debug.txt:/minetest/debug.txt \
-v /home/thej/mintest_api_volume/minetest.conf:/minetest/minetest.conf \
-v /home/thej/mintest_api_volume/games:/minetest/games \
-v /home/thej/mintest_api_volume/mods:/minetest/mods \
-v /home/thej/mintest_api_volume/worlds:/minetest/worlds \
localhost/thejeshgn/minetest
Connect to it using the standard minetest client.
Server: localhost
Port: 30000
First, click on the register and register with a username and password. And then connect to it, to see if it works.
Change configuration
Update the mintest_api_volume
/minetest.conf
with the following details
name = thej
creative_mode = true
secure.trusted_mods = mineysocket
mineysocket.host_ip = 0.0.0.0
Update the mintest_api_volume/worlds/world/world.mt
and enable the mineysocket by adding
load_mod_mineysocket = true
and restart the docker server
podman restart minetest_api_container
mineysocket starts a server at port 29999 by default. You can change it if required. Hence if you look at our Dockerfile, port 29999 is exposed.
Connect using raw Sockets
import socket
import time
import os
import json
chunk_size = 4096
data_buffer: bytes = b""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", int(29999)))
s.send(b"ping\n")
reply = s.recv(4096).decode()
print(reply)
auth_message = {"playername": "thej", "password": "thej"}
raw_data: bytes = str.encode(json.dumps(auth_message) + "\n")
if len(raw_data) < chunk_size:
print("sending")
x = s.sendall(raw_data)
print(x)
print("Recv")
data_buffer = s.recv(4096)
print(data_buffer)
print("Sending")
data = {"lua": "return 12 + 2", "id":"myrandomstring12"}
raw_data: bytes = str.encode(json.dumps(data) + "\n")
x = s.sendall(raw_data)
print(x)
print("Recv")
data_buffer = s.recv(4096)
print(data_buffer)
First part just pings the Minetest server and the server returns pong as an output. In the second message I am trying to auth to the server. And it will result the response with auth_ok if evrything went well
b'{"result":["auth_ok","10.0.2.100:36494"],"id":"auth"}\n'
In the third call, I am sending some lua code to run on the server. It will run and respond back with the answer. In fact this is what we will use to execute various commands on the server.
b'{"result":["auth_ok","10.0.2.100:36494"],"id":"auth"}\n'
If you don't want to write raw JSON commands, then you can use a Python wrapper package called Miney. It makes working with mineysocket easy. We will do that in our next blog post.
Debug
if you face any issues you can look for logs inside your debug.txt
2 Responses
[…] Previous Post Communicating with Minetest Server Using APIs https://thejeshgn.com/2023/02/14/communicating-with-minetest-server-using-apis/ via @thej Posted on February 14, 2023 by @thej in […]
[…] with Minetest continues; I wrote a blog post about Communicating with Minetest Server Using APIs as a result. I want a simple Python API that I can share with my niece and nephew where they […]