mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-12 02:57:26 +08:00
Update to v2.8.6 without release
- Code refactoring - Update the song database - Fix a bug of the friend system which arose in the last version - Fix a bug of duplicate calculating finishing states when players finish playing the chart in Link Play.
This commit is contained in:
@@ -1,54 +1,72 @@
|
|||||||
from setting import Config
|
from setting import Config
|
||||||
from .error import ArcError, NoData
|
from .error import ArcError, InputError, NoData, ItemNotEnough
|
||||||
from .constant import Constant
|
from .constant import Constant
|
||||||
from .item import Item
|
from .item import Item, ItemCore
|
||||||
|
|
||||||
|
|
||||||
class Level:
|
class Level:
|
||||||
max_level = None
|
|
||||||
mid_level = 20
|
mid_level = 20
|
||||||
min_level = 1
|
min_level = 1
|
||||||
level = None
|
|
||||||
exp = None
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
self.max_level = None
|
||||||
|
self.level = None
|
||||||
|
self.exp = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def level_exp(self):
|
def level_exp(self):
|
||||||
return Constant.LEVEL_STEPS[self.level]
|
return Constant.LEVEL_STEPS[self.level]
|
||||||
|
|
||||||
|
def add_exp(self, exp_addition: float):
|
||||||
|
# 添加经验计算
|
||||||
|
|
||||||
|
exp = self.exp + exp_addition
|
||||||
|
|
||||||
|
if exp >= Constant.LEVEL_STEPS[self.max_level]:
|
||||||
|
self.exp = Constant.LEVEL_STEPS[self.max_level]
|
||||||
|
self.level = self.max_level
|
||||||
|
|
||||||
|
a = []
|
||||||
|
b = []
|
||||||
|
for i in Constant.LEVEL_STEPS:
|
||||||
|
a.append(i)
|
||||||
|
b.append(Constant.LEVEL_STEPS[i])
|
||||||
|
|
||||||
|
if exp < b[0]: # 向下溢出,是异常状态,不该被try捕获,不然数据库无法回滚
|
||||||
|
raise ValueError('EXP value error.')
|
||||||
|
|
||||||
|
i = len(a) - 1
|
||||||
|
while exp < b[i]:
|
||||||
|
i -= 1
|
||||||
|
|
||||||
|
self.exp = exp
|
||||||
|
self.level = a[i]
|
||||||
|
|
||||||
|
|
||||||
class Skill:
|
class Skill:
|
||||||
skill_id = None
|
|
||||||
skill_id_uncap = None
|
|
||||||
skill_unlock_level = None
|
|
||||||
skill_requires_uncap = None
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
self.skill_id = None
|
||||||
|
self.skill_id_uncap = None
|
||||||
|
self.skill_unlock_level = None
|
||||||
|
self.skill_requires_uncap = None
|
||||||
|
|
||||||
|
|
||||||
class Core(Item):
|
class Core(Item):
|
||||||
item_type = 'core'
|
item_type = 'core'
|
||||||
amount = None
|
|
||||||
|
|
||||||
def __init__(self, core_type: str = '', amount: int = 0) -> None:
|
def __init__(self, core_type: str = '', amount: int = 0) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.item_id = core_type
|
self.item_id = core_type
|
||||||
self.amount = amount
|
self.amount = amount
|
||||||
|
self.is_available = True
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {'core_type': self.item_id, 'amount': self.amount}
|
return {'core_type': self.item_id, 'amount': self.amount}
|
||||||
|
|
||||||
|
|
||||||
class CharacterValue:
|
class CharacterValue:
|
||||||
start = None
|
def __init__(self, start: float = 0, mid: float = 0, end: float = 0) -> None:
|
||||||
mid = None
|
self.set_parameter(start, mid, end)
|
||||||
end = None
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _calc_char_value_20(level, stata, statb, lva=1, lvb=20):
|
def _calc_char_value_20(level, stata, statb, lva=1, lvb=20):
|
||||||
@@ -82,20 +100,19 @@ class CharacterValue:
|
|||||||
|
|
||||||
|
|
||||||
class Character:
|
class Character:
|
||||||
character_id = None
|
|
||||||
name = None
|
|
||||||
char_type = None
|
|
||||||
is_uncapped = None
|
|
||||||
is_uncapped_override = None
|
|
||||||
skill = Skill()
|
|
||||||
level = Level()
|
|
||||||
frag = CharacterValue()
|
|
||||||
prog = CharacterValue()
|
|
||||||
overdrive = CharacterValue()
|
|
||||||
uncap_cores = None
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
self.character_id = None
|
||||||
|
self.name = None
|
||||||
|
self.char_type = None
|
||||||
|
self.is_uncapped = None
|
||||||
|
self.is_uncapped_override = None
|
||||||
|
self.skill = Skill()
|
||||||
|
self.level = Level()
|
||||||
|
self.frag = CharacterValue()
|
||||||
|
self.prog = CharacterValue()
|
||||||
|
self.overdrive = CharacterValue()
|
||||||
|
self.uncap_cores = []
|
||||||
|
self.voice = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def uncap_cores_to_dict(self):
|
def uncap_cores_to_dict(self):
|
||||||
@@ -103,6 +120,7 @@ class Character:
|
|||||||
|
|
||||||
|
|
||||||
class UserCharacter(Character):
|
class UserCharacter(Character):
|
||||||
|
database_table_name = 'user_char_full' if Config.CHARACTER_FULL_UNLOCK else 'user_char'
|
||||||
|
|
||||||
def __init__(self, c, character_id=None) -> None:
|
def __init__(self, c, character_id=None) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -122,12 +140,10 @@ class UserCharacter(Character):
|
|||||||
def select_character_uncap_condition(self, user):
|
def select_character_uncap_condition(self, user):
|
||||||
# parameter: user - User类或子类的实例
|
# parameter: user - User类或子类的实例
|
||||||
# 获取此角色的觉醒信息
|
# 获取此角色的觉醒信息
|
||||||
if Config.CHARACTER_FULL_UNLOCK:
|
|
||||||
self.c.execute('''select is_uncapped, is_uncapped_override from user_char_full where user_id = :a and character_id = :b''',
|
self.c.execute('''select is_uncapped, is_uncapped_override from %s where user_id = :a and character_id = :b''' % self.database_table_name,
|
||||||
{'a': user.user_id, 'b': self.character_id})
|
{'a': user.user_id, 'b': self.character_id})
|
||||||
else:
|
|
||||||
self.c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user.user_id, 'b': self.character_id})
|
|
||||||
x = self.c.fetchone()
|
x = self.c.fetchone()
|
||||||
if not x:
|
if not x:
|
||||||
raise NoData('The character of the user does not exist.')
|
raise NoData('The character of the user does not exist.')
|
||||||
@@ -138,12 +154,10 @@ class UserCharacter(Character):
|
|||||||
def select_character_info(self, user):
|
def select_character_info(self, user):
|
||||||
# parameter: user - User类或子类的实例
|
# parameter: user - User类或子类的实例
|
||||||
# 获取所给用户此角色信息
|
# 获取所给用户此角色信息
|
||||||
if not Config.CHARACTER_FULL_UNLOCK:
|
|
||||||
self.c.execute('''select * from user_char a,character b where a.user_id=? and a.character_id=b.character_id and a.character_id=?''',
|
self.c.execute('''select * from %s a,character b where a.user_id=? and a.character_id=b.character_id and a.character_id=?''' % self.database_table_name,
|
||||||
(user.user_id, self.character_id))
|
(user.user_id, self.character_id))
|
||||||
else:
|
|
||||||
self.c.execute('''select * from user_char_full a,character b where a.user_id=? and a.character_id=b.character_id and a.character_id=?''',
|
|
||||||
(user.user_id, self.character_id))
|
|
||||||
y = self.c.fetchone()
|
y = self.c.fetchone()
|
||||||
if y is None:
|
if y is None:
|
||||||
raise NoData('The character of the user does not exist.')
|
raise NoData('The character of the user does not exist.')
|
||||||
@@ -162,37 +176,40 @@ class UserCharacter(Character):
|
|||||||
self.skill.skill_id_uncap = y[21]
|
self.skill.skill_id_uncap = y[21]
|
||||||
self.skill.skill_unlock_level = y[19]
|
self.skill.skill_unlock_level = y[19]
|
||||||
self.skill.skill_requires_uncap = y[20] == 1
|
self.skill.skill_requires_uncap = y[20] == 1
|
||||||
|
|
||||||
|
if self.character_id == 21 or self.character_id == 46:
|
||||||
|
self.voice = [0, 1, 2, 3, 100, 1000, 1001]
|
||||||
|
|
||||||
self.select_character_core()
|
self.select_character_core()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {"is_uncapped_override": self.is_uncapped_override,
|
r = {"is_uncapped_override": self.is_uncapped_override,
|
||||||
"is_uncapped": self.is_uncapped,
|
"is_uncapped": self.is_uncapped,
|
||||||
"uncap_cores": self.uncap_cores_to_dict,
|
"uncap_cores": self.uncap_cores_to_dict,
|
||||||
"char_type": self.char_type,
|
"char_type": self.char_type,
|
||||||
"skill_id_uncap": self.skill.skill_id_uncap,
|
"skill_id_uncap": self.skill.skill_id_uncap,
|
||||||
"skill_requires_uncap": self.skill.skill_requires_uncap,
|
"skill_requires_uncap": self.skill.skill_requires_uncap,
|
||||||
"skill_unlock_level": self.skill.skill_unlock_level,
|
"skill_unlock_level": self.skill.skill_unlock_level,
|
||||||
"skill_id": self.skill.skill_id,
|
"skill_id": self.skill.skill_id,
|
||||||
"overdrive": self.overdrive.get_value(self.level),
|
"overdrive": self.overdrive.get_value(self.level),
|
||||||
"prog": self.overdrive.get_value(self.level),
|
"prog": self.overdrive.get_value(self.level),
|
||||||
"frag": self.overdrive.get_value(self.level),
|
"frag": self.overdrive.get_value(self.level),
|
||||||
"level_exp": self.level.level_exp,
|
"level_exp": self.level.level_exp,
|
||||||
"exp": self.level.exp,
|
"exp": self.level.exp,
|
||||||
"level": self.level.level,
|
"level": self.level.level,
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"character_id": self.character_id
|
"character_id": self.character_id
|
||||||
}
|
}
|
||||||
|
if self.voice:
|
||||||
|
r['voice'] = self.voice
|
||||||
|
return r
|
||||||
|
|
||||||
def change_uncap_override(self, user):
|
def change_uncap_override(self, user):
|
||||||
# parameter: user - User类或子类的实例
|
# parameter: user - User类或子类的实例
|
||||||
# 切换觉醒状态
|
# 切换觉醒状态
|
||||||
if not Config.CHARACTER_FULL_UNLOCK:
|
self.c.execute('''select is_uncapped, is_uncapped_override from %s where user_id = :a and character_id = :b''' % self.database_table_name,
|
||||||
self.c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id = :a and character_id = :b''',
|
{'a': user.user_id, 'b': self.character_id})
|
||||||
{'a': user.user_id, 'b': self.character_id})
|
|
||||||
else:
|
|
||||||
self.c.execute('''select is_uncapped, is_uncapped_override from user_char_full where user_id = :a and character_id = :b''',
|
|
||||||
{'a': user.user_id, 'b': self.character_id})
|
|
||||||
|
|
||||||
x = self.c.fetchone()
|
x = self.c.fetchone()
|
||||||
if x is None or x[0] == 0:
|
if x is None or x[0] == 0:
|
||||||
@@ -201,13 +218,80 @@ class UserCharacter(Character):
|
|||||||
self.c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
self.c.execute('''update user set is_char_uncapped_override = :a where user_id = :b''', {
|
||||||
'a': 1 if x[1] == 0 else 0, 'b': user.user_id})
|
'a': 1 if x[1] == 0 else 0, 'b': user.user_id})
|
||||||
|
|
||||||
if not Config.CHARACTER_FULL_UNLOCK:
|
self.c.execute('''update %s set is_uncapped_override = :a where user_id = :b and character_id = :c''' % self.database_table_name, {
|
||||||
self.c.execute('''update user_char set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
'a': 1 if x[1] == 0 else 0, 'b': user.user_id, 'c': self.character_id})
|
||||||
'a': 1 if x[1] == 0 else 0, 'b': user.user_id, 'c': self.character_id})
|
|
||||||
else:
|
|
||||||
self.c.execute('''update user_char_full set is_uncapped_override = :a where user_id = :b and character_id = :c''', {
|
|
||||||
'a': 1 if x[1] == 0 else 0, 'b': user.user_id, 'c': self.character_id})
|
|
||||||
|
|
||||||
def character_uncap(self):
|
self.is_uncapped_override = x[1] == 0
|
||||||
|
|
||||||
|
def character_uncap(self, user):
|
||||||
|
# parameter: user - User类或子类的实例
|
||||||
# 觉醒角色
|
# 觉醒角色
|
||||||
pass
|
if Config.CHARACTER_FULL_UNLOCK:
|
||||||
|
# 全解锁了你觉醒个鬼啊
|
||||||
|
raise ArcError('All characters are available.')
|
||||||
|
|
||||||
|
if not self.uncap_cores:
|
||||||
|
self.select_character_core()
|
||||||
|
|
||||||
|
if self.is_uncapped is None:
|
||||||
|
self.c.execute(
|
||||||
|
'''select is_uncapped from user_char where user_id=? and character_id=?''', (user.user_id, self.character_id))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if x and x[0] == 1:
|
||||||
|
raise ArcError('The character has been uncapped.')
|
||||||
|
elif self.is_uncapped:
|
||||||
|
raise ArcError('The character has been uncapped.')
|
||||||
|
|
||||||
|
for i in self.uncap_cores:
|
||||||
|
self.c.execute(
|
||||||
|
'''select amount from user_item where user_id=? and item_id=? and type="core"''', (user.user_id, i.item_id))
|
||||||
|
y = self.c.fetchone()
|
||||||
|
if not y or i.amount > y[0]:
|
||||||
|
raise ItemNotEnough('The cores are not enough.')
|
||||||
|
|
||||||
|
for i in self.uncap_cores:
|
||||||
|
ItemCore(self.c, i, reverse=True).user_claim_item(user)
|
||||||
|
|
||||||
|
self.c.execute('''update user_char set is_uncapped=1, is_uncapped_override=0 where user_id=? and character_id=?''',
|
||||||
|
(user.user_id, self.character_id))
|
||||||
|
|
||||||
|
self.is_uncapped = True
|
||||||
|
self.is_uncapped_override = False
|
||||||
|
|
||||||
|
def upgrade(self, user, exp_addition: float):
|
||||||
|
# parameter: user - User类或子类的实例
|
||||||
|
# 升级角色
|
||||||
|
if Config.CHARACTER_FULL_UNLOCK:
|
||||||
|
# 全解锁了你升级个鬼啊
|
||||||
|
raise ArcError('All characters are available.')
|
||||||
|
|
||||||
|
if self.level.exp is None:
|
||||||
|
self.select_character_info(user)
|
||||||
|
|
||||||
|
if self.is_uncapped is None:
|
||||||
|
self.c.execute(
|
||||||
|
'''select is_uncapped from user_char where user_id=? and character_id=?''', (user.user_id, self.character_id))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if x:
|
||||||
|
self.is_uncapped = x[0] == 1
|
||||||
|
|
||||||
|
self.level.max_level = 30 if self.is_uncapped else 20
|
||||||
|
self.level.add_exp(exp_addition)
|
||||||
|
|
||||||
|
self.c.execute('''update user_char set level=?, exp=? where user_id=? and character_id=?''',
|
||||||
|
(self.level.level, self.level.exp, user.user_id, self.character_id))
|
||||||
|
|
||||||
|
def upgrade_by_core(self, user, core):
|
||||||
|
# parameter: user - User类或子类的实例
|
||||||
|
# core - ItemCore类或子类的实例
|
||||||
|
# 以太之滴升级,注意这里core.amount应该是负数
|
||||||
|
|
||||||
|
if core.item_id != 'core_generic':
|
||||||
|
raise ArcError('Core type error.')
|
||||||
|
|
||||||
|
if core.amount >= 0:
|
||||||
|
raise InputError(
|
||||||
|
'The amount of `core_generic` should be negative.')
|
||||||
|
|
||||||
|
core.user_claim_item(user)
|
||||||
|
self.upgrade(user, - core.amount * Constant.CORE_EXP)
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
class ArcError(Exception):
|
class ArcError(Exception):
|
||||||
api_error_code = -999
|
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None) -> None:
|
||||||
error_code = 108
|
|
||||||
message = None
|
|
||||||
extra_data = None
|
|
||||||
|
|
||||||
def __init__(self, message=None, error_code=None, api_error_code=None, extra_data=None) -> None:
|
|
||||||
self.message = message
|
self.message = message
|
||||||
if error_code:
|
self.error_code = error_code
|
||||||
self.error_code = error_code
|
self.api_error_code = api_error_code
|
||||||
if api_error_code:
|
self.extra_data = extra_data
|
||||||
self.api_error_code = api_error_code
|
|
||||||
if extra_data:
|
|
||||||
self.extra_data = extra_data
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return repr(self.message)
|
return repr(self.message)
|
||||||
@@ -19,7 +11,7 @@ class ArcError(Exception):
|
|||||||
|
|
||||||
class InputError(ArcError):
|
class InputError(ArcError):
|
||||||
# 输入类型错误
|
# 输入类型错误
|
||||||
def __init__(self, message=None, error_code=None, api_error_code=-100, extra_data=None) -> None:
|
def __init__(self, message=None, error_code=108, api_error_code=-100, extra_data=None) -> None:
|
||||||
super().__init__(message, error_code, api_error_code, extra_data)
|
super().__init__(message, error_code, api_error_code, extra_data)
|
||||||
|
|
||||||
|
|
||||||
@@ -46,6 +38,24 @@ class UserBan(ArcError):
|
|||||||
super().__init__(message, error_code, api_error_code, extra_data)
|
super().__init__(message, error_code, api_error_code, extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemNotEnough(ArcError):
|
||||||
|
# 物品数量不足
|
||||||
|
def __init__(self, message=None, error_code=-6, api_error_code=-999, extra_data=None) -> None:
|
||||||
|
super().__init__(message, error_code, api_error_code, extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemUnavailable(ArcError):
|
||||||
|
# 物品不可用
|
||||||
|
def __init__(self, message=None, error_code=-6, api_error_code=-999, extra_data=None) -> None:
|
||||||
|
super().__init__(message, error_code, api_error_code, extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
class FriendError(ArcError):
|
||||||
|
# 好友系统出错
|
||||||
|
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None) -> None:
|
||||||
|
super().__init__(message, error_code, api_error_code, extra_data)
|
||||||
|
|
||||||
|
|
||||||
class NoAccess(ArcError):
|
class NoAccess(ArcError):
|
||||||
# 无权限
|
# 无权限
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,7 +1,185 @@
|
|||||||
|
from sympy import Nor
|
||||||
|
from .error import NoData, ItemUnavailable, ItemNotEnough, InputError
|
||||||
|
|
||||||
|
|
||||||
class Item:
|
class Item:
|
||||||
item_id = None
|
|
||||||
item_type = None
|
item_type = None
|
||||||
is_available = None
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
self.item_id = None
|
||||||
|
self.__amount = None
|
||||||
|
self.is_available = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def amount(self):
|
||||||
|
return self.__amount
|
||||||
|
|
||||||
|
@amount.setter
|
||||||
|
def amount(self, value: int):
|
||||||
|
self.__amount = int(value)
|
||||||
|
|
||||||
|
def user_claim_item(self, user):
|
||||||
|
# parameter: user - User类或子类的实例
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NormalItem(Item):
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.c = c
|
||||||
|
|
||||||
|
def user_claim_item(self, user):
|
||||||
|
if not self.is_available:
|
||||||
|
self.c.execute(
|
||||||
|
'''select is_available from item where item_id=? and type=?''', (self.item_id, self.item_type))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if x:
|
||||||
|
if x[0] == 0:
|
||||||
|
self.is_available = False
|
||||||
|
raise ItemUnavailable('The item is unavailable.')
|
||||||
|
else:
|
||||||
|
self.is_available = True
|
||||||
|
else:
|
||||||
|
raise NoData('No item data.')
|
||||||
|
|
||||||
|
self.c.execute('''select exists(select * from user_item where user_id=? and item_id=? and type=?)''',
|
||||||
|
(user.user_id, self.item_id, self.item_type))
|
||||||
|
if self.c.fetchone() == (0,):
|
||||||
|
self.c.execute('''insert into user_item values(:a,:b,:c,1)''',
|
||||||
|
{'a': user.user_id, 'b': self.item_id, 'c': self.item_type})
|
||||||
|
|
||||||
|
|
||||||
|
class PositiveItem(Item):
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.c = c
|
||||||
|
|
||||||
|
def user_claim_item(self, user):
|
||||||
|
self.c.execute('''select amount from user_item where user_id=? and item_id=? and type=?''',
|
||||||
|
(user.user_id, self.item_id, self.item_type))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if x:
|
||||||
|
if x[0] + self.amount < 0: # 数量不足
|
||||||
|
raise ItemNotEnough(
|
||||||
|
'The user does not have enough `%s`.' % self.item_id)
|
||||||
|
self.c.execute('''update user_item set amount=? where user_id=? and item_id=? and type=?''',
|
||||||
|
(x[0]+self.amount, user.user_id, self.item_id, self.item_type))
|
||||||
|
else:
|
||||||
|
if self.amount < 0: # 添加数量错误
|
||||||
|
raise InputError(
|
||||||
|
'The amount of `%s` is wrong.' % self.item_id)
|
||||||
|
self.c.execute('''insert into user_item values(?,?,?,?)''',
|
||||||
|
(user.user_id, self.item_id, self.item_type, self.amount))
|
||||||
|
|
||||||
|
|
||||||
|
class ItemCore(PositiveItem):
|
||||||
|
item_type = 'core'
|
||||||
|
|
||||||
|
def __init__(self, c, core=None, reverse=False) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
self.is_available = True
|
||||||
|
if core:
|
||||||
|
self.item_id = core.item_id
|
||||||
|
self.amount = - core.amount if reverse else core.amount
|
||||||
|
|
||||||
|
|
||||||
|
class ItemCharacter(Item):
|
||||||
|
item_type = 'character'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.c = c
|
||||||
|
self.is_available = True
|
||||||
|
|
||||||
|
def set_id(self, character_id):
|
||||||
|
# 将name: str转为character_id: int存到item_id里
|
||||||
|
if character_id.isdigit():
|
||||||
|
self.item_id = int(character_id)
|
||||||
|
else:
|
||||||
|
self.c.execute(
|
||||||
|
'''select character_id from character where name=?''', (character_id,))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if x:
|
||||||
|
self.item_id = x[0]
|
||||||
|
else:
|
||||||
|
raise NoData('No character `%s`.' % character_id)
|
||||||
|
|
||||||
|
def user_claim_item(self, user):
|
||||||
|
self.c.execute(
|
||||||
|
'''select exists(select * from user_char where user_id=? and character_id=?)''', (user.user_id, self.item_id))
|
||||||
|
if self.c.fetchone() == (0,):
|
||||||
|
self.c.execute(
|
||||||
|
'''insert into user_char values(?,?,1,0,0,0)''', (user.user_id, self.item_id))
|
||||||
|
|
||||||
|
|
||||||
|
class Memory(Item):
|
||||||
|
item_type = 'memory'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.c = c
|
||||||
|
self.is_available = True
|
||||||
|
|
||||||
|
def user_claim_item(self, user):
|
||||||
|
self.c.execute(
|
||||||
|
'''select ticket from user where user_id=?''', (user.user_id,))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if x is not None:
|
||||||
|
self.c.execute('''update user set ticket=? where user_id=?''',
|
||||||
|
(x[0]+self.amount, user.user_id))
|
||||||
|
else:
|
||||||
|
raise NoData('The ticket of the user is null.')
|
||||||
|
|
||||||
|
|
||||||
|
class Anni5tix(PositiveItem):
|
||||||
|
item_type = 'anni5tix'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
self.is_available = True
|
||||||
|
|
||||||
|
|
||||||
|
class WorldSong(NormalItem):
|
||||||
|
item_type = 'world_song'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
|
||||||
|
|
||||||
|
class WorldUnlock(NormalItem):
|
||||||
|
item_type = 'world_unlock'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
|
||||||
|
|
||||||
|
class Single(NormalItem):
|
||||||
|
item_type = 'single'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
|
||||||
|
|
||||||
|
class Pack(NormalItem):
|
||||||
|
item_type = 'pack'
|
||||||
|
|
||||||
|
def __init__(self, c) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_cores(c, user) -> list:
|
||||||
|
# parameter: user - User类或子类的实例
|
||||||
|
# 得到用户的cores,返回字典列表
|
||||||
|
r = []
|
||||||
|
c.execute(
|
||||||
|
'''select item_id, amount from user_item where user_id = ? and type="core"''', (user.user_id,))
|
||||||
|
x = c.fetchall()
|
||||||
|
if x:
|
||||||
|
for i in x:
|
||||||
|
if i[1]:
|
||||||
|
amount = i[1]
|
||||||
|
else:
|
||||||
|
amount = 0
|
||||||
|
r.append({'core_type': i[0], 'amount': amount})
|
||||||
|
|
||||||
|
return r
|
||||||
|
|||||||
73
latest version/core/score.py
Normal file
73
latest version/core/score.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
from .song import Chart
|
||||||
|
|
||||||
|
|
||||||
|
class Score:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.song = Chart()
|
||||||
|
self.score = None
|
||||||
|
self.shiny_perfect_count = None
|
||||||
|
self.perfect_count = None
|
||||||
|
self.near_count = None
|
||||||
|
self.miss_count = None
|
||||||
|
self.health = None
|
||||||
|
self.modifier = None
|
||||||
|
self.time_played = None
|
||||||
|
self.best_clear_type = None
|
||||||
|
self.clear_type = None
|
||||||
|
self.rating = None
|
||||||
|
|
||||||
|
def set_score(self, score: int, shiny_perfect_count: int, perfect_count: int, near_count: int, miss_count: int, health: int, modifier: int, time_played: int, clear_type: int):
|
||||||
|
self.score = score
|
||||||
|
self.shiny_perfect_count = shiny_perfect_count
|
||||||
|
self.perfect_count = perfect_count
|
||||||
|
self.near_count = near_count
|
||||||
|
self.miss_count = miss_count
|
||||||
|
self.health = health
|
||||||
|
self.modifier = modifier
|
||||||
|
self.time_played = time_played
|
||||||
|
self.clear_type = clear_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self) -> bool:
|
||||||
|
# 分数有效性检查
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def calculate_rating(defnum: int, score: int) -> float:
|
||||||
|
# 计算rating,-1视作Unrank
|
||||||
|
if not defnum or defnum <= 0:
|
||||||
|
# 谱面没定数或者定数小于等于0被视作Unrank
|
||||||
|
return -1
|
||||||
|
|
||||||
|
if score >= 10000000:
|
||||||
|
ptt = defnum + 2
|
||||||
|
elif score < 9800000:
|
||||||
|
ptt = defnum + (score-9500000) / 300000
|
||||||
|
if ptt < 0:
|
||||||
|
ptt = 0
|
||||||
|
else:
|
||||||
|
ptt = defnum + 1 + (score-9800000) / 200000
|
||||||
|
|
||||||
|
return ptt
|
||||||
|
|
||||||
|
def get_rating_by_calc(self) -> float:
|
||||||
|
# 通过计算得到本成绩的rating
|
||||||
|
self.rating = self.calculate_rating(self.song.defnum, self.score)
|
||||||
|
return self.rating
|
||||||
|
|
||||||
|
@property
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"rating": self.rating,
|
||||||
|
"modifier": self.modifier,
|
||||||
|
"time_played": self.time_played,
|
||||||
|
"health": self.health,
|
||||||
|
"clear_type": self.clear_type,
|
||||||
|
"miss_count": self.miss_count,
|
||||||
|
"near_count": self.near_count,
|
||||||
|
"perfect_count": self.perfect_count,
|
||||||
|
"shiny_perfect_count": self.shiny_perfect_count,
|
||||||
|
"score": self.score,
|
||||||
|
"difficulty": self.song.difficulty,
|
||||||
|
"song_id": self.song.song_id
|
||||||
|
}
|
||||||
7
latest version/core/song.py
Normal file
7
latest version/core/song.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
class Chart:
|
||||||
|
# defnum: chart const * 10
|
||||||
|
|
||||||
|
def __init__(self, song_id: str = None, difficulty: int = None, defnum: int = None) -> None:
|
||||||
|
self.song_id = song_id
|
||||||
|
self.difficulty = difficulty
|
||||||
|
self.defnum = defnum
|
||||||
@@ -20,14 +20,17 @@ class Connect():
|
|||||||
return self.c
|
return self.c
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
if exc_type is not None:
|
||||||
|
if self.conn:
|
||||||
|
self.conn.rollback()
|
||||||
|
|
||||||
|
current_app.logger.error(
|
||||||
|
traceback.format_exception(exc_type, exc_val, exc_tb))
|
||||||
|
|
||||||
if self.conn:
|
if self.conn:
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
self.conn.close()
|
self.conn.close()
|
||||||
|
|
||||||
if exc_type is not None:
|
|
||||||
current_app.logger.error(
|
|
||||||
traceback.format_exception(exc_type, exc_val, exc_tb))
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
from .error import ArcError, InputError, DataExist, NoAccess, NoData, UserBan
|
from .error import ArcError, InputError, DataExist, NoAccess, NoData, UserBan, FriendError
|
||||||
from .constant import Constant
|
from .constant import Constant
|
||||||
from .character import UserCharacter
|
from .character import UserCharacter
|
||||||
|
from .score import Score
|
||||||
|
from .world import Map
|
||||||
|
from .item import get_user_cores
|
||||||
from setting import Config
|
from setting import Config
|
||||||
import hashlib
|
import hashlib
|
||||||
import base64
|
import base64
|
||||||
@@ -8,23 +11,42 @@ import time
|
|||||||
from os import urandom
|
from os import urandom
|
||||||
|
|
||||||
|
|
||||||
class User:
|
def code_get_id(c, user_code: str) -> int:
|
||||||
name = None
|
# 用user_code获取user_id
|
||||||
email = None
|
|
||||||
password = None
|
|
||||||
user_id = None
|
|
||||||
user_code = None
|
|
||||||
|
|
||||||
|
c.execute('''select user_id from user where user_code = :a''',
|
||||||
|
{'a': user_code})
|
||||||
|
x = c.fetchone()
|
||||||
|
|
||||||
|
if x is not None:
|
||||||
|
user_id = int(x[0])
|
||||||
|
else:
|
||||||
|
raise NoData('No user.', 401, -3)
|
||||||
|
|
||||||
|
return user_id
|
||||||
|
|
||||||
|
|
||||||
|
class User:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
self.name = None
|
||||||
|
self.email = None
|
||||||
|
self.password = None
|
||||||
|
self.user_id = None
|
||||||
|
self.user_code = None
|
||||||
|
|
||||||
|
self.join_date = None
|
||||||
|
self.rating_ptt = None
|
||||||
|
|
||||||
|
self.ticket = None
|
||||||
|
self.world_rank_score = None
|
||||||
|
self.ban_flag = None
|
||||||
|
|
||||||
|
|
||||||
class UserRegister(User):
|
class UserRegister(User):
|
||||||
hash_pwd = None
|
|
||||||
|
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
|
self.hash_pwd = None
|
||||||
|
|
||||||
def set_name(self, name: str):
|
def set_name(self, name: str):
|
||||||
if 3 <= len(name) <= 16:
|
if 3 <= len(name) <= 16:
|
||||||
@@ -115,15 +137,14 @@ class UserRegister(User):
|
|||||||
|
|
||||||
class UserLogin(User):
|
class UserLogin(User):
|
||||||
# 密码和token的加密方式为 SHA-256
|
# 密码和token的加密方式为 SHA-256
|
||||||
device_id = None
|
|
||||||
ip = None
|
|
||||||
hash_pwd = None
|
|
||||||
token = None
|
|
||||||
now = 0
|
|
||||||
|
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
|
self.device_id = None
|
||||||
|
self.ip = None
|
||||||
|
self.hash_pwd = None
|
||||||
|
self.token = None
|
||||||
|
self.now = 0
|
||||||
|
|
||||||
def set_name(self, name: str):
|
def set_name(self, name: str):
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -230,11 +251,10 @@ class UserLogin(User):
|
|||||||
|
|
||||||
|
|
||||||
class UserAuth(User):
|
class UserAuth(User):
|
||||||
token = None
|
|
||||||
|
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
|
self.token = None
|
||||||
|
|
||||||
def token_get_id(self):
|
def token_get_id(self):
|
||||||
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
# 用token获取id,没有考虑不同用户token相同情况,说不定会有bug
|
||||||
@@ -248,33 +268,155 @@ class UserAuth(User):
|
|||||||
|
|
||||||
return self.user_id
|
return self.user_id
|
||||||
|
|
||||||
def code_get_id(self):
|
|
||||||
# 用user_code获取id
|
|
||||||
|
|
||||||
self.c.execute('''select user_id from user where user_code = :a''',
|
|
||||||
{'a': self.user_code})
|
|
||||||
x = self.c.fetchone()
|
|
||||||
|
|
||||||
if x is not None:
|
|
||||||
self.user_id = x[0]
|
|
||||||
else:
|
|
||||||
raise NoData('No user.', 401, -3)
|
|
||||||
|
|
||||||
return self.user_id
|
|
||||||
|
|
||||||
|
|
||||||
class UserOnline(User):
|
class UserOnline(User):
|
||||||
character = None
|
|
||||||
|
|
||||||
def __init__(self, c, user_id=None) -> None:
|
def __init__(self, c, user_id=None) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
self.user_id = user_id
|
self.user_id = user_id
|
||||||
|
self.character = None
|
||||||
|
self.is_skill_sealed = False
|
||||||
|
self.is_hide_rating = False
|
||||||
|
self.recent_score = Score()
|
||||||
|
self.favorite_character = -1
|
||||||
|
self.max_stamina_notification_enabled = False
|
||||||
|
self.prog_boost = 0
|
||||||
|
|
||||||
|
self.__cores = None
|
||||||
|
self.__friends = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cores(self) -> list:
|
||||||
|
if self.__cores is None:
|
||||||
|
self.__cores = get_user_cores(self.c, self)
|
||||||
|
|
||||||
|
return self.__cores
|
||||||
|
|
||||||
|
@property
|
||||||
|
def friends(self) -> list:
|
||||||
|
# 得到用户的朋友列表
|
||||||
|
if self.__friends is None:
|
||||||
|
self.c.execute('''select user_id_other from friend where user_id_me = :user_id''', {
|
||||||
|
'user_id': self.user_id})
|
||||||
|
x = self.c.fetchall()
|
||||||
|
s = []
|
||||||
|
if x != [] and x[0][0] is not None:
|
||||||
|
for i in x:
|
||||||
|
self.c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||||
|
{'x': i[0], 'y': self.user_id})
|
||||||
|
|
||||||
|
is_mutual = True if self.c.fetchone() == (1,) else False
|
||||||
|
|
||||||
|
you = UserOnline(self.c, i[0])
|
||||||
|
you.select_user()
|
||||||
|
character = you.character if you.favorite_character is None else you.favorite_character
|
||||||
|
character.select_character_uncap_condition(you)
|
||||||
|
|
||||||
|
rating = you.rating_ptt if not you.is_hide_rating else -1
|
||||||
|
|
||||||
|
s.append({
|
||||||
|
"is_mutual": is_mutual,
|
||||||
|
"is_char_uncapped_override": character.is_uncapped_override,
|
||||||
|
"is_char_uncapped": character.is_uncapped,
|
||||||
|
"is_skill_sealed": you.is_skill_sealed,
|
||||||
|
"rating": rating,
|
||||||
|
"join_date": you.join_date,
|
||||||
|
"character": character.character_id,
|
||||||
|
"recent_score": you.recent_score_list,
|
||||||
|
"name": you.name,
|
||||||
|
"user_id": you.user_id
|
||||||
|
})
|
||||||
|
s.sort(key=lambda item: item["recent_score"][0]["time_played"] if len(
|
||||||
|
item["recent_score"]) > 0 else 0, reverse=True)
|
||||||
|
self.__friends = s
|
||||||
|
|
||||||
|
return self.__friends
|
||||||
|
|
||||||
|
@property
|
||||||
|
def recent_score_list(self) -> list:
|
||||||
|
# 用户最近一次成绩,是列表
|
||||||
|
if self.name is None:
|
||||||
|
self.select_user()
|
||||||
|
|
||||||
|
if self.recent_score.song.song_id is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
self.c.execute('''select best_clear_type from best_score where user_id=:u and song_id=:s and difficulty=:d''', {
|
||||||
|
'u': self.user_id, 's': self.recent_score.song.song_id, 'd': self.recent_score.song.difficulty})
|
||||||
|
y = self.c.fetchone()
|
||||||
|
best_clear_type = y[0] if y is not None else self.recent_score.clear_type
|
||||||
|
|
||||||
|
r = self.recent_score.to_dict
|
||||||
|
r["best_clear_type"] = best_clear_type
|
||||||
|
return [r]
|
||||||
|
|
||||||
def change_character(self, character_id: int, skill_sealed: bool = False):
|
def change_character(self, character_id: int, skill_sealed: bool = False):
|
||||||
# 用户角色改变,包括技能封印的改变
|
# 用户角色改变,包括技能封印的改变
|
||||||
self.character = UserCharacter(self.c, character_id)
|
self.character = UserCharacter(self.c, character_id)
|
||||||
self.character.select_character_uncap_condition(self)
|
self.character.select_character_uncap_condition(self)
|
||||||
|
self.is_skill_sealed = skill_sealed
|
||||||
|
|
||||||
self.c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
self.c.execute('''update user set is_skill_sealed = :a, character_id = :b, is_char_uncapped = :c, is_char_uncapped_override = :d where user_id = :e''', {
|
||||||
'a': 1 if skill_sealed else 0, 'b': self.character.character_id, 'c': self.character.is_uncapped, 'd': self.character.is_uncapped_override, 'e': self.user_id})
|
'a': 1 if self.is_skill_sealed else 0, 'b': self.character.character_id, 'c': self.character.is_uncapped, 'd': self.character.is_uncapped_override, 'e': self.user_id})
|
||||||
|
|
||||||
|
def select_user(self):
|
||||||
|
# 查user表所有信息
|
||||||
|
self.c.execute(
|
||||||
|
'''select * from user where user_id = :x''', {'x': self.user_id})
|
||||||
|
x = self.c.fetchone()
|
||||||
|
if not x:
|
||||||
|
raise NoData('No user.', 108, -3)
|
||||||
|
|
||||||
|
self.name = x[1]
|
||||||
|
self.join_date = int(x[3])
|
||||||
|
self.user_code = x[4]
|
||||||
|
self.rating_ptt = x[5]
|
||||||
|
self.character = UserCharacter(self.c, x[6])
|
||||||
|
self.is_skill_sealed = x[7] == 1
|
||||||
|
self.character.is_uncapped = x[8] == 1
|
||||||
|
self.character.is_uncapped_override = x[9] == 1
|
||||||
|
self.is_hide_rating = x[10] == 1
|
||||||
|
|
||||||
|
self.recent_score.song.song_id = x[11]
|
||||||
|
self.recent_score.song.difficulty = x[12]
|
||||||
|
self.recent_score.set_score(
|
||||||
|
x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21])
|
||||||
|
self.recent_score.rating = x[22]
|
||||||
|
|
||||||
|
self.favorite_character = None if x[23] == - \
|
||||||
|
1 else UserCharacter(self.c, x[23])
|
||||||
|
self.max_stamina_notification_enabled = x[24] == 1
|
||||||
|
self.current_map = Map(x[25])
|
||||||
|
self.ticket = x[26]
|
||||||
|
self.prog_boost = x[27]
|
||||||
|
self.email = x[28]
|
||||||
|
self.world_rank_score = x[29]
|
||||||
|
self.ban_flag = x[30]
|
||||||
|
|
||||||
|
self.next_fragstam_ts = x[31]
|
||||||
|
self.max_stamina_ts = x[32]
|
||||||
|
self.stamina = x[33]
|
||||||
|
|
||||||
|
def add_friend(self, friend_id: int):
|
||||||
|
# 加好友
|
||||||
|
if self.user_id == friend_id:
|
||||||
|
raise FriendError('Add yourself as a friend.', 604)
|
||||||
|
|
||||||
|
self.c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||||
|
{'x': self.user_id, 'y': friend_id})
|
||||||
|
if self.c.fetchone() == (0,):
|
||||||
|
self.c.execute('''insert into friend values(:a, :b)''', {
|
||||||
|
'a': self.user_id, 'b': friend_id})
|
||||||
|
else:
|
||||||
|
raise FriendError('The user has been your friend.', 602)
|
||||||
|
|
||||||
|
def delete_friend(self, friend_id: int):
|
||||||
|
# 删好友
|
||||||
|
|
||||||
|
self.c.execute('''select exists(select * from friend where user_id_me = :x and user_id_other = :y)''',
|
||||||
|
{'x': self.user_id, 'y': friend_id})
|
||||||
|
if self.c.fetchone() == (1,):
|
||||||
|
self.c.execute('''delete from friend where user_id_me = :x and user_id_other = :y''',
|
||||||
|
{'x': self.user_id, 'y': friend_id})
|
||||||
|
else:
|
||||||
|
raise FriendError('No user or the user is not your friend.', 401)
|
||||||
|
|||||||
3
latest version/core/world.py
Normal file
3
latest version/core/world.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class Map:
|
||||||
|
def __init__(self, map_id: str = None) -> None:
|
||||||
|
self.map_id = map_id
|
||||||
Binary file not shown.
@@ -4,7 +4,7 @@ import json
|
|||||||
|
|
||||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
||||||
|
|
||||||
ARCAEA_SERVER_VERSION = 'v2.8.5'
|
ARCAEA_SERVER_VERSION = 'v2.8.6'
|
||||||
|
|
||||||
|
|
||||||
def main(path='./'):
|
def main(path='./'):
|
||||||
@@ -387,7 +387,7 @@ def main(path='./'):
|
|||||||
c.execute('''insert into item values(?,"core",1,'')''', (i,))
|
c.execute('''insert into item values(?,"core",1,'')''', (i,))
|
||||||
|
|
||||||
world_songs = ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster",
|
world_songs = ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster",
|
||||||
"cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take", "lifeispiano", "vandalism", "nexttoyou3", "lostcivilization3", "turbocharger", "bookmaker3", "laqryma3", "kyogenkigo", "hivemind", "seclusion", "quonwacca3", "bluecomet", "energysynergymatrix", "gengaozo", "lastendconductor3", "antithese3", "qualia3", "kanagawa3", "heavensdoor3", "pragmatism3", "nulctrl", "avril", "ddd", "merlin3", "omakeno3", "nekonote"]
|
"cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take", "lifeispiano", "vandalism", "nexttoyou3", "lostcivilization3", "turbocharger", "bookmaker3", "laqryma3", "kyogenkigo", "hivemind", "seclusion", "quonwacca3", "bluecomet", "energysynergymatrix", "gengaozo", "lastendconductor3", "antithese3", "qualia3", "kanagawa3", "heavensdoor3", "pragmatism3", "nulctrl", "avril", "ddd", "merlin3", "omakeno3", "nekonote", "sanskia"]
|
||||||
for i in world_songs:
|
for i in world_songs:
|
||||||
c.execute('''insert into item values(?,"world_song",1,'')''', (i,))
|
c.execute('''insert into item values(?,"world_song",1,'')''', (i,))
|
||||||
|
|
||||||
|
|||||||
@@ -1180,5 +1180,23 @@
|
|||||||
],
|
],
|
||||||
"orig_price": 100,
|
"orig_price": 100,
|
||||||
"price": 100
|
"price": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mu",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "single",
|
||||||
|
"id": "mu",
|
||||||
|
"is_available": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "core",
|
||||||
|
"amount": 1,
|
||||||
|
"id": "core_generic",
|
||||||
|
"is_available": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -226,85 +226,6 @@ def user_me(user_id):
|
|||||||
return error_return(108)
|
return error_return(108)
|
||||||
|
|
||||||
|
|
||||||
# 角色觉醒
|
|
||||||
@app.route(add_url_prefix('/<path:path>/uncap', True), methods=['POST'])
|
|
||||||
@server.auth.auth_required(request)
|
|
||||||
def character_first_uncap(user_id, path):
|
|
||||||
character_id = int(path[path.find('character')+10:])
|
|
||||||
r = server.character.char_uncap(user_id, character_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
# 角色使用以太之滴
|
|
||||||
@app.route(add_url_prefix('/<path:path>/exp', True), methods=['POST'])
|
|
||||||
@server.auth.auth_required(request)
|
|
||||||
def character_exp(user_id, path):
|
|
||||||
character_id = int(path[path.find('character')+10:])
|
|
||||||
amount = int(request.form['amount'])
|
|
||||||
r = server.character.char_use_core(user_id, character_id, amount)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": r
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route(add_url_prefix('/friend/me/add'), methods=['POST']) # 加好友
|
|
||||||
@server.auth.auth_required(request)
|
|
||||||
def add_friend(user_id):
|
|
||||||
friend_code = request.form['friend_code']
|
|
||||||
friend_id = server.auth.code_get_id(friend_code)
|
|
||||||
if friend_id is not None:
|
|
||||||
r = server.setme.arc_add_friend(user_id, friend_id)
|
|
||||||
if r is not None and r != 602 and r != 604:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
if r is not None:
|
|
||||||
return error_return(r)
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(401)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route(add_url_prefix('/friend/me/delete'), methods=['POST']) # 删好友
|
|
||||||
@server.auth.auth_required(request)
|
|
||||||
def delete_friend(user_id):
|
|
||||||
friend_id = int(request.form['friend_id'])
|
|
||||||
if friend_id is not None:
|
|
||||||
r = server.setme.arc_delete_friend(user_id, friend_id)
|
|
||||||
if r is not None:
|
|
||||||
return jsonify({
|
|
||||||
"success": True,
|
|
||||||
"value": {
|
|
||||||
"user_id": user_id,
|
|
||||||
"updatedAt": "2020-09-07T07:32:12.740Z",
|
|
||||||
"createdAt": "2020-09-06T10:05:18.471Z",
|
|
||||||
"friends": r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
return error_return(108)
|
|
||||||
else:
|
|
||||||
return error_return(401)
|
|
||||||
|
|
||||||
|
|
||||||
# 好友排名,默认最多50
|
# 好友排名,默认最多50
|
||||||
@app.route(add_url_prefix('/score/song/friend'), methods=['GET'])
|
@app.route(add_url_prefix('/score/song/friend'), methods=['GET'])
|
||||||
@server.auth.auth_required(request)
|
@server.auth.auth_required(request)
|
||||||
@@ -701,10 +622,10 @@ def multiplayer_update(user_id):
|
|||||||
return error_return(error_code), 400
|
return error_return(error_code), 400
|
||||||
|
|
||||||
|
|
||||||
@app.route(add_url_prefix('/user/me/request_delete'), methods=['POST']) # 删除账号
|
# @app.route(add_url_prefix('/user/me/request_delete'), methods=['POST']) # 删除账号
|
||||||
@server.auth.auth_required(request)
|
# @server.auth.auth_required(request)
|
||||||
def user_delete(user_id):
|
# def user_delete(user_id):
|
||||||
return error_return(151), 404
|
# return error_return(151), 404
|
||||||
|
|
||||||
|
|
||||||
# 三个设置,写在最后降低优先级
|
# 三个设置,写在最后降低优先级
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ from flask import Blueprint
|
|||||||
from setting import Config
|
from setting import Config
|
||||||
from . import user
|
from . import user
|
||||||
from . import auth
|
from . import auth
|
||||||
|
from . import friend
|
||||||
|
|
||||||
bp = Blueprint('server', __name__, url_prefix=Config.GAME_API_PREFIX)
|
bp = Blueprint('server', __name__, url_prefix=Config.GAME_API_PREFIX)
|
||||||
bp.register_blueprint(user.bp)
|
bp.register_blueprint(user.bp)
|
||||||
bp.register_blueprint(auth.bp)
|
bp.register_blueprint(auth.bp)
|
||||||
|
bp.register_blueprint(friend.bp)
|
||||||
|
|||||||
@@ -1149,4 +1149,10 @@ class Constant:
|
|||||||
}, {
|
}, {
|
||||||
"unlock_key": "cyberneciacatharsis|2|0",
|
"unlock_key": "cyberneciacatharsis|2|0",
|
||||||
"complete": 1
|
"complete": 1
|
||||||
|
}, {
|
||||||
|
"unlock_key": "sanskia|1|0",
|
||||||
|
"complete": 1
|
||||||
|
}, {
|
||||||
|
"unlock_key": "sanskia|2|0",
|
||||||
|
"complete": 1
|
||||||
}]
|
}]
|
||||||
|
|||||||
49
latest version/server/friend.py
Normal file
49
latest version/server/friend.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
from flask import Blueprint, request
|
||||||
|
from core.sql import Connect
|
||||||
|
from core.error import ArcError
|
||||||
|
from core.user import UserOnline, code_get_id
|
||||||
|
from .func import error_return, success_return
|
||||||
|
from .auth import auth_required
|
||||||
|
|
||||||
|
bp = Blueprint('friend', __name__, url_prefix='/friend')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/add', methods=['POST']) # 加好友
|
||||||
|
@auth_required(request)
|
||||||
|
def add_friend(user_id):
|
||||||
|
with Connect() as c:
|
||||||
|
try:
|
||||||
|
friend_code = request.form['friend_code']
|
||||||
|
friend_id = code_get_id(c, friend_code)
|
||||||
|
user = UserOnline(c, user_id)
|
||||||
|
user.add_friend(friend_id)
|
||||||
|
|
||||||
|
return success_return({
|
||||||
|
"user_id": user.user_id,
|
||||||
|
"updatedAt": "2020-09-07T07:32:12.740Z",
|
||||||
|
"createdAt": "2020-09-06T10:05:18.471Z",
|
||||||
|
"friends": user.friends
|
||||||
|
})
|
||||||
|
except ArcError as e:
|
||||||
|
return error_return(e)
|
||||||
|
return error_return()
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/delete', methods=['POST']) # 删好友
|
||||||
|
@auth_required(request)
|
||||||
|
def delete_friend(user_id):
|
||||||
|
with Connect() as c:
|
||||||
|
try:
|
||||||
|
friend_id = int(request.form['friend_id'])
|
||||||
|
user = UserOnline(c, user_id)
|
||||||
|
user.delete_friend(friend_id)
|
||||||
|
|
||||||
|
return success_return({
|
||||||
|
"user_id": user.user_id,
|
||||||
|
"updatedAt": "2020-09-07T07:32:12.740Z",
|
||||||
|
"createdAt": "2020-09-06T10:05:18.471Z",
|
||||||
|
"friends": user.friends
|
||||||
|
})
|
||||||
|
except ArcError as e:
|
||||||
|
return error_return(e)
|
||||||
|
return error_return()
|
||||||
@@ -3,6 +3,7 @@ from core.error import ArcError, NoAccess
|
|||||||
from core.sql import Connect
|
from core.sql import Connect
|
||||||
from core.user import UserRegister, UserLogin, User, UserOnline
|
from core.user import UserRegister, UserLogin, User, UserOnline
|
||||||
from core.character import UserCharacter
|
from core.character import UserCharacter
|
||||||
|
from core.item import ItemCore
|
||||||
from .func import error_return, success_return
|
from .func import error_return, success_return
|
||||||
from .auth import auth_required
|
from .auth import auth_required
|
||||||
from setting import Config
|
from setting import Config
|
||||||
@@ -63,11 +64,49 @@ def toggle_uncap(user_id, character_id):
|
|||||||
try:
|
try:
|
||||||
user = User()
|
user = User()
|
||||||
user.user_id = user_id
|
user.user_id = user_id
|
||||||
character = UserCharacter(c)
|
character = UserCharacter(c, character_id)
|
||||||
character.character_id = character_id
|
|
||||||
character.change_uncap_override(user)
|
character.change_uncap_override(user)
|
||||||
character.select_character_info(user)
|
character.select_character_info(user)
|
||||||
return success_return({'user_id': user.user_id, 'character': [character.to_dict]})
|
return success_return({'user_id': user.user_id, 'character': [character.to_dict]})
|
||||||
except ArcError as e:
|
except ArcError as e:
|
||||||
return error_return(e)
|
return error_return(e)
|
||||||
return error_return()
|
return error_return()
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/character/<int:character_id>/uncap', methods=['POST']) # 角色觉醒
|
||||||
|
@auth_required(request)
|
||||||
|
def character_first_uncap(user_id, character_id):
|
||||||
|
with Connect() as c:
|
||||||
|
try:
|
||||||
|
user = UserOnline(c, user_id)
|
||||||
|
character = UserCharacter(c, character_id)
|
||||||
|
character.select_character_info(user)
|
||||||
|
character.character_uncap(user)
|
||||||
|
return success_return({'user_id': user.user_id, 'character': [character.to_dict], 'cores': user.cores})
|
||||||
|
except ArcError as e:
|
||||||
|
return error_return(e)
|
||||||
|
return error_return()
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/character/<int:character_id>/exp', methods=['POST']) # 角色使用以太之滴
|
||||||
|
@auth_required(request)
|
||||||
|
def character_exp(user_id, character_id):
|
||||||
|
with Connect() as c:
|
||||||
|
try:
|
||||||
|
user = UserOnline(c, user_id)
|
||||||
|
character = UserCharacter(c, character_id)
|
||||||
|
character.select_character_info(user)
|
||||||
|
core = ItemCore(c)
|
||||||
|
core.amount = - int(request.form['amount'])
|
||||||
|
core.item_id = 'core_generic'
|
||||||
|
character.upgrade_by_core(user, core)
|
||||||
|
return success_return({'user_id': user.user_id, 'character': [character.to_dict], 'cores': user.cores})
|
||||||
|
except ArcError as e:
|
||||||
|
return error_return(e)
|
||||||
|
return error_return()
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/request_delete', methods=['POST']) # 删除账号
|
||||||
|
@auth_required(request)
|
||||||
|
def user_delete(user_id):
|
||||||
|
return error_return(ArcError('Cannot delete the account.', 151)), 404
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class Config():
|
|||||||
Allowed game versions
|
Allowed game versions
|
||||||
If it is blank, all are allowed.
|
If it is blank, all are allowed.
|
||||||
'''
|
'''
|
||||||
ALLOW_APPVERSION = ['3.12.6', '3.12.6c', '3.12.8', '3.12.8c']
|
ALLOW_APPVERSION = ['3.12.6', '3.12.6c', '3.12.10', '3.12.10c']
|
||||||
'''
|
'''
|
||||||
--------------------
|
--------------------
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ class Room:
|
|||||||
|
|
||||||
def is_finish(self):
|
def is_finish(self):
|
||||||
# 是否全部进入结算
|
# 是否全部进入结算
|
||||||
|
if self.state == 8:
|
||||||
|
return False
|
||||||
|
|
||||||
for i in self.players:
|
for i in self.players:
|
||||||
if i.player_id != 0 and (i.finish_flag == 0 or i.online == 0):
|
if i.player_id != 0 and (i.finish_flag == 0 or i.online == 0):
|
||||||
return False
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user