Files
thomasasfk_drs2dd/fs2dd.py
T
2023-09-23 21:52:59 +01:00

195 lines
6.3 KiB
Python

from __future__ import annotations
import argparse
import os
import shutil
from datetime import datetime
from model.dancedash import DD_LEFT
from model.dancedash import DDBeatMap
from model.dancedash import DDBeatMapData
from model.dancedash import DDBeatMapInfoFile
from model.dancedash import DDLineNode
from model.dancedash import DDRoadBlockNode
from model.dancedash import DDSphereNode
from model.dancedash import ORDER_COUNT_PER_BEAT
from model.dancedash import X_Y
from model.feetsaber import FSBeatMapFile
from model.feetsaber import FSInfoDat
from util import convert_egg_to_ogg_and_get_length
from util import get_first_image_file_in_folder
from util import random_9_digit_int
from util import yyyymmdd_to_ticks
def map_sphere_nodes(fs_beat_map: FSBeatMapFile, total_time_seconds: float) -> list[DDSphereNode]:
spheres = []
...
return spheres
def map_line_nodes(fs_beat_map: FSBeatMapFile, total_time_seconds: float) -> list[DDLineNode]:
lines = []
line_obstacles = [
o for o in fs_beat_map.obstacles if o.customData.is_fs_slider
]
left_obstacles = [
o for o in line_obstacles if o.customData.dd_note_type == DD_LEFT
]
right_obstacles = [ # noqa
o for o in line_obstacles if o.customData.dd_note_type != DD_LEFT
] # noqa
line_group_id = 1
index_in_line = 0
for idx, obstacle in enumerate(left_obstacles):
for multiplier in (0, obstacle.duration): # line start and line end
index_in_line += 1
lines.append(
DDLineNode(
lineGroupId=line_group_id,
indexInLine=index_in_line,
noteOrder=round(
(
(obstacle.time + multiplier) *
ORDER_COUNT_PER_BEAT
) - ORDER_COUNT_PER_BEAT,
),
time=fs_beat_map.customData.time / total_time_seconds,
position=X_Y(x=obstacle.customData.dd_x, y=0),
noteType=obstacle.customData.dd_note_type,
),
)
# todo(aggg figure this out i give up for today)
is_last_obstacle = idx == len(left_obstacles) - 1
next_obstacle = left_obstacles[
idx +
1
] if not is_last_obstacle else None
if next_obstacle and not next_obstacle.is_part_of_last_obstacle(obstacle):
line_group_id += 1
index_in_line = 0
return lines
def map_down_and_jump_notes(fs_beat_map: FSBeatMapFile, total_time_seconds: float) -> list[DDRoadBlockNode]:
spheres = []
...
return spheres
def create_dd_tracks_from_fs(fs_map_dir: str) -> DDBeatMapInfoFile:
info_file_path = os.path.join(fs_map_dir, 'Info.dat')
fs_info = FSInfoDat.from_json_file(info_file_path)
egg_song_path = [
os.path.join(fs_map_dir, f) for f in os.listdir(
fs_map_dir,
) if f.endswith('.egg')
][0]
target_dir = f'{fs_info.songName} - {fs_info.levelAuthorName}'
if not os.path.exists(target_dir):
os.makedirs(target_dir)
ogg_song_name, song_length = convert_egg_to_ogg_and_get_length(
egg_song_path,
)
new_song_path = os.path.join(target_dir, ogg_song_name)
shutil.copy(egg_song_path, new_song_path)
song_path = new_song_path
if song_cover_path := get_first_image_file_in_folder(fs_map_dir):
new_song_cover_path = os.path.join(
target_dir, os.path.basename(song_cover_path),
)
shutil.copy(song_cover_path, new_song_cover_path)
song_cover_path = new_song_cover_path
song_paths = []
for difficulty_set in fs_info.difficultyBeatmapSets:
for difficulty_set in difficulty_set.difficultyBeatmaps:
beat_map: FSBeatMapFile = difficulty_set.get_beatmap(fs_map_dir)
sphere_notes = map_sphere_nodes(beat_map, song_length)
line_notes = map_line_nodes(beat_map, song_length)
road_block_notes = map_down_and_jump_notes(
beat_map, song_length,
)
total_note_count = len(sphere_notes + line_notes + road_block_notes) # noqa
dd_beat_map = DDBeatMap(
data=DDBeatMapData(
name=f'{fs_info.songName}',
sphereNodes=sphere_notes,
lineNodes=line_notes,
roadBlockNodes=road_block_notes,
),
BPM=fs_info.beatsPerMinute,
NPS=str(round(total_note_count / song_length, 2)),
)
song_paths.append(
dd_beat_map.save_to_file(
target_dir, 'a.json',
),
)
available_difficulties = [
'Easy', 'Normal',
'Hard', 'Expert', 'Master', 'ACE',
]
song_path_difficulties = zip(song_paths, available_difficulties)
difficulties = {
f'DRS_{d}': os.path.basename(
sp,
) for sp, d in song_path_difficulties
}
create_ticks = yyyymmdd_to_ticks(datetime.now().strftime('%Y%m%d'))
dd_beat_map_info = DDBeatMapInfoFile(
CreateTicks=create_ticks,
CreateTime=str(create_ticks),
BeatMapId=random_9_digit_int(),
SongName=fs_info.songName,
SongLength=str(song_length),
SongAuthorName=fs_info.songAuthorName,
LevelAuthorName=fs_info.levelAuthorName,
Bpm=str(fs_info.beatsPerMinute),
SongPath=os.path.basename(song_path),
CoverPath=os.path.basename(song_cover_path or '') or None,
SongPreviewSection=fs_info.previewStartTime,
**difficulties,
)
dd_beat_map_info.save_to_file(target_dir)
print(
f'Created {dd_beat_map_info.SongName} ({dd_beat_map_info.BeatMapId})',
)
return dd_beat_map_info
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Create Dance Dash tracks from Feet Saber maps',
)
parser.add_argument(
'--fs-map-dir',
type=str,
help='The directory containing the Feet Saber map files',
required=True,
)
args = parser.parse_args()
if not os.path.exists(args.fs_map_dir):
print(f'Invalid Feet Saber map directory: {args.fs_map_dir}')
raise SystemExit(1)
create_dd_tracks_from_fs(args.fs_map_dir)
raise SystemExit(0)