import os.path
import traceback
from path_dict import PathDict
from RWESharp.Core import lingoIO
import json
import ujson # just for json to be more compact and fast
from RWESharp import info
from RWESharp.Core.Exceptions import *
from RWESharp.Core.HistorySystem import LevelHistory
from RWESharp.Level.LevelPart import LevelPart
from RWESharp.Level.CustomLevelData import CustomLevelData
from PySide6.QtCore import QPoint, Slot, QRect, QSize
from RWESharp.Core.HistorySystem import LevelResized
from RWESharp.Modify.HistoryElement import HistoryElement
defaultlevel = open(os.path.join(info.PATH_FILES, "default.txt"), "r").read()
minimallevel = open(os.path.join(info.PATH_FILES, "minimal.txt"), "r").read()
defaultlevellines = defaultlevel.split("\n")
minimallevellines = minimallevel.split("\n")
[docs]
class RWELevel:
[docs]
def __init__(self, manager, file=None):
from BaseMod.LevelParts import GeoLevelPart, TileLevelPart, EffectLevelPart, PropLevelPart, CameraLevelPart, InfoLevelPart, LightLevelPart
self.manager = manager
self.file = file
self.lightdata = None
if file is not None:
self.openfile(os.path.abspath(file))
else:
self.data = RWELevel.turntoproject(defaultlevel)
self._level_size = lingoIO.frompoint(self.data["EX2"]["size"])
self.history = LevelHistory(self)
self.viewport = None
self.levelparts: dict[str, LevelPart] = {}
self.mount_levelparts()
# quick access stuff
self.l_info: InfoLevelPart = self.levelparts["info"]
self.l_geo: GeoLevelPart = self.levelparts["geo"]
self.l_tiles: TileLevelPart = self.levelparts["tiles"]
self.l_effects: EffectLevelPart = self.levelparts["effects"]
self.l_props: PropLevelPart = self.levelparts["props"]
self.l_cameras: CameraLevelPart = self.levelparts["camera"]
self.l_light: LightLevelPart = self.levelparts["light"]
self.custom_level_data = CustomLevelData(self)
self.was_resized = False
self.was_changed = False
[docs]
def level_resized(self, newrect: QRect):
oldrect = self.level_rect
self._level_size = [newrect.width(), newrect.height()]
elements: list[HistoryElement] = []
for i in self.levelparts.values():
element = i.level_resized(newrect)
if element is None:
continue
elements.append(element)
self.add_history(LevelResized, elements, oldrect, newrect)
[docs]
def mount_levelparts(self):
if self.manager is None:
return
for i in self.manager.mods:
i.mount_levelparts(self)
[docs]
@Slot()
def undo(self):
self.was_changed = True
if self.viewport is not None:
self.viewport.setTabName()
self.history.undo()
[docs]
@Slot()
def redo(self):
self.was_changed = True
if self.viewport is not None:
self.viewport.setTabName()
self.history.redo()
[docs]
def add_history(self, historytype, *args, **kwargs):
self.was_changed = True
if self.viewport is not None:
self.viewport.setTabName()
self.history.add_element(historytype(self.history, *args, **kwargs))
@property
def last_history_element(self):
return self.history.last_element
@property
def shortname(self):
if self.file is None:
return "Unnamed *"
return os.path.split(self.file)[1] + (" *" if self.was_changed else "")
def __getitem__(self, item):
return self.data[item]
def __setitem__(self, key, value):
self.data[key] = value
@property
def level_rect(self) -> QRect:
return QRect(0, 0, self.level_width, self.level_height)
@property
def extra_tiles(self) -> list[int]:
return self.l_info.extra_tiles
[docs]
def inside(self, point: QPoint) -> bool:
return 0 <= point.x() < self.level_width and 0 <= point.y() < self.level_height
[docs]
def inside_border(self, point: QPoint) -> bool:
borders = self.extra_tiles
topleft = QPoint(borders[0], borders[1])
bottomright = self.level_size - QPoint(borders[2], borders[3])
rect = QRect(topleft, bottomright)
return rect.contains(point)
@property
def level_width(self) -> int:
return self._level_size[0]
@property
def level_height(self) -> int:
return self._level_size[1]
@property
def level_size(self) -> QPoint:
return QPoint(self.level_width, self.level_height)
@property
def level_size_qsize(self) -> QSize:
return QSize(self.level_width, self.level_height)
@property
def changed(self):
return len(self.history.undoactions) > 0
[docs]
def turntolingo(self, file):
with file as fl:
fl.write(str(self["GE"]) + "\r")
fl.write(lingoIO.tolingo(self["TE"]) + "\r")
fl.write(lingoIO.tolingo(self["FE"]) + "\r")
fl.write(lingoIO.tolingo(self["LE"]) + "\r")
fl.write(lingoIO.tolingo(self["EX"]) + "\r")
fl.write(lingoIO.tolingo(self["EX2"]) + "\r")
fl.write(lingoIO.tolingo(self["CM"]) + "\r")
fl.write(lingoIO.tolingo(self["WL"]) + "\r")
fl.write(lingoIO.tolingo(self["PR"]) + "\r")
if self.data.get("CLD") is not None:
fl.write(lingoIO.tolingo(self["CLD"]) + "\r")
[docs]
@staticmethod
def turntoproject(string: str) -> PathDict:
proj = {}
lines = string.split("\n")
proj["GE"] = json.loads(lines[0]) # geometry
proj["TE"] = lingoIO.tojson(lines[1]) # tile editor and his settings
proj["FE"] = lingoIO.tojson(lines[2]) # effect editor params
proj["LE"] = lingoIO.tojson(lines[3], defaultlevellines[3]) # light editor and presets
proj["EX"] = lingoIO.tojson(lines[4], defaultlevellines[4]) # map settings
proj["EX2"] = lingoIO.tojson(lines[5], defaultlevellines[5]) # light and level settings
proj["CM"] = lingoIO.tojson(lines[6], defaultlevellines[6]) # camera settings
proj["WL"] = lingoIO.tojson(lines[7], defaultlevellines[7]) # water level
proj["PR"] = lingoIO.tojson(lines[8], defaultlevellines[8]) # props and settings why the hell i typed both settings wrong???
try:
if len(lines) > 9:
proj["CLD"] = lingoIO.tojson(lines[9])
except:
pass
return PathDict(proj)
[docs]
def openfile(self, file: str):
from RWESharp.Level.RWLParser import RWLParser
if not os.path.exists(file):
raise FileNotFoundError("No file found!!!")
_, ext = os.path.splitext(file)
if ext == ".rwl":
level, light = RWLParser.parse_rwl(file)
self.lightdata = light
self.data = PathDict(level)
return
with open(file) as f:
if ext == ".txt":
self.data = RWELevel.turntoproject(f.read())
self.get_light(file)
return
elif ext == ".wep":
self.data = PathDict(json.load(f))
self.get_light(file)
return
raise FileNotCompatible(f"{file} is not compatible with {info.NAME}!")
[docs]
def get_light(self, file):
lightpath, _ = os.path.splitext(file)
lightpath += ".png"
if os.path.exists(lightpath):
with open(lightpath, "rb") as f:
self.lightdata = f.read()
[docs]
def save_light(self, file):
if self.lightdata is None:
return
lightpath, _ = os.path.splitext(file)
with open(lightpath + ".png", "wb") as l:
l.write(self.lightdata)
[docs]
def save_file(self) -> bool:
from RWESharp.Level.RWLParser import RWLParser
for i, v in self.levelparts.items():
v.save_level()
if self.file is None:
return False
self.was_resized = False
self.was_changed = False
self.viewport.setTabName()
_, ex = os.path.splitext(self.file)
if ex == ".txt":
self.turntolingo(open(self.file, "w"))
self.save_light(self.file)
return True
elif ex == ".wep":
with open(self.file, "w") as f:
f.write(ujson.dumps(self.data.data))
self.save_light(self.file)
return True
elif ex == ".rwl":
RWLParser.save_rwl(self.data.data, self.file, self.lightdata)
return True
try:
self.file += ".rwl"
RWLParser.save_rwl(self.data.data, self.file, self.lightdata)
return True
except Exception:
traceback.print_exc()
return False
[docs]
def export_txt(self) -> None | str:
if self.file is None:
return None
for i, v in self.levelparts.items():
v.save_level()
name, ex = os.path.splitext(self.file)
newname = name + ".txt"
self.turntolingo(open(newname, "w"))
self.save_light(self.file)
return newname