mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-03 19:28:25 +02:00
250 lines
8.7 KiB
Python
250 lines
8.7 KiB
Python
from source.definition import *
|
|
from source.wszst import *
|
|
from source.Error import *
|
|
|
|
|
|
WARNING_NONE = 0
|
|
WARNING_MINOR = 1
|
|
WARNING_MAJOR = 2
|
|
WARNING_DOLPHIN = 3
|
|
|
|
|
|
def get_trackdata_from_json(track_json, *args, **kwargs):
|
|
return (TrackGroup if "group" in track_json else Track)(*args, **kwargs).load_from_json(track_json)
|
|
|
|
|
|
def check_file_sha1(file: str, excepted_sha1: str) -> int:
|
|
"""
|
|
check if track szs sha1 is correct
|
|
:return: 1 if yes, 0 if no
|
|
"""
|
|
if not os.path.exists(file): return 0
|
|
calculated_sha1 = szs.sha1(file=file)
|
|
if calculated_sha1 == excepted_sha1:
|
|
return 1
|
|
else:
|
|
print(f"incorrect sha1 for {file} {calculated_sha1} : (expected {excepted_sha1})")
|
|
return 0
|
|
|
|
|
|
class Track:
|
|
_wu8_dir = None
|
|
_szs_dir = None
|
|
tag_retro = None
|
|
prefix_list = None
|
|
suffix_list = None
|
|
tags_color = None
|
|
|
|
def __init__(self, name: str = " ", author: str = "Nintendo", special: str = "T11", music: str = "T11",
|
|
sha1: str = None, since_version: str = None, score: int = -1, warning: int = 0,
|
|
version: str = None, tags: list = None, is_in_group: bool = False, weight: int = 1, *args, **kwargs):
|
|
"""
|
|
Track class
|
|
:param name: track name
|
|
:param author: track creator(s)
|
|
:param special: track special slot
|
|
:param music: track music slot
|
|
:param new: is the track original or from an older game
|
|
:param sha1: track sha1
|
|
:param since_version: since when version did the track got added to the mod
|
|
:param score: what it the score of the track
|
|
:param warning: what is the warn level of the track (0 = none, 1 = minor bug, 2 = major bug)
|
|
:param track_version: version of the track
|
|
:param tags: a list of tags that correspond to the track
|
|
|
|
:param args: /
|
|
:param kwargs: /
|
|
"""
|
|
|
|
self.name = name # Track name
|
|
self.author = author # Track author
|
|
self.sha1 = sha1 # Track sha1 from wszst SHA1
|
|
self.special = special # Special slot of the track
|
|
self.music = music # Music of the track
|
|
self.since_version = since_version # Since which version is this track available
|
|
self.score = score # Track score between 1 and 3 stars
|
|
self.warning = warning # Track bug level (1 = minor, 2 = major)
|
|
self.version = version
|
|
self.tags = tags if tags else []
|
|
self.weight = weight
|
|
|
|
self._is_in_group = is_in_group
|
|
|
|
def __repr__(self) -> str:
|
|
"""
|
|
track representation when printed
|
|
:return: track information
|
|
"""
|
|
return f"{self.name} sha1={self.sha1} score={self.score}"
|
|
|
|
def check_wu8_sha1(self) -> int:
|
|
"""
|
|
check if track wu8 sha1 is correct
|
|
:return: 0 if yes, -1 if no
|
|
"""
|
|
return check_file_sha1(self.get_wu8_file(), self.sha1)
|
|
|
|
def check_szs_sha1(self) -> int:
|
|
"""
|
|
check if track szs sha1 is correct
|
|
:return: 0 if yes, -1 if no
|
|
"""
|
|
return check_file_sha1(self.get_szs_file(), self.sha1)
|
|
|
|
def get_wu8_file(self): return f"{self._wu8_dir}/{self.sha1}.wu8"
|
|
def get_szs_file(self): return f"{self._szs_dir}/{self.sha1}.szs"
|
|
|
|
def convert_wu8_to_szs(self) -> None:
|
|
"""
|
|
convert track to szs
|
|
"""
|
|
|
|
szs_file = self.get_szs_file()
|
|
wu8_file = self.get_wu8_file()
|
|
|
|
if os.path.exists(szs_file) and os.path.getsize(szs_file) < 1000:
|
|
os.remove(szs_file) # File under this size are corrupted
|
|
|
|
if not self.check_szs_sha1(): # if sha1 of track's szs is incorrect or track's szs does not exist
|
|
if os.path.exists(wu8_file):
|
|
szs.normalize(
|
|
src_file=wu8_file,
|
|
dest_file=szs_file
|
|
)
|
|
else:
|
|
raise MissingTrackWU8()
|
|
|
|
def get_author_str(self) -> str:
|
|
"""
|
|
:return: the list of authors with ", " separating them
|
|
"""
|
|
return self.author if type(self.author) == str else ", ".join(self.author)
|
|
|
|
def get_ctfile(self, race=False, filter_random_new=None, *args, **kwargs) -> str:
|
|
"""
|
|
get ctfile text to create CTFILE.txt and RCTFILE.txt
|
|
:param filter_random_new: function to decide if the track should be used by the "random new" option
|
|
:param race: is it a text used for Race_*.szs ?
|
|
:return: ctfile definition for the track
|
|
"""
|
|
track_type = "T"
|
|
if not filter_random_new:
|
|
filter_random_new = lambda track: not (track.tags_retro in track.tags) and track.warning != WARNING_DOLPHIN
|
|
track_flag = 0x01 if filter_random_new(self) else 0x00
|
|
|
|
if self._is_in_group:
|
|
track_type = "H"
|
|
track_flag |= 0x04
|
|
|
|
ctfile_track = f' {track_type} {self.music}; {self.special}; {hex(track_flag)}; '
|
|
|
|
if race:
|
|
ctfile_track += (
|
|
f'"-"; ' # track path, not used in Race_*.szs, save a bit of space
|
|
f'"{self.get_track_formatted_name(*args, **kwargs)}\\n{self.get_author_str()}"; '
|
|
# only in race show author's name
|
|
f'"-"\n' # sha1, not used in Race_*.szs, save a bit of space
|
|
)
|
|
|
|
else:
|
|
ctfile_track += (
|
|
f'"{self.sha1}"; ' # track path
|
|
f'"{self.get_track_formatted_name(*args, **kwargs)}"; ' # track text shown ig
|
|
f'"{self.sha1}"\n' # sha1
|
|
)
|
|
|
|
return ctfile_track
|
|
|
|
def select_tag(self, tag_list: list) -> str:
|
|
for tag in self.tags:
|
|
if tag in tag_list: return tag
|
|
return ""
|
|
|
|
def get_track_formatted_name(self, filter_highlight=None, *args, **kwargs) -> str:
|
|
"""
|
|
get the track name with score, color, ...
|
|
:param ct_config: ct_config for tags configuration
|
|
:param filter_highlight: filter function to decide if the track should be filtered.
|
|
:return: the name of the track with colored prefix, suffix
|
|
"""
|
|
if not filter_highlight: filter_highlight = lambda track: False
|
|
|
|
hl_prefix = "" # highlight
|
|
hl_suffix = ""
|
|
prefix = self.select_tag(self.prefix_list) # tag prefix
|
|
suffix = self.select_tag(self.suffix_list) # tag suffix
|
|
star_prefix = "" # star
|
|
star_suffix = ""
|
|
star_text = ""
|
|
|
|
if 0 <= self.score <= 5:
|
|
star_text = f"\\\\x{0xFF10 + self.score:04X}"
|
|
star_prefix = "\\\\c{YOR2}" # per default, stars are colored in gold
|
|
star_suffix = "\\\\c{off} "
|
|
if 0 < self.warning <= 3:
|
|
star_prefix = warning_color[self.warning]
|
|
|
|
if filter_highlight(self): hl_prefix, hl_suffix = "\\\\c{blue1}", "\\\\c{off}"
|
|
|
|
if prefix: prefix = "\\\\c{" + self.tags_color[prefix] + "}" + prefix + "\\\\c{off} "
|
|
if suffix: suffix = " (\\\\c{" + self.tags_color[suffix] + "}" + suffix + "\\\\c{off})"
|
|
|
|
name = f"{star_prefix}{star_text}{star_suffix}{prefix}{hl_prefix}{self.name}{hl_suffix}{suffix}"
|
|
return name
|
|
|
|
def get_track_name(self, ct_config, *args, **kwargs) -> str:
|
|
"""
|
|
get the track name without score, color...
|
|
:return: track name
|
|
"""
|
|
return f"{self.select_tag(ct_config.prefix_list)}{self.name}{self.select_tag(ct_config.suffix_list)}"
|
|
|
|
def load_from_json(self, track_json: dict):
|
|
"""
|
|
load the track from a dictionary
|
|
:param track_json: track's dictionary
|
|
"""
|
|
self.__init__(**track_json)
|
|
|
|
return self
|
|
|
|
def create_from_track_file(self, track_file: str) -> None:
|
|
pass
|
|
|
|
def copy(self):
|
|
new = type(self)()
|
|
for k, v in self.__dict__.items():
|
|
setattr(new, k, v)
|
|
return new
|
|
|
|
def get_tracks(self): yield self
|
|
|
|
|
|
class TrackGroup(Track):
|
|
def __init__(self, tracks: list = None, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.tracks = tracks if tracks else []
|
|
|
|
def load_from_json(self, group_json: dict, *args, **kwargs):
|
|
for key, value in group_json.items(): # load all value in the json as class attribute
|
|
if key == "group":
|
|
for track_json in value:
|
|
track = Track(is_in_group=True, *args, **kwargs).load_from_json(track_json)
|
|
self.tracks.extend(
|
|
[track] * track.weight
|
|
)
|
|
|
|
else:
|
|
setattr(self, key, value)
|
|
|
|
return self
|
|
|
|
def get_tracks(self):
|
|
for track in self.tracks: yield track
|
|
|
|
def get_ctfile(self, *args, **kwargs):
|
|
ctfile_group = f' T T11; T11; 0x02; "-"; "{self.get_track_formatted_name()}"; "-"\n'
|
|
for track in self.tracks:
|
|
ctfile_group += track.get_ctfile(*args, **kwargs)
|
|
|
|
return ctfile_group
|