From 1771253acc2fcb69e712082f57a720f0c5742447 Mon Sep 17 00:00:00 2001 From: 544146 Date: Sun, 8 Oct 2023 22:06:44 +0100 Subject: [PATCH] More feet saber progress... kind of --- fs2dd.py | 95 ++++++++++++++++++++++++++++++++++++++++------ model/feetsaber.py | 49 ++++++++++++++++++------ 2 files changed, 122 insertions(+), 22 deletions(-) diff --git a/fs2dd.py b/fs2dd.py index a2af73c0..3b0cc66a 100644 --- a/fs2dd.py +++ b/fs2dd.py @@ -69,17 +69,90 @@ def map_line_nodes( ) -> 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 = [ - # o for o in line_obstacles if o.customData.dd_note_type == DD_RIGHT - # ] + line_obstacles = [ + o for o in fs_beat_map.obstacles if o.customData.is_fs + ] - # todo: implement lines + obstacles_by_type = { + DD_LINE_LEFT: [ + o for o in line_obstacles if o.customData.dd_note_type == DD_LINE_LEFT + ], + DD_LINE_RIGHT: [ + o for o in line_obstacles if o.customData.dd_note_type == DD_LINE_RIGHT + ], + } + + index_in_line = 0 + line_group_id = 1 + last_obstacle = None + for note_type, obstacles in obstacles_by_type.items(): + for obstacle in obstacles: + if obstacle.is_part_of_last_obstacle(last_obstacle) and not obstacle.customData.is_fs_slider: + index_in_line += 1 + is_left = obstacle.customData.position[0] < last_obstacle.customData.position[0] + last_obstacle_x = lines[-1].position.x + lines.append( + DDLineNode( + lineGroupId=line_group_id, + indexInLine=index_in_line, + noteOrder=round(obstacle.time * ORDER_COUNT_PER_BEAT), + time=(fs_info_dat.bps * obstacle.time) / + total_time_seconds, + position=X_Y( + last_obstacle_x + + (-1 if is_left else 1), y=0, + ), + noteType=note_type, + ), + ) + index_in_line += 1 + lines.append( + DDLineNode( + lineGroupId=line_group_id, + indexInLine=index_in_line, + noteOrder=round( + obstacle.time * ORDER_COUNT_PER_BEAT, + ) + ORDER_COUNT_PER_BEAT / 4, + time=(fs_info_dat.bps * obstacle.time) / + total_time_seconds, + position=X_Y( + last_obstacle_x + + (-1 if is_left else 1), y=0, + ), + noteType=note_type, + ), + ) + last_obstacle = obstacle + continue + + if not obstacle.is_part_of_last_obstacle(last_obstacle): + index_in_line = 0 + line_group_id += 1 + + lines.append( + DDLineNode( + lineGroupId=line_group_id, + indexInLine=index_in_line, + noteOrder=round(obstacle.time * ORDER_COUNT_PER_BEAT), + time=(fs_info_dat.bps * obstacle.time) / + total_time_seconds, + position=X_Y(x=obstacle.to_dd_x(), y=0), + noteType=note_type, + ), + ) + index_in_line += 1 + lines.append( + DDLineNode( + lineGroupId=line_group_id, + indexInLine=index_in_line, + noteOrder=round(obstacle.end_time * ORDER_COUNT_PER_BEAT), + time=(fs_info_dat.bps * obstacle.time) / + total_time_seconds, + position=X_Y(x=obstacle.end_to_dd_x, y=0), + noteType=note_type, + ), + ) + last_obstacle = obstacle return lines @@ -179,7 +252,7 @@ def create_dd_tracks_from_fs(fs_map_dir: str) -> DDBeatMapInfoFile: create_ticks = yyyymmdd_to_ticks(datetime.now().strftime('%Y%m%d')) dd_beat_map_info = DDBeatMapInfoFile( - OstId=random_9_digit_int(), + OstId=0, # default CreateTicks=create_ticks, CreateTime=str(create_ticks), BeatMapId=random_9_digit_int(), diff --git a/model/feetsaber.py b/model/feetsaber.py index 417fd8a0..a2d38800 100644 --- a/model/feetsaber.py +++ b/model/feetsaber.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import math import os from dataclasses import dataclass from dataclasses import field @@ -209,8 +210,12 @@ class FSBeatMapFileNote: customData: FSBeatMapFileNoteCustomData @property - def to_dd_x(self): - return 0 # TODO + def to_dd_x(self) -> 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9: + x = self.customData.position[0] + x_min, x_max = -2, 1 + y_min, y_max = 1, 9 + y = (x - x_min) * (y_max - y_min) / (x_max - x_min) + y_min + return round(y) FS_RIGHT_COLOUR = (0.0, 1.0, 3.0, 1.0) @@ -264,6 +269,32 @@ class FSBeatMapFileObstacle: width: int customData: FSBeatMapFileObstacleCustomData + def to_dd_x(self, x: float = None) -> 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9: + x_min, x_max = -2, 1 + y_min, y_max = 1, 9 + if not x: + x = self.customData.position[0] + if x < x_min: + x = -2 + elif x > x_max: + x = 1 + y = (x - x_min) * (y_max - y_min) / (x_max - x_min) + y_min + return round(y) + + @property + def end_to_dd_x(self) -> 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9: + opposite_angle = self.customData.localRotation[1] + if opposite_angle == 0.0: + return self.to_dd_x() + # this angle calculation came out of nowhere, fix this with proper math or something idk + opposite_length = self.duration * \ + math.sin(math.radians(opposite_angle)) + return self.to_dd_x(x=self.customData.position[0] + (opposite_length * 6.4)) + + @property + def has_rotation(self) -> bool: + return self.customData.localRotation[1] != 0.0 + @property def end_time(self): return self.time + self.duration @@ -280,7 +311,9 @@ class FSBeatMapFileObstacle: return False return self.customData.track.casefold() == 'JumpBar'.casefold() - def is_part_of_last_obstacle(self, last_obstacle: FSBeatMapFileObstacle) -> bool: + def is_part_of_last_obstacle(self, last_obstacle: FSBeatMapFileObstacle | None) -> bool: + if not last_obstacle: + return False return last_obstacle.time <= self.time <= last_obstacle.end_time @@ -317,14 +350,8 @@ class FSBeatMapFile: notes = [ FSBeatMapFileNote( time=note['_time'], - lineIndex=note['_lineIndex'] * - 1000 if len( # line index is meant to be between 0 and 3, but sometimes it can be # noqa - str(note['_lineIndex']), # a 4 digit between like 1000 - 3500 (????) # noqa - ) == 1 else note['_lineIndex'], # https://bsmg.wiki/mapping/difficulty-format-v2.html#lineindex # noqa - lineLayer=note['_lineLayer'] * - 1000 if len( - str(note['_lineLayer']), - ) == 1 else note['_lineLayer'], + lineIndex=note['_lineIndex'], + lineLayer=note['_lineLayer'], type=note['_type'], cutDirection=note['_cutDirection'], customData=FSBeatMapFileNoteCustomData(