From b9ae094c24e4d3e0efbe1cc4ec1f04d89b852225 Mon Sep 17 00:00:00 2001 From: Alvarito050506 Date: Fri, 28 Aug 2020 16:41:31 -0300 Subject: [PATCH] Big updates! --- .gitignore | 4 ++ .gitmodules | 12 ++++ README.md | 47 +++++------- build.py | 7 +- build/minecraft/minecraft-pi.sh | 2 + example.mcpi | Bin 813 -> 0 bytes example.py | 50 ------------- libmcpi | 1 + mcpi-central | 1 + modpi | 1 + proxy | 1 + src/api/mcpil/__init__.py | 41 ----------- src/api/setup.py | 47 ------------ src/install.py | 42 +++++------ src/mcpil.py | 20 +++--- src/mcpim.py | 4 +- src/mcpip.py | 122 -------------------------------- 17 files changed, 80 insertions(+), 322 deletions(-) create mode 100644 .gitmodules delete mode 100644 example.mcpi delete mode 100755 example.py create mode 160000 libmcpi create mode 160000 mcpi-central create mode 160000 modpi create mode 160000 proxy delete mode 100644 src/api/mcpil/__init__.py delete mode 100644 src/api/setup.py delete mode 100755 src/mcpip.py diff --git a/.gitignore b/.gitignore index 5dc933e..afbc933 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ # Builds *.pyc +*.so + +# Python stuff +__pycache__/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d2ff656 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "libmcpi"] + path = libmcpi + url = https://github.com/MCPI-Devs/libmcpi +[submodule "mcpi-central"] + path = mcpi-central + url = https://github.com/MCPI-Devs/mcpi-central +[submodule "modpi"] + path = modpi + url = https://github.com/MCPI-Devs/modpi +[submodule "proxy"] + path = proxy + url = https://github.com/MCPI-Devs/proxy diff --git a/README.md b/README.md index d774ee0..6358e4a 100644 --- a/README.md +++ b/README.md @@ -7,32 +7,32 @@ A simple launcher for Minecraft: Pi Edition. ## Getting started ### Prerequisites -To use MCPIL you need to have Python 3.7 pre-installed. +To use MCPIL you need to have `Python >= 3.7.x` pre-installed. ### Installation To install MCPIL, download or clone the repository and run the `build.py` file in the root of the repo: ```shell -git clone https://github.com/MCPI-Devs/MCPIL.git -cd ./MCPIL/ -python3.7 ./build.py +git clone --recurse-submodules https://github.com/MCPI-Devs/MCPIL.git +cd MCPIL +python3 ./build.py ``` It will generate a `install.pyc` file under the `build` directory, run it: ```shell -cd ./build/ -python3.7 ./install.pyc +cd build +python3 ./install.pyc ``` It will "install" MCPI and MCPE, and configure the Launcher. ## Features -+ Switch between Minecraft Pi and PE -+ Username changing -+ Skin changing -+ Mod loading -+ Mod API -+ Mod compilation -+ World setting (game mode and name) changing -+ Join non-local servers -+ Coming soon: More stuff + + Switch between Minecraft Pi and PE + + Username changing + + Skin changing + + Mod loading + + Mod API + + Mod compilation + + World setting (game mode and name) changing + + Join non-local servers + + Coming soon: More stuff ## Usage Launch the MCPIL desktop file or run the `mcpil.pyc` file in the `build` folder as following to see the magic! :wink: @@ -41,25 +41,14 @@ python3.7 ./mcpil.pyc ``` ## API -**Warning**: The API will be refactored in the next release. +The API documentation was moved to the [ModPi repo](https://github.com/MCPI-Devs/modpi). -There is an MCPIL API that you can use by importing the `mcpil` module into your Python mod. It exposes the following functions: - -### `def get_user_name()` -Returns the user name of the player. - -### `def get_world_name()` -Returns the name of the current world. - -### `def get_game_mode()` -Returns the game mode of the current world as an interger: - + 0 = Survival - + 1 = Creative +The old API still can be used, and its documentation is still avaiable [here](https://github.com/MCPI-Devs/MCPIL/tree/3470fb73b81510f5e819a34c04cca6f86457c2b2#api). However it is obsolete, it will be removed from future releases of the Launcher, and it is recommended to use the new ModPi API. ## Mod compilation To compile (compress) a Python mod, run the `mcpim.py` file passing the filename of the mod as the first argument. For example: ```shell -python3.7 ./mcpim.pyc example.py +python3 ./mcpim.pyc example.py ``` This will produce an `example.mcpi` mod file. diff --git a/build.py b/build.py index d2b9de8..367bb22 100644 --- a/build.py +++ b/build.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # build.py @@ -24,6 +24,7 @@ import sys import py_compile import glob +import subprocess from os import chdir def main(args): @@ -32,7 +33,9 @@ def main(args): while i < len(src): py_compile.compile(src[i], cfile="./build/" + src[i].replace("./src", "").replace(".py", ".pyc"), optimize=2); i += 1; - + py_compile.compile("./proxy/proxy.py", cfile="./build/mcpip.pyc", optimize=2); + null = open("/dev/null", "wb"); + subprocess.call(["make", "-C", "modpi"], stdout=null); return 0; if __name__ == '__main__': diff --git a/build/minecraft/minecraft-pi.sh b/build/minecraft/minecraft-pi.sh index 190101e..bb6b448 100755 --- a/build/minecraft/minecraft-pi.sh +++ b/build/minecraft/minecraft-pi.sh @@ -10,4 +10,6 @@ else export LD_LIBRARY_PATH=./lib/brcm fi +export LD_PRELOAD="./preload.so" + ./minecraft-pi diff --git a/example.mcpi b/example.mcpi deleted file mode 100644 index 3c00144496a2bbedc56fdab3de8e282aa1c598fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 813 zcmV+|1Je9>oP|{HZ__Xk{Y?Ifqx(PyUDgf_(8>^@T1TbPRc)$i(xk{uE{VZEBHKwR ze?8}{T@hnLRVDj;_x$d?a}Hh}*VY`bxH?AFK(%qDR&T@i!2uk-K7v$dToq?fyZq>b zj|2yF0{D~3N?=%R{LcSJy4o0Clnze%Cw+)S!wh%2e@ef1@G;XWH?`BY&=P-rE+pe3 zOtt*9tB*@=p)$HKOad))g9ujVZp{o1VWVqEnF50ux6bfY?GU&Frm|ygKoZToa2o8<3p!0TfIbFgfDl|;MtX>J8!WBnt++( zS`DE=V`%{=JMb-1_*6T4)){csmXx|8h9z^J^O_3*D}>r&UW=ZGpk%n2#9yzMF+|f_ zxQXWTXd2%RDVa>7Q*7`aijx_fkcp>Z%58|1NBDLzAAO~g=*#4465j#|HJ-%Ni^T%Q z*K>$q7R}?yXn7UQVYZylt``>}zyduj^Z?IDmba>tEEziT(mr&4OHNs$Co(8mgXCC> zydiRohN;^8-whAKgjPk{CnfKd90JclY1e}_4HwbWkA3pxd#iddQEAwN(*b2M^+S;O z3rG2cG3GhpkA>Ez2Vb;xl-|k~LH}eh=pPN<_6I#!E~1C#f*>HRwQ*oKcDHm~Vvrjx zL8cXlZS?g%B=)gDrf?3DD@+Z`UHI)`l^SFYyNAOd$S?N(aU8o_So z1_eFGR?-JfFylSwz#AygB{Z2PQH0+;q(~?1`~xH=GknUu$>bYbqxGmQY5xxHIy=1k zKK6ijTS#))9~X3x(6jcZ=jYHT75=`>Pnv(2-qPAMyrEI@756wOEIwZ}@`}@F{!!$u z46Q({x~Dtoo)&)0=#IbBd`FHIHfgx!j|{2=+o0KJGx{ceuVwX=jZ -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# - - -import sys -import time -from mcpi import * -from mcpil import * - -mc = minecraft.Minecraft.create(); - -def main(args): - mc.setting("world_immutable", True); - mc.camera.setFollow(); - mc.saveCheckpoint(); - mc.postToChat("Welcome to Minecraft Pi, " + get_user_name() + "."); - mc.postToChat("The name of this awesome world is \"" + get_world_name() + "\"."); - if get_game_mode() == 0: - mc.postToChat("You are in Survival mode."); - else: - mc.postToChat("You are in Creative mode."); - time.sleep(5); - mc.setting("world_immutable", False); - mc.setting("nametags_visible", True); - mc.player.setting("autojump", True); - mc.camera.setNormal(); - return 0; - -if __name__ == '__main__': - sys.exit(main(sys.argv)); diff --git a/libmcpi b/libmcpi new file mode 160000 index 0000000..86c9419 --- /dev/null +++ b/libmcpi @@ -0,0 +1 @@ +Subproject commit 86c941914027d821169568895882bc1a1e6638da diff --git a/mcpi-central b/mcpi-central new file mode 160000 index 0000000..eae4b18 --- /dev/null +++ b/mcpi-central @@ -0,0 +1 @@ +Subproject commit eae4b18fb3dfbbd5413f842864db734f12811c76 diff --git a/modpi b/modpi new file mode 160000 index 0000000..67297f8 --- /dev/null +++ b/modpi @@ -0,0 +1 @@ +Subproject commit 67297f88b5ae36d42c963d49893562617988d7ca diff --git a/proxy b/proxy new file mode 160000 index 0000000..805af1c --- /dev/null +++ b/proxy @@ -0,0 +1 @@ +Subproject commit 805af1c9baadca817eb913cb008d7e6022e3c887 diff --git a/src/api/mcpil/__init__.py b/src/api/mcpil/__init__.py deleted file mode 100644 index 7b90c92..0000000 --- a/src/api/mcpil/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3.7 -# -*- coding: utf-8 -*- -# -# __init__.py -# -# Copyright 2020 Alvarito050506 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# - -import sys -import psutil -from os import environ - -def get_user_name(): - return environ.get("MCPIL_USERNAME"); - -def get_world_name(): - mcpi_process = psutil.Process(int(environ.get("MCPIL_PID"))); - return mcpi_process.open_files()[-1].path.split("/")[-2]; - -def get_game_mode(): - world_name = get_world_name(); - world_file = open("/root/.minecraft/games/com.mojang/minecraftWorlds/" + world_name + "/level.dat", "rb"); - world_file.seek(0x16); - game_mode = int.from_bytes(world_file.read(1), "little"); - world_file.close(); - return game_mode; diff --git a/src/api/setup.py b/src/api/setup.py deleted file mode 100644 index e543258..0000000 --- a/src/api/setup.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3.7 -# -*- coding: utf-8 -*- -# -# setup.py -# -# Copyright 2020 Alvarito050506 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# - -from setuptools import setup, find_packages - -setup( - name="mcpil", - version="v0.1.1", - description="MCPI API extensions.", - author="Alvarito050506", - author_email="donfrutosgomez@gmail.com", - url="https://github.com/Alvarito050506/MCPIL", - project_urls={ - "Bug Tracker": "https://github.com/Alvarito050506/MCPIL/issues", - "Documentation": "https://github.com/Alvarito050506/MCPIL#readme", - "Source Code": "https://github.com/Alvarito050506/MCPIL", - }, - packages=["mcpil"], - install_requires=["psutil>=5.7.0"], - classifiers=[ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3 :: Only", - "License :: OSI Approved :: GNU General Public License v2 (GPLv2)" - ] -); diff --git a/src/install.py b/src/install.py index f07289c..9637e9e 100644 --- a/src/install.py +++ b/src/install.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # install.py @@ -26,7 +26,7 @@ from os import uname, getenv, path, makedirs, mkdir, getcwd, chdir import shutil -def main(): +def main(args): if "arm" not in uname()[4] and "aarch" not in uname()[4]: sys.stdout.write("Error: Minecraft Pi Launcher must run on a Raspberry Pi.\n"); return 1; @@ -34,26 +34,28 @@ def main(): sizes = ["16", "32", "48", "64", "128"]; chdir(path.dirname(path.realpath(__file__))); - if not path.exists(getenv("HOME") + "/.mcpil"): - subprocess.call(["pip3.7", "install", "--user", "-qq", "psutil"]); - subprocess.call(["python3.7", "../src/api/setup.py", "-q", "install"]); - if not path.exists(getenv("HOME") + "/.local/share/applications"): - makedirs(getenv("HOME") + "/.local/share/applications"); - i = 0; - while i < len(sizes): - subprocess.call(["xdg-icon-resource", "install", "--novendor", "--size", sizes[i], "./res/application-x-mcpimod_" + sizes[i] + "px.png", "application-x-mcpimod"]); - subprocess.call(["xdg-icon-resource", "install", "--novendor", "--size", sizes[i], "./res/mcpil_" + sizes[i] + "px.png", "mcpil"]); - i += 1; - subprocess.call(["xdg-mime", "install", "--novendor", "./res/mcpimod.xml"]); + subprocess.call(["pip3", "-q", "install", "mcpi"]); + subprocess.call(["pip3", "-q", "install", "../modpi/"]); + subprocess.call(["pip3", "-q", "install", "../mcpi-central/"]); + shutil.copy2("../modpi/build/preload.so", "./minecraft/preload.so"); + if not path.exists(getenv("HOME") + "/.local/share/applications"): + makedirs(getenv("HOME") + "/.local/share/applications"); + i = 0; + while i < len(sizes): + subprocess.call(["xdg-icon-resource", "install", "--novendor", "--size", sizes[i], "./res/application-x-mcpimod_" + sizes[i] + "px.png", "application-x-mcpimod"]); + subprocess.call(["xdg-icon-resource", "install", "--novendor", "--size", sizes[i], "./res/mcpil_" + sizes[i] + "px.png", "mcpil"]); + i += 1; + subprocess.call(["xdg-mime", "install", "--novendor", "./res/mcpimod.xml"]); + if not path.exists(getenv("HOME") + "/.mcpil/"): mkdir(getenv("HOME") + "/.mcpil"); - shutil.copytree("./minecraft", getenv("HOME") + "/.mcpil/minecraft"); + shutil.copytree("./minecraft/", getenv("HOME") + "/.mcpil/minecraft/"); mkdir(getenv("HOME") + "/.mcpil/mods"); - desktop_template = open("./res/tk.mcpi.mcpil.desktop", "r"); - desktop_file = open(getenv("HOME") + "/.local/share/applications/tk.mcpi.mcpil.desktop", "w"); - desktop_file.write(desktop_template.read().replace("$(EXECUTABLE_PATH)", "python3.7 " + getcwd() + "/mcpil.pyc")); - desktop_template.close(); - desktop_file.close(); + desktop_template = open("./res/tk.mcpi.mcpil.desktop", "r"); + desktop_file = open(getenv("HOME") + "/.local/share/applications/tk.mcpi.mcpil.desktop", "w"); + desktop_file.write(desktop_template.read().replace("$(EXECUTABLE_PATH)", "python3 " + getcwd() + "/mcpil.pyc")); + desktop_template.close(); + desktop_file.close(); return 0; if __name__ == '__main__': - sys.exit(main()); + sys.exit(main(sys.argv)); diff --git a/src/mcpil.py b/src/mcpil.py index 7258f0d..b1f7c3a 100755 --- a/src/mcpil.py +++ b/src/mcpil.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # mcpil.py @@ -79,10 +79,13 @@ def save_settings(): return 0; def on_select_mods(event): - if mods.get(int(event.widget.curselection()[0])) is not None: - delete_button["state"] = NORMAL; - else: - delete_button["state"] = DISABLED; + try: + if mods.get(int(event.widget.curselection()[0])) is not None: + delete_button["state"] = NORMAL; + else: + delete_button["state"] = DISABLED; + except IndexError: + pass; return 0; def install_mod(mod_file=None): @@ -119,7 +122,7 @@ def start_mods(): mods_env["MCPIL_USERNAME"] = mcpi_file.read(7).decode("utf-8"); mcpi_file.close(); mods_env["MCPIL_PID"] = str(mcpi_pid); - mods_process = subprocess.Popen(["python3.7", "./mcpim.pyc"], env=mods_env); + mods_process = subprocess.Popen(["python3", "./mcpim.pyc"], env=mods_env); return 0; def kill_mods(): @@ -161,7 +164,7 @@ def add_server(): global proxy_process; server_addr = server_addr_entry.get(); server_port = server_port_entry.get(); - proxy_process = subprocess.Popen(["python3.7", "./mcpip.pyc", server_addr, server_port]); + proxy_process = subprocess.Popen(["python3", "./mcpip.pyc", server_addr, server_port]); return 0; def kill_proxy(): @@ -332,14 +335,13 @@ def about_tab(parent): title.config(font=("", 24)); title.pack(); - version = Label(tab, text="v0.3.0"); + version = Label(tab, text="v0.4.0"); version.config(font=("", 10)); version.pack(); author = Label(tab, text="by @Alvarito050506"); author.config(font=("", 10)); author.pack(); - author.bind("", web_open); url = Label(tab, text="https://github.com/MCPI-Devs/MCPIL", fg="blue", cursor="hand2"); url.config(font=("", 10)); diff --git a/src/mcpim.py b/src/mcpim.py index 5a321b2..9e367d2 100755 --- a/src/mcpim.py +++ b/src/mcpim.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # mcpim.py @@ -72,7 +72,7 @@ def main(args): mod_file = open(mod_name, "w"); mod_file.write(mod_code); mod_file.close(); - subprocess.Popen(["python3.7", mod_name], env=environ); + subprocess.Popen(["python3", mod_name], env=environ); time.sleep(5); remove(mod_name); i += 1; diff --git a/src/mcpip.py b/src/mcpip.py deleted file mode 100755 index f992e7d..0000000 --- a/src/mcpip.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3.7 -# -*- coding: utf-8 -*- -# -# mcpip.py -# -# Copyright 2020 Alvarito050506 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# - -import sys -import socket -import struct - -def decode_packet(data): - if data[4] == 0x00: - packet = { - "iteration": data[1], - "encapsulation": data[4], - "length": int(struct.unpack("!H", data[5:7])[0] / 8), - "id": data[7], - "data": data[8:-1] + bytes([data[-1]]) - }; - elif data[4] == 0x40: - packet = { - "iteration": data[1], - "encapsulation": data[4], - "length": int(struct.unpack("!H", data[5:7])[0] / 8), - "id": data[10], - "data": data[11:-1] + bytes([data[-1]]) - }; - elif data[4] == 0x60: - packet = { - "iteration": data[1], - "encapsulation": data[4], - "length": int(struct.unpack("!H", data[5:7])[0] / 8), - "id": data[14], - "data": data[15:-1] + bytes([data[-1]]) - }; - else: - print(data); - return packet; - -class Proxy: - def __init__(self): - self.start = False; - self.__options = { - "src_addr": None, - "src_port": 19132, - "dst_port": 19133 - }; - - def set_option(self, name, value): - if name in self.__options: - self.__options[name] = value; - else: - raise NameError(name); - return self.__options; - - def get_options(self): - return self.__options; - - def run(self): - dst_addr = ("0.0.0.0", self.__options["dst_port"]); - src_addr = (self.__options["src_addr"], self.__options["src_port"]); - client_addr = None; - self.__socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP); - self.__socket.bind(dst_addr); - - while True: - data, addr = self.__socket.recvfrom(4096); - if addr == src_addr: - self.__socket.sendto(data, client_addr); - if self.start == True: - print("[S --> C]: ".encode("utf-8") + data); - else: - if client_addr is None or client_addr[0] == addr[0]: - client_addr = addr; - #if data[0] == 0x84 and data[7] == 0x89: - # print(data); - if data[0] == 0x84: - if decode_packet(data)["id"] == 0x00 and decode_packet(data)["encapsulation"] == 0x40 and decode_packet(data)["length"] == 0x09: - self.start = True; - if self.start == True: - print("[C --> S]: ".encode("utf-8") + data); - self.__socket.sendto(data, src_addr); - return 0; - -if __name__ == '__main__': - args = sys.argv; - if len(args) < 2: - print("Error: You must provide a source address."); - print("Usage: " + args[0] + " src_addr [src_port [dst_port]]"); - print("Where src_addr is a valid internet address and src_port and dst_port are valid internet ports.") - sys.exit(-1); - - proxy = Proxy(); - proxy.set_option("src_addr", args[1]); - if len(args) > 2: - proxy.set_option("src_port", int(args[2])); - if len(args) > 3: - proxy.set_option("dst_port", int(args[3])); - options = proxy.get_options(); - print(options["src_addr"] + ":" + str(options["src_port"]) + " --> 0.0.0.0:" + str(options["dst_port"])); - try: - proxy.run(); - except KeyboardInterrupt: - print(""); - sys.exit(0);