planet/planet/mcpiedit.py

350 lines
11 KiB
Python

"""
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
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/")
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):
print("Hellow, Cruel World!")
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/mcpiedit.png"))
window.show()
app.exec()