Move NBT editor to EditPi's repo

This commit is contained in:
leha-code 2022-04-27 19:37:45 -04:00
parent 9a7be48a19
commit 6db29308a2
No known key found for this signature in database
GPG Key ID: 15227A6455DDF7EE
6 changed files with 6 additions and 435 deletions

View File

@ -47,7 +47,7 @@ Instead of making you type in every single field, Planet lets you write it one t
* Pillow was used for skin manipulation
* PyNBT is used for the built-in MCPIedit
* `click` is an awesome interface, unfortunately, not to handle autoclickers, but for CLI interfaces used in the texture pack tool.
* The NBT editor is now served through [`editpi`](https://github.com/mcpiscript/editpi)
## Installation
#### Prerequisites
@ -61,6 +61,7 @@ Instead of making you type in every single field, Planet lets you write it one t
* `darkdetect`
* PyNBT
* `click`
* EditPi
If you're installing a DEB, all of them with the exception of Minecraft: Pi Edition: Reborn will be automatically installed. Please install an AppImage for the latest build. If you want a DEB, please consider checking out [MCPI++](https://github.com/mobilegmyt/mcpi-reborn-extended).
#### Installation

View File

@ -56,8 +56,6 @@ _ = gettext.translation(
# Local imports
import launcher
from splashes import SPLASHES
import web
import mcpiedit
# PyQt5 imports
from PyQt5.QtCore import *
@ -66,7 +64,6 @@ from PyQt5.QtGui import *
from PyQt5.QtWebKit import *
from PyQt5.QtWebKitWidgets import *
from qtwidgets import AnimatedToggle
# Additional imports
import qdarktheme # Dark style for PyQt5
@ -74,6 +71,8 @@ import pypresence # Discord RPC
from PIL import Image
import darkdetect
import editpi as mcpiedit
# Load dark theme
dark_stylesheet = qdarktheme.load_stylesheet()

View File

@ -1,363 +0,0 @@
"""
Copyright (C) 2022 Alexey Pavlov
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
# MCPIEdit
# This is a different editor from revival's MCPIedit!
# This one is intended to work with Planet but it can work on its own
import sys
import os
import pathlib
import gettext
LOCALE = os.getenv("LANG")
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import nbt_utils as nbt
USER = os.getenv("USER") # Get the username, used for later
absolute_path = pathlib.Path(__file__).parent.absolute()
if str(absolute_path).startswith("/usr/bin"):
absolute_path = "/usr/lib/planet-launcher/"
sys.path.append(absolute_path)
if os.path.exists("/usr/lib/planet-launcher/"):
sys.path.append("/usr/lib/planet-launcher/")
if not os.path.exists(f"/home/{USER}/.minecraft-pi/games/com.mojang/minecraftWorlds/"):
os.makedirs(f"/home/{USER}/.minecraft-pi/games/com.mojang/minecraftWorlds/")
_ = gettext.translation(
"mcpiedit",
localedir=str(absolute_path) + "/assets/translations/",
languages=[LOCALE],
).gettext
GAME_TYPES = {"Survival": nbt.pynbt.TAG_Int(0), "Creative": nbt.pynbt.TAG_Int(1)}
GAME_INTREGERS = {"0": "Survival", "1": "Creative"}
BOOLEAN_INTREGERS = {0: False, 1: True}
BOOLEAN_INTREGERS_REVERSED = {False: 0, True: 1}
class AboutWindow(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
label = QLabel("About MCPIedit")
label.setAlignment(Qt.AlignHCenter)
font = label.font() # Font used
font.setPointSize(15) # Set the font size
label.setFont(font) # Aplly the font onto the label
desc_label = QLabel(
_(
"The default built-in NBT editor for Planet.\n\nMCPIedit makes use of Pi-NBT\n from the original MCPIedit project\nby TheBrokenRail, which is\nlicensed under the MIT license."
)
)
desc_label.setAlignment(Qt.AlignHCenter)
layout.addWidget(label)
layout.addWidget(desc_label)
self.setLayout(layout)
class FileSelectorTab(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
info_label = QLabel(
_(
"NBT editors allow you to edit your world\nfiles to change game modes, time,\nand even the world name. Select an NBT\nfile to edit using the button below."
)
)
info_label.setAlignment(Qt.AlignHCenter)
self.load_button = QPushButton(_("Select NBT File"))
self.about_button = QPushButton(_("About"))
self.about_button.clicked.connect(self.about_window)
layout.addWidget(info_label)
layout.addWidget(self.load_button)
layout.addWidget(self.about_button)
self.setLayout(layout)
def about_window(self):
self.window = AboutWindow()
self.window.show()
class EditorTab(QWidget):
def __init__(self, filename):
super().__init__()
layout = QVBoxLayout()
self.nbt = nbt.load_nbt(filename, True)
self.filename = filename
self.tabs = QTabWidget()
self.tabs.setTabPosition(QTabWidget.West)
self.tabs.setMovable(True)
self.tabs.addTab(self.main_tab(), _("General"))
self.tabs.addTab(self.world_tab(), _("World"))
self.name_edit.setText(str(self.nbt["LevelName"].value))
self.timestamp_box.setValue(int(self.nbt["LastPlayed"].value))
self.game_box.setCurrentText(
GAME_INTREGERS[str(int(self.nbt["GameType"].value))]
)
self.seed_edit.setText(str(int(self.nbt["RandomSeed"].value)))
self.time_edit.setText(str(int(self.nbt["Time"].value)))
# self.mobs_toggle.setChecked(BOOLEAN_INTREGERS[int(self.nbt["SpawnMobs"])]) # REMOVED BECAUSE DOES NOT WORK
self.spawn_x_box.setValue(int(self.nbt["SpawnX"].value))
self.spawn_y_box.setValue(int(self.nbt["SpawnY"].value))
self.spawn_z_box.setValue(int(self.nbt["SpawnZ"].value))
self.player_spawn_x_box.setValue(int(self.nbt["Player"]["SpawnX"].value))
self.player_spawn_y_box.setValue(int(self.nbt["Player"]["SpawnY"].value))
self.player_spawn_z_box.setValue(int(self.nbt["Player"]["SpawnZ"].value))
layout.addWidget(self.tabs)
self.setLayout(layout)
def main_tab(self):
widget = QWidget()
layout = QGridLayout()
self.name_label = QLabel(_("World name"))
self.name_edit = QLineEdit()
self.name_edit.setPlaceholderText(_("OneChunk"))
self.seed_label = QLabel("World Seed")
self.seed_edit = QLineEdit()
self.seed_edit.setPlaceholderText("-121542953")
self.seed_edit.setValidator(QIntValidator())
self.timestamp_label = QLabel(_("Last Played Timestamp"))
self.timestamp_box = QSpinBox()
self.timestamp_box.setMaximum(2147483647)
self.game_label = QLabel(_("Game mode"))
self.game_box = QComboBox()
self.game_box.addItems(["Survival", "Creative"])
# self.mobs_toggle = AnimatedToggle(
# checked_color="#59b8e0",
# pulse_checked_color="#92cee8"
# )
self.time_label = QLabel(_("Time (In Ticks)"))
self.time_edit = QLineEdit()
self.time_edit.setPlaceholderText("1770")
self.time_edit.setValidator(QIntValidator())
self.back_button = QPushButton(_("Back"))
self.save_button = QPushButton(_("Save"))
self.save_button.clicked.connect(self.save)
layout.addWidget(self.name_label, 0, 0)
layout.addWidget(self.name_edit, 0, 1)
layout.addWidget(self.seed_label, 1, 0)
layout.addWidget(self.seed_edit, 1, 1)
layout.addWidget(self.timestamp_label, 2, 0)
layout.addWidget(self.timestamp_box, 2, 1)
layout.addWidget(self.game_label, 3, 0)
layout.addWidget(self.game_box, 3, 1)
layout.addWidget(self.time_label, 4, 0)
layout.addWidget(self.time_edit, 4, 1)
layout.addWidget(self.back_button, 5, 0)
layout.addWidget(self.save_button, 5, 1)
widget.setLayout(layout)
return widget
def world_tab(self):
layout = QGridLayout()
x_label = QLabel(_("Spawnpoint X"))
self.spawn_x_box = QSpinBox()
self.spawn_x_box.setMinimum(-128)
self.spawn_x_box.setMaximum(128)
y_label = QLabel(_("Spawnpoint Y"))
self.spawn_y_box = QSpinBox()
self.spawn_y_box.setMinimum(-64)
self.spawn_y_box.setMaximum(64)
z_label = QLabel(_("Spawnpoint Z"))
self.spawn_z_box = QSpinBox()
self.spawn_z_box.setMinimum(-128)
self.spawn_z_box.setMaximum(128)
player_x_label = QLabel(_("Player Spawnpoint X"))
self.player_spawn_x_box = QSpinBox()
self.player_spawn_x_box.setMinimum(-128)
self.player_spawn_x_box.setMaximum(128)
player_y_label = QLabel(_("Player Spawnpoint Y"))
self.player_spawn_y_box = QSpinBox()
self.player_spawn_y_box.setMinimum(-64)
self.player_spawn_y_box.setMaximum(64)
player_z_label = QLabel(_("Player Spawnpoint Z"))
self.player_spawn_z_box = QSpinBox()
self.player_spawn_z_box.setMinimum(-128)
self.player_spawn_z_box.setMaximum(128)
layout.addWidget(x_label, 0, 0)
layout.addWidget(y_label, 1, 0)
layout.addWidget(z_label, 2, 0)
layout.addWidget(player_x_label, 3, 0)
layout.addWidget(player_y_label, 4, 0)
layout.addWidget(player_z_label, 5, 0)
note_label = QLabel(
_(
"Note:\nPlayer spawnpoints are very buggy!\nYou might spawn in the wrong\nplace or even outside the world!\nDo not use on valuable worlds."
)
)
layout.addWidget(self.spawn_x_box, 0, 1)
layout.addWidget(self.spawn_y_box, 1, 1)
layout.addWidget(self.spawn_z_box, 2, 1)
layout.addWidget(self.player_spawn_x_box, 3, 1)
layout.addWidget(self.player_spawn_y_box, 4, 1)
layout.addWidget(self.player_spawn_z_box, 5, 1)
layout.addWidget(note_label, 6, 0, 1, 2)
widget = QWidget()
widget.setLayout(layout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(widget)
return self.scroll
def save(self):
self.nbt["LevelName"] = nbt.pynbt.TAG_String(self.name_edit.text())
self.nbt["LastPlayed"] = nbt.pynbt.TAG_Long(self.timestamp_box.value())
self.nbt["GameType"] = GAME_TYPES[self.game_box.currentText()]
self.nbt["RandomSeed"] = nbt.pynbt.TAG_Long(int(self.seed_edit.text()))
self.nbt["Time"] = nbt.pynbt.TAG_Long(int(self.time_edit.text()))
self.nbt["SpawnX"] = nbt.pynbt.TAG_Int(self.spawn_x_box.value())
self.nbt["SpawnY"] = nbt.pynbt.TAG_Int(self.spawn_y_box.value())
self.nbt["SpawnZ"] = nbt.pynbt.TAG_Int(self.spawn_z_box.value())
self.nbt["Player"]["SpawnX"] = nbt.pynbt.TAG_Int(
self.player_spawn_x_box.value()
)
self.nbt["Player"]["SpawnY"] = nbt.pynbt.TAG_Int(
self.player_spawn_y_box.value()
)
self.nbt["Player"]["SpawnZ"] = nbt.pynbt.TAG_Int(
self.player_spawn_z_box.value()
)
nbt.save_nbt(self.nbt, self.filename)
class NBTEditor(QWidget):
def __init__(self):
super().__init__()
self.layout = QStackedLayout()
selector = FileSelectorTab()
selector.load_button.clicked.connect(self.load_nbt)
self.layout.addWidget(selector)
self.setLayout(self.layout)
def load_nbt(self):
fname = QFileDialog.getOpenFileName(
self,
_("Open NBT File"),
f"/home/{USER}/.minecraft-pi/games/com.mojang/minecraftWorlds/",
_("Minecraft Pi Level NBT (level.dat)"),
)
if fname[0] == "":
return
editor = EditorTab(fname[0])
editor.back_button.clicked.connect(lambda: self.layout.setCurrentIndex(0))
self.layout.insertWidget(1, editor)
self.layout.setCurrentIndex(1)
self.setLayout(self.layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QMainWindow()
window.setCentralWidget(NBTEditor())
window.setWindowTitle(_("MCPIEdit"))
window.setWindowIcon(QIcon(f"{absolute_path}/assets/img/full/mcpiedit.png"))
window.show()
app.exec()

View File

@ -1,67 +0,0 @@
"""
This file is uniquely licensed under the MIT license because it may be useful in other applications an utilites.
MIT License
Copyright (c) 2022 Alexey Pavlov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import pynbt
import subprocess
def remove_header(filename: str):
# with open(filename, "rb") as file:
# data = file.read()
# with open(filename, "wb") as write_file:
# write_file.write(data[8:])
# This is WIP code! Do not use!
return subprocess.Popen(
["pi-nbt", "remove-header", filename, filename + "_temp.dat"]
).wait()
def add_header(filename: str):
return subprocess.Popen(
["pi-nbt", "add-header", filename + "_temp.dat", filename]
).wait()
def load_nbt(filename: str, header=False):
if header:
remove_header(filename)
with open(filename + "_temp.dat", "rb") as nbt:
nbt = pynbt.NBTFile(io=nbt, little_endian=True)
return nbt
def save_nbt(nbt: pynbt.NBTFile, filename: str, header=True):
with open(filename + "_temp.dat", "wb") as writefile:
nbt.save(io=writefile, little_endian=True)
if header:
add_header(filename)

View File

@ -5,3 +5,4 @@ pillow
qtwidgets
darkdetect
pynbt
editpi

View File

@ -1,4 +1,4 @@
pip3 install pyqtdarktheme pypresence pillow darkdetect qtwidgets pynbt
pip3 install pyqtdarktheme pypresence pillow darkdetect qtwidgets pynbt editpi
link /usr/lib/planet-launcher/main.py /usr/bin/planet-launcher
chmod 755 /usr/lib/planet-launcher/main.py
link /usr/lib/planet-launcher/assets/misc/planet-launcher.desktop /usr/share/applications/planet-launcher.desktop