13 Commits
v2.8 ... v2.8.1

Author SHA1 Message Date
Lost-MSth
5de274fdf5 Update to v2.8.1 2022-02-20 23:36:44 +08:00
Lost-MSth
b60457c38b Ready to update to v2.8.1
Wait for chart constants and character values.
2022-02-17 21:16:57 +08:00
Lost-MSth
35b954e549 Fix two bugs
- Fix a bug when downloading a beyond chart which has another audio file.

- Fix a safety problem when downloading.
2022-02-14 16:35:36 +08:00
Lost-MSth
ceebba4664 Fix a bug
Fix a bug that the high version of ios client cannot log in.
2022-01-27 19:26:13 +08:00
Lost-MSth
5bc9b9a3dc Fix a bug
Fix a bug about link play not getting the right address.
If you use reverse proxy, this may be helpful.
2022-01-24 22:38:43 +08:00
Lost-MSth
d9a543bc5a Change something about constant table and aggregate 2022-01-24 21:44:37 +08:00
Lost-MSth
4666c9c153 Merge pull request #35 from Young-Lord/master
加入aggregate
2022-01-24 21:28:44 +08:00
Lost-MSth
32bcbb0ccd Change something about aggregate 2022-01-24 21:22:38 +08:00
Young-Lord
34497d0638 Remove requests from requirements 2022-01-22 10:42:42 +08:00
Young-Lord
23bf3c020f Change the implement of experimental agreegate API 2022-01-22 10:40:06 +08:00
Young-Lord
e1fc1bbcd1 Minor fix 2022-01-22 07:35:57 +08:00
Young-Lord
355ec3557f Add experimental aggregate API 2022-01-21 22:55:23 +08:00
Young-Lord
cc4ac192e7 Update .gitignore 2022-01-21 22:53:22 +08:00
17 changed files with 1592 additions and 1309 deletions

4
.gitignore vendored
View File

@@ -1 +1,5 @@
*.log *.log
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

View File

@@ -66,20 +66,23 @@ 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.8 ### Version 2.8.1
- 适用于Arcaea 3.11.2版本 For Arcaea 3.11.2 - 适用于Arcaea 3.12.0版本 For Arcaea 3.12.0
- 更新了歌曲数据库 Update the song database. - 更新了歌曲数据库 Update the song database.
-增对Link Play的支持 Add support for Link Play. -搭档**维塔**已解锁 Unlock the character **Vita**.
- 搭档**彩梦**已觉醒 Uncap the character **ayu**. - 新增对**维塔**的技能支持 Add support for the skill of **Vita**.
- 修正世界模式进度计算方式 Revise the algorithm of world mode progress.
- 修复世界模式下 **对立(风暴)** 数值计算错误的问题 Fix the wrong value of **Tairitsu(Tempest)** in the World Mode.
- 以下是累积更新 The following are cumulative updates: - 以下是累积更新 The following are cumulative updates:
- 修复注册接口端点多了个杠的问题 Fix an unexpected slash at the registered interface endpoint. - #35 集成式接口优化By Young-Lord Optimize `aggregate` interface. (By Young-Lord)
-搭档**白姬**已解锁 Unlock the character **shirahime**. -增填写Link Play服务器地址的选项解决地址无法正确自动获取的问题 Add the option of filling in Link Play server address, which can solve the problem that the address cannot be obtained automatically.
-正两个角色的数值问题 Fix the values of two characters. -复高版本iOS客户端无法登陆的问题 Fix a bug that the high version of iOS client cannot log in.
- 新搭档**玛莉嘉**已解锁 Unlock the character **marija**. - 修复有关下载的安全性问题 Fix a safety problem about downloading.
- 修复有不同音频的Beyond谱面无法下载的问题 Fix a bug about unable to download a beyond chart which has another audio file.
> 提示Link Play可能存在大量bug
> Tips: There may be many bugs in Link Play system.
## 运行环境与依赖 Running environment and requirements ## 运行环境与依赖 Running environment and requirements

Binary file not shown.

View File

@@ -4,7 +4,7 @@ import json
# 数据库初始化文件删掉arcaea_database.db文件后运行即可谨慎使用 # 数据库初始化文件删掉arcaea_database.db文件后运行即可谨慎使用
ARCAEA_SERVER_VERSION = 'v2.8' ARCAEA_SERVER_VERSION = 'v2.8.1'
def main(path='./'): def main(path='./'):
@@ -299,46 +299,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', 'linka', 'nami', 'Saya & Elizabeth', 'lily', 'kanae(midsummer)', 'alice&tenniel(minuet)', 'tairitsu(elegy)', 'marija'] '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', 'linka', 'nami', 'Saya & Elizabeth', 'lily', 'kanae(midsummer)', 'alice&tenniel(minuet)', 'tairitsu(elegy)', 'marija', 'vita']
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', 'gauge_safe_10', 'frags_nami', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', '', '', 'visual_ghost_skynotes'] '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_elizabeth', 'skill_lily', 'skill_kanae_midsummer', '', '', 'visual_ghost_skynotes', 'skill_vita']
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', 'eto_uncap', 'luna_uncap', 'shirabe_entry_fee', skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', 'eto_uncap', 'luna_uncap', 'shirabe_entry_fee',
'', '', '', '', '', 'ayu_uncap', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] '', '', '', '', '', 'ayu_uncap', '', '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, 0, 0, 0, 0, 8] 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, 0, 0, 0, 0, 8, 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, 50, 25, 58, 50, 61, 45, 45, 38] 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, 58, 50, 61, 45, 45, 38, 34]
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, 50, 50, 45, 41, 61, 45, 45, 58] 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, 45, 41, 61, 45, 45, 58, 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, 50, 30, 49, 15, 34, 45, 45, 38] 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, 49, 15, 34, 45, 45, 38, 67]
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, 100, 50, 68, 60, 90, 67, 50, 60] 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, 68, 60, 90, 67, 50, 60, 51]
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, 100, 55, 65, 59, 90, 50, 90, 90] 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, 65, 59, 90, 50, 90, 90, 75]
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, 100, 40, 69, 62, 51, 90, 67, 60] 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, 69, 62, 51, 90, 67, 60, 100]
frag30 = [88, 90, 100, 75, 80, 0, 70, 79, 65, 40, 50, 90, 100, 92, 0, 61, 67, 92, 85, 50, 86, 62, frag30 = [88, 90, 100, 75, 80, 0, 70, 79, 65, 40, 50, 90, 100, 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, 100, 50, 68, 60, 90, 67, 50, 60] 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, 68, 60, 90, 67, 50, 60, 51]
prog30 = [71, 90, 80, 75, 100, 0, 90, 102, 84, 78, 105, 77, 73, 78, 0, 99, 80, 66, 46, 93, 40, 83, prog30 = [71, 90, 80, 75, 100, 0, 90, 102, 84, 78, 105, 77, 73, 78, 0, 99, 80, 66, 46, 93, 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, 100, 55, 65, 59, 90, 50, 90, 90] 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, 65, 59, 90, 50, 90, 90, 75]
overdrive30 = [71, 90, 57, 75, 80, 0, 95, 79, 65, 31, 50, 69, 100, 68, 0, 78, 50, 70, 62, 59, 64, overdrive30 = [71, 90, 57, 75, 80, 0, 95, 79, 65, 31, 50, 69, 100, 68, 0, 78, 50, 70, 62, 59, 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, 100, 40, 69, 62, 51, 90, 67, 60] 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, 69, 62, 51, 90, 67, 60, 100]
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, 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, 0, 0, 0, 0, 0, 0, 2]
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}],
@@ -359,7 +359,7 @@ def main(path='./'):
19: [{'core_id': 'core_colorful', 'amount': 30}] 19: [{'core_id': 'core_colorful', 'amount': 30}]
} }
for i in range(0, 54): for i in range(0, 55):
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, 11, 12, 19]: if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43, 11, 12, 19]:
@@ -386,12 +386,12 @@ def main(path='./'):
c.execute('''insert into item values(?,"core",1,'')''', (i,)) c.execute('''insert into item values(?,"core",1,'')''', (i,))
world_songs = ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster", world_songs = ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster",
"cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take", "lifeispiano", "vandalism", "nexttoyou3", "lostcivilization3", "turbocharger", "bookmaker3", "laqryma3", "kyogenkigo", "hivemind", "seclusion", "quonwacca3", "bluecomet", "energysynergymatrix", "gengaozo", "lastendconductor3", "antithese3", "qualia3", "kanagawa3", "heavensdoor3", "pragmatism3"] "cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take", "lifeispiano", "vandalism", "nexttoyou3", "lostcivilization3", "turbocharger", "bookmaker3", "laqryma3", "kyogenkigo", "hivemind", "seclusion", "quonwacca3", "bluecomet", "energysynergymatrix", "gengaozo", "lastendconductor3", "antithese3", "qualia3", "kanagawa3", "heavensdoor3", "pragmatism3", "nulctrl", "avril"]
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,))
world_unlocks = ["scenery_chap1", "scenery_chap2", world_unlocks = ["scenery_chap1", "scenery_chap2",
"scenery_chap3", "scenery_chap4", "scenery_chap5"] "scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6"]
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,))

View File

@@ -1054,5 +1054,77 @@
], ],
"orig_price": 100, "orig_price": 100,
"price": 100 "price": 100
},
{
"name": "internetoverdose",
"items": [
{
"type": "single",
"id": "internetoverdose",
"is_available": true
},
{
"type": "core",
"amount": 1,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 100,
"price": 100
},
{
"name": "macromod",
"items": [
{
"type": "single",
"id": "macromod",
"is_available": true
},
{
"type": "core",
"amount": 1,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 100,
"price": 100
},
{
"name": "neowings",
"items": [
{
"type": "single",
"id": "neowings",
"is_available": true
},
{
"type": "core",
"amount": 1,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 100,
"price": 100
},
{
"name": "kissinglucifer",
"items": [
{
"type": "single",
"id": "kissinglucifer",
"is_available": true
},
{
"type": "core",
"amount": 1,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 100,
"price": 100
} }
] ]

View File

@@ -1,6 +1,6 @@
# encoding: utf-8 # encoding: utf-8
from flask import Flask, json, request, jsonify, make_response, send_from_directory from flask import Flask, json, request, jsonify, send_from_directory
from logging.config import dictConfig from logging.config import dictConfig
from setting import Config from setting import Config
import base64 import base64
@@ -23,6 +23,10 @@ import sys
from multiprocessing import Process, Pipe from multiprocessing import Process, Pipe
from urllib.parse import parse_qs, urlparse
from werkzeug.datastructures import ImmutableMultiDict
app = Flask(__name__) app = Flask(__name__)
wsgi_app = app.wsgi_app wsgi_app = app.wsgi_app
@@ -122,10 +126,16 @@ def error_return(error_code, extra={}): # 错误返回
}) })
def success_return(value):
return jsonify({
"success": True,
"value": value
})
@app.route('/') @app.route('/')
def hello(): def hello():
return "Hello World!" return "Hello World!"
# 自定义路径
@app.route('/favicon.ico', methods=['GET']) # 图标 @app.route('/favicon.ico', methods=['GET']) # 图标
@@ -153,10 +163,10 @@ def login():
else: else:
device_id = 'low_version' device_id = 'low_version'
token, error_code, extra = server.auth.arc_login( token, user_id, 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", 'user_id': user_id}
r['access_token'] = token r['access_token'] = token
return jsonify(r) return jsonify(r)
else: else:
@@ -191,25 +201,83 @@ def register():
return error_return(error_code) return error_return(error_code)
# 集成式请求,没想到什么好办法处理,就先这样写着 @app.route(add_url_prefix('/purchase/bundle/pack'), methods=['GET']) # 曲包信息
@app.route(add_url_prefix('/compose/aggregate'), methods=['GET'])
@server.auth.auth_required(request) @server.auth.auth_required(request)
def aggregate(user_id): def bundle_pack(user_id):
calls = request.args.get('calls') return success_return(server.info.get_purchase_pack(user_id))
if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断我猜get的参数就两种
r = server.info.arc_aggregate_small(user_id)
else:
r = server.info.arc_aggregate_big(user_id)
return jsonify(r)
@app.route(add_url_prefix('/user/me'), methods=['GET']) # 用户信息给baa查分器用的 @app.route(add_url_prefix('/game/info'), methods=['GET']) # 系统信息
def game_info():
return success_return(server.info.get_game_info())
@app.route(add_url_prefix('/present/me'), methods=['GET']) # 用户奖励信息
@server.auth.auth_required(request)
def present_info(user_id):
return success_return(server.info.get_user_present(user_id))
@app.route(add_url_prefix('/compose/aggregate'), methods=['GET']) # 集成式请求
def aggregate():
try:
#global request
finally_response = {'success': True, 'value': []}
#request_ = request
get_list = json.loads(request.args.get('calls'))
if len(get_list) > 10:
# 请求太多驳回
return error_return(108)
for i in get_list:
endpoint = i['endpoint']
url = add_url_prefix(endpoint)
request.args = ImmutableMultiDict(
{key: value[0] for key, value in parse_qs(urlparse(url).query).items()})
resp_t = map_dict[urlparse(endpoint).path]()
if hasattr(resp_t, "response"):
resp_t = resp_t.response[0].decode().rstrip('\n')
resp = json.loads(resp_t)
if hasattr(resp, 'get') and resp.get('success') is False:
finally_response = {'success': False, 'error_code': 7, 'extra': {
"id": i['id'], 'error_code': resp.get('error_code')}}
if "extra" in resp:
finally_response['extra']['extra'] = resp['extra']
#request = request_
return jsonify(finally_response)
finally_response['value'].append(
{'id': i.get('id'), 'value': resp['value'] if hasattr(resp, 'get') else resp})
#request = request_
return jsonify(finally_response)
except KeyError:
return error_return(108)
# # 集成式请求,没想到什么好办法处理,就先这样写着
# @app.route(add_url_prefix('/compose/aggregate'), methods=['GET'])
# @server.auth.auth_required(request)
# def aggregate(user_id):
# calls = request.args.get('calls')
# if calls == '[{ "endpoint": "/user/me", "id": 0 }]': # 极其沙雕的判断我猜get的参数就两种
# r = server.info.arc_aggregate_small(user_id)
# else:
# r = server.info.arc_aggregate_big(user_id)
# return jsonify(r)
@app.route(add_url_prefix('/user/me'), methods=['GET']) # 用户信息
@server.auth.auth_required(request) @server.auth.auth_required(request)
def user_me(user_id): def user_me(user_id):
r = server.info.arc_aggregate_small(user_id) r = server.info.get_user_me_c(user_id)
if r['success']: if r:
r['value'] = r['value'][0]['value'] return success_return(r)
return jsonify(r) else:
return error_return(108)
@app.route(add_url_prefix('/user/me/character'), methods=['POST']) # 角色切换 @app.route(add_url_prefix('/user/me/character'), methods=['POST']) # 角色切换
@@ -614,10 +682,11 @@ def world_one(user_id, map_id):
@server.auth.auth_required(request) @server.auth.auth_required(request)
def download_song(user_id): def download_song(user_id):
song_ids = request.args.getlist('sid') song_ids = request.args.getlist('sid')
if server.arcdownload.is_able_download(user_id): url_flag = json.loads(request.args.get('url', 'true'))
if server.arcdownload.is_able_download(user_id) or not url_flag:
re = {} re = {}
if not song_ids: if not song_ids:
re = server.arcdownload.get_all_songs(user_id) re = server.arcdownload.get_all_songs(user_id, url_flag=url_flag)
else: else:
re = server.arcdownload.get_some_songs(user_id, song_ids) re = server.arcdownload.get_some_songs(user_id, song_ids)
@@ -633,7 +702,7 @@ def download_song(user_id):
def download(file_path): def download(file_path):
try: try:
t = request.args.get('t') t = request.args.get('t')
message = server.arcdownload.is_token_able_download(t) message = server.arcdownload.is_token_able_download(t, file_path)
if message == 0: if message == 0:
path = os.path.join('./database/songs', file_path) path = os.path.join('./database/songs', file_path)
if os.path.isfile(path) and not('../' in path or '..\\' in path): if os.path.isfile(path) and not('../' in path or '..\\' in path):
@@ -658,7 +727,11 @@ def room_create(user_id):
conn1, user_id, client_song_map) conn1, user_id, client_song_map)
if error_code == 0: if error_code == 0:
value['endPoint'] = request.host.split(':')[0] if Config.LINK_PLAY_HOST == '':
value['endPoint'] = request.host.split(':')[0]
else:
value['endPoint'] = Config.LINK_PLAY_HOST
value['port'] = int(Config.UDP_PORT) value['port'] = int(Config.UDP_PORT)
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -680,7 +753,11 @@ def room_join(user_id, room_code):
conn1, user_id, client_song_map, room_code) conn1, user_id, client_song_map, room_code)
if error_code == 0: if error_code == 0:
value['endPoint'] = request.host.split(':')[0] if Config.LINK_PLAY_HOST == '':
value['endPoint'] = request.host.split(':')[0]
else:
value['endPoint'] = Config.LINK_PLAY_HOST
value['port'] = int(Config.UDP_PORT) value['port'] = int(Config.UDP_PORT)
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -700,7 +777,11 @@ def multiplayer_update(user_id):
error_code, value = server.arclinkplay.update_room(conn1, user_id, token) error_code, value = server.arclinkplay.update_room(conn1, user_id, token)
if error_code == 0: if error_code == 0:
value['endPoint'] = request.host.split(':')[0] if Config.LINK_PLAY_HOST == '':
value['endPoint'] = request.host.split(':')[0]
else:
value['endPoint'] = Config.LINK_PLAY_HOST
value['port'] = int(Config.UDP_PORT) value['port'] = int(Config.UDP_PORT)
return jsonify({ return jsonify({
"success": True, "success": True,
@@ -723,9 +804,20 @@ def sys_set(user_id, path):
set_arg = path[5:] 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.get_user_me_c(user_id)
r['value'] = r['value'][0]['value'] if r:
return jsonify(r) return success_return(r)
else:
return error_return(108)
map_dict = {'/user/me': user_me,
'/purchase/bundle/pack': bundle_pack,
'/serve/download/me/song': download_song,
'/game/info': game_info,
'/present/me': present_info,
'/world/map/me': world_all,
'/score/song/friend': song_score_friend}
def main(): def main():

View File

@@ -51,11 +51,14 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs', url_flag=True
'a': user_id, 'b': song_id}) 'a': user_id, 'b': song_id})
for i in dir_list: for i in dir_list:
if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg']: if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg', '3.ogg']:
token = hashlib.md5( token = hashlib.md5(
(str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest() (str(user_id) + song_id + i + str(now)).encode(encoding='UTF-8')).hexdigest()
if i == 'base.ogg': if i == 'base.ogg':
if 'audio' not in re:
re['audio'] = {}
c.execute( c.execute(
'''select md5 from songfile where song_id=:a and file_type=-1''', {'a': song_id}) '''select md5 from songfile where song_id=:a and file_type=-1''', {'a': song_id})
x = c.fetchone() x = c.fetchone()
@@ -65,11 +68,29 @@ def get_one_song(c, user_id, song_id, file_dir='./database/songs', url_flag=True
checksum = get_file_md5(os.path.join( checksum = get_file_md5(os.path.join(
file_dir, song_id, 'base.ogg')) file_dir, song_id, 'base.ogg'))
re['audio']["checksum"] = checksum
if url_flag: if url_flag:
re['audio'] = {"checksum": checksum, "url": get_url( re['audio']["url"] = get_url(
file_path=song_id+'/base.ogg', t=token)} file_path=song_id+'/base.ogg', t=token)
elif i == '3.ogg':
if 'audio' not in re:
re['audio'] = {}
c.execute(
'''select md5 from songfile where song_id=:a and file_type=-2''', {'a': song_id})
x = c.fetchone()
if x:
checksum = x[0]
else: else:
re['audio'] = {"checksum": checksum} checksum = get_file_md5(os.path.join(
file_dir, song_id, '3.ogg'))
if url_flag:
re['audio']['3'] = {"checksum": checksum, "url": get_url(
file_path=song_id+'/3.ogg', t=token)}
else:
re['audio']['3'] = {"checksum": checksum}
else: else:
if 'chart' not in re: if 'chart' not in re:
re['chart'] = {} re['chart'] = {}
@@ -116,7 +137,7 @@ def get_some_songs(user_id, song_ids):
return re return re
def is_token_able_download(t): def is_token_able_download(t, path):
# token是否可以下载返回错误码0即可以 # token是否可以下载返回错误码0即可以
errorcode = 108 errorcode = 108
with Connect() as c: with Connect() as c:
@@ -124,7 +145,7 @@ def is_token_able_download(t):
{'t': t}) {'t': t})
x = c.fetchone() x = c.fetchone()
now = int(time.time()) now = int(time.time())
if x and now - x[4] <= time_gap_limit: if x and now - x[4] <= time_gap_limit and x[1]+'/'+x[2] == path:
c.execute( c.execute(
'''select count(*) from user_download where user_id = :a''', {'a': x[0]}) '''select count(*) from user_download where user_id = :a''', {'a': x[0]})
y = c.fetchone() y = c.fetchone()
@@ -162,10 +183,13 @@ def initialize_one_songfile(c, song_id, file_dir='./database/songs'):
# 计算并添加歌曲md5到表中无返回 # 计算并添加歌曲md5到表中无返回
dir_list = os.listdir(os.path.join(file_dir, song_id)) dir_list = os.listdir(os.path.join(file_dir, song_id))
for i in dir_list: for i in dir_list:
if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg']: if os.path.isfile(os.path.join(file_dir, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg', '3.ogg']:
if i == 'base.ogg': if i == 'base.ogg':
c.execute('''insert into songfile values(:a,-1,:c)''', { c.execute('''insert into songfile values(:a,-1,:c)''', {
'a': song_id, 'c': get_file_md5(os.path.join(file_dir, song_id, 'base.ogg'))}) 'a': song_id, 'c': get_file_md5(os.path.join(file_dir, song_id, 'base.ogg'))})
elif i == '3.ogg':
c.execute('''insert into songfile values(:a,-2,:c)''', {
'a': song_id, 'c': get_file_md5(os.path.join(file_dir, song_id, '3.ogg'))})
else: else:
c.execute('''insert into songfile values(:a,:b,:c)''', { c.execute('''insert into songfile values(:a,:b,:c)''', {
'a': song_id, 'b': int(i[0]), 'c': get_file_md5(os.path.join(file_dir, song_id, i))}) 'a': song_id, 'b': int(i[0]), 'c': get_file_md5(os.path.join(file_dir, song_id, i))})

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
import json import json
from server.sql import Connect from server.sql import Connect
from .config import Constant
from setting import Config from setting import Config
import server.item import server.item
import server.character import server.character
@@ -10,11 +11,6 @@ import time
import random import random
ETO_UNCAP_BONUS_PROGRESS = 7
LUNA_UNCAP_BONUS_PROGRESS = 7
AYU_UNCAP_BONUS_PROGRESS = 5
def int2b(x): def int2b(x):
# int与布尔值转换 # int与布尔值转换
if x is None or x == 0: if x is None or x == 0:
@@ -26,14 +22,14 @@ def int2b(x):
def calc_stamina(max_stamina_ts, curr_stamina): def calc_stamina(max_stamina_ts, curr_stamina):
# 计算体力,返回剩余体力数值 # 计算体力,返回剩余体力数值
stamina = int(server.info.MAX_STAMINA - (max_stamina_ts - stamina = int(Constant.MAX_STAMINA - (max_stamina_ts -
int(time.time()*1000)) / server.info.STAMINA_RECOVER_TICK) int(time.time()*1000)) / Constant.STAMINA_RECOVER_TICK)
if stamina >= server.info.MAX_STAMINA: if stamina >= Constant.MAX_STAMINA:
if curr_stamina >= server.info.MAX_STAMINA: if curr_stamina >= Constant.MAX_STAMINA:
stamina = curr_stamina stamina = curr_stamina
else: else:
stamina = server.info.MAX_STAMINA stamina = Constant.MAX_STAMINA
if stamina < 0: if stamina < 0:
stamina = 0 stamina = 0
@@ -245,8 +241,8 @@ def play_world_song(user_id, args):
return {} return {}
stamina = calc_stamina(max_stamina_ts, stamina) - \ stamina = calc_stamina(max_stamina_ts, stamina) - \
info['stamina_cost'] * stamina_multiply info['stamina_cost'] * stamina_multiply
max_stamina_ts = now + server.info.STAMINA_RECOVER_TICK * \ max_stamina_ts = now + Constant.STAMINA_RECOVER_TICK * \
(server.info.MAX_STAMINA - stamina) (Constant.MAX_STAMINA - stamina)
c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''', c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''',
(max_stamina_ts, stamina, user_id)) (max_stamina_ts, stamina, user_id))
r = { r = {
@@ -356,7 +352,7 @@ def climb_step(user_id, map_id, step, prev_capture, prev_position):
return rewards, steps, curr_position, curr_capture, info return rewards, steps, curr_position, curr_capture, info
def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gauge, stamina_multiply=1, fragment_multiply=100, prog_boost_multiply=0): def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gauge, health, stamina_multiply=1, fragment_multiply=100, prog_boost_multiply=0):
# 成绩上传后世界模式更新,返回字典 # 成绩上传后世界模式更新,返回字典
step_times = stamina_multiply * fragment_multiply / \ step_times = stamina_multiply * fragment_multiply / \
@@ -377,6 +373,11 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
is_skill_sealed = x[3] if x and x[3] is not None else 1 is_skill_sealed = x[3] if x and x[3] is not None else 1
skill = False skill = False
skill_uncap = False skill_uncap = False
level = 1
exp = 0
frag = 50
prog = 50
overdrive = 50
if not is_skill_sealed: if not is_skill_sealed:
if x: if x:
skill = True skill = True
@@ -385,55 +386,76 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
if x[5] is not None and x[5] == 1: if x[5] is not None and x[5] == 1:
skill_uncap = False skill_uncap = False
c.execute('''select frag1,prog1,overdrive1,frag20,prog20,overdrive20,frag30,prog30,overdrive30,skill_id,skill_id_uncap from character where character_id=?''', (character_id,)) c.execute('''select frag1,prog1,overdrive1,frag20,prog20,overdrive20,frag30,prog30,overdrive30,skill_id,skill_id_uncap from character where character_id=?''', (character_id,))
x = c.fetchone() x = c.fetchone()
if Config.CHARACTER_FULL_UNLOCK: if Config.CHARACTER_FULL_UNLOCK:
c.execute('''select level, exp from user_char_full where user_id = :a and character_id = :b''', { c.execute('''select level, exp from user_char_full where user_id = :a and character_id = :b''', {
'a': user_id, 'b': character_id}) 'a': user_id, 'b': character_id})
else:
c.execute('''select level, exp from user_char where user_id = :a and character_id = :b''', {
'a': user_id, 'b': character_id})
y = c.fetchone()
if y:
level = y[0]
exp = y[1]
else:
level = 1
exp = 0
if x:
flag = server.character.calc_char_value(level, x[0], x[3], x[6])
prog = server.character.calc_char_value(level, x[1], x[4], x[7])
overdrive = server.character.calc_char_value(level, x[2], x[5], x[8])
if x[9] is not None and x[9] != '' and skill:
skill = x[9]
else: else:
c.execute('''select level, exp from user_char where user_id = :a and character_id = :b''', {
'a': user_id, 'b': character_id})
y = c.fetchone()
if y:
level = y[0]
exp = y[1]
else:
level = 1
exp = 0
if x:
frag = server.character.calc_char_value(level, x[0], x[3], x[6])
prog = server.character.calc_char_value(level, x[1], x[4], x[7])
overdrive = server.character.calc_char_value(
level, x[2], x[5], x[8])
if x[9] is not None and x[9] != '' and skill:
skill = x[9]
else:
skill = None
if x[10] is not None and x[9] != '' and skill_uncap:
skill_uncap = x[10]
else:
skill_uncap = None
else:
frag = 0
prog = 0
overdrive = 0
skill = None skill = None
if x[10] is not None and x[9] != '' and skill_uncap:
skill_uncap = x[10]
else:
skill_uncap = None skill_uncap = None
else:
flag = 0 skill_special = ''
prog = 0 if skill_uncap is not None and skill_uncap and skill_uncap in ['eto_uncap', 'luna_uncap', 'ayu_uncap', 'skill_vita']:
overdrive = 0 skill_special = skill_uncap
skill = None elif skill is not None and skill and skill in ['eto_uncap', 'luna_uncap', 'ayu_uncap', 'skill_vita']:
skill_uncap = None skill_special = skill
c.execute('''select current_map from user where user_id = :a''', { c.execute('''select current_map from user where user_id = :a''', {
'a': user_id}) 'a': user_id})
map_id = c.fetchone()[0] map_id = c.fetchone()[0]
if beyond_gauge == 0: # 是否是beyond挑战 if beyond_gauge == 0: # 是否是beyond挑战
prog_tempest = 0
if not is_skill_sealed and character_id == 35:
# 风暴对立
if Config.CHARACTER_FULL_UNLOCK:
prog_tempest = 60
else:
c.execute(
'''select sum(level) from user_char where user_id=?''', (user_id,))
prog_tempest = int(x[0]) / 10 if x else 0
if prog_tempest > 60:
prog_tempest = 60
elif prog_tempest < 0:
prog_tempest = 0
base_step = 2.5 + 2.45*rating**0.5 base_step = 2.5 + 2.45*rating**0.5
step = base_step * (prog/50) * step_times step = base_step * (prog + prog_tempest) / 50 * step_times
else: else:
info = get_world_info(map_id) info = get_world_info(map_id)
if clear_type == 0: if clear_type == 0:
base_step = 8/9 + (rating/1.3)**0.5 base_step = 25/28 + (rating)**0.5 * 0.43
else: else:
base_step = 8/3 + (rating/1.3)**0.5 base_step = 75/28 + (rating)**0.5 * 0.43
if character_id in info['character_affinity']: if character_id in info['character_affinity']:
affinity_multiplier = info['affinity_multiplier'][info['character_affinity'].index( affinity_multiplier = info['affinity_multiplier'][info['character_affinity'].index(
@@ -441,7 +463,17 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
else: else:
affinity_multiplier = 1 affinity_multiplier = 1
step = base_step * (prog/50) * step_times * affinity_multiplier if skill_special == 'skill_vita':
# vita技能overdrive随回忆率提升提升量最多为10
# 此处采用线性函数
overdrive_extra = 0
if 0 < health <= 100:
overdrive_extra = health / 10
overdrive += overdrive_extra
step = base_step * overdrive / 50 * \
step_times * affinity_multiplier
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})
@@ -451,13 +483,9 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
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])
# Eto和Luna的技能
# Eto、Luna、Ayu的技能
character_bonus_progress = None character_bonus_progress = None
skill_special = ''
if skill_uncap is not None and skill_uncap and skill_uncap in ['eto_uncap', 'luna_uncap', 'ayu_uncap']:
skill_special = skill_uncap
elif skill is not None and skill and skill in ['eto_uncap', 'luna_uncap', 'ayu_uncap']:
skill_special = skill
if skill_special == 'eto_uncap': if skill_special == 'eto_uncap':
# eto觉醒技能获得残片奖励时世界模式进度加7 # eto觉醒技能获得残片奖励时世界模式进度加7
fragment_flag = False fragment_flag = False
@@ -469,7 +497,7 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
if fragment_flag: if fragment_flag:
break break
if fragment_flag: if fragment_flag:
character_bonus_progress = ETO_UNCAP_BONUS_PROGRESS character_bonus_progress = Constant.ETO_UNCAP_BONUS_PROGRESS
step += character_bonus_progress * step_times step += character_bonus_progress * step_times
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]) # 二次爬梯,重新计算
@@ -477,7 +505,7 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
elif skill_special == 'luna_uncap': elif skill_special == 'luna_uncap':
# luna觉醒技能限制格开始时世界模式进度加7 # luna觉醒技能限制格开始时世界模式进度加7
if 'restrict_id' in steps[0] and 'restrict_type' in steps[0] and steps[0]['restrict_type'] != '' and steps[0]['restrict_id'] != '': if 'restrict_id' in steps[0] and 'restrict_type' in steps[0] and steps[0]['restrict_type'] != '' and steps[0]['restrict_id'] != '':
character_bonus_progress = LUNA_UNCAP_BONUS_PROGRESS character_bonus_progress = Constant.LUNA_UNCAP_BONUS_PROGRESS
step += character_bonus_progress * step_times step += character_bonus_progress * step_times
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]) # 二次爬梯,重新计算
@@ -485,9 +513,9 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
elif skill_special == 'ayu_uncap': elif skill_special == 'ayu_uncap':
# ayu觉醒技能世界模式进度+5或-5但不会小于0 # ayu觉醒技能世界模式进度+5或-5但不会小于0
if random.random() >= 0.5: if random.random() >= 0.5:
character_bonus_progress = AYU_UNCAP_BONUS_PROGRESS character_bonus_progress = Constant.AYU_UNCAP_BONUS_PROGRESS
else: else:
character_bonus_progress = -AYU_UNCAP_BONUS_PROGRESS character_bonus_progress = -Constant.AYU_UNCAP_BONUS_PROGRESS
step += character_bonus_progress * step_times step += character_bonus_progress * step_times
if step < 0: if step < 0:
@@ -515,62 +543,42 @@ def world_update(c, user_id, song_id, difficulty, rating, clear_type, beyond_gau
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))
else: else:
exp = server.character.LEVEL_STEPS[level] exp = Constant.LEVEL_STEPS[level]
re = {
"rewards": rewards,
"exp": exp,
"level": level,
"base_progress": base_step,
"progress": step,
"user_map": {
"user_id": user_id,
"curr_position": curr_position,
"curr_capture": curr_capture,
"is_locked": int2b(y[4]),
"map_id": map_id,
"prev_capture": y[3],
"prev_position": y[2],
"beyond_health": info['beyond_health']
},
"char_stats": {
"character_id": character_id,
"frag": frag,
"prog": prog,
"overdrive": overdrive
},
"current_stamina": calc_stamina(max_stamina_ts, stamina),
"max_stamina_ts": max_stamina_ts
}
if beyond_gauge == 0: if beyond_gauge == 0:
re = { re["user_map"]["steps"] = steps
"rewards": rewards,
"exp": exp,
"level": level,
"base_progress": base_step,
"progress": step,
"user_map": {
"user_id": user_id,
"curr_position": curr_position,
"curr_capture": curr_capture,
"is_locked": int2b(y[4]),
"map_id": map_id,
"prev_capture": y[3],
"prev_position": y[2],
"beyond_health": info['beyond_health'],
"steps": steps
},
"char_stats": {
"character_id": character_id,
"frag": flag,
"prog": prog,
"overdrive": overdrive
},
"current_stamina": calc_stamina(max_stamina_ts, stamina),
"max_stamina_ts": max_stamina_ts
}
else: else:
re = { re["user_map"]["steps"] = len(steps)
"rewards": rewards,
"exp": exp, if character_id == 35 and not is_skill_sealed:
"level": level, re['char_stats']['prog_tempest'] = prog_tempest
"base_progress": base_step, re['char_stats']['prog'] += prog_tempest
"progress": step,
"user_map": {
"user_id": user_id,
"curr_position": curr_position,
"curr_capture": curr_capture,
"is_locked": int2b(y[4]),
"map_id": map_id,
"prev_capture": y[3],
"prev_position": y[2],
"beyond_health": info['beyond_health'],
"step_count": len(steps)
},
"char_stats": {
"character_id": character_id,
"frag": flag,
"prog": prog,
"overdrive": overdrive
},
"current_stamina": calc_stamina(max_stamina_ts, stamina),
"max_stamina_ts": max_stamina_ts
}
if character_bonus_progress is not None: if character_bonus_progress is not None:
re['character_bonus_progress'] = character_bonus_progress re['character_bonus_progress'] = character_bonus_progress
@@ -600,11 +608,11 @@ def add_stamina(c, user_id, add_stamina):
if x and x[0] is not None and x[1] is not None: if x and x[0] is not None and x[1] is not None:
stamina = calc_stamina(x[0], x[1]) + add_stamina stamina = calc_stamina(x[0], x[1]) + add_stamina
max_stamina_ts = now - \ max_stamina_ts = now - \
(stamina-server.info.MAX_STAMINA) * \ (stamina-Constant.MAX_STAMINA) * \
server.info.STAMINA_RECOVER_TICK Constant.STAMINA_RECOVER_TICK
else: else:
max_stamina_ts = now max_stamina_ts = now
stamina = server.info.MAX_STAMINA stamina = Constant.MAX_STAMINA
c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''', c.execute('''update user set max_stamina_ts=?, stamina=? where user_id=?''',
(max_stamina_ts, stamina, user_id)) (max_stamina_ts, stamina, user_id))

View File

@@ -9,12 +9,13 @@ 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和extra # 查询数据库中的user表验证账号密码返回并记录token和user_id多返回个error code和extra
# token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear # token采用user_id和时间戳连接后hash生成真的是瞎想的没用bear
# 密码和token的加密方式为 SHA-256 # 密码和token的加密方式为 SHA-256
error_code = 108 error_code = 108
token = None token = None
user_id = 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, ban_flag from user where name = :name''', { c.execute('''select user_id, password, ban_flag from user where name = :name''', {
@@ -61,7 +62,7 @@ def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判
'''select count(*) from login where user_id=? and login_time>?''', (user_id, now-86400000)) '''select count(*) from login where user_id=? and login_time>?''', (user_id, now-86400000))
if c.fetchone()[0] >= Config.LOGIN_DEVICE_NUMBER_LIMIT: if c.fetchone()[0] >= Config.LOGIN_DEVICE_NUMBER_LIMIT:
remaining_ts = arc_auto_ban(c, user_id, now) remaining_ts = arc_auto_ban(c, user_id, now)
return None, 105, {'remaining_ts': remaining_ts} return None, 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)})
@@ -76,7 +77,7 @@ def arc_login(name: str, password: str, device_id: str, ip: str): # 登录判
# 用户名错误 # 用户名错误
error_code = 104 error_code = 104
return token, error_code, None return token, user_id, 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): # 注册

View File

@@ -1,12 +1,10 @@
from setting import Config from setting import Config
from server.sql import Connect from server.sql import Connect
from .config import Constant
import server.info import server.info
import server.item import server.item
import server.setme import server.setme
LEVEL_STEPS = {1: 0, 2: 50, 3: 100, 4: 150, 5: 200, 6: 300, 7: 450, 8: 650, 9: 900, 10: 1200, 11: 1600, 12: 2100, 13: 2700, 14: 3400, 15: 4200, 16: 5100,
17: 6100, 18: 7200, 19: 8500, 20: 10000, 21: 11500, 22: 13000, 23: 14500, 24: 16000, 25: 17500, 26: 19000, 27: 20500, 28: 22000, 29: 23500, 30: 25000}
def int2b(x): def int2b(x):
# int与布尔值转换 # int与布尔值转换
@@ -18,7 +16,7 @@ def int2b(x):
def get_level_steps(): def get_level_steps():
# 返回level_steps字典数组 # 返回level_steps字典数组
return [{'level': i, 'level_exp': LEVEL_STEPS[i]} for i in LEVEL_STEPS] return [{'level': i, 'level_exp': Constant.LEVEL_STEPS[i]} for i in Constant.LEVEL_STEPS]
def calc_char_value(level, value1, value20, value30): def calc_char_value(level, value1, value20, value30):
@@ -114,7 +112,7 @@ def get_user_character(c, user_id):
"overdrive": calc_char_value(i[2], i[11], i[14], i[17]), "overdrive": calc_char_value(i[2], i[11], i[14], i[17]),
"prog": calc_char_value(i[2], i[10], i[13], i[16]), "prog": calc_char_value(i[2], i[10], i[13], i[16]),
"frag": calc_char_value(i[2], i[9], i[12], i[15]), "frag": calc_char_value(i[2], i[9], i[12], i[15]),
"level_exp": LEVEL_STEPS[i[2]], "level_exp": Constant.LEVEL_STEPS[i[2]],
"exp": i[3], "exp": i[3],
"level": i[2], "level": i[2],
"name": i[7], "name": i[7],
@@ -151,7 +149,7 @@ def get_one_character(c, user_id, character_id):
"overdrive": calc_char_value(x[2], x[11], x[14], x[17]), "overdrive": calc_char_value(x[2], x[11], x[14], x[17]),
"prog": calc_char_value(x[2], x[10], x[13], x[16]), "prog": calc_char_value(x[2], x[10], x[13], x[16]),
"frag": calc_char_value(x[2], x[9], x[12], x[15]), "frag": calc_char_value(x[2], x[9], x[12], x[15]),
"level_exp": LEVEL_STEPS[x[2]], "level_exp": Constant.LEVEL_STEPS[x[2]],
"exp": x[3], "exp": x[3],
"level": x[2], "level": x[2],
"name": x[7], "name": x[7],
@@ -168,18 +166,18 @@ def calc_level_up(c, user_id, character_id, exp, exp_addition):
exp += exp_addition exp += exp_addition
if exp >= LEVEL_STEPS[20]: # 未觉醒溢出 if exp >= Constant.LEVEL_STEPS[20]: # 未觉醒溢出
c.execute('''select is_uncapped from user_char where user_id=? and character_id=?''', c.execute('''select is_uncapped from user_char where user_id=? and character_id=?''',
(user_id, character_id)) (user_id, character_id))
x = c.fetchone() x = c.fetchone()
if x and x[0] == 0: if x and x[0] == 0:
return LEVEL_STEPS[20], 20 return Constant.LEVEL_STEPS[20], 20
a = [] a = []
b = [] b = []
for i in LEVEL_STEPS: for i in Constant.LEVEL_STEPS:
a.append(i) a.append(i)
b.append(LEVEL_STEPS[i]) b.append(Constant.LEVEL_STEPS[i])
if exp >= b[-1]: # 溢出 if exp >= b[-1]: # 溢出
return b[-1], a[-1] return b[-1], a[-1]
@@ -213,11 +211,11 @@ 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*server.info.CORE_EXP) c, user_id, character_id, x[0], amount*Config.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(
c, user_id, 'core_generic', 'core', -amount) c, user_id, 'core_generic', 'core', -amount)
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)

File diff suppressed because it is too large Load Diff

View File

@@ -6,10 +6,7 @@ import server.character
import server.item import server.item
import time import time
from setting import Config from setting import Config
from .config import Constant
MAX_STAMINA = 12
STAMINA_RECOVER_TICK = 1800000
CORE_EXP = 250
def int2b(x): def int2b(x):
@@ -202,6 +199,38 @@ def get_user_me(c, user_id):
return r return r
def get_user_me_c(user_id):
# user/me调用上边没开数据库这里开一下
with Connect() as c:
return get_user_me(c, user_id)
def get_purchase_pack(user_id):
# 返回曲包数据
with Connect() as c:
return server.arcpurchase.get_purchase(c, 'pack')
def get_game_info():
# 返回游戏基本信息
r = {
"max_stamina": Constant.MAX_STAMINA,
"stamina_recover_tick": Constant.STAMINA_RECOVER_TICK,
"core_exp": Constant.CORE_EXP,
"curr_ts": int(time.time()*1000),
"level_steps": server.character.get_level_steps(),
"world_ranking_enabled": True,
"is_byd_chapter_unlocked": True
}
return r
def get_user_present(user_id):
# 返回奖励信息
with Connect() as c:
return server.arcpurchase.get_user_present(c, user_id)
def arc_aggregate_small(user_id): def arc_aggregate_small(user_id):
# 返回用户数据 # 返回用户数据
r = {"success": False} r = {"success": False}
@@ -239,9 +268,9 @@ def arc_aggregate_big(user_id):
}, { }, {
"id": 3, "id": 3,
"value": { "value": {
"max_stamina": MAX_STAMINA, "max_stamina": Constant.MAX_STAMINA,
"stamina_recover_tick": STAMINA_RECOVER_TICK, "stamina_recover_tick": Constant.STAMINA_RECOVER_TICK,
"core_exp": CORE_EXP, "core_exp": Constant.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": True, "world_ranking_enabled": True,

View File

@@ -1,5 +1,6 @@
from server.sql import Connect from server.sql import Connect
from setting import Config from setting import Config
from .config import Constant
import server.info import server.info
import server.character import server.character
@@ -90,7 +91,7 @@ def change_char_uncap(user_id, character_id):
"overdrive": server.character.calc_char_value(y[2], y[11], y[14], y[17]), "overdrive": server.character.calc_char_value(y[2], y[11], y[14], y[17]),
"prog": server.character.calc_char_value(y[2], y[10], y[13], y[16]), "prog": server.character.calc_char_value(y[2], y[10], y[13], y[16]),
"frag": server.character.calc_char_value(y[2], y[9], y[12], y[15]), "frag": server.character.calc_char_value(y[2], y[9], y[12], y[15]),
"level_exp": server.character.LEVEL_STEPS[y[2]], "level_exp": Constant.LEVEL_STEPS[y[2]],
"exp": y[3], "exp": y[3],
"level": y[2], "level": y[2],
"name": y[7], "name": y[7],

View File

@@ -19,7 +19,7 @@ class Config():
游戏API地址前缀 游戏API地址前缀
Game API's URL prefix Game API's URL prefix
''' '''
GAME_API_PREFIX = '/merikuri/17' GAME_API_PREFIX = '/bridge/18'
''' '''
-------------------- --------------------
''' '''
@@ -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.11.2', '3.11.2c'] ALLOW_APPVERSION = ['3.5.3', '3.5.3c', '3.12.0', '3.12.0c']
''' '''
-------------------- --------------------
''' '''
@@ -46,6 +46,17 @@ class Config():
-------------------- --------------------
''' '''
'''
--------------------
联机功能地址,留空则自动获取
Link Play address
If left blank, it will be obtained automatically.
'''
LINK_PLAY_HOST = '' # ***.com
'''
--------------------
'''
''' '''
-------------------- --------------------
SSL证书路径 SSL证书路径
@@ -225,7 +236,7 @@ class Config():
''' '''
-------------------- --------------------
是否全解锁世界场景 是否全解锁世界场景
If unlocking all world scenerys is enabled If unlocking all world sceneries is enabled
''' '''
WORLD_SCENERY_FULL_UNLOCK = True WORLD_SCENERY_FULL_UNLOCK = True
''' '''

View File

@@ -20,4 +20,4 @@
{% endfor %} {% block content %}{% endblock %} {% endfor %} {% block content %}{% endblock %}
</section> </section>
<footer id="footer" class="footer">Made by Lost@2020-2021</footer> <footer id="footer" class="footer">Made by Lost@2020-2022</footer>

View File

@@ -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', 'gauge_safe_10', 'frags_nami', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', 'eto_uncap', 'luna_uncap', 'frags_preferred_song', 'visual_ghost_skynotes', 'ayu_uncap'] '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', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', 'eto_uncap', 'luna_uncap', 'frags_preferred_song', 'visual_ghost_skynotes', 'ayu_uncap', 'skill_vita']
return render_template('web/changechar.html', skill_ids=skill_ids) return render_template('web/changechar.html', skill_ids=skill_ids)