mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2025-12-14 08:06:23 +08:00
Ready to Update to v2.9
- Add support for finale state data
This commit is contained in:
40
README.md
40
README.md
@@ -21,6 +21,7 @@ This procedure is mainly used for study and research, and shall not be used for
|
||||
- PTT
|
||||
- 世界排名 Global rank
|
||||
- 排名 Rank
|
||||
- 段位系统 Course system
|
||||
- Link Play
|
||||
- 好友系统 Friends
|
||||
- 数据同步 Data synchronization
|
||||
@@ -66,23 +67,30 @@ It is just so interesting. What it can do is under exploration.
|
||||
> Tips: When updating, please keep the original database in case of data loss.
|
||||
|
||||
|
||||
### Version 2.8.5
|
||||
- 适用于Arcaea 3.12.8版本 For Arcaea 3.12.8
|
||||
- 更新了歌曲数据库 Update the song database.
|
||||
- 修复一个导致无法升级角色的拼写错误 Fix a typing error, which makes giving characters Exp wrong.
|
||||
- 尝试强制指定多进程启动方式为spawn,这可能对UNIX系统中UDP服务器的启动有所帮助 Try to forcibly specify the multiprocess startup mode as spawn, which may be helpful for the startup of UDP server in UNIX system.
|
||||
- 添加了注册API对外接口 Add an external API interface of user register.
|
||||
- 重构一些代码,顺手修复了登陆时因多设备登录封号的用户没有正确显示错误提示的问题 Refactoring some codes and in passing fix the problem that users which has been banned because of multiple devices do not show error messages correctly when logging in.
|
||||
### Version 2.9
|
||||
- 适用于Arcaea 4.0.0版本 For Arcaea 4.0.0
|
||||
- 新增段位/课题模式 Add Dan/Course Mode.
|
||||
- 新搭档 **光(Fatalis)** 已解锁 Unlock the character **Hikari(Fatalis)**.
|
||||
- 新增对`光(Fatalis)`的技能的支持 Add support for the skill of `Hikari(Fatalis)`.
|
||||
- 新增对额外文件下载的支持 Add support for downloading additional files.
|
||||
- 新增对`结局挑战`的云端存档的支持 Add support for the cloud save of `finale challenge`.
|
||||
- 修复`Link Play`模式下当房主退出时,新房主没有立即显示的问题 Fix a bug that the other player will not become the host of the room at once, when the player disconnect in `Link Play`.
|
||||
- 修改了`Link Play`模式的一些时间常数 Change some constants of time in `Link Play` mode.
|
||||
- 重构一些代码,可能引入了新Bug Refactoring some codes and there may be more bugs.
|
||||
|
||||
- 以下是累积更新 The following are cumulative updates:
|
||||
- 修复一个`v2.8.5`版本引入的有关无法加好友的问题 Fix a bug of unable to add friend which arose in the `version 2.8.5`.
|
||||
- 修复`Link Play`模式下重复计算歌曲完成状态的问题 Fix a bug of duplicate calculating finishing states when players finish playing the chart in `Link Play`.
|
||||
|
||||
> 注意:
|
||||
> - 现在Flask最低版本要求提高到2.0
|
||||
> - 服务端可能不再完全支持低版本客户端
|
||||
> - 对3.12.6c版本,愚人节开关打开时点击`网络`按钮会闪退,原因不明
|
||||
> - 不再提供歌曲数据
|
||||
> - 目前尽量不会对前端web页面增补功能
|
||||
> - `对立`不会死
|
||||
>
|
||||
> Note:
|
||||
> - Now the version of Flask which is required should be up to 2.0.
|
||||
> - The server may no longer fully support lower version clients.
|
||||
> - For version 3.12.6c, when the switch of April Fool's Day is on, clicking the `Network` button will make the client break down. The reason is not clear now.
|
||||
> - No longer provide song data.
|
||||
> - Since now, probably not add functions to the front-end web pages.
|
||||
> - `Tairitsu` will not die.
|
||||
|
||||
|
||||
|
||||
@@ -109,8 +117,10 @@ It is just so interesting. What it can do is under exploration.
|
||||
|
||||
|
||||
## 鸣谢 Thanks
|
||||
歌曲数据库来自 Using song database from
|
||||
[BotArcAPI releases](https://github.com/TheSnowfield/BotArcAPI/releases)
|
||||
~~歌曲数据库来自 Using song database from
|
||||
[BotArcAPI releases](https://github.com/TheSnowfield/BotArcAPI/releases)~~
|
||||
> 从v2.9开始不再提供歌曲数据
|
||||
> Since v2.9, song data will not be provided.
|
||||
|
||||
网站图标来自 Using favicon from [black fate - てんてん - pixiv](https://www.pixiv.net/artworks/82374369)
|
||||
|
||||
|
||||
@@ -37,3 +37,48 @@ class Constant:
|
||||
LINK_PLAY_TIMEOUT = 10 # Units: seconds
|
||||
|
||||
COURSE_STAMINA_COST = 4
|
||||
|
||||
# Well, I can't say a word when I see this.
|
||||
SHIT_DATA_OF_616 = [
|
||||
(0x0015F0, 0x00B032), (0x014C9A, 0x014408), (0x062585, 0x02783B),
|
||||
(0x02429E, 0x0449A4), (0x099C9C,
|
||||
0x07CFB4), (0x0785BF, 0x019B2C),
|
||||
(0x0EFF43, 0x0841BF), (0x07C88B,
|
||||
0x0DE9FC), (0x000778, 0x064815),
|
||||
(0x0E62E3, 0x079F02), (0x0188FE,
|
||||
0x0923EB), (0x0E06CD, 0x0E1A26),
|
||||
(0x00669E, 0x0C8BE1), (0x0BEB7A, 0x05D635), (0x040E6F,
|
||||
0x0B465B), (0x0568EC, 0x07ED2B),
|
||||
(0x189614, 0x00A3D2), (0x62D98D,
|
||||
0x45E5CA), (0x6D8769, 0x473F0E),
|
||||
(0x922E4F, 0x667D6C), (0x021F5C,
|
||||
0x298839), (0x2A1201, 0x49FB7E),
|
||||
(0x158B81, 0x8D905D), (0x2253A5,
|
||||
0x7E7067), (0x3BEF79, 0x9368E9),
|
||||
(0x00669E, 0x0C8BE1), (0x0BEB7A,
|
||||
0x05D635), (0x040E6F, 0x0B465B),
|
||||
(0x756276, 0x55CD57), (0x130055, 0x7010E7), (0x55E28D,
|
||||
0x4477FB), (0x5E99CB, 0x81060E),
|
||||
(0x7F43A4, 0x8FEC56), (0x69412F,
|
||||
0x32735C), (0x8FF846, 0x14B5A1),
|
||||
(0x8716BE, 0x5C78BE), (0x62ED0E,
|
||||
0x348E4B), (0x4B20C8, 0x56E0C3),
|
||||
(0x0AF6BC, 0x872441), (0x8825BC,
|
||||
0x94B315), (0x792784, 0x5B2C8E),
|
||||
(0x1AE3A7, 0x688E97), (0x0D630F,
|
||||
0x06BE78), (0x792784, 0x5B2C8E),
|
||||
(0x314869, 0x41CCC1), (0x311934, 0x24DD94), (0x190EDB,
|
||||
0x33993D), (0x25F5C5, 0x15FAE6),
|
||||
(0x18CA10, 0x1B761A), (0x51BE82,
|
||||
0x120089), (0x51D3B6, 0x2C29A2),
|
||||
(0x402075, 0x4A89B2), (0x00697B,
|
||||
0x0E6497), (0x6D872D, 0x618AE7),
|
||||
(0x3DC0BE, 0x4E2AC8), (0x8C6ACF,
|
||||
0x9776CF), (0x84673B, 0x5CA060),
|
||||
(0x4B05EC, 0x97FDFE), (0x207258,
|
||||
0x02BB9B), (0x20A9EE, 0x1BA4BB),
|
||||
(0x503D21, 0x6A41D0), (0x1C256C,
|
||||
0x6DD3BC), (0x6E4E0C, 0x89FDAA), (0x3C5F95, 0x3BA786)
|
||||
]
|
||||
UNKNOWN_SHIT = [0XFEA5, 0X7BF653, 0X46BEA7B,
|
||||
0X8BFB04, 0X5D6FC5, 0X237206D, 0XA3DEE, 0XA35687B]
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from .util import md5
|
||||
from .error import InputError
|
||||
from setting import Config
|
||||
from time import time
|
||||
import json
|
||||
from time import time
|
||||
|
||||
from setting import Config
|
||||
|
||||
from core.constant import Constant
|
||||
|
||||
from .error import InputError
|
||||
from .util import md5
|
||||
|
||||
|
||||
class SaveData:
|
||||
@@ -17,7 +21,7 @@ class SaveData:
|
||||
self.devicemodelname_data: str = ''
|
||||
self.story_data = []
|
||||
self.createdAt: int = 0
|
||||
self.finalestate_data: str = "0|100|5616|85146|402821|148126|629916|492991|982851|510091|1912|942819|100606|919245|26270|781178|265839|354540|1611284|6478221|7178089|9580111|139100|2757121|1411969|2249637|3927929|26270|781178|265839|7692918|1245269|5628557|6199755|8340388|6897967|9435206|8853182|6483214|4923592|718524|8922556|7939972|1762215|877327|7939972|3229801|3217716|1642203|2487749|1624592|5357186|5362614|4202613|27003|7178029|4047038|9202383|8677179|4916716|2126424|2140654|5258529|1844588|7228940|3956629|65189|8123987|74181243|9173764|6123461|37167213|671214|171272315|1337"
|
||||
self.finalestate_data: str = ''
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@@ -47,9 +51,9 @@ class SaveData:
|
||||
"val": 1
|
||||
},
|
||||
"createdAt": self.createdAt,
|
||||
# 'finalestate': {
|
||||
# 'val': self.finalestate_data
|
||||
# }
|
||||
'finalestate': {
|
||||
'val': self.finalestate_data
|
||||
}
|
||||
}
|
||||
|
||||
def select_all(self, user) -> None:
|
||||
@@ -70,6 +74,7 @@ class SaveData:
|
||||
self.story_data = json.loads(x[7])[""]
|
||||
if x[8] is not None:
|
||||
self.createdAt = int(x[8])
|
||||
self.finalestate_data = x[9] if x[9] is not None else ''
|
||||
|
||||
if Config.SAVE_FULL_UNLOCK:
|
||||
self.installid_data = "0fcec8ed-7b62-48e2-9d61-55041a22b123" # 使得可以进入存档选择上传或下载界面
|
||||
@@ -88,6 +93,9 @@ class SaveData:
|
||||
else:
|
||||
i['complete'] = 1
|
||||
|
||||
self.finalestate_data = '|'.join(['0', '100'] + [str(i[1]) for i in Constant.SHIT_DATA_OF_616] + [
|
||||
str(i) for i in Constant.UNKNOWN_SHIT] + ['1337'])
|
||||
|
||||
def update_all(self, user) -> None:
|
||||
'''
|
||||
parameter: `user` - `User`类或子类的实例
|
||||
@@ -95,8 +103,8 @@ class SaveData:
|
||||
self.createdAt = int(time() * 1000)
|
||||
self.c.execute('''delete from user_save where user_id=:a''', {
|
||||
'a': user.user_id})
|
||||
self.c.execute('''insert into user_save values(:a,:b,:c,:d,:e,:f,:g,:h,:i)''', {
|
||||
'a': user.user_id, 'b': json.dumps({'': self.scores_data}), 'c': json.dumps({'': self.clearlamps_data}), 'd': json.dumps({'': self.clearedsongs_data}), 'e': json.dumps({'': self.unlocklist_data}), 'f': json.dumps({'val': self.installid_data}), 'g': json.dumps({'val': self.devicemodelname_data}), 'h': json.dumps({'': self.story_data}), 'i': self.createdAt})
|
||||
self.c.execute('''insert into user_save values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j)''', {
|
||||
'a': user.user_id, 'b': json.dumps({'': self.scores_data}), 'c': json.dumps({'': self.clearlamps_data}), 'd': json.dumps({'': self.clearedsongs_data}), 'e': json.dumps({'': self.unlocklist_data}), 'f': json.dumps({'val': self.installid_data}), 'g': json.dumps({'val': self.devicemodelname_data}), 'h': json.dumps({'': self.story_data}), 'i': self.createdAt, 'j': self.finalestate_data})
|
||||
|
||||
def set_value(self, key: str, value: str, checksum: str) -> None:
|
||||
'''
|
||||
@@ -107,7 +115,7 @@ class SaveData:
|
||||
'Property `%s` is not found in the instance of `SaveData` class.' % key)
|
||||
|
||||
if md5(value) == checksum:
|
||||
if key == 'installid_data' or key == 'devicemodelname_data':
|
||||
if key == 'installid_data' or key == 'devicemodelname_data' or key == 'finalestate_data':
|
||||
self.__dict__[key] = json.loads(value)['val']
|
||||
else:
|
||||
self.__dict__[key] = json.loads(value)['']
|
||||
|
||||
@@ -4,7 +4,7 @@ import json
|
||||
|
||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
||||
|
||||
ARCAEA_SERVER_VERSION = 'v2.8.9.dev.616sb'
|
||||
ARCAEA_SERVER_VERSION = 'v2.9.0'
|
||||
|
||||
|
||||
def main(path='./'):
|
||||
@@ -245,7 +245,8 @@ def main(path='./'):
|
||||
installid_data text,
|
||||
devicemodelname_data text,
|
||||
story_data text,
|
||||
createdAt int
|
||||
createdAt int,
|
||||
finalestate_data text
|
||||
);''')
|
||||
c.execute('''create table if not exists present(present_id text primary key,
|
||||
expire_ts int,
|
||||
@@ -481,15 +482,21 @@ def main(path='./'):
|
||||
(i['name'], j['id'], j['type'], amount))
|
||||
|
||||
# item初始化
|
||||
f = open(path+'singles.json', 'r')
|
||||
singles = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, singles)
|
||||
try:
|
||||
f = open(path+'singles.json', 'r')
|
||||
singles = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, singles)
|
||||
except:
|
||||
pass
|
||||
|
||||
f = open(path+'packs.json', 'r')
|
||||
packs = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, packs)
|
||||
try:
|
||||
f = open(path+'packs.json', 'r')
|
||||
packs = json.load(f)
|
||||
f.close()
|
||||
insert_items(c, packs)
|
||||
except:
|
||||
pass
|
||||
|
||||
# course初始化
|
||||
try:
|
||||
|
||||
@@ -46,9 +46,17 @@ def download_song(user_id):
|
||||
|
||||
@bp.route('/finale/progress', methods=['GET'])
|
||||
def finale_progress():
|
||||
# 世界boss血条
|
||||
return success_return({'percentage': 100000})
|
||||
|
||||
|
||||
@bp.route('/finale/finale_start', methods=['POST'])
|
||||
def finale_start():
|
||||
# testify开始,对立再见
|
||||
# 没数据
|
||||
return success_return({})
|
||||
|
||||
|
||||
map_dict = {'/user/me': user_me,
|
||||
'/purchase/bundle/pack': bundle_pack,
|
||||
'/serve/download/me/song': download_song,
|
||||
|
||||
@@ -43,6 +43,7 @@ def get_single(user_id):
|
||||
@bp.route('/bundle/bundle', methods=['GET']) # 捆绑包
|
||||
def bundle_bundle():
|
||||
return success_return([])
|
||||
# 感觉上是定死的,没意义啊
|
||||
# return success_return([{
|
||||
# "name": "chronicles",
|
||||
# "items": [{
|
||||
|
||||
@@ -158,6 +158,8 @@ def cloud_post(user_id):
|
||||
request.form['devicemodelname_data'], request.form['devicemodelname_checksum'])
|
||||
save.set_value(
|
||||
'story_data', request.form['story_data'], request.form['story_checksum'])
|
||||
save.set_value(
|
||||
'finalestate_data', request.form['finalestate_data'], request.form['finalestate_checksum'])
|
||||
|
||||
save.update_all(user)
|
||||
return success_return({'user_id': user.user_id})
|
||||
|
||||
@@ -247,6 +247,8 @@ class Config():
|
||||
--------------------
|
||||
是否强制使用全解锁云端存档
|
||||
If forcing full unlocked cloud save is enabled
|
||||
请注意,当前对于最终结局的判定为固定在`Testify`解锁之前
|
||||
Please note that the current setting of the finale state is before the unlock of `Testify`
|
||||
'''
|
||||
SAVE_FULL_UNLOCK = False
|
||||
'''
|
||||
|
||||
@@ -204,6 +204,11 @@ def update_database():
|
||||
update_one_table(c1, c2, 'role_power')
|
||||
update_one_table(c1, c2, 'api_login')
|
||||
update_one_table(c1, c2, 'chart')
|
||||
update_one_table(c1, c2, 'user_course')
|
||||
update_one_table(c1, c2, 'course')
|
||||
update_one_table(c1, c2, 'course_item')
|
||||
update_one_table(c1, c2, 'course_chart')
|
||||
update_one_table(c1, c2, 'course_requirement')
|
||||
|
||||
update_one_table(c1, c2, 'user_char')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user