mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-04 21:47:28 +08:00
- Fix a logical bug that the course's high score will not update if the user does not complete the whole course challenge.
302 lines
10 KiB
Python
302 lines
10 KiB
Python
from .error import NoData
|
||
from .item import ItemFactory
|
||
from .song import Chart
|
||
|
||
|
||
class CourseChart(Chart):
|
||
def __init__(self, c=None, song_id: str = None, difficulty: int = None) -> None:
|
||
super().__init__(c, song_id, difficulty)
|
||
self.flag_as_hidden: bool = None
|
||
|
||
def from_dict(self, d: dict) -> 'CourseChart':
|
||
self.song_id = d['id']
|
||
self.difficulty = d['difficulty']
|
||
self.flag_as_hidden = d.get('flag_as_hidden', False)
|
||
return self
|
||
|
||
def to_dict(self) -> dict:
|
||
return {
|
||
'id': self.song_id,
|
||
'difficulty': self.difficulty,
|
||
'flag_as_hidden': self.flag_as_hidden
|
||
}
|
||
|
||
def insert_course_chart(self, course_id: str, song_index: int) -> None:
|
||
self.c.execute('insert into course_chart values (?,?,?,?,?)',
|
||
(course_id, self.song_id, self.difficulty, self.flag_as_hidden, song_index))
|
||
|
||
|
||
class Course:
|
||
def __init__(self, c=None) -> None:
|
||
self.c = c
|
||
self.course_id: str = None
|
||
self.course_name: str = None
|
||
self.dan_name: str = None
|
||
self.style: int = None
|
||
self.gauge_requirement: str = None
|
||
self.flag_as_hidden_when_requirements_not_met: bool = None
|
||
self.can_start: bool = None # 这有什么鬼用?
|
||
|
||
self.requirements: list = []
|
||
self.charts: list = [None, None, None, None]
|
||
self.items: list = None
|
||
|
||
def to_dict(self) -> dict:
|
||
if self.course_name is None:
|
||
self.select_course()
|
||
if not self.items:
|
||
self.select_course_item()
|
||
if not self.charts:
|
||
self.select_course_chart()
|
||
return {
|
||
'course_id': self.course_id,
|
||
'course_name': self.course_name,
|
||
'dan_name': self.dan_name,
|
||
'style': self.style,
|
||
'gauge_requirement': self.gauge_requirement,
|
||
'flag_as_hidden_when_requirements_not_met': self.flag_as_hidden_when_requirements_not_met,
|
||
'can_start': self.can_start,
|
||
'requirements': [{'value': x, 'type': 'course'} for x in self.requirements],
|
||
'songs': [x.to_dict() for x in self.charts],
|
||
'rewards': [str(x) for x in self.items]
|
||
}
|
||
|
||
def from_dict(self, d: dict) -> 'Course':
|
||
self.course_id = d['course_id']
|
||
self.course_name = d.get('course_name', '')
|
||
self.dan_name = d.get('dan_name', '')
|
||
self.style = d.get('style', 1)
|
||
self.gauge_requirement = d.get('gauge_requirement', 'default')
|
||
self.flag_as_hidden_when_requirements_not_met = d.get(
|
||
'flag_as_hidden_when_requirements_not_met', False)
|
||
self.can_start = d.get('can_start', True)
|
||
self.requirements = [x['value'] for x in d.get('requirements', [])]
|
||
self.charts = [CourseChart(self.c).from_dict(x)
|
||
for x in d.get('songs', [])]
|
||
self.items = [ItemFactory.from_str(x, self.c)
|
||
for x in d.get('rewards', [])]
|
||
|
||
return self
|
||
|
||
def from_list(self, l: list) -> 'Course':
|
||
self.course_id = l[0]
|
||
self.course_name = l[1]
|
||
self.dan_name = l[2]
|
||
self.style = l[3] if l[3] else 1
|
||
self.gauge_requirement = l[4] if l[4] else 'default'
|
||
self.flag_as_hidden_when_requirements_not_met = l[5] == 1
|
||
self.can_start = l[6] == 1
|
||
|
||
return self
|
||
|
||
def select_course(self, course_id: str = None) -> 'Course':
|
||
if course_id is not None:
|
||
self.course_id = course_id
|
||
self.c.execute(
|
||
'''select * from course where course_id = ?''', (self.course_id,))
|
||
x = self.c.fetchone()
|
||
if x is None:
|
||
raise NoData(f'The course `{self.course_id}` is not found.')
|
||
return self.from_list(x)
|
||
|
||
def select_course_chart(self) -> None:
|
||
self.c.execute(
|
||
'''select * from course_chart where course_id = ?''', (self.course_id,))
|
||
|
||
for i in self.c.fetchall():
|
||
self.charts[i[4]] = CourseChart(self.c).from_dict({
|
||
'id': i[1],
|
||
'difficulty': i[2],
|
||
'flag_as_hidden': i[3] == 1
|
||
})
|
||
|
||
def select_course_requirement(self) -> None:
|
||
self.c.execute(
|
||
'''select required_id from course_requirement where course_id = ?''', (self.course_id,))
|
||
self.requirements = [x[0] for x in self.c.fetchall()]
|
||
|
||
def select_course_item(self) -> None:
|
||
self.c.execute(
|
||
'''select * from course_item where course_id = ?''', (self.course_id,))
|
||
self.items = [ItemFactory.from_dict({
|
||
'item_id': x[1],
|
||
'type': x[2],
|
||
'amount': x[3] if x[3] else 1,
|
||
}, self.c) for x in self.c.fetchall()]
|
||
|
||
def insert_course(self) -> None:
|
||
self.c.execute(
|
||
'''insert into course values (?,?,?,?,?,?,?)''', (self.course_id, self.course_name, self.dan_name, self.style, self.gauge_requirement, self.flag_as_hidden_when_requirements_not_met, self.can_start))
|
||
|
||
def insert_course_item(self) -> None:
|
||
for i in self.items:
|
||
self.c.execute('''insert into course_item values (?,?,?,?)''',
|
||
(self.course_id, i.item_id, i.item_type, i.amount))
|
||
|
||
def insert_course_chart(self) -> None:
|
||
for i, x in enumerate(self.charts):
|
||
x.insert_course_chart(self.course_id, i)
|
||
|
||
def insert_course_requirement(self) -> None:
|
||
for i in self.requirements:
|
||
self.c.execute('''insert into course_requirement values (?,?)''',
|
||
(self.course_id, i))
|
||
|
||
def insert_all(self) -> None:
|
||
self.insert_course()
|
||
self.insert_course_item()
|
||
self.insert_course_chart()
|
||
self.insert_course_requirement()
|
||
|
||
|
||
class UserCourse(Course):
|
||
'''
|
||
用户课题类
|
||
|
||
parameter: `user` - `User`类或子类的实例
|
||
'''
|
||
|
||
def __init__(self, c=None, user=None) -> None:
|
||
super().__init__(c)
|
||
self.user = user
|
||
|
||
# self.is_completed: bool = False
|
||
self.high_score: int = None
|
||
self.best_clear_type: int = None
|
||
|
||
@property
|
||
def is_completed(self) -> bool:
|
||
return self.best_clear_type != 0
|
||
|
||
def to_dict(self) -> dict:
|
||
r = super().to_dict()
|
||
if self.best_clear_type is None:
|
||
self.select_user_course()
|
||
r.update({
|
||
'is_completed': self.is_completed,
|
||
'high_score': self.high_score,
|
||
'best_clear_type': self.best_clear_type
|
||
})
|
||
return r
|
||
|
||
def select_user_course(self, course_id: str = None) -> None:
|
||
if course_id is not None:
|
||
self.course_id = course_id
|
||
self.c.execute('''select * from user_course where user_id = ? and course_id = ?''',
|
||
(self.user.user_id, self.course_id))
|
||
x = self.c.fetchone()
|
||
if x is None:
|
||
self.high_score = 0
|
||
self.best_clear_type = 0
|
||
else:
|
||
self.high_score = x[2]
|
||
self.best_clear_type = x[3]
|
||
|
||
def insert_or_update_user_course(self) -> None:
|
||
self.c.execute('''insert or replace into user_course values (?,?,?,?)''',
|
||
(self.user.user_id, self.course_id, self.high_score, self.best_clear_type))
|
||
|
||
|
||
class UserCourseList:
|
||
'''
|
||
用户课题列表类
|
||
|
||
parameter: `user` - `User`类或子类的实例
|
||
'''
|
||
|
||
def __init__(self, c=None, user=None) -> None:
|
||
self.c = c
|
||
self.user = user
|
||
|
||
self.courses: list = []
|
||
|
||
def to_dict_list(self) -> list:
|
||
# 临时修复满足条件也无法解锁隐藏段位的问题
|
||
completed_course_id_list: list = []
|
||
r: list = []
|
||
for x in self.courses:
|
||
if x.is_completed:
|
||
completed_course_id_list.append(x.course_id)
|
||
r.append(x.to_dict())
|
||
for x in r:
|
||
for i in x['requirements']:
|
||
if i['value'] in completed_course_id_list:
|
||
i['is_fullfilled'] = True
|
||
return r
|
||
|
||
def select_all(self) -> None:
|
||
self.c.execute('''select * from course''')
|
||
self.courses = [UserCourse(self.c, self.user).from_list(x)
|
||
for x in self.c.fetchall()]
|
||
for i in self.courses:
|
||
i.select_user_course()
|
||
i.select_course_chart()
|
||
i.select_course_item()
|
||
i.select_course_requirement()
|
||
|
||
|
||
class CoursePlay(UserCourse):
|
||
'''
|
||
课题模式打歌类,联动UserPlay
|
||
|
||
parameter: `user` - `UserOnline`类或子类的实例
|
||
'user_play` - `UserPlay`类的实例
|
||
'''
|
||
|
||
def __init__(self, c=None, user=None, user_play=None) -> None:
|
||
super().__init__(c, user)
|
||
self.user_play = user_play
|
||
|
||
self.score: int = None
|
||
self.clear_type: int = None
|
||
|
||
def to_dict(self) -> dict:
|
||
return {
|
||
'rewards': [x.to_dict() for x in self.items],
|
||
"current_stamina": self.user.stamina.stamina,
|
||
"max_stamina_ts": self.user.stamina.max_stamina_ts,
|
||
'user_course_banners': self.user.course_banners
|
||
}
|
||
|
||
def update(self) -> None:
|
||
'''课题模式更新'''
|
||
self.select_user_course()
|
||
|
||
self.score += self.user_play.score
|
||
|
||
flag = False
|
||
if self.score > self.high_score:
|
||
self.high_score = self.score
|
||
flag = True
|
||
|
||
if self.user_play.health < 0:
|
||
# 你挂了
|
||
self.user_play.course_play_state = 5
|
||
self.score = 0
|
||
self.clear_type = 0
|
||
self.user_play.update_play_state_for_course()
|
||
if flag:
|
||
self.insert_or_update_user_course()
|
||
return None
|
||
|
||
self.user_play.course_play_state += 1
|
||
|
||
from .score import Score
|
||
if Score.get_song_state(self.clear_type) > Score.get_song_state(self.user_play.clear_type):
|
||
self.clear_type = self.user_play.clear_type
|
||
self.user_play.update_play_state_for_course()
|
||
|
||
if self.user_play.course_play_state == 4:
|
||
if not self.is_completed:
|
||
self.user.select_user_about_stamina()
|
||
self.select_course_item()
|
||
for i in self.items:
|
||
i.user_claim_item(self.user)
|
||
|
||
if Score.get_song_state(self.clear_type) > Score.get_song_state(self.best_clear_type):
|
||
self.best_clear_type = self.clear_type
|
||
flag = True
|
||
|
||
if flag:
|
||
self.insert_or_update_user_course()
|