10 Commits
v2.5 ... v2.6

Author SHA1 Message Date
Lost-MSth
9286caf900 Update to v2.6 2021-07-01 18:46:16 +08:00
Lost-MSth
b0647bedb6 Merge pull request #24 from MBRjun/patch-1
Update run.bat

To deal with the problem when you run *run.bat* with Administrator power and in another path.
2021-06-20 22:07:52 +08:00
MBRjun
f49a868707 Update run.bat 2021-06-20 22:04:41 +08:00
MBRjun
28bca25092 Update run.bat
cd %~dp0 用于cd到当前目录
使用管理员权限或Administrator账户运行脚本默认路径为%windir%\system32
2021-06-20 21:47:02 +08:00
Lost-MSth
0227d2b44a Merge pull request #22 from Menci/sort_friend_list
Sort friend list
2021-06-17 13:03:54 +08:00
Lost-MSth
0d95b886bc Merge pull request #23 from Menci/use_b10_as_r10
Add USE_B10_AS_R10 option
2021-06-17 12:53:33 +08:00
Menci
9b61acd163 Sort friend list 2021-06-17 03:04:39 +08:00
Menci
be134bbc6e Add USE_B10_AS_R10 option 2021-06-16 19:02:04 +00:00
Lost-MSth
c8d0463b9e Fix a small bug
Fix a bug about double slashes in URL, which will influence character uncap, uncap override and level up with EXP cores when you use a special game API prefix, like '/latte' or '/latte/1'.
It means that the length of game API prefix is not 2 in the end (not '/*** . . . **/**') and the bug will happen.
2021-06-14 18:04:16 +08:00
Lost-MSth
871c2082a8 Fix two small bugs
1. Rank list numbers in my world rank may disappear.
2.  Characters in rank list may be locked to uncapping state.
2021-06-10 22:27:29 +08:00
22 changed files with 1308 additions and 748 deletions

View File

@@ -62,26 +62,19 @@ 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. > Tips: When updating, please keep the original database in case of data loss.
### Version 2.5 ### Version 2.6
- 适用于Arcaea 3.6.2版本 For Arcaea 3.6.2 - 适用于Arcaea 3.6.4版本 For Arcaea 3.6.4
- 更新了歌曲数据库 Update the song database. - 更新了歌曲数据库 Update the song database.
- 新增世界排名 Add global rank. - 新增体力系统 Add stamina system.
- 新增世界模式的奖励获取 Add reward acquisition of new world mode. - 完善了登陆奖励系统 Improve the login present system.
- 完善角色系统,包括: Improve the character system, including - 完善了兑换码系统 Improve the redeem code system.
- 角色升级 Level up - 新增了多设备自动封号机制 Add multi device auto ban mechanism.
- 角色觉醒 Upcapping
- 角色核心 Character cores
- 世界模式下的数值计算 Numerical calculation in world mode
- 某些场景下的角色解锁 Character unlocking in some cases
- 新增了一些设置选项和后台功能 Add some setting options and background functions.
- 正在构建API接口 Building API interface.
- 打算重新写后台界面 Plan to rewrite the background interface.
- 修复了一些Bug Fix some bugs. - 修复了一些Bug Fix some bugs.
- 登录时获取信息的并行计算导致的数据库锁错误 Database lock error caused by parallel computing of getting information during login - 修复好友列表没有按照最近成绩日期排序的问题(Menci) Fix the friend list not sorted by last score date. (From Menci)
- 修复某些情况下跨目录运行失败的问题(MBRjun) Fix cross directory running problem in some cases. (From MBRjun)
> 提醒:由于时间仓促,本版本可能存在较多问题与漏洞,请谨慎使用 > 提醒:使用新版本前可能需要清空redeemuser_redeempresentuser_present表
> Tips: Due to lack of time, this version may have many bugs, please use it with caution. > Tips: Before using the new version, you may need to clear the redeem, user_redeem, present, user_present table.
## 运行环境与依赖 Running environment and requirements ## 运行环境与依赖 Running environment and requirements
- Windows/Linux/Mac OS/Android - Windows/Linux/Mac OS/Android
@@ -93,11 +86,11 @@ It is just so interesting. What it can do is under exploration.
## 环境搭建 Environment construction ## 环境搭建 Environment construction
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) [中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA)
[English](https://github.com/Lost-MSth/Arcaea-server/wiki/Environment-construction) [English](https://github.com/Lost-MSth/Arcaea-server/wiki/Environment-construction)
-->
## 使用说明 Instruction for use ## 使用说明 Instruction for use
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E) [中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E)
[English](https://github.com/Lost-MSth/Arcaea-server/wiki/Instruction-for-use) [English](https://github.com/Lost-MSth/Arcaea-server/wiki/Instruction-for-use)
-->
## 注意 Attentions ## 注意 Attentions
[中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E6%B3%A8%E6%84%8F) [中文](https://github.com/Lost-MSth/Arcaea-server/wiki/%E6%B3%A8%E6%84%8F)

Binary file not shown.

View File

@@ -4,7 +4,7 @@ import json
# 数据库初始化文件删掉arcaea_database.db文件后运行即可谨慎使用 # 数据库初始化文件删掉arcaea_database.db文件后运行即可谨慎使用
ARCAEA_SERVER_VERSION = 'v2.5' ARCAEA_SERVER_VERSION = 'v2.6'
def main(path='./'): def main(path='./'):
@@ -44,7 +44,11 @@ def main(path='./'):
ticket int, ticket int,
prog_boost int, prog_boost int,
email text, email text,
world_rank_score int world_rank_score int,
ban_flag text,
next_fragstam_ts int,
max_stamina_ts int,
stamina int
);''') );''')
c.execute('''create table if not exists login(access_token text, c.execute('''create table if not exists login(access_token text,
user_id int, user_id int,
@@ -238,26 +242,36 @@ def main(path='./'):
);''') );''')
c.execute('''create table if not exists present(present_id text primary key, c.execute('''create table if not exists present(present_id text primary key,
expire_ts int, expire_ts int,
items text,
description text description text
);''') );''')
c.execute('''create table if not exists user_present(user_id int, c.execute('''create table if not exists user_present(user_id int,
present_id text, present_id text,
primary key(user_id, present_id) primary key(user_id, present_id)
);''') );''')
c.execute('''create table if not exists present_item(present_id text,
item_id text,
type text,
amount int,
primary key(present_id, item_id, type)
);''')
c.execute('''create table if not exists songfile(song_id text, c.execute('''create table if not exists songfile(song_id text,
file_type int, file_type int,
md5 text, md5 text,
primary key(song_id, file_type) primary key(song_id, file_type)
);''') );''')
c.execute('''create table if not exists redeem(code text primary key, c.execute('''create table if not exists redeem(code text primary key,
items text,
type int type int
);''') );''')
c.execute('''create table if not exists user_redeem(user_id int, c.execute('''create table if not exists user_redeem(user_id int,
code text, code text,
primary key(user_id, code) primary key(user_id, code)
);''') );''')
c.execute('''create table if not exists redeem_item(code text,
item_id text,
type text,
amount int,
primary key(code, item_id, type)
);''')
c.execute('''create table if not exists role(role_id int primary key, c.execute('''create table if not exists role(role_id int primary key,
role_name text, role_name text,
@@ -284,46 +298,46 @@ def main(path='./'):
# 搭档初始化 # 搭档初始化
char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', '', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'stella', 'Hikari & Fisica', 'ilith', 'eto', 'luna', 'shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin', char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', '', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'stella', 'Hikari & Fisica', 'ilith', 'eto', 'luna', 'shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin',
'ayu', 'Eto & Luna', 'yume', 'Seine & Hikari', 'saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'haruna', 'nono', 'MTA-XXX', 'MDA-21', 'kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'sia', 'DORO*C', 'Tairitsu(Tempest)', 'brillante', 'Ilith(Summer)', 'etude', 'Alice & Tenniel', 'Luna & Mia', 'areus', 'seele', 'isabelle', 'mir', 'lagrange'] 'ayu', 'Eto & Luna', 'yume', 'Seine & Hikari', 'saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'haruna', 'nono', 'MTA-XXX', 'MDA-21', 'kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'sia', 'DORO*C', 'Tairitsu(Tempest)', 'brillante', 'Ilith(Summer)', 'etude', 'Alice & Tenniel', 'Luna & Mia', 'areus', 'seele', 'isabelle', 'mir', 'lagrange', '???', 'nami']
skill_id = ['gauge_easy', '', '', '', 'note_mirror', '', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere', skill_id = ['gauge_easy', '', '', '', 'note_mirror', '', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere',
'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange'] 'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange', 'gauge_safe_10', 'frags_nami']
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee', skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', '', '', 'shirabe_entry_fee',
'', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] '', '', '', '', '', '', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
skill_unlock_level = [0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, skill_unlock_level = [0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0,
0, 0, 0, 8, 0, 14, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0] 0, 0, 0, 8, 0, 14, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0]
frag1 = [55, 55, 60, 50, 47, 0, 47, 57, 41, 22, 50, 54, 60, 56, 78, 42, 41, 61, 52, 50, 52, 32, frag1 = [55, 55, 60, 50, 47, 0, 47, 57, 41, 22, 50, 54, 60, 56, 78, 42, 41, 61, 52, 50, 52, 32,
42, 55, 45, 58, 43, 0.5, 68, 50, 62, 45, 45, 52, 44, 27, 59, 0, 45, 50, 50, 47, 47, 61, 43, 42] 42, 55, 45, 58, 43, 0.5, 68, 50, 62, 45, 45, 52, 44, 27, 59, 0, 45, 50, 50, 47, 47, 61, 43, 42, 50, 25]
prog1 = [35, 55, 47, 50, 60, 0, 60, 70, 58, 45, 70, 45, 42, 46, 61, 67, 49, 44, 28, 45, 24, 46, 52, prog1 = [35, 55, 47, 50, 60, 0, 60, 70, 58, 45, 70, 45, 42, 46, 61, 67, 49, 44, 28, 45, 24, 46, 52,
59, 62, 33, 58, 25, 63, 69, 50, 45, 45, 51, 34, 70, 62, 70, 45, 32, 32, 61, 47, 47, 37, 42] 59, 62, 33, 58, 25, 63, 69, 50, 45, 45, 51, 34, 70, 62, 70, 45, 32, 32, 61, 47, 47, 37, 42, 50, 50]
overdrive1 = [35, 55, 25, 50, 47, 0, 72, 57, 41, 7, 10, 32, 65, 31, 61, 53, 31, 47, 38, 12, 39, 18, overdrive1 = [35, 55, 25, 50, 47, 0, 72, 57, 41, 7, 10, 32, 65, 31, 61, 53, 31, 47, 38, 12, 39, 18,
48, 65, 45, 55, 44, 25, 46, 44, 33, 45, 45, 37, 25, 27, 50, 20, 45, 63, 21, 47, 61, 47, 65, 80] 48, 65, 45, 55, 44, 25, 46, 44, 33, 45, 45, 37, 25, 27, 50, 20, 45, 63, 21, 47, 61, 47, 65, 80, 50, 30]
frag20 = [78, 80, 90, 75, 70, 0, 70, 79, 65, 40, 50, 80, 90, 82, 0, 61, 67, 92, 85, 50, 86, 52, frag20 = [78, 80, 90, 75, 70, 0, 70, 79, 65, 40, 50, 80, 90, 82, 0, 61, 67, 92, 85, 50, 86, 52,
65, 85, 67, 88, 64, 0.5, 95, 70, 95, 50, 80, 87, 71, 50, 85, 0, 80, 75, 50, 70, 70, 90, 65, 80] 65, 85, 67, 88, 64, 0.5, 95, 70, 95, 50, 80, 87, 71, 50, 85, 0, 80, 75, 50, 70, 70, 90, 65, 80, 100, 50]
prog20 = [61, 80, 70, 75, 90, 0, 90, 102, 84, 78, 105, 67, 63, 68, 0, 99, 80, 66, 46, 83, 40, 73, prog20 = [61, 80, 70, 75, 90, 0, 90, 102, 84, 78, 105, 67, 63, 68, 0, 99, 80, 66, 46, 83, 40, 73,
80, 90, 93, 50, 86, 78, 89, 98, 75, 80, 50, 64, 55, 100, 90, 110, 80, 50, 74, 90, 70, 70, 56, 80] 80, 90, 93, 50, 86, 78, 89, 98, 75, 80, 50, 64, 55, 100, 90, 110, 80, 50, 74, 90, 70, 70, 56, 80, 100, 55]
overdrive20 = [61, 80, 47, 75, 70, 0, 95, 79, 65, 31, 50, 59, 90, 58, 0, 78, 50, 70, 62, 49, 64, overdrive20 = [61, 80, 47, 75, 70, 0, 95, 79, 65, 31, 50, 59, 90, 58, 0, 78, 50, 70, 62, 49, 64,
46, 73, 95, 67, 84, 70, 78, 69, 70, 50, 80, 80, 63, 25, 50, 72, 55, 50, 95, 55, 70, 90, 70, 99, 80] 46, 73, 95, 67, 84, 70, 78, 69, 70, 50, 80, 80, 63, 25, 50, 72, 55, 50, 95, 55, 70, 90, 70, 99, 80, 100, 40]
frag30 = [88, 90, 100, 75, 80, 0, 70, 79, 65, 40, 50, 80, 90, 92, 0, 61, 67, 92, 85, 50, 86, 62, frag30 = [88, 90, 100, 75, 80, 0, 70, 79, 65, 40, 50, 80, 90, 92, 0, 61, 67, 92, 85, 50, 86, 62,
65, 85, 67, 88, 74, 0.5, 105, 80, 95, 50, 80, 87, 71, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65, 80] 65, 85, 67, 88, 74, 0.5, 105, 80, 95, 50, 80, 87, 71, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65, 80, 100, 50]
prog30 = [71, 90, 80, 75, 100, 0, 90, 102, 84, 78, 105, 67, 63, 78, 0, 99, 80, 66, 46, 83, 40, 83, prog30 = [71, 90, 80, 75, 100, 0, 90, 102, 84, 78, 105, 67, 63, 78, 0, 99, 80, 66, 46, 83, 40, 83,
80, 90, 93, 50, 96, 88, 99, 108, 75, 80, 50, 64, 55, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56, 80] 80, 90, 93, 50, 96, 88, 99, 108, 75, 80, 50, 64, 55, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56, 80, 100, 55]
overdrive30 = [71, 90, 57, 75, 80, 0, 95, 79, 65, 31, 50, 59, 90, 68, 0, 78, 50, 70, 62, 49, 64, overdrive30 = [71, 90, 57, 75, 80, 0, 95, 79, 65, 31, 50, 59, 90, 68, 0, 78, 50, 70, 62, 49, 64,
56, 73, 95, 67, 84, 80, 88, 79, 80, 50, 80, 80, 63, 25, 50, 82, 55, 50, 95, 55, 70, 100, 80, 99, 80] 56, 73, 95, 67, 84, 80, 88, 79, 80, 50, 80, 80, 63, 25, 50, 82, 55, 50, 95, 55, 70, 100, 80, 99, 80, 100, 40]
char_type = [1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 2, 3, 1, 0, 0, 0, 1, char_type = [1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 2, 3, 1, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 1, 0] 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 1, 0, 0, 0]
char_core = { char_core = {
0: [{'core_id': 'core_hollow', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}], 0: [{'core_id': 'core_hollow', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}],
@@ -341,7 +355,7 @@ def main(path='./'):
43: [{'core_id': 'core_chunithm', 'amount': 15}] 43: [{'core_id': 'core_chunithm', 'amount': 15}]
} }
for i in range(0, 46): for i in range(0, 48):
skill_requires_uncap = 1 if i == 2 else 0 skill_requires_uncap = 1 if i == 2 else 0
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43]: if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43]:
@@ -349,7 +363,7 @@ def main(path='./'):
c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i], c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i],
frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i])) frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i]))
else: else:
if i != 5: if i != 5 and i != 46:
sql = '''insert into character values(?,?,20,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)''' sql = '''insert into character values(?,?,20,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)'''
c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i], c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i],
frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i])) frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i]))
@@ -365,7 +379,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"] "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"]
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,))
@@ -374,6 +388,11 @@ def main(path='./'):
for i in world_unlocks: for i in world_unlocks:
c.execute('''insert into item values(?,"world_unlock",1,'')''', (i,)) c.execute('''insert into item values(?,"world_unlock",1,'')''', (i,))
c.execute('''insert into item values(?,?,?,?)''',
('fragment', 'fragment', 1, ''))
c.execute('''insert into item values(?,?,?,?)''',
('memory', 'memory', 1, ''))
def insert_items(c, items): def insert_items(c, items):
# 物品数据导入 # 物品数据导入
for i in items: for i in items:

View File

@@ -1,475 +1,638 @@
[{ [
{
"name":"testsingle", "name":"testsingle",
"items": [{ "items":[
{
"id":"testsingle", "id":"testsingle",
"type":"single", "type":"single",
"is_available":false "is_available":false
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"dataerror", "name":"dataerror",
"items": [{ "items":[
{
"id":"dataerror", "id":"dataerror",
"type":"single", "type":"single",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"yourvoiceso", "name":"yourvoiceso",
"items": [{ "items":[
{
"id":"yourvoiceso", "id":"yourvoiceso",
"type":"single", "type":"single",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"crosssoul", "name":"crosssoul",
"items": [{ "items":[
{
"id":"crosssoul", "id":"crosssoul",
"type":"single", "type":"single",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"impurebird", "name":"impurebird",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"impurebird", "id":"impurebird",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"auxesia", "name":"auxesia",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"auxesia", "id":"auxesia",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1520413239000, "discount_from":1520413239000,
"discount_to":1521072000000 "discount_to":1521072000000
}, { },
{
"name":"modelista", "name":"modelista",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"modelista", "id":"modelista",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"yozakurafubuki", "name":"yozakurafubuki",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"yozakurafubuki", "id":"yozakurafubuki",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"surrender", "name":"surrender",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"surrender", "id":"surrender",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"metallicpunisher", "name":"metallicpunisher",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"metallicpunisher", "id":"metallicpunisher",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"carminescythe", "name":"carminescythe",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"carminescythe", "id":"carminescythe",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"bethere", "name":"bethere",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"bethere", "id":"bethere",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"callmyname", "name":"callmyname",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"callmyname", "id":"callmyname",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"fallensquare", "name":"fallensquare",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"fallensquare", "id":"fallensquare",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"dropdead", "name":"dropdead",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"dropdead", "id":"dropdead",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"alexandrite", "name":"alexandrite",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"alexandrite", "id":"alexandrite",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"astraltale", "name":"astraltale",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"astraltale", "id":"astraltale",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"phantasia", "name":"phantasia",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"phantasia", "id":"phantasia",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"empireofwinter", "name":"empireofwinter",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"empireofwinter", "id":"empireofwinter",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"libertas", "name":"libertas",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"libertas", "id":"libertas",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"dottodot", "name":"dottodot",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"dottodot", "id":"dottodot",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"dreadnought", "name":"dreadnought",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"dreadnought", "id":"dreadnought",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"mirzam", "name":"mirzam",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"mirzam", "id":"mirzam",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"heavenlycaress", "name":"heavenlycaress",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"heavenlycaress", "id":"heavenlycaress",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"filament", "name":"filament",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"filament", "id":"filament",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"avantraze", "name":"avantraze",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"avantraze", "id":"avantraze",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"battlenoone", "name":"battlenoone",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"battlenoone", "id":"battlenoone",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"saikyostronger", "name":"saikyostronger",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"saikyostronger", "id":"saikyostronger",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"izana", "name":"izana",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"izana", "id":"izana",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"einherjar", "name":"einherjar",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"einherjar", "id":"einherjar",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"laqryma", "name":"laqryma",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"laqryma", "id":"laqryma",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"amygdata", "name":"amygdata",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"amygdata", "id":"amygdata",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"altale", "name":"altale",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"altale", "id":"altale",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"feelssoright", "name":"feelssoright",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"feelssoright", "id":"feelssoright",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"scarletcage", "name":"scarletcage",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"scarletcage", "id":"scarletcage",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"teriqma", "name":"teriqma",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"teriqma", "id":"teriqma",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"mahoroba", "name":"mahoroba",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"mahoroba", "id":"mahoroba",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"badtek", "name":"badtek",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"badtek", "id":"badtek",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"maliciousmischance", "name":"maliciousmischance",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"maliciousmischance", "id":"maliciousmischance",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"buchigireberserker", "name":"buchigireberserker",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"buchigireberserker", "id":"buchigireberserker",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"galaxyfriends", "name":"galaxyfriends",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"galaxyfriends", "id":"galaxyfriends",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100, "orig_price":100,
"discount_from":1615248000000, "discount_from":1615248000000,
"discount_to":1615852799000 "discount_to":1615852799000
}, { },
{
"name":"xeraphinite", "name":"xeraphinite",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"xeraphinite", "id":"xeraphinite",
"is_available":true "is_available":true
}], }
],
"orig_price":100, "orig_price":100,
"price":100 "price":100
}, { },
{
"name":"xanatos", "name":"xanatos",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"xanatos", "id":"xanatos",
"is_available":true "is_available":true
}], }
],
"price":100, "price":100,
"orig_price":100 "orig_price":100
}, { },
{
"name":"attraqtia", "name":"attraqtia",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"attraqtia", "id":"attraqtia",
"is_available":true "is_available":true
}], }
],
"orig_price":100, "orig_price":100,
"price":100 "price":100
}, { },
{
"name":"gimmedablood", "name":"gimmedablood",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"gimmedablood", "id":"gimmedablood",
"is_available":true "is_available":true
}], }
],
"orig_price":100, "orig_price":100,
"price":100 "price":100
}, { },
{
"name":"bassline", "name":"bassline",
"items": [{ "items":[
{
"type":"single", "type":"single",
"id":"bassline", "id":"bassline",
"is_available":true "is_available":true
}], }
],
"orig_price":100, "orig_price":100,
"price":100 "price":100
}] },
{
"name":"theultimacy",
"items":[
{
"type":"single",
"id":"theultimacy",
"is_available":true
}
],
"orig_price":100,
"price":100
},
{
"name":"rekkaresonance",
"items":[
{
"type":"single",
"id":"rekkaresonance",
"is_available":true
}
],
"orig_price":100,
"price":100
}
]

View File

@@ -113,13 +113,14 @@ def add_url_prefix(url, strange_flag=False):
return prefix + r return prefix + r
def error_return(error_code): # 错误返回 def error_return(error_code, extra={}): # 错误返回
# -7 处理交易时发生了错误 # -7 处理交易时发生了错误
# -5 所有的曲目都已经下载完毕 # -5 所有的曲目都已经下载完毕
# -4 您的账号已在别处登录 # -4 您的账号已在别处登录
# -3 无法连接至服务器 # -3 无法连接至服务器
# 2 Arcaea服务器正在维护 # 2 Arcaea服务器正在维护
# 5 请更新Arcaea到最新版本 # 5 请更新Arcaea到最新版本
# 9 新版本请等待几分钟
# 100 无法在此ip地址下登录游戏 # 100 无法在此ip地址下登录游戏
# 101 用户名占用 # 101 用户名占用
# 102 电子邮箱已注册 # 102 电子邮箱已注册
@@ -156,6 +157,13 @@ def error_return(error_code): # 错误返回
# 9907 更新数据时发生了问题 # 9907 更新数据时发生了问题
# 9908 服务器只支持最新的版本请更新Arcaea # 9908 服务器只支持最新的版本请更新Arcaea
# 其它 发生未知错误 # 其它 发生未知错误
if extra:
return jsonify({
"success": False,
"error_code": error_code,
"extra": extra
})
else:
return jsonify({ return jsonify({
"success": False, "success": False,
"error_code": error_code "error_code": error_code
@@ -182,7 +190,7 @@ def login():
if 'AppVersion' in request.headers: # 版本检查 if 'AppVersion' in request.headers: # 版本检查
if Config.ALLOW_APPVERSION: if Config.ALLOW_APPVERSION:
if request.headers['AppVersion'] not in Config.ALLOW_APPVERSION: if request.headers['AppVersion'] not in Config.ALLOW_APPVERSION:
return jsonify({"success": False, "error_code": 5}) return error_return(5)
headers = request.headers headers = request.headers
id_pwd = headers['Authorization'] id_pwd = headers['Authorization']
@@ -193,12 +201,15 @@ def login():
else: else:
device_id = 'low_version' device_id = 'low_version'
token, error_code = server.auth.arc_login( token, error_code, extra = server.auth.arc_login(
name, password, device_id, request.remote_addr) name, password, device_id, request.remote_addr)
if not error_code: if not error_code:
r = {"success": True, "token_type": "Bearer"} r = {"success": True, "token_type": "Bearer"}
r['access_token'] = token r['access_token'] = token
return jsonify(r) return jsonify(r)
else:
if extra:
return error_return(error_code, extra)
else: else:
return error_return(error_code) return error_return(error_code)
@@ -208,7 +219,7 @@ def register():
if 'AppVersion' in request.headers: # 版本检查 if 'AppVersion' in request.headers: # 版本检查
if Config.ALLOW_APPVERSION: if Config.ALLOW_APPVERSION:
if request.headers['AppVersion'] not in Config.ALLOW_APPVERSION: if request.headers['AppVersion'] not in Config.ALLOW_APPVERSION:
return jsonify({"success": False, "error_code": 5}) return error_return(5)
name = request.form['name'] name = request.form['name']
password = request.form['password'] password = request.form['password']
@@ -263,9 +274,7 @@ def character_change(user_id):
@app.route(add_url_prefix('/<path:path>/toggle_uncap', True), methods=['POST']) @app.route(add_url_prefix('/<path:path>/toggle_uncap', True), methods=['POST'])
@server.auth.auth_required(request) @server.auth.auth_required(request)
def character_uncap(user_id, path): def character_uncap(user_id, path):
while '//' in path: character_id = int(path[path.find('character')+10:])
path = path.replace('//', '/')
character_id = int(path[21:])
r = server.setme.change_char_uncap(user_id, character_id) r = server.setme.change_char_uncap(user_id, character_id)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -283,9 +292,7 @@ def character_uncap(user_id, path):
@app.route(add_url_prefix('/<path:path>/uncap', True), methods=['POST']) @app.route(add_url_prefix('/<path:path>/uncap', True), methods=['POST'])
@server.auth.auth_required(request) @server.auth.auth_required(request)
def character_first_uncap(user_id, path): def character_first_uncap(user_id, path):
while '//' in path: character_id = int(path[path.find('character')+10:])
path = path.replace('//', '/')
character_id = int(path[21:])
r = server.character.char_uncap(user_id, character_id) r = server.character.char_uncap(user_id, character_id)
if r is not None: if r is not None:
return jsonify({ return jsonify({
@@ -300,9 +307,7 @@ def character_first_uncap(user_id, path):
@app.route(add_url_prefix('/<path:path>/exp', True), methods=['POST']) @app.route(add_url_prefix('/<path:path>/exp', True), methods=['POST'])
@server.auth.auth_required(request) @server.auth.auth_required(request)
def character_exp(user_id, path): def character_exp(user_id, path):
while '//' in path: character_id = int(path[path.find('character')+10:])
path = path.replace('//', '/')
character_id = int(path[21:])
amount = int(request.form['amount']) amount = int(request.form['amount'])
r = server.character.char_use_core(user_id, character_id, amount) r = server.character.char_use_core(user_id, character_id, amount)
if r is not None: if r is not None:
@@ -457,15 +462,14 @@ def score_token():
@server.auth.auth_required(request) @server.auth.auth_required(request)
def score_token_world(user_id): def score_token_world(user_id):
args = request.args args = request.args
server.arcworld.play_world_song(user_id, args) r = server.arcworld.play_world_song(user_id, args)
if r:
return jsonify({ return jsonify({
"success": True, "success": True,
"value": { "value": r
"stamina": 12,
"max_stamina_ts": 1599547603825,
"token": "13145201919810"
}
}) })
else:
return error_return(108)
@app.route(add_url_prefix('/user/me/save'), methods=['GET']) # 从云端同步 @app.route(add_url_prefix('/user/me/save'), methods=['GET']) # 从云端同步
@@ -536,6 +540,28 @@ def claim_present(user_id, present_id):
return error_return(108) return error_return(108)
# 购买体力
@app.route(add_url_prefix('/purchase/me/stamina/<buy_stamina_type>'), methods=['POST'])
@server.auth.auth_required(request)
def purchase_stamina(user_id, buy_stamina_type):
if buy_stamina_type == 'fragment':
r, error_code = server.arcworld.buy_stamina_by_fragment(user_id)
else:
return error_return(108)
if error_code:
return error_return(error_code)
else:
if r:
return jsonify({
"success": True,
"value": r
})
else:
return error_return(108)
# 购买world模式boost # 购买world模式boost
@app.route(add_url_prefix('/purchase/me/item'), methods=['POST']) @app.route(add_url_prefix('/purchase/me/item'), methods=['POST'])
@server.auth.auth_required(request) @server.auth.auth_required(request)
@@ -551,6 +577,16 @@ def prog_boost(user_id):
"success": True, "success": True,
"value": {'ticket': ticket} "value": {'ticket': ticket}
} }
elif request.form['item_id'] == 'stamina6':
r, error_code = server.arcworld.buy_stamina_by_ticket(user_id)
if error_code:
return error_return(error_code)
re = {
"success": True,
"value": r
}
return jsonify(re) return jsonify(re)
@@ -591,8 +627,9 @@ def world_all(user_id):
@server.auth.auth_required(request) @server.auth.auth_required(request)
def world_in(user_id): def world_in(user_id):
map_id = request.form['map_id'] map_id = request.form['map_id']
flag = server.arcworld.unlock_user_world(user_id, map_id)
return jsonify({ return jsonify({
"success": True, "success": flag,
"value": server.arcworld.get_user_world(user_id, map_id) "value": server.arcworld.get_user_world(user_id, map_id)
}) })
@@ -652,7 +689,7 @@ def download(file_path):
@app.route(add_url_prefix('/<path:path>', True), methods=['POST']) @app.route(add_url_prefix('/<path:path>', True), methods=['POST'])
@server.auth.auth_required(request) @server.auth.auth_required(request)
def sys_set(user_id, path): def sys_set(user_id, path):
set_arg = path[10:] set_arg = path[5:]
value = request.form['value'] value = request.form['value']
server.setme.arc_sys_set(user_id, value, set_arg) server.setme.arc_sys_set(user_id, value, set_arg)
r = server.info.arc_aggregate_small(user_id) r = server.info.arc_aggregate_small(user_id)

View File

@@ -1 +1,2 @@
cd /d %~dp0
python -B main.py python -B main.py

View File

@@ -165,10 +165,22 @@ def get_user_present(c, user_id):
if x: if x:
for i in x: for i in x:
if now <= int(i[1]): if now <= int(i[1]):
c.execute(
'''select * from present_item where present_id=?''', (i[0],))
y = c.fetchall()
items = []
if y:
for j in y:
if j is not None:
items.append({
"type": j[2],
"id": j[1],
"amount": j[3]
})
re.append({'expire_ts': i[1], re.append({'expire_ts': i[1],
'description': i[3], 'description': i[2],
'present_id': i[0], 'present_id': i[0],
'items': json.loads(i[2]) 'items': items
}) })
return re return re
@@ -189,16 +201,16 @@ def claim_user_present(user_id, present_id):
now = int(time.time() * 1000) now = int(time.time() * 1000)
if now <= int(x[1]): if now <= int(x[1]):
# 处理memory # 处理memory
items = json.loads(x[2]) c.execute(
for i in items: '''select * from present_item where present_id=?''', (x[0],))
if i['id'] == 'memory': y = c.fetchall()
c.execute('''select ticket from user where user_id=:a''', {
'a': user_id})
ticket = int(c.fetchone()[0])
ticket += int(i['amount'])
c.execute('''update user set ticket=:b where user_id=:a''', {
'a': user_id, 'b': ticket})
flag = True flag = True
if y:
for j in y:
if j is not None:
flag = flag and server.item.claim_user_item(
c, user_id, j[1], j[2], j[3])
else: else:
# 过期 # 过期
flag = False flag = False
@@ -216,12 +228,12 @@ def claim_user_redeem(user_id, code):
if not x: if not x:
return 0, 504 return 0, 504
if x[2] == 0: # 一次性 if x[1] == 0: # 一次性
c.execute( c.execute(
'''select exists(select * from user_redeem where code=:a)''', {'a': code}) '''select exists(select * from user_redeem where code=:a)''', {'a': code})
if c.fetchone() == (1,): if c.fetchone() == (1,):
return 0, 505 return 0, 505
elif x[2] == 1: # 每个玩家一次 elif x[1] == 1: # 每个玩家一次
c.execute('''select exists(select * from user_redeem where code=:a and user_id=:b)''', c.execute('''select exists(select * from user_redeem where code=:a and user_id=:b)''',
{'a': code, 'b': user_id}) {'a': code, 'b': user_id})
if c.fetchone() == (1,): if c.fetchone() == (1,):
@@ -230,17 +242,17 @@ def claim_user_redeem(user_id, code):
c.execute('''insert into user_redeem values(:b,:a)''', c.execute('''insert into user_redeem values(:b,:a)''',
{'a': code, 'b': user_id}) {'a': code, 'b': user_id})
items = json.loads(x[1]) c.execute('''select * from redeem_item where code=?''', (code,))
for i in items: x = c.fetchall()
if i['type'] == 'fragment': flag = True
fragment = i['amount'] if x:
if i['type'] == 'memory': for i in x:
c.execute('''select ticket from user where user_id=:a''', { if i[2] == 'fragment':
'a': user_id}) fragment += i[3]
ticket = int(c.fetchone()[0]) else:
ticket += int(i['amount']) flag = flag and server.item.claim_user_item(
c.execute('''update user set ticket=:b where user_id=:a''', { c, user_id, i[1], i[2], i[3])
'a': user_id, 'b': ticket}) if flag:
error_code = None error_code = None
return fragment, error_code return fragment, error_code

View File

@@ -38,14 +38,14 @@ def get_score(c, user_id, song_id, difficulty):
{'a': user_id, 'b': song_id, 'c': difficulty}) {'a': user_id, 'b': song_id, 'c': difficulty})
x = c.fetchone() x = c.fetchone()
if x is not None: if x is not None:
c.execute('''select name, character_id, is_skill_sealed, is_char_uncapped, favorite_character from user where user_id = :a''', { c.execute('''select name, character_id, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, favorite_character from user where user_id = :a''', {
'a': user_id}) 'a': user_id})
y = c.fetchone() y = c.fetchone()
if y is not None: if y is not None:
character = y[1] character = y[1]
is_char_uncapped = int2b(y[3]) is_char_uncapped = int2b(y[3])
if y[4] != -1: if y[5] != -1:
character = y[4] character = y[5]
if not Config.CHARACTER_FULL_UNLOCK: if not Config.CHARACTER_FULL_UNLOCK:
c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id=:a and character_id=:b''', { c.execute('''select is_uncapped, is_uncapped_override from user_char where user_id=:a and character_id=:b''', {
'a': user_id, 'b': character}) 'a': user_id, 'b': character})
@@ -58,6 +58,9 @@ def get_score(c, user_id, song_id, difficulty):
is_char_uncapped = int2b(z[0]) is_char_uncapped = int2b(z[0])
else: else:
is_char_uncapped = False is_char_uncapped = False
else:
if y[4] == 1:
is_char_uncapped = False
return { return {
"user_id": x[0], "user_id": x[0],
@@ -173,6 +176,8 @@ def arc_score_me(user_id, song_id, difficulty, limit=20):
x = c.fetchall() x = c.fetchall()
if x != []: if x != []:
rank = amount - limit rank = amount - limit
if rank < 0:
rank = 0
for i in x: for i in x:
rank += 1 rank += 1
y = get_score(c, i[0], song_id, difficulty) y = get_score(c, i[0], song_id, difficulty)
@@ -277,6 +282,7 @@ def get_user_ptt_float(c, user_id) -> float:
c.execute('''select rating from best_score where user_id = :a order by rating DESC limit 30''', { c.execute('''select rating from best_score where user_id = :a order by rating DESC limit 30''', {
'a': user_id}) 'a': user_id})
x = c.fetchall() x = c.fetchall()
if not Config.USE_B10_AS_R10:
if x != []: if x != []:
for i in x: for i in x:
sumr += float(i[0]) sumr += float(i[0])
@@ -300,6 +306,13 @@ def get_user_ptt_float(c, user_id) -> float:
sumr += r30[i] sumr += r30[i]
songs.append(s30[i]) songs.append(s30[i])
i += 1 i += 1
else:
if x != []:
for i in range(len(x)):
t = float(x[i][0])
sumr += t
if i < 10:
sumr += t
return sumr/40 return sumr/40

View File

@@ -3,7 +3,10 @@ from server.sql import Connect
from setting import Config from setting import Config
import server.item import server.item
import server.character import server.character
import server.info
import server.arcpurchase
import os import os
import time
def int2b(x): def int2b(x):
@@ -14,6 +17,23 @@ def int2b(x):
return True return True
def calc_stamina(max_stamina_ts, curr_stamina):
# 计算体力,返回剩余体力数值
stamina = int(server.info.MAX_STAMINA - (max_stamina_ts -
int(time.time()*1000)) / server.info.STAMINA_RECOVER_TICK)
if stamina >= server.info.MAX_STAMINA:
if curr_stamina >= server.info.MAX_STAMINA:
stamina = curr_stamina
else:
stamina = server.info.MAX_STAMINA
if stamina < 0:
stamina = 0
return stamina
def get_world_name(file_dir='./database/map'): def get_world_name(file_dir='./database/map'):
# 获取所有地图名称,返回列表 # 获取所有地图名称,返回列表
L = [] L = []
@@ -45,7 +65,10 @@ def get_user_world_info(user_id, map_id):
info['curr_capture'] = x[3] info['curr_capture'] = x[3]
info['is_locked'] = int2b(x[4]) info['is_locked'] = int2b(x[4])
else: else:
c.execute('''insert into user_world values(:a,:b,0,0,0)''', { info['curr_position'] = 0
info['curr_capture'] = 0
info['is_locked'] = True
c.execute('''insert into user_world values(:a,:b,0,0,1)''', {
'a': user_id, 'b': map_id}) 'a': user_id, 'b': map_id})
return info return info
@@ -87,7 +110,10 @@ def get_world_all(user_id):
info['curr_capture'] = x[3] info['curr_capture'] = x[3]
info['is_locked'] = int2b(x[4]) info['is_locked'] = int2b(x[4])
else: else:
c.execute('''insert into user_world values(:a,:b,0,0,0)''', { info['curr_position'] = 0
info['curr_capture'] = 0
info['is_locked'] = True
c.execute('''insert into user_world values(:a,:b,0,0,1)''', {
'a': user_id, 'b': map_id}) 'a': user_id, 'b': map_id})
re.append(info) re.append(info)
@@ -106,7 +132,7 @@ def get_user_world(user_id, map_id):
"user_id": user_id, "user_id": user_id,
"curr_position": 0, "curr_position": 0,
"curr_capture": 0, "curr_capture": 0,
"is_locked": False, "is_locked": True,
"map_id": map_id "map_id": map_id
} }
if x: if x:
@@ -114,12 +140,40 @@ def get_user_world(user_id, map_id):
re['curr_capture'] = x[3] re['curr_capture'] = x[3]
re['is_locked'] = int2b(x[4]) re['is_locked'] = int2b(x[4])
else: else:
c.execute('''insert into user_world values(:a,:b,0,0,0)''', { c.execute('''insert into user_world values(:a,:b,0,0,1)''', {
'a': user_id, 'b': map_id}) 'a': user_id, 'b': map_id})
return re return re
def unlock_user_world(user_id, map_id):
# 解锁用户的图,返回成功与否布尔值
with Connect() as c:
c.execute(
'''select is_locked from user_world where map_id=? and user_id=?''', (map_id, user_id))
x = c.fetchone()
if x:
is_locked = x[0]
else:
is_locked = 1
c.execute('''insert into user_world values(:a,:b,0,0,1)''', {
'a': user_id, 'b': map_id})
if is_locked == 1:
map_info = get_world_info(map_id)
if 'require_type' in map_info and map_info['require_type'] != '':
if map_info['require_type'] in ['pack', 'single']:
c.execute('''select exists(select * from user_item where user_id=? and item_id=? and type=?)''',
(user_id, map_info['require_id'], map_info['require_type']))
if c.fetchone() == (0,):
return False
c.execute(
'''update user_world set is_locked=0 where user_id=? and map_id=?''', (user_id, map_id))
return True
def change_user_current_map(user_id, map_id): def change_user_current_map(user_id, map_id):
# 改变用户当前图 # 改变用户当前图
with Connect() as c: with Connect() as c:
@@ -129,7 +183,8 @@ def change_user_current_map(user_id, map_id):
def play_world_song(user_id, args): def play_world_song(user_id, args):
# 声明是世界模式的打歌,并且记录加成信息 # 声明是世界模式的打歌,并且记录加成信息,返回字典
r = {}
with Connect() as c: with Connect() as c:
stamina_multiply = 1 stamina_multiply = 1
fragment_multiply = 100 fragment_multiply = 100
@@ -150,7 +205,34 @@ def play_world_song(user_id, args):
c.execute('''insert into world_songplay values(:a,:b,:c,:d,:e,:f)''', { c.execute('''insert into world_songplay values(:a,:b,:c,:d,:e,:f)''', {
'a': user_id, 'b': args['song_id'], 'c': args['difficulty'], 'd': stamina_multiply, 'e': fragment_multiply, 'f': prog_boost_multiply}) 'a': user_id, 'b': args['song_id'], 'c': args['difficulty'], 'd': stamina_multiply, 'e': fragment_multiply, 'f': prog_boost_multiply})
return None c.execute('''select current_map from user where user_id = :a''', {
'a': user_id})
map_id = c.fetchone()[0]
info = get_world_info(map_id)
# 体力计算
c.execute(
'''select max_stamina_ts, stamina from user where user_id=?''', (user_id,))
x = c.fetchone()
max_stamina_ts = x[0] if x and x[0] is not None else 0
stamina = x[1] if x and x[1] is not None else 12
now = int(time.time() * 1000)
# 体力不足
if calc_stamina(max_stamina_ts, stamina) < info['stamina_cost']:
return {}
stamina = calc_stamina(max_stamina_ts, stamina) - \
info['stamina_cost'] * stamina_multiply
max_stamina_ts = now + server.info.STAMINA_RECOVER_TICK * \
(server.info.MAX_STAMINA - stamina)
c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''',
(max_stamina_ts, stamina, user_id))
r = {
"stamina": stamina,
"max_stamina_ts": max_stamina_ts,
"token": "13145201919810"
}
return r
def climb_step(user_id, map_id, step, prev_capture, prev_position): def climb_step(user_id, map_id, step, prev_capture, prev_position):
@@ -263,9 +345,12 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', { c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
'a': user_id, 'b': song_id, 'c': difficulty}) 'a': user_id, 'b': song_id, 'c': difficulty})
c.execute('''select character_id from user where user_id=?''', (user_id,)) c.execute(
'''select character_id, max_stamina_ts, stamina from user where user_id=?''', (user_id,))
x = c.fetchone() x = c.fetchone()
character_id = x[0] if x else 0 character_id = x[0] if x and x[0] is not None else 0
max_stamina_ts = x[1] if x and x[1] is not None else 0
stamina = x[2] if x and x[2] is not None else 12
c.execute('''select frag1,prog1,overdrive1,frag20,prog20,overdrive20,frag30,prog30,overdrive30 from character where character_id=?''', (character_id,)) c.execute('''select frag1,prog1,overdrive1,frag20,prog20,overdrive20,frag30,prog30,overdrive30 from character where character_id=?''', (character_id,))
x = c.fetchone() x = c.fetchone()
@@ -317,6 +402,9 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
c.execute('''select * from user_world where user_id = :a and map_id =:b''', c.execute('''select * from user_world where user_id = :a and map_id =:b''',
{'a': user_id, 'b': map_id}) {'a': user_id, 'b': map_id})
y = c.fetchone() y = c.fetchone()
if y[4] == 1: # 图不可用
return {}
rewards, steps, curr_position, curr_capture, info = climb_step( rewards, steps, curr_position, curr_capture, info = climb_step(
user_id, map_id, step, y[3], y[2]) user_id, map_id, step, y[3], y[2])
for i in rewards: # 物品分发 for i in rewards: # 物品分发
@@ -324,6 +412,12 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
amount = j['amount'] if 'amount' in j else 1 amount = j['amount'] if 'amount' in j else 1
item_id = j['id'] if 'id' in j else '' item_id = j['id'] if 'id' in j else ''
server.item.claim_user_item(c, user_id, item_id, j['type'], amount) server.item.claim_user_item(c, user_id, item_id, j['type'], amount)
if 'step_type' in steps[-1]:
if 'plusstamina' in steps[-1]['step_type'] and 'plus_stamina_value' in steps[-1]:
# 体力格子
max_stamina_ts, stamina = add_stamina(
c, user_id, int(steps[-1]['plus_stamina_value']))
# 角色升级 # 角色升级
if not Config.CHARACTER_FULL_UNLOCK: if not Config.CHARACTER_FULL_UNLOCK:
exp, level = server.character.calc_level_up( exp, level = server.character.calc_level_up(
@@ -357,8 +451,8 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
"prog": prog, "prog": prog,
"overdrive": overdrive "overdrive": overdrive
}, },
"current_stamina": 12, "current_stamina": calc_stamina(max_stamina_ts, stamina),
"max_stamina_ts": 1586274871917 "max_stamina_ts": max_stamina_ts
} }
else: else:
re = { re = {
@@ -384,8 +478,8 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
"prog": prog, "prog": prog,
"overdrive": overdrive "overdrive": overdrive
}, },
"current_stamina": 12, "current_stamina": calc_stamina(max_stamina_ts, stamina),
"max_stamina_ts": 1586274871917 "max_stamina_ts": max_stamina_ts
} }
if stamina_multiply != 1: if stamina_multiply != 1:
@@ -401,3 +495,77 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
'a': curr_position, 'b': curr_capture, 'c': user_id, 'd': map_id}) 'a': curr_position, 'b': curr_capture, 'c': user_id, 'd': map_id})
return re return re
def add_stamina(c, user_id, add_stamina):
# 增添体力返回max_stamina_ts和stamina
now = int(time.time() * 1000)
c.execute(
'''select max_stamina_ts, stamina from user where user_id=?''', (user_id,))
x = c.fetchone()
if x and x[0] is not None and x[1] is not None:
stamina = calc_stamina(x[0], x[1]) + add_stamina
max_stamina_ts = now - \
(stamina-server.info.MAX_STAMINA) * \
server.info.STAMINA_RECOVER_TICK
else:
max_stamina_ts = now
stamina = server.info.MAX_STAMINA
c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''',
(max_stamina_ts, stamina, user_id))
return max_stamina_ts, stamina
def buy_stamina_by_fragment(user_id):
# 残片买体力,返回字典和错误码
r = {}
with Connect() as c:
c.execute(
'''select next_fragstam_ts from user where user_id=?''', (user_id,))
x = c.fetchone()
if x:
now = int(time.time() * 1000)
next_fragstam_ts = x[0] if x[0] else 0
if now < next_fragstam_ts:
return {}, 905
next_fragstam_ts = now + 24*3600*1000
max_stamina_ts, stamina = add_stamina(c, user_id, 6)
c.execute('''update user set next_fragstam_ts=?, max_stamina_ts=?, stamina=? where user_id=?''',
(next_fragstam_ts, max_stamina_ts, stamina, user_id))
r = {
"user_id": user_id,
"stamina": stamina,
"max_stamina_ts": max_stamina_ts,
"next_fragstam_ts": next_fragstam_ts
}
return r, None
def buy_stamina_by_ticket(user_id):
# 源点买体力,返回字典和错误码
r = {}
with Connect() as c:
flag, ticket = server.arcpurchase.buy_item(c, user_id, 50)
if flag:
max_stamina_ts, stamina = add_stamina(c, user_id, 6)
c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''',
(max_stamina_ts, stamina, user_id))
r = {
"user_id": user_id,
"stamina": stamina,
"max_stamina_ts": max_stamina_ts,
"ticket": ticket
}
else:
return None, 501
return r, None

View File

@@ -5,9 +5,11 @@ import functools
from setting import Config from setting import Config
from flask import jsonify from flask import jsonify
BAN_TIME = [1, 3, 7, 15, 31]
def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判断 def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判断
# 查询数据库中的user表验证账号密码返回并记录token多返回个error code # 查询数据库中的user表验证账号密码返回并记录token多返回个error code和extra
# token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear # token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear
# 密码和token的加密方式为 SHA-256 # 密码和token的加密方式为 SHA-256
@@ -15,16 +17,21 @@ def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判
token = None token = None
with Connect() as c: with Connect() as c:
hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest() hash_pwd = hashlib.sha256(password.encode("utf8")).hexdigest()
c.execute('''select user_id, password from user where name = :name''', { c.execute('''select user_id, password, ban_flag from user where name = :name''', {
'name': name}) 'name': name})
x = c.fetchone() x = c.fetchone()
if x is not None: if x is not None:
now = int(time.time() * 1000)
if x[2] is not None and x[2] != '':
# 自动封号检查
ban_timestamp = int(x[2].split(':', 1)[1])
if ban_timestamp > now:
return None, 105, {'remaining_ts': ban_timestamp-now}
if x[1] == '': if x[1] == '':
# 账号封禁 # 账号封禁
error_code = 106 error_code = 106
elif x[1] == hash_pwd: elif x[1] == hash_pwd:
user_id = str(x[0]) user_id = str(x[0])
now = int(time.time() * 1000)
token = hashlib.sha256( token = hashlib.sha256(
(user_id + str(now)).encode("utf8")).hexdigest() (user_id + str(now)).encode("utf8")).hexdigest()
c.execute( c.execute(
@@ -49,6 +56,13 @@ def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判
device_list) + 1 - device_list.count(device_id) - Config.LOGIN_DEVICE_NUMBER_LIMIT device_list) + 1 - device_list.count(device_id) - Config.LOGIN_DEVICE_NUMBER_LIMIT
if should_delete_num >= 1: # 删掉多余token if should_delete_num >= 1: # 删掉多余token
if not Config.ALLOW_LOGIN_SAME_DEVICE and Config.ALLOW_BAN_MULTIDEVICE_USER_AUTO: # 自动封号检查
c.execute(
'''select count(*) from login where user_id=? and login_time>?''', (user_id, now-86400000))
if c.fetchone()[0] >= Config.LOGIN_DEVICE_NUMBER_LIMIT:
remaining_ts = arc_auto_ban(c, user_id, now)
return None, 105, {'remaining_ts': remaining_ts}
c.execute('''delete from login where rowid in (select rowid from login where user_id=:user_id limit :a);''', c.execute('''delete from login where rowid in (select rowid from login where user_id=:user_id limit :a);''',
{'user_id': user_id, 'a': int(should_delete_num)}) {'user_id': user_id, 'a': int(should_delete_num)})
@@ -62,7 +76,7 @@ def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判
# 用户名错误 # 用户名错误
error_code = 104 error_code = 104
return token, error_code return token, error_code, None
def arc_register(name: str, password: str, device_id: str, email: str, ip: str): # 注册 def arc_register(name: str, password: str, device_id: str, email: str, ip: str): # 注册
@@ -195,3 +209,24 @@ def auth_required(request):
return wrapped_view return wrapped_view
return decorator return decorator
def arc_auto_ban(c, user_id, now):
# 多设备自动封号机制,返回封号时长
c.execute('''delete from login where user_id=?''', (user_id, ))
c.execute('''select ban_flag from user where user_id=?''', (user_id,))
x = c.fetchone()
if x and x[0] != '' and x[0] is not None:
last_ban_time = int(x[0].split(':', 1)[0])
i = 0
while i < len(BAN_TIME) - 1 and BAN_TIME[i] <= last_ban_time:
i += 1
ban_time = BAN_TIME[i]
else:
ban_time = BAN_TIME[0]
ban_flag = ':'.join((str(ban_time), str(now + ban_time*24*60*60*1000)))
c.execute('''update user set ban_flag=? where user_id=?''',
(ban_flag, user_id))
return ban_time*24*60*60*1000

View File

@@ -1,5 +1,6 @@
from setting import Config from setting import Config
from server.sql import Connect from server.sql import Connect
import server.info
import server.item import server.item
import server.setme import server.setme
@@ -212,7 +213,7 @@ def char_use_core(user_id, character_id, amount):
x = c.fetchone() x = c.fetchone()
if x: if x:
exp, level = calc_level_up( exp, level = calc_level_up(
c, user_id, character_id, x[0], amount*250) c, user_id, character_id, x[0], amount*server.info.CORE_EXP)
c.execute('''update user_char set level=?, exp=? where user_id=? and character_id=?''', c.execute('''update user_char set level=?, exp=? where user_id=? and character_id=?''',
(level, exp, user_id, character_id)) (level, exp, user_id, character_id))
server.item.claim_user_item( server.item.claim_user_item(
@@ -244,10 +245,10 @@ def char_uncap(user_id, character_id):
break break
if success: if success:
for i in x:
server.item.claim_user_item(c, user_id, i[1], i[2], -i[3])
c.execute('''update user_char set is_uncapped=1, is_uncapped_override=0 where user_id=? and character_id=?''', c.execute('''update user_char set is_uncapped=1, is_uncapped_override=0 where user_id=? and character_id=?''',
(user_id, character_id)) (user_id, character_id))
for i in x:
server.item.claim_user_item(c, user_id, i[1], i[2], -i[3])
r = {'character': [get_one_character(c, user_id, character_id)]} r = {'character': [get_one_character(c, user_id, character_id)]}
r['cores'] = server.item.get_user_cores(c, user_id) r['cores'] = server.item.get_user_cores(c, user_id)

View File

@@ -7,6 +7,10 @@ import server.item
import time import time
from setting import Config from setting import Config
MAX_STAMINA = 12
STAMINA_RECOVER_TICK = 1800000
CORE_EXP = 250
def int2b(x): def int2b(x):
# int与布尔值转换 # int与布尔值转换
@@ -100,6 +104,8 @@ def get_user_friend(c, user_id):
"user_id": i[0] "user_id": i[0]
}) })
s.sort(key=lambda item: item["recent_score"][0]["time_played"] if len(
item["recent_score"]) > 0 else 0, reverse=True)
return s return s
@@ -122,11 +128,12 @@ def get_user_me(c, user_id):
'''update user set character_id=0 where user_id=?''', (user_id,)) '''update user set character_id=0 where user_id=?''', (user_id,))
favorite_character_id = x[23] favorite_character_id = x[23]
if favorite_character_id not in characters: if favorite_character_id not in characters: # 这是考虑有可能favourite_character设置了用户未拥有的角色
favorite_character_id = -1 favorite_character_id = -1
c.execute( c.execute(
'''update user set favorite_character=-1 where user_id=?''', (user_id,)) '''update user set favorite_character=-1 where user_id=?''', (user_id,))
# 计算世界排名
c.execute( c.execute(
'''select world_rank_score from user where user_id=?''', (user_id,)) '''select world_rank_score from user where user_id=?''', (user_id,))
y = c.fetchone() y = c.fetchone()
@@ -141,10 +148,22 @@ def get_user_me(c, user_id):
else: else:
world_rank = 0 world_rank = 0
# 源点强化
prog_boost = 0 prog_boost = 0
if x[27] and x[27] != 0: if x[27] and x[27] != 0:
prog_boost = 300 prog_boost = 300
# 体力计算
next_fragstam_ts = -1
max_stamina_ts = 1586274871917
stamina = 12
if x[31]:
next_fragstam_ts = x[31]
if x[32]:
max_stamina_ts = x[32]
if x[33]:
stamina = x[33]
r = {"is_aprilfools": Config.IS_APRILFOOLS, r = {"is_aprilfools": Config.IS_APRILFOOLS,
"curr_available_maps": [], "curr_available_maps": [],
"character_stats": user_character, "character_stats": user_character,
@@ -164,9 +183,9 @@ def get_user_me(c, user_id):
"is_skill_sealed": int2b(x[7]), "is_skill_sealed": int2b(x[7]),
"current_map": x[25], "current_map": x[25],
"prog_boost": prog_boost, "prog_boost": prog_boost,
"next_fragstam_ts": -1, "next_fragstam_ts": next_fragstam_ts,
"max_stamina_ts": 1586274871917, "max_stamina_ts": max_stamina_ts,
"stamina": 12, "stamina": server.arcworld.calc_stamina(max_stamina_ts, stamina),
"world_unlocks": server.item.get_user_items(c, user_id, 'world_unlock'), "world_unlocks": server.item.get_user_items(c, user_id, 'world_unlock'),
"world_songs": server.item.get_user_items(c, user_id, 'world_song'), "world_songs": server.item.get_user_items(c, user_id, 'world_song'),
"singles": server.item.get_user_items(c, user_id, 'single'), "singles": server.item.get_user_items(c, user_id, 'single'),
@@ -220,12 +239,12 @@ def arc_aggregate_big(user_id):
}, { }, {
"id": 3, "id": 3,
"value": { "value": {
"max_stamina": 12, "max_stamina": MAX_STAMINA,
"stamina_recover_tick": 1800000, "stamina_recover_tick": STAMINA_RECOVER_TICK,
"core_exp": 250, "core_exp": CORE_EXP,
"curr_ts": int(time.time())*1000, "curr_ts": int(time.time()*1000),
"level_steps": server.character.get_level_steps(), "level_steps": server.character.get_level_steps(),
"world_ranking_enabled": False, "world_ranking_enabled": True,
"is_byd_chapter_unlocked": True "is_byd_chapter_unlocked": True
} }
}, { }, {

View File

@@ -19,7 +19,7 @@ class Config():
游戏API地址前缀 游戏API地址前缀
Game API's URL prefix Game API's URL prefix
''' '''
GAME_API_PREFIX = '/blockchain/14' GAME_API_PREFIX = '/kusoatui/15'
''' '''
-------------------- --------------------
''' '''
@@ -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.5.3', '3.5.3c', '3.6.2', '3.6.2c'] ALLOW_APPVERSION = ['3.5.3', '3.5.3c', '3.6.4', '3.6.4c']
''' '''
-------------------- --------------------
''' '''
@@ -96,7 +96,7 @@ class Config():
API interface full control permission Token API interface full control permission Token
If you don't want to use it, leave it blank. If you don't want to use it, leave it blank.
''' '''
API_TOKEN = '' API_TOKEN = '123'
''' '''
-------------------- --------------------
''' '''
@@ -135,10 +135,17 @@ class Config():
LOGIN_DEVICE_NUMBER_LIMIT = 1 LOGIN_DEVICE_NUMBER_LIMIT = 1
''' '''
是否允许同设备多应用共存登录 是否允许同设备多应用共存登录
请注意这个选项设置为True时下一个选项将自动变为False
If logging in from multiple applications on the same device is allowed If logging in from multiple applications on the same device is allowed
Note that when this option is set to True, the next option automatically becomes False
''' '''
ALLOW_LOGIN_SAME_DEVICE = False ALLOW_LOGIN_SAME_DEVICE = False
''' '''
24小时内登陆设备数超过最大允许设备数量时是否自动封号1天、3天、7天、15天、31天
When the number of login devices exceeds the maximum number of devices allowed to log in Arcaea within 24 hours, whether the account will be automatically banned (1 day, 3 days, 7 days, 15 days, 31 days)
'''
ALLOW_BAN_MULTIDEVICE_USER_AUTO = True
'''
-------------------- --------------------
''' '''
@@ -201,3 +208,13 @@ class Config():
''' '''
-------------------- --------------------
''' '''
'''
--------------------
是否使用最好的 10 条记录(而不是最近的 30 条记录中较好的 10 条)来计算 PTT
Calculate PTT with best 10 instead of recent best 10
'''
USE_B10_AS_R10 = False
'''
--------------------
'''

View File

@@ -20,10 +20,28 @@
<span class="char-num">{{present['description']}}</span> <span class="char-num">{{present['description']}}</span>
<br /> <br />
<span>Items: </span> {% if present['items'] %}<br />
<span class="char-num" style='white-space:pre'>{{present['items']}}</span> {% for x in present['items'] %}
<span>Item id: </span>
<span class="char-num">{{x['item_id']}}</span>
<br /> <br />
<span>Item type: </span>
<span class="char-num">{{x['type']}}</span>
<br />
<span>Amount: </span>
<span class="char-num">{{x['amount']}}</span>
<br />
{% if not loop.last %}
<br />
{% endif %}
{% endfor %}
{% endif %}
</div> </div>
{% if not loop.last %} {% if not loop.last %}

View File

@@ -1,6 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block header %} {% block header %}
<h1>{% block title %}All items{% endblock %}</h1> <h1>{% block title %}All purchases{% endblock %}</h1>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@@ -22,9 +22,28 @@
</span> </span>
<br /> <br />
<span>Items: </span> {% if redeem['items'] %}<br />
<span class="char-num" style='white-space:pre'>{{redeem['items']}}</span> {% for x in redeem['items'] %}
<span>Item id: </span>
<span class="char-num">{{x['item_id']}}</span>
<br /> <br />
<span>Item type: </span>
<span class="char-num">{{x['type']}}</span>
<br />
<span>Amount: </span>
<span class="char-num">{{x['amount']}}</span>
<br />
{% if not loop.last %}
<br />
{% endif %}
{% endfor %}
{% endif %}
<div><a href="/web/redeem/{{redeem['code']}}">使用者 Players who have used it.</a></div> <div><a href="/web/redeem/{{redeem['code']}}">使用者 Players who have used it.</a></div>
</div> </div>

View File

@@ -14,15 +14,25 @@
<label for="expire_ts">Expire time</label> <label for="expire_ts">Expire time</label>
<input type="datetime-local" name="expire_ts" id="expire_ts" required> <input type="datetime-local" name="expire_ts" id="expire_ts" required>
<br /> <br />
<div>Items:</div>
<label for="fragment">Fragments</label>
<input name="fragment" id="fragment">
<label for="ticket">Memories</label>
<input name="ticket" id="ticket">
<div class="content">两种奖励只能有一个,另一个请留空。如果都填写,以记忆源点优先。</div> <label for="item_id">ID of the item</label>
<div class="content">There can only be one of the two kinds of present. Please leave the other one blank. If you <input name="item_id" id="item_id" required>
fill both, the memories will be given priority.</div> <label for="type">Type</label>
<div>
<select name="type">
<option value='single' selected>Single song</option>
<option value='world_song'>World song</option>
<option value='world_unlock'>World unlock scene</option>
<option value='character'>Character</option>
<option value='core'>Character core</option>
<option value='fragment'>Fragment</option>
<option value='memory'>Memory</option>
</select>
</div>
<label for="amount">Amount</label>
<input name="amount" id="amount" value="1" required>
<br />
<div class="content">时间填写是一个HTML5控件</div> <div class="content">时间填写是一个HTML5控件</div>
<div class="content">Time filling is an HTML5 control.</div> <div class="content">Time filling is an HTML5 control.</div>
<input type="submit" value="Add"> <input type="submit" value="Add">

View File

@@ -13,8 +13,8 @@
<label for="type">Type</label> <label for="type">Type</label>
<div> <div>
<select name="type"> <select name="type">
<option value='single' selected>Single</option> <option value='single' selected>Single song</option>
<option value='pack'>Pack</option> <option value='pack'>Song pack</option>
<option value='world_song'>World song</option> <option value='world_song'>World song</option>
<option value='character'>Character</option> <option value='character'>Character</option>
</select> </select>

View File

@@ -11,27 +11,40 @@
<input name="code" id="code"> <input name="code" id="code">
<div>Or</div> <div>Or</div>
<div>随机批量生成 Batch generation at random</div> <div>随机批量生成 Batch generation at random</div>
<label for="amount">Amount</label> <label for="redeem_amount">Redeem code amount</label>
<input name="amount" id="amount"> <input name="redeem_amount" id="redeem_amount">
<br /> <br />
<div>Type: <div>Redeem code type:
<br /> <br />
<br /> <br />
<label><input type="radio" name="type" value="0" checked>仅可使用一次 It can only be used once.</label> <label><input type="radio" name="redeem_type" value="0" checked>仅可使用一次 It can only be used once.</label>
<br /> <br />
<label><input type="radio" name="type" value="1">每个用户仅可以使用一次 Each user can only use it once.</label> <label><input type="radio" name="redeem_type" value="1">每个用户仅可以使用一次 Each user can only use it once.</label>
</div> </div>
<br /> <br />
<div>Items:</div>
<label for="fragment">Fragments</label>
<input name="fragment" id="fragment">
<label for="ticket">Memories</label>
<input name="ticket" id="ticket">
<div class="content">两种奖励可以都有,不需要请留空。</div> <label for="item_id">ID of the item</label>
<div class="content">You can have both kinds of items. Please leave it blank if you don't need it.</div> <input name="item_id" id="item_id" required>
<label for="type">Type</label>
<div>
<select name="type">
<option value='single' selected>Single song</option>
<option value='pack'>Song pack</option>
<option value='world_song'>World song</option>
<option value='world_unlock'>World unlock scene</option>
<option value='character'>Character</option>
<option value='core'>Character core</option>
<option value='fragment'>Fragment</option>
<option value='memory'>Memory</option>
</select>
</div>
<label for="amount">Amount</label>
<input name="amount" id="amount" value="1" required>
<br />
<div class="content">兑换码长度为10~20。</div> <div class="content">兑换码长度为10~20。</div>
<div class="content">The length of redeem code is 10 ~ 20.</div> <div class="content">The length of redeem code is 10 ~ 20.</div>
<div class="content">随机生成数量不得超过1000。</div> <div class="content">随机生成数量不得超过1000。</div>

View File

@@ -10,10 +10,10 @@
<input type="submit" value="Submit"> <input type="submit" value="Submit">
</form> </form>
<div class="content"> <div class="content">
这里可以将旧版本的数据库同步到新版本的数据库,并刷新用户拥有的角色列表。<br /> 这里可以将旧版本的数据库同步到新版本的数据库,并刷新用户拥有的角色列表。<br />
可上传文件: arcaea_database.db和arcsong.db<br /> 可上传文件: arcaea_database.db和arcsong.db<br />
新数据库不存在的数据会被添加,存在的重复数据也会被改变。<br /><br /> 新数据库不存在的数据会被添加,存在的重复数据也会被改变。<br /><br />
Here you can synchronize the old version of the database to the new version of the database and refresh the list of Here you can synchronize the old version of the database to the new version of the database and refresh the list of full
characters owned by players.<br /> characters owned by players.<br />
Uploadable files: arcaea_database.db & arcsong.db<br /> Uploadable files: arcaea_database.db & arcsong.db<br />
Data that does not exist in the new database will be added and the existing duplicate data will also be changed. Data that does not exist in the new database will be added and the existing duplicate data will also be changed.

View File

@@ -1,5 +1,5 @@
from flask import ( from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for Blueprint, flash, redirect, render_template, request, url_for
) )
from web.login import login_required from web.login import login_required
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@@ -418,7 +418,7 @@ def all_character():
def change_character(): def change_character():
# 修改角色数据 # 修改角色数据
skill_ids = ['No_skill', 'gauge_easy', 'note_mirror', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere', skill_ids = ['No_skill', 'gauge_easy', 'note_mirror', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere',
'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', 'frags_kou', 'visual_ink', 'shirabe_entry_fee', 'frags_yume', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange'] 'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', 'frags_kou', 'visual_ink', 'shirabe_entry_fee', 'frags_yume', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange', 'gauge_safe_10', 'frags_nami']
return render_template('web/changechar.html', skill_ids=skill_ids) return render_template('web/changechar.html', skill_ids=skill_ids)
@@ -604,7 +604,8 @@ def edit_user_purchase():
if method == '0': if method == '0':
web.system.unlock_all_user_item(c) web.system.unlock_all_user_item(c)
else: else:
c.execute('''delete from user_item''') c.execute(
'''delete from user_item where type in ('pack', 'single')''')
flash("全部用户购买信息修改成功 Successfully edit all the users' purchase information.") flash("全部用户购买信息修改成功 Successfully edit all the users' purchase information.")
@@ -629,8 +630,8 @@ def edit_user_purchase():
if method == '0': if method == '0':
web.system.unlock_user_item(c, user_id) web.system.unlock_user_item(c, user_id)
else: else:
c.execute('''delete from user_item where user_id=:a''', { c.execute('''delete from user_item where type in ('pack', 'single') and user_id = :user_id''', {
'a': user_id}) 'user_id': user_id})
flash('用户购买信息修改成功 Successfully edit the user purchase information.') flash('用户购买信息修改成功 Successfully edit the user purchase information.')
else: else:
@@ -975,16 +976,19 @@ def all_present():
if x: if x:
posts = [] posts = []
for i in x: for i in x:
items = json.loads(i[2]) items = []
items_string = '' c.execute(
for j in items: '''select * from present_item where present_id=?''', (i[0],))
items_string = items_string + '\n' + \ y = c.fetchall()
str(j['id']) + ': ' + str(j['amount']) for j in y:
if j is not None:
items.append(
{'item_id': j[1], 'type': j[2], 'amount': j[3]})
posts.append({'present_id': i[0], posts.append({'present_id': i[0],
'expire_ts': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(i[1])//1000)), 'expire_ts': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(i[1])//1000)),
'items': items_string, 'items': items,
'description': i[3] 'description': i[2]
}) })
else: else:
error = '没有奖励数据 No present data.' error = '没有奖励数据 No present data.'
@@ -1010,13 +1014,15 @@ def add_present():
present_id = request.form['present_id'] present_id = request.form['present_id']
expire_ts = request.form['expire_ts'] expire_ts = request.form['expire_ts']
description = request.form['description'] description = request.form['description']
fragment = request.form['fragment'] item_id = request.form['item_id']
ticket = request.form['ticket'] item_type = request.form['type']
item_amount = request.form['amount']
try: try:
if ticket: if item_amount:
ticket = int(ticket) item_amount = int(item_amount)
if fragment: else:
fragment = int(fragment) item_amount = 1
expire_ts = int(time.mktime(time.strptime( expire_ts = int(time.mktime(time.strptime(
expire_ts, "%Y-%m-%dT%H:%M"))) * 1000 expire_ts, "%Y-%m-%dT%H:%M"))) * 1000
except: except:
@@ -1028,18 +1034,8 @@ def add_present():
if len(description) >= 256: if len(description) >= 256:
description = description[:200] description = description[:200]
items = []
if ticket:
items.append({'type': 'memory', 'id': 'memory', 'amount': ticket})
if fragment:
items.append(
{'type': 'fragment', 'id': 'fragment', 'amount': fragment})
if items == []:
flash('奖励为空 No items.')
return redirect(url_for('index.change_present'))
message = web.system.add_one_present( message = web.system.add_one_present(
present_id, expire_ts, description, json.dumps(items)) present_id, expire_ts, description, item_id, item_type, item_amount)
if message: if message:
flash(message) flash(message)
@@ -1128,15 +1124,18 @@ def all_redeem():
if x: if x:
posts = [] posts = []
for i in x: for i in x:
items = json.loads(i[1]) items = []
items_string = '' c.execute(
for j in items: '''select * from redeem_item where code=?''', (i[0],))
items_string = items_string + '\n' + \ y = c.fetchall()
str(j['id']) + ': ' + str(j['amount']) for j in y:
if j is not None:
items.append(
{'item_id': j[1], 'type': j[2], 'amount': j[3]})
posts.append({'code': i[0], posts.append({'code': i[0],
'items': items_string, 'items': items,
'type': i[2] 'type': i[1]
}) })
else: else:
error = '没有兑换码数据 No redeem code data.' error = '没有兑换码数据 No redeem code data.'
@@ -1159,48 +1158,39 @@ def change_redeem():
@login_required @login_required
def add_redeem(): def add_redeem():
# 添加兑换码数据 # 添加兑换码数据
print(request.form)
code = request.form['code'] code = request.form['code']
amount = request.form['amount'] redeem_amount = request.form['redeem_amount']
redeem_type = request.form['type'] redeem_type = request.form['redeem_type']
fragment = request.form['fragment'] item_id = request.form['item_id']
ticket = request.form['ticket'] item_type = request.form['type']
item_amount = request.form['amount']
try: try:
if amount: if item_amount:
amount = int(amount) item_amount = int(item_amount)
if ticket: else:
ticket = int(ticket) item_amount = 1
if fragment: if redeem_amount:
fragment = int(fragment) redeem_amount = int(redeem_amount)
except: except:
flash('数据错误 Wrong data.') flash('数据错误 Wrong data.')
return redirect(url_for('index.change_redeem')) return redirect(url_for('index.change_redeem'))
items = [] if code and not redeem_amount:
if ticket:
items.append({'type': 'memory', 'id': 'memory', 'amount': ticket})
if fragment:
items.append(
{'type': 'fragment', 'id': 'fragment', 'amount': fragment})
if items == []:
flash('奖励为空 No items.')
return redirect(url_for('index.change_redeem'))
if code and not amount:
if len(code) > 20 or len(code) < 10: if len(code) > 20 or len(code) < 10:
flash('兑换码长度不合适 Inappropriate length of redeem code.') flash('兑换码长度不合适 Inappropriate length of redeem code.')
return redirect(url_for('index.change_redeem')) return redirect(url_for('index.change_redeem'))
message = web.system.add_one_redeem( message = web.system.add_one_redeem(
code, redeem_type, json.dumps(items)) code, redeem_type, item_id, item_type, item_amount)
elif amount and not code: elif redeem_amount and not code:
if amount <= 0 or amount > 1000: if redeem_amount <= 0 or redeem_amount > 1000:
flash('数量错误 Wrong amount.') flash('数量错误 Wrong amount.')
return redirect(url_for('index.change_redeem')) return redirect(url_for('index.change_redeem'))
message = web.system.add_some_random_redeem( message = web.system.add_some_random_redeem(
amount, redeem_type, json.dumps(items)) redeem_amount, redeem_type, item_id, item_type, item_amount)
elif amount and code: elif redeem_amount and code:
flash('只能使用一种添加方式 Only one add method can be used.') flash('只能使用一种添加方式 Only one add method can be used.')
return redirect(url_for('index.change_redeem')) return redirect(url_for('index.change_redeem'))
else: else:

View File

@@ -177,7 +177,7 @@ def update_user_char(c):
def update_database(): def update_database():
# 将old数据库不存在数据加入到新数据库上并删除old数据库 # 将old数据库不存在数据加入到新数据库上并删除old数据库
# 对于arcaea_datebase.db更新一些表并用character数据更新user_char # 对于arcaea_datebase.db更新一些表并用character数据更新user_char_full
# 对于arcsong.db更新songs # 对于arcsong.db更新songs
if os.path.isfile("database/old_arcaea_database.db") and os.path.isfile("database/arcaea_database.db"): if os.path.isfile("database/old_arcaea_database.db") and os.path.isfile("database/arcaea_database.db"):
with Connect('./database/old_arcaea_database.db') as c1: with Connect('./database/old_arcaea_database.db') as c1:
@@ -196,8 +196,10 @@ def update_database():
update_one_table(c1, c2, 'login') update_one_table(c1, c2, 'login')
update_one_table(c1, c2, 'present') update_one_table(c1, c2, 'present')
update_one_table(c1, c2, 'user_present') update_one_table(c1, c2, 'user_present')
update_one_table(c1, c2, 'present_item')
update_one_table(c1, c2, 'redeem') update_one_table(c1, c2, 'redeem')
update_one_table(c1, c2, 'user_redeem') update_one_table(c1, c2, 'user_redeem')
update_one_table(c1, c2, 'redeem_item')
update_one_table(c1, c2, 'role') update_one_table(c1, c2, 'role')
update_one_table(c1, c2, 'user_role') update_one_table(c1, c2, 'user_role')
update_one_table(c1, c2, 'power') update_one_table(c1, c2, 'power')
@@ -205,6 +207,10 @@ def update_database():
update_one_table(c1, c2, 'api_auth') update_one_table(c1, c2, 'api_auth')
update_one_table(c1, c2, 'user_char') update_one_table(c1, c2, 'user_char')
# ---You can comment this line by yourself, if you want to only keep newest official character data.
update_one_table(c1, c2, 'character')
# ---
update_user_char(c2) # 更新user_char_full update_user_char(c2) # 更新user_char_full
os.remove('database/old_arcaea_database.db') os.remove('database/old_arcaea_database.db')
@@ -224,13 +230,15 @@ def unlock_all_user_item(c):
c.execute('''select user_id from user''') c.execute('''select user_id from user''')
x = c.fetchall() x = c.fetchall()
c.execute('''select item_id, type from item''') c.execute('''select item_id, type from purchase_item''')
y = c.fetchall() y = c.fetchall()
c.execute('''delete from user_item''')
if x and y: if x and y:
for i in x: for i in x:
for j in y: for j in y:
c.execute('''insert into user_item values(:a,:b,:c)''', { c.execute('''select exists(select * from user_item where user_id=:a and item_id=:b and type=:c)''', {
'a': i[0], 'b': j[0], 'c': j[1]})
if c.fetchone() == (0,) and j[1] != 'character':
c.execute('''insert into user_item values(:a,:b,:c,1)''', {
'a': i[0], 'b': j[0], 'c': j[1]}) 'a': i[0], 'b': j[0], 'c': j[1]})
return return
@@ -239,14 +247,14 @@ def unlock_all_user_item(c):
def unlock_user_item(c, user_id): def unlock_user_item(c, user_id):
# 解锁用户购买 # 解锁用户购买
c.execute('''select item_id, type from item''') c.execute('''select item_id, type from purchase_item''')
y = c.fetchall() y = c.fetchall()
for j in y: for j in y:
c.execute('''select exists(select * from user_item where user_id=:a and item_id=:b and type=:c)''', { c.execute('''select exists(select * from user_item where user_id=:a and item_id=:b and type=:c)''', {
'a': user_id, 'b': j[0], 'c': j[1]}) 'a': user_id, 'b': j[0], 'c': j[1]})
if c.fetchone() == (0,): if c.fetchone() == (0,) and j[1] != 'character':
c.execute('''insert into user_item values(:a,:b,:c)''', { c.execute('''insert into user_item values(:a,:b,:c,1)''', {
'a': user_id, 'b': j[0], 'c': j[1]}) 'a': user_id, 'b': j[0], 'c': j[1]})
return return
@@ -360,7 +368,7 @@ def update_all_save(c):
return return
def add_one_present(present_id, expire_ts, description, items): def add_one_present(present_id, expire_ts, description, item_id, item_type, item_amount):
# 添加一个奖励 # 添加一个奖励
message = None message = None
@@ -368,9 +376,16 @@ def add_one_present(present_id, expire_ts, description, items):
c.execute( c.execute(
'''select exists(select * from present where present_id=:a)''', {'a': present_id}) '''select exists(select * from present where present_id=:a)''', {'a': present_id})
if c.fetchone() == (0,): if c.fetchone() == (0,):
c.execute('''insert into present values(:a,:b,:c,:d)''', { c.execute(
'a': present_id, 'b': expire_ts, 'c': items, 'd': description}) '''select exists(select * from item where item_id=? and type=?)''', (item_id, item_type))
if c.fetchone() == (1,):
c.execute('''insert into present values(:a,:b,:c)''', {
'a': present_id, 'b': expire_ts, 'c': description})
c.execute('''insert into present_item values(?,?,?,?)''',
(present_id, item_id, item_type, item_amount))
message = '添加成功 Successfully add it.' message = '添加成功 Successfully add it.'
else:
message = '物品不存在 The item does not exist.'
else: else:
message = '奖励已存在 The present exists.' message = '奖励已存在 The present exists.'
@@ -389,6 +404,8 @@ def delete_one_present(present_id):
{'a': present_id}) {'a': present_id})
c.execute('''delete from user_present where present_id =:a''', { c.execute('''delete from user_present where present_id =:a''', {
'a': present_id}) 'a': present_id})
c.execute('''delete from present_item where present_id =:a''', {
'a': present_id})
message = '删除成功 Successfully delete it.' message = '删除成功 Successfully delete it.'
else: else:
message = '奖励不存在 The present does not exist.' message = '奖励不存在 The present does not exist.'
@@ -431,7 +448,7 @@ def deliver_all_user_present(c, present_id):
return return
def add_one_redeem(code, redeem_type, items): def add_one_redeem(code, redeem_type, item_id, item_type, item_amount):
# 添加一个兑换码 # 添加一个兑换码
message = None message = None
@@ -439,28 +456,41 @@ def add_one_redeem(code, redeem_type, items):
c.execute( c.execute(
'''select exists(select * from redeem where code=:a)''', {'a': code}) '''select exists(select * from redeem where code=:a)''', {'a': code})
if c.fetchone() == (0,): if c.fetchone() == (0,):
c.execute('''insert into redeem values(:a,:b,:c)''', { c.execute(
'a': code, 'b': items, 'c': redeem_type}) '''select exists(select * from item where item_id=? and type=?)''', (item_id, item_type))
if c.fetchone() == (1,):
c.execute('''insert into redeem values(:a,:c)''', {
'a': code, 'c': redeem_type})
c.execute('''insert into redeem_item values(?,?,?,?)''',
(code, item_id, item_type, item_amount))
message = '添加成功 Successfully add it.' message = '添加成功 Successfully add it.'
else:
message = '物品不存在 The item does not exist.'
else: else:
message = '兑换码已存在 The redeem code exists.' message = '兑换码已存在 The redeem code exists.'
return message return message
def add_some_random_redeem(amount, redeem_type, items): def add_some_random_redeem(amount, redeem_type, item_id, item_type, item_amount):
# 随机生成一堆10位的兑换码 # 随机生成一堆10位的兑换码
message = None message = None
with Connect() as c: with Connect() as c:
c.execute(
'''select exists(select * from item where item_id=? and type=?)''', (item_id, item_type))
if c.fetchone() == (0,):
return '物品不存在 The item does not exist.'
i = 1 i = 1
while i <= amount: while i <= amount:
code = random_str() code = random_str()
c.execute( c.execute(
'''select exists(select * from redeem where code=:a)''', {'a': code}) '''select exists(select * from redeem where code=:a)''', {'a': code})
if c.fetchone() == (0,): if c.fetchone() == (0,):
c.execute('''insert into redeem values(:a,:b,:c)''', c.execute('''insert into redeem values(:a,:c)''',
{'a': code, 'b': items, 'c': redeem_type}) {'a': code, 'c': redeem_type})
c.execute('''insert into redeem_item values(?,?,?,?)''',
(code, item_id, item_type, item_amount))
i += 1 i += 1
message = '添加成功 Successfully add it.' message = '添加成功 Successfully add it.'
@@ -479,6 +509,8 @@ def delete_one_redeem(code):
c.execute('''delete from redeem where code = :a''', {'a': code}) c.execute('''delete from redeem where code = :a''', {'a': code})
c.execute( c.execute(
'''delete from user_redeem where code =:a''', {'a': code}) '''delete from user_redeem where code =:a''', {'a': code})
c.execute(
'''delete from redeem_item where code =:a''', {'a': code})
message = '删除成功 Successfully delete it.' message = '删除成功 Successfully delete it.'
else: else:
message = '兑换码不存在 The redeem code does not exist.' message = '兑换码不存在 The redeem code does not exist.'